夜猫子的知识栈 夜猫子的知识栈
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

夜猫子

前端练习生
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript教程》
    • 《Web Api》
    • 《ES6教程》
    • 《Vue》
    • 《React》
    • 《TypeScript》
    • 《Git》
    • 《Uniapp》
    • 小程序笔记
    • 《Electron》
    • JS设计模式总结
  • 《前端架构》

    • 《微前端》
    • 《权限控制》
    • monorepo
  • 全栈项目

    • 任务管理日历
    • 无代码平台
    • 图书管理系统
  • HTML
  • CSS
  • Nodejs
  • Midway
  • Nest
  • MySql
  • 其他
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • Ajax
  • Vite
  • Vitest
  • Nuxt
  • UI库文章
  • Docker
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • JavaScript文章

    • 33个非常实用的JavaScript一行代码
    • 实用JavaScricpt封装
    • ES5面向对象
    • ES6面向对象
    • 多种数组去重性能对比
    • 获取ip地址
    • ES6扩展符运用
    • file、base64和blob互相转化
    • 图片转base64格式
    • 弹窗的封装
    • websocket实现二维码扫描
    • 比typeof运算符更准确的类型判断
    • 前端下载excel文件
    • 数组与对象的互相转化
    • JS编码与转码
    • 树结构与扁平化相互转换
    • 实现微信登录
    • 常用表单验证
    • 在H5中实现OCR拍照识别身份证功能
    • 滚动条元素定位
    • 获取目标容器内的元素列表
    • 微信H5支付
    • js中的函数注释
    • 大模型流式数据前端实现
    • 定高虚拟列表
    • 不定高虚拟列表
    • 虚拟表格
    • 移动端文件预览
    • 浏览器缓存机制
    • 前端从剪切板获取word图片
    • 微信公众号调试
    • html导出pdf
    • node转化多语言
      • 将翻译输出成 json
      • 批量同步新修改的翻译
      • 将 json 反向输出回多语言配置
      • 最佳实践
  • 前端架构

  • 学习笔记

  • 全栈项目

  • 前端
  • JavaScript文章
夜猫子
2024-08-23
目录

node转化多语言

# node转化多语言

# 将翻译输出成 json

执行 node merge-translations.js

会将翻译合并输出至 translations.json 中

// merge-translations.js
import fs from 'fs';
import path from 'path';
import { fileURLToPath, pathToFileURL } from 'url';
// 获取当前文件的目录名
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 输出文件路径
const outputFile = path.resolve(__dirname, 'translations.json');

// 递归提取所有键值对,支持嵌套
function flattenObject(obj, prefix = '', result = {}) {
  for (const key in obj) {
    const value = obj[key];
    const fullKey = prefix ? `${prefix}.${key}` : key;
    if (typeof value === 'object' && value !== null) {
      flattenObject(value, fullKey, result);
    } else {
      result[fullKey] = value;
    }
  }
  return result;
}

// 动态导入语言文件并提取内容
async function extractLangObject(filePath) {
  try {
    // 转换为 file:// URL
    const fileUrl = pathToFileURL(filePath).href;
    const module = await import(fileUrl);
    const langObj = module.default || module;
    return flattenObject(langObj);
  } catch (e) {
    console.error(`Failed to import ${filePath}:`, e.message);
    return {};
  }
}

// 合并翻译文件
async function mergeTranslations() {
  const mainLangFiles = {
    en: path.resolve(__dirname, './src/lang/language/en.js'),
    ja: path.resolve(__dirname, './src/lang/language/ja.js'),
    zh_CN: path.resolve(__dirname, './src/lang/language/zh_CN.js'),
    zh_TW: path.resolve(__dirname, './src/lang/language/zh_TW.js'),
  };

  // 提取所有语言的翻译
  const langObjects = {};
  for (const lang in mainLangFiles) {
    langObjects[lang] = await extractLangObject(mainLangFiles[lang]);
    console.log(`Extracted ${lang} language file`);
  }

  // 获取所有唯一键
  const allKeys = new Set();
  for (const lang in langObjects) {
    Object.keys(langObjects[lang]).forEach((key) => allKeys.add(key));
  }

  // 构建翻译条目数组
  const translationEntries = [];
  for (const key of allKeys) {
    const entry = { key };
    for (const lang in langObjects) {
      entry[lang] = langObjects[lang][key] || '';
    }
    translationEntries.push(entry);
  }

  // 按键名排序以保持一致性
  translationEntries.sort((a, b) => a.key.localeCompare(b.key));

  // 写入文件
  fs.writeFileSync(outputFile, JSON.stringify(translationEntries, null, 2), 'utf8');
  console.log(`Merged translations into ${outputFile}`);
  console.log(`Processed ${translationEntries.length} translation entries`);
}

// 执行合并
mergeTranslations();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

# 批量同步新修改的翻译

translationsChange.json 中为新修改的翻译,执行 node sync-translations.js 后会将 translationsChange.json 更改同步至 translations.json 中,然后执行 node write-translations.js 后更新多语言配置

