[vue]国际化功能的实现

通过语言的选择,使得网页展示内容为对应的语言

UI组件使用的是ant-design-vue,直接使用它的国际化组件,用于实现ant-design-vue各组件的国际化;

第一次实现国际化的功能时直接使用了 ant-design-vue的国际化组件,标签没有起作用

在真正的使用过程中绕了很多弯路,这里记录一下,方便以后查找

环境:

"vue": "^3.0.0"
 "ant-design-vue": "^3.1.0-rc.5"

ant-design-vue的国际化

这个主要是引入的UI框架(ant-design-vue)自己的组件,例如时间选择组件,输入框等的默认提示信息的国际化变更

引入国际化组件 :ConfigProvider

const app = createApp(App);

import {  ConfigProvider} from "ant-design-vue";

app.use(ConfigProvider);

修改antd的语言类型

 <a-config-provider :locale="antdLocale">

该标签一般放在最外层的.vue文件中 一般是App.vue ,也可以是你自定义的其它可以包含其它所有路由的外层vue文件,这样修改语言的时候,内部的所有组件都可以被国际化组件重新渲染

引入ant-design-vue 的你涉及到的国际化文件类型

import zhCN from "ant-design-vue/es/locale/zh_CN";
import zhTW from "ant-design-vue/es/locale/zh_TW";
import enUS from "ant-design-vue/es/locale/en_US";


export const antdLang: { [key: string]: any } = {
  zh_CN: zhCN,
  zh_TW: zhTW,
  en_US: enUS
};

设置antdLocale的定义与变更,param.key是点击要变成的语言的值,可以是 zh_CN/zh_TW/en_US

setup(){

const antdLocale=ref<string>(antdLang[" zh_CN"]);

const changLang=(param)=>{
      	//转化为antd对应的语言,
      	antdLocale.value=antdLang[param.key];//作用于所有的 ant-design-vue 的所有组件
        }
}

在这里插入图片描述

在这里插入图片描述

配置自定义文件的国际化

像是菜单等这种目录内容,也希望根据选择的语言,实现不同的语言展示,这个的展示内容需要自已定义各种语言的展示内容
这个要如何实现?

基本设置

此时需要引入

npm install vue-i18n

配置文件i18n.ts

import { createI18n, VueMessageType } from "vue-i18n";
import { LocaleMessages } from "@intlify/core-base";
import zhCN from "ant-design-vue/es/locale/zh_CN";
import zhTW from "ant-design-vue/es/locale/zh_TW";
import enUS from "ant-design-vue/es/locale/en_US";

export const antdLang: { [key: string]: any } = {
  zh_CN: zhCN,
  zh_TW: zhTW,
  en_US: enUS
};
//语言存储标志
export const langKey = "lang";
// 默认语言
export const defaultLang = "zh_CN";

/**
 * 验证语言命名规则 zh_CN
 * @returns boolen
 */
export const localeNameExp = (lang: string): boolean => {
  const localeExp = new RegExp(`^([a-z]{2})_?([A-Z]{2})?$`);
  return localeExp.test(lang);
};

/**
 * 获取当前语言
 * @returns string
 */
export const getLocale = (): string => {
  const lang =typeof localStorage !== "undefined" ? localStorage.getItem(langKey) : "";
  const isNavigatorLang =typeof navigator !== "undefined" && typeof navigator.language === "string";
  const browserLang = isNavigatorLang ? navigator.language.split("-").join("_") :"";
  return lang || browserLang || defaultLang;
};

/**
 * 设置 html 页面 lang 属性值
 * @param lang 语言的 key
 */
export const setPageLang = (lang: string) => {
  //axios.defaults.headers.common['Accept-Language'] = locale
  document.querySelector("html")?.setAttribute("lang", lang);
};
/**
 * 切换语言
 * @param lang 语言的 key
 * @param reload 是否刷新页面(一般不应该整个页面刷新)
 */
export const setLocale = (lang: string, reload: boolean, callback: Function) => {
  if (lang !== undefined && !localeNameExp(lang)) {
    // for reset when lang === undefined
    throw new Error("setLocale lang format error");
  }
  if (getLocale() !== lang) {
    if (typeof localStorage !== "undefined") {
      localStorage.setItem(langKey, lang || "");
    }

    if (reload) {
      window.location.reload();
    } else {
      setPageLang(lang);

      if (typeof callback === "function") {
        callback();
      }
    }
  }
};
/**
 * 设置语言
 * @param locale
 */
export function setI18nLang(locale: string, reload = true) {
  setLocale(locale, reload, function() {
    i18n.global.locale = locale; // legacy: true
    // i18n.global.locale.value = locale;
  });
}
/**
 * 自动导入 所有自定义的语言--获取所有自定义的国际化文件,并返回
 */
