ToolJet 本地化(Localization)贡献指南:从零为 ToolJet 添加一门新语言的完整实战
2026/9/12 17:04:06 网站建设 项目流程

ToolJet 本地化(Localization)贡献指南:从零为 ToolJet 添加一门新语言的完整实战

【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet

ToolJet 是一款用于构建内部工具、仪表盘、业务应用、工作流与 AI Agent 的开源企业级应用生成平台,其前端界面基于 i18next 构建了一套完整的国际化(i18n)机制。本文基于 ToolJet 官方文档中的本地化贡献指南,结合仓库内真实的前端源码与翻译文件,完整讲解如何为 ToolJet 添加一门新语言——从创建语言 JSON 文件、翻译关键词,到在语言注册表中登记并最终出现在产品界面,帮助你以最低成本参与开源贡献,让 ToolJet 更贴近全球不同语言与文化的用户。读完本文,你将掌握一整套可复现、可提交的本地化贡献流程,并理解语言文件在运行时是如何被加载与切换的。

本地化机制概览:ToolJet 是如何支持多语言的

ToolJet 的本地化采用标准的「翻译键值 + 语言文件 + 运行时加载」模型:

  • 界面中的所有可翻译文本都以**翻译键(key)**的形式写在组件代码中,而不是直接写死文字;
  • 每种语言对应一个独立的 JSON 文件,存放「键 → 目标语言文本」的映射;
  • 前端启动时通过 i18next 加载对应语言的 JSON 文件,并支持在界面中随时切换语言。

以仓库现状为例,frontend/assets/translations 目录下目前已经包含 10 个语言文件:en.jsonfr.jsones.jsonit.jsonid.jsonuk.jsonru.jsonde.jsonzh.json以及注册表languages.jsonen.json是全仓库最完整的基础语言文件(约 1077 行),其他语言文件均以它为蓝本翻译而来,因此en.json也是你新增语言时唯一的翻译基准。

添加翻译的完整步骤

第一步:定位 translations 目录

进入仓库根目录下的frontend目录,再进入assets,在 assets 内部即可找到translations目录。它的结构如下:

frontend |-- assets |-- -- translations |-- -- -- languages.json |-- -- -- en.json

其中languages.json是语言注册表(决定哪些语言会出现在产品界面上),各语言的 JSON 文件(如en.json)存放实际的翻译内容。

第二步:按 ISO 639-1 语言代码创建语言文件

translations目录内新建一个以语言代码命名的 JSON 文件。语言代码必须遵循 ISO 639-1 标准(两字母代码),例如:

  • en—— English(英语)
  • fr—— French(法语)
  • es—— Spanish(西班牙语)
  • zh—— Chinese(中文)
  • de—— German(德语)

假设我们要把 ToolJet 本地化为法语:在translations目录下新建文件并命名为fr.jsonfr即法语的 ISO 639-1 语言代码。

第三步:复制 en.json 作为翻译模板

打开仓库中的 en.json,将其中全部内容复制到新建的fr.json中。这一步非常关键——它保证了新语言文件与基础语言文件的键结构完全一致,不会因为遗漏某个键而导致界面出现空白或回退。

en.json采用嵌套的键组织方式,顶层大致包含如下结构:

{ "globals": { "readDocumentation": "Read documentation", "cancel": "Cancel", "save": "Save", "search": "Search", "delete": "Delete", "add": "Add" }, "errorBoundary": "Something went wrong.", "viewer": "Sorry!. This app is under maintenance", "app": { "updateAvailable": "Update available", "newVersionReleased": "A new version of ToolJet has been released." } }

可以看到,globals中存放的是全站通用的高频词(保存、取消、编辑、删除等),而app等命名空间则存放某个功能模块的专属文案。翻译时只需替换每个键右侧的值(value),键名(key)必须原样保留。

第四步:逐条翻译关键词

复制完成后,即可开始把fr.json中的英文值逐条替换为法语。以仓库中真实存在的 fr.json 为例:

{ "globals": { "readDocumentation": "Lire la documentation", "cancel": "Annuler", "save": "Sauvegarder", "back": "Retour", "edit": "Éditer", "search": "Recherche", "delete": "Effacer", "add": "Ajouter", "enabled": "Activé", "disabled": "Désactivé", "yes": "Oui", "submit": "Soumettre", "select": "Sélectionner", "saving": "Enregistrement...", "saveDatasource": "Enregistrer la source de données", "authorize": "Autoriser", "connect": "Relier", "send": "Envoyer" }, "errorBoundary": "Quelque chose s'est mal passé." }

翻译时请特别注意:

  • 保持键名不变:只修改 value,绝不改动 key;
  • 保持 JSON 合法:法语中大量使用撇号(如s'estl'interface),必须转义为\'或使用双引号包裹正确的转义形式,否则 JSON 解析会失败,导致整个语言文件无法加载;
  • 注意特殊字符编码:é、è、ç、ü 等 Unicode 字符应保持 UTF-8 编码,仓库内语言文件均以 UTF-8 存储;
  • 上下文一致性:同一个键在界面多处复用,翻译措辞要尽量中性、通用,与组件使用场景匹配。

第五步:在 languages.json 中注册语言

翻译完成后,只差最后一步——将新语言登记到 languages.json 中,它才会出现在 ToolJet 界面的语言选择器里。

你需要向languageList数组中追加一个包含三个键值对的对象:

字段含义示例
lang语言的英文名称French
codeISO 639-1 语言代码fr
nativeLang该语言母语者视角的名称Français

以法语为例,注册后的languages.json应如下所示:

{ "languageList": [ { "lang": "English", "code": "en", "nativeLang": "English" }, { "lang": "French", "code": "fr", "nativeLang": "Français" } ] }

