使用 Gatsby 和 Cosmic JS 创建多语言网站

一个朋友最近让我建立一个网站,有日语和英语版本。我从来没有写过一个国际化的网站,但我对本地化应该如何工作有强烈的意见。因此,这里有一种使用Cosmic JS(一种无头CMS)在Gatsby中实现国际化的方法。

一点上下文

本地化的方法有很多种,而且一如既往地没有灵丹妙药。每种方法都以不同的方式解决问题。因此,我的背景是:

  • 我想建立一个网站,尽可能少的维护成本。
  • 内容编写者没有任何编程经验
  • 网站的维护成本应尽可能低。
  • 网站不应该强迫用户使用网站的一个版本。

最后这一点对我来说非常重要。当你在国外时,一些网站会强迫你使用他们网站的当地版本。当[一大堆跨国公司]强迫我使用`[一长串我不懂的语言]‘版本的网站时,我简直要疯了。我对页面的自动翻译也有同样的问题。如果我想要自动翻译我的网站,我可以使用非常棒的谷歌翻译Chrome extension.

该网站面向日语和英语用户。因此,网站的所有页面都应该有一个英文版本和一个日文版本。如果用户想要更改网站的当前版本,可以点击导航栏中的语言菜单。

我的做法

Gatsby和Reaction提供许多工具来接近本地化(L10n)和国际化(i18n).

我首先使用gatsby-plugin-i18n轻松生成路由。

例如,/page/Team.ja.js会生成如下URL:/ja/Team(ja是日本的语言代码)。

这是一个非常好的插件,但问题是它不是程序化的。我必须为每种语言编写一个新文件。在每个文件中,我必须进行特定的GraphQL查询来获取数据。例如,如果我将一种新语言引入我的CMS,我必须使用新语言扩展重新创建所有路线。

所以,我决定在没有任何插件的情况下构建l10n。这个项目的所有代码都可以在https://github.com/alligatorio/kodou上找到。

在这种情况下,内容作者完全负责本地化。当她写日语版的网站时,她应该确保日期格式正确。这就是为什么我们没有使用act-intl,它依赖于国际化API,并将成为未来帖子的主题。

设置宇宙JS

Cosmic JS是一个很棒的无头CMS选项,允许您在创建新对象类型时激活本地化。

截图:宇宙JS中的L10N选项

不要忘记选择优先区域设置,否则新对象将不会保存。

在我们的新站点中,我们有一个团队页面,因此我们创建一个Team Members对象。当我们创建一个新的团队成员时,我们现在可以选择它的语言。

屏幕截图:宇宙JS中的团队成员语言选择

现在,要从Gatsby访问该数据,我们需要添加`gatsby-source-Cosmicjs‘源插件:

1$ yarn add gatsby-source-cosmicjs

然后,我们需要在plugins中添加以下代码,将gatsby-config.js配置为使用gatsby-source-Cosmicjs

 1[label Module: gatsby-config.js]
 2{
 3  resolve: "gatsby-source-cosmicjs",
 4  options: {
 5    bucketSlug: process.env.COSMIC_BUCKET,
 6    // We add the 'team-members' object type to be able to fetch it later
 7    objectTypes: ["team-members"],
 8    // If you have enabled read_key to fetch data (optional).
 9    apiAccess: {
10      read_key: process.env.COSMIC_ENV_KEY,
11    }
12  }
13}

在我们代码的其余部分中,我们可以通过运行以下命令从Cosic JS访问团队成员数据:

 1graphql(`
 2  {
 3    allCosmicjsTeamMembers  {
 4      edges {
 5      # Here we have the structure of out `team-members` object
 6        node {
 7          title
 8          locale
 9          content
10          metadata {
11            profile_picture {
12              imgix_url
13            }
14          }
15        }
16      }
17    }
18  }
19`)

现在,本地化魔法发生了。

生成本地化页面

我希望我的朋友能够自己做任何他想做的改变。因此,我完全放弃了/pages目录,转而使用/temples目录。Gatsby模板允许我们拥有可重用的内容并以编程方式创建页面;这正是我们需要做的!

