经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » Vue.js » 查看文章
扩展 jQurey.i18n.properties 的能力来向 vue-i18n 靠齐
来源:cnblogs  作者:请叫我大苏  时间:2024/1/8 9:27:22  对本文有异议

jQuery.i18n.properties 是 jQuery 老项目的国际化框架,其实国际化方案本质上都大同小异,都是需要用翻译函数包裹词条,然后根据词条文件来进行翻译

就是使用上与其他框架不太一样而已

但由于我们已经基于 vue 框架实现了一个国际化自动处理脚本,脚本会自动用全局函数包裹词条,自动提取到 json 文件中

因此,为了让这个老项目也能够用脚本来进行维护,又考虑到最小的改造成本和最小的影响,我们决定扩展 jQuery.i18n.properties 的能力,让它的国际化行为跟 vue-i18n 一致,也就能够用脚本来进行维护了

而且对于团队内的其他新人而言,也没必要去了解 jQuery.i18n.properties,毕竟扩展后的使用方式跟 vue-i18n 基本一样

那么扩展之前,先来看下 jQuery.i18n.properties 这个框架:

全局函数

$.i18n.properties(settings)

国际化初始化函数,用来设置当前语言,资源文件路径

$.i18n.prop(key, ...args)

国际化全局函数,根据 key 值去资源文件里找翻译,后续参数支持占位符替换

当根据 key 值找不到翻译时,会直接返回 key 值

类似 vue-i18n 的 $t

词条文件

.properties 格式文件

也是个键值对的配置文件,只是格式与 json 不一样

【en.properties】

  1. string_login=Login
  2. string_username=username
  3. string_password=password

【zh.properties】

  1. string_login=登录
  2. string_username=账号
  3. string_password=密码

扩展

增加支持 .json 格式的词条文件

重写 $.i18n 的全局函数,内部增加支持 json 词条的挂载,以及在原本翻译行为结束后,如果没翻译成功,则走入 json 词条里进行匹配,查看是否能翻译成功

这样能保证不改动原本项目里已有的国际化代码和行为,保持原样

新增或新改动到的代码就可以用新的方式去进行维护

所以才叫做扩展,而不是改造,毕竟扩展是以不影响原样为前提,不然谁知道老项目的屎山会由于什么修改而突然崩塌

  1. // i18n.expand.js
  2. /**
  3. * 劫持 jQuery.i18n.properties 的 api,扩展国际化能力:
  4. * 1. 支持 .json 格式的资源文件
  5. */
  6. function init(i18n) {
  7. // 注意,初始化需要在 jQuery.i18n.properties.js 文件加载后才能正常劫持到 i18n 的 api
  8. if (!i18n) return;
  9. wrapFnProperties(i18n);
  10. wrapFnProp(i18n);
  11. wrapMap(i18n);
  12. }
  13. /**
  14. * 挂载新的 map 对象来存储从 .json 资源文件里读取的国际化翻译信息
  15. */
  16. function wrapMap(i18n) {
  17. i18n.mapFromJson = i18n.mapFromJson || {};
  18. }
  19. /**
  20. * 劫持原 prop,如果原 prop 翻译失败,则再去 mapFromJson 里尝试翻译
  21. */
  22. function wrapFnProp(i18n) {
  23. let oldFn = i18n.prop;
  24. i18n.prop = function (key, ...args) {
  25. let value = oldFn.call(i18n, key, ...args);
  26. // 如果原翻译行为未翻译成功,则尝试从 json 词条里去寻找翻译
  27. if (value === key) {
  28. // 这里把原 jquery.i18n.properties#prop 代码拷贝过来就行,然后把词条来源改成从json词条里寻找翻译
  29. value = $.i18n.mapFromJson[key];
  30. // ... 省略拷贝过来的代码
  31. }
  32. return value;
  33. };
  34. }
  35. /**
  36. * 劫持原 properties,获取国际化相关配置信息
  37. * 如:当前语言 language,【新增】json的国际化翻译信息
  38. */
  39. function wrapFnProperties(i18n) {
  40. let oldFn = i18n.properties;
  41. i18n.properties = function (settings, ...args) {
  42. if (settings.jsonResource) {
  43. i18n.mapFromJson = settings.jsonResource;
  44. }
  45. return oldFn.call(i18n, settings, ...args);
  46. };
  47. }
  48. // 如果当前已经加载完jquery.i18n.properties.js文件,就直接扩展它的能力
  49. if ($.i18n) {
  50. // 扩展 jquery.i18n.properties 的能力
  51. init($.i18n);
  52. }
  53. export default {
  54. init: init,
  55. };

然后在引入 jquery.i18n.properties.js 的 html 下面增加:

  1. <script type="text/javascript" src="/lib/jquery.i18n.properties.js"></script>
  2. <script type="text/javascript" src="/lib/i18n.expand.js"></script>

