i18n.ts 3.7 KB

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