i18n.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import type { App } from 'vue';
  2. import type { Locale } from 'vue-i18n';
  3. import type {
  4. ImportLocaleFn,
  5. LoadMessageFn,
  6. LocaleSetupOptions,
  7. SupportedLanguagesType,
  8. } from './typing';
  9. import { unref } from 'vue';
  10. import { createI18n } from 'vue-i18n';
  11. import { useSimpleLocale } from '@vben-core/composables';
  12. const i18n = createI18n({
  13. globalInjection: true,
  14. legacy: false,
  15. locale: '',
  16. messages: {},
  17. });
  18. const modules = import.meta.glob('./langs/**/*.json');
  19. const { setSimpleLocale } = useSimpleLocale();
  20. const localesMap = loadLocalesMapFromDir(
  21. /\.\/langs\/([^/]+)\/(.*)\.json$/,
  22. modules,
  23. );
  24. let loadMessages: LoadMessageFn;
  25. /**
  26. * Load locale modules
  27. * @param modules
  28. */
  29. function loadLocalesMap(modules: Record<string, () => Promise<unknown>>) {
  30. const localesMap: Record<Locale, ImportLocaleFn> = {};
  31. for (const [path, loadLocale] of Object.entries(modules)) {
  32. const key = path.match(/([\w-]*)\.(json)/)?.[1];
  33. if (key) {
  34. localesMap[key] = loadLocale as ImportLocaleFn;
  35. }
  36. }
  37. return localesMap;
  38. }
  39. /**
  40. * Load locale modules with directory structure
  41. * @param regexp - Regular expression to match language and file names
  42. * @param modules - The modules object containing paths and import functions
  43. * @returns A map of locales to their corresponding import functions
  44. */
  45. function loadLocalesMapFromDir(
  46. regexp: RegExp,
  47. modules: Record<string, () => Promise<unknown>>,
  48. ): Record<Locale, ImportLocaleFn> {
  49. const localesRaw: Record<Locale, Record<string, () => Promise<unknown>>> = {};
  50. const localesMap: Record<Locale, ImportLocaleFn> = {};
  51. // Iterate over the modules to extract language and file names
  52. for (const path in modules) {
  53. const match = path.match(regexp);
  54. if (match) {
  55. const [_, locale, fileName] = match;
  56. if (locale && fileName) {
  57. if (!localesRaw[locale]) {
  58. localesRaw[locale] = {};
  59. }
  60. if (modules[path]) {
  61. localesRaw[locale][fileName] = modules[path];
  62. }
  63. }
  64. }
  65. }
  66. // Convert raw locale data into async import functions
  67. for (const [locale, files] of Object.entries(localesRaw)) {
  68. localesMap[locale] = async () => {
  69. const messages: Record<string, any> = {};
  70. for (const [fileName, importFn] of Object.entries(files)) {
  71. messages[fileName] = ((await importFn()) as any)?.default;
  72. }
  73. return { default: messages };
  74. };
  75. }
  76. return localesMap;
  77. }
  78. /**
  79. * Set i18n language
  80. * @param locale
  81. */
  82. function setI18nLanguage(locale: Locale) {
  83. i18n.global.locale.value = locale;
  84. document?.querySelector('html')?.setAttribute('lang', locale);
  85. }
  86. async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
  87. const { defaultLocale = 'zh-CN' } = options;
  88. // app可以自行扩展一些第三方库和组件库的国际化
  89. loadMessages = options.loadMessages || (async () => ({}));
  90. app.use(i18n);
  91. await loadLocaleMessages(defaultLocale);
  92. // 在控制台打印警告
  93. i18n.global.setMissingHandler((locale, key) => {
  94. if (options.missingWarn && key.includes('.')) {
  95. console.warn(
  96. `[intlify] Not found '${key}' key in '${locale}' locale messages.`,
  97. );
  98. }
  99. });
  100. }
  101. /**
  102. * Load locale messages
  103. * @param lang
  104. */
  105. async function loadLocaleMessages(lang: SupportedLanguagesType) {
  106. if (unref(i18n.global.locale) === lang) {
  107. return setI18nLanguage(lang);
  108. }
  109. setSimpleLocale(lang);
  110. const message = await localesMap[lang]?.();
  111. if (message?.default) {
  112. i18n.global.setLocaleMessage(lang, message.default);
  113. }
  114. const mergeMessage = await loadMessages(lang);
  115. i18n.global.mergeLocaleMessage(lang, mergeMessage);
  116. return setI18nLanguage(lang);
  117. }
  118. export {
  119. i18n,
  120. loadLocaleMessages,
  121. loadLocalesMap,
  122. loadLocalesMapFromDir,
  123. setupI18n,
  124. };