Многоязычное меню сайта на Gatsby.js
Development | Комментировать запись
В предыдущем материале по работе с Gatsby мы поговорили о создании многоязычного сайта и в качестве примера рассмотрели сайт Kodou, у которого есть японская и английская версии. Материал получился довольно длинным, поэтому мы не стали останавливаться на некоторых использованных утилитах и на том, как создать меню навигации по сайту.
Читайте также: Многоязычный сайт на Gatsby и Cosmic JS
Краткое резюме
Итак, в предыдущем мануале мы создали сайт на японском и английском языках. По умолчанию язык сайта – английский. Это означает, что на сайте есть два типа URL:
- Страницы на японском: kodou.me/ja/team
- Страницы на английском: kodou.me/team
В Cosmic JS написаны разные версии страниц. Gatsby узнает, какие языки используются на сайте, из файла /config/languages. В файле gatsby-node.js мы создаем страницы. Это делается с помощью шаблонов, которые мы заполняем данными из Cosmic JS.
Вот упрощенная версия того, как может выглядеть массив team-members, возвращаемый Cosmic JS.
teamMembers = [
{
title: 'CEO',
fullName: 'Jack Misteli',
content: 'The CEO of the Company',
locale: 'en'
},
{
title: 'CEO',
fullName: 'ジャック・ミステリ',
content: '会社のCEO',
locale: 'ja'
}
]
Получив объект teamMembers, мы создаем два объекта – jaTeamMembers и enTeamMembers – и заполняем templates/team: jaTeamMembers создаст /ja/team, а enTeamMembers создаст /team.
Настройка языковых версий сайта
Сегодня очень важно разрабатывать доступные сайты. Итак, первое, что нам нужно сделать, это добавить наши языки в метаданные сайта. Это также поможет вам получить более точные результаты поиска. Откройте gatsby-config.js:
module.export = {
siteMetadata: {
title: `Kodou`,
description: `Kodou site description`,
author: `Jack Misteli `,
languages
},
//....
Также в приложении Gatsby нужно передать шаблонам текущий язык в контексте страницы. Откройте pageGenerator.js:
// langs содержит языки сайта, а defaultLangKey является языком сайта по умолчанию
// langs можно было бы вычислить программным образом
// здесь langs = ['en', 'ja'] и 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)
})
// создаем новую страницу для каждого языка
langs.forEach(lang => {
createPage({
// функция localizeUrl создает URL-адрес, который учитывает язык по умолчанию
path: localizeUrl(lang, defaultLangKey, '/team'),
component: path.resolve(`src/templates/team.js`),
context: {
profiles: profiles[lang],
// передаем текущий язык странице
lang
}
})
})
}
Теперь можно получить доступ к lang в шаблоне:
const { lang } = props.pageContext;
Использование Intl API
Intl API используется для сравнения строк, а также для форматирования чисел, даты и времени. В нем много интересных функций, но, к сожалению, многие из них выходят за рамки нашего материала. Здесь мы просто будем использовать Intl API для отображения дат в соответствующем формате.
Добавляем пакет response-intl в файл Layout:
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 }) => {
// Мы заполнили siteMetaData в файле gatsby-config.js и извлекаем их здесь для дополнительного языкового контекста
// Здесь было бы лучше получить эти данные из config напрямую, но мы хотим показать разные способы работы
const data = useStaticQuery(graphql`
query SiteInfoQuery {
site {
siteMetadata {
title
languages {
defaultLang
langs
}
}
}
}
`)
// langs – массив поддерживаемых языков
// defaultLang – язык сайта по умолчанию
// title – заголовок сайта
const {langs, defaultLang, title} = data.site.siteMetadata
return (
// IntlProvider определяет язык страницы по умолчанию
<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 отформатирует нашу дату в соответствии с языком, который мы установили в свойстве IntlProvider */}
© <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日月曜日.
Создание меню
Возможно, вы обратили внимание на компонент Header в Layout. Мы передаем в него всю информацию о языке, кроме свойства текущего языка, – это нужно, чтобы мы могли показать вам другой вариант.
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)
// добавьте слеш перед языком, чтобы создать ссылку home
const homeLink = localizeUrl(currentLangKey, defaultLang, '/')
// langs вернуть информацию о меню языка
// langsMenu создаст раскрывающийся список со всеми доступными языковыми параметрами
const langsMenu = buildMenu(languages, defaultLang, currentLangKey, url)
// на странице /team это вернет следующий массив
// [{selected: true, link: "/team/", langKey: "en"},
// {selected: false, link: "/ja/team/", langKey: "ja"}]
// все заголовки пунктов меню навигации
const allLanguageTitles = {
'en':['Concept', 'Work', 'Team', 'News', 'Contact'],
'ja': ['コンセプト', '仕事', 'チーム', 'ニュース', '連絡先']
}
// Устанавливает английский в качестве текущего и языка по умолчанию
const currentLanguageTitles = allLanguageTitles[currentLangKey] || allLanguageTitles['en']
// allNavigationLinks содержит имена всех страниц с URL-адресами на всех поддерживаемых языках
const allNavigationLinks = currentLanguageTitles.map((page, i) => ({
name: page,
url: `${homeLink.replace(defaultLang, '')}${allLanguageTitles.en[i].toLowerCase()}`
}))
// на англоязычной странице это вернет:
// [{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 – это объект, который содержит языковые ключи {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.
Tags: API, Cosmic JS, Gatsby