Gatsby.js中的国际化导航菜单
在之前的一篇文章中,使用 Gatsby 创建多语言网站,我构建了 kodou.me。 Kodou 有日语和英语版本。 这篇文章有点长,所以我没有谈论我使用的一些实用程序以及如何构建网站的导航菜单。
快速总结
在我们之前的帖子中,我们用日语和英语建立了一个网站。 该站点的默认语言是英语。 这意味着我们有两种 URL 类型:
- 日文页面:
kodou.me/ja/team - 英文页面
kodou.me/team
不同的页面版本用 Cosmic JS 编写。 我们让 Gatsby 了解我们在 /config/languages 中使用的语言。 在 gatsby-node.js 中,我们使用从 Cosmic JS 中填充数据的模板来创建页面。
这是 Cosmic JS 返回的 team-members 数组的简化版本。
teamMembers = [
{
title: 'CEO',
fullName: 'Jack Misteli',
content: 'The CEO of the Company',
locale: 'en'
},
{
title: 'CEO',
fullName: 'ジャック・ミステリ',
content: '会社のCEO',
locale: 'ja'
}
]
在我们收到 teamMembers 后,我们创建两个对象 jaTeamMembers 和 enTeamMembers。 我们用 jaTeamMembers 填充 templates/team 以创建 /ja/team 和 enTeamMembers 以创建 /team。
使您的网站具有语言意识
成为一名优秀的网络公民并让我们创建的网站易于访问是很重要的。 所以我们需要做的第一件事就是将我们的语言添加到我们网站的元数据中。 它还可以帮助您获得更有针对性的搜索结果。
模块:gatsby-config.js
module.export = {
siteMetadata: {
title: `Kodou`,
description: `Kodou site description`,
author: `Jack Misteli `,
languages
},
//....
在我们的 Gatsby 应用程序中,我们还将页面上下文中的当前语言传递给我们的模板。
模块:pageGenerator.js
// langs contains the languages of our blog and default langKey is the default language of the site
// To be fully programmatic we could calculate langs
// here langs = ['en', 'ja'] and defaultLangKey = 'en'
const { langs, defaultLangKey } = require('../config/languages')
const path = require(`path`)
const { localizeUrl, createLanguagesObject } = require('../utils/localization')
module.exports = async (options, createPage, graphql) => {
const {query, pageName} = options
let templateName = options.templateName ? options.templateName : pageName
const result = await graphql(query)
if (result.errors)
console.error(result.errors)
const cosmicJSData = createLanguagesObject(langs)
Object.values(result.data)[0].edges.forEach(({ node }) => {
cosmicJSData[node.locale].push(node)
})
// we create a new page for each language
langs.forEach(lang => {
createPage({
// the localizeUrl function creates a url which takes into consideration what the default language is
path: localizeUrl(lang, defaultLangKey, '/team'),
component: path.resolve(`src/templates/team.js`),
context: {
profiles: profiles[lang],
// Here we pass the current language to the page
lang
}
})
})
}
现在我们可以在模板中访问 lang
const { lang } = props.pageContext;
使用国际化 API
Intl API 用于字符串比较、数字格式化以及日期和时间格式化。 它有很多很酷的功能,我们不会在这里探索。 我们将在这里简单地使用它来以适当的格式显示日期。
我们在 Layout 文件中添加 react-intl 包。
模块:layout.js
import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import "../styles/main.scss"
import Header from "./header"
import { IntlProvider, FormattedDate } from "react-intl"
const Layout = ({ children, location, lang }) => {
// We populated the siteMetaData in `gatsby-config.js` and are extracting it here for some extra language context
// The best practice here would be to directly get that data from `config` but I want to show different ways to do it
const data = useStaticQuery(graphql`
query SiteInfoQuery {
site {
siteMetadata {
title
languages {
defaultLang
langs
}
}
}
}
`)
// langs is an array of all the supported languages
// defaultLang is the default site language
// title is the website's title
const {langs, defaultLang, title} = data.site.siteMetadata
return (
// We use IntlProvider to set the default language of our page
<IntlProvider
locale={lang}
defaultLocale={defaultLang}
>
<Header
location={location}
defaultLang={defaultLang}
languages={langs}
siteTitle={title} />
<main className="section">
<div className="container">
{children}
</div>
</main>
<footer>
<div className="footer">
<div className="content has-text-centered">
{/* FormattedDate will format our date according to the language we set in IntlProvider locale prop */}
© <FormattedDate value={new Date()}
year="numeric"
month="long"
day="numeric"
weekday="long" />, Built by
<a href="https://jmisteli.com"> Jack Misteli</a>
</div>
</div>
</footer>
</IntlProvider>
)
}
export default Layout
当页面生成英文时,<FormattedDate>会返回Monday, December 9, 2019。 当页面生成日文时 <FormattedDate> 将返回 2019年12月9日月曜日。
创建菜单
你可以看到在 Layout 我们有一个 Header 组件。 除了当前语言属性之外,我们将所有语言信息传递给标题。 我们没有通过它,因为我想向您展示页面当前语言的另一种方式。
import { Link } from "gatsby"
import PropTypes from "prop-types"
import React from "react"
import { getCurrentLangKey, getLangs, getUrlForLang } from 'ptz-i18n'
import langmap from 'langmap'
import { localizeUrl, buildMenu } from '../../utils/localization'
const Header = ({ languages, location, defaultLang}) => {
const url = location.pathname
const currentLangKey = getCurrentLangKey(languages, defaultLang, url)
// Create a home link by adding a slash before the language and if it
const homeLink = localizeUrl(currentLangKey, defaultLang, '/')
// Get langs return language menu information
// langsMenu will allow us to build a dropdown with all the available language options
const langsMenu = buildMenu(languages, defaultLang, currentLangKey, url)
// On the `/team` page this will return the following array
// [{selected: true, link: "/team/", langKey: "en"},
// {selected: false, link: "/ja/team/", langKey: "ja"}]
// All the navigation menu item titles
const allLanguageTitles = {
'en':['Concept', 'Work', 'Team', 'News', 'Contact'],
'ja': ['コンセプト', '仕事', 'チーム', 'ニュース', '連絡先']
}
// Selecting the current language and default to english titles
const currentLanguageTitles = allLanguageTitles[currentLangKey] || allLanguageTitles['en']
// allNavigationLinks contains all the pages name, with urls in every supported language
const allNavigationLinks = currentLanguageTitles.map((page, i) => ({
name: page,
url: `${homeLink.replace(defaultLang, '')}${allLanguageTitles.en[i].toLowerCase()}`
}))
// On the English page it will return
// [{name: "Concept", url: "/concept"}, {name: "Work", url: "/work"}, {name: "Team", url: "/team"}...]
// [{name: "コンセプト", url: "/ja/concept"}, {name: "仕事", url: "/ja/work"}, {name: "チーム", url: "/ja/team"} ...]
return (
<nav>
<Link to={homeLink} className="navbar-item">
HOME
</Link>
{allLinks.map((link, i) => (
<Link key={i} to={link.url} className="navbar-item">
{link.name.toUpperCase()}
</Link>
))}
<div className="navbar-language-menu">
<div className="current-language">
// langmap is an object with the language keys as object keys and english, original versions of the language
{langmap[langKey]['englishName']}
</div>
<div className="all-languages-dropdown">
{langsMenu.map((lang)=>(
!lang.selected &&
<Link key={lang.langKey} to={lang.link} className="navbar-item">
{langmap[lang.langKey]['englishName']}
</Link>
))}
</div>
</div>
</nav>
)}
export default Header
就是这样,您有一个不同语言的导航菜单,可以根据用户当前的语言调整其链接。 如果你想查看我构建的实用程序函数,它们可以在 GitHub 存储库 中找到。