翼度科技»论坛 编程开发 html5 查看内容

如何用 vscode 捞出还未国际化的中文词条

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
做国际化一个很头疼的坑就是,你不知道项目里到底还有哪些中文词条没有国际化处理
纯靠人工去检查不现实,也不靠谱,而且浪费资源
所以还是得通过脚本工具来检查,思路是:

  • 先保存好本地代码变更,准备好一个无文件变更的本地环境
  • 再通过脚本把代码里的非展示性中文移除掉

    • 注释里的中文、console 里的中文,已经国际化处理过的中文

  • 再用中文正则在 vscode 的全局搜索里匹配,捞出来的就是未国际化处理的中文词条
  • 最后需要回退本地的更改,毕竟脚本是直接改动本地文件
脚本仅仅是检查用,用完记得回退代码
匹配中文词条的正则


  • 单个中文:

    • [\u4E00-\u9FFF]

  • 连续中文:

    • [\u4E00-\u9FFF]+

  • 掺杂了各种符号、字母的中文句子:

    • [a-zA-Z0-9、:]*[\u4E00-\u9FFF]+[\u4E00-\u9FFF\.\-\*。,,a-zA-Z0-9/()()::”“!?、%_【】《》>~~ ]*
    • (这里不建议把 : : - ' " 这几个特殊符号也列到正则里,因为这些符号比较特殊,有的语法层面也支持,列进来反而会引出新问题,所以宁愿这种场景的句子被截成多断)

  • 最好再加上文件的排除:

    • *.css,*.scss,*.less,*.json,*.bat,privacyProtocal.html,userProtocal.html,*.md,webpack**.js,*.txt,*.svg,*.properties,*.npmrc,vve-i18n-cli.config.js,baas,config,*.art,demo_index.html,*.sh,*.xml,*.java


脚本

移除非展示性中文的脚本
  1. // index.js
  2. #!/usr/bin/env node
  3. /**
  4. * 用来移除掉指定项目里的以下几类场景的中文:
  5. * - 注释里的中文
  6. * - 被国际化全局函数包裹的中文 $t
  7. *
  8. * 这样子方便借助 vs code 的全局正则搜索中文功能,来快速 review 未国际化的中文
  9. * 正则: [\u4E00-\u9FA5]+
  10. */
  11. "use strict";
  12. const program = require("commander");
  13. const { loadConfig } = require("../configuration");
  14. const core = require("./core");
  15. const vfs = require("vinyl-fs");
  16. const map = require("map-stream");
  17. const path = require("path");
  18. const fs = require("fs");
  19. function commaSeparatedList(value, split = ",") {
  20.   return value.split(split).filter((item) => item);
  21. }
  22. program
  23.   .version(require("../../package.json").version)
  24.   .option("--cwd <path>", "工作目录")
  25.   .option("--root-dir <path>", "国际文本所在的根目录")
  26.   .option(
  27.     "--config <path>",
  28.     "配置文件的路径,没有配置,默认路径是在${cwd}/vve-i18n-cli.config.js"
  29.   )
  30.   .option("--no-config", "是否取配置文件")
  31.   .option(
  32.     "--i18n-file-rules <items>",
  33.     "匹配含有国际化文本的文件规则",
  34.     commaSeparatedList
  35.   )
  36.   .option(
  37.     "--ignore-i18n-file-rules <items>",
  38.     "不匹配含有国际化文本的文件规则",
  39.     commaSeparatedList
  40.   )
  41.   .parse(process.argv);
  42. const config = {
  43.   // 工作目录
  44.   cwd: ".",
  45.   // 根目录,国际文本所在的根目录
  46.   rootDir: "src",
  47.   // 配置文件的路径,没有配置,默认路径是在${cwd}/vve-i18n-cli.config.js
  48.   config: undefined,
  49.   // 是否取配置文件
  50.   noConfig: false,
  51.   // 匹配含有国际化文本的文件规则
  52.   i18nFileRules: ["**/*.+(vue|js|html|htm)"],
  53.   // 不匹配含有国际化文本的文件规则
  54.   ignoreI18nFileRules: ["**/node_modules/**"],
  55. };
  56. Object.assign(config, program);
  57. const CONFIG_JS_FILENAME = "vve-i18n-cli.config.js";
  58. let absoluteCwd = path.resolve(config.cwd);
  59. // 优先判断是否需要读取文件
  60. if (!config.noConfig) {
  61.   let configFilePath = path.join(absoluteCwd, CONFIG_JS_FILENAME);
  62.   if (config.config) {
  63.     configFilePath = path.resolve(config.config);
  64.   }
  65.   if (fs.existsSync(configFilePath)) {
  66.     const conf = loadConfig(configFilePath);
  67.     if (conf && conf.options && conf.options.zhCheck) {
  68.       Object.assign(config, conf.options.zhCheck, program);
  69.     }
  70.   }
  71. }
  72. // 制定配置文件后,cwd在配置文件中定义,则cwd就需要重新获取
  73. if (!program.cwd) {
  74.   absoluteCwd = path.resolve(config.cwd);
  75. }
  76. const absoluteRootDir = path.resolve(absoluteCwd, config.rootDir);
  77. function run() {
  78.   console.log("================================>start");
  79.   vfs
  80.     .src(
  81.       config.i18nFileRules.map((item) => path.resolve(absoluteRootDir, item)),
  82.       {
  83.         ignore: config.ignoreI18nFileRules.map((item) =>
  84.           path.resolve(absoluteRootDir, item)
  85.         ),
  86.         dot: false,
  87.       }
  88.     )
  89.     .pipe(
  90.       map((file, cb) => {
  91.         console.log("开始解析 =========================>", file.path);
  92.         const extname = path.extname(file.path);
  93.         let fileContent = file.contents.toString();
  94.         let newFileContent = fileContent;
  95.         if (extname.toLowerCase() === ".vue") {
  96.           newFileContent = core.removeUnusedZhInVue(fileContent);
  97.         } else if (extname.toLowerCase() === ".js") {
  98.           newFileContent = core.removeUnusedZhInJs(fileContent);
  99.         } else if ([".html", ".htm"].includes(extname.toLowerCase())) {
  100.           newFileContent = core.removeUnusedZhInHtml(fileContent);
  101.         }
  102.         if (newFileContent !== fileContent) {
  103.           console.log("发现无用的中文,正在移除中...");
  104.           fs.writeFileSync(file.path, newFileContent);
  105.         }
  106.         console.log("解析结束 =========================>", file.path);
  107.         cb();
  108.       })
  109.     )
  110.     .on("end", () => {
  111.       console.log("================================>end");
  112.     });
  113. }
  114. run();
复制代码
  1. // core.js
  2. // 包含中文
  3. const zhReg = new RegExp("[\\u4E00-\\u9FFF]+", "");
  4. // 处理 vue 文件
  5. function removeUnusedZhInVue(fileContent) {
  6.   return removeUnusedZh(fileContent);
  7. }
  8. exports.removeUnusedZhInVue = removeUnusedZhInVue;
  9. // 处理 js 文件
  10. function removeUnusedZhInJs(fileContent) {
  11.   return removeUnusedZh(fileContent);
  12. }
  13. exports.removeUnusedZhInJs = removeUnusedZhInJs;
  14. // 处理 html 文件
  15. // 处理 js 文件
  16. function removeUnusedZhInHtml(fileContent) {
  17.   return removeUnusedZh(fileContent);
  18. }
  19. exports.removeUnusedZhInHtml = removeUnusedZhInHtml;
  20. function removeUnusedZh(fileContent) {
  21.   const hasAnnotation = {
  22.     "/*": false,
  23.     "
  24.   if (hasAnnotation["", "g");
  25.     fileContent = fileContent.replace(reg, function (match, key, index) {
  26.       let newKey = key;
  27.       while (newKey.match(zhReg)) {
  28.         newKey = newKey.replace(zhReg, "");
  29.       }
  30.       return match.replace(key, newKey);
  31.     });
  32.   }
  33.   return fileContent;
  34. }
复制代码
  1. // configuration.js
  2. const buildDebug = require("debug");
  3. const path = require("path");
  4. const debug = buildDebug("files:configuration");
  5. function loadConfig(filepath) {
  6.   try {
  7.     const conf = readConfig(filepath);
  8.     return conf;
  9.   } catch (e) {
  10.     debug("error", e);
  11.     return null;
  12.   }
  13. }
  14. function readConfig(filepath) {
  15.   let options;
  16.   try {
  17.     const configModule = require(filepath);
  18.     options =
  19.       configModule && configModule.__esModule
  20.         ? configModule.default || undefined
  21.         : configModule;
  22.   } catch (err) {
  23.     throw err;
  24.   } finally {
  25.   }
  26.   return {
  27.     filepath,
  28.     dirname: path.dirname(filepath),
  29.     options,
  30.   };
  31. }
  32. module.exports = {
  33.   loadConfig,
  34.   readConfig,
  35. };
复制代码
  1. {
  2.   "dependencies": {
  3.     "commander": "^3.0.2",
  4.     "debug": "^4.1.1",
  5.     "jsonfile": "^5.0.0",
  6.     "lodash.uniq": "^4.5.0",
  7.     "map-stream": "0.0.7",
  8.     "pinyin-pro": "^3.11.0",
  9.     "translation.js": "^0.7.9",
  10.     "vinyl-fs": "^3.0.3",
  11.     "xlsx": "^0.18.5"
  12.   },
  13.   "devDependencies": {
  14.     "chai": "^4.2.0",
  15.     "mocha": "^6.2.1",
  16.     "nyc": "^14.1.1",
  17.     "shelljs": "^0.8.3",
  18.     "standard-version": "^7.0.0"
  19.   },
  20.   "version": "3.2.3"
  21. }
复制代码
  1. // vve-i18n-cli.config.js
  2. module.exports = {
  3.   // 工作目录
  4.   cwd: ".",
  5.   // 根目录,国际文本所在的根目录
  6.   rootDir: "demo",
  7.   // 默认所有模块,如果有传module参数,就只处理某个模块
  8.   // '**/module-**/**/index.js'
  9.   moduleIndexRules: ["*/pro.properties"],
  10.   // 匹配含有国际化文本的文件规则
  11.   i18nFileRules: ["**/*.+(vue|js)"],
  12.   // 国际化文本的正则表达式,正则中第一个捕获对象当做国际化文本
  13.   i18nTextRules: [/(?:[\$.])t\(['"](.+?)['"]/g],
  14.   // 模块的国际化的json文件需要被保留下的key,即使这些组件在项目中没有被引用
  15.   // key可以是一个字符串,正则,或者是函数
  16.   keepKeyRules: [
  17.     /^G\/+/, // G/开头的会被保留
  18.   ],
  19.   ignoreKeyRules: [/^el/],
  20.   // 生成的国际化资源包的输出目录
  21.   outDir: "i18n",
  22.   // 生成的国际化的语言
  23.   i18nLanguages: [
  24.     "zh", // 中文
  25.     "en", // 英文
  26.   ],
  27.   // 是否翻译
  28.   translate: false,
  29.   // 翻译的基础语言,默认是用中文翻译
  30.   translateFromLang: "zh",
  31.   // 是否强制翻译,即已翻译修改的内容,也重新用翻译生成
  32.   forceTranslate: false,
  33.   // 翻译的语言
  34.   translateLanguage: ["zh", "en"],
  35.   // 模块下${outDir}/index.js文件不存在才拷贝index.js
  36.   copyIndex: true,
  37.   // 是否强制拷贝最新index.js
  38.   forceCopyIndex: false,
  39.   // 国际化文本包裹相关
  40.   zhWrap: {
  41.     cwd: ".",
  42.     // 根目录,国际文本所在的根目录
  43.     rootDir: ".",
  44.     i18nFileRules: [
  45.       "!(node_modules|config)/**/*.+(vue)",
  46.       // "base/components/login.vue",
  47.       "base/common/js/httpHandle.js",
  48.     ],
  49.     ignorePreReg: [
  50.       /t\s*\(\s*$/,
  51.       /tl\s*\(\s*$/,
  52.       /console\.(?:log|error|warn|info|debug)\s*\(\s*$/,
  53.       new RegExp("//.+"),
  54.     ],
  55.     // js相关文件需要引入的国际化文件
  56.     i18nImportForJs: "import i18n from '@inap_base/i18n/core'",
  57.     // js相关文件需要使用国际化方法
  58.     jsI18nFuncName: "i18n.t",
  59.     // vue相关文件需要使用的国际化方法
  60.     vueI18nFuncName: "$t",
  61.   },
  62. };
复制代码
硬替换脚本

具体查看 zh-i18n.zip

来源:https://www.cnblogs.com/dasusu/p/17945999
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具