TOAST UI Editor 国际化(i18n)完全指南:语言包机制、代码注册与自定义语言扩展
【免费下载链接】tui.editor🍞📝 Markdown WYSIWYG Editor. GFM Standard + Chart & UML Extensible.项目地址: https://gitcode.com/gh_mirrors/tu/tui.editor
TOAST UI Editor 内置了一套完整的国际化(i18n)机制,允许开发者将编辑器工具栏、弹窗、提示等所有 UI 文案切换为多种语言,并可通过setLanguage静态方法覆盖默认文案甚至注册全新的语言包。本文以 docs/en/i18n.md 为骨架,结合 apps/editor/src/i18n/i18n.ts 等源码实现,完整讲解语言文件目录结构、20 余种内置语言代码、ESM/CommonJS/CDN 三种导入方式、三种典型使用场景以及新增语言文件的贡献流程,读完即可在项目中落地多语言编辑器。
一、i18n 机制概览:语言代码如何生效
TOAST UI Editor 的 i18n 采用「语言文件注册 + 实例选项指定」两步走的设计:
- 导入语言文件:每个语言文件在加载时会调用
Editor.setLanguage(code, data)把一份完整的 UI 文案表注册到全局的I18n单例中; - 指定实例语言:创建
Editor或Viewer实例时,通过language选项传入已注册的语言代码,编辑器即按该语言渲染所有 UI 文案。
从源码看,这一机制由 apps/editor/src/i18n/i18n.ts 中的I18n类实现:
- 默认语言代码为
DEFAULT_CODE = 'en-US'; - 构造函数将当前代码初始化为
en-US,并初始化一个用于存放各语言文案表的Map; setCode(code)切换当前语言(未传参则回退到en-US);setLanguage(codes, data)支持同时为一个或多个代码(string | string[])注册文案表,且对已存在的语言执行浅合并(extend),这正是「局部覆盖」能力的底层来源;get(key, code)按当前代码取文案,若该代码尚未注册则回退到en-US,若连默认文案都没有对应 key 则抛出There is no text key "..."错误。
实例创建时,apps/editor/src/editorCore.ts 会执行this.i18n.setCode(this.options.language)把实例选项写入 I18n 单例;而工具栏、切换开关、弹窗等 UI 组件则通过i18n.get('Markdown')、i18n.get('Headings')等调用读取对应语言的文案(参见 apps/editor/src/ui/toolbarItemFactory.ts 与 apps/editor/src/ui/components/switch.ts)。
注意:
I18n是全局单例(export default new I18n()),因此语言注册与当前代码切换是跨实例共享的——这也是为什么多个编辑器实例可以各自通过language选项使用不同语言,而无需重复导入语言文件。
二、语言文件目录结构
语言文件在项目开发、构建产物、npm 包和 CDN 四个阶段的存放位置各不相同,理解这些路径有助于定位文件与排查问题。
源码目录(供贡献者)
所有内置语言文件以 TypeScript 源码形式存放于:
apps/editor/src/i18n/ - en-us.ts - ko-kr.ts - zh-cn.ts - ...每个文件的结构完全一致:先import Editor from '../editorCore',随后调用Editor.setLanguage(...)注册文案。以 apps/editor/src/i18n/ko-kr.ts 为例:
import Editor from '../editorCore'; Editor.setLanguage(['ko', 'ko-KR'], { Markdown: '마크다운', WYSIWYG: '위지윅', Write: '편집하기', Preview: '미리보기', // ... });构建产物(供维护者)
构建后,语言文件会被编译为独立 JS 文件输出到apps/editor/dist/i18n/:
apps/editor/dist/ - i18n/ - ko-kr.js - ...npm 包内
安装@toast-ui/editor后,语言文件位于包内的dist/i18n/目录,这是日常开发中最常用的导入路径:
node_modules/@toast-ui/editor/dist/ - i18n/ - ko-kr.js - ...CDN 分发
CDN 上同一份语言文件提供普通版与压缩版(.min.js),可直接通过<script>标签引入:
uicdn.toast.com/editor/latest/ - i18n/ - ko-kr.js - ko-kr.min.js - ...三、内置语言与有效语言代码
下表列出了 TOAST UI Editor 内置提供的全部语言文件及其可用的语言代码。语言代码遵循 IETF language tag 规范;导入语言文件后,其注册的代码即可作为language选项的值。
| 语言名称 | i18n 文件 | 注册代码 |
|---|---|---|
| Arabic | ar.js | ar |
| Chinese (S) | zh-cn.js | zh-CN |
| Chinese (T) | zh-tw.js | zh-TW |
| Croatian (Croatia) | hr-hr.js | hr|hr-HR |
| Czech (Czech Republic) | cs-cz.js | cs|cs-CZ |
| Dutch (Netherlands) | nl-nl.js | nl|nl-NL |
| English (United States) | en-us.js | en|en-US |
| Finnish (Finland) | fi-fi.js | fi|fi-FI |
| French (France) | fr-fr.js | fr|fr-FR |
| Galician (Spain) | gl-es.js | gl|gl-ES |
| German (Germany) | de-de.js | de|de-DE |
| Italian (Italy) | it-it.js | it|it-IT |
| Japanese (Japan) | ja-jp.js | ja|ja-JP |
| Korean (Korea) | ko-kr.js | ko|ko-KR |
| Norwegian Bokmål (Norway) | nb-no.js | nb|nb-NO |
| Polish (Poland) | pl-pl.js | pl|pl-PL |
| Portuguese (Brazil) | pt-br.js | pt|pt-BR |
| Russian (Russia) | ru-ru.js | ru|ru-RU |
| Spanish (Castilian, Spain) | es-es.js | es|es-ES |
| Swedish (Sweden) | sv-se.js | sv|sv-SE |
| Turkish (Turkey) | tr-tr.js | tr|tr-TR |
| Ukrainian (Ukraine) | uk-ua.js | uk|uk-UA |
重要说明:默认语言是英语。编辑器不会提供英语的生产语言文件(
en-us.js),也无需导入该文件——en-US作为DEFAULT_CODE内置于核心,未导入任何语言文件时编辑器即呈现英文界面。这在源码中体现为I18n.get()在目标代码未注册时的en-US回退逻辑(apps/editor/src/i18n/i18n.ts)。
从源码看,各语言文件注册的代码与上表完全一致,例如中文简体(apps/editor/src/i18n/zh-cn.ts)只注册了'zh-CN'一个代码,而韩语(apps/editor/src/i18n/ko-kr.ts)同时注册了['ko', 'ko-KR']两个代码,因此language: 'ko'与language: 'ko-KR'均有效。
四、导入语言文件:三种方式
使用任何非英语语言前,必须先导入对应的语言文件完成注册。下面代码中的${fileName}对应上表「i18n File」列的文件名(可省略扩展名)。
ES Modules(推荐)
import '@toast-ui/editor/dist/i18n/${fileName}';例如导入韩语:
import '@toast-ui/editor/dist/i18n/ko-kr';CommonJS
require('@toast-ui/editor/dist/i18n/${fileName}');CDN<script>引入
通过 CDN 使用时,同样需要额外引入语言文件(提供压缩版):
<script src="https://uicdn.toast.com/editor/latest/i18n/${fileName}"></script>仓库中的 i18n 示例页 apps/editor/examples/example16-i18n.html 展示了 CDN 引入方式:页面依次加载toastui-editor-all.js与i18n/ko-kr.js,随后用language: 'ko'创建编辑器;文件头部的注释也提示了 ESM 环境下应改为import '@toast-ui/editor/dist/i18n/ko-kr';。
五、实际使用:三个典型场景
以下示例均基于 npm 安装方式。
场景一:基本用法——按实例指定语言
language选项的值对应上表「Registered Code」列,默认值为en与en-US(两者等效,均指向内置的英文文案)。你可以让不同编辑器实例使用不同语言:
import Editor from '@toast-ui/editor'; // Step 1 : 导入语言文件(注册语言代码) import '@toast-ui/editor/dist/i18n/ko-kr'; // Step 2 : 为每个编辑器分别设置语言 const foo = new Editor({ // 未设置 language,使用默认英文 // ... }); const bar = new Editor({ // 使用韩语 // ... language: 'ko-KR', });从 apps/editor/src/editorCore.ts 的默认选项可见language: 'en-US'即为内置默认值,实例创建时会被写入 I18n 单例。
场景二:局部覆盖——修改指定语言的某些文案
当内置文案不完全符合你的产品语境时,可调用静态方法Editor.setLanguage(code, data)覆盖特定语言代码下的部分键值。该方法会以「合并」而非「整体替换」的方式生效:源码中setLanguage对已存在的代码执行extend(langData, data)(apps/editor/src/i18n/i18n.ts),因此只需给出要修改的键即可。英文默认值可参考 apps/editor/src/i18n/en-us.ts。
import Editor from '@toast-ui/editor'; // Step 1 : 导入语言文件 import '@toast-ui/editor/dist/i18n/ko-kr'; // Step 2 : 覆盖指定语言的部分文案 Editor.setLanguage('en-US', { 'Add row': '[Add Row]', // 默认值是 'Add row' }); Editor.setLanguage('ko-KR', { 'Add row': '[로우 추가]', // 默认值是 '행 추가' }); // Step 3 : 为每个编辑器分别设置语言 const foo = new Editor({ // 使用默认英文 // ... }); const bar = new Editor({ // 使用韩语 // ... language: 'ko-KR', });覆盖操作同样可以作用于尚未导入的内置语言:即使你只导入了ko-kr.js,先setLanguage('en-US', ...)也会把英文默认文案的对应键一并覆盖。
场景三:注册全新语言
如果目标语言不在内置列表中,可直接用setLanguage注册一个全新代码及其完整文案表,随后在language选项中直接使用:
import Editor from '@toast-ui/editor'; // Step 1 : 注册新语言 Editor.setLanguage('en-GB', { Markdown: '...', WYSIWYG: '...', // 其余键…… }); // Step 2 : 使用新注册的代码创建实例 const bar = new Editor({ // ... language: 'en-GB', });注册时只需保证文案表包含所有 UI 会读取的键(完整键集见 apps/editor/src/i18n/en-us.ts),漏掉的键会在运行时触发There is no text key异常,因此建议以英文文件为模板逐键补全。
六、为仓库贡献新的语言文件
若希望为社区贡献一种内置列表之外的语言,可按以下流程操作(以泰语th-TH为例):
Step 1:添加语言源文件
Fork 仓库后,在源码目录新增语言文件,文件名遵循${languageCode}-${countryCode}.js约定,且languageCode与countryCode均使用小写(如en-gb.ts):
apps/editor/src/i18n/ - en-us.ts - ko-kr.ts - th-th.ts // 新增Step 2:编写并注册文案
参照 apps/editor/src/i18n/en-us.ts 编写setLanguage调用的各参数值。第一个参数是映射到该语言文件的代码值,遵循${languageCode}-${countryCode}约定:languageCode小写、countryCode大写。
// th-th.js // ... Editor.setLanguage('th-TH', { Markdown: '...', WYSIWYG: '...', // ... });Step 3(可选):省略国家代码的代码别名
当满足 IETF 语言标签规范时,可以额外注册不带国家代码的别名,让language选项既支持th-TH也支持th:
- 可选脚本与区域子标签在不能提供额外区分信息时应省略。例如西班牙语完全预期使用拉丁字母书写,
es优于es-Latn;日语在日本的使用与其他地区差异不大,ja优于ja-JP。 - 并非所有语言区域都能用有效的区域子标签表示:主语言的次国家级地区方言以变体子标签注册。例如加泰罗尼亚语瓦伦西亚方言的变体子标签在 Language Subtag Registry 中以前缀
ca注册,由于该方言几乎只在西班牙使用,区域子标签ES通常可以省略。
// th-th.js // ... Editor.setLanguage(['th', 'th-TH'], { Markdown: '...', WYSIWYG: '...', // ... });源码中这种「一文件多代码」的写法已有大量先例:绝大多数内置语言都通过数组同时注册语言代码与「语言-国家」代码(如['ko', 'ko-KR']、['zh-CN' 之外的 'cs', 'cs-CZ']等),而 apps/editor/src/i18n/ar.ts 仅注册了'ar',说明是否添加国家代码别名完全由语言文件作者按 IETF 规范决定。
七、验证与示例
仓库提供了可直接运行验证的 i18n 示例页 apps/editor/examples/example16-i18n.html:以 CDN 方式加载编辑器与ko-kr.js语言文件后,用language: 'ko'创建实例,即可观察工具栏提示(tooltip)等 UI 文案切换为韩语的效果——这也印证了「语言代码别名(ko)与完整代码(ko-KR)等效」的设计。
单元测试方面,apps/editor/src/test/unit/editor.spec.ts 覆盖了setLanguage()静态方法,验证其会正确转发到i18n.setLanguage,可作为理解「语言文件注册 → 全局文案表 → 实例生效」调用链的参考。
八、关键要点速查
- 默认英文免导入:
en-US内置于核心,使用英文无需导入任何语言文件。 - 先注册后使用:非英语语言必须先导入对应
dist/i18n/下的文件,再在language选项中写注册代码。 - 代码可带别名:多数语言同时注册了
语言代码与语言-国家代码(如ko与ko-KR),两者皆可作为language值。 - 覆盖与新建都走
setLanguage:静态方法Editor.setLanguage(code, data)对已存在代码做键级合并覆盖,对不存在代码则整体注册。 - 文案缺失会抛错:若当前语言缺少 UI 读取的某个键,
i18n.get()会抛出There is no text key "...",自定义语言包务必以 apps/editor/src/i18n/en-us.ts 为模板补全。
【免费下载链接】tui.editor🍞📝 Markdown WYSIWYG Editor. GFM Standard + Chart & UML Extensible.项目地址: https://gitcode.com/gh_mirrors/tu/tui.editor
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考