对照仓库中当前的 languages.json 实际内容,完整注册表包含 9 种语言:

{ "languageList": [ { "lang": "English", "code": "en", "nativeLang": "English" }, { "lang": "French", "code": "fr", "nativeLang": "Français" }, { "lang": "Spanish", "code": "es", "nativeLang": "Español" }, { "lang": "Italian", "code": "it", "nativeLang": "Italiano" }, { "lang": "Indonesian", "code": "id", "nativeLang": "Bahasa Indonesia" }, { "lang": "Ukrainian", "code": "uk", "nativeLang": "Українська" }, { "lang": "Russian", "code": "ru", "nativeLang": "Русский" }, { "lang": "German", "code": "de", "nativeLang": "Deutsch" }, { "lang": "Chinese", "code": "zh", "nativeLang": "Chinese" } ] }

注意:code必须与你新建的 JSON 文件名完全一致(例如注册fr,文件就必须是fr.json),语言选择器正是通过该 code 来拼接翻译文件路径并加载的。

源码纵深:语言文件在运行时如何被加载与切换

理解完贡献流程后,我们再从源码层面看这套机制是如何运作的,这能帮助你在翻译时理解「为什么这样注册」「界面如何找到你的语言」。

i18next 初始化与翻译文件加载

前端应用入口 frontend/src/index.jsx 中完成了 i18next 的初始化:

const language = config.LANGUAGE || 'en'; const path = config?.SUB_PATH || '/'; i18n .use(Backend) .use(initReactI18next) .init({ load: 'languageOnly', fallbackLng: 'en', lng: language, backend: { loadPath: `${path}assets/translations/{{lng}}.json`, }, });

其中几个关键配置决定了翻译文件的行为:

  • load: 'languageOnly':只按语言代码(如fr)加载,不细分地区变体(如fr-FR);
  • fallbackLng: 'en':当目标语言的某个键缺失时,自动回退到英文,避免界面出现空白;
  • lng: language:初始语言取自服务端配置的LANGUAGE,缺省为en
  • loadPath: ${path}assets/translations/{{lng}}.json:翻译文件按${语言代码}.json的命名约定从assets/translations目录加载——这就是为什么你的文件名必须与注册的code严格一致的底层原因。

语言选择器组件:切换语言的完整调用链

界面右上角的语言切换入口由 frontend/src/_components/LanguageSelection.jsx 组件实现,它揭示了你新增语言后用户侧看到的效果:

  1. 组件挂载时通过fetch('/assets/translations/languages.json')拉取注册表,并读取data.languageList
  2. 用当前i18n.language在列表中查找对应语言;如果当前语言未被注册,则回退到en
    const filteredLanguage = languageRef.current.find((ln) => ln.code === lang); if (filteredLanguage === undefined) { setLanguage(languageRef.current.find((ln) => ln.code === 'en')); } else { setLanguage(filteredLanguage); }
  3. 用户点击某个语言后调用i18n.changeLanguage(lang.code)完成切换:
    const onLanguageSelection = (lang) => { setLanguage(lang); i18n.changeLanguage(lang.code); handleClose(); };
  4. 弹窗内还提供了语言搜索能力,分别按lang(英文名)、nativeLang(母语名)和code三种字段做前缀匹配过滤。

这段源码同时也印证了注册表的重要性:如果新语言没有写进languages.jsonlanguageList,即使fr.json文件已创建,用户也无法在选择器中找到并切换到该语言。

翻译键在界面中的使用方式

翻译键通过 react-i18next 的useTranslationHook 消费。例如LanguageSelection.jsx中弹窗标题与搜索框占位符:

const { t } = useTranslation(); // ... <Modal.Title>{t('header.languageSelection.changeLanguage', 'Change language')}</Modal.Title> // ... <SearchBox placeholder={t('header.languageSelection.searchLanguage', 'Search language')} />

t()的第一个参数是翻译键路径,第二个参数是回退文案(当键不存在时显示)。这意味着:即使某条翻译暂时缺失,界面也不会崩溃,而是显示英文回退——这也是建议以en.json为完整蓝本逐条翻译的原因,翻译覆盖越全,用户界面体验越一致。

提交前的质量检查清单

在提交本地化贡献前,建议按以下清单自检:

  1. 文件命名:语言文件位于 frontend/assets/translations 下,文件名为两字母 ISO 639-1 代码(如fr.json);
  2. JSON 合法性:可用node -e "JSON.parse(require('fs').readFileSync('frontend/assets/translations/fr.json'))"验证文件可被正确解析;
  3. 键完整性:与en.json逐键比对,确保没有遗漏或多余的键;
  4. 注册登记languages.jsonlanguageList中已添加包含langcodenativeLang三个字段的对象,且code与文件名一致;
  5. 编码:文件以 UTF-8 保存,非 ASCII 字符(如法语重音字符)显示正常;
  6. 特殊字符转义:撇号、引号等已按 JSON 规则转义。

相关参考文件

  • 本地化指南文档:docs/versioned_docs/version-3.0.0-LTS/contributing-guide/l10n.md
  • 翻译文件目录:frontend/assets/translations
  • 语言注册表:languages.json
  • 英文基准文件:en.json
  • 法语翻译示例:fr.json
  • i18n 初始化源码:frontend/src/index.jsx
  • 语言选择器组件:frontend/src/_components/LanguageSelection.jsx

按照上述流程,你就可以为 ToolJet 贡献一门新的语言,帮助更多地区的用户以母语使用这一开源平台。如果你在本地化过程中遇到任何问题,也可以随时联系 ToolJet 官方社区寻求帮助。

【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询