Giter Club home page Giter Club logo

Comments (13)

ruucm avatar ruucm commented on August 18, 2024 5

@angrypie @sn3h

I got a simple solution for using the changeLocale call.

Just add intl context like the plugin when you create pages from your MDX files

Here are my codes(gatsby-node.js) based on #47

const { createFilePath } = require("gatsby-source-filesystem")
const path = require("path")
const languages = ["en", "ko"] // plugin options

function flattenMessages(nestedMessages, prefix = "") {
  return Object.keys(nestedMessages).reduce((messages, key) => {
    let value = nestedMessages[key]
    let prefixedKey = prefix ? `${prefix}.${key}` : key

    if (typeof value === "string") {
      messages[prefixedKey] = value
    } else {
      Object.assign(messages, flattenMessages(value, prefixedKey))
    }

    return messages
  }, {})
}

const basicPages = new Map()
// Programmatically create the pages for browsing blog posts (Create Page!)
exports.createPages = async ({ graphql, actions, reporter }) => {
  const { createPage } = actions
  const getMessages = (path, language) => {
    try {
      // TODO load yaml here
      const messages = require(`${path}/${language}.json`)

      return flattenMessages(messages)
    } catch (error) {
      if (error.code === "MODULE_NOT_FOUND") {
        process.env.NODE_ENV !== "test" &&
          console.error(
            `[gatsby-plugin-intl] couldn't find file "${path}/${language}.json"`
          )
      }

      throw error
    }
  }

  /**
   * Basic Contents
   */
  const resultsBasic = await graphql(`
    query {
      allMdx(
        sort: { fields: [frontmatter___order], order: ASC }
        filter: { frontmatter: { type: { eq: "basic" } } }
      ) {
        edges {
          node {
            id
            excerpt(pruneLength: 250)
            frontmatter {
              title
              author
              lang
            }
            fields {
              slug
            }
          }
        }
      }
    }
  `)
  // Handle errors
  if (resultsBasic.errors) {
    reporter.panicOnBuild(`🚨 Error while running GraphQL(resultsBasic) query.`)
    return
  }
  console.log("resultsBasic", resultsBasic)
  // you'll call `createPage` for each result
  resultsBasic.data.allMdx.edges.forEach(({ node }, index) => {
    let slug = node.fields.slug
    basicPages.set(`${slug}`, {})
    createPage({
      path: slug,
      // This component will wrap our MDX content
      component: path.resolve(`./src/templates/blog-post-layout.js`),
      context: {
        id: node.id,
        slug: slug,
        prev: index - 1,
        next: index + 1,
        type: "basic",
        // ADD INITL CONTEXT AT HERE
        intl: {
          language: node.frontmatter.lang,
          languages,
          messages: getMessages("./src/intl/", node.frontmatter.lang),
          routed: true,
          originalPath: slug.substr(3), // remove front /en or /ko strings
          redirect: false,
        },
      },
    })
  })
}

// Create Slug!
exports.onCreateNode = async ({
  node,
  actions,
  getNode,
  store,
  cache,
  createNodeId,
}) => {
  const { createNodeField, createNode } = actions
  if (node.internal.type === "Mdx") {
    const value = createFilePath({ node, getNode })
    const newSlug =
      "/" + node.frontmatter.lang + "/clone-apple-music/basic" + value
    createNodeField({
      // Individual MDX node
      node,
      // Name of the field you are adding
      name: "slug",
      // Generated value based on filepath with "blog" prefix
      value: newSlug,
    })
  }
}

// remove duplicated init pages
exports.onCreatePage = async ({ page, actions }) => {
  const { createPage, deletePage } = actions
  // console.log('page.context.type', page.context.type)
  const isBasicPage = page.context.type === "basic"
  const hasInvalidBlogPath = !basicPages.has(page.path)

  // If page is a blog page but has the wrong path
  if (isBasicPage && hasInvalidBlogPath) {
    deletePage(page)
  }
}

from gatsby-plugin-intl.

darekaze avatar darekaze commented on August 18, 2024 2

I've found out a blog from Hiddentao that setup multilingual blog using this plugin with markdown.