在查看模板文件之前,让我们先看看如何从Cosic JS获取数据以创建新页面。

 1[label Module: gatsby-node.js]
 2// langs contains the languages of our blog and default langKey is the default language of the site
 3// To be fully programmatic we could calculate langs
 4// here langs = ['en', 'ja'] and defaultLangKey = 'en'
 5const { langs, defaultLangKey } = require('../config/languages')
 6const path = require(`path`)
 7const { localizeUrl, createLanguagesObject } = require('../utils/localization')
 8
 9exports.createPages = async ({ actions, graphql }) => {
10  const { createPage } = actions
11
12  const result = await graphql(`
13    {
14      allCosmicjsTeamMembers  {
15        edges {
16          node {
17            title
18            locale
19            content
20            metadata {
21              profile_picture {
22                imgix_url
23              }
24            }
25          }
26        }
27      }
28    }
29  `)
30
31  if (result.errors) {
32    console.error(result.errors)
33  }
34
35  // Creates a profiles object with out site's languages 
36  const profiles = createLanguagesObject(langs)
37  // profiles = {
38  // 'en': [],
39  // 'ja': []  
40  // }
41
42  // converting the raw cosmic data into a more useable data structure
43  result.data.allCosmicjsTeamMembers.edges.forEach(({ node }) => {
44    profiles[node.locale].push(node)
45  })
46  // profiles = {
47  // 'en': [...all English profiles],
48  // 'ja': [...all Japanese profiles]  
49  // }
50
51  // we create a new page for each language
52  langs.forEach(lang =>{
53     createPage({
54      // the localizeUrl function creates a url which takes into consideration what the default language is
55      path: localizeUrl(lang, defaultLangKey, '/team'),
56      component: path.resolve(`src/templates/team.js`),
57      context: {
58        profiles: profiles[lang]
59      }
60    })
61  })
62}

此代码将创建两个新页面,路径分别为/ja/Team/Team(没有/en,因为我们将英语设置为默认语言)。

如您所见,createPage以一个对象作为参数,该对象有三个字段路径组件上下文。路径就是我们希望新页面具有的路径。Component是我们要使用的模板。Conext是我们想要传递给模板的数据。在这里,我们传递用我们想要的语言编写的配置文件。

模板

让我们来看看我们的团队模板。

 1import React from "react"
 2import Layout from "../components/layout"
 3import SEO from "../components/seo"
 4
 5const TeamPage = (props) => {
 6  // We will see about pageContext in the next section
 7  const {profiles} = props.pageContext
 8  return (
 9  <Layout location={props.location}>
10    <SEO title="Team" />
11    <h1>Team</h1>
12    // Iterating trough the array of profiles
13    {profiles.map((profile,i)=>(
14      <div key={i} className="columns">
15        <div className="column">
16          // Here are some nice profile pictures of our team members
17          <div className="square-image" style={{backgroundImage: `url("${profile.metadata.profile_picture.imgix_url}")`}}/>
18        </div>
19        <div className="column is-two-thirds">
20          <div className="team-member-title">{profile.title}</div>
21          // Here is some html content we get from Cosmic
22          <div dangerouslySetInnerHTML={{ __html: profile.content }}/>
23        </div>
24      </div>
25      )
26    )}
27  </Layout>
28  )
29}
30
31export default TeamPage

综上所述,上面的代码接受了一个profiles props,它是我们从Cosmic JS中获得的配置文件数组。每个配置文件都有一个配置文件图片对象、一个标题和一个内容字段。content实际上是一个HTML字符串,所以我们必须使用construouslySetInnerHTML属性来设置它。

为了使该模板起作用,提前准备好您的css文件以获得一致的结果是很重要的。我的朋友将不能在宇宙的所见即所得中添加类名或ID。

还有更多要说和做的事情:

  • 创建导航栏和位置感知布局
  • 如何使用国际化接口
  • 如何温和地将用户重定向到他们的网站版本

你可以浏览Github repo),了解我是如何解决这些问题的,并在kodou.me.)上查看结果或者使用Alliator.io查看我们是否上载了关于该主题的一些新内容。但我认为,在一个帖子中处理这件事已经很多了。以上,我希望这将对建立你自己的国际化网站有一点或很大帮助,并期待更多的未来!😉

Published At
Categories with 技术
Tagged with
comments powered by Disqus