整体架构图
┌─────────────────┐ ┌─────────────────┐
│ │ │ │
│ 前端层 │ │ 后端层 │
│ │ │ │
└────────┬────────┘ └────────┬────────┘
│ │
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Vue I18n 管理 │ │ 国际化资源文件 │
│ │◄────── API 请求 ─────►│ 多语言数据库 │
│ 本地化资源文件 │ (带语言标识) │ 翻译服务 │
└─────────────────┘ └─────────────────┘
│ │
│ │
▼ ▼
┌─────────────────────────────────────────────────────────┐
│ │
│ 多语言内容展示 │
│ │
└─────────────────────────────────────────────────────────┘
前端多语言详细架构图
┌─────────────────────────────────────────────────────────────────────────────┐
│ Vue 应用 │
└───────────────────────────────────┬─────────────────────────────────────────┘
│
│ 注册
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ Vue I18n │
│ │
│ ┌───────────────────┐ ┌───────────────────┐ ┌────────────────────┐ │
│ │ Composition │ │ Options │ │ 插件注册机制 │ │
│ │ API │ │ API │ │ app.use(i18n) │ │
│ │ useI18n() 钩子 │ │ $t(), $tc() │ │ │ │
│ └───────────────────┘ └───────────────────┘ └────────────────────┘ │
│ │
└───────────────┬─────────────────────┬──────────────────────┬───────────────┘
│ │ │
▼ ▼ ▼
┌───────────────────────┐ ┌─────────────────────┐ ┌─────────────────────────┐
│ 语言资源管理 │ │ 本地存储机制 │ │ 动态语言切换 │
│ │ │ │ │ │
│ ┌─────────────────┐ │ │ ┌───────────────┐ │ │ ┌───────────────────┐ │
│ │ 语言包文件 │ │ │ │ localStorage │ │ │ │ setLocale() │ │
│ │ zh-CN.js │ │ │ │ 存储当前语言 │ │ │ │ 切换语言函数 │ │
│ │ en-US.js │ │ │ │ 设置 │ │ │ │ │ │
│ └─────────────────┘ │ │ └───────────────┘ │ │ └───────────────────┘ │
│ │ │ │ │ │
│ ┌─────────────────┐ │ │ ┌───────────────┐ │ │ ┌───────────────────┐ │
│ │ 日期时间格式 │ │ │ │ 浏览器语言 │ │ │ │ HTML lang 属性 │ │
│ │ 数字格式 │ │ │ │ 检测机制 │ │ │ │ 自动更新 │ │
│ │ 货币格式 │ │ │ │ │ │ │ │ │ │
│ └─────────────────┘ │ │ └───────────────┘ │ │ └───────────────────┘ │
└───────────────────────┘ └─────────────────────┘ └─────────────────────────┘
│ │ │
└──────────────────────────┼─────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────────────────┐
│ 组件层多语言应用 │
│ │
│ ┌────────────────────┐ ┌────────────────────┐ ┌─────────────────────┐ │
│ │ 文本国际化 │ │ 图片国际化 │ │ 格式化国际化 │ │
│ │ │ │ │ │ │ │
│ │ ┌──────────────┐ │ │ ┌──────────────┐ │ │ ┌───────────────┐ │ │
│ │ │ {
{ $t(...) }}│ │ │ │ :src=$t(...) │ │ │ │ {
{ d(...) }} │ │ │
│ │ │ 模板中使用 │ │ │ │ 动态绑定图片 │ │ │ │ 日期格式化 │ │ │
│ │ └──────────────┘ │ │ └──────────────┘ │ │ └───────────────┘ │ │
│ │ │ │ │ │ │ │
│ │ ┌──────────────┐ │ │ ┌──────────────┐ │ │ ┌───────────────┐ │ │
│ │ │ t('...') │ │ │ │ 图片目录结构 │ │ │ │ {
{ n(...) }} │ │ │
│ │ │ JS中使用 │ │ │ │ 按语言区分 │ │ │ │ 数字格式化 │ │ │
│ │ └──────────────┘ │ │ └──────────────┘ │ │ └───────────────┘ │ │
│ └────────────────────┘ └────────────────────┘ └─────────────────────┘ │
└────────────────────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────────────────┐
│ 接口请求与后端交互 │
│ │
│ ┌────────────────────────┐ ┌────────────────────────────────────────┐ │
│ │ 请求拦截器 │ │ 响应处理 │ │
│ │ │ │ │ │
│ │ 添加语言标识头 │ │ 处理多语言数据 │ │
│ │ Accept-Language │ │ 动态更新UI │ │
│ └────────────────────────┘ └────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────────┘
后端多语言详细架构图
┌───────────────────────────────────────────────────────────────────────────────┐
│ 后端服务层 │
└───────────────────────────────────┬───────────────────────────────────────────┘
│
│ 请求处理
▼
┌───────────────────────────────────────────────────────────────────────────────┐
│ 语言识别与处理中间件 │
│ │
│ ┌────────────────────────┐ ┌────────────────────────┐ ┌─────────────────┐ │
│ │ Accept-Language 解析 │ │ 语言区域设置 │ │ 语言回退策略 │ │
│ │ │ │ │ │ │ │
│ │ 提取客户端语言标识 │ │ 设置当前请求的语言环境 │ │ 不支持语言的 │ │
│ │ zh-CN, en-US 等 │ │ req.locale = 'zh-CN' │ │ 默认处理机制 │ │
│ └────────────────────────┘ └────────────────────────┘ └─────────────────┘ │
└───────────────────────────────────┬───────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────────────────────┐
│ 多语言数据存储层 │
│ │
│ ┌────────────────────────────────────┐ ┌───────────────────────────────────┐│
│ │ 数据库设计 │ │ 缓存策略 ││
│ │ │ │ ││
│ │ ┌──────────────────────────────┐ │ │ ┌────────────────────────────┐ ││
│ │ │ 单表JSON字段方案 │ │ │ │ Redis缓存 │ ││
│ │ │ { │ │ │ │ │ ││
│ │ │ "zh-CN": "产品名称", │ │ │ │ 多语言内容缓存 │ ││
│ │ │ "en-US": "Product Name" │ │ │ │ 减少数据库查询 │ ││
│ │ │ } │ │ │ │ │ ││
│ │ └──────────────────────────────┘ │ │ └────────────────────────────┘ ││
│ │ │ │ ││
│ │ ┌──────────────────────────────┐ │ │ ┌────────────────────────────┐ ││
│ │ │ 关联表方案 │ │ │ │ 缓存更新机制 │ ││
│ │ │ │ │ │ │ 语言数据变更时 │ ││
│ │ │ 主表 + 翻译表 │ │ │ │ 自动刷新缓存 │ ││
│ │ │ 一对多关系 │ │ │ │ │ ││
│ │ └──────────────────────────────┘ │ │ └────────────────────────────┘ ││
│ └────────────────────────────────────┘ └───────────────────────────────────┘│
└───────────────────────────────────┬───────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────────────────────────────────────┐
│ 数据处理与响应层 │
│ │
│ ┌────────────────────────────────┐ ┌─────────────────────────────────────┐│
│ │ 查询适配器 │ │ 响应格式化 ││
│ │ │ │ ││
│ │ 根据当前语言环境 │ │ 统一响应格式 ││
│ │ 动态构建查询条件 │ │ 处理多语言字段 ││
│ │ SELECT ... WHERE locale = ? │ │ 处理特殊字符编码 ││
│ └────────────────────────────────┘ └─────────────────────────────────────┘│
│ │
│ ┌────────────────────────────────┐ ┌─────────────────────────────────────┐│
│ │ 翻译服务集成 │ │ 多语言日志 ││
│ │ │ │ ││
│ │ 对缺失翻译的内容 │ │ 记录语言相关问题 ││
│ │ 调用第三方翻译API进行翻译 │ │ 便于后期分析和优化 ││
│ │ 如Google Translate API │ │ 监控翻译覆盖率 ││
│ └────────────────────────────────┘ └─────────────────────────────────────┘│
└───────────────────────────────────────────────────────────────────────────────┘
完整多语言交互流程图
┌──────────────┐ ┌───────────────┐ ┌──────────────┐ ┌──────────────┐
│ │ │ │ │ │ │ │
│ 用户 │ │ 前端应用 │ │ 后端服务 │ │ 数据库 │
│ │ │ │ │ │ │ │
└──────┬───────┘ └───────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │ │
│ 1.访问应用 │ │ │
│ ─────────────────────────> │ │
│ │ │ │
│ │ 2.检测用户语言设置 │ │
│ │ ──────────────────┐ │ │
│ │ │ │ │
│ │ <────────────────┘ │ │
│ │ │ │
│ │ 3.加载对应语言包 │ │
│ │ ──────────────────┐ │ │
│ │ │ │ │
│ │ <────────────────┘ │ │
│ │ │ │
│ │ 4.渲染初始界面 │ │
│ │ ──────────────────┐ │ │
│ │ │ │ │
│ │ <────────────────┘ │ │
│ │ │ │
│ 5.查看界面 │ │ │
│ <───────────────────────── │ │
│ │ │ │
│ 6.切换语言 │ │ │
│ ─────────────────────────> │ │
│ │ │ │
│ │ 7.切换本地语言设置 │ │
│ │ ──────────────────┐ │ │
│ │ │ │ │
│ │ <────────────────┘ │ │
│ │ │ │
│ │ 8.更新UI界面 │ │
│ │ ──────────────────┐ │ │
│ │ │ │ │
│ │ <────────────────┘ │ │
│ │ │ │
│ 9.查看新语言界面 │ │ │
│ <───────────────────────── │ │
│ │ │ │
│ 10.请求数据 │ │ │
│ ─────────────────────────> │ │
│ │ │ │
│ │ 11.请求数据(带语言标识) │ │
│ │ ─────────────────────────> │
│ │ │ │
│ │ │ 12.查询多语言数据 │
│ │ │ ─────────────────────────>
│ │ │ │
│ │ │ 13.返回指定语言数据 │
│ │ │ <─────────────────────────
│ │ │ │
│ │ │ 14.处理数据与翻译 │
│ │ │ ──────────────────┐ │
│ │ │ │ │
│ │ │ <────────────────┘ │
│ │ │ │
│ │ 15.返回多语言数据 │ │
│ │ <───────────────────────── │
│ │ │ │
│ │ 16.使用i18n渲染数据 │ │
│ │ ──────────────────┐ │ │
│ │ │ │ │
│ │ <────────────────┘ │ │
│ │ │ │
│ 17.查看本地化内容 │ │ │
│ <───────────────────────── │ │
│ │ │ │
▼ ▼ ▼ ▼
多语言系统维护与管理流程
┌──────────────────────────────────────────────────────────────────────┐
│ 多语言内容管理系统 │
└───────────────┬───────────────────────────────────────┬───────────────┘
│ │
▼ ▼
┌───────────────────────────────┐ ┌───────────────────────────────┐
│ 翻译工作流管理 │ │ 缺失翻译处理 │
│ │ │ │
│ ┌─────────────────────────┐ │ │ ┌─────────────────────────┐ │
│ │ 新增文本识别 │ │ │ │ 降级策略 │ │
│ │ │ │ │ │ │ │
│ │ 扫描代码中的新文本 │ │ │ │ 使用默认语言作为备选 │ │
│ │ 提取需要翻译的内容 │ │ │ │ 防止UI显示问题 │ │
│ └─────────────────────────┘ │ │ └─────────────────────────┘ │
│ │ │ │
│ ┌─────────────────────────┐ │ │ ┌─────────────────────────┐ │
│ │ 翻译任务分配 │ │ │ │ 自动翻译机制 │ │
│ │ │ │ │ │ │ │
│ │ 分配给专业翻译人员 │ │ │ │ 接入机器翻译API │ │
│ │ 或使用翻译服务 │ │ │ │ 临时解决缺失翻译 │ │
│ └─────────────────────────┘ │ │ └─────────────────────────┘ │
│ │ │ │
│ ┌─────────────────────────┐ │ │ ┌─────────────────────────┐ │
│ │ 翻译审核流程 │ │ │ │ 翻译覆盖率报告 │ │
│ │ │ │ │ │ │ │
│ │ 确保翻译质量 │ │ │ │ 监控各语言翻译完成度 │ │
│ │ 上下文一致性检查 │ │ │ │ 优先补充高频使用内容 │ │
│ └─────────────────────────┘ │ │ └─────────────────────────┘ │
└───────────────────────────────┘ └───────────────────────────────┘
│ │
▼ ▼
┌───────────────────────────────────────────────────────────────────────┐
│ 语言包发布与更新 │
│ │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ 版本控制 │ │ 增量更新机制 │ │
│ │ │ │ │ │
│ │ 语言包版本管理 │ │ 只更新变更的语言条目 │ │
│ │ 历史翻译记录 │ │ 减少更新成本 │ │
│ └─────────────────────────┘ └─────────────────────────┘ │
│ │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ 按需加载策略 │ │ 语言包CDN分发 │ │
│ │ │ │ │ │
│ │ 只加载当前使用语言 │ │ 全球就近访问 │ │
│ │ 减少资源占用 │ │ 提高加载速度 │ │
│ └─────────────────────────┘ └─────────────────────────┘ │
└───────────────────────────────────────────────────────────────────────┘
前端实现方案
1. 安装依赖
npm install vue-i18n@next
2. 目录结构
src/
├── i18n/
│ ├── index.js # i18n配置文件
│ ├── messages/ # 语言包目录
│ │ ├── zh-CN.js # 中文语言包
│ │ ├── en-US.js # 英文语言包
│ │ └── ... # 其他语言包
│ └── dateTimeFormats/ # 日期时间格式配置
├── assets/
│ └── images/
│ ├── common/ # 通用图片
│ └── i18n/ # 国际化图片
│ ├── zh-CN/ # 中文图片
│ ├── en-US/ # 英文图片
│ └── ... # 其他语言图片
└── utils/
└── request.js # 请求工具(添加语言标识)
3. 初始化 Vue I18n
// src/i18n/index.js
import {
createI18n } from "vue-i18n";
import zhCN from "./messages/zh-CN";
import enUS from "./messages/en-US";
// 获取浏览器语言或本地存储中的语言设置
const getLocale = () => {
const cachedLocale = localStorage.getItem("language");
if (cachedLocale) return cachedLocale;
const browserLocale = navigator.language;
return browserLocale.includes("zh") ? "zh-CN" : "en-US";
};
const i18n = createI18n({
legacy: false, // 使用composition API
locale: getLocale(),
fallbackLocale: "zh-CN",
messages: {
"zh-CN": zhCN,
"en-US": enUS,
},
// 日期时间格式化
datetimeFormats: {
"zh-CN": {
short: {
year: "numeric",
month: "2-digit",
day: "2-digit",
},
long: {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
},
},
"en-US": {
short: {
year: "numeric",
month: "2-digit",
day: "2-digit",
},
long: {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: true,
},
},
},
});
// 语言切换函数
export const setLocale = (locale) => {
i18n.global.locale.value = locale;
localStorage.setItem("language", locale);
document.querySelector("html").setAttribute("lang", locale);
};
export default i18n;
4. 在 Vue 应用中注册
// src/main.js
import {
createApp } from "vue";
import App from "./App.vue";
import i18n from "./i18n";
const app = createApp(App);
app.use(i18n);
app.mount("#app");
5. 文本国际化
语言包示例
// src/i18n/messages/zh-CN.js
export default {
common: {
hello: '你好,世界',
welcome: '欢迎来到{name}',
submit: '提交',
cancel: '取消'
},
login: {
title: '用户登录',
username: '用户名',
password: '密码',
remember: '记住我',
loginBtn: '登录'
},
// 针对图片的国际化配置
images: {
logo: '/assets/images/i18n/zh-CN/logo.png',
banner: '/assets/images/i18n/zh-CN/banner.jpg'
}
};
// src/i18n/messages/en-US.js
export default {
common: {
hello: 'Hello World',
welcome: 'Welcome to {name}',
submit: 'Submit',
cancel: 'Cancel'
},
login: {
title: 'User Login',
username: 'Username',
password: 'Password',
remember: 'Remember me',
loginBtn: 'Login'
},
// 针对图片的国际化配置
images: {
logo: '/assets/images/i18n/en-US/logo.png',
banner: '/assets/images/i18n/en-US/banner.jpg'
}
};
在组件中使用
<template>
<div>
<!-- 基本使用 -->
<h1>{
{ $t("common.hello") }}</h1>
<!-- 带参数的翻译 -->
<p>{
{ $t("common.welcome", { name: appName }) }}</p>
<!-- 使用组合式API -->
<p>{
{ t("login.title") }}</p>
<!-- 复数形式 -->
<p>{
{ $tc("message.itemCount", itemCount) }}</p>
<!-- 国际化的按钮 -->
<button
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
{
{ $t("common.submit") }}
</button>
</div>
</template>
<script setup>
import { ref } from "vue";
import { useI18n } from "vue-i18n";
const { t, tc, d } = useI18n();
const appName = ref("MyApp");
const itemCount = ref(5);
</script>
6. 图片国际化
通过 i18n 配置图片路径
<template>
<div>
<!-- 使用国际化图片 -->
<img :src="$t('images.logo')" alt="Logo" class="h-10 w-auto" />
<img :src="$t('images.banner')" alt="Banner" class="w-full h-auto" />
</div>
</template>
7. 接口请求头国际化
// src/utils/request.js
import axios from "axios";
import {
useI18n } from "vue-i18n";
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 5000,
});
// 请求拦截器
service.interceptors.request.use(
(config) => {
// 从 i18n 获取当前语言
const currentLocale = localStorage.getItem("language") || "zh-CN";
// 添加语言标识到请求头
config.headers["Accept-Language"] = currentLocale;
return config;
},
(error) => {
return Promise.reject(error);
}
);
export default service;
8. 语言切换组件
<template>
<div class="relative">
<button
@click="toggleDropdown"
class="flex items-center space-x-1 px-3 py-2 rounded hover:bg-gray-100"
>
<span>{
{ currentLangLabel }}</span>
<span class="transform" :class="isOpen ? 'rotate-180' : ''">▼</span>
</button>
<div
v-if="isOpen"
class="absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg z-10"
>
<div class="py-1">
<a
v-for="lang in languages"
:key="lang.value"
@click="changeLang(lang.value)"
class="block px-4 py-2 text-gray-800 hover:bg-gray-100 cursor-pointer"
>
{
{ lang.label }}
</a>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from "vue";
import { useI18n } from "vue-i18n";
import { setLocale } from "@/i18n";
const { locale } = useI18n();
const isOpen = ref(false);
const languages = [
{ label: "简体中文", value: "zh-CN" },
{ label: "English", value: "en-US" },
];
const currentLangLabel = computed(() => {
const lang = languages.find((l) => l.value === locale.value);
return lang ? lang.label : languages[0].label;
});
const toggleDropdown = () => {
isOpen.value = !isOpen.value;
};
const changeLang = (langValue) => {
setLocale(langValue);
isOpen.value = false;
};
</script>
后端实现方案
1. 数据库设计
使用 JSON 字段或者关联表存储多语言文本:
// 单表方案(使用JSON字段)
products (
id INT PRIMARY KEY,
name_translations JSON, // {"zh-CN": "产品名称", "en-US": "Product Name"}
description_translations JSON
)
// 关联表方案
products (
id INT PRIMARY KEY,
default_name VARCHAR(255),
default_description TEXT
)
product_translations (
id INT PRIMARY KEY,
product_id INT FOREIGN KEY,
locale VARCHAR(10),
name VARCHAR(255),
description TEXT
)
2. API 接口设计
// 接口输入
GET /api/products
Headers:
Accept-Language: zh-CN
// 接口输出
{
"code": 0,
"data": [
{
"id": 1,
"name": "产品名称", // 已根据请求头的语言返回对应文本
"description": "产品描述"
}
]
}
3. 后端处理流程
- 解析请求头中的语言标识
- 根据语言标识查询对应的语言数据
- 返回对应语言的数据给前端
// 伪代码示例
app.use((req, res, next) => {
// 从请求头获取语言标识
const locale = req.headers["accept-language"] || "zh-CN";
// 保存到请求上下文中
req.locale = locale;
next();
});
项目配置最佳实践
-
代码规范:
- 禁止硬编码文本,所有文本必须使用 i18n
- 代码审查时检查国际化问题
-
自动化工具:
- 使用工具提取代码中的文本到语言文件
- 使用翻译服务 API 自动翻译新增文本
-
性能优化:
- 按需加载语言包
- 缓存已加载的语言包
-
测试策略:
- 为每种语言编写 UI 测试
- 确保布局在不同语言下正常显示
总结
这套多语言技术方案通过前后端协同工作,为应用提供完整的国际化支持。前端使用 Vue I18n 管理文本、图片和日期时间格式,后端通过请求头识别语言并返回相应数据。这样的架构使应用能够无缝地支持多种语言,提升全球用户体验。