拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Joplin 桌面版 TinyMCE 语言包机制:从 Assets/TinyMCE/langs 到富文本编辑器本地化的完整构建与加载流程

Joplin 桌面版 TinyMCE 语言包机制从 Assets/TinyMCE/langs 到富文本编辑器本地化的完整构建与加载流程【免费下载链接】joplinJoplin - the privacy-focused note taking app with sync capabilities for Windows, macOS, Linux, Android and iOS.项目地址: https://gitcode.com/GitHub_Trending/jo/joplinJoplin 桌面版Electron 应用内置了基于 TinyMCE 的富文本编辑器其界面文案工具栏按钮、菜单、对话框的多语言支持依赖一套独立的 TinyMCE 语言包language packs。本文以仓库中的 Assets/TinyMCE/langs/README.md 为核心结合桌面版构建脚本与编辑器初始化源码讲清这些语言包的存放位置、构建期拷贝流程gulp 任务copyApplicationAssets以及运行时的按需加载机制读完后可完整掌握 Joplin 富文本编辑器本地化的原理与实操方式。语言包是什么为什么单独维护Assets/TinyMCE/langs/README.md 的原文只有三行但它描述了 Joplin 富文本编辑器本地化链路的起点语言包来自 TinyMCE 官方的语言包下载页面Tiny Language Packages语言包需要被放置到node_modules/tinymce目录才能被编辑器识别这一步由 Electron 客户端桌面版的 gulpfile 自动完成。这里的“语言包”指 TinyMCE 编辑器自身的 UI 翻译文件——每个语言对应一个独立的.js文件例如de.js之于德语、ja.js之于日语文件内以tinymce.addI18n(de, {...})的形式注册该语言的词条。注意它和 Joplin 应用本身的翻译体系是分开的应用级翻译由 packages/tools/locales 下的.po文件管理而 TinyMCE 编辑器内部的工具栏提示、对话框文案则使用这一套语言包。当前仓库中Assets/TinyMCE/langs/目录下实际存放了约 50 个语言包文件覆盖范围包括ar.js、de.js、fr_FR.js、ja.js、ko_KR.js、ru.js、es_MX.js、zh_CN.js、zh_TW.js等完整列表可直接查看 Assets/TinyMCE/langs/ 目录。也就是说仓库把语言包“vendoring”到了Assets/目录中保证构建时不再依赖外部网络下载。构建期gulp 任务 copyApplicationAssets 的拷贝流程README 提到“由 ElectronClient 的 gulpfile 完成拷贝”。在代码库演进的现状中这一职责由桌面版的 gulp 任务copyApplicationAssets承担。任务定义见 packages/app-desktop/gulpfile.tscopyApplicationAssets: { fn: require(./tools/copyApplicationAssets.js), ... }其实现位于 packages/app-desktop/tools/copyApplicationAssets.js核心逻辑分三步1. 定位语言包源目录与目标目录const langSourceDir resolve(__dirname, ../../../Assets/TinyMCE/langs); const buildLibDir resolve(__dirname, ../vendor/lib);拷贝清单dirs中显式声明了语言包这一项copyApplicationAssets.js#L67-L80const dirs [ tinymce, // node_modules/tinymce - vendor/lib/tinymce fortawesome/fontawesome-free/webfonts, roboto-fontface/fonts, codemirror/theme, { src: langSourceDir, // Assets/TinyMCE/langs dest: ${buildLibDir}/tinymce/langs, // packages/app-desktop/vendor/lib/tinymce/langs }, { src: ${nodeModulesDir}/tesseract.js-core, dest: ${buildDir}/tesseract.js-core, }, ];可以看到node_modules/tinymce整个目录包含tinymce.min.js核心被拷贝到vendor/lib/tinymce而仓库Assets/TinyMCE/langs/中的语言包则被合并拷贝到vendor/lib/tinymce/langs/——这正是 README 所说“拷贝到 node_modules/tinymce 目录”这一意图在当前构建体系中的落地形态桌面版最终把vendor/打包进应用分发的vendorDir()而非运行时直接读node_modules。2. 针对 CI 不稳定的重试机制值得注意的是源码注释记录了该脚本在 CI 上出现过随机性失败ENOENT: copyfile、ENOTEMPTY: directory not empty等看似不可能的错误见 copyApplicationAssets.js#L22-L44。为此脚本为每个文件操作实现了指数退避重试最多 5 次const withRetry async (fn) { for (let i 0; i 5; i) { try { await fn(); return; } catch (error) { console.warn(withRetry: Failed calling function - will retry (${i}), error); await msleep(1000 i * 1000); } } throw new Error(withRetry: Could not run function after multiple attempts); };此外脚本先统一删除所有目标目录、再统一执行拷贝for (const action of [delete, copy])见 copyApplicationAssets.js#L109-L131注释说明这样做是为了规避“删除后立即拷贝”时的竞态条件。3. 自动生成 supportedLocales.js 清单拷贝完成后脚本扫描语言包目录生成一份“受支持语言清单”文件copyApplicationAssets.js#L150-L159const supportedLocales glob.sync(${langSourceDir}/*.js).map(s { s basename(s).split(.); return s[0]; }); supportedLocales.sort(); const content module.exports ${JSON.stringify(supportedLocales, null, 2)}; await writeFile(${__dirname}/../gui/NoteEditor/NoteBody/TinyMCE/supportedLocales.js, content, utf8);即Assets/TinyMCE/langs/里放了哪些语言文件supportedLocales数组就包含哪些语言代码输出产物是 packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/supportedLocales.js构建时生成的文件。这意味着“新增一个语言包”不需要改任何代码——把对应.js放进Assets/TinyMCE/langs/重新构建即可被运行时识别。运行期编辑器如何按需加载语言包桌面版富文本编辑器的初始化入口在 packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx。运行时加载语言包的完整调用链如下第一步从受支持清单中解析出最接近的语言代码const supportedLocales require(./supportedLocales); ... const language closestSupportedLocale(props.locale, true, supportedLocales);closestSupportedLocale定义在 packages/lib/locale.ts它接受用户当前的应用 locale、defaultToEnglish true标志以及 TinyMCE 语言包清单返回一个 TinyMCE 实际具备的语言代码。其单测 packages/lib/locale.test.ts 覆盖了多种 locale 归并场景如区域变体回退到语言主干。第二步非英语语言才动态注入语言包脚本const isDefaultEnglishLocale [en_US, en_GB].includes(language); if (!isDefaultEnglishLocale) { await loadScript({ id: tinyMceLang_${language}, src: ${bridge().vendorDir()}/lib/tinymce/langs/${language}.js, }, editorContainerDom); }见 TinyMCE.tsx#L710-L717这里有两个设计要点脚本从bridge().vendorDir()下的lib/tinymce/langs/加载路径与构建期copyApplicationAssets的拷贝目标一一对应英语en_US/en_GB是 TinyMCE 的默认语言无需加载额外脚本直接跳过注入。第三步把语言传给 tinymce.initlanguage: isDefaultEnglishLocale ? undefined : language,见 TinyMCE.tsx#L749tinymce.init的完整配置中还有若干与本地化/编辑器行为相关的选项例如localization_function: _接入 Joplin 自身的翻译函数、icons: Joplin与icons_url自定义图标集对应 packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/icons.js、branding: false与promotion: false去掉 TinyMCE 品牌标识与付费推广。当前锁定的编辑器版本为tinymce: 6.8.5见 packages/app-desktop/package.json语言包格式与该版本的tinymce.addI18n约定匹配。实操如何查看、新增或更新一个语言包基于上述源码链路围绕语言包的实际操作路径如下均以查看仓库为准仓库为只读参考查看现有语言支持范围直接浏览 Assets/TinyMCE/langs/文件名即 TinyMCE 语言代码bg_BG.js、he_IL.js、ta_IN.js等。新增语言从 TinyMCE 官方语言包页面下载对应的lang.js放入Assets/TinyMCE/langs/目录。构建时copyApplicationAssets会自动将其拷入vendor/lib/tinymce/langs/并自动更新supportedLocales.js清单当用户应用语言对应该 locale 时closestSupportedLocale即可命中并加载。更新 TinyMCE 或语言包版本Assets/TinyMCE/langs/中的语言包必须与node_modules中的 tinymce 版本配套见 packages/app-desktop/package.json 中锁定的tinymce版本更换大版本时应整包重新获取避免旧格式文件与新版addI18n约定不兼容。验证构建产物构建后检查packages/app-desktop/vendor/lib/tinymce/langs/是否包含预期文件vendor/为构建输出不入库。小结Assets/TinyMCE/langs/README.md 虽仅三行却勾勒出 Joplin 桌面版富文本编辑器本地化的完整契约语言包由 TinyMCE 官方获取并 vendoring 至Assets/TinyMCE/langs/构建期由 gulpfile.ts 中的copyApplicationAssets任务拷入vendor/lib/tinymce/langs/并顺带生成supportedLocales.js清单运行期由 TinyMCE.tsx 通过closestSupportedLocale解析语言、非英语场景按需注入脚本、最终经tinymce.init的language选项生效。理解这条“资产 → 构建 → 运行时”的单向流水线即可准确解释 Joplin 富文本编辑器各语言界面文案的来源与扩展方式。【免费下载链接】joplinJoplin - the privacy-focused note taking app with sync capabilities for Windows, macOS, Linux, Android and iOS.项目地址: https://gitcode.com/GitHub_Trending/jo/joplin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门