Open wottpal opened 3 years ago
Update: I just implemented a way myself via redirects. For others having the same problem I post my code underneath. @microapps Do you think that could be a nice PR in any way?
Helper file i18n-redirects.js
/**
* Returns relative file path of given node under given `basePath` (optionally omitting file-extension)
*/
function getNodeRelativePath(
{ fileAbsolutePath },
omitFileExt,
basePath = `/src/markdown`
) {
const relativePath = (fileAbsolutePath || ``).split(basePath)?.[1]
if (!relativePath || !omitFileExt) return relativePath
return relativePath.split(`.`)?.[0]
}
/**
* Returns language code from file path of given node. As a fallback `defaultLang` is returned.
*/
function getNodeLangCode({ fileAbsolutePath }, defaultLang = `en`) {
const langCodeRegex = /(?:[^/]*\.)(.*)(?:\.md)/
return (fileAbsolutePath || ``).match(langCodeRegex)?.[1] || defaultLang
}
/**
* Creates and returns the theoretically translated url with the original slug.
* If `omitDefaultLang` si true, the given `defaultLang` will not be included in paths for this language.
*/
function getTranslatedUrlPath(
slug,
sourceLang,
destLang,
omitDefaultLang,
defaultLang = `en`
) {
const baseUrlPathRegex = new RegExp(`(?:/${sourceLang})?(/.*)`)
const baseUrlPath = slug.match(baseUrlPathRegex)?.[1] || `/`
return omitDefaultLang && destLang === defaultLang
? `${baseUrlPath}`
: `/${destLang}${baseUrlPath}`
}
/**
* Determines equally named markdown-files with a different language,
* and creates redirects from the theoretically translated url to the actual slug.
*/
module.exports = function createMultilingualRedirects(
{ createRedirect },
allNodes,
node
) {
const { slug } = node.frontmatter
const relativePath = getNodeRelativePath(node, true)
const langCode = getNodeLangCode(node)
allNodes
.map(({ node: translatedNode }) => ({
translatedNode,
translatedNodeLangCode: getNodeLangCode(translatedNode),
translatedNodeRelativePath: getNodeRelativePath(translatedNode, true),
}))
.filter(
({ translatedNodeLangCode, translatedNodeRelativePath }) =>
langCode !== translatedNodeLangCode &&
relativePath === translatedNodeRelativePath
)
.forEach(({ translatedNode, translatedNodeLangCode }) => {
const newRedirect = {
fromPath: getTranslatedUrlPath(
slug,
langCode,
translatedNodeLangCode,
true
),
toPath: translatedNode.frontmatter.slug,
isPermanent: true,
force: true,
redirectInBrowser: true,
}
console.log(`Adding Redirect: `, newRedirect)
createRedirect(newRedirect)
})
}
gatsby-node.js
const path = require(`path`)
const createMultilingualRedirects = require(`./i18n-redirects`)
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const result = await graphql(`
{
allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }) {
edges {
node {
id
fileAbsolutePath
frontmatter {
slug
}
}
}
}
}
`)
if (result.errors) return Promise.reject(result.errors)
// Create pages for each markdown-file
const pageTemplate = path.resolve(`src/templates/article.js`)
const articleNodes = result.data.allMarkdownRemark.edges
articleNodes.forEach(({ node }) => {
// Create Redirects for multilingual pages with different slugs
createMultilingualRedirects(actions, articleNodes, node)
// Create page for each article
createPage({
path: node.frontmatter.slug,
component: pageTemplate,
context: {
// additional data can be passed via context
slug: node.frontmatter.slug,
},
})
})
}
Hey there,
I have German and English markdown files like:
article-name.en.js
article-name.de.js
which should have different slugs/urls on the site like (respectively):
/blog/article-name
/de/blog/artikel-name
I'm already matching those urls with
matchPath
in the config and setgetLanguageFromPath
to true but still, this is only working out if the url after thelang
-part is exactly the same. How can I "link" those files together so that my language-switcher (usingnavigate
fromusei18next
) still works and re-routes between those slugs?Thank you in advance :)