1.antd组件国际化配置
因为我们的项目依赖于 antd 组件库,所以我们先进行antd的国际化配置 antd官网
import zhCN from 'antd/locale/zh_CN';
// for date-picker i18n
import 'dayjs/locale/zh-cn';
return (
<ConfigProvider locale={zhCN}>
<App />
</ConfigProvider>
);
注意:这里的配置仅对 antd 组件预先设计好的文字生效,对我们自己定义的文字不起任何作用。所以之后我们会使用 react-int 对自己定义的文本进行国际化配置(antd的国际化配置和react-intl进行国际化配置无任何联系,请不要搞混淆了)
2.react-intl基本配置
1.首先下载 react-intl 包
npm install react-intl
#或者
yarn add react-intl
npm install intl //用于兼容性
在现代浏览器环境中,大多数已经内置了国际化 API,因此你可以在大多数情况下不需要下载 intl 包。然而,如果你需要支持一些旧的浏览器(比如 IE 11),则可能需要下载 npm install intl
注意: 要实现 intl 包对旧版本浏览器做兼容,只需要下载,然后在项目入口文件中引入就好,无需写任何代码和任何配置就可以实现低版本浏览器兼容
下面是一个详细的说明,说明如何在项目中引入 intl 以确保在低版本浏览器中的兼容性:
1. 安装 intl 包
npm install intl
import 'intl'; // 入口文件中导入 intl 用于兼容低版本浏览器
import 'locale-data/jsonp/en'; // 如果你的项目中使用了不同的语言,需要引入相应的语言包
import 'locale-data/jsonp/zh'; // 引入中文语言包
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
// 你项目的其他代码...
2.创建语言包en.json 和 zh.json文件(这里只对中英文切换做演示)
{
"app.greeting": "Hello, World!",
"hello":"hello"
}
{
"app.greeting": "你好,世界!",
"hello":"你好"
}
注意:json文件中的key必须是唯一的,否则会报错;再者两个文件中的key必须保持相同,这样才能实现文字的切换,最后,两个json文件中的数据条数必须保持一致,以避免程序出现错误
3.在App根组件中对react-intl进行配置
import React from 'react';
import ReactDOM from 'react-dom';
// import 'intl'; // 如果需要兼容低版本浏览器,可以在此导入 intl 用于兼容低版本浏览器
import { IntlProvider } from 'react-intl';
import App from './App';
import enMessages from './locales/en.json';
import zhMessages from './locales/zh.json';
const messages = {
en: enMessages,
zh: zhMessages
};
const language = navigator.language.split(/[-_]/)[0]; // 根据浏览器语言设置语言
// 为了减少代码的复杂度,这里没有将antd国际化一同在这配置,实际开发中记得另外配置antd的国际化
ReactDOM.render(
<IntlProvider locale={language} messages={messages[language]}>
<App />
</IntlProvider>,
document.getElementById('root')
);
这里对上面代码进行一个简单的解释:
1、import enMessages from './locales/en.json';import zhMessages from './locales/zh.json';这行代码导入的是本地的json文件,这里这个文件是需要自己去建立的,具体文件名称和位置可以随意配置,但是文件格式必须为json
2、navigator.language.split(/[-_]/)[0] ;这行代码获取的是浏览器的语言,实际开发中建议不要怎么操作,使用localStorge存储在本地会更加方便
3.react-intl的使用
当我们按照上方代码配置完毕后,我们就可以到组件中去使用他了,下面将讲解react-intl的几种使用方式
1.基本使用
//直接将此段代码替换你的文本即可,id则为自定义json文件中对应的
// defaultMessage 相当于一个默认值属性,当id对应的key缺失时,
//就会自动使用defaultMessage的值作为填充(这个属性可不配置)
<FormattedMessage id="app.greeting" defaultMessage="Hello, World!" />
//注意:这里的id和html中的id无任何联系,不会引起冲突,这里的id仅用于做国际化的标识
//编译后id将不会存在,无需有任何担心
案例
//未进行国际化配置
<Button type="primary">Primary Button</Button>
<p>我是一名程序猿</p>
//配置国际化后
import React from 'react';
import { FormattedMessage } from 'react-intl';
const Greeting = () => (
<div>
<Button type="primary">
<FormattedMessage id="此次替换为你在json文件中定义的key" defaultMessage="Hello, World!" />
</Button>
<p>
{// defaultMessage 属性可以不配置}
<FormattedMessage id="此次替换为你在json文件中定义的key" />
</p>
</div>
);
export default Greeting;
2.高级使用
1.消息模板语法
// json文件定义
{
"welcomeMessage":"欢迎使用我们的应用!""count":"计数:{change}",
"primaryButton":"主按钮",
"defaultButton":"默认按钮",
"dashedButton":"虚线按钮",
"textButton":"文本按钮",
"linkButton":"链接按钮"
}
//FormattedMessage可以配置values属性,用于动态加载json文件中定义{xxx}字符
//values的key必须和ison文件中的模板字符对应,“xxx”则为你在组件中动态拿到的值
<FormattedMessage id="count" values={{ change:"xxx" }} />
//因为values的格式为对象形式,所以可以配置多个动态值
{"day":"今天星期{change},有{change2}节数学课,还有{change3}"}节英语课"}
<FormattedMessage id="day" values={{ change:"4",change2:"2",change3:"3",}}/>
// 转换后的结果为:"今天星期4,有2节数学课,还有3节英语课”
2.给国际化文字写上特定的颜色
// json文件
{
"welcomeMessage": "欢迎使用我们的应用!",
"count": "计数: {change}",
"primaryButton": "主按<span>钮</span>"
}
// 代码
import React from 'react';
import { FormattedMessage } from 'react-intl';
const App = () => {
const change = <span style={{ color: 'red' }}>变化值</span>;
return (
<div>
{/* 欢迎消息 */}
<FormattedMessage id="welcomeMessage" />
{/* 计数 */}
<br />
<FormattedMessage
id="count"
{/* 通过读取一个标签的方式来改变字体颜色,而不是直接读取一个普通变量 */}
values={{ change }}
/>
{/* 样式化按钮文字 */}
<br />
<FormattedMessage
id="primaryButton"
{/* 需要使用函数的方式去实现字体变色 */}
values={{
span: (chunks) => <span style={{ fontWeight: 'bold', color: 'blue' }}>{chunks}</span>
}}
/>
</div>
);
};
export default App;
3.扩展——消息模板语法的更多使用:
{
"greeting": "Hello, {name}!",
"date": "Today is {ts, date, ::yyyyMMdd}",
"time": "The current time is {timeValue, time, short}",
"price": "The total price is {price, number, USD}",
"photos": "You have {photoCount, plural, =0{no photos} one{photo} other{# photos}}",
"userGender": "{gender, select, male{He is} female{She is} other{They are}}",
"completedTasks": "{taskCount, plural, =0{You have not completed any tasks} one{You have completed # task} other{You have completed # tasks}}",
"welcome": "{userName}, welcome to the platform. {link}",
"specialOffer": "Check out our special offer!"
}
import React from 'react';
import { FormattedMessage } from 'react-intl';
const App = () => {
const name = 'John';
const ts = Date.now();
const timeValue = new Date();
const price = 12345.67;
const photoCount = 5;
const gender = 'male';
const taskCount = 3;
const userName = 'Alice';
const link = <a href="https://www.example.com">点击这里</a>;
return (
<div>
{/* 简单文本 */}
{/* 转换后的内容:Hello, John! */}
<FormattedMessage id="greeting" values={{ name }} />
{/* 日期 */}
{/* 转换后的内容:Today is 20230518 */}
<FormattedMessage id="date" values={{ ts }} />
{/* 时间 */}
{/* 转换后的内容:The current time is 12:34 PM */}
<FormattedMessage id="time" values={{ timeValue }} />
{/* 数字 */}
{/* 转换后的内容:The total price is $12,345.67 */}
<FormattedMessage id="price" values={{ price }} />
{/* 复数 */}
{/* 转换后的内容:You have 5 photos */}
<FormattedMessage id="photos" values={{ photoCount }} />
{/* 选择 */}
{/* 转换后的内容:He is */}
<FormattedMessage id="userGender" values={{ gender }} />
{/* 更复杂的复数结构 */}
{/* 转换后的内容:You have completed 3 tasks */}
<FormattedMessage id="completedTasks" values={{ taskCount }} />
{/* 包含链接的欢迎消息 */}
{/* 转换后的内容:Alice, welcome to the platform. 点击这里 */}
<FormattedMessage id="welcome" values={{ userName, link: link }} />
{/* 特别优惠 */}
{/* 转换后的内容:Check out our special offer! */}
<FormattedMessage id="specialOffer" />
</div>
);
};
export default App;
案例:
// json文件定义
{
"count":“计数:{count}",
"day":"今天星期{change},有{change2}节数学课,还有{change3}"}节英语课"
}
import React from 'react';
import { FormattedMessage } from 'react-intl';
const Greeting = () => (
const [count,setCount]=useState(8);
<>
{/* demo1 */}
<p><FormattedMessage id="count"values={{ count }}/>
{/* 页面渲染后的内容为<p>计数:8</p> */}
</p>
{/* demo2 */}
<span>
<FormattedMessage id="day" values={{ change:"4",change2:"2",change3:"3"}}
</span>
{/* 页面渲染后的内容为<span>今天星期4,有2节数学课,还有3节英语课</span> */}</>
);
export default Greeting;
3.编程式使用
// 当你需要在组件中插入翻译文本,但又不在 JSX 返回的模板中时
//(比如设置文档标题、生成表单选项等非直接渲染的场合),intl.formatMessage()就特别有用
//可以直接将此段代码替换你的文本
{intl.formatMessage({ id:"clickMe"})}
//intl.formatMessage({id:'pageTitle'});也能使用消息模板,和FormattedMessage类似
// json文件定义
{
"greeting":"Hello,{name}!Welcome back to {location}."
}
// 使用
intl.formatMessage({
id:'greeting',
values:{
name: 'Alice',
location: "Wonderland'
}
});
//转换后:Hello, Alice! Welcome back to Wonderland.
//注意:这里的1d和html中的id无任何联系,不会引起冲突,这里的id仅用于做国际化的标识
//编译后id将不会存在,无需有任何担心
案例
import { useIntl } from 'react-intl';
function MyComponent(){
const intl= useIntl();
//使用 intl 创建动态文档标题
useEffect(()=>{
document.title=intl.formatMessage({ id:'pageTitle'});
},[intl]);
}
说明:通过上面的例子,大家不难发现 int.formatMessage(id:"clickMe”))不仅可以在编程式中使用,使用差值语法的方式在isx中使用也是OK的。虽然不会有什么问题,但是这里不建议这么做,这样违背了react-intl 创建者的意图。在组件中还是建议使用<FormattedMessage id="count" values={{count }}/>这种形式,在编程逻辑中可以使用 intl.formatMessage({id:"clickMe"})这种形式
4. 切换语言
import React, { useState } from 'react';
import { IntlProvider } from 'react-intl';
import enMessages from './locales/en.json';
import zhMessages from './locales/zh.json';
import Greeting from './Greeting';
const messages = {
en: enMessages,
zh: zhMessages
};
const App = () => {
const [locale, setLocale] = useState('en');
const switchLanguage = (language) => {
setLocale(language);
};
return (
<IntlProvider locale={locale} messages={messages[locale]}>
<div>
<button onClick={() => switchLanguage('en')}>English</button>
<button onClick={() => switchLanguage('zh')}>中文</button>
<Greeting />
</div>
</IntlProvider>
);
};
export default App;
5.如何解决文本动态加载翻译问题
注意:这一情况是针对于国际化业务的,提供解决问题思路,与任何npm无关,可以被任何国际化场景借鉴或使用有一种情况,当消息模板中的文字是动态加载的,我该如何翻译呢?例如值可能是”loading”,"success",或"error",那我们怎么翻译不同的值?
//如果你有一个状态消息,可能是"loading","success",或“error"
// 那么你可以在你的国际化消息中为每个状态定义一个条目:
// json文件定义
{
"status_loading":"正在加载...",
"status_success":"加载成功!",
"status_error":"加载失败。"
}
// 使用
<FormattedMessage id={`status ${status}`} />
// 如果返回的是"加载中,成功,失败”这些中文也同样可以使用
{
"status_加载中":"正在加载...",
"status_成功":"加载成功!",
"status_失败":"加载失败。"
}
//使用
<FormattedMessage id={`status_${status}`} />
最后,还有一个最为极端的情况,就是如果返回的是随机一段中文文本,那该如何解决?那么将很难实现,因为标准的国际化实践是基于静态键值对的,依赖预先定义好的翻译映射。但对于随机或动态生成的文本(完全随机的情况),这里可以提供几种实现思路:
1.调用第三方翻译的api实现文本翻译
2.后端翻译,后端将同时提供几种语言的字段,前端用来动态取值
注意:本篇文章中,只针对了中英文两种语言的切换,但实际上是可以对于多种语言的切换,并不局限于某几种语言,多种语言需要定义多个json文件,这个在你熟读完整篇文章后可以去尝试多语言的切换。 注意:这里无论是FormattedMessage中的id还是formatMessage中的id,都与html中的id无任何联系,不会引起冲突,这里的id仅用于做国际化的标识, 编译后id将不会存在,无需有任何担心
插入:小编自己封装了一个大文件上传的工具函数,支持切片上传、错误重试、上传进度、暂停和继续等,目前已发布在npm官网,感兴趣的可以看看。
下载命令:npm i enlarge-file-upload