提起React項目國際化,首先想到著名的 react-intl 庫,這個庫提供了針對組件、日期、數字、字符串等多種國際化方法。使用方法也很簡單:javascript
將不一樣語言的翻譯文件放在各自的js文件中,同一處文本的多種語言翻譯使用相同的key前端
// en_US.js
const en_US = {
"intl_hello": "Hello!",
}
export default en_US;
// zh_CN.js
const zh_CN = {
"intl_hello": "你好!",
}
export default zh_CN;
複製代碼
在入口文件中配置 react-intl 庫java
// index.js
import { addLocaleData, IntlProvider } from 'react-intl';
// 引入多語言環境
import en from 'react-intl/locale-data/en';
import zh from 'react-intl/locale-data/zh';
addLocaleData([...en, ...zh]);
// 引入翻譯文本
import en_US from '.../intl/en_US.js';
import zh_CN from '.../intl/zh_CN.js';
const messagesMap = {
en: en_US,
zh: zh_CN
}
const locale = 'zh'; // 此處作了簡化,下文將從redux中獲取語言環境
render((
// 使用<IntlProvicer>包裝項目組件,配置語言環境和翻譯文本
<IntlProvider locale={local} messages={messages[local]}>
//···
</IntlProvider>
), document.getElementById("root"));
複製代碼
使用 react-intl 中內置的組件或方法替換須要作多語言的字符串、時間等,具體可參考 API文檔。react
因爲項目使用redux來管理狀態,將語言環境與翻譯文本都放入reducer中,使用相關action來觸發語言切換:git
// actions.js
export const switchLocal = local => ({
type: 'SWITCH_INTL_LOCAL',
payload: { local },
});
// reducers.js
import en_US from '.../intl/en_US.js';
import zh_CN from '.../intl/zh_CN.js';
const messagesMap = {
en: en_US,
zh: zh_CN
}
const defaultLocal = { //默認語言環境,也可從瀏覽器或用戶配置數據中獲取
local: 'zh',
messages: messagesMap.zh
};
export const intlLocal = (state=defaultLocal, action) => {
switch(action.type) {
case 'SWITCH_INTL_LOCAL':
return {
local: action.payload.local,
messages: messagesMap[action.payload.local],
}
default:
return state;
}
}
// index.js
// 略去了文件中的redux配置等代碼
const { local, messages } = store.getState().intlLocal; // 從store中獲取語言配置
render((
// react-redux中的Provider須要包在IntlProvider以外,IntlProvider才能訪問到store
<Provider store={store}>
<IntlProvider locale={local} messages={messages}>
//···
</IntlProvider>
</Provider>
), document.getElementById("root"));
複製代碼
完成以後發現初始化的時候能夠訪問到store,使用指定的默認語言環境,但切換語言無效,排查後發現觸發action後reducer確實更改了,但沒有觸發組件更新。查閱相關文檔後,使用react內部的key屬性來強制觸發更新:github
// index.js
render((
<Provider store={store}> // 加入key屬性來強制觸發更新 <IntlProvider key={local} locale={local} messages={messages}> //··· </IntlProvider> </Provider>
), document.getElementById("root"));
複製代碼
在上一步中使用key來強制觸發更新,對於通常簡單的網站或前端系統來講,到這一步就能夠了。web
萬惡的可是,因爲接手的系統過於複雜,使用key強制觸發組件更新時,會引發此<IntlProvider>
包裹下的全部組件所有被更新,致使相似於頁面總體被刷新的效果,從而出現websocket重連、數據丟失等一系列問題,因爲不便於動用其餘模塊,思考事後剩下兩種方案:redux
<FormattedMessage>
組件,使用的時候又發現只能用於組件的侷限性,又參考阿里的 react-intl-universal ,寫了個直接由key生成翻譯文本的方法。而這個方案目前還在完善和測試中。