目录
react-i18next使用上下文API、或者 hook:
1.3设置VueI18n的options中的messages登
src/declare.d.ts:declare module 'VueI18n';
设置语言
页面:html标签的 lang属性
- 英语:
<html lang="en">
- 中文:
<html lang="zh">
或<html lang="zh-CN">
"CN" 则表示该语言的特定区域,即中华人民共和国(China)。
更符合语言标准的规范
- 西班牙语:
<html lang="es">
- 法语:
<html lang="fr">
- 日语:
<html lang="ja">
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Your Webpage Title</title>
</head>
<body>
<!-- Your webpage content goes here -->
</body>
</html>
浏览器->设置->语言
命名由来
国际化(i18n):
- i 表示单词 "internationalization" 的首字母。
- 18 表示在 "i" 和 "n" 之间有 18 个字母。
本地化(l10n):
- l 表示单词 "localization" 的首字母。
- 10 表示在 "l" 和 "n" 之间有 10 个字母。
- react-i18next:i18n+extend(推测)
原理
从本地化资源文件中获取特定键的字符串,并且可以动态地插入变量。本地资源一般是.json,.xml,.ts存储对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Translation 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>
</html>
t参数
t
(translate) 函数: 这个函数用于翻译文本,传入翻译文件(如下述home.json)或命名空间(namespace,如下述zh.json中的login)
i18n
对象: 包含国际化设置的对象,判断和切换语言
i18n.language
的默认值是浏览器的语言首选项(navigator.language)
i18n.language; // 当前语言环境
i18n.changeLanguage('en'); // 切换到英语
-
变量替换 (
variables
):- 用法:通过一个对象来传递需要替换的变量。
- 示例:
t('welcomeMessage', { username: 'John' })
- 说明:这种方式允许你将动态变量插入到翻译文本中,类似占位符的功能。
-
格式化 (
format
):- 用法:指定特定的格式化选项,例如日期、数字格式化等。
- 示例:
t('date', { date: new Date(), format: 'longDate' })
- 说明:在需要根据语言环境格式化日期、数字或其他类型的内容时特别有用。
-
复数形式 (
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/2024 - ISO 8601 格式 (
isoDate
):例如 2024-07-13 - 完整日期时间 (
fullDateTime
):例如 July 13th 2024, 2:30:00 pm
react组件
//不传参的话加载所有的本地资源
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>
<p>Welcome, 张三!</p>
<p>3 items</p>
<p>July 12th, 2024</p>
<p>Open</p>
<p>Default Text</p>
...
</div>
<div>
<p>欢迎,张三!</p>
<p>3 个项目</p>
<p>2024年7月12日</p>
<p>打开</p>
<p>Default Text</p>
...
</div>
本地资源:语言包对象
zh.ts
export default {
languageName: '简体中文',
common: { //通用
you: '你',
}
}
en.ts
export default {
languageName: 'English',
common: { //通用
you: 'you',
},
}
staticData.ts:直接返回对象效率更高
-
适用于静态语言
-
若固定顺序,可遍历对象属性
例子可见下文的react-i18next
export function getFeatures(lang: string){
if(lang==='cn'){
return [
{
title: '免费',
description: [
'你好',
...
],
},
{
...
}
]
}else{
return [
{
title: 'Free',
description: [
'hi~~~😄',
....
],
},
{
....
],
}
]
}
}
public->locales->en->模块名.json
public->locales->zh->模块名.json
-
适用于动态语言,非固定顺序,零散重复使用
-
returnObjects: true,可遍历对象属性
react-i18next:hook、组件级
安装
npm i i18next react-i18next
- i18next 提供了翻译的基本能力。
- react-i18next 是 i18next 的一个插件,用来降低 react 的使用成本。
可选:
npm i i18next-browser-languagedetector i18next-http-backend
- i18next-browser-languagedetector 检测浏览器语言的插件。
- i18next-http-backend从服务器加载翻译资源文件
react-i18next使用上下文API、或者 hook:
React 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.ts
<h1 className="font-bold text-2xl">{t('Sign in/Sign up')}</h1>
{features?.map((item, index) => (
<div className='flex 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-i18n
1.配置语言包(src\i18n或language)
整合语言包对象和创建 VueI18n 实例并配置
1.1注册vue-i18n
import 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(path,deep,regExp)
- path(目录路径): 表示需要搜索的目录路径。
- deep(是否搜索子目录): 表示是否搜索该目录下的子目录。
- regExp(匹配文件的正则表达式): 表示匹配文件的正则表达式。
日期时间格式文件(zh.ts+en.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.ts,prop 将会是 ['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中的locale
let 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.使用
.vue
//标签文本内容
<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})
.ts:如工具函数
import i18n from '@/i18n'
class IMConListUtil {
i18n.t('common.private'),
}
ts
src/declare.d.ts:declare 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';
Element:UI组件库
全局加载
import 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)
按需加载
import 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))
无法兼容ts
手动将'element-ui/lib/locale/lang/en','element-ui/lib/locale/lang/zh-CN'中相关内容粘贴合并到本地语言包文件中即可
在实现功能时可以节省时间,但不利于工程化
main.ts
import ElementLocale from 'element-ui/lib/locale'
ElementLocale.i18n((key:any, value:any) => i18n.t(key, value))