Gatsby.js 中的国际化导航菜单

在上一篇文章中,用Gatsby,创建多语言网站](https://kodou.me/).Kodou有日语和英语版本。这篇帖子有点长,所以我没有谈论我使用的一些实用程序,以及如何构建网站的导航菜单。

快速总结

在上一篇文章中,我们用日语和英语建立了一个网站。该网站的默认语言是英语。这意味着我们有两种URL类型:

  • 日文页面:kodou.me/ja/Team
  • 英文页面kodou.me/Team

不同的页面版本用宇宙JS.)编写我们让Gatsby知道我们在/config/languages中使用的语言。在gatsby-node.js中,我们使用模板创建页面,模板中填充了来自Cosic JS的数据。

下面是Cosic JS返回的`Team-Members‘数组的简化版本。

 1teamMembers = [
 2  {
 3    title: 'CEO',
 4    fullName: 'Jack Misteli',
 5    content: 'The CEO of the Company',
 6    locale: 'en'
 7  },
 8  {
 9    title: 'CEO',
10    fullName: 'ジャック・ミステリ',
11    content: '会社のCEO',
12    locale: 'ja'
13  }
14]

在我们收到teamMembers之后,我们创建了两个对象jaTeamMembersenTeamMembers。我们使用jaTeamMembers填充templates/team以创建/ja/team,使用enTeamMembers填充templates/team以创建/team

让你的站点语言感知

做一个好的网民,让我们创建的网站变得可访问,这一点很重要。因此,我们需要做的第一件事是将我们的语言添加到我们站点的元数据中。它还可能帮助你获得更有针对性的搜索结果。

1[label Module: gatsby-config.js]
2module.export = {
3  siteMetadata: {
4    title: `Kodou`,
5    description: `Kodou site description`,
6    author: `Jack Misteli `,
7    languages
8  },
9  //....

在我们的Gatsby应用程序中,我们还将页面上下文中的当前语言传递给模板。

 1[label Module: pageGenerator.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
 9module.exports = async (options, createPage, graphql) => {
10  const {query, pageName} = options
11  let templateName = options.templateName ? options.templateName : pageName
12  const result = await graphql(query)
13  if (result.errors)
14      console.error(result.errors)
15
16  const cosmicJSData = createLanguagesObject(langs)
17
18  Object.values(result.data)[0].edges.forEach(({ node }) => {
19  cosmicJSData[node.locale].push(node)
20  })
21
22  // we create a new page for each language
23  langs.forEach(lang => {
24    createPage({
25      // the localizeUrl function creates a url which takes into consideration what the default language is
26      path: localizeUrl(lang, defaultLangKey, '/team'),
27      component: path.resolve(`src/templates/team.js`),
28      context: {
29      profiles: profiles[lang],
30      // Here we pass the current language to the page
31      lang
32    }
33  })
34  })
35}

现在我们可以在模板中访问lang

1const { lang } = props.pageContext;

使用国际化接口

Intl API用于字符串比较、数字格式化以及日期和时间格式化。它有很多很酷的功能,我们不会在这里探索。我们将在这里简单地使用它来以适当的格式显示日期。

我们将在Layout文件中添加react-intl包。

 1[label Module: layout.js]
 2import React from "react"
 3import { useStaticQuery, graphql } from "gatsby"
 4import "../styles/main.scss"
 5import Header from "./header"
 6import { IntlProvider, FormattedDate } from "react-intl"
 7
 8const Layout = ({ children, location, lang }) => {
 9
10  // We populated the siteMetaData in `gatsby-config.js` and are extracting it here for some extra language context
11  // The best practice here would be to directly get that data from `config` but I want to show different ways to do it
12  const data = useStaticQuery(graphql`
13    query SiteInfoQuery {
14      site {
15        siteMetadata {
16          title
17          languages {
18            defaultLang
19            langs
20          }
21        }
22      }
23}
24  `)
25  // langs is an array of all the supported languages
26  // defaultLang is the default site language
27  // title is the website's title
28  const {langs, defaultLang, title} = data.site.siteMetadata
29
30  return (
31    // We use IntlProvider to set the default language of our page
32    <IntlProvider
33      locale={lang}
34      defaultLocale={defaultLang}
35    >
36      <Header 
37        location={location}
38        defaultLang={defaultLang}
39        languages={langs}
40        siteTitle={title} />
41        <main className="section">
42          <div className="container"> 
43            {children}
44          </div>
45        </main>
46        <footer>
47          <div className="footer">
48            <div className="content has-text-centered">
49            {/* FormattedDate will format our date according to the language we set in IntlProvider locale prop */}
50              © <FormattedDate value={new Date()}
51               year="numeric"
52                month="long"
53                day="numeric"
54                weekday="long" />, Built by 
55              <a href="https://jmisteli.com"> Jack Misteli</a>
56            </div>
57          </div>
58        </footer>
59    </IntlProvider>
60  )
61}
62
63export default Layout

生成英文页面时,<FormattedDate>返回2019年12月9日星期一。生成日文页面时,<FormattedDate>将返回2019年12月9日月曜日

创建菜单

您可以看到,在Layout中,我们有一个Header组件。我们将所有语言信息传递给标头,但当前语言属性除外。我们没有通过它,因为我想向您展示页面当前语言的另一种方式。

 1import { Link } from "gatsby"
 2import PropTypes from "prop-types"
 3import React from "react"
 4import { getCurrentLangKey, getLangs, getUrlForLang } from 'ptz-i18n'
 5import langmap from 'langmap'
 6import { localizeUrl, buildMenu } from '../../utils/localization'
 7
 8const Header = ({ languages, location, defaultLang}) => {
 9
10  const url = location.pathname
11  const currentLangKey = getCurrentLangKey(languages, defaultLang, url)
12
13  // Create a home link by adding a slash before the language and if it
14  const homeLink = localizeUrl(currentLangKey, defaultLang, '/')
15
16  // Get langs return language menu information
17
18  // langsMenu will allow us to build a dropdown with all the available language options
19  const langsMenu = buildMenu(languages, defaultLang, currentLangKey, url)
20  // On the `/team` page this will return the following array
21  //  [{selected: true, link: "/team/", langKey: "en"},
22  //  {selected: false, link: "/ja/team/", langKey: "ja"}]
23
24  // All the navigation menu item titles
25  const allLanguageTitles = {
26    'en':['Concept', 'Work', 'Team', 'News', 'Contact'],
27    'ja': ['コンセプト', '仕事', 'チーム', 'ニュース', '連絡先']
28  }
29
30  // Selecting the current language and default to english titles
31  const currentLanguageTitles = allLanguageTitles[currentLangKey] || allLanguageTitles['en']
32
33  // allNavigationLinks contains all the pages name, with urls in every supported language
34  const allNavigationLinks = currentLanguageTitles.map((page, i) => ({
35    name: page,
36    url: `${homeLink.replace(defaultLang, '')}${allLanguageTitles.en[i].toLowerCase()}`
37  }))
38  // On the English page it will return 
39  // [{name: "Concept", url: "/concept"}, {name: "Work", url: "/work"}, {name: "Team", url: "/team"}...]
40  // [{name: "コンセプト", url: "/ja/concept"}, {name: "仕事", url: "/ja/work"}, {name: "チーム", url: "/ja/team"} ...]
41
42  return (
43    <nav>
44      <Link to={homeLink} className="navbar-item">
45        HOME
46      </Link>
47      {allLinks.map((link, i) => (
48      <Link key={i} to={link.url} className="navbar-item">
49        {link.name.toUpperCase()}
50      </Link>
51      ))}
52
53      <div className="navbar-language-menu">
54        <div className="current-language">
55        // langmap is an object with the language keys as object keys and english, original versions of the language
56        {langmap[langKey]['englishName']}
57        </div>
58        <div className="all-languages-dropdown">
59          {langsMenu.map((lang)=>(
60            !lang.selected && 
61            <Link key={lang.langKey} to={lang.link} className="navbar-item">
62            {langmap[lang.langKey]['englishName']}
63            </Link>
64          ))}
65        </div>
66      </div>
67    </nav>
68)}
69
70export default Header

就是这样,你有一个不同语言的导航菜单,可以根据用户的当前语言调整其链接。如果您想查看我构建的实用程序函数,它们可以在giHub repo.]中找到

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