问在开头,国际化到底是个啥?
每个开发者能希望编写的程序可以让全世界的用户使用,应用程序 的功能和代码设计时考虑在不同地区运行的需要,其代码适应不同区域要求。开发这样的的过程,就称为国际化( internationalization)。
冷知识:i18n的简称和k8s有异曲同工之妙,i-n之间有18个字母简称i18n
具体对应需要处理的场景包括但不限于
-
不同国家的语言;
-
文字书写方向;(比如德语是从左到右,而波斯语、希伯来语和阿拉伯语是由右到左。)
-
图片中包含的文字;
-
程序中的音频;
-
程序中的视频字幕;
-
图片和颜色:这牵涉到理解和文化适宜的议题;
-
名字和称谓;
-
政府给定的编码(如美国的社会安全码,英国的National Insurance number,爱沙尼亚的Isikukood及其它各国的身份证号码)和护照;
-
电话号码前缀、地址和国际邮递区号;
-
货币 (符号、货币标志的位置);
-
长度、容积、重量单位;
-
标准纸张大小;
但是今天主要讨论的还是语言的国际化 => 代码翻译问题
我们调研了市面上的常用工具/插件,大致将其分为以下三类
各种工具的使用
纯手动工具的使用 i18next
- 第一步进入到一个react项目内
- 安装npm包
npm install i18next react-i18next i18next-browser-languagedetector
- 创建语言文件夹
js
// index.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import translationEN from './locales/en-US';
import translationZH from './locales/zh-CN';
const resources = {
en: {
translation: translationEN,
},
zh: {
translation: translationZH,
},
};
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
debug: true,
fallbackLng: 'en',
interpolation: {
escapeValue: false,
},
resources,
});
export default i18n;
js
// zh-CN/index.js
export default {
common: {
login: '登录',
register: '注册',
},
};
- 在app.js内添加引用
js
import { useLaunch } from "@tarojs/taro";
import "./app.css";
import "../i18n";
function App({ children }) {
......
- 具体页面中使用
需要注意的点是,切换语言后,不会自动刷新页面,所以使用state变更来引起页面刷新
js
......
import { t, changeLanguage } from "i18next";
......
<View className="index">
<View
onClick={() => {
changeLanguage(first ? "en-US" : "zh-CN");
setfirst(!first);
}}
>
切换语言
</View>
<Text>{t("common.login")}</Text>
</View>
......
纯手动工具小总结
纯手动工具,文字的收集比较麻烦,翻译需要人工进行,且在代码内的枚举可读性不高
半自动工具的使用 di18n
作为大厂出品的国际化工具,尽管2年未更新,但是使用没有太大的障碍,且在当前项目场景下满足我们的需要。
- 接入项目 可安装在项目内也可全局安装
npm install --save-dev di18n-cli / npm install -g di18n-cli
- 进入到项目目录内到终端运行
di18n init
会自动生成di18n.config.js和locales文件夹(语言包)
- 进入到di18n.config.js文件进行配置修改
js
module.exports = {
entry: ['src'] /** 入口目录 */,
exclude: [] /** 忽略文件及文件夹 */,
output: ['src'] /** 输出目录 */,
disableAutoTranslate: true /** 是否禁用自动翻译 */,
extractOnly: false /** 是否只提取 */,
translator: null /** 翻译器 非谷歌需要自定义 */,
ignoreComponents: [] /** 忽略组件 */,
ignoreMethods: [] /** 忽略具体执行的方法 */,
primaryLocale: 'zh-CN' /** 默认语言 */,
supportedLocales: ['zh-CN', 'zh-HK', 'en-US'] /** 支持的语言 */,
importCode: "import { intl } from 'di18n-react';" /** 项目内使用的国际化切换库,导入代码 */,
i18nObject: 'intl' /** 国际化库 方法对象 */,
i18nMethod: 't' /** 国际化库 方法名 最后组合成 intl.t */,
prettier: {},
localeConf: { type: 'file', folder: 'locales' } /** 国际化目录配置 type支持excel,json,js */,
};
- 运行
di18n sync
运行前文件
运行后文件
语言包内自动收集
- 运行项目就可以直接只用了
半自动工具小总结
相较于纯手动的工具,他完善了自动收集、自动翻译、自动将源代码添加国际化hanshuo,但是还是对代码有侵入性修改
纯自动化工具 vite-plugin-auto-i18n
只需要增加配置,无需任何命令,通过webpack/vite/eslint在打包时对所有代码扫描并翻译,生成语言包使用 vite.config.js
js
......
plugins:[
vuePlugin,
vuePluginsAutoI18n({
option: {
globalPath: './lang', // 配置文件生成位置
namespace: 'lang', // 命名空间
targetLangList: ['en', 'ko', 'ja', 'zh-hk', 'zh-tw'], // 翻译目标语言
originLang: 'zh-cn', // 翻译源语言
distPath: './dist/assets', // 打包后生成文件位置
distKey: 'index', // 打包后主文件名称
}
}),
],
]
......
自动化工具小总结
启动项目后,会自动收集依赖,且对打包产物进行修改,对代码无侵入性,不过复杂代码无法自动收集且无法手动修改
使用大总结
半自动是输出了命令,全自动是输出了插件
源码阅读 di18n 只讲核心流程,边界case处理请自己看源码
di18n源码github.com/didi/di18n
在终端输入**di18n sync** 会进入以下代码
遍历在配置文件写的目录文件夹,并将路径存储下来方便之后读取
对刚才的文件路径进行遍历
核心babel解析 替换
举例 对jsxText文本的替换 还有表达式和jsxElement 等等
将收集到的字符存储到数组,待整个项目遍历完后写入到本地locales文件夹内
本地落库操作,并和本地已有的进行对比,未在使用的remove,已有的做增量更新
by the way 自动翻译功能的实现
最后浅浅总结下
如果是新项目的话,而且有人工进行翻译的话,可以考虑使用普通的国际化库或者半自动化库,相对来说会更有保障,可以将收集编译的步骤加入到打包命令中也能大体实现自动化的功能
当然,如果是已经达到一定体量的维护阶段的大项目还是首推全自动化和半自动化库,节省更多的人力