如果你们多页应用没有基类 html 文件的话,那如果有基类 js 的话,也可以在基类 js 里去初始化
尽量只在一个地方去初始化,省得需要每个 html 里去加代码

  1. import i18nExpand from "./i18n.expand";
  2. if ($.i18n) {
  3. // 扩展 jquery.i18n.properties 的能力
  4. i18nExpand.init($.i18n);
  5. }

给 Vue 挂载个全局函数 $t 指向 $.i18n.prop

我们老项目里有引入 Vue 框架,但也仅仅引入 Vue,没有引入其他全家桶系列,只用来在有新改动时,可以局部性使用 Vue 的响应式编程

而这里老项目里没必要再引入个 Vue-i18n 框架了,直接给挂载个全局函数 $t 指向原本的国际化方案的翻译函数即可

  1. if (Vue) {
  2. // 给 Vue 挂载全局函数
  3. Vue.prototype.$t = $.i18n.prop;
  4. }

properties 转 json 的脚本

如果嫌弃 properties 格式的文件不好维护词条,可以写个脚本来转换:

  1. /**
  2. * 将 properties 文件的国际化资源文件转成 json 格式文件
  3. * 脚本命令挂在 package.json 文件里
  4. * 注:由于 properties 文件的中文经过编码,该脚本会进行解码处理,以便中文可正常显示
  5. */
  6. const vfs = require("vinyl-fs");
  7. const map = require("map-stream");
  8. const path = require("path");
  9. const fs = require("fs");
  10. const ROOT_DIR = path.resolve(__dirname, "./");
  11. const fileRules = ["**/*.+(properties)"];
  12. const jsonFile = "properties2json.json";
  13. function ascii2native(value) {
  14. var character = value.split("\\u");
  15. var native1 = character[0];
  16. for (var i = 1; i < character.length; i++) {
  17. var code = character[i];
  18. native1 += String.fromCharCode(parseInt("0x" + code.substring(0, 4)));
  19. if (code.length > 4) {
  20. native1 += code.substring(4, code.length);
  21. }
  22. }
  23. return native1;
  24. }
  25. function run() {
  26. console.log("================================>start");
  27. let zhProperties = {};
  28. let enProperties = {};
  29. let curProperties = {};
  30. let res = {};
  31. const exist = fs.existsSync(path.resolve(ROOT_DIR, jsonFile));
  32. if (exist) {
  33. res = fs.readFileSync(path.resolve(ROOT_DIR, jsonFile), "utf-8");
  34. res = JSON.parse(res);
  35. }
  36. vfs
  37. .src(fileRules.map((item) => path.resolve(ROOT_DIR, item)))
  38. .pipe(
  39. map((file, cb) => {
  40. console.log("开始解析 =========================>", file.path);
  41. let count = 0;
  42. if (file.path.indexOf("_zh") > -1) {
  43. curProperties = zhProperties;
  44. } else {
  45. curProperties = enProperties;
  46. }
  47. let fileContent = file.contents.toString();
  48. fileContent.split("\n").map((line) => {
  49. if (line.indexOf("=") > -1) {
  50. count++;
  51. line = ascii2native(line);
  52. const [key, ...value] = line.split("=");
  53. // console.log(key, value);
  54. curProperties[key.trim()] = value.join("=").trim();
  55. }
  56. });
  57. console.log("词条数量:", count);
  58. console.log("解析结束 =========================>", file.path);
  59. cb();
  60. })
  61. )
  62. .on("end", () => {
  63. console.log("================================>end");
  64. // console.log(zhProperties);
  65. // console.log(enProperties);
  66. let unTranslate = {};
  67. Object.keys(zhProperties).map((key) => {
  68. if (enProperties[key]) {
  69. res[zhProperties[key]] = enProperties[key];
  70. } else {
  71. unTranslate[key] = zhProperties[key].trim();
  72. console.log("==>翻译丢失", key, zhProperties[key].trim());
  73. }
  74. });
  75. fs.writeFileSync(
  76. path.resolve(ROOT_DIR, jsonFile),
  77. JSON.stringify(res, " ", 2)
  78. );
  79. // fs.writeFileSync(
  80. // path.resolve(ROOT_DIR, "unTranslate.json"),
  81. // JSON.stringify(unTranslate, " ", 2)
  82. // );
  83. });
  84. }
  85. run();

总之,老项目的国际化原则就是控制影响面,降低维护成本,包括需要考虑交给新人去维护的情况

因此,能不改动到原方案就不改动,保持原方案不变的情况下,扩展支持跟 vue 项目一致的使用方式,以便国际化自动处理脚本也能够直接用来维护老项目

原文链接:https://www.cnblogs.com/dasusu/p/17946005

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号