Skip to content

国际化(多语言)

WEB端

语言包定义

TIP

您可以在 /src/lang/autoload.ts 内定义按需加载的 额外加载 映射关系;您还可能需要脱离按需加载,可以直接将语言包放置于 /src/lang/common 目录,这样就能随处使用了。

  • WEB端项目语言包分为 第三方、全局、页面按需加载 语言包三种,其中最常用的 页面语言包,我们设计了分目录的管理方式。
  • 可以在 /src/lang/backend/语言/src/lang/frontend/语言 目录下,建立任意目录和语言包文件,程序会自动进行动态批量加载。

以下代码仅为定义和后续的使用演示用示例,以方便读者理解,并非项目实际的语言包文件。

ts
// 全局中文语言包文件 /src/lang/globs-zh-cn.ts
export default {
    // 语言翻译的key请勿带有英文句号(.)
    Home: '首页',
}

// 全局英文语言包文件 /src/lang/globs-en.ts
export default {
    Home: 'Home',
}

// 管理员后台`控制台页面`的中文语言包文件 /src/lang/backend/zh-cn/dashboard.ts(页面语言包,后台放在 backend 目录)
export default {
    republish: '重新发布',
}

// 管理员后台`控制台页面`的英文语言包文件 /src/lang/backend/en/dashboard.ts(页面语言包,后台放在 backend 目录)
export default {
    republish: 'Republish',
}

// 会员前台`会员登录`页面的中文语言包文件 /src/lang/frontend/zh-cn/user/login.ts(页面语言包,前台放在 frontend 目录)
export default {
    title: '登录到会员中心',
}

// 会员前台`会员登录`页面的英文语言包文件 /src/lang/frontend/en/user/login.ts(页面语言包,前台放在 frontend 目录)
export default {
    title: 'Login',
}

语言包使用

在模板和 TS 代码中使用

vue
<template>
    <!-- 全局翻译 -->
    <span :title="t('Home')"></span>
    <span>{{ t('Home') }}</span>

    <!-- 控制台页面可以使用的语言翻译 -->
    <!-- 系统根据路由的 name 和 path 自动加载对应目录结构的语言包 -->
    <span :title="t('dashboard.republish')"></span>
    <span>{{ t('dashboard.republish') }}</span>

    <!-- 会员登录页面可以使用的语言翻译 -->
    <!-- 系统根据路由的 name 和 path 自动加载对应目录结构的语言包 -->
    <span :title="t('user.login.title')"></span>
</template>

<script setup lang="ts">
import { useI18n } from 'vue-i18n'
const { t } = useI18n()

const globs = t('Home') // 使用全局翻译
const dashboard = t('dashboard.republish') // 在控制台页面内可以使用的语言翻译
const login = t('user.login.title') // 在会员登录页面内可以使用的语言翻译
</script>

仅在模板中使用

vue
<template>
    <!-- 全局翻译 -->
    <span :title="$t('Home')"></span>
    <span>{{ $t('Home') }}</span>

    <!-- 页面语言翻译 -->
    <span :title="$t('dashboard.republish')"></span>
    <span>{{ $t('dashboard.republish') }}</span>
</template>

<script setup lang="ts"></script>

实现介绍

  • web端的国际化使用了 vue-i18n 实现。
  • 我们只加载了当前环境对应的语言包,比如 zh-cn 或者 en 的语言包文件,所以切换语言包,站点会自动刷新。
  • 我们在 main.js 文件中调用 /@/lang/index 文件内的 loadLang 函数对多语言支持进行了初始化。
  • /@/lang/index 文件中,我们利用 import.meta.glob 批量加载了 element、公共 的语言包文件,并准备好了 页面 语言包的按需加载句柄(页面语言包并没有真正的加载,相当于准备好了可加载列表)。
  • 在用户真正打开对应页面时,再根据路由的 pathname 进行加载,按需自动加载的工作是在 /src/router/index.ts 中定义的。
  • 页面 语言包,支持无限目录层级加载,我们根据对应目录结构,实现了以 . 分隔的语言翻译 key,比如:/@/lang/backend/zh-cn/auth/menu.ts 语言包定义如下:
ts
export default {
    name: '名称',
    stateList: {
        'state 1': '状态1',
        'state 2': '状态2',
    },
}
ts
// 使用该语言翻译
// 它的格式是:目录.目录.翻译key
t('auth.menu.name')
t('auth.menu.stateList.state 1')

element-plus 的语言包,我们只载入了 中文英文,若需支持 element-plus 的其他语言包,请自行在 /@/lang/index 文件中添加。

重要提示

WEB端语言翻译的 key 请勿带有英文句号(.

Server端

Server端使用了 Thinkphp8 自带的多语言功能,并做了适当封装。

语言包定义

一个应用下的语言包目录结构类似于:

bash
app/admin/lang
├─lang
  en.php 应用公共英文语言包
  zh-cn.php 应用公共中文语言包

  ├─en
  index.php Index控制器英文语言包

  └─user
          moneylog.php user/MoneyLog控制器英文语言包

  └─zh-cn
  index.php Index控制器中文语言包

      └─user
              moneylog.php user/MoneyLog控制器中文语言包

我们已经在 app\common\controller\Api Api基类中,实现了对应控制器的语言包自动加载,所以可以直接使用语言翻译,而无需额外的语言包加载。

以下代码仅为 定义 和后续的 使用 演示用示例,以方便读者理解,并非项目实际的语言包文件。

php
// 应用公共英文语言包文件
// app/admin/lang/en.php
return [
    'Hello %s' => 'Hello,%s',
    "Hello %s, I'm %s" => "Hello %s, I'm %s",
];

// 应用公共中文语言包文件
// app/admin/lang/zh-cn.php
return [
    'Hello %s' => '你好,%s',
    "Hello %s, I'm %s" => "你好%s,我是%s",
];

语言包使用

我们定义了全局公共函数 __,来进行语言翻译:

函数定义:

php
/**
 * 语言翻译
 * @param string $name 被翻译字符
 * @param array  $vars 替换字符数组
 * @param string $lang 指定翻译语言
 * @return string
 */
__(string $name, array $vars = [], string $lang = '');

函数使用:

php
__('Hello %s', ['BuildAdmin']);
__('Hello %s', ['BuildAdmin'], 'en');
__("Hello %s, I'm %s", ['BuildAdmin', '妙码生花'], 'zh-cn');

加载说明

如果控制器继承了 app\common\controller\Api,则可以实现语言包按控制器自动加载

假设当前为中文语言环境

bash
# 访问
https://buildadmin.com/index.php/admin/auth.admin/index
bash
# 自动加载语言包
app/admin/lang/zh-cn.php
app/admin/lang/zh-cn/auth/admin.php

有时我们需要在当前控制器导入其他语言包文件,可以参考以下代码进行加载:

php
$langset = $this->app->lang->getLangSet();
$this->app->lang->load([
    app_path() . 'lang' . DIRECTORY_SEPARATOR . $langset . DIRECTORY_SEPARATOR . (str_replace('/', DIRECTORY_SEPARATOR, $this->app->request->controllerPath)) . '.php'
]);