十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

国际化(i18n):react、vue、element兼容

国际化(i18n):react、vue、element兼容 目录设置语言页面html标签的 lang属性浏览器-设置-语言判断语言命名由来注意通用性考虑location:位置 vs location:[位置]首字母大写Title Case“动作按钮 / 标题 / 菜单项”标题含列表都大写除了 冠、连、介词除非首原理tc参数复数翻译t参数单一翻译变量替换 (variables)vue-i18n 9.x 版本与Vue 3.x 兼容选项对象 (options)格式化 (format)数字格式化1,000复数形式 (count)上下文 (context)默认值 (defaultValue)返回对象zh.jsonen.jsonreact组件传参和效果本地资源语言包对象zh.tsen.ts开发staticData.ts直接返回对象效率更高适用于静态语言若固定顺序可遍历对象属性public-locales-en-模块名.jsonpublic-locales-zh-模块名.json适用于动态语言非固定顺序零散重复使用returnObjects: true可遍历对象属性react-i18next库hook、组件级安装react-i18next使用上下文API、或者 hookvue-i18n库原型链、全局0.安装1.配置语言包src\i18n或language1.1注册vue-i18n1.2动态加载语言文件1.3设置VueI18n的options中的messages登1.4设置VueI18n的options中的locale1.5创建 VueI18n 实例并导出完整代码2.main.js引入实例化Vue3.使用选项式 API .vue类式 API .vue、工具函数.tstssrc/declare.d.tsdeclare module VueI18n;ElementUI组件库0.全局加载0.按需加载0.无法兼容/按需修改1.重启主服务/项目CDN加载性能提升就近缓存优化可靠性增强多节点备份带宽节省分担请求自动更新源码分析设置语言页面html标签的 lang属性英语:html langen中文:html langzh或html langzh-CNCN 则表示该语言的特定区域即中华人民共和国China。更符合语言标准的规范西班牙语:html langes法语:html langfr日语:html langja!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleYour Webpage Title/title /head body !-- Your webpage content goes here -- /body /html浏览器-设置-语言判断语言场景若法国、日韩本地语言不是“en”但需要用“en”所以不能靠“en”判断而是非“zh”时就显示英文const appLanguage window.app window.app.appLocaleInfo ? window.app.appLocaleInfo.appLanguage : zh; const isZhLocal (appLanguage zh);命名由来国际化i18ni表示单词 internationalization 的首字母。18表示在 i 和 n 之间有 18 个字母。本地化l10nl表示单词 localization 的首字母。10表示在 l 和 n 之间有 10 个字母。react-i18nexti18nextend推测注意通用性考虑location:位置 vs location:[位置][${i18n.t(message.location)}]首字母大写Title Case“动作按钮 / 标题 / 菜单项”标题含列表都大写除了 冠、连、介词除非首如冠词a, an, the、连词and, but, or和介词in, on, with通常不大写除非它们是标题的第一个或最后一个词。The Quick Brown Fox Jumps Over the Lazy DogSoftware Update原理从本地化资源文件中获取特定键的字符串并且可以动态地插入变量。本地资源一般是.json.xml.ts存储对象!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleTranslation Example/title /head body script const translationContext { t: (key) { // 获取浏览器当前语言 const userLanguage navigator.language || navigator.userLanguage; // 默认翻译 const defaultTranslations { No modifications at present.: No modifications at present., Time Error: Current creation time is earlier than the server time, unable to submit.: Time Error: Current creation time is earlier than the server time, unable to submit., // 添加其他英文翻译 }; // 按语言选择翻译 const zhCNTranslations { No modifications at present.: 当前无修改, Time Error: Current creation time is earlier than the server time, unable to submit.: 时间异常当前创建时间早于服务器端时间无法提交, // 添加其他中文翻译 }; const currentTranslations [zh, zh-CN, cn].includes(userLanguage) ? zhCNTranslations : defaultTranslations; // 示例翻译 const translatedText currentTranslations[key] || defaultTranslations[key] || key; // 在控制台输出翻译结果 console.log(translatedText); console.log(userLanguage); // 可以将翻译结果插入到页面中 // document.body.innerHTML translatedText; return translatedText; }, }; // 示例使用 translationContext.t(No modifications at present.); translationContext.t(Time Error: Current creation time is earlier than the server time, unable to submit.); /script /body /htmltc参数复数翻译apple: no apples | one apple | {count} apples因为tc函数可以用|分割而t不能count、n、可以随意命名p{{ $tc(apple, 0) }}/p p{{ $tc(apple, 1) }}/p p{{ $tc(apple, 10, { count: 10 }) }}/p 覆盖预定义的命名参数 p{{ $tc(apple, 100, { count: too many }) }}/p pno apples/p pone apple/p p10 apples/p ptoo many apples/pt参数单一翻译t(translate) 函数这个函数用于翻译文本传入翻译文件如下述home.json或命名空间namespace如下述zh.json中的logini18n对象包含国际化设置的对象判断和切换语言i18n.language的默认值是浏览器的语言首选项navigator.languagei18n.language; // 当前语言环境 i18n.changeLanguage(en); // 切换到英语变量替换(variables)用法通过一个对象来传递需要替换的变量。示例t(welcomeMessage, { username: John })说明这种方式允许你将动态变量插入到翻译文本中类似占位符的功能。vue-i18n9.x版本与Vue 3.x 兼容选项对象(options)可选包含配置选项如locale,pluralization等。this.$t(greeting, { name: Alice, locale: fr }) // 使用 fr 语言环境格式化(format)用法指定特定的格式化选项例如日期、数字格式化等。示例t(date, { date: new Date(), format: longDate })说明在需要根据语言环境格式化日期、数字或其他类型的内容时特别有用。数字格式化1,000复数形式(count)用法指定一个用于选择适当复数形式的数值。示例t(items, { count: 5 })说明根据给定的数值选择文本的复数形式如单数、复数等。上下文(context)用法指定一个上下文参数用于选择文本的特定变体。示例t(open, { context: verb })说明在需要根据不同语境下选择不同翻译版本时使用例如动词形式和名词形式的不同翻译。默认值(defaultValue)用法指定在找不到翻译键时返回的默认文本。示例t(nonExistentKey, { defaultValue: Default Text })说明确保在没有对应翻译键的情况下能够提供一个合适的默认文本避免出现空白或错误。返回对象{ returnObjects: true }选项来告诉t函数返回一个包含多个条目的对象适用于本身就需要对象遍历对象对象层级深避免名字太长zh.json{ home: { welcomeMessage: 欢迎{{username}}, items: { one: 一个项目, other: {{count}} 个项目 }, date: { longDate: {{date, YYYY年MM月DD日}}, shortDate: {{date, YYYY-MM-DD}}, fullDateTime: {{date, YYYY年MM月DD日Ah点mm分ss秒}} } open: { verb: 打开, noun: 开放 }, features: { free: { title: 免费, description: [ 免费注册, 免费试用 ] }, }, login: { title: 登录, username: 用户名, password: 密码, loginButton: 登录 } }长日期(longDate)例如 2024年07月13日短日期(shortDate)例如 2024-07-13完整日期时间(fullDateTime)例如 2024年07月13日下午02点30分00秒en.json{ home: { welcomeMessage: Welcome, {{username}}!, items: { one: One item, other: {{count}} items }, date: { longDate: {{date, MMMM Do, YYYY}}, shortDate: {{date, MM/DD/YYYY}}, isoDate: {{date, YYYY-MM-DD}}, fullDateTime: {{date, MMMM Do YYYY, h:mm:ss a}} features: { free: { title: Free, description: [ Free registration, Free trial ] }, } open: { verb: Open, noun: Openness } }, login: { title: Login, username: Username, password: Password, loginButton: Login } }长日期(longDate)例如 July 13th, 2024短日期(shortDate)例如 07/13/2024ISO 8601 格式(isoDate)例如 2024-07-13完整日期时间(fullDateTime)例如 July 13th 2024, 2:30:00 pmreact组件//不传参的话加载所有的本地资源const { t, i18n } useTranslation([home, login]);import React from react; import { useTranslation } from react-i18next; function WelcomeComponent({ username, itemCount, date }) { //只加载home.json就不用带前缀home只在home内查找 const { t } useTranslation(home); return ( div p{t(welcomeMessage, { username: username })}/p p{t(items, { count: itemCount })}/p p{t(date, { date: date, format: longDate })}/p p{t(open, { context: verb })}/p p{t(nonExistentKey, { defaultValue: Default Text })}/p ul {t(features.free.description, { returnObjects: true }).map((desc, index) (li key{index}{desc}/li))} /ul /div ); } export default WelcomeComponent;传参和效果WelcomeComponent username张三 itemCount{3} date{new Date()} / div pWelcome, 张三!/p p3 items/p pJuly 12th, 2024/p pOpen/p pDefault Text/p ... /div div p欢迎张三/p p3 个项目/p p2024年7月12日/p p打开/p pDefault Text/p ... /div本地资源语言包对象zh.tsexport default { languageName: 简体中文, common: { //通用 you: 你, } }en.tsexport default { languageName: English, common: { //通用 you: you, }, }开发staticData.ts直接返回对象效率更高适用于静态语言若固定顺序可遍历对象属性例子可见下文的react-i18nextexport function getFeatures(lang: string){ if(langcn){ return [ { title: 免费, description: [ 你好, ... ], }, { ... } ] }else{ return [ { title: Free, description: [ hi~~~, .... ], }, { .... ], } ] } }public-locales-en-模块名.jsonpublic-locales-zh-模块名.json适用于动态语言非固定顺序零散重复使用returnObjects: true可遍历对象属性react-i18next库hook、组件级安装npm i i18next react-i18nexti18next 提供了翻译的基本能力。react-i18next 是 i18next 的一个插件用来降低 react 的使用成本。可选npm i i18next-browser-languagedetector i18next-http-backendi18next-browser-languagedetector 检测浏览器语言的插件。i18next-http-backend从服务器加载翻译资源文件react-i18next使用上下文API、或者 hookReact Context API实现状态和数据在组件树中的共享。它允许在组件之间共享数据而无需手动通过props一层层地传递数据。尤其适用于全局数据、主题设置、用户身份验证等在整个应用程序中需要访问的数据。hook只能在函数组件中import { useTranslation } from react-i18next; import { getFeatures } from ./staticData; export default function HomeContent() { //解构变量根据本地的home和login文件设置i18n const { t, i18n } useTranslation([home, login]); const features getFeatures([zh, zh-CN, cn].includes(i18n.language) ? cn : en)getFeatures见上文中的staticData.tsh1 classNamefont-bold text-2xl{t(Sign in/Sign up)}/h1 {features?.map((item, index) ( div classNameflex flex-col items-center p-4 md:w-1/2 key{item.title} div className min-w-full h-full bg-[#2A2935] rounded-lg p-4 div className text-2xl leading-loose md:leading-tight{item.title} {item.subtitle span className text-xs text-gray-400 ml-2( {item.subtitle} )/span} /div {item.description.map((item, index) ( div className text-xs text-gray-400 leading-relaxed key{index}- {item}/div ))} /div /div ))}vue-i18n库原型链、全局0.安装npm install vue-i18nVue I18n官方文档1.配置语言包src\i18n或language整合语言包对象和创建 VueI18n 实例并配置1.1注册vue-i18nimport Vue from vue import VueI18n from vue-i18n Vue.use(VueI18n) // 将 VueI18n 注入到 Vue 实例中的所有子组件在 Vue.js 中插件通常通过Vue.use()方法来注册和安装。vue-i18n注册后将i18n实例挂载到原型链上。全局可访问任何 Vue 组件中都可以通过this.$i18n访问到国际化实例一致性保证所有组件使用同一个i18n实例避免了不同组件间状态管理的复杂性和冗余性。1.2动态加载语言文件let langFileds require.context(./locales, false, /\.ts$/) let dateTimeFormatsFileds require.context(./dateTimeFormats, false, /\.ts$/) let regExp /\.\/([^\.\/])\.([^\.])$/require.context是 webpack 提供的一种函数用于在编译时动态地引入模块。它接受三个参数require.context(pathdeepregExp)path(目录路径): 表示需要搜索的目录路径。deep(是否搜索子目录): 表示是否搜索该目录下的子目录。regExp(匹配文件的正则表达式): 表示匹配文件的正则表达式。日期时间格式文件(zh.tsen.ts一致export default { shortMonth: { month: short, }, numberMonth: { month: narrow, }, shortYear: { year: numeric } }shortMonth:month: short表示月份的简短格式。具体格式比如 Jan、Feb取决于具体的本地化设置通常是缩写形式的月份名称。numberMonth:month: narrow表示月份的窄格式。这种格式可能比 short 更加紧凑通常用于较窄的显示空间或者日历视图中。shortYear:year: numeric表示年份的数字格式。这种格式通常是完整的四位数字年份例如 2023。1.3设置VueI18n的options中的messages登langFileds.keys().forEach((key:any) { let prop regExp.exec(key)//正则匹配en|zh这样的值 if(prop){ //messages[prop]相当于 messages[en] {table:{...}} messages[prop[1]] langFileds(key).default //对于 ./en.tsprop 将会是 [en, ts] //.default 表示 ES6 默认导出的内容因为 webpack 在处理 ES6 模块时会将其包装为一个包含 default 属性的对象。 } }) dateTimeFormatsFileds.keys().forEach((key:any) { let prop regExp.exec(key)//正则匹配en|zh这样的值 if(prop){ dateTimeFormats[prop[1]] dateTimeFormatsFileds(key).default } })messages对象{en: {greeting: Hello!,farewell: Goodbye!},zh: {greeting: 你好,farewell: 再见}}1.4设置VueI18n的options中的localelet locale window.xxx.appLocaleInfo.appLanguage || zh //从localstorag中获取1.5创建 VueI18n 实例并导出export default new VueI18n({ locale, // 指定当前的语言环境 messages, // 语言包对象包含不同语言的翻译 dateTimeFormats // 日期时间格式对象包含不同语言的日期时间格式配置 })完整代码import Vue from vue import VueI18n from vue-i18n Vue.use(VueI18n) //注入到所有的子组件 let langFileds require.context(./locales, false, /\.ts$/) let dateTimeFormatsFileds require.context(./dateTimeFormats, false, /\.ts$/) let regExp /\.\/([^\.\/])\.([^\.])$/ //正则用于匹配 ./en.js中的en let messages {} //声明一个数据模型对应i18n中的message属性 let dateTimeFormats {} langFileds.keys().forEach((key:any) { let prop regExp.exec(key)//正则匹配en|zh这样的值 if(prop){ //messages[prop]相当于 messages[en] {table:{...}} messages[prop[1]] langFileds(key).default } }) dateTimeFormatsFileds.keys().forEach((key:any) { let prop regExp.exec(key)//正则匹配en|zh这样的值 if(prop){ dateTimeFormats[prop[1]] dateTimeFormatsFileds(key).default } }) let locale window.xxx.appLocaleInfo.appLanguage || zh //从localstorag中获取 export default new VueI18n({ locale,//指定语言字段 messages,//定义语言字段 dateTimeFormats })2.main.js引入实例化Vue基于组件的本地化import i18n from ./i18n //渲染函数 (render)动态地生成虚拟 DOM适合复杂的逻辑和定制化需求。 new Vue({ i18n, render: h h(App) }).$mount(#app) ​//模板字符串 (template)适合基本的应用程序结构和布局,易读和维护。 new Vue({ i18n, // 语言国际化配置 template: App/, // 模板字符串指定根组件 components: { App } // 注册根组件 }).$mount(#app)3.使用选项式 API.vueJS对象方式定义组件Vue 在此对象中注入了上下文包括this.$t方法//标签文本内容 span{{$t(workplace.updateRecurringSchedule)}}/span //标签属性 :placeholder$t(chartSend.addScheduleTheme) //js this.$t(chartSend.waitBotReply) //键值对removeMsg:确定将 {nickname} 移除群聊吗?, const item.nickname{nickname:M7} this.$t(chartSend.removeMsg, {nickname: item.nickname})extent.js Vue 的原型中挂载 $t 方法// 把 VueI18n 对象实例的方法都注入到 Vue 实例上 Vue.prototype.$t function (key: Path, ...values: any): TranslateResult { const i18n this.$i18n // 代理模式的使用 return i18n._t(key, i18n.locale, i18n._getMessages(), this, ...values) }调用 index.js 中的 $t 的方法// $t 最后调用的方法 _t (key: Path, _locale: Locale, messages: LocaleMessages, host: any, ...values: any): any { if (!key) { return } const parsedArgs parseArgs(...values) // 如果 escapeParameterHtml 被配置为 true那么插值参数将在转换消息之前被转义。 if(this._escapeParameterHtml) { parsedArgs.params escapeParams(parsedArgs.params) } const locale: Locale parsedArgs.locale || _locale // 翻译 let ret: any this._translate( messages, locale, this.fallbackLocale, key, host, string, parsedArgs.params ) }a类式 API.vue、工具函数.tsimport i18n from /i18n class IMConListUtil { i18n.t(common.private), }如果类式 API 用 this.$t会报错原因ES6 类来定义组件需要使用vue-class-component插件来处理 Vue 的特性[warn]:不会阻断运行逻辑但error会TypeError: Cannot read properties of undefined (reading _t)at Vue.$t (todo.common.js:20045:1)at VueComponent.selectPractitioners (todo.common.js:25065:1)at click (todo.common.js:17124:2746)export default class CreateBacklogTask extends Vue { this.searchSelectPerson params this.$t(todo.add.subscriberss) ? this.followersList : this.executorList; }tssrc/declare.d.tsdeclare module VueI18n;TypeScript项目中当第三方库或模块不是由 TypeScript 编写的因此可能没有原生的 TypeScript 类型定义文件。会创建一个declare.d.ts文件声明模块的类型信息以便在编译时进行类型检查和提供类型提示。declare module element-ui; declare module vuex; declare module vue; declare module VueI18n; declare module axios; eclare module lodash; declare module vue-router;ElementUI组件库若用main.ts记得声明declare.d.tsdeclare module element-ui/lib/locale;0.全局加载main.jsimport Vue from vue import VueI18n from vue-i18n import Element from element-ui import enLocale from element-ui/lib/locale/lang/en import zhLocale from element-ui/lib/locale/lang/zh-CN Vue.use(VueI18n) Vue.use(Element) //设置默认语言 Vue.config.lang zh-cn //注册了中文简体和英文的本地化资源 Vue.locale(zh-cn, zhLocale) Vue.locale(en, enLocale)Tip全局安装Element组件配置相应localeVue.use(Element)Vue.use(ElementUI, { locale })按需安装Element组件配置相应localeVue.use(DatePicker)ElementLocale.i18n((key, value) i18n.t(key, value))若用Vue.use(Element)配ElementLocale.i18n((key, value) i18n.t(key, value))会报错Vue.use(Element)默认没有指定语言环境Element UI将使用它内置的默认语言设置。此时用ElementLocale.i18n()去改变其语言处理函数可能会导致冲突或重复配置从而引发错误。0.按需加载main.jsimport Vue from vue import DatePicker from element/lib/date-picker import VueI18n from vue-i18n import enLocale from element-ui/lib/locale/lang/en import zhLocale from element-ui/lib/locale/lang/zh-CN import ElementLocale from element-ui/lib/locale Vue.use(VueI18n) Vue.use(DatePicker) const messages { en: { message: hello, ...enLocale }, zh: { message: 你好, ...zhLocale } } // Create VueI18n instance with options const i18n new VueI18n({ locale: en, // set locale messages, // set locale messages }) ElementLocale.i18n((key, value) i18n.t(key, value))0.无法兼容/按需修改vscommandp 查找文件en.jsuse strict; exports.__esModule true; exports.default { el: { colorpicker: { confirm: OK, clear: Clear }, datepicker: { now: Now, today: Today, cancel: Cancel, clear: Clear, ...将element-ui/lib/locale/lang/enzh-CN中相关内容粘贴合并到本地语言包文件中即可靠el-识别el: { colorpicker: { confirm: OK, clear: Clear }, datepicker: { now: Now, today: Today, cancel: Cancel, clear: Clear, ...main.ts//全局加载 import locale_en from element-ui/lib/locale/lang/en import locale_zh from element-ui/lib/locale/lang/zh-CN const appLanguage:string window.appName.appLocaleInfo ? window.appName.appLocaleInfo.appLanguage : zh const locale appLanguage zh ? locale_zh : locale_en; Vue.use(ElementUI, { locale });1.重启主服务/项目不重启的话会报错/配置不生效CDN加载性能提升就近CDN 分布在全球多个节点通过就近的服务器提供文件减少了用户的加载时间提高了性能。缓存优化CDN 会缓存文件减轻了源服务器的负担并使文件的访问速度更快。可靠性增强多节点备份CDN 提供高可用性和容错性确保文件在多个节点上都有备份即使某些节点出现问题用户仍然可以从其他节点获取文件。带宽节省分担请求通过 CDN减少了直接从源服务器的带宽使用因为文件请求会分担到 CDN 网络上。自动更新CDN 提供的文件可以自动更新确保用户获取到的是最新版本的语言文件。源码分析​​​​​​​
返回列表