前情提要:昨天大略說明了一下react-intl有哪些功用,今天就來把訊息字串換成多國語言吧!
很老套的先安裝react-intl
yarn add react-intl
import React from 'react';
import { connect } from 'react-redux';
import { addLocaleData, IntlProvider } from "react-intl";
import en from "react-intl/locale-data/en";
import zh from "react-intl/locale-data/zh";
import ja from "react-intl/locale-data/ja";
addLocaleData([...en, ...zh, ...ja]);
import RootRouter from "./router";
const Intl = ({locale, messages}) => {
return (
<IntlProvider key={locale} locale={locale} messages={messages}>
<RootRouter />
</IntlProvider>
);
};
export default connect(({lang: { locale, messages }}) => (
{ locale, messages }
))(Intl);
因為和todoList與news資料完全不同,所以在combieReducers新增lang
import langReducer from './lang_reducer';
const rootReducer = combineReducers({
// ...
lang: langReducer
});
// ...
lang_reducers.js內容,這邊的zhMessages內容就是自己設定的各語系訊息
// ...
import zhMessages from "../lang/zh";
export default function(state = {
locale: "zh",
messages: zhMessages
}, action) {
switch (action.type) {
case CHANGE_LANG:
return { ...mapLang(action.lang) }
default:
return state;
}
}
messages內容會是這樣:
之後就是透過key值去取對應的value顯示
const zh = {
home: "首頁",
todos: "待辦事項",
news: "新聞",
// ...
};
const en = {
home: "Home",
todos: "Todos",
news: "News",
// ...
};
const ja = {
home: "ホームページ",
todos: "ToDoリスト",
news: "ニュース",
// ...
}
import { FormattedMessage } from "react-intl";
<FormattedMessage id="heading" description="heading" />
值得一提的是有個調整需要改select內option的value,因為option內只能是純文字,所以使用了injectIntl,把intl作為props匯入,使用方式會換成formatMessage({ id: "xxx", description: "xxx" })
,如下:
import React from "react";
import { injectIntl } from "react-intl";
const OPTIONS = [
{ value: "", textId: "defaultOption", attr: { disabled: "disabled" } },
{ value: "tw", textId: "tw" },
{ value: "jp", textId: "jp" },
{ value: "us", textId: "usa" }
];
const NewsSelect = ({ country, fetchNews, intl: { formatMessage } }) => {
return (
<div className="news-selection">
<form className="vertical-center">
<label htmlFor="newsCountry" className="news-selection-label">
{formatMessage({ id: "topHeadlines" })}
</label>
<select
className="news-selection-select"
name="country"
id="newsCountry"
onChange={e => fetchNews(e.target.value)}
value={country}
>
{OPTIONS.map(({ value, textId: id, attr }, index) => (
<option key={index} value={value} {...attr}>
{formatMessage({ id })}
</option>
))}
</select>
</form>
</div>
);
};
export default injectIntl(NewsSelect);
因為只替換訊息有點寂寞,所以在很空的Home頁加上FormattedTime和FormattedDate顯示目前時間和日期
import { FormattedMessage, FormattedTime, FormattedDate } from "react-intl";
const Home = () => {
return (
// ...
<FormattedDate value={new Date()}/>
<FormattedTime value={new Date()}/>
//...
);
};
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import { changeLang } from '../actions';
class Lang extends PureComponent {
constructor(props) {
super(props);
this.state = {
showOptionFlag: false
}
this.toggleOptions = this.toggleOptions.bind(this);
}
toggleOptions() {
this.setState({showOptionFlag: !this.state.showOptionFlag});
}
handleLang(lang) {
this.props.changeLang(lang);
this.setState({showOptionFlag: false})
}
render() {
let showOption = this.state.showOptionFlag ? {display: "flex"} : {display: "none"}
return (
<div className="lang" >
<span onClick={this.toggleOptions}>Language</span>
<ul className="lang-options" style={showOption}>
<li className="icon icon-taiwan" onClick={() => this.handleLang('zh')}></li>
<li className="icon icon-japan" onClick={() => this.handleLang('ja')}></li>
<li className="icon icon-us" onClick={() => this.handleLang('en')}></li>
</ul>
</div>
);
}
}
export default connect(null, { changeLang })(Lang);
其他細節部分如果有興趣的客倌可以去github看看
實際操作如下:
本日總結:
使用react-intl最困難的地方大概就是翻譯了吧~!
其他只要參考API就可以順利達成目標了。