gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.29k stars 10.31k forks source link

Is there any way to create a dynamic "prefix" for the pages? #12258

Closed danechitoaie closed 5 years ago

danechitoaie commented 5 years ago

I'd like to handle the localization by having the locale id as prefix to all my pages. So something like /en/contact-us, /fr/contactez-nous, etc.

Is this possible?

DSchau commented 5 years ago

Definitely!

Because we expose our Node APIs (e.g. createPages) you're in total control over what gets created and the path(s) which you create pages.

So, if we wanted multiple variants of our pages, we just need to ensure we have the appropriate content and a structure that makes sense. For example, if your app were powered by Markdown, we could do a directory structure like:

content/
  en/
    contact-us.md
  fr/
    contactez-nous.md

and then we just create pages from the local filesystem, e.g. in gatsby-node.js

const path = require('path')
const { createFilePath } = require('gatsby-source-filesystem')

exports.onCreateNode = function onCreateNode({ actions, node, getNode }) {
  if (node.internal.type === 'MarkdownRemark') {
    const slug = createFilePath({
      node,
      getNode
    })

    actions.createNodeField({
      name: 'slug',
      value: slug,
      node
    })
  }
}

exports.createPages = async function createPages({ actions, graphql }) {
  const { data, errors } = await graphql(`
    {
      allMarkdownRemark {
        edges {
          node {
            fields {
              slug
            }
          }
        }
      }
    }
  `)

  if (errors) {
    return Promise.reject(errors)
  }

  const mdTemplate = path.resolve('src/templates/md-template.js')

  data.allMarkdownRemark.edges.forEach(({ node }) => {
    const { slug } = node.fields
    actions.createPage({
      path: slug, // /en/contact-us/, /fr/contactez-nous/, etc.
      component: mdTemplate,
      context: {
        slug
      }
    })
  })
}

in gatsby-config.js

const path = require('path')

module.exports = {
  // other stuff
  plugins: [
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'content',
        path: path.join(__dirname, 'content')
      }
    }
  ]
}

Of course, you would insert your own data layer (e.g. whether page content is sourced in Contentful, Wordpress, etc.) but the general idea is the same and looks something like:

@LekoArts has a great example of this with his site, and the source is available here

Going to close this as answered, but please feel free to reply if we can help further.

Thanks for using Gatsby 💜