It's ok with .md but I want to try with mdx files using gatsby-mdx. Taking the above blog and this doc as references, It seems doesn't work out with <MDXRenderer> (haven't try it with <MDXProvider> but that way is kinda hacky) and the process to setup this is cumbersome.

I ended up using using-i18n in the official example without any i18n library and works well with mdx file (in my case).

I still like the approach that react-intl provides. Hope this plugin can further support creating pages with md/mdx.

from gatsby-plugin-intl.

angrypie avatar angrypie commented on August 18, 2024 2

@sn3h Hey. Look at issue #47, it's already solved :)

from gatsby-plugin-intl.

angrypie avatar angrypie commented on August 18, 2024 2

@sn3h No, it will not work with translated slug.

from gatsby-plugin-intl.

sn3h avatar sn3h commented on August 18, 2024 1

thinking about this more.. Let's say I have blog entry
`

  • slug: 'test'
  • localization:
    • en:
      • title: 'Hello'
    • de:
      • title: 'Guten tag'
        `

then en.json and de.json and some blog.js template (using this plugin with [en, de] as languages)... If blog.js has query depending on language variable
data (filter: localization: { eq: $intl.language} }), would this plugin generate /en/blog/test and /de/blog/test correctly? Because we know the current language..
kind of brainstorming, but I hope something like this works. If I find some solution for this, I will let you know ;)

from gatsby-plugin-intl.

rchrdnsh avatar rchrdnsh commented on August 18, 2024 1

hmmmm...how would you go about changing this example around to support regular mdx files, rather than content coming from a cms @ruucm? It's a bit hard for me to follow :-(

The multi language mdx content is in a folder structure in the project as follows:

src
- content
- - news /* folder of the category type, due to multiple folders of content types */
- - - hipster /* name of the article for the folder */
- - - - index.en.mdx /* or index-en.mdx or anything else that works */
- - - - index.vi.mdx /* or index-vi.mdx or anything else that works */

current node file with some of my guesses as to what should be different:

const { createFilePath } = require("gatsby-source-filesystem")
const path = require("path")
const languages = ["en", "vi"] // plugin options

function flattenMessages(nestedMessages, prefix = "") {
  return Object.keys(nestedMessages).reduce((messages, key) => {
    let value = nestedMessages[key]
    let prefixedKey = prefix ? `${prefix}.${key}` : key

    if (typeof value === "string") {
      messages[prefixedKey] = value
    } else {
      Object.assign(messages, flattenMessages(value, prefixedKey))
    }

    return messages
  }, {})
}

const basicPages = new Map()
// Programmatically create the pages for browsing blog posts (Create Page!)
exports.createPages = async ({ graphql, actions, reporter }) => {
  const { createPage } = actions
  const getMessages = (path, language) => {
    try {
      // TODO load yaml here
      const messages = require(`${path}/${language}.json`)

      return flattenMessages(messages)
    } catch (error) {
      if (error.code === "MODULE_NOT_FOUND") {
        process.env.NODE_ENV !== "test" &&
          console.error(
            `[gatsby-plugin-intl] couldn't find file "${path}/${language}.json"`
          )
      }

      throw error
    }
  }

  /**
   * News Content
   */
  const news = await graphql(`
    query {
      allMdx(
        sort: { order: DESC, fields: [frontmatter___date] }
        filter: { frontmatter: { category: { eq: "news" } } }
      )
      {
        edges {
          node {
            id
            excerpt(pruneLength: 100)
            frontmatter {
              title
              author
              language
            }
            fields {
              slug
            }
          }
        }
      }
    }
  `)
  // Handle errors
  if (news.errors) {
    reporter.panicOnBuild(`🚨 Error while running GraphQL(news) query.`)
    return
  }
  console.log("news", news)
  // you'll call `createPage` for each result
  news.data.allMdx.edges.forEach(({ node }, index) => {
    let slug = node.fields.slug
    basicPages.set(`${slug}`, {})
    createPage({
      path: slug,
      // This component will wrap our MDX content
      component: path.resolve(`./src/templates/article.js`),
      context: {
        id: node.id,
        slug: slug,
        prev: index - 1,
        next: index + 1,
        category: "news",
        // ADD INITL CONTEXT AT HERE
        intl: {
          language: node.frontmatter.language,
          languages,
          messages: getMessages("./src/intl/", node.frontmatter.language),
          routed: true,
          originalPath: slug.substr(3), // remove front /en or /vi strings
          redirect: false,
        },
      },
    })
  })
}

