[architecture] React / Redux和多語言(國際化)應用程序 - 架構



Answers

根據我的經驗,最好的方法是創建一個i18n的redux狀態並使用它,原因很多:

1-這將允許您從數據庫,本地文件或者模板引擎(如ejs或玉)傳遞初始值

2-當用戶更改語言時,可以更改整個應用程序語言,而無需刷新UI。

3-當用戶改變語言時,這也將允許你從api,本地文件甚至常量中檢索新的語言

4-您還可以保存其他重要的東西,如時區,貨幣,方向(RTL / LTR)和可用語言列表

5-您可以將更改語言定義為正常的還原操作

6-你可以將你的後端和前端字符串放在一個地方,例如在我的情況下,我使用i18n-node進行本地化,當用戶更改ui語言時,我只做一個正常的api調用,在後端我只是返回i18n.getCatalog(req)這將僅返回當前語言的所有用戶字符串

我對國際初始狀態的建議是:

{
  "language":"ar",
  "availableLanguages":[
    {"code":"en","name": "English"},
    {"code":"ar","name":"عربي"}
  ],
  "catalog":[
     "Hello":"مرحباً",
     "Thank You":"شكراً",
     "You have {count} new messages":"لديك {count} رسائل جديدة"
   ],
  "timezone":"",
  "currency":"",
  "direction":"rtl",
}

為i18n增加有用的模塊:

1- string-template這將允許您在您的目錄字符串之間插入值,例如:

import template from "string-template";
const count = 7;
//....
template(i18n.catalog["You have {count} new messages"],{count}) // لديك ٧ رسائل جديدة

2- human-format這個模塊可以讓你將數字轉換成可讀的字符串,例如:

import humanFormat from "human-format";
//...
humanFormat(1337); // => '1.34 k'
// you can pass your own translated scale, e.g: humanFormat(1337,MyScale)

3- momentjs是最著名的日期和時間npm庫,你可以翻譯時間,但它已經有一個內置的翻譯,只需要通過當前狀態語言,例如:

import moment from "moment";

const umoment = moment().locale(i18n.language);
umoment.format('MMMM Do YYYY, h:mm:ss a'); // أيار مايو ٢ ٢٠١٧، ٥:١٩:٥٥ م
Question

我正在構建一個需要以多種語言和區域設置提供的應用程序。

我的問題不純粹是技術性的,而是關於體系結構,以及人們在生產中實際使用的模式來解決這個問題。 我找不到任何“烹飪書”,所以我轉向我最喜歡的Q / A網站:)

這是我的要求(他們真的是“標準”):

  • 用戶可以選擇語言(微不足道)
  • 在改變語言時,界面應該自動翻譯成新的選定語言
  • 我現在不太擔心格式化數字,日期等,我想要一個簡單的解決方案來轉換字符串

以下是我可以想到的可能解決方案:

每個組件都獨立處理翻譯

這意味著每個組件都帶有一組en.json,fr.json等文件以及翻譯後的字符串。 還有一個幫助函數可以幫助讀取取決於所選語言的值。

  • Pro:更尊重React哲學,每個組件都是“獨立的”
  • 缺點:你不能將所有的翻譯集中到一個文件中(例如讓其他人添加一種新的語言)
  • 缺點:你仍然需要通過當前的語言作為道具,在每一個血腥的組件和他們的孩子

每個組件通過道具接收翻譯

所以他們沒有意識到當前的語言,他們只是將字符串列表作為與當前語言匹配的道具

  • Pro:由於這些字符串是“從頂部”來的,它們可以集中在某個地方
  • 缺點:每個組件現在都綁定到翻譯系統中,您不能只重用一個,每次都需要指定正確的字符串

你繞過道具一點,可能使用context thingy來傳遞當前的語言

  • Pro:它大多是透明的,不必一直通過道具傳遞當前的語言和/或翻譯
  • 缺點:使用起來很麻煩

如果您有任何其他想法,請說!

你怎麼做呢?




我想使用create-react-app提出另一個簡單的解決方案。

郎/ ru.json

{"hello": "Привет"}

的package.json

"start": "REACT_APP_LANG=ru npm-run-all -p watch-css start-js",

LIB / lang.js

export default require(`../lang/${process.env.REACT_APP_LANG}.json`);

SRC / App.jsx

import lang from '../lib/lang.js';
console.log(lang.hello);



從我對這方面的研究看來,似乎有兩種主要方法用於JavaScript, ICUgettext

我只用過gettext,所以我很偏向。

令我感到驚訝的是,這種支持有多糟糕。 我來自PHP世界,無論是CakePHP還是WordPress。 在這兩種情況下,這是一個基本標準,所有字符串都被__('')包圍,然後更容易地使用PO文件進行翻譯。

gettext的

您可以熟悉sprintf格式化字符串,PO文件將由成千上萬的不同機構輕鬆轉換。

有兩種流行的選擇:

  1. i18next ,使用此arkency.com博客文章中描述的用法
  2. Jed ,用sentry.io文章和這個React + Redux文章描述的用法,

兩者都支持gettext風格,sprintf風格的字符串格式以及導入/導出到PO文件。

i18next有自己開發的React擴展 。 傑德沒有。 Sentry.io似乎使用了Jed與React的自定義集成。 React + Redux後 ,建議使用

工具:jed + po2json + jsxgettext

然而,傑德看起來像一個更強調gettext的實現 - 這是它表達的意圖,其中i18next只是它的一個選項。

ICU

這對翻譯方面的邊緣案例有更多的支持,例如處理性別問題。 如果你有更複雜的語言可以翻譯成英文,我認為你會看到這方面的好處。

一個流行的選擇是messageformat.js 。 在此sentry.io博客教程中簡要討論。 messageformat.js實際上是由寫Jed的同一個人開發的。 他對使用ICU提出了相當強烈的要求

傑德在我看來功能完整。 我很樂意修復錯誤,但一般不會對向庫中添加更多內容感興趣。

我也維護messageformat.js。 如果您不特別需要gettext實現,我可能會建議使用MessageFormat,因為它更好地支持複數/性別並具有內置區域設置數據。

粗略比較

帶sprintf的gettext:

i18next.t('Hello world!');
i18next.t(
    'The first 4 letters of the english alphabet are: %s, %s, %s and %s', 
    { postProcess: 'sprintf', sprintf: ['a', 'b', 'c', 'd'] }
);

messageformat.js(閱讀guide最佳猜測):

mf.compile('Hello world!')();
mf.compile(
    'The first 4 letters of the english alphabet are: {s1}, {s2}, {s3} and {s4}'
)({ s1: 'a', s2: 'b', s3: 'c', s4: 'd' });





Related