國際化對於某些大型公司很常見的業務,他們基本也都有本身的一套國際化規範,但對於小公司而言可能並無這些需求,平時也不太注重。若是有需求,一般解決的方法就是使用 react-intl
,react-i18next
等一些現有的npm包。如下是我大體瞭解的方案,以react-intl
爲例,以下:node
參考文檔:react-intl 國際化 文檔指引react
import React, {Component} from 'react'; import ReactDOM from 'react-dom'; import {IntlProvider, FormattedMessage} from 'react-intl'; ... ReactDOM.render( <IntlProvider locale="en"> <App /> </IntlProvider>, document.getElementById('container') );)
App.jswebpack
import {FormattedMessage} from 'react-intl'; ... class App extends Component { constructor(props) { super(props); this.state = { name: 'Eric', unreadCount: 1000, }; } render() { const {name, unreadCount} = this.state; return <p> <FormattedMessage id="welcome" defaultMessage={ `Hello {name}, you have {unreadCount, number} {unreadCount, plural, one {message} other {messages}}` } values={{name: <b>{name}</b>, unreadCount}}/> </p> } }
看出來了嗎?若是你沒有學習過,你根本不會知道上面的屬性表明着什麼,這樣的國際化已經變了原有的頁面結構,並且每用到一處就得改動對應的代碼,及其繁瑣。git
import React, {Component} from 'react'; import locale from './resources/locale'; import t from 'xxx'; ... class App extends Component { render() { return <div> <header>{ t.i18n('我是要翻譯的內容') }</header> <div>{ t.text(locale.a.b) }</div> //這是我另外一處要翻譯的內容 </div> } }
// resources語言包結構 const locale = { a:{ b:'這是我另外一處要翻譯的內容', c:'ccc', d:'xxx', ... } ... }
這是經過函數調用的思路來實現的,這種不會對react
的層級結構有太大影響,也相對靈活,其痛點在於語言包文件管理時命名讓人很頭痛,幾十個翻譯字段還好。想想你有個項目有幾千個翻譯字段,並且仍是一個老項目,一個個字段取名,而後在翻譯到對應的頁面上,香不香?這種方法不只有可能會遺漏,還可能會出錯。github
對於目前已有的國際化方案,先拋開學習成本不說,立立刻手,作一個國際化項目大概須要多久呢?一天?一週?仍是一個月?,個人答案是基本在一週以上,對於緊急的項目時間是極其重要的。web
因爲現有的國際化方案都極其繁瑣、枯燥,且隨着項目的進展愈來愈難以維護,尤爲是對於多人開發的大型項目。既然不盡如人意,咱們不妨探討一下方便快速的國際化方案。npm
對於國際化這種重複性的工做,最合適的就是自動化,一切交給程序來解決,豈不是更香?segmentfault
自動化的大體思路就是經過代碼自動實現上面的方案二,具體作法:babel
爲了實現自動化,最早想到的是webpack,網上搜索了一遍發現並無現成的工具可用,只能本身手寫一個插件,學習了一番怎麼寫插件以後,發現webpack文檔並無面面俱到,都只給你個大概,想了解更詳細的信息只能本身去看源碼,學習成本陡然增長。dom
ps:學習無果以後,我還試着想能不能經過正則來實現呢,都是字符串處理啊。想一想仍是太天真了,這估計和寫個js解析引擎也差很少了。
因爲webpack的構建都是基於babel實現的,直接擼一個babel插件是否是會更好呢?因而着手學習babel,發現文檔更齊全,更加規範。學習babel以前,要先了解AST語法樹請參考:AST Explorer(https://astexplorer.net),AST很早以前就有了,但不多用於普通開發者,直到nodejs
,react
,webpack
等技術的興起,才被普遍使用。
babel根據AST規範將咱們的js代碼解析成樹狀結構,如同咱們常見的dom樹同樣,用不一樣的標籤,表示不一樣的語義。AST則定義了不一樣的類型來表示不一樣js代碼的語義,具體可參考@babel/typesAPI,列出了全部已實現的語法類型及其用法。
關於babel的更多詳細解析請移步至:剖析 Babel——Babel 總覽 http://www.alloyteam.com/2017/04/analysis-of-babel-babel-overview/
有了babel的認知基礎以後咱們就能夠開始寫babel插件了。它可以原子級別的控制咱們的代碼,輕鬆實現咱們想要的功能。
export default function() { return { visitor: { Identifier(path) { // 全部類型爲Identifier的AST樹,都會經過此方法進行處理 const name = path.node.name; // reverse the name: JavaScript -> tpircSavaJ // 編譯前 var JavaScript; // 編譯後 var tpircSavaJ; path.node.name = name .split("") .reverse() .join(""); }, StringLiteral(path) { // 處理StringLiteral(字符串)類型 let {node} = path; ... }, }, }; }
實現方式:react國際化自動化插件 react-i18n-auto
使用安裝
npm install react-i18n-auto --save-dev
添加babel插件配置項
{ "plugins": [ ... "react-i18n-auto" ... ] }
編譯前效果:
export default class App extends React.Comment{ render(){ let title = '這是翻譯的文字' return <div title={title}> <div title='這是要翻譯的標題'> 我是要翻譯的內容 </div> </div> } }
編譯後效果:
export default class App extends React.Comment{ render(){ let title = $T('aa8ds','這是翻譯的文字') return <div title={title}> <div title={$T('see23','這是要翻譯的標題')}> {$T('ae22s','我是要翻譯的內容')} </div> </div> } }
自動生成的語言包配置
locale.js
export let locale = { "aa8ds":"這是翻譯的文字", "see23":"這是要翻譯的標題", "ae22s":"我是要翻譯的內容", }
react-i18n-auto實現了對源碼的無污染,開發時無感知,隻影響打包後的代碼,實現所有自動化。只需將locale.js翻譯成對應的語言包文件,根據語言加載對應的語言包便可。對於React項目可實現快速完成國際化開發任務。
更多使用詳情請參考:react-i18n-auto github主頁