React项目国际化-React-intl
import {IntlProvider} from "react-intl"; ReactDOM.render( <React.StrictMode> <IntlProvider locale='en-us'> <App /> </IntlProvider> </React.StrictMode>, document.getElementById('root') );
怎么翻译项目中的文本?翻译文件放到什么地方?通常来说,会为每一种语言提供一个翻译文件(json文件),src/translations/zh.json提供中文翻译 . en.json file 提供英文翻译。假设要翻译App.js中的内容,src/translations/en.json
{ "app.learn-react-link": "Learn React.", "app.text": "Edit <code>src/App.js</code> and save to reload." }
src/translations/zh.json
{ "app.learn-react-link": "学习 React.", "app.text": "编辑<code>src/App.js</code>,保存,并刷新页面" }
项目中怎么获取到翻译文件? <IntlProvider />有messages属性, 把locale设置的语言对应的翻译内容,传给它,就可以为项目提供翻译内容。比如locale是en-us,那就要把en.json中的翻译内容传递给messsages. locale是zh-cn,那就把zh.json中的翻译内容传递给messages。怎么传递,只能先把json文件引入到项目中,再构建一个以locale为属性,翻译内容为值的对象,让messages的值根据locale来定。index.js中
import zh from './translations/zh.json'; import en from './translations/en.json'; const messages = { 'en-us': en, 'zh-cn': zh } const locale = 'zh-cn'; ReactDOM.render( <React.StrictMode> <IntlProvider locale={locale} messages={messages[locale]}> <App /> </IntlProvider> </React.StrictMode>, document.getElementById('root') );
组件中怎么使用翻译内容?最简单的方法就是把要翻译的文本使用<FormattedMessage> 组件来代替。组件有一个必传属性id,用来引用翻译文件。怎么理解id呢?IntlProvider 的messages属性实际上是一个js对象,包含着项目中每一句文本的翻译,格式为{"app.learn-react-link": "学习 React."},"app.learn-react-link"可以看作组件中使用翻译时引用的id,react-intl自动会引用id 对应的翻译好的文本。<FormattedMessage> 中的id就是引用的这个id,也就是说,id必须和messages中指向json文件中的id一致。App.js
import {FormattedMessage} from 'react-intl'; <p><FormattedMessage id="app.text" /></p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer"> <FormattedMessage id="app.learn-react-link" /> </a>
npm start, 可以看到项目已经翻译成中文了。能不能把<code> 去掉呢?FormattedMessage 可以在value属性中解析出富文本中的XML标签。FormattedMessage 有一个value属性
<FormattedMessage id="app.text" values={{ code: chunks => <code>{chunks}</code> }} > </FormattedMessage>
code对应的就是app.text中的<code></code>标签, 要解析富文本中的哪个标签,属性就是哪个标签。chunks就可解析出标签中的的内容,在这里就是code标签中的内容,src/App.js, 返回值就是替换整个标签及内容。但此时有个问题,如果有一种语言,恰好没有翻译呢?比如把locale改成en,
const locale = 'en';
页面就只显示app.text和app.learn-react-link 等Id
这时要用<FormattedMessage />的defaultMessage属性,设置默认展示的文本。 如果此文本没有在翻译文件中找到,就显示默认文本。它还有一个description: 描述这个文本的作用,主要为翻译者提供上下文。
<FormattedMessage id="app.text" values={{ code: chunks => <code>{chunks}</code> }} defaultMessage="编辑<code>src/App.js</code>,保存,并刷新页面" description="edit text" > <FormattedMessage id="app.learn-react-link" defaultMessage="学习 React." description="text link" />
import React from 'react'; import { useIntl } from 'react-intl'; export function Input() { const intl = useIntl(); const placeholder = intl.formatMessage({id: 'app.placeholder'}) return <input placeholder={placeholder}></input> }
引入useIntl,在组件中调用它,返回intl上下文,调用formatMessage方法,它接受一个对象作为参数,id属性就是对应翻译文件中的id。不要忘了在,json文件中写
"app.placeholder": "请输入数字"
当然,id属性可以是动态生成的,比如
const intlKey = "something" const placeholder = intl.formatMessage({ id: `${intlKey}` })
import { defineMessages } from 'react-intl' export default defineMessages({ text: { id: 'app.text', defaultMessage: 'Edit <code>src/App.js</code>' }, link: { id: 'app.learn-react-link', defaultMessage: 'Lerne React', description: 'Link on react page' },
});
<FormattedMessage /> and formatMessage()就可以使用message.js中定义的text和link。App.js
import messages from './message.js' import { FormattedMessage } from 'react-intl' <p> <FormattedMessage {...messages.text} values={{ code: chunks => <code>{chunks}</code> }} > </FormattedMessage> </p> <a className="App-link" href="https://reactjs.org" target="_blank" > <FormattedMessage {...messages.link} /> </a>
Input.js
import { useIntl } from 'react-intl'; import messages from './message' export function Input() { const intl = useIntl(); const placeholder = intl.formatMessage(messages.placeholder) return <input placeholder={placeholder}></input> }
如果不能使用useIntl hooks, 在普通函数或类组件中可以使用injectIntl函数提供intl上下文。Input.js
import React from 'react'; import messages from './message.js' import { injectIntl } from 'react-intl' function Input({intl}) { const placeholder = intl.formatMessage(messages.placeholder) return <input placeholder={placeholder}></input> } export default injectIntl(Input);
使用类
import React from 'react'; import messages from './message.js' import { injectIntl } from 'react-intl' class Input extends React.Component { render() { const {intl} = this.props; const placeholder = intl.formatMessage(messages.placeholder) return <input placeholder={placeholder}></input> } } export default injectIntl(Input);