2.0.0 • Published 3 years ago

@fatesigner/i18n v2.0.0

Weekly downloads
-
License
MIT
Repository
github
Last release
3 years ago

i18n

npm download commitizen

i18n 国际化工具库

安装

npm i -S @fatesigner/i18n

使用

src/i18n/messages.ts

import { createLocaleMessages } from '@fatesigner/i18n';

// 先创建一份本地化环境对象并导出
export const i18nMessages = createLocaleMessages({
  app: {
    name: '',
    sidebar: {
      shrink: '',
      unfold: ''
    },
    settings: {
      title: ''
    }
  }
});

// 导出本地化环境对象类型
export type I18nMessagesType = typeof i18nMessages;
<template>
  <!-- 传统方式:字符串 -->
  <div class="flex items-center p-5 border-4 border-indigo-600">
    <p>app.name: {{ $t('app.name') }}</p>
    <p>app.sidebar.shrink: {{ $t('app.sidebar.shrink') }}</p>
  </div>
  <!-- I18nx createLocaleMessages 创建的 messages 可直接通过变量方式传入 $t,结合 typescript 从而获得强类型提示和检查的特性 -->
  <div class="flex items-center p-5 border-4 border-indigo-600">
    <p>app.name: {{ $t(i18nMessages.app.name) }}</p>
    <p>app.sidebar.shrink: {{ $t(i18nMessages.app.sidebar.shrink) }}</p>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';

import { i18nMessages } from './i18n/messages';

export default defineComponent({
  setup(){
    // 将输出: "app.name"
    console.log(i18nMessages.app.name);
    return {
      i18nMessages
    }
  }
});
</script>

src/i18n/langs/zh-CN.ts

根据类型配置对应的语言环境消息

import { I18nMessagesType } from '../messages';

// 中文 export default { app: { name: 'i18n 国际化', sidebar: { shrink: '折叠', unfold: '展开' }, settings: { title: '标题' } } } as I18nMessagesType;

### src/i18n/langs/en-US.ts
```ts
import { I18nMessagesType } from '../messages';

// 英语
export default {
  app: {
    name: 'i18n locale',
    sidebar: {
      shrink: 'Shrink',
      unfold: 'Unfold'
    },
    settings: {
      title: 'Title'
    }
  }
} as I18nMessagesType;

src/i18n/index.ts

import { I18nLanguageType, createVueI18n } from '@fatesigner/i18n';

// 定义默认显示语言,该变量可从缓存、环境变量中获取
const defaultLang: I18nLanguageType = 'zh_CN';

// 创建 i18n 实例
export const i18n = createVueI18n(
  {
    locale: defaultLang,
    messages: {
      // 同步加载默认语言包,因为使用按需加载的方式,所以在此不导入其他语言包
      [defaultLang]: require(`./langs/${defaultLang}`).default
    },
    // 是否使用 vue-i18n Legacy API 模式,默认为 true
    legacy: true,
    // 当前不存在 message 键时,将会显式回退到指定的语言环境
    fallbackLocale: defaultLang,
    // 只保留那些完全没有翻译给定关键字的警告
    silentFallbackWarn: true
  },
  {
    // 定义您的本地化环境信息加载的方式,当调用 i18n.set('zh-CN') 时执行
    loadLocale(langs) {
      return import(`./langs/${langs}`).then(async (msg) => {
        return msg.default;
      });
    }
  }
);

// 注册勾子,当语言包加载完成后执行
i18n.hooks.afterSet.tap(function (langs: I18nLanguageType) {
  // 动态改变您的 http request header,让服务器能提供支持的语言
  Axios.defaults.headers.common['Accept-Language'] = langs;
  // 改变当前 html 的 langs 标签
  document.querySelector('html').setAttribute('langs', langs);
});

src/plugins/dayjs.ts

如果您的应用使用了类似 dayjs 的插件,这些插件拥有自己的国际化加载方式,您可以注册 i18n 的 afterSet 钩子

import dayjs from 'dayjs';

import { i18n } from '../i18n';

// 定义 dayjs 的语言包加载方式 const loadDayjsLang = async (langs: I18nLanguageType) => { if (langs === 'zh-CN') { import('dayjs/locale/zh-cn').then(() => { dayjs.locale('zh-cn'); }); } else { // 其他环境统一使用英文 import('dayjs/locale/es-us').then(() => { dayjs.locale('es-us'); }); } };

// 加载初始语言包 loadDayjsLang(i18n._.global.locale);

// 注册 i18n 勾子,每当切换语言之后,重新加载 dayjs 的语言包 i18n.hooks.afterSet.tapAsync(loadLang);

### src/plugins/moduleA.ts
> 如果您的应用包含多个模块,它们有各自的本地化语言信息,您可以注册 i18n 的 beforeSet 钩子,将 messages 合并
```ts
import { merge } from 'lodash-es';

// 定义该 moduleA 的语言包加载方式
const loadModuleALang = async (langs: I18nLanguageType) => {
  if (langs === 'zh-CN') {
    import('./langs/zh-cn').then((res) => {
      return res.default;
    });
  } else {
    // 其他环境统一使用英文
    import('./langs/es-us').then((res) => {
      return res.default;
    });
  }
};

// 加载初始语言包
loadModuleALang(i18n._.global.locale).then((res) => {
  merge(i18n._.global.messages[i18n._.global.locale], res);
});

// 注册 i18n 勾子,每当切换语言之前,将会执行
i18n.hooks.beforeSet.tapAsync((langs: I18nLanguageType, locale) => {
  return loadModuleALang(langs).then((res) => {
    // 合并 message 对象
    return merge(locale, res);
  });
});

合并后,新的 i18n messages 对象结构为:

// i18n._.global.messages
{
  app: {
    sidebar: {
      shrink: '',
        unfold: ''
    },l
    settings: {
      title: ''
    }
  },
  moduleA: {
    title: '',
    message: ''  
  }
}

Vue3

src/main.ts

import { createApp } from 'vue';

import App from './App.vue';
import { i18n } from './i18n';

// 将 i18n._ 安装至 vue 实例中
const app = createApp(App).use(i18n._);

app.mount('#app');

src/App.vue

<template>
  <div class="p-20">
    <div class="flex items-center p-5 mb-6 border-4 border-indigo-600">
      <div>选择语言:</div>
      <select @change="onLanguageChange" v-model="language">
        <option v-for="item in languages" :value="item.value">{{item.text}}</option>
      </select>
    </div>
    <div class="flex items-center p-5 border-4 border-indigo-600">
      <p>app.name: {{ $t(i18nMessages.app.name) }}</p>
      <p>app.sidebar.shrink: {{ $t(i18nMessages.app.sidebar.shrink) }}</p>
    </div>
  </div>
</template>

<script lang="ts">
import { I18nLanguageType } from '@fatesigner/i18n';
import { defineComponent, ref } from 'vue';

import { i18n, i18nMessages } from './i18n';

export default defineComponent({
  setup(){
    // 当前选中的语言
    const language = ref<I18nLanguageType>(i18n._.global.locale);

    // 定义语言列表
    const languages = [
      {
        name: 'CN',
        value: 'zh-CN',
        text: '简体中文'
      },
      {
        name: 'US',
        value: 'en-US',
        text: 'English'
      }
    ];

    // 用户切换语言
    const onLanguageChange = () => {
      i18n.set(language);
    };

    return {
      i18nMessages,
      language,
      languages,
      onLanguageChange
    }
  }
});
</script>