i18n.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // 多组件库的国际化和本地项目国际化兼容
  2. import { type I18n, createI18n } from "vue-i18n";
  3. import type { App, WritableComputedRef } from "vue";
  4. import { responsiveStorageNameSpace } from "@/config";
  5. import { storageLocal, isObject } from "@pureadmin/utils";
  6. // element-plus国际化
  7. import enLocale from "element-plus/es/locale/lang/en";
  8. import zhLocale from "element-plus/es/locale/lang/zh-cn";
  9. const siphonI18n = (function () {
  10. // 仅初始化一次国际化配置
  11. const cache = Object.fromEntries(
  12. Object.entries(
  13. import.meta.glob("../../locales/*.y(a)?ml", { eager: true })
  14. ).map(([key, value]: any) => {
  15. const matched = key.match(/([A-Za-z0-9-_]+)\./i)[1];
  16. return [matched, value.default];
  17. })
  18. );
  19. return (prefix = "zh-CN") => {
  20. return cache[prefix];
  21. };
  22. })();
  23. export const localesConfigs = {
  24. zh: {
  25. ...siphonI18n("zh-CN"),
  26. ...zhLocale
  27. },
  28. en: {
  29. ...siphonI18n("en"),
  30. ...enLocale
  31. }
  32. };
  33. /** 获取对象中所有嵌套对象的key键,并将它们用点号分割组成字符串 */
  34. function getObjectKeys(obj) {
  35. const stack = [];
  36. const keys: Set<string> = new Set();
  37. stack.push({ obj, key: "" });
  38. while (stack.length > 0) {
  39. const { obj, key } = stack.pop();
  40. for (const k in obj) {
  41. const newKey = key ? `${key}.${k}` : k;
  42. if (obj[k] && isObject(obj[k])) {
  43. stack.push({ obj: obj[k], key: newKey });
  44. } else {
  45. keys.add(key);
  46. }
  47. }
  48. }
  49. return keys;
  50. }
  51. /** 将展开的key缓存 */
  52. const keysCache: Map<string, Set<string>> = new Map();
  53. const flatI18n = (prefix = "zh-CN") => {
  54. let cache = keysCache.get(prefix);
  55. if (!cache) {
  56. cache = getObjectKeys(siphonI18n(prefix));
  57. keysCache.set(prefix, cache);
  58. }
  59. return cache;
  60. };
  61. /**
  62. * 国际化转换工具函数(自动读取根目录locales文件夹下文件进行国际化匹配)
  63. * @param message message
  64. * @returns 转化后的message
  65. */
  66. export function transformI18n(message: any = "") {
  67. if (!message) {
  68. return "";
  69. }
  70. // 处理存储动态路由的title,格式 {zh:"",en:""}
  71. if (typeof message === "object") {
  72. const locale: string | WritableComputedRef<string> | any =
  73. i18n.global.locale;
  74. return message[locale?.value];
  75. }
  76. const key = message.match(/(\S*)\./)?.input;
  77. if (key && flatI18n("zh-CN").has(key)) {
  78. return i18n.global.t.call(i18n.global.locale, message);
  79. } else if (!key && Object.hasOwn(siphonI18n("zh-CN"), message)) {
  80. // 兼容非嵌套形式的国际化写法
  81. return i18n.global.t.call(i18n.global.locale, message);
  82. } else {
  83. return message;
  84. }
  85. }
  86. /** 此函数只是配合i18n Ally插件来进行国际化智能提示,并无实际意义(只对提示起作用),如果不需要国际化可删除 */
  87. export const $t = (key: string) => key;
  88. export const i18n: I18n = createI18n({
  89. legacy: false,
  90. locale:
  91. storageLocal().getItem<StorageConfigs>(
  92. `${responsiveStorageNameSpace()}locale`
  93. )?.locale ?? "zh",
  94. fallbackLocale: "en",
  95. messages: localesConfigs
  96. });
  97. export function useI18n(app: App) {
  98. app.use(i18n);
  99. }