需要帮助以支持来自Yaml文件的Gatsby网站中的多种语言 1为每个内容文件创建一个元字段 2以编程方式在页面和模板上调用onSourceNode 3按模板中的语言字段查询数据: 4使前端导航正常工作

问题描述

上下文

我有一个Gatsby项目,我在这里使用gatsby-source-filesystem从整个站点内的YAML文件获取内容,但这不是一个大问题(最多四页,没有博客)。

为什么要使用YAML?

选择YAML是基于以下事实:客户端不希望在其后方拥有CMS,而是要编辑文件。而且由于无法告诉人们编辑其内容的人员是否具有编程背景等知识,因此我们所有人都同意,YAML格式“容易”且“简单”,可以向团队解释,以便在完成后接管。 还需要支持以葡萄牙语(应为认语言)和英语开头的语言。稍后,他们将决定是否需要添加其他语言。

问题

我已经修改了一些教程,并浏览了Gatsby插件目录,以获取i18n and intl支持,它们是react-i18next和react-intl这些插件背后的大多数依赖关系。实际上,有一个非常具体的名为gatsby-plugin-yaml-i18n的声音听起来像是该项目的正确选择,但是它的文档记录很差,而且在github上的文件中查看时,我真的无法理解其背后的含义,这意味着难以实现。

i18n

i18n方法的问题在于我们还真的不知道认文本是什么,这意味着首页内容将来可能会更改,因此翻译其内容可能会成为问题。

我们知道,需要的是在我们的代码中指出每个实例的位置,以便盖茨比在构建时使用每种语言的选项(如果有任何意义的话)。

可能的解决方案(?)

总而言之,我认为最好的方法是为区域设置单独的文件,并根据用户是否切换为语言来获取内容-如果使用认值 示例:

./src
 |- content
 |  |- homepage.pt-br.yaml
 |  |- homepage.en-us.yaml
 |- template
 |  |- homepage.js

两个文件的结构都相似,因此编辑者可以读取两个文件并将它们中的文本关联起来。像这样:

# homepage.pt-br.yaml
titulo: "titulo principal"
texto: "texto corrido"
...
# homepage.en-us.yaml
titulo: "main header"
texto: "text fill"

尽管我不确定是否可以仅使用gatsby-source-filesystem从我的简单配置中获取它。这个想法来自以前的经验,在该经验中,我们使用了Contentful CMS,它在graphql查询中为每个节点和数组结果分别获取了区域设置。我不记得是怎么回事 完成,但类似<h1>{['pt-BR'].title</h1>之类的东西。然后,我必须配置gatsby-node.js来基于我们所使用的语言创建上下文,设置认值,使用适当的子句构建页面等。因此,每个页面都将调用适当的lang,并且用户可以选择它是通过开关来实现的。

我不确定从哪里开始。过去,我曾经使用过createResolvers API来处理同一个Contenful无法处理的节点,但是我不确定是否可以用它来为每种语言构建节点。

有正确的方法吗?为此我会阅读任何文档吗? 如果这个问题看起来太“不合适”,我感到抱歉。我正在努力更深入地学习React和Gatsby。

任何评论,建议和问题将不胜感激。

解决方法

我在以前的i18n Gatsby项目中使用了类似的设置,在该项目中,我们还使用文件名来分隔不同的语言(即ToListToListAsync)。

1。为每个内容文件创建一个元字段

例如,查询 async eventListener() {Notifications.events().registerNotificationOpened(async (notification: Notification,completion: () => void,action: NotificationActionResponse) => { await this.setInititalScreen(notification.payload) // console.log("Notification opened by device user",notification.payload); // console.log(`Notification opened with an action identifier: ${action.identifier} and response text: ${action.text}`); completion(); });} 将显示类似main.en.md

对于您的情况,可以在main.ko.mdmain.en.md中执行此操作,获取yaml的父File节点,然后检查它是否包含语言字符串。我们是在{ _meta: { lang: 'en' },title: 'hello',...}可用之前完成此操作的,因此我们在onSourceNode中使用了createSchemaCustomization

2。以编程方式在页面和模板上调用onSourceNode

我们有一系列已知语言

createSchemaCustomization

对于createNodeField文件夹中的页面,我们使用createPage将语言添加到上下文和url:

['en','ko','ja'].forEach(lang => {
  createPage({
    // result in url such as 'site.com/ko/main'
    path: path.join('/',lang,slug),component: componentPath,context: { lang,otherContext }
  })
})

3。按模板中的语言字段查询数据:

src/pages

4。使前端导航正常工作

这是最混乱的部分,我们在其中创建语言的React上下文,用它包装根,然后编写一个环绕onCreatePages的自定义Link组件,以确保站点中的所有链接都指向同一个语言部分。

另一件事是存储用户语言选择,然后在页面加载时重定向(如果用户位于网站的“错误”语言部分)。


在实践中,我们的解决方案也稍微复杂一点,因为我们在单独的文件(exports.onCreatePages = ({ page,actions }) => { const { createPage,deletePage } = actions if (!page.componentPath.includes('src/pages')) { return } languages.forEach(lang => { createPage({ ...page,path: path.join('/',page.path),context: { lang } }) }) deletePage(page) } 中有包含i18n数据的页面,并且在同一文件中具有该信息的页面。

我们还希望有一个很好的默认URL(query SomePage($lang: String!) { myPage( _meta: { lang: { eq: $lang } } ) { /* stuff */ } } ),因此我们的GatsbyLink逻辑也考虑到了这一点。

这绝对是一团糟-我们在早期的盖茨比2.0(Gatsby 2.0)中做到了这一点,当时没有很好的i18n解决方案,否则我肯定会首先寻找替代方案。

,
// this code can be used to create your Gatsby JS site multilingual as well as you can pass id or data which you require to send as a parameter. to make this code works create a page name colors in your pages directory and this is now you can access your single page with multiple urls.

// http://localhost:8001/en-us/color/984 => for en-us language
// http://localhost:8000/en-ca/colour/987 => for en-ca language
// http://localhost:8000/fr-ca/couleur/987 => for fr-ca language
 
const path = require(`path`);
// language locales
const locales = ["en-us","en-ca","fr-ca"];
// names of pages in different locales
const colorPageNames = ["color","colour","couleur"];

// this method will automatically execute on every page creation
exports.onCreatePage = ({ page,actions }) => {
  // destruct createPage and deletePage methods from actions
  const { createPage,deletePage } = actions;
  // Grab the keys of locales and map over them
  colorPageNames.map((pagename,index) => {
    // condition to match page path
    if (page.path.match(/^\/color/)) {
      // first delete the incoming page that was automatically created by Gatsby. if path is matched
      deletePage(page);
      // use the values defined in "locales" to construct the path
      const localizedPath = `${locales[index]}/${pagename}`;
      // match the url format of page
      page.matchPath = `/${locales[index]}/${pagename}/:id`;
      // call a function createPage to construcut new pages with multiple routes
      return createPage({
        // pass on everything from the original page
        ...page,// path use to create path for the new page
        path: localizedPath,// pass in the locale and pagename as context to every page
        context: {
          locale: `${locales[index]}`,pagename: `${pagename}`,},});
    }
  });
};