// Create Slug!
exports.onCreateNode = async ({
  node,
  actions,
  getNode,
  store,
  cache,
  createNodeId,
}) => {
  const { createNodeField, createNode } = actions
  if (node.internal.type === "Mdx") {
    const value = createFilePath({ node, getNode })
    const newSlug =
      "/" + node.frontmatter.language + "/" + value
    createNodeField({
      // Individual MDX node
      node,
      // Name of the field you are adding
      name: "slug",
      // Generated value based on filepath with "news" prefix
      value: newSlug,
    })
  }
}

// remove duplicated init pages
exports.onCreatePage = async ({ page, actions }) => {
  const { createPage, deletePage } = actions
  // console.log('page.context.type', page.context.type)
  const isBasicPage = page.context.type === "basic"
  const hasInvalidBlogPath = !basicPages.has(page.path)

  // If page is a blog page but has the wrong path
  if (isBasicPage && hasInvalidBlogPath) {
    deletePage(page)
  }
}

...and from this I'm getting double posts for each language in the blog posts page, and then I'm getting whacky urls like this for each post, which is not working, obviously:

http://localhost:8000/en/en/hipster/index.en/

...soooooooo, yeah...

...no idea what I'm doing...

...just shooting at bugs in the desert at night over here...

from gatsby-plugin-intl.

samajammin avatar samajammin commented on August 18, 2024 1

Thanks for the hot tip @ruucm! That did the trick for me 😄

from gatsby-plugin-intl.

rchrdnsh avatar rchrdnsh commented on August 18, 2024

oh nice, i'll check it out :-)

from gatsby-plugin-intl.

angrypie avatar angrypie commented on August 18, 2024

@rchrdnsh You can use react-intl with MDX in the same way as with JSX.

If you want to generate pages programmatically, and keep separate files for different languages, you should not rely on this plugin i think. It's different task.

@darekaze If I understand correctly all page translations are sent to the client. Not perfect solution for me. I personally did this by passing correct data into the context of the page that was already generated by gatsby-plugin-intl. Also found out some bug (#43) on the way :)

from gatsby-plugin-intl.

sn3h avatar sn3h commented on August 18, 2024

If I understand you correctly, you need to transform parts of any data format, which go something like this:

  • slug : 'blogPost'
  • en
    • title
    • text
  • es
    • title
    • text

into 2 pages. /en/blogPost and /es/blogPost, each using adequate subtree of data.. if you tell Gatsby to create pages for each language, this plugin creates another language mutations for each of them, so you would have to intercept and delete them in the gatsby-node. Something like
onCreatePage ...
if(page.url.contains('/en/de/')) deletePage(page)

I just thought that up, want to try it in few days, but might not work. I am still beginner at this :)

from gatsby-plugin-intl.

sn3h avatar sn3h commented on August 18, 2024

@angrypie thank you, but will it work with changeLocale call?

from gatsby-plugin-intl.

rchrdnsh avatar rchrdnsh commented on August 18, 2024

Hi @darekaze,

I checked out the official 'using-i18n' example and mostly everything looks good, except for the language switcher at the top, which takes the user back to the homepage of the other language, rather than staying on the current page, which is a biiiiiiiiiiiiiiiiiiiiig UI/UX no-no. Trying to figure out how to make a switcher that stays on the same page using that example, but I don't really know how to go about it.

If you have any thoughts, I'm all ears.

from gatsby-plugin-intl.

bolonio avatar bolonio commented on August 18, 2024

Is there any real solution to avoid the duplicates??

http://localhost:8000/en/en/SLUG/index.en/
http://localhost:8000/es/es/SLUG/index.es/

Thanks :)

from gatsby-plugin-intl.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.