React-Intl,实现 React 项目的前端国际化

React 项目默认你已经搭建好了。可以用过气的 CRA,流行的 vite,或者用 React 推荐的 Next.js。

React 项目默认你已经搭建好了。可以用过气的 CRA,流行的 vite,或者用 React 推荐的 Next.js。

React-Intl,实现 React 项目的前端国际化

本文讲解如何使用 React-Intl 库给你的 React 应用做国际化。

安装

React 项目默认你已经搭建好了。可以用过气的 CRA,流行的 vite,或者用 React 推荐的 Next.js。

安装 React-Intl。

npm i -S react-intl

或者用 yarn。

yarn add react-intl

使用

接着我们需要将国际化能力注入到 React 应用中。

使用的是经典的 context 上下文方案:

const root = ReactDOM.createRoot(
document.getElementById('root')
);

root.render(
<IntlProvider locale={locale} messages={messageMap[locale]}>
<App />
</IntlProvider>
);

IntlProvider 是一个 context.provider 组件,用来注入一些国际化需要的信息。其中最重要的信息是 locale 和 messages。

locale 是一个字符串,代表一个语言标识,使用了 BCP 47 语言标记规范。比如中文用​​zh​​​,英文用​​en​​​,简体用​​zh-CN​​。

标识符是会提供给浏览器自带的 Intl 对象使用的,Intl 对象的方法会通过它确定如何做转换,比如不同国家数字的分隔符是不同的。

图片

可以看到,原点、逗号、空格,什么都有。所以你要传一个正确的语言标识符。

messages就简单多了,就是一个 id 到 value 的映射,组件中传一个 id,就能拿到对应的语言文案了。比如

const zh = {
'command.undo': '撤销',
'command.redo': '重做',
'arrange.forward': '上移一层',
'arrange.backward': '下移一层',
'arrange.front': '移到顶部',
'arrange.back': '移到底部',
'zoom.zoomIn': '放大',
'zoom.zoomOut': '缩小'
};

const en = {
'command.undo': 'Undo',
'command.redo': 'Redo',
'arrange.forward': 'Forward',
'arrange.backward': 'Backward',
'arrange.front': 'Bring to Front',
'arrange.back': 'Send to Back',
'zoom.zoomIn': 'Zoom In',
'zoom.zoomOut': 'zoom Out',
};

更具体的引入写法:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { IntlProvider } from 'react-intl';
import { zh } from './locale/zh';
import { en } from './locale/en';

const messageMap = {
zh,
en,
};

const getLocale = () => {
const locale = navigator.language;
return locale.startsWith('zh') ? 'zh' : 'en'; // en 是兜底语言
};
const locale = getLocale();

const root = ReactDOM.createRoot(
document.getElementById('root')
);
root.render(
<IntlProvider locale={locale} messages={messageMap[locale]}>
<App />
</IntlProvider>
);

  1. 计算一个语言标识符,因为网站支持的语言可能就两三种,当用户客户端的语言不在范围内时,给一个兜底的。
  2. 确认语言后,找出对应的 messages 对象。

然后是一些其他的点:如果语言很多,可以考虑做语言包懒加载。另外还要做用户修改语言后,更新 locale 和 messages props。

组件

然后是在业务组件中使用国际化文案。

最常用的就是 FormattedMessage 组件了,给 id props 提供 id 即可。

<FormattedMessage id="command.undo" />

如果你需要得到文案字符串,传入到一些组件中,比如 tooltip,你可以用主流的 hook 写法:

import { useIntl } from 'react-intl';

const intl = useIntl();

<ToolBtn tooltipCnotallow={intl.formatMessage({ id: 'tool.select' })}><IconSelect /></ToolBtn>

或者可以用 HOC(高阶组件),我没用过,我不写类组件。

类型安全

如果你用 TypeScript,你会希望传入的 id 是有类型的,反正写错 id。React-Intl 提供了全局类型的设置。你只需要这样写:

import { en } from './locale/en';
import { zh } from './locale/zh';


declare global {
namespace FormatjsIntl {
interface Message {
ids: (keyof typeof zh) & (keyof typeof en)
}
}
}

keyof typeof zh就是将中文 message 对象的 key 提取为一个联合类型。

这里我巧妙地用了一个 & 交叉类型,这样不在二者 id 的交集内的 key 会被排除在外,防止使用一个没有在所有语言中都被定义的 id。

locale 也可以设置类型,防止错误设置一些不支持的语言标识。如下:

declare global {
namespace FormatjsIntl {
interface IntlConfig {
locale: 'en' | 'zh'
}
}
}

可能你希望 en 和 zh 的 key 要一致,我这里想到一个比较巧妙的做法。en 作为兜底语言,用 typeof 拿到类型,作为其他语言的类型,防止 id 漏写。

const en = {
'delete': 'Delete',
}

// zh 对象的类型是 typeof en
const zh: (typeof en) = {
'delete': '删除',
}

message 不支持嵌套

React-Intl 的 message 是不支持嵌套的。

你可以这样写:

const zh = {
'command.undo': '撤销',
'command.redo': '重做',
}

但不能这样写:

const zh = {
'command': {
'undo': '撤销',
'redo': '重做',
}
}

这个我是支持的。

嵌套并无必要,我们加前缀就好了,并且方便全局搜索,能够快速定义一个国际化 id 的文本位置。类似 Vue 框架会做大量的驼峰和连线符的变换,全局搜索非常不友好,我不喜欢。

如果你喜欢嵌套的风格,可以考虑写一些脚本,支持将嵌套的转换为拍平格式。

结尾

以上是 React-Intl 的一些入门用法。

©本文为清一色官方代发,观点仅代表作者本人,与清一色无关。清一色对文中陈述、观点判断保持中立,不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。本文不作为投资理财建议,请读者仅作参考,并请自行承担全部责任。文中部分文字/图片/视频/音频等来源于网络,如侵犯到著作权人的权利,请与我们联系(微信/QQ:1074760229)。转载请注明出处:清一色财经

(0)
打赏 微信扫码打赏 微信扫码打赏 支付宝扫码打赏 支付宝扫码打赏
清一色的头像清一色管理团队
上一篇 2023年5月7日 00:54
下一篇 2023年5月7日 00:54

相关推荐

发表评论

登录后才能评论

联系我们

在线咨询:1643011589-QQbutton

手机:13798586780

QQ/微信:1074760229

QQ群:551893940

工作时间:工作日9:00-18:00,节假日休息

关注微信