import type { App } from 'vue'; import type { Locale } from 'vue-i18n'; import type { ImportLocaleFn, LoadMessageFn, LocaleSetupOptions, SupportedLanguagesType, } from './typing'; import { unref } from 'vue'; import { createI18n } from 'vue-i18n'; import { useSimpleLocale } from '@vben-core/composables'; const i18n = createI18n({ globalInjection: true, legacy: false, locale: '', messages: {}, }); const modules = import.meta.glob('./langs/**/*.json'); const { setSimpleLocale } = useSimpleLocale(); const localesMap = loadLocalesMapFromDir( /\.\/langs\/([^/]+)\/(.*)\.json$/, modules, ); let loadMessages: LoadMessageFn; /** * Load locale modules * @param modules */ function loadLocalesMap(modules: Record Promise>) { const localesMap: Record = {}; for (const [path, loadLocale] of Object.entries(modules)) { const key = path.match(/([\w-]*)\.(json)/)?.[1]; if (key) { localesMap[key] = loadLocale as ImportLocaleFn; } } return localesMap; } /** * Load locale modules with directory structure * @param regexp - Regular expression to match language and file names * @param modules - The modules object containing paths and import functions * @returns A map of locales to their corresponding import functions */ function loadLocalesMapFromDir( regexp: RegExp, modules: Record Promise>, ): Record { const localesRaw: Record Promise>> = {}; const localesMap: Record = {}; // Iterate over the modules to extract language and file names for (const path in modules) { const match = path.match(regexp); if (match) { const [_, locale, fileName] = match; if (locale && fileName) { if (!localesRaw[locale]) { localesRaw[locale] = {}; } if (modules[path]) { localesRaw[locale][fileName] = modules[path]; } } } } // Convert raw locale data into async import functions for (const [locale, files] of Object.entries(localesRaw)) { localesMap[locale] = async () => { const messages: Record = {}; for (const [fileName, importFn] of Object.entries(files)) { messages[fileName] = ((await importFn()) as any)?.default; } return { default: messages }; }; } return localesMap; } /** * Set i18n language * @param locale */ function setI18nLanguage(locale: Locale) { i18n.global.locale.value = locale; document?.querySelector('html')?.setAttribute('lang', locale); } async function setupI18n(app: App, options: LocaleSetupOptions = {}) { const { defaultLocale = 'zh-CN' } = options; // app可以自行扩展一些第三方库和组件库的国际化 loadMessages = options.loadMessages || (async () => ({})); app.use(i18n); await loadLocaleMessages(defaultLocale); // 在控制台打印警告 i18n.global.setMissingHandler((locale, key) => { if (options.missingWarn && key.includes('.')) { console.warn( `[intlify] Not found '${key}' key in '${locale}' locale messages.`, ); } }); } /** * Load locale messages * @param lang */ async function loadLocaleMessages(lang: SupportedLanguagesType) { if (unref(i18n.global.locale) === lang) { return setI18nLanguage(lang); } setSimpleLocale(lang); const message = await localesMap[lang]?.(); if (message?.default) { i18n.global.setLocaleMessage(lang, message.default); } const mergeMessage = await loadMessages(lang); i18n.global.mergeLocaleMessage(lang, mergeMessage); return setI18nLanguage(lang); } export { i18n, loadLocaleMessages, loadLocalesMap, loadLocalesMapFromDir, setupI18n, };