Я создаю приложение, которое должно быть доступно на нескольких языках и в разных регионах.
Мой вопрос не чисто технический, а скорее об архитектуре и шаблонах, которые люди фактически используют в производстве для решения этой проблемы. Я нигде не нашел для этого никакой "кулинарной книги", поэтому перехожу на свой любимый сайт вопросов и ответов :)
Вот мои требования (они действительно «стандартные»):
- Пользователь может выбрать язык (тривиально)
- При изменении языка интерфейс должен автоматически переводиться на новый выбранный язык.
- На данный момент я не слишком беспокоюсь о форматировании чисел, дат и т. Д., Мне нужно простое решение для простого перевода строк
Вот возможные решения, которые я мог бы придумать:
Каждый компонент выполняет перевод отдельно
Это означает, что каждый компонент имеет, например, набор файлов en.json, fr.json и т. Д. Вместе с переведенными строками. И вспомогательная функция, помогающая читать значения, зависящие от выбранного языка.
- Pro: более уважительно к философии React, каждый компонент является «автономным»
- Минусы: вы не можете централизовать все переводы в файле (например, чтобы кто-то еще добавил новый язык).
- Минусы: вам все равно нужно передавать текущий язык в качестве опоры в каждом кровавом компоненте и их дочерних элементах.
Каждый компонент получает переводы через реквизиты
Таким образом, они не знают текущий язык, они просто принимают список строк в качестве свойств, которые совпадают с текущим языком.
- Плюс: поскольку эти струны идут «сверху», их можно где-то централизовать.
- Минусы: каждый компонент теперь привязан к системе перевода, вы не можете просто использовать его повторно, вам нужно каждый раз указывать правильные строки
Вы немного обходите реквизиты и, возможно, используете контекстную штуку для передачи текущего языка
- Плюсы: в основном прозрачно, не нужно постоянно передавать текущий язык и / или переводы через реквизиты.
- Минусы: выглядит громоздко в использовании.
Если у вас есть другие идеи, пожалуйста, скажите!
Как ты это делаешь?
источник
Ответы:
Попробовав несколько решений, я думаю, что нашел тот, который хорошо работает и должен быть идиоматическим решением для React 0.14 (то есть он не использует миксины, а компоненты более высокого порядка) ( редактировать : также, конечно, отлично подходит для React 15! ).
Итак, вот решение, начиная снизу (отдельные компоненты):
Компонент
Единственное, что понадобится вашему компоненту (по соглашению), это
strings
реквизит. Это должен быть объект, содержащий различные строки, которые нужны вашему Компоненту, но на самом деле его форма зависит от вас.Он действительно содержит переводы по умолчанию, поэтому вы можете использовать компонент в другом месте без необходимости предоставлять какой-либо перевод (он будет работать из коробки с языком по умолчанию, в этом примере английский)
Компонент высшего порядка
В предыдущем фрагменте вы могли заметить это в последней строке:
translate('MyComponent')(MyComponent)
translate
в данном случае это компонент более высокого порядка, который обертывает ваш компонент и предоставляет некоторые дополнительные функции (эта конструкция заменяет миксины предыдущих версий React).Первый аргумент - это ключ, который будет использоваться для поиска переводов в файле перевода (здесь я использовал имя компонента, но это могло быть что угодно). Второй (обратите внимание, что функция каррирована, чтобы позволить декораторам ES7) - это сам Компонент, который нужно обернуть.
Вот код для компонента перевода:
Это не волшебство: он просто считывает текущий язык из контекста (и этот контекст не растекается по всей базе кода, он просто используется здесь в этой оболочке), а затем получит соответствующий объект строки из загруженных файлов. Эта логика довольно наивна в данном примере, может быть реализована так, как вы действительно хотите.
Важным моментом является то, что он берет текущий язык из контекста и преобразует его в строки с учетом предоставленного ключа.
На самом верху иерархии
В корневом компоненте вам просто нужно установить текущий язык из вашего текущего состояния. В следующем примере Redux используется в качестве реализации, подобной Flux, но его можно легко преобразовать с помощью любой другой структуры / шаблона / библиотеки.
И, наконец, файлы перевода:
Файлы перевода
Что, вы парни, думаете?
Я думаю, что это решает всю проблему, которую я пытался избежать в своем вопросе: логика перевода не распространяется на весь исходный код, она достаточно изолирована и позволяет повторно использовать компоненты без нее.
Например, MyComponent не нужно оборачивать с помощью translate (), и он может быть отдельным, что позволяет повторно использовать его любым другим, желающим предоставить
strings
его своими собственными средствами.[Edit: 31/03/2016]: недавно я работал над Retrospective Board (для Agile Retrospectives), созданным с помощью React и Redux, и многоязычным. Поскольку довольно много людей просили в комментариях привести пример из реальной жизни, вот он:
Вы можете найти код здесь: https://github.com/antoinejaussoin/retro-board/tree/master
источник
dangerouslySetInnerHTML
опору, просто помните о последствиях (дезинфицируйте ввод вручную). См. Facebook.github.io/react/tips/dangerously-set-inner-html.htmlconst formStrings = { cancel, create, required }; export default { fooForm: { ...formStrings, foo: 'foo' }, barForm: { ...formStrings, bar: 'bar' } }
По моему опыту, лучший подход - создать состояние редукции i18n и использовать его по многим причинам:
1- Это позволит вам передать начальное значение из базы данных, локального файла или даже из механизма шаблонов, такого как EJS или jade.
2- Когда пользователь меняет язык, вы можете изменить весь язык приложения, даже не обновляя пользовательский интерфейс.
3- Когда пользователь меняет язык, это также позволит вам получить новый язык из API, локального файла или даже из констант.
4- Вы также можете сохранить другие важные вещи с помощью строк, таких как часовой пояс, валюта, направление (RTL / LTR) и список доступных языков.
5- Вы можете определить язык изменения как обычное действие redux
6- Вы можете разместить свои бэкэнд и интерфейсные строки в одном месте, например, в моем случае я использую i18n-node для локализации, и когда пользователь меняет язык пользовательского интерфейса, я просто выполняю обычный вызов API, а в бэкенде я просто возвращаю
i18n.getCatalog(req)
это вернет все пользовательские строки только для текущего языкаМое предложение для начального состояния i18n:
Дополнительные полезные модули для i18n:
1- string-template, это позволит вам вставлять значения между строками вашего каталога, например:
2- человеческий формат этот модуль позволит вам преобразовать число в / из удобочитаемой строки, например:
3- momentjs самая известная библиотека npm даты и времени, вы можете перевести момент, но у нее уже есть встроенный перевод, вам просто нужно передать текущий язык состояния, например:
Обновление (14.06.2019)
В настоящее время существует множество фреймворков, реализующих ту же концепцию с использованием API контекста реакции (без сокращения), я лично рекомендовал I18next
источник
Решение Антуана работает нормально, но с некоторыми оговорками:
Вот почему мы построили Redux-полиглот на вершине как Redux и AirBnB в Полиглот .
(Я один из авторов)
Это обеспечивает :
setLanguage(lang, messages)
getP(state)
селектор , который извлекаетP
объект , который предоставляет 4 методы:t(key)
: исходная функция полиглота Ttc(key)
: перевод с заглавной буквыtu(key)
: перевод заглавными буквамиtm(morphism)(key)
: пользовательский преобразованный переводgetLocale(state)
селектор , чтобы получить текущий языкtranslate
компонент более высокого порядка для улучшения ваших компонентов React путем внедренияp
объекта в реквизитыПростой пример использования:
отправить новый язык:
в компоненте:
Скажите, пожалуйста, если у вас есть вопросы / предложения!
источник
_()
функций, например, чтобы получить все эти строки. Таким образом, вы можете переводить в языковом файле проще и не связываться с сумасшедшими переменными. В некоторых случаях целевым страницам требуется, чтобы определенная часть макета отображалась по-другому. Таким образом, должна быть доступна некоторая умная функция, позволяющая выбрать вариант по умолчанию и другие возможные варианты.Судя по моему исследованию, к i18n в JavaScript, ICU и gettext используются два основных подхода .
Я когда-либо использовал только gettext, поэтому я предвзято.
Что меня поражает, так это то, насколько плохая поддержка. Я пришел из мира PHP, CakePHP или WordPress. В обеих этих ситуациях это базовый стандарт, заключающийся в том, что все строки просто окружены
__('')
, а дальше по строке вы очень легко получаете переводы с использованием файлов PO.Gettext
Вы знакомы с sprintf для форматирования строк, а PO-файлы будут легко переведены тысячами различных агентств.
Есть два популярных варианта:
Оба имеют поддержку стиля gettext, форматирование строк в стиле sprintf и импорт / экспорт в файлы PO.
i18next имеет расширение React, разработанное ими самими. Джед не знает. Sentry.io, похоже, использует пользовательскую интеграцию Jed с React. Сообщение React + Redux предлагает использовать
Однако Jed кажется более ориентированной на gettext реализацией - то есть выраженным намерением, тогда как i18next имеет это просто как вариант.
ICU
Это больше поддерживает крайние случаи, связанные с переводами, например, когда речь идет о гендере. Я думаю, вы увидите преимущества этого, если вам нужно будет переводить на более сложные языки.
Популярным вариантом для этого является messageformat.js . Кратко обсуждается в этом руководстве блога sentry.io . messageformat.js на самом деле разработан тем же человеком, который написал Jed. Он делает довольно резкие заявления об использовании ICU :
Грубое сравнение
gettext с помощью sprintf:
messageformat.js (я догадываюсь, прочитав руководство ):
источник
Если вы еще не сделали этого, посмотрите https://react.i18next.com/, возможно, это будет хорошим советом. Он основан на i18next: учись один раз - переводи везде.
Ваш код будет выглядеть примерно так:
Поставляется с образцами для:
https://github.com/i18next/react-i18next/tree/master/example
Кроме того, вам также следует учитывать рабочий процесс во время разработки, а затем и для ваших переводчиков -> https://www.youtube.com/watch?v=9NOzJhgmyQE
источник
Я хотел бы предложить простое решение с использованием приложения create-react-app .
Приложение будет построено для каждого языка отдельно, поэтому вся логика перевода будет вынесена из приложения.
Веб-сервер будет обслуживать правильный язык автоматически, в зависимости от заголовка Accept-Language , или вручную, установив файл cookie. .
В большинстве случаев мы не меняем язык более одного раза, если вообще меняем)
Данные перевода помещаются в тот же файл компонента, который их использует, вместе со стилями, html и кодом.
И здесь у нас есть полностью независимый компонент, отвечающий за собственное состояние, представление, перевод:
Добавьте переменную языковой среды в свой package.json
Вот и все!
Также мой исходный ответ включал более монолитный подход с одним файлом json для каждого перевода:
языки / ru.json
Lib / lang.js
SRC / App.jsx
источник