vue3实现国际化

2023-10-26 17:25:47 浏览数 (2)

很多情况下要求代码支持国际化。看了文档及查阅资料。现将代码支持国际化的流程整理如下(vue版本3.2.27)

1.安装vue-i18n(vue3的话安装最新版本,否则可能会报错)

代码语言:javascript复制
npm install vue-i18n@next

2. 在utils文件下创建misc.js(此例子支持中文,英文,繁体,若想支持其他语言可配置相应语言)

代码语言:javascript复制
function useIE() {
  // for Now, detect IE 11 and Edge only, other IE version will has no support
  return (navigator.appName === 'Microsoft Internet Explorer'
    || !!(navigator.userAgent.match(/Trident/)
    || navigator.userAgent.match(/rv:11/)
    || navigator.userAgent.match(/Edge/)));
}

function isEllipsisActive(elem) {
  // Check whether text ellipsis is active
  return elem.offsetWidth < elem.scrollWidth;
}

function getRemoteFile(res) {
  if (!res) {
    return null;
  }
  const head = res.headers['content-disposition'];
  const type = res.headers['content-type'];

  const blob = new Blob([res.data], { type });
  let filename = head.split(';')[1].split('=')[1];
  const reg = new RegExp('"', 'g');
  filename = filename.replace(reg, '');
  return ({
    blob, filename,
  });
}


function downloadRawFile(blobData, filename) {
  if (blobData != null && navigator.msSaveBlob) {
    navigator.msSaveBlob(blobData, filename);
    return;
  }
  const link = document.createElement('a');
  link.href = window.URL.createObjectURL(blobData);
  link.setAttribute('download', filename);
  document.body.appendChild(link);
  link.click();
  window.URL.revokeObjectURL(link.href);
  document.body.removeChild(link);
}

function getBrowserLanguage() {
  const browserLanguage = window.navigator.language;
  console.log('browserLanguage: ', browserLanguage);
  // const validZHTW = ['zh-TW', 'zh-CN','en'];
  // console.log(i18n)
  return browserLanguage? browserLanguage : 'zh-CN';
}

function checkLanguage(locale) {
  const BaseLanguage = ['zh-CN', 'en','zh-TW'];
  return BaseLanguage.find(i18n => i18n === locale) || 'zh-CN';
  // return validZHTW.find(i18n => i18n === browserLanguage) ? 'zh-TW' : 'zh-CN';
}

// eslint-disable-next-line
document.head || (document.head = document.getElementsByTagName('head')[0]);
function changeFavicon(src) {
  const link = document.createElement('link');
  const oldLink = document.getElementById('dynamic-favicon');
  link.id = 'dynamic-favicon';
  link.rel = 'shortcut icon';
  link.href = src;
  if (oldLink) {
    document.head.removeChild(oldLink);
  }
  document.head.appendChild(link);
}


const passKeys = [
  16, // shift
  17, // ctrl
  18, // alt
  91, // meta
  93, // meta
  9, // tab
  20, // caps lock
];
// e is keyboard event, check if press controll key only
function controlKeyOnly(e) {
  for (let i = 0; i < passKeys.length; i  = 1) {
    if (e.keyCode === passKeys[i]) {
      return true;
    }
  }
  return false;
}

function recognizeJSDataType(obj) {
  let classToType;
  if (!classToType) {
    classToType = {};
    ['Boolean', 'Number', 'String', 'Function', 'Array', 'Date', 'RegExp', 'Object', 'Error'].forEach((e) => {
      classToType[`[object ${e}]`] = e.toLowerCase();
    });
  }
  if (obj === null) {
    return 'null';
  }
  if (typeof obj === 'object' || typeof obj === 'function') {
    return classToType[classToType.toString.call(obj)] || 'object';
  }
  return typeof obj;
}

function setPageTitle(name) {
  document.title = name;
}

function openWin(url, name, iWidth, iHeight) {
  const iTop = (window.screen.availHeight - 30 - iHeight) / 2;
  const iLeft = (window.screen.availWidth - 10 - iWidth) / 2;
  // eslint-disable-next-line
  window.open(url, name, 'height='   iHeight   ',innerHeight='   iHeight   ',width='   iWidth   ',innerWidth='   iWidth   ',top='   iTop   ',left='   iLeft   ',status=no,toolbar=no,menubar=no,location=no,resizable=no,scrollbars=0,titlebar=no');
}

