Многоязычное меню сайта на 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