// sync-translations.js
import fs from 'fs';
import path from 'path';
import { fileURLToPath, pathToFileURL } from 'url';
// 获取当前文件的目录名
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 输出文件路径
const outputFile = path.resolve(__dirname, 'translations.json');

// 递归提取所有键值对,支持嵌套
function flattenObject(obj, prefix = '', result = {}) {
  for (const key in obj) {
    const value = obj[key];
    const fullKey = prefix ? `${prefix}.${key}` : key;
    if (typeof value === 'object' && value !== null) {
      flattenObject(value, fullKey, result);
    } else {
      result[fullKey] = value;
    }
  }
  return result;
}

// 动态导入语言文件并提取内容
async function extractLangObject(filePath) {
  try {
    // 转换为 file:// URL
    const fileUrl = pathToFileURL(filePath).href;
    const module = await import(fileUrl);
    const langObj = module.default || module;
    return flattenObject(langObj);
  } catch (e) {
    console.error(`Failed to import ${filePath}:`, e.message);
    return {};
  }
}

// 合并翻译文件
async function mergeTranslations() {
  const mainLangFiles = {
    en: path.resolve(__dirname, './src/lang/language/en.js'),
    ja: path.resolve(__dirname, './src/lang/language/ja.js'),
    zh_CN: path.resolve(__dirname, './src/lang/language/zh_CN.js'),
    zh_TW: path.resolve(__dirname, './src/lang/language/zh_TW.js'),
  };

  // 提取所有语言的翻译
  const langObjects = {};
  for (const lang in mainLangFiles) {
    langObjects[lang] = await extractLangObject(mainLangFiles[lang]);
    console.log(`Extracted ${lang} language file`);
  }

  // 获取所有唯一键
  const allKeys = new Set();
  for (const lang in langObjects) {
    Object.keys(langObjects[lang]).forEach((key) => allKeys.add(key));
  }

  // 构建翻译条目数组
  const translationEntries = [];
  for (const key of allKeys) {
    const entry = { key };
    for (const lang in langObjects) {
      entry[lang] = langObjects[lang][key] || '';
    }
    translationEntries.push(entry);
  }

  // 按键名排序以保持一致性
  translationEntries.sort((a, b) => a.key.localeCompare(b.key));

  // 写入文件
  fs.writeFileSync(outputFile, JSON.stringify(translationEntries, null, 2), 'utf8');
  console.log(`Merged translations into ${outputFile}`);
  console.log(`Processed ${translationEntries.length} translation entries`);
}

// 执行合并
mergeTranslations();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

# 将 json 反向输出回多语言配置

执行 node write-translations.js (单语言会合并输出到一个文件中)

// write-translations
import fs from 'fs';
import path from 'path';

// 还原嵌套对象
function unflattenObject(flatObj) {
  const result = {};
  for (const flatKey in flatObj) {
    const keys = flatKey.split('.');
    let cur = result;
    keys.forEach((k, idx) => {
      if (idx === keys.length - 1) {
        cur[k] = flatObj[flatKey];
      } else {
        cur[k] = cur[k] || {};
        cur = cur[k];
      }
    });
  }
  return result;
}

// 读取 translations.json
const translations = JSON.parse(fs.readFileSync(path.resolve('./translations.json'), 'utf8'));

// 语言列表
const langs = ['en', 'ja', 'zh_CN', 'zh_TW'];

// 为每种语言生成对象
const langObjects = {};
langs.forEach((lang) => {
  const flatObj = {};
  translations.forEach((item) => {
    if (item[lang] !== undefined) flatObj[item.key] = item[lang];
  });
  langObjects[lang] = unflattenObject(flatObj);
});

// 输出到各语言 JS 文件
langs.forEach((lang) => {
  const filePath = path.resolve(`./src/lang/language/${lang}.js`);
  const content = `export default ${JSON.stringify(langObjects[lang], null, 2)};\n`;
  fs.writeFileSync(filePath, content, 'utf8');
  console.log(`Synced translations to ${filePath}`);
});

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# 最佳实践

新增的没确认的翻译写在 translationsChange.json 里然后通过 node sync-translations.js write-translations.js 批量同步到多语言配置中

后续只要把 translationsChange.json 给翻译人员确认后,确认后的 translationsChange.json 再执行 node sync-translations.js write-translations.js 批量同步到多语言配置中,确认并同步过后就可以清空 translationsChange.json 了

也就是说日常只需要维护 translationsChange.json 文件就可以了,确保 translationsChange.json 中的都是没确认或需要修改的翻译

编辑 (opens new window)
上次更新: 2025/10/27 13:17:32
html导出pdf
微前端

← html导出pdf 微前端→

最近更新
01
H5调用微信jssdk
09-28
02
VueVirtualScroller
09-19
03
IoC 解决了什么痛点问题?
03-10
更多文章>
Copyright © 2019-2025 Study | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式