在上一篇文章中,用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
之后,我们创建了两个对象jaTeamMembers
和enTeamMembers
。我们使用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.]中找到