Вы ведь знаете Gatsby? — Если нет, то прекратите читать эту статью и займитесь чем-нибудь другим.
Да, Gatsby — это фреймворк с открытым исходным кодом, который объединяет функциональность React, GraphQL и Webpack в единый инструмент для создания статических веб-сайтов и приложений.
Но как выглядит интернационализация (i18n) в Gatsby?
Есть несколько плагинов/библиотек, которые могут помочь с инструментарием кода Gatsby для интернационализации.
В этой статье мы будем использовать плагин, основанный на известном i18n-фреймворке i18next, соответственно его замечательному расширению для React.js — react-i18next.
Плагин Gatsby, который мы используем, — gatsby-plugin-react-i18next, созданный Дмитрием Невзоровым.
- TOC
- Итак, прежде всего: «Почему i18next?».
- Давайте разберемся…
- Предварительные условия
- Начало работы
- Переключатель языков
- Интернационализированные ссылки
- Интерполяция и плюрализация
- Почему мои клавиши множественного числа не работают?
- Форматирование
- Контекст
- Извлечение ключей
- Дополнительная мощность
- Конечно!
- Как это выглядит?
- 👀 но это еще не все… (InContext Editor)
- 🎉🥳 Поздравляю 🎊🎁.
- 👍
TOC
- Итак, прежде всего: «Почему i18next?».
- Давайте разберемся…
- Предварительные условия
- Начало работы
- Переключатель языков
- Интернационализированные ссылки
- Интерполяция и плюрализация
- Форматирование
- Контекст
- Извлечение ключей
- Обязательно!
- Как это выглядит?
- 👀 но это еще не все… (InContext Editor)
- 🎉🥳 Поздравляем 🎊🎁
Итак, прежде всего: «Почему i18next?».
Когда речь заходит о локализации React. Одним из самых популярных i18n framework является i18next с его react расширением react-i18next, и на то есть веские причины:
i18next был создан в конце 2011 года. Это старше, чем большинство библиотек, которые вы используете сегодня, включая ваши основные фронтенд-технологии (react, vue, …).
➡️ устойчивый
Судя по тому, как долго i18next уже доступен с открытым исходным кодом, нет ни одного реального случая i18n, который нельзя было бы решить с помощью i18next.
➡️ зрелый
i18next может быть использован в любой среде javascript (и нескольких не javascript — .net, elm, iOS, android, ruby, …), с любым фреймворком UI, с любым форматом i18n, … возможности безграничны.
➡️ расширяемость
В i18next вы получите множество функций и возможностей по сравнению с другими обычными i18n-фреймворками.
➡️ богатый
Здесь вы можете найти больше информации о том, почему i18next особенный и как он работает.
Давайте разберемся…
Предварительные условия
Убедитесь, что у вас установлен Node.js и npm. Лучше всего, если у вас есть некоторый опыт работы с простым HTML, JavaScript, React.js и базовым Gatsby, прежде чем переходить к gatsby-plugin-react-i18next. Этот пример локализации Gatsby не является учебником для начинающих по Gatsby или React.
Начало работы
Возьмите свой собственный проект Gatsby или создайте новый, т.е. с помощью gatsby-cli.
npx gatsby-cli new
Мы создадим переключатель языков, чтобы контент менялся между разными языками.
Давайте установим некоторые зависимости i18next:
- gatsby-plugin-react-i18next
- i18next
- react-i18next
npm install gatsby-plugin-react-i18next i18next react-i18next
Создайте директорию locales
и добавьте в нее подпапку для вашего языка по умолчанию/справочного языка (например, en
для английского).
Туда мы добавим наши файлы пространства имен, например:
|-- en
|-- common.json
|-- index.json
Добавим файл languages.js
:
const { join } = require('path')
const { readdirSync, lstatSync } = require('fs')
const defaultLanguage = 'en';
// based on the directories get the language codes
const languages = readdirSync(join(__dirname, 'locales')).filter((fileName) => {
const joinedPath = join(join(__dirname, 'locales'), fileName)
const isDirectory = lstatSync(joinedPath).isDirectory()
return isDirectory
});
// defaultLanguage as first
languages.splice(languages.indexOf(defaultLanguage), 1);
languages.unshift(defaultLanguage);
module.exports = {
languages,
defaultLanguage,
};
Импортируйте файл languages.js
в файл gatsby-config.js
и настройте некоторые плагины:
const { languages, defaultLanguage } = require('./languages');
// somewhere in your plugins add:
module.exports = {
// ...
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/locales`,
name: `locale`
}
},
{
resolve: 'gatsby-plugin-react-i18next',
options: {
languages,
defaultLanguage,
siteUrl,
i18nextOptions: {
// debug: true,
fallbackLng: defaultLanguage,
supportedLngs: languages,
defaultNS: 'common',
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
}
},
},
},
// ...
]
}
Теперь приступим к созданию нашего первого интернационализированного текста.
Поскольку gatsby-plugin-react-i18next экспортирует все методы и компоненты react-i18next, мы можем это сделать:
В файле страницы:
import { Trans, useTranslation } from 'gatsby-plugin-react-i18next';
import { graphql } from 'gatsby';
import React from 'react';
// ...
const IndexPage = () => {
const { t } = useTranslation();
return (
<Layout>
<Seo title={t('seo')} />
<h1>
<Trans i18nKey="title">Hi people</Trans>
</h1>
{ /* ... */}
</Layout>
)
}
export default IndexPage;
export const query = graphql`
query ($language: String!) {
locales: allLocale(
filter: { ns: { in: ["index"] }, language: { eq: $language } }
) {
edges {
node {
ns
data
language
}
}
}
}
`;
Теперь также определите файл пространства имен locales/en/index.json
, вот так:
{
"seo": "Home",
"title": "Hi people"
}
И, возможно, еще один для немецкого языка?
locales/de/index.json
:
{
"seo": "Startseite",
"title": "Hallo Leute"
}
Переключатель языков
Чтобы иметь возможность переключаться между разными языками, нам нужен переключатель языков:
import { Link, useI18next } from 'gatsby-plugin-react-i18next';
import React from 'react';
const Header = ({ siteTitle }) => {
const { languages, originalPath, t, i18n } = useI18next();
return (
<header className="main-header">
{/* ... */}
<ul className="languages">
{languages.map((lng) => (
<li key={lng}>
<Link to={originalPath} language={lng} style={{ textDecoration: i18n.resolvedLanguage === lng ? 'underline' : 'none' }}>
{lng}
</Link>
</li>
))}
</ul>
</header>
);
};
export default Header;
Теперь вы должны увидеть что-то вроде этого:
По умолчанию, при первой загрузке, gatsby-plugin-react-i18next будет возвращаться к defaultLanguage
, если обнаруженный язык браузера не включен в массив languages
.
Если вы хотите сделать откат на другой язык из массива languages
, вы можете установить опцию fallbackLanguage
.
Теперь переключение на de
(немецкий) также должно работать:
🥳 Потрясающе, вы только что создали свой первый переключатель языков!
Интернационализированные ссылки
Давайте создадим вторую страницу…
import { graphql } from 'gatsby';
import React, { useState } from 'react';
import Layout from '../components/layout';
import { useTranslation } from 'gatsby-plugin-react-i18next';
const SecondPage = (props) => {
const { t } = useTranslation();
const [count, setCounter] = useState(0);
return (
<Layout>
<Seo title={t('title')} />
<h1>
<Trans i18nKey="title">Page two</Trans>
</h1>
<p>
<Trans i18nKey="welcome">Welcome to page 2</Trans> ({props.path})
</p>
{/* ... */}
</Layout>
);
};
export default SecondPage;
export const query = graphql`
query ($language: String!) {
locales: allLocale(
filter: { ns: { in: ["page-2"] }, language: { eq: $language } }
) {
edges {
node {
ns
data
language
}
}
}
}
`;
Новое пространство имен:locales/en/page-2.json
{
"title": "Page two",
"welcome": "Welcome to page 2"
}
locales/de/page-2.json
{
"title": "Seite zwei",
"welcome": "Willkommen auf Seite 2"
}
…и ссылку на эту страницу с первой:
import { Link, Trans, useTranslation } from 'gatsby-plugin-react-i18next';
import { graphql } from 'gatsby';
import React from 'react';
// ...
const IndexPage = () => {
const { t } = useTranslation();
return (
<Layout>
<Seo title={t('seo')} />
<h1>
<Trans i18nKey="title">Hi people</Trans>
</h1>
{ /* ... */}
<p>
<Link to="/page-2/">
<Trans i18nKey="goToPage2">Go to page 2</Trans>
</Link>
</p>
</Layout>
)
}
export default IndexPage;
export const query = graphql`
query ($language: String!) {
locales: allLocale(
filter: { ns: { in: ["index"] }, language: { eq: $language } }
) {
edges {
node {
ns
data
language
}
}
}
}
`;
Новый ключ перевода для locales/en/index.json
:
{
"seo": "Home",
"title": "Hi people",
"goToPage2": "Go to page 2"
}
locales/de/index.json
:
{
"seo": "Startseite",
"title": "Hallo Leute",
"goToPage2": "Gehen Sie zu Seite 2"
}
Компонент Link
, экспортируемый из gatsby-plugin-react-i18next
, автоматически устанавливает ссылку на нужный язык.
Компонент Link
идентичен компоненту Gatsby Link, за исключением того, что вы можете указать дополнительный реквизит языка для создания ссылки на страницу с другим языком.
Интерполяция и плюрализация
i18next не ограничивается предоставлением стандартных функций i18n.
Но, безусловно, он способен обрабатывать множественное число и интерполяцию.
Давайте посчитаем каждый раз, когда нажимается кнопка:
import { graphql } from 'gatsby';
import React, { useState } from 'react';
import Layout from '../components/layout';
import { useTranslation } from 'gatsby-plugin-react-i18next';
const SecondPage = (props) => {
const { t } = useTranslation();
const [count, setCounter] = useState(0);
return (
<Layout>
<Seo title={t('title')} />
<h1>
<Trans i18nKey="title">Page two</Trans>
</h1>
<p>
<Trans i18nKey="welcome">Welcome to page 2</Trans> ({props.path})
</p>
<p>
<button onClick={() => {
setCounter(count + 1);
}}>{
t('counter', { count })
}</button>
</p>
{/* ... */}
</Layout>
);
};
export default SecondPage;
export const query = graphql`
query ($language: String!) {
locales: allLocale(
filter: { ns: { in: ["page-2"] }, language: { eq: $language } }
) {
edges {
node {
ns
data
language
}
}
}
}
`;
…и расширение ресурсов перевода:locales/en/page-2.json
{
"title": "Page two",
"welcome": "Welcome to page 2",
"counter_one": "clicked one time",
"counter_other": "clicked {{count}} time",
"counter_zero": "Click me!"
}
locales/de/page-2.json
{
"title": "Seite zwei",
"welcome": "Willkommen auf Seite 2",
"counter_one": "einmal angeklickt",
"counter_other": "{{count}} Mal geklickt",
"counter_zero": "Klick mich!"
}
На основе значения count i18next выберет правильную форму множественного числа.
i18next также предоставляет возможность специального перевода для {count: 0}
, чтобы можно было использовать более естественный язык. Если count
равно 0
, и присутствует запись _zero
, то она будет использоваться вместо суффикса множественного числа обычного языка (_other
).
Подробнее о множественном числе и интерполяции читайте в официальной документации i18next.
💡 i18next также может работать с языками с несколькими формами множественного числа, например арабским:
// translation resources:
{
"key_zero": "zero",
"key_one": "singular",
"key_two": "two",
"key_few": "few",
"key_many": "many",
"key_other": "other"
}
// usage:
t('key', {count: 0}); // -> "zero"
t('key', {count: 1}); // -> "singular"
t('key', {count: 2}); // -> "two"
t('key', {count: 3}); // -> "few"
t('key', {count: 4}); // -> "few"
t('key', {count: 5}); // -> "few"
t('key', {count: 11}); // -> "many"
t('key', {count: 99}); // -> "many"
t('key', {count: 100}); // -> "other"
Почему мои клавиши множественного числа не работают?
Вы видите это предупреждение в консоли разработки (debug: true
)?
i18next::pluralResolver: Ваша среда, похоже, не совместима с Intl API, используйте полифилл Intl.PluralRules. Будет откат к обработке формата compatibilityJSON v3.
В v21 i18next упорядочил суффикс с тем, который используется в Intl API.
В средах, где Intl.PluralRules API недоступен (например, на старых устройствах Android), вам может понадобиться полифилл Intl.PluralRules API.
В случае его отсутствия будет выполнен откат к обработке множественного числа в формате i18next JSON v3. И если ваш json уже использует новые суффиксы, ваши ключи множественного числа, вероятно, не будут отображаться.
tldr;
npm install intl-pluralrules
import 'intl-pluralrules'
Форматирование
Теперь давайте проверим, как с помощью i18next и Luxon можно использовать различные форматы для работы с датой и временем.
npm install luxon
Нам нравится, когда в нижнем колонтитуле отображается текущая дата:
import React from 'react';
import { DateTime } from 'luxon';
import { useI18next } from 'gatsby-plugin-react-i18next';
// ...
const Layout = ({ children }) => {
const { t, i18n } = useI18next();
// defining custom formatters is normally done immediately after the i18next.init call, but with gatsby-plugin-react-i18next is not possible, so let's add it here
if (!i18n.services.formatter.date_huge) {
i18n.services.formatter.add('date_huge', (value, lng, options) => {
return DateTime.fromJSDate(value).setLocale(lng).toLocaleString(DateTime.DATE_HUGE)
});
}
return (
<>
<Header />
<div
style={{
margin: '0 auto',
maxWidth: 960,
padding: '0 1.0875rem 1.45rem',
}}
>
<main>{children}</main>
<footer style={{ marginTop: 50 }}>
<i>
{
t('footer', { date: new Date() })
}
</i>
</footer>
</div>
</>
);
};
export default Layout;
Импортируйте luxon и определите функцию формата, как описано в документации, и добавьте новый ключ перевода:
locales/en/common.json
{
"footer": "Today is {{date, date_huge}}"
}
locales/de/common.json
{
"footer": "Heute ist {{date, date_huge}}"
}
😎 Круто, теперь у нас есть форматирование даты в зависимости от языка!
Английский:
Немецкий:
Контекст
Как насчет специфического приветствия, основанного на текущем времени суток? Например, утро, вечер и т.д.
Это возможно благодаря контекстной функции i18next.
Давайте создадим функцию getGreetingTime
и используем результат в качестве контекстной информации для перевода колонтитула:
import React from 'react';
import { DateTime } from 'luxon';
import { useI18next } from 'gatsby-plugin-react-i18next';
// ...
const getGreetingTime = (d = DateTime.now()) => {
const split_afternoon = 12; // 24hr time to split the afternoon
const split_evening = 17; // 24hr time to split the evening
const currentHour = parseFloat(d.toFormat('hh'));
if (currentHour >= split_afternoon && currentHour <= split_evening) {
return 'afternoon';
} else if (currentHour >= split_evening) {
return 'evening';
}
return 'morning';
}
const Layout = ({ children }) => {
const { t, i18n } = useI18next();
// defining custom formatters is normally done immediately after the i18next.init call, but with gatsby-plugin-react-i18next is not possible, so let's add it here
if (!i18n.services.formatter.date_huge) {
i18n.services.formatter.add('date_huge', (value, lng, options) => {
return DateTime.fromJSDate(value).setLocale(lng).toLocaleString(DateTime.DATE_HUGE)
});
}
return (
<>
<Header />
<div
style={{
margin: '0 auto',
maxWidth: 960,
padding: '0 1.0875rem 1.45rem',
}}
>
<main>{children}</main>
<footer style={{ marginTop: 50 }}>
<i>
{
t('footer', { date: new Date(), context: getGreetingTime() })
}
</i>
</footer>
</div>
</>
);
};
export default Layout;
И добавим несколько контекстно-специфических клавиш перевода:
locales/en/common.json
{
"footer": "Today is {{date, date_huge}}",
"footer_afternoon": "Good afternoon! It's {{date, date_huge}}",
"footer_evening": "Good evening! Today was the {{date, date_huge}}",
"footer_morning": "Good morning! Today is {{date, date_huge}} | Have a nice day!"
}
locales/de/common.json
{
"footer": "Heute ist {{date, date_huge}}",
"footer_afternoon": "Guten Nachmittag! Es ist {{date, date_huge}}",
"footer_evening": "Guten Abend! Heute war der {{date, date_huge}}",
"footer_morning": "Guten Morgen! Heute ist {{date, date_huge}} | Einen schönen Tag noch!"
}
😁 Да, это работает!
Извлечение ключей
Благодаря babel-plugin-i18next-extract вы можете автоматически извлекать переводы внутри функции t
и компонента Trans
из ваших страниц и сохранять их в файлах пространства имен.
Это работает следующим образом:
Сначала установите необходимые зависимости:
npm install @babel/cli @babel/plugin-transform-typescript babel-plugin-i18next-extract
Создайте или обновите файл babel-extract.config.js
(НЕ называйте его babel.config.js
, иначе он будет использоваться gatsby):
const { defaultLanguage } = require('./languages');
process.env.NODE_ENV = 'test';
module.exports = {
presets: ['babel-preset-gatsby'],
plugins: [
[
'i18next-extract',
{
keyAsDefaultValue: [defaultLanguage],
useI18nextDefaultValue: [defaultLanguage],
// discardOldKeys: true,
defaultNS: 'common',
outputPath: 'locales/{{locale}}/{{ns}}.json',
customTransComponents: [['gatsby-plugin-react-i18next', 'Trans']],
compatibilityJSON: 'v4',
}
]
],
overrides: [
{
test: [`**/*.ts`, `**/*.tsx`],
plugins: [[`@babel/plugin-transform-typescript`, {isTSX: true}]]
}
]
};
Добавьте скрипт в ваш package.json
:
"scripts": {
"extract": "babel --config-file ./babel-extract.config.js -o tmp/chunk.js 'src/**/*.{js,jsx,ts,tsx}' && rm -rf tmp"
}
Если вы хотите извлечь переводы на страницу для определенного пространства имен, вы можете добавить специальный комментарий в начале страницы:
// i18next-extract-mark-ns-start index
import React from 'react';
// ...
fyi: Существуют и другие подсказки к комментариям, которые вы можете использовать.
Подготовили все свои страницы? Отлично, давайте попробуем:
// i18next-extract-mark-ns-start index
import React from 'react';
import { Link, Trans, useTranslation } from 'gatsby-plugin-react-i18next';
import { graphql, Link as GatsbyLink } from 'gatsby';
import { StaticImage } from 'gatsby-plugin-image';
import Layout from '../components/layout';
import Seo from '../components/seo';
const IndexPage = () => {
const { t } = useTranslation();
return (
<Layout>
<Seo title={t('seo')} />
<h1>
<Trans i18nKey="title">Hi people</Trans>
</h1>
<p>
<Trans i18nKey="welcome">Welcome to your new Gatsby site.</Trans>
</p>
<p>
<Trans i18nKey="cta">Now go build something great.</Trans>
</p>
<p>
<Link to="/page-2/">
<Trans i18nKey="goToPage2">Go to page 2</Trans>
</Link>
</p>
</Layout>
);
};
export default IndexPage;
export const query = graphql`
query ($language: String!) {
locales: allLocale(
filter: { ns: { in: ["common", "index"] }, language: { eq: $language } }
) {
edges {
node {
ns
data
language
}
}
}
}
`;
Запуск npm run extract
теперь добавит этот новый ключ cta
в файл пространства имен:
{
"cta": "Now go build something great.",
"goToPage2": "Go to page 2",
"seo": "Home",
"title": "Hi people",
"welcome": "Welcome to your new Gatsby site."
}
Дополнительная мощность
Все это уже замечательно, но мы можем сделать еще больше!
Было бы неплохо иметь обзор, показывающий, какие переводы отсутствуют, а какие файлы переведены полностью…
И подумайте о том, чтобы при извлечении новых ключей они автоматически переводились?
Чтобы это стало реальностью, нам нужен менеджмент переводов…
Посылая переводы некоторым переводчикам или бюро переводов, вы получаете больше контроля и прямой контакт с ними. Но это также означает больше работы для вас.
Это традиционный способ. Но имейте в виду, что пересылка файлов всегда сопряжена с накладными расходами.
Существует ли лучший вариант?
Конечно!
i18next помогает перевести приложение, и это замечательно, но есть и другие варианты.
- Как вы интегрируете любые переводческие службы / агентства?
- Как вы отслеживаете новый или удаленный контент?
- Как вы обеспечиваете надлежащее версионирование?
- и многое другое…
Ищу что-то вроде этого❓
- Легко интегрировать
- Непрерывное развертывание? Непрерывная локализация!
- Легко управляйте файлами переводов
- Заказывайте профессиональные переводы
- Аналитика и статистика
- Версионирование ваших переводов
- Автоматический и машинный перевод по требованию
- Без риска: Возьмите свои данные с собой
- Прозрачное и справедливое ценообразование
- и многое другое…
Как это выглядит?
Сначала вам нужно зарегистрироваться в locize и войти в систему.
Затем создать новый проект в locize и добавить все необходимые языки. И наконец, вы можете добавить свои переводы либо с помощью cli, либо импортировав отдельные json-файлы, либо через API.
Теперь давайте установим locize-cli:
npm install -g locize-cli
Мы подготовим новый скрипт, который будет синхронизировать наши локальные изменения с locize.
А также необязательный второй скрипт, который будет просто загружать новейшие переводы из locize.
Убедитесь, что вы используете свой project-id и api-key:
"scripts": {
"syncLocales": "locize sync --project-id=5d47a999-5c34-4161-a389-bc2189507a50 --ver=latest --api-key=42ca9d58-18da-44c7-8dd3-8f59b8c35bda --path=./locales",
"downloadLocales": "locize download --project-id=5d47a999-5c34-4161-a389-bc2189507a50 --ver=latest --clean=true --path=./locales"
}
Используйте скрипт npm run syncLocales
для синхронизации вашего локального репозитория с тем, что опубликовано на locize.
В качестве альтернативы вы также можете использовать скрипт npm run downloadLocales
, чтобы всегда загружать опубликованные переводы locize в ваш локальный репозиторий перед сборкой вашего приложения.
Если теперь мы добавим новый ключ перевода, например, такой:
<Trans i18nKey="newKey">this will be added automatically after "extract" and "syncLocales"</Trans>
и запустить npm run export
, а затем npm run syncLocales
, мы получим следующее:
locales/en/page-2.json
:
{
"back": "Go back to the homepage",
"counter_one": "clicked one time",
"counter_other": "clicked {{count}} time",
"counter_zero": "Click me!",
"title": "Page two",
"welcome": "Welcome to page 2",
"newKey": "this will be added automatically after "extract" and "syncLocales""
}
locales/de/page-2.json
:
{
"back": "Gehen Sie zurück zur Startseite",
"counter_one": "einmal angeklickt",
"counter_other": "{{count}} Mal geklickt",
"counter_zero": "Klick mich!",
"title": "Seite zwei",
"welcome": "Willkommen auf Seite 2",
"newKey": "dies wird automatisch nach "extract" und "syncLocales" hinzugefügt"
}
Благодаря опционально включенной опции автоматического машинного перевода новые ключи не только добавляются в locize в процессе разработки приложения, но и автоматически переводятся на целевые языки с помощью машинного перевода.
👀 но это еще не все… (InContext Editor)
С помощью плагина locize вы сможете использовать свое приложение в InContext Editor от locize.
Хотите посмотреть, как это выглядит?
Итак, сначала установите зависимость locize:
npm install locize
Затем в коде (выбираем наш файл layout.js
) добавьте следующее:
import React from 'react';
import { useI18next } from 'gatsby-plugin-react-i18next';
import { locizePlugin, setEditorLng } from 'locize';
// ...
const Layout = ({ children }) => {
const { t, i18n } = useI18next();
// defining custom formatters is normally done immediately after the i18next.init call, but with gatsby-plugin-react-i18next is not possible, so let's add it here
if (!i18n.services.formatter.date_huge) {
i18n.services.formatter.add('date_huge', (value, lng, options) => {
return DateTime.fromJSDate(value).setLocale(lng).toLocaleString(DateTime.DATE_HUGE)
});
// also the locize plugin normally is automatically configured, but here we need to do it that way
locizePlugin.init(i18n);
setEditorLng(i18n.resolvedLanguage);
}
return (
<>
<Header />
<div
style={{
margin: '0 auto',
maxWidth: 960,
padding: '0 1.0875rem 1.45rem',
}}
>
<main>{children}</main>
<footer style={{ marginTop: 50 }}>
<i>
{
t('footer', { date: new Date(), context: getGreetingTime() })
}
</i>
</footer>
</div>
</>
);
};
export default Layout;
И в gatsby-config.js
добавьте несколько новых опций react:
const { languages, defaultLanguage } = require('./languages');
module.exports = {
// ...
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
path: `${__dirname}/locales`,
name: `locale`
}
},
{
resolve: 'gatsby-plugin-react-i18next',
options: {
languages,
defaultLanguage,
siteUrl,
i18nextOptions: {
// debug: true,
fallbackLng: defaultLanguage,
supportedLngs: languages,
defaultNS: 'common',
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
react: {
bindI18n: 'languageChanged editorSaved', // the editorSaved event will trigger a rerender
}
},
},
},
// ...
]
}
Затем перейдите в ваш проект locize и определите урлы вашего контекстного редактора, как описано здесь.
Результат будет выглядеть следующим образом:
Разве это не здорово?
🧑💻 Полный код можно найти здесь.
Если вы хотите узнать больше об основах i18next, есть также видео «i18next crash course».
🎉🥳 Поздравляю 🎊🎁.
Надеюсь, вы узнали несколько новых вещей о gatsby-plugin-react-i18next, i18next, локализации React.js и современных рабочих процессах локализации.
Итак, если вы хотите вывести тему i18n на новый уровень, стоит попробовать платформу управления локализацией — locize.
Основатели locize также являются создателями i18next. Таким образом, используя locize, вы напрямую поддерживаете будущее i18next.
👍