react
的國際化方案,能夠說是十分紅熟了。react
react-intl
一用上,文本,日期、貨幣通通搞定。git
這裏想和你們交流的並非如何使用 react-intl
,抑或如何在 redux
框架中去使用。github
而是一個小知識,如何在 placeholder
等屬性中支持多語言,而且你只需按照 react-intl
的方式去維護多套語言庫。redux
由於像 placeholder
, title
這種 HTML
自帶的屬性,組件庫向來都是直接支持的,那麼問題來了,使用 react-intl
中的 <FormattedMessage />
做爲一個 Object
是沒法用到這些屬性中去的,那麼咱們應該怎麼去處理這個問題呢?框架
下面先說幾個我搜索到的方法。dom
injectIntl()
是官方推薦的方法。<FormattedMessage />
的回調方法。以上兩種方法均可以在這個issue中找到。ide
兩種方式的實現原理很清晰。函數
方法一,強調使用高階組件來處理這個問題,將 intl
注入到組件的 props
中,最後使用 intl.formatMessage
來解決問題。學習
方法二,很巧妙的利用到了 <FormattedMessage />
組件的返回值,函數式的渲染了自身的子組件。this
這兩種思路當然都有可取之處,可是也有相應的問題。
injectIntl()
若是沒有從全局層面出發,去封裝的這種只是用於渲染的高階組件,帶來的成本,可想而知。
舉個例子,咱們有時候會封裝一些本身的基礎業務組件 BaseApp
,他們自己並無render方法,在不一樣權限的客戶訪問時,實現不一樣的派生類( StaffApp
, CustomerApp
),對基礎業務組件進行調用。
class BaseApp extends Component {
renderPersonInfo() {}
renderDataAnalytical() {}
renderTasks() {}
}
class StaffApp extends BaseApp {
render() {
return (
{
this.renderPersonInfo(),
this.renderDataAnalytical()
}
)
}
}
class CustomerApp extends BaseApp {
render() {
return (
{
this.renderPersonInfo(),
this.renderTasks()
}
)
}
}
複製代碼
假設這個時候咱們對 BaseApp
進行 injectIntl
,那麼本來能夠繼承的方法,就所有失效了。因此咱們必須對派生類進行 injectIntl
, 至關於,原本要作一次的事情,作了 N
次。
固然,咱們能夠把 BaseApp
中用到 placeholder
的組件,單獨的抽出來,進行 injectIntl
,不失爲一種解決方案。
因此雖然 injectIntl
是把好刀,可是用得好,用很差,就要看本身對整個項目的理解了。
拋開這麼寫,究竟是否優美不談。
最大的問題,仍是帶來了沒必要要的 dom
結構,由於 <FormattedMessage />
組件是會渲染 <span />
標籤的。
想象下你的 input
組件外面還包了一個 span
是否是瑟瑟發抖呢。
基於上述狀況,我認爲以上兩種方法,不太適合目前的項目,那就是要本身造輪子啦。
開心,又能夠本身造輪子啦。
先亮代碼
const intl = {
lang: {}
};
intl.formatMessage = (props) => {
let message = intl.lang[props.id] || props.defaultMessage || props.id;
if (!props.values) return message;
const keys = Object.keys(props.values);
for (let i = 0, l = keys.length; i < l; i++) {
const key = keys[i];
message = message.replace(new RegExp(`{${key}}`, "g"), props.values[key]);
}
return message;
}
export default intl;
複製代碼
原理比較簡單,兩步。
程序初始化的時候,對 intl.lang
賦值,同 react-intl
。
利用 props
中的 id
和 values
屬性,獲取值並進行替換,返回真正的值。
使用方法:
<Input
value={showName}
// placeholder="支持(1-10)位中文、英文與數字"
placeholder={intl.formatMessage({id: "intl.showName.placeholder"})}
onChange={this.handleNameChange.bind(this)}
/>
複製代碼
-----------------------分割線-----------------------
粘貼一段項目中的實現
redux Provider
和 react-intl IntlProvider
並無衝突,能夠直接嵌套使用。
動態切換語言,我這裏的思路是把ReactDOM.render
抽成一個方法,切換的使用再次調用就能夠了。僅供參考,可能有更好的思路。
效果:
圖中部分字段還未翻譯,故切換時沒有變動。