export function importAllLocales(): LocaleMessages<VueMessageType> {
  const modules: LocaleMessages<VueMessageType> = {};
  const contextList=[];
  try {
    // 导入 @/views 下文件,包含子目录,文件名为:[/\\]locales[/\\]([a-z]{2})-?([A-Z]{2})?\.ts
    const localesFolderReg: RegExp = new RegExp(
      /[/\\]locales[/\\]([a-z]{2})_?([A-Z]{2})?\.ts$/,
      "g"
    );
    // const folders = ["../router"];//"../views", "../components", "../"
    // folders.forEach(item => {
    //require.context("查找目录",是否查找子文件夹,符合规则的正则表达式) :

    // require.context不能使用表达式的变量作为参数,只能直接使用
   // require.context尝试变量替换后报错  require.context不是方法
    //路径也不能使用变量代替
    //require.context不能在循环中使用,因为require.context的参数只能使用字面值,不能使用变量代替
    const folderRequireContext: __WebpackModuleApi.RequireContext = require.context("../router",true,/[/\\]locales[/\\]([a-z]{2})_?([A-Z]{2})?\.ts$/);
    contextList.push(folderRequireContext);
    //可以继续添加其它路径的folderRequireContext

   contextList.forEach(requireCtx=>{
requireCtx.keys().forEach(fileName => {
      // 获取内容
      const modulesConent =requireCtx(fileName);
      if (modulesConent.default) {
        // 获取 PascalCase 命名
        const modulesName = fileName.replace(/(.*\/)*([^.]+).*/gi, "$2");
        if (modules[modulesName]) {
          modules[modulesName] = {
            ...modules[modulesName],
            ...modulesConent.default
          };
        } else {
          modules[modulesName] = modulesConent.default;
        }
      }
    });
   });
  } catch (error) {
    console.log(error);
  }
  console.log(modules);
  return modules;
}
const messages = importAllLocales();

const i18n = createI18n({
  // legacy: false,
  locale: getLocale(),
  messages: messages,
  silentFallbackWarn:true,
  silentTranslationWarn: true //去除警告信息
});


export default i18n;

在该配置文件中 importAllLocales 非常重要,将所有的自定义的国际化文件引入 i18n的范围内,使得 i18n.global.locale 值发生变化的时候 所有通过t()解析时去获取对应文件的值

报错 TypeError: __webpack_require__(...).context is not a function

TypeError: webpack_require(…).context is not a function
at importAllLocales (i18n.ts?b778:129)
at eval (i18n.ts?b778:166)
at Module…/src/config/i18n.ts (app.js:162)
at webpack_require (app.js:1473)
at fn (app.js:1755)
at eval (main.ts:6)
at Module…/src/main.ts (app.js:195)
at webpack_require (app.js:1473)
at app.js:2664
at Function.webpack_require.O (app.js:1522)

主要使用require.context(path,true,folderRule)使用变量了,若是直接使用值就没有问题
folderRule是个表达式,主要是用来表示文件名称的命名规则

全局使用国际化的配置,在main.ts文件中:

app.use( i18n);

在具体的vue文件中设置国际化的配置

template

<a-config-provider :locale="antdLocale">

script:

import { useI18n } from "vue-i18n";
import {antdLang,setI18nLang} from "@/config/i18n";

const { locale } = useI18n();//获取国际化配置文件中设置的语言默认值

const antdLocale=ref<string>(antdLang[locale.value]);

const changLang=(param)=>{
      //转化为对应的语言,
      antdLocale.value=antdLang[param.key];
     //修改全局的国际化配置中当前语言的值
      setI18nLang(param.key,false);

 }

国际化展示自定义内容

在具体的国际化展示自定义内容中,类似于自定义的路由名称的国际化展示作为例子

我们在路由文件中定义路由时,可以设置路由的名称为一个键值"sider.index"

{
    path: "/index",
    name:"sider.index",
    component: Index
  },

然后在对应的locales文件夹的不同语言文件中分别设置该值应该展示的内容
在这里插入图片描述

en_US

export default {
  'sider.index': 'index',
};

zh_CN

export default {
  'sider.index': '首页',
};

在使用该值的过程中

需要使用方法t
这里的menu就是路由的一个项

{
    path: "/index",
    name:"sider.index",
    component: Index
  }

menu.name即指向了sider.index

然后通过t()解析该键值

相关代码

template:

<span>{{t(menu.name)}}</span>

引入t

import { useI18n } from "vue-i18n";
setup() {
    const { t } = useI18n();
    return {
      t
    }
  }

在这里插入图片描述

importAllLocales() 引入的配置文件 对403/404这两个目录没有对应的中英问解析,所以报错.其它正常
在这里插入图片描述

silentFallbackWarn:true,
silentTranslationWarn: true //去除警告信息
同时设置上述值去除所有警告
然后可以看到正常的语言切换

Logo

前往低代码交流专区

更多推荐