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

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

本文讲解如何使用 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 的一些入门用法。

责任编辑:姜华 来源: 前端西瓜哥
相关推荐

2024-05-17 08:25:06

数据驱动React语言包

2024-01-17 10:16:22

前端国际化消息键

2023-01-31 10:29:26

JavaScript国际化国际化库

2010-01-04 13:09:51

Silverlight

2017-01-09 16:24:07

滴滴Android 端 App

2009-12-29 15:05:29

WPF支持国际化

2011-08-11 13:26:30

iPhoneNSLocalized

2011-08-18 15:24:40

iPhone国际化

2011-07-20 14:53:28

iPhone NSLocalize 国际化

2009-01-19 09:06:31

gettextPHP国际化编程

2023-07-07 07:22:13

ReactProfiler

2023-07-04 07:30:35

React开发样式

2011-07-08 11:13:42

Cocoa Touch XCode

2024-04-03 13:27:28

Next.js扩展项目

2020-03-11 20:38:13

JavaScript前端工具

2020-09-16 14:39:13

ReactJavaScript框架

2016-09-20 12:49:29

2018-05-24 15:19:19

AWS创业云服务

2021-05-17 10:13:24

iOS名词复数开发

2011-08-19 13:13:14

struts2Java
点赞
收藏

51CTO技术栈公众号