i18n支持传入变量标识可以做变更文字显示,但如果要让这个变量显示组件的话需要用到插槽
在vue3中需要用i18n-t标签,keypath为i18n值的路径,里面就可以放我们想要的组件
代码如下
i18n已全局引入,无需再引入i18n-t。
- // routes.operConfig.json
- {"low": "换电前电量低于{number1}%,换电后电量高于{number2}%,为有效换电"}
"routes.operConfig.low"> - <template #number1>
- <InputNumber :max="100" v-model:value="formData.sysOperPowerReplace.beforeRate" />
- template>
- <template #number2>
- <InputNumber :max="100" v-model:value="formData.sysOperPowerReplace.afterRate" />
- template>
如何配置全局i18n
- // main.js
- import { setupI18n } from '@/locales/setupI18n';
- // 异步案例:语言文件可能从服务器端获取
- await setupI18n(app);
@/locales/setupI18n
- import type { App } from 'vue';
- import type { I18nOptions } from 'vue-i18n';
-
- import { createI18n } from 'vue-i18n';
- import { setHtmlPageLang, setLoadLocalePool } from './helper';
- import { localeSetting } from '@/settings/localeSetting';
- import { useLocaleStoreWithOut } from '@/store/modules/locale';
-
- const { fallback, availableLocales } = localeSetting;
-
- export let i18n: ReturnType<typeof createI18n>;
-
- async function createI18nOptions(): Promise
{ - const localeStore = useLocaleStoreWithOut();
- const locale = localeStore.getLocale;
- const defaultLocal = await import(`./lang/${locale}.ts`);
- const message = defaultLocal.default?.message ?? {};
-
- setHtmlPageLang(locale);
- setLoadLocalePool((loadLocalePool) => {
- loadLocalePool.push(locale);
- });
-
- return {
- legacy: false,
- locale,
- fallbackLocale: fallback,
- messages: {
- [locale]: message,
- },
- availableLocales: availableLocales,
- sync: true, //If you don’t want to inherit locale from global scope, you need to set sync of i18n component option to false.
- silentTranslationWarn: true, // true - warning off
- missingWarn: false,
- silentFallbackWarn: true,
- };
- }
-
- // setup i18n instance with glob
- export async function setupI18n(app: App) {
- const options = await createI18nOptions();
- i18n = createI18n(options);
- app.use(i18n);
- }
./helper.ts
- import type { LocaleType } from '#/config';
-
- export const loadLocalePool: LocaleType[] = [];
-
- export function setHtmlPageLang(locale: LocaleType) {
- document.querySelector('html')?.setAttribute('lang', locale);
- }
-
- export function setLoadLocalePool(cb: (loadLocalePool: LocaleType[]) => void) {
- cb(loadLocalePool);
- }
@/settings/localeSetting
- import type { LocaleSetting, LocaleType } from '#/config';
-
- export const LOCALE: { [key: string]: LocaleType } = {
- ZH_CN: 'zhCn',
- EN_US: 'enUs',
- KM_KH: 'kmKh',
- TH_TH: 'thTh',
- };
-
- export const localeSetting: LocaleSetting = {
- showPicker: true,
- // Locale
- locale: LOCALE.ZH_CN,
- // Default locale
- fallback: LOCALE.ZH_CN,
- // available Locales
- availableLocales: [LOCALE.ZH_CN, LOCALE.EN_US],
- };
@/store/modules/locale
- import type { LocaleSetting, LocaleType } from '#/config';
- import { defineStore } from 'pinia';
- import { store } from '@/store';
- import { LOCALE_KEY } from '@/enums/cacheEnum';
- import { createLocalStorage } from '@/utils/cache';
- import { localeSetting, LOCALE } from '@/settings/localeSetting';
-
- const ls = createLocalStorage();
-
- const lsLocaleSetting = (ls.get(LOCALE_KEY) || localeSetting) as LocaleSetting;
-
- interface LocaleState {
- localInfo: LocaleSetting;
- }
-
- export const useLocaleStore = defineStore({
- id: 'app-locale',
- state: (): LocaleState => ({
- localInfo: lsLocaleSetting,
- }),
- getters: {
- getShowPicker(state): boolean {
- return !!state.localInfo?.showPicker;
- },
- getLocale(state): LocaleType {
- return state.localInfo?.locale ?? 'zhCn';
- },
- },
- actions: {
- /**
- * getValue 函数用于从给定对象中获取值。
- * 它首先尝试获取 this.getLocale 的值,如果不存在,它将按照 LOCALE 对象的顺序获取值。
- * 如果所有尝试都失败,它将返回空字符串。
- *
- * @param {Object} obj - 需要获取值的对象,对象的键是字符串,值也是字符串
- * @returns {string} 返回获取到的值,如果没有找到则返回空字符串
- */
- getValue(obj: { [key: string]: string }) {
- if (obj) {
- if (Object.prototype.hasOwnProperty.call(obj, this.getLocale)) {
- return obj[this.getLocale];
- }
-
- for (const key in LOCALE) {
- if (Object.prototype.hasOwnProperty.call(obj, LOCALE[key])) {
- return obj[LOCALE[key]];
- }
- }
- }
-
- return '';
- },
-
- /**
- * Set up multilingual information and cache
- * @param info multilingual info
- */
- setLocaleInfo(info: Partial
) { - this.localInfo = { ...this.localInfo, ...info };
- ls.set(LOCALE_KEY, this.localInfo);
- },
- /**
- * Initialize multilingual information and load the existing configuration from the local cache
- */
- initLocale() {
- this.setLocaleInfo({
- ...localeSetting,
- ...this.localInfo,
- });
- },
- },
- });
-
- // Need to be used outside the setup
- export function useLocaleStoreWithOut() {
- return useLocaleStore(store);
- }
@/locales/useLocale
- import type { LocaleType } from '#/config';
-
- import { i18n } from './setupI18n';
- import { useLocaleStoreWithOut } from '@/store/modules/locale';
- import { unref, computed } from 'vue';
- import { loadLocalePool, setHtmlPageLang } from './helper';
- import { Locale } from 'ant-design-vue/es/locale';
-
- interface LangModule {
- message: Recordable;
- dateLocale: Recordable;
- dateLocaleName: string;
- }
-
- function setI18nLanguage(locale: LocaleType) {
- const localeStore = useLocaleStoreWithOut();
-
- if (i18n.mode === 'legacy') {
- i18n.global.locale = locale;
- } else {
- (i18n.global.locale as any).value = locale;
- }
- localeStore.setLocaleInfo({ locale });
- setHtmlPageLang(locale);
- }
-
- export function useLocale() {
- const localeStore = useLocaleStoreWithOut();
- const getLocale = computed(() => localeStore.getLocale);
- const getShowLocalePicker = computed(() => localeStore.getShowPicker);
-
- const getAntdLocale = computed((): any => {
- const localeMessage = i18n.global.getLocaleMessage<{ antdLocale: Locale }>(unref(getLocale));
- return localeMessage?.antdLocale ?? {};
- });
-
- // Switching the language will change the locale of useI18n
- // And submit to configuration modification
- async function changeLocale(locale: LocaleType) {
- const globalI18n = i18n.global;
- const currentLocale = unref(globalI18n.locale);
- if (currentLocale === locale) {
- return locale;
- }
-
- if (loadLocalePool.includes(locale)) {
- setI18nLanguage(locale);
- return locale;
- }
- const langModule = ((await import(`./lang/${locale}.ts`)) as any).default as LangModule;
- if (!langModule) return;
-
- const { message } = langModule;
-
- globalI18n.setLocaleMessage(locale, message);
- loadLocalePool.push(locale);
-
- setI18nLanguage(locale);
- return locale;
- }
-
- return {
- getLocale,
- getShowLocalePicker,
- changeLocale,
- getAntdLocale,
- };
- }
App.vue
- <ConfigProvider :locale="getAntdLocale" :theme="themeConfig">
- <AppProvider>
- <RouterView />
- AppProvider>
- ConfigProvider>
-
- <script lang="ts" setup>
- import { AppProvider } from '@/components/Application';
- import { useTitle } from '@/hooks/web/useTitle';
- import { useLocale } from '@/locales/useLocale';
- import { ConfigProvider } from 'ant-design-vue';
-
- import { useDarkModeTheme } from '@/hooks/setting/useDarkModeTheme';
- import 'dayjs/locale/zh-cn';
- import { computed } from 'vue';
-
- // support Multi-language
- const { getAntdLocale } = useLocale();
-
- const { isDark, darkTheme } = useDarkModeTheme();
-
- const themeConfig = computed(() =>
- Object.assign(
- {
- token: {
- colorPrimary: '#0062F7',
- colorSuccess: '#00B042',
- colorWarning: '#FF9200',
- colorError: '#FF5219',
- colorInfo: '#0062F7',
- },
- },
- isDark.value ? darkTheme : {},
- ),
- );
- // Listening to page changes and dynamically changing site titles
- useTitle();
- script>
语言包文件夹locales/lang/zhCn.ts
- import { genMessage } from '../helper';
- import antdLocale from 'ant-design-vue/es/locale/zh_CN';
- import { deepMerge } from '@/utils';
-
- const modules = import.meta.glob('./zh-CN/**/*.json', { eager: true });
-
- export default {
- message: {
- ...genMessage(modules as Recordable<Recordable>, 'zh-CN'),
- antdLocale: {
- ...antdLocale,
- DatePicker: deepMerge(
- antdLocale.DatePicker,
- genMessage(modules as Recordable<Recordable>, 'zh-CN').antdLocale.DatePicker,
- ),
- },
- },
- };
- // /locales/lang/zh-CN/common.json
- {
- "action": "操作",
- "add": "新增"
- }
递归合并两个对象
- /**
- * Recursively merge two objects.
- * 递归合并两个对象。
- *
- * @param source The source object to merge from. 要合并的源对象。
- * @param target The target object to merge into. 目标对象,合并后结果存放于此。
- * @param mergeArrays How to merge arrays. Default is "replace".
- * 如何合并数组。默认为replace。
- * - "union": Union the arrays. 对数组执行并集操作。
- * - "intersection": Intersect the arrays. 对数组执行交集操作。
- * - "concat": Concatenate the arrays. 连接数组。
- * - "replace": Replace the source array with the target array. 用目标数组替换源数组。
- * @returns The merged object. 合并后的对象。
- */
- export function deepMerge
extends object | null | undefined, U extends object | null | undefined>( - source: T,
- target: U,
- mergeArrays: 'union' | 'intersection' | 'concat' | 'replace' = 'replace',
- ): T & U {
- if (!target) {
- return source as T & U;
- }
- if (!source) {
- return target as T & U;
- }
- return mergeWith({}, source, target, (sourceValue, targetValue) => {
- if (isArray(targetValue) && isArray(sourceValue)) {
- switch (mergeArrays) {
- case 'union':
- return unionWith(sourceValue, targetValue, isEqual);
- case 'intersection':
- return intersectionWith(sourceValue, targetValue, isEqual);
- case 'concat':
- return sourceValue.concat(targetValue);
- case 'replace':
- return targetValue;
- default:
- throw new Error(`Unknown merge array strategy: ${mergeArrays as string}`);
- }
- }
- if (isObject(targetValue) && isObject(sourceValue)) {
- return deepMerge(sourceValue, targetValue, mergeArrays);
- }
- return undefined;
- });
- }
@/hooks/web/useI18n
- import { i18n } from '@/locales/setupI18n';
-
- type I18nGlobalTranslation = {
- (key: string): string;
- (key: string, locale: string): string;
- (key: string, locale: string, list: unknown[]): string;
- (key: string, locale: string, named: Record
): string; - (key: string, list: unknown[]): string;
- (key: string, named: Record
): string; - };
-
- type I18nTranslationRestParameters = [string, any];
-
- function getKey(namespace: string | undefined, key: string) {
- if (!namespace) {
- return key;
- }
- if (key.startsWith(namespace)) {
- return key;
- }
- return `${namespace}.${key}`;
- }
-
- export function useI18n(namespace?: string): {
- t: I18nGlobalTranslation;
- } {
- const normalFn = {
- t: (key: string) => {
- return getKey(namespace, key);
- },
- };
-
- if (!i18n) {
- return normalFn;
- }
-
- const { t, ...methods } = i18n.global;
-
- const tFn: I18nGlobalTranslation = (key: string, ...arg: any[]) => {
- if (!key) return '';
- if (!key.includes('.') && !namespace) return key;
-
- return (t as (arg0: string, ...arg: I18nTranslationRestParameters) => string)(
- getKey(namespace, key),
- ...(arg as I18nTranslationRestParameters),
- );
- };
- return {
- ...methods,
- t: tFn,
- };
- }
- // 为什么要编写此函数?
- // 主要用于配合vscode i18nn ally插件。此功能仅用于路由和菜单。请在其他地方使用useI18n
- export const t = (key: string) => key;
页面引用i18n
-
- {{t('common.is')}}
- <script setup lang="ts">
- import { useI18n } from '@/hooks/web/useI18n';
- const { t } = useI18n();
- script>