# 国际化

如果你使用的 vscode 开发工具，则推荐安装 [I18n-ally](https://marketplace.visualstudio.com/items?itemName=Lokalise.i18n-ally) 这个插件

## I18n-ally 插件

安装了该插件后，你的代码内可以实时看到对应的语言内容

![](/images/i18n.png)

## 配置默认语言

在 [src/settings/localeSetting.ts](http://192.168.9.192/eci-frontend/starter-template/-/blob/main/src/settings/localeSetting.ts) 内可以配置默认语言

```ts
export const LOCALE: { [key: string]: LocaleType } = {
  ZH_CN: 'zh_CN',
  EN_US: 'en',
};

export const localeSetting: LocaleSetting = {
  // 是否显示语言选择器
  showPicker: true,
  // 当前语言
  locale: LOCALE.ZH_CN,
  // 默认语言
  fallback: LOCALE.ZH_CN,
  // 允许的语言
  availableLocales: [LOCALE.ZH_CN, LOCALE.EN_US],
};

// 配置语言列表
export const localeList: DropMenu[] = [
  {
    text: '简体中文',
    event: 'zh_CN',
  },
  {
    text: 'English',
    event: 'en',
  },
];
```

## 配置

在 [src/setupI18n.ts](http://192.168.9.192/eci-frontend/base-framework/-/blob/main/packages/locales/src/setupI18n.ts) 内引入的 i18n 这个无需修改

### 语言文件

在 [src/locales/lang/](http://192.168.9.192/eci-frontend/starter-template/-/tree/main/src/locales/lang) 可以配置具体的语言

```bash
# locales/lang/

# 中文语言
zh_CN:
  component: 组件相关
  layout: 布局相关
  routes: 路由菜单相关
  sys: 系统页面相关

en: 同上

```

### 语言导入逻辑说明

1. 初始化

在 [/packages/locales/src/setupI18n.ts](http://192.168.9.192/eci-frontend/base-framework/-/blob/main/packages/locales/src/setupI18n.ts) 内的根语言文件可以看到

```ts
const defaultLocal = await import(`./lang/${locale}.ts`);
```

这会导入 `src/locales/lang/{lang}.ts` 文件语言包，此文件会导入对应语言下的所有文件。

```ts
import { genMessage } from '../helper';
import antdLocale from 'ant-design-vue/es/locale/zh_CN';
import momentLocale from 'moment/dist/locale/zh-cn';

const modules = import.meta.glob('./zh_CN/**/*.ts', { eager: true });
export default {
  message: {
    ...genMessage(modules, 'zh_CN'),
    antdLocale,
  },
  momentLocale,
  momentLocaleName: 'zh-cn',
};
```

并将其按相应的目录结构转化为多层级的

例:

`lang/zh_CN/components/modal.ts` 的文件内容为

```ts
{
  title: '标题';
}
```

则在使用的使用直接使用 `t('components.modal.title')` 进行获取。

这样做的好处在于更容易管理大型项目的多语言。如果不需要分模块划分，可以直接自己手动导入即可。

## 使用

引入项目自带的 `useI18n` **注意不要引入 vue-i18n 的 useI18n**

```ts
import { useI18n } from '@eciol/locale';

const { t } = useI18n();

const title = t('components.modal.title');
```

## 切换语言

切换语言需要使用 [/packages/locales/src/useLocale.ts](http://192.168.9.192/eci-frontend/base-framework/-/blob/main/packages/locales/src/useLocale.ts)

```ts
import { useLocale } from '@eciol/locale';

const { changeLocale } = useLocale();

changeLocale('en');
```

## 新增

### 语言文件

在 [src/locales/lang/](http://192.168.9.192/eci-frontend/starter-template/-/tree/main/src/locales/lang) 增加对应语言的文件即可

### 新增语言

目前项目自带的语言只有 `zh_CN` 和 `en` 两种

如果需要新增，按以下操作即可

1. 在 [src/locales/lang/](http://192.168.9.192/eci-frontend/starter-template/-/tree/main/src/locales/lang) 下新增相应的语言目录及语言文件并引入 引入 ant-design-vue 和 moment 对应的语言包
2. 在 [types/config.d.ts](http://192.168.9.192/eci-frontend/starter-template/-/tree/main/types/config) 内加上预览类型定义
3. 在 [src/settings/localeSetting.ts](http://192.168.9.192/eci-frontend/starter-template/-/tree/main/src/settings/localeSetting.ts) 修改语言配置

## 远程读取语言数据

目前项目会在 `src/main.ts` 内等待 `setupI18n` 这个函数执行完之后才会渲染界面，所以只需在 setupI18n 内发送 ajax 请求，将对应的数据设置到 i18n 实例上即可

```ts
// src/main.ts
await setupI18n(app);

app.mount('#app', true);
```

### setupI18n 函数

代码: [/packages/locales/src/setupI18n.ts](http://192.168.9.192/eci-frontend/base-framework/-/blob/main/packages/locales/src/setupI18n.ts)

如下所示，这里会先设置一个默认语言，默认语言可以设置在本地，也可以在这里等待接口返回默认语言

```ts
// setup i18n instance with glob
export async function setupI18n(app: App) {
  const options = await createI18nOptions();
  i18n = createI18n(options) as I18n;
  app.use(i18n);
}

async function createI18nOptions(): Promise<I18nOptions> {
  const locale = localeStore.getLocale;

  // 这里改成接口获取
  const defaultLocal = await import(`./lang/${locale}.ts`);
  const message = defaultLocal.default?.message ?? {};

  return {
    legacy: false,
    locale,
    fallbackLocale: fallback,
    messages: {
      [locale]: message,
    },
    availableLocales: availableLocales,
    sync: true,
    silentTranslationWarn: true,
    missingWarn: false,
    silentFallbackWarn: true,
  };
}
```

### changeLocale 函数

代码: [/packages/locales/src/useLocale](http://192.168.9.192/eci-frontend/base-framework/-/blob/main/packages/locales/src/useLocale)

当手动切换语言的时候会触发 `useLocale` 函数，useLocale 也是异步函数，只需等待接口返回响应的数据后，再进行设置即可

```ts
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, momentLocale, momentLocaleName } = langModule;

  globalI18n.setLocaleMessage(locale, message);
  moment.updateLocale(momentLocaleName, momentLocale);
  loadLocalePool.push(locale);

  setI18nLanguage(locale);
  return locale;
}
```
