业务组件 i18n 接入指南¶
📄 创建: 未记录
快速入门¶
核心概念¶
业务组件接入 i18n 的三个核心步骤:
- 定义模块 →
defineBusinessI18n() - 挂载组件 →
attachI18n() - 使用翻译 →
useComponentI18n()
完整接入示例¶
1. 目录结构¶
ui-i18n-demo/
├── index.js # 组件入口
├── src/
│ ├── component.vue # 主组件
│ ├── i18n/
│ │ ├── index.js # i18n 模块定义
│ │ ├── zh-CN.js # 中文语言包
│ │ └── en-US.js # 英文语言包
│ └── business/
│ └── MainContent.vue
2. 创建语言包¶
// src/i18n/zh-CN.js
export default {
common: {
title: "i18n国际化功能演示",
switchLang: "切换语言",
confirm: "确定",
cancel: "取消",
},
modules: {
basic: {
title: "基础翻译功能",
simple: "这是一个简单的翻译文本",
interpolation: "你好,{name}!",
},
},
};
// src/i18n/en-US.js
export default {
common: {
title: "i18n Internationalization Demo",
switchLang: "Switch Language",
confirm: "Confirm",
cancel: "Cancel",
},
modules: {
basic: {
title: "Basic Translation",
simple: "This is a simple translation text",
interpolation: "Hello, {name}!",
},
},
};
3. 定义 i18n 模块 (src/i18n/index.js)¶
import { defineBusinessI18n } from '@bams-app/i18n';
import zhCN from './zh-CN.js';
import enUS from './en-US.js';
export default defineBusinessI18n({
name: 'ui-i18n-demo', // 包名,会自动转成 namespace: "uiI18nDemo"
messages: {
'zh-CN': zhCN,
'en-US': enUS,
}
});
4. 组件入口文件 (index.js)¶
import Component from './src/component.vue';
import { attachI18n } from '@bams-app/i18n';
import i18nModule from './src/i18n/index.js';
export default attachI18n(Component, i18nModule);
5. 主组件 (src/component.vue)¶
<template>
<ComponentContainer>
<MainContent />
</ComponentContainer>
</template>
<script setup>
import { ComponentContainer } from "@bams-app/components";
import MainContent from "./business/MainContent.vue";
/** 注意:根组件不写业务逻辑代码,用于通用配置和work配置 */
defineOptions({
name: "uiI18nDemo",
dicts: [],
config: {},
});
</script>
6. 业务组件 (src/business/MainContent.vue)¶
<script setup>
import { useComponentI18n } from "@bams-app/i18n";
import { useLocale } from "@bams-app/i18n";
// 使用业务组件的命名空间
const { t } = useComponentI18n();
// 也可以使用通用的 useLocale
const { setLocale } = useLocale();
</script>
<template>
<div>
<h2>{{ t('common.title') }}</h2>
<p>{{ t('modules.basic.simple') }}</p>
<p>{{ t('modules.basic.interpolation', { name: '张三' }) }}</p>
</div>
</template>
进阶用法¶
异步加载语言包¶
// src/i18n/index.js
import { defineBusinessI18n } from '@bams-app/i18n';
export default defineBusinessI18n({
name: 'ui-i18n-demo',
// 使用 loaders 异步加载(减少首屏体积)
loaders: {
'zh-CN': () => import('./zh-CN.js'),
'en-US': () => import('./en-US.js'),
}
});
同步与异步结合使用¶
import { defineBusinessI18n } from '@bams-app/i18n';
import commonZhCN from './common-zh-CN.js';
import commonEnUS from './common-en-US.js';
export default defineBusinessI18n({
name: 'ui-i18n-demo',
// 常用翻译同步加载
messages: {
'zh-CN': commonZhCN,
'en-US': commonEnUS,
},
// 不常用的翻译异步加载
loaders: {
'zh-CN': () => import('./zh-CN.js'),
'en-US': () => import('./en-US.js'),
}
});
自定义 namespace¶
import { defineBusinessI18n } from '@bams-app/i18n';
import zhCN from './zh-CN.js';
import enUS from './en-US.js';
export default defineBusinessI18n({
name: 'ui-i18n-demo',
namespace: 'customNamespace', // 显式指定 namespace
messages: {
'zh-CN': zhCN,
'en-US': enUS,
}
});
局部翻译 - 完整能力详解¶
局部翻译适用于以下场景: - 弹窗、对话框的临时文案 - 某个功能模块的独立字典 - 不想污染全局命名空间的文案 - 需要局部优先,全局回退的场景
方式一:useLocalI18n - 函数式使用(单组件内)¶
<script setup>
import { useLocalI18n, useComponentI18n } from "@bams-app/i18n";
const { t } = useComponentI18n();
// 定义局部消息字典
const localMessages = {
"zh-CN": {
localTitle: "这是局部翻译的标题",
localContent: "这是局部翻译的内容",
onlyLocal: "这个翻译只存在于局部字典中",
welcome: "欢迎,{name}!",
},
"en-US": {
localTitle: "This is local translation title",
localContent: "This is local translation content",
onlyLocal: "This translation only exists in local dictionary",
welcome: "Welcome, {name}!",
},
};
// 基本用法 - 继承父组件的 namespace
const localT = useLocalI18n({
messages: localMessages,
// 可选:指定局部 namespace
// namespace: 'myLocalModule',
// 可选:关闭回退到全局(默认 true)
// fallbackToGlobal: false,
});
</script>
<template>
<div>
<!-- 方式1:直接调用 translator -->
<p>{{ localT('localTitle') }}</p>
<p>{{ localT('localContent') }}</p>
<p>{{ localT('welcome', { name: '张三' }) }}</p>
<!-- 方式2:通过 .t 调用 -->
<p>{{ localT.t('localTitle') }}</p>
<!-- 检查翻译是否存在 -->
<p v-if="localT.te('onlyLocal')">{{ localT('onlyLocal') }}</p>
<!-- 回退到全局:局部找不到时自动使用全局 -->
<p>{{ localT('common.title') }}</p>
</div>
</template>
方式二:LocalI18nProvider + useLocalI18nProvided - 跨组件共享¶
<!-- 父组件:提供局部翻译 -->
<template>
<LocalI18nProvider
:messages="localMessages"
namespace="myDialog"
:fallback-to-global="true"
>
<template #default="{ t: providerT }">
<!-- 通过 slot 直接使用 -->
<div>
<h3>{{ providerT('dialogTitle') }}</h3>
</div>
<!-- 子组件通过 useLocalI18nProvided 消费 -->
<DialogContent />
</template>
</LocalI18nProvider>
</template>
<script setup>
import { LocalI18nProvider } from "@bams-app/i18n";
import DialogContent from './DialogContent.vue';
const localMessages = {
"zh-CN": {
dialogTitle: "确认对话框",
dialogContent: "您确定要执行此操作吗?",
confirmBtn: "确定",
},
"en-US": {
dialogTitle: "Confirm Dialog",
dialogContent: "Are you sure you want to do this?",
confirmBtn: "Confirm",
},
};
</script>
<!-- 子组件:消费父组件提供的局部翻译 -->
<script setup>
import { useLocalI18nProvided } from "@bams-app/i18n";
// 获取父组件 provide 的局部翻译
// 如果找不到,会自动回退到全局翻译并警告
const localT = useLocalI18nProvided();
</script>
<template>
<div class="dialog-content">
<p>{{ localT('dialogContent') }}</p>
<a-button type="primary">{{ localT('confirmBtn') }}</a-button>
</div>
</template>
方式三:createLocalTranslator - 纯 JS 环境使用¶
// utils/helper.js
import { createLocalTranslator } from "@bams-app/i18n";
// 定义局部消息
const localMessages = {
"zh-CN": {
errorTitle: "操作失败",
successTitle: "操作成功",
},
"en-US": {
errorTitle: "Operation Failed",
successTitle: "Operation Succeeded",
},
};
// 创建局部翻译器
const localT = createLocalTranslator({
messages: localMessages,
namespace: 'myUtils',
fallbackToGlobal: true,
});
// 使用方式
export function showSuccess() {
console.log(localT('successTitle'));
console.log(localT.t('successTitle'));
console.log(localT.te('successTitle'));
}
局部翻译的回退机制详解¶
局部翻译的查找顺序(优先级从高到低):
- 局部字典查找 → 当前语言的对应 key
- 全局回退 → 如果找不到且
fallbackToGlobal=true,查找全局翻译 - 兜底语言查找 → 当前语言找不到,尝试
fallbackLocale的局部字典
<script setup>
import { useLocalI18n } from "@bams-app/i18n";
const localMessages = {
"zh-CN": {
localKey: "中文局部翻译",
},
"en-US": {
localKey: "English local translation",
},
};
const localT = useLocalI18n({
messages: localMessages,
fallbackToGlobal: true, // 默认 true
});
</script>
<template>
<div>
<!-- 1. 优先使用局部翻译 -->
<p>{{ localT('localKey') }}</p>
<!-- 2. 局部找不到,回退到全局(假设全局有 'common.title') -->
<p>{{ localT('common.title') }}</p>
<!-- 3. 都找不到,返回 key 本身 -->
<p>{{ localT('nonExistentKey') }}</p>
</div>
</template>
useLocalI18n 的完整返回值¶
const translator = useLocalI18n({
messages: localMessages,
namespace: 'myModule',
fallbackToGlobal: true,
});
// 可以直接调用 translator()
translator('key');
// 也可以通过属性访问:
translator.t; // 翻译函数
translator.te; // 检查翻译是否存在
translator.locale; // 当前语言(响应式)
translator.setLocale; // 设置语言
translator.antdLocale;// Ant Design 的 locale 对象
translator.loading; // 加载状态
translator.state; // 完整的 i18n 状态
translator.namespace; // 当前 namespace
响应式的 messages 和 options¶
useLocalI18n 支持响应式的配置:
<script setup>
import { ref, computed } from 'vue';
import { useLocalI18n } from "@bams-app/i18n";
const isDarkMode = ref(false);
// 响应式的 messages
const dynamicMessages = computed(() => ({
"zh-CN": {
theme: isDarkMode.value ? "深色模式" : "浅色模式",
},
"en-US": {
theme: isDarkMode.value ? "Dark Mode" : "Light Mode",
},
}));
const localT = useLocalI18n({
messages: dynamicMessages, // 传入 ref 或 computed
});
</script>
<template>
<div>
<a-switch v-model:checked="isDarkMode" />
<p>{{ localT('theme') }}</p>
</div>
</template>
使用 provideComponentI18n¶
<script setup>
import { provideComponentI18n } from "@bams-app/i18n";
// 显式提供 namespace
provideComponentI18n("myCustomNamespace");
</script>
常见问题¶
| 问题 | 解决方案 |
|---|---|
useComponentI18n() 提示未找到 namespace |
确保在 index.js 中正确调用 attachI18n() |
| 翻译显示路径不对 | 检查 defineBusinessI18n() 的 name 是否正确 |
| 子组件无法获取不到 namespace | 确保子组件在被 attachI18n() 的组件内部使用 |
| 切换语言组件不更新 | 确保使用了 useComponentI18n() 返回的 t 函数 |
useLocalI18nProvided() 警告找不到 provider |
确保父组件确实用 LocalI18nProvider 包裹 |
| 局部翻译不生效 | 检查 messages 的语言 key 是否和当前语言匹配 |
最佳实践¶
- 语言文件独立存放于
src/i18n/目录 - 在
src/i18n/index.js中统一导出 i18n 模块 - 使用 kebab-case 命名包名
- 按功能模块组织翻译 key
- 常用翻译用
messages同步加载,不常用翻译用loaders异步加载 - 组件库或大型组件使用业务组件接入方式
- 临时弹窗/对话框文案优先考虑局部翻译
- 共享的局部翻译用
LocalI18nProvider提供给子孙组件 - 纯 JS 工具函数用
createLocalTranslator