export default {
  useIE,
  isEllipsisActive,
  getRemoteFile,
  downloadRawFile,
  controlKeyOnly,
  getBrowserLanguage,
  recognizeJSDataType,
  setPageTitle,
  changeFavicon,
  checkLanguage,
  openWin,
};

3.在src目录下创建locales文件夹,在locales文件夹下创建index.js

代码语言:javascript复制
import { createI18n } from "vue-i18n";
import zh from "./zh-CN";
import en from "./en";
import tw from "./zh-TW"
import misc from '@/utils/misc';


let locale = localStorage.getItem('locale');
console.log('locale: ', locale);
console.log('locale: ', !locale === true);
if (!locale) {
  locale = misc.getBrowserLanguage();
  console.log('locale: ', locale);
  // locale = 'zh-CN';
  localStorage.setItem('locale', locale);
}
// locale = misc.checkLanguage(locale);
// localStorage.setItem('locale', locale);
const i18n = createI18n({
  locale: locale, // 定义默认语言为中文
  legacy: false,
  globalInjection: true,
  messages: {
    'zh-CN': zh,
    'zh-TW': tw,
    en,
  },
});

export default i18n;
// {{ t('header_menu.logout') }}

4. 在locales文件夹下创建zh-CN.js(存放字典的js文件)

代码语言:javascript复制
export default {
  "welcomeToUse": "欢迎使用i18n",
  "login": "登录"
};

5. 在locales文件夹下创建zh-TW.js(存放字典的js文件)

代码语言:javascript复制
export default {
  "welcomeToUse": "欢迎使用i18n",
  "login": "台湾繁体"
};

6. 在locales文件夹下创建en.js(存放字典的js文件)

代码语言:javascript复制
export default {
  "welcomeToUse": "welcomeToUse.i18n",
  "login": "login"
};

7. 最后在main.js文件中引入

代码语言:javascript复制
import I18n from "./locales/index"

app.use(I18n);

8.路由和面包屑国际化

在国际化过程中会遇到路由和面包屑的国际化。在router中,跟i18n对象是同级传入new Vue()的,router无法获取i18n信息,因为国际化的方式则为:

代码语言:javascript复制
router下的路由规则文件(改变title的写法)
{
    path: '/scriptlibrary',
    component: () => import('@/views/Scriptlibrary/index'),
    meta: { 
      title: 'router.scriptlibrary',
      icon: "@scriptlibrary",
      activeMenu: '/scriptlibrary'
    },
    redirect: "/scriptlibrary/list",
    children: [
      {
        path: '/scriptlibrary/list',
        name: "Scriptlibrary",
        component: () => import('@/views/Scriptlibrary/List'),
        meta: { 
          title: 'router.scriptlibrary',
          icon: "@scriptlibrary",
        },
      },
      {
        path: '/scriptlibrary/scriptdetails',
        component: () => import('@/views/Scriptlibrary/ScriptDetails'),
        meta: { 
          title: 'router.scriptdetails',
          // icon: "ScriptDetails",
        },
        hidden: true,
      },
    ]
  },
代码语言:javascript复制
获取导航栏的写法不同($t(item.meta.title) ,面包屑同理)

<el-menu-item
          :index="resolvePath(onlyOneChild.path)"
          :class="{ 'submenu-title-noDropdown': !isNest }"
        >
          <svg-icon :icon-class="item.meta.icon.slice(1)" v-if="iconSubType(item) === 1"></svg-icon>
          <el-icon v-else-if="iconSubType(item) === 2">
            <component :is="item.meta.icon"></component>
          </el-icon>
          <template #title>
            <span class="title">{{ $t(item.meta.title) }}</span>
          </template>
        </el-menu-item>

9.在script中使用国际化

代码语言:javascript复制
引入
import { useI18n } from 'vue-i18n'
const { t } = useI18n()

使用
t('scriptlibrary.importDrawer.success')

0 人点赞