Vue-i18n踩坑记录

136 阅读2分钟

因为最近的一个Vue项目要上线国际版了,需要在中文版的基础上增加一个英文版。i18n虽然很方便,但还是有不少坑,记录在这里。

基本内容

  1. 现在Vue-i18n12+版本还没有太好的支持,建议使用9+版本。
npm install vue-i18n@9
  1. Vue-i18n是支持插值文本的,但插值用单括号。使用时用对象传入
// en.ts
const en = {
    hint: "{ count } files in total, { selected } selected"
}
<div class="selected-count">{{ t('upload.uploadTable.hint', {
        count: rows.length,
        selected: selectedFiles.length
    }) }}
</div>
  1. 列表渲染的中文文本在添加国际化后,不能用ref,ref也不能响应。必须用computed
const headers = computed(() => [
    { label: t('upload.table.selected'), key: '已选择', width: '60px' },
    { label: t('upload.table.id'), key: 'id', width: '130px' },
    { label: t('upload.table.filename'), key: '文件名', width: '160px' },
    { label: t('upload.table.expireTime'), key: '过期时间', width: '130px' },
    { label: t('upload.table.operation'), key: '操作', width: '160px' }
])
  1. 大部分中文转英文后文本会变长,需要换行或改元素宽度
<Button :width="locale === 'en' ? '130px' : '140px'" @click="handleConfirmUpload">
    {{t('upload.buttons.confirm')}}
</Button>
  1. 中文不需要考虑复数,英文还要加一层if判断,多于一个需要加复数
  2. 不支持响应式的环境怎么办? 比如Web Worker。建议中文英文各维护一个worker.ts版本,再把公共函数抽出来!因为需要中英文的多线程模块一般都非常复杂,不适合直接维护。比如我用的jsPDF渲染文档,排版和字体包都不一样。

其他内容

如何把来自后台的错误提示i18n化?

例如:登录页面一共有2个错误码:"USR_001"(用户名不存在)、"USR_002"(密码不正确)

首先把i18n组织成一个文件:

// i18n.ts
import zh from "./zh.ts";
import en from "./en.ts";
import { createI18n } from "vue-i18n";

export const i18n = createI18n({
  legacy: false,
  locale: "zh",
  fallbackLocale: "en",
  messages: {
    zh,
    en,
  },
});

并导入axios响应拦截器:

// axios.ts
export function setupAxiosInterceptors(app: App) {
  axiosInstance.interceptors.response.use(
    (response: AxiosResponse) => {
      return response.data;
    },
    (error: any) => {
      console.log(error.response);
      // 将i18n对应字段以插值方式拼接成对应的i18n字段
      alert(t(`errCode.${error.response.data.detail.code}`)); 
      if (error.response.status === 401) {
        app.config.globalProperties.$router.push("/login"); // 401跳转
      }
      return Promise.reject(/*错误处理*/);
    }
  );
}

main.ts引入:

// main.ts
// ···
app.use(i18n);
setupAxiosInterceptors(app);
// ···

这样可以把i18n的错误码组织成:

// zh.ts
export interface ErrCode {
  USER_001: string;
  USER_002: string;
  // ···
}

const errCode: ErrCode = {
  USER_001: "用户不存在",
  USER_002: "用户账号或密码错误",
  // ···
};

const zh = {
  errCode,
  // ···
};
export default zh;