Vue 3 + TypeScript 中 Vue-i18n Hooks 的最佳实践
message: {navbar: {action: {类型安全使用 TypeScript 定义翻译键类型为 i18n 实例添加泛型约束2.性能优化支持语言包的按需加载使用 computed 属性优化响应式数据3.用户体验提供加载状态反馈支持多种切换语言的方式持久化语言选择4.可维护性模块化的语言包管理统一的类型定义清晰的目录结构5.扩展性支持动态添加新的语言包灵活的 Hook 封装可复用的组件设
·
在现代前端开发中,国际化(i18n)是提升用户体验的重要功能。本文将详细介绍如何在 Vue 3 + TypeScript 项目中优雅地封装和使用 Vue-i18n。
1. 安装依赖
首先安装必要的依赖包:
# 安装 vue-i18n 及其类型支持
npm install vue-i18n@next @intlify/vue-i18n-loader -D
2. 类型定义
创建翻译键的类型定义文件:
// types/i18n.d.ts
import { DefineLocaleMessage } from "vue-i18n";
declare module "vue-i18n" {
export interface DefineLocaleMessage {
message: {
hello: string;
welcome: string;
};
navbar: {
action: {
locale: string;
};
};
language: {
"zh-CN": string;
"en-US": string;
};
}
}
3. 语言包配置
创建语言文件:
// src/locales/zh-CN.ts
export default {
message: {
hello: "你好",
welcome: "欢迎",
},
navbar: {
action: {
locale: "切换语言",
},
},
language: {
"zh-CN": "简体中文",
"en-US": "English",
},
};
// src/locales/en-US.ts
export default {
message: {
hello: "Hello",
welcome: "Welcome",
},
navbar: {
action: {
locale: "Switch Language",
},
},
language: {
"zh-CN": "Chinese",
"en-US": "English",
},
};
4. i18n 实例配置
// src/i18n/index.ts
import { createI18n, type I18nOptions } from "vue-i18n";
import zh from "../locales/zh-CN";
import en from "../locales/en-US";
type MessageSchema = {
message: {
hello: string;
welcome: string;
};
navbar: {
action: {
locale: string;
};
};
language: {
"zh-CN": string;
"en-US": string;
};
};
const options: I18nOptions = {
legacy: false, // 启用组合式API
locale: localStorage.getItem("locale") || "zh-CN",
fallbackLocale: "en-US",
messages: {
"zh-CN": zh,
"en-US": en,
},
};
const i18n = createI18n<[MessageSchema], "zh-CN" | "en-US">(options);
export default i18n;
5. Hook 封装
// src/hooks/useLocale.ts
import { useI18n } from "vue-i18n";
import { computed, ref } from "vue";
import type { Ref } from "vue";
export function useLocale() {
const { locale, t, availableLocales: locales } = useI18n();
const loading = ref(false);
const currentLocale = computed(() => locale.value);
// 支持的语言列表
const availableLocales = computed(() => locales);
// 切换语言
const changeLocale = async (value: string) => {
loading.value = true;
try {
// 动态导入语言包
const messages = await import(`../locales/${value}.ts`);
i18n.global.setLocaleMessage(value, messages.default);
locale.value = value;
localStorage.setItem("locale", value);
// 可选: 修改 HTML lang 属性
document.querySelector("html")?.setAttribute("lang", value);
} catch (error) {
console.error("Failed to load locale:", error);
} finally {
loading.value = false;
}
};
return {
t,
loading,
currentLocale,
availableLocales,
changeLocale,
};
}
6. 在 Vue 应用中使用
// src/main.ts
import { createApp } from "vue";
import App from "./App.vue";
import i18n from "./i18n";
const app = createApp(App);
app.use(i18n);
app.mount("#app");
7. 组件中的使用示例
<!-- src/components/LanguageSwitcher.vue -->
<script setup lang="ts">
import { useLocale } from "@/hooks/useLocale";
const { t, loading, currentLocale, availableLocales, changeLocale } =
useLocale();
const switchLang = async () => {
const nextLocale = currentLocale.value === "zh-CN" ? "en-US" : "zh-CN";
await changeLocale(nextLocale);
};
</script>
<template>
<div class="lang-switcher">
<!-- 按钮切换方式 -->
<button @click="switchLang" :disabled="loading" class="switch-btn">
{{ loading ? "切换中..." : t("navbar.action.locale") }}
</button>
<!-- 下拉框切换方式 -->
<select
v-model="currentLocale"
@change="changeLocale($event.target.value)"
:disabled="loading"
class="lang-select"
>
<option v-for="locale in availableLocales" :key="locale" :value="locale">
{{ t(`language.${locale}`) }}
</option>
</select>
</div>
</template>
<style scoped>
.lang-switcher {
display: flex;
gap: 1rem;
}
.switch-btn {
padding: 0.5rem 1rem;
border-radius: 4px;
border: 1px solid #ddd;
cursor: pointer;
}
.switch-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.lang-select {
padding: 0.5rem;
border-radius: 4px;
border: 1px solid #ddd;
}
</style>
8. Vite 配置优化
// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
export default defineConfig({
plugins: [vue()],
resolve: {
alias: [
{
find: "vue-i18n",
replacement: "vue-i18n/dist/vue-i18n.cjs.js",
},
],
},
});
9. 最佳实践总结
- 类型安全:
- 使用 TypeScript 定义翻译键类型
- 为 i18n 实例添加泛型约束
2.性能优化:
-
- 支持语言包的按需加载
- 使用 computed 属性优化响应式数据
3.用户体验:
-
- 提供加载状态反馈
- 支持多种切换语言的方式
- 持久化语言选择
4.可维护性:
-
- 模块化的语言包管理
- 统一的类型定义
- 清晰的目录结构
5.扩展性:
-
- 支持动态添加新的语言包
- 灵活的 Hook 封装
- 可复用的组件设计
通过以上配置和实践,我们可以在 Vue 3 + TypeScript 项目中实现一个类型安全、性能优良、用户体验好的国际化解决方案。这种方案既保持了代码的简洁性,又具有良好的可维护性和扩展性
更多推荐
所有评论(0)