国际化处理方案
基于 vue-i18n
安装
bash
npm install vue-i18n@next
webpack
文件目录
- 创建目录
bash
├── src
│ ├── assets
│ ├── components
│ ├── i18n
│ │ ├── langs
│ │ │ ├── en.js
│ │ │ ├── zh.js
│ │ │ ├── ja.js
│ │ │ ├── index.js
│ │ ├── i18n.js
i18n.js
js
import { createI18n } from "vue-i18n";
import messages from "./langs/index.js";
//从localStorage中拿到用户的语言选择,如果没有,那默认英文。
const i18n = createI18n({
legacy: false, //这个legacy必须加
locale: localStorage.lang || "en",
messages,
});
export default i18n;
index.js
js
import en from "./en";
import cn from "./cn";
import ja from "./ja";
export default {
en,
cn,
ja,
};
cn.js
js
const cn = {
message: {
hello: "你好",
themeChange: "主题更换",
textChange: "文字更换",
activetextChange: "选中更换",
route: {
profile: "个人中心",
login: "登录",
register: "注册",
home: "首页",
user: "用户",
userManage: "用户管理",
roleList: "角色列表",
permissionList: "权限列表",
excelImport: "Excel导入",
article: "文章管理",
articleRanking: "文章等级",
articleCreate: "文章创建",
},
},
};
export default cn;
en.js
js
const en = {
message: {
hello: "hello",
themeChange: "themeChange",
textChange: "textChange",
activetextChange: "activetextChange",
route: {
profile: "profile",
login: "login",
register: "register",
home: "home",
user: "user",
userManage: "userManage",
roleList: "roleList",
permissionList: "permissionList",
excelImport: "excelImport",
article: "article",
articleRanking: "articleRanking",
articleCreate: "articleCreate",
},
},
};
export default en;
ja.js
js
const ja = {
message: {
hello: "日本语hello",
themeChange: "themeChange",
textChange: "textChange",
activetextChange: "activetextChange",
route: {
profile: "profile",
login: "login",
register: "register",
home: "home",
user: "user",
userManage: "userManage",
roleList: "roleList",
permissionList: "permissionList",
excelImport: "excelImport",
article: "article",
articleRanking: "articleRanking",
articleCreate: "articleCreate",
},
},
};
export default ja;
注意
在配置语言包的时候,key 值一定要保持同意,因为 i18n 是通过你的 key 值来切换语言,如果 key 值有误,就不能切换
main.js
js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import i18n from "./i18n/i18n.js";
import "normalize.css";
const app = createApp(App);
app.use(router).use(i18n);
app.mount("#app");
配置页面
vue
<template>
<div>
<p>{{ $t("message.hello") }}</p>
<p>{{ title }}</p>
<button @click="switchLang('en')">英语</button>
<button @click="switchLang('cn')">中文</button>
<button @click="switchLang('ja')">日语</button>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs } from "vue";
import { useI18n } from "vue-i18n";
export default defineComponent({
setup() {
const { t } = useI18n();
const data = reactive({
message: "首页",
title: t("message.hello"),
switchLang(lang: string) {
//把语言保存在localStorage中
localStorage.setItem("lang", lang);
location.reload();
},
});
return {
...toRefs(data),
};
},
});
</script>
<style scoped></style>
vite 版本
安装
bash
npm install vue-i18n@next
目录
- 创建目录
bash
├── src
│ ├── assets
│ ├── components
│ ├── i18n
│ │ ├── langs
│ │ │ ├── en.js
│ │ │ ├── zh.js
│ │ │ ├── ja.js
│ │ ├── index.js
index.js
js
import { createI18n } from "vue-i18n";
// 导入你自己创建的语言 js 文件
import cn from "./langs/cn";
import en from "./langs/en";
import ja from "./langs/ja";
// 创建 i18n 对象
const i18n = createI18n({
legacy: false,
globalInjection: true, // 全局模式,可以直接使用 $t
locale: localStorage.getItem("lang") || "cn",
messages: {
cn,
en,
ja,
},
});
export default i18n;
cn.js
js
const cn = {
message: {
hello: "你好",
themeChange: "主题更换",
textChange: "文字更换",
activetextChange: "选中更换",
route: {
profile: "个人中心",
login: "登录",
register: "注册",
home: "首页",
user: "用户",
userManage: "用户管理",
roleList: "角色列表",
permissionList: "权限列表",
excelImport: "Excel导入",
article: "文章管理",
articleRanking: "文章等级",
articleCreate: "文章创建",
},
},
};
export default cn;
en.js
js
const en = {
message: {
hello: "hello",
themeChange: "themeChange",
textChange: "textChange",
activetextChange: "activetextChange",
route: {
profile: "profile",
login: "login",
register: "register",
home: "home",
user: "user",
userManage: "userManage",
roleList: "roleList",
permissionList: "permissionList",
excelImport: "excelImport",
article: "article",
articleRanking: "articleRanking",
articleCreate: "articleCreate",
},
},
};
export default en;
ja.js
js
const ja = {
message: {
hello: "日本语hello",
themeChange: "themeChange",
textChange: "textChange",
activetextChange: "activetextChange",
route: {
profile: "profile",
login: "login",
register: "register",
home: "home",
user: "user",
userManage: "userManage",
roleList: "roleList",
permissionList: "permissionList",
excelImport: "excelImport",
article: "article",
articleRanking: "articleRanking",
articleCreate: "articleCreate",
},
},
};
export default ja;
main.js
js
// 引入i18n.js
import i18n from "@/i18n/index";
app.use(i18n);
封装中英文切换组件
- components/i18n/index.vue
vue
<template>
<el-dropdown>
<span class="imgicon">
<SvgIcon icon="language" :size="size" :color="color"></SvgIcon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item :disabled="flag" @click="changelan('cn')"
>中文</el-dropdown-item
>
<el-dropdown-item :disabled="!flag" @click="changelan('en')"
>英文</el-dropdown-item
>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
<script setup>
import { useI18n } from "vue-i18n";
defineProps({
color: {
type: String,
default: "#fff",
},
size: {
type: String,
default: "36",
},
});
// 切换语言的方法
const i18n = useI18n();
let flag = computed(() => {
const result = i18n.locale.value;
if (result == "cn") {
return true;
} else {
return false;
}
});
const changelan = (val) => {
i18n.locale.value = val;
localStorage.setItem("lang", val);
location.reload();
};
</script>
<style scoped>
:deep(.el-tooltip__trigger:focus-visible) {
outline: unset;
}
.el-dropdown {
float: right;
margin-right: 20px;
.imgicon {
width: 30px;
height: 30px;
float: right;
display: block;
img {
display: block;
width: 100%;
height: 100%;
}
}
}
</style>
(2) 封装 hooks 方法 切换语言
- hooks/usei18n.js
js
import { useI18n } from "vue-i18n";
const usei18n = () => {
const { t } = useI18n();
const test_login_title = ref(t("message.hello"));
const switchLanguage = (lang) => {
localStorage.setItem("lang", lang);
location.reload();
};
return { test_login_title, switchLanguage };
};
export default usei18n;
(3) 封装工具类
- utils/i18n.js
js
import { watch } from "vue";
import i18nAll from "@/i18n";
import { useI18n } from "vue-i18n";
export function generateTitle(title) {
return i18nAll.global.t("message.route." + title);
}
/**
*
* @param {...any} cbs 所有的回调
*/
export function watchSwitchLang(...cbs) {
// 切换语言的方法
const i18n = useI18n();
watch(
() => i18n.locale.value,
() => {
cbs.forEach((cb) => cb(i18n.locale.value));
}
);
}
Elementui-plus 国际化
vue
<template>
<el-config-provider :locale="localLanguage">
<router-view></router-view>
</el-config-provider>
</template>
<script setup>
import zhCn from "element-plus/es/locale/lang/zh-cn";
import en from "element-plus/es/locale/lang/en";
import { useI18n } from "vue-i18n";
// 切换语言的方法
const i18n = useI18n();
const localLanguage = computed(() => {
const result = i18n.locale.value;
if (result == "cn") {
return zhCn;
} else {
return en;
}
});
</script>
页面上使用
- 登录页
vue
<!--
* @Author: jsopy
* @Date: 2025-01-11 09:10:41
* @LastEditTime: 2025-01-18 07:19:19
* @FilePath: /adminvue/src/pages/login/index.vue
* @Description:
*
-->
<template>
<div>
<div class="login-container">
<el-form
class="login-form"
ref="loginFromRef"
:model="loginForm"
:rules="loginRules"
>
<div class="title-container">
<div class="title">用户登陆</div>
<div class="langselecticon">
<I18n></I18n>
</div>
</div>
<el-form-item prop="username">
<span class="svg-container">
<SvgIcon icon="user" size="16" />
</span>
<el-input
placeholder="username"
name="username"
type="text"
v-model="loginForm.username"
/>
</el-form-item>
<el-form-item prop="password">
<span class="svg-container">
<SvgIcon icon="password" size="16" />
</span>
<el-input
placeholder="password"
name="password"
:type="passwordType"
v-model="loginForm.password"
/>
<span class="show-pwd">
<SvgIcon
:icon="passwordType === 'password' ? 'eye' : 'eye-open'"
size="14"
@click="onChangePwdType"
/>
</span>
</el-form-item>
<el-button
type="primary"
style="width: 100%; margin-bottom: 30px; background-color: cadetblue"
:loading="loading"
@click="handleLogin"
>登陆</el-button
>
<div class="tips">
<p>测试权限账号:</p>
<p>提供三种权限账号:</p>
<p>1. 超级管理员账号: super-admin</p>
<p>2. 管理员账号:admin</p>
<p>3. 测试可配置账号:test</p>
<p>密码统一为:123456</p>
<p>
测试中英文切换
<span> {{ $t("message.hello") }}</span>
</p>
<!--
<p>
<span>{{ test_login_title }}</span>
<el-button @click="switchLanguage('cn')">切换语言</el-button>
</p> -->
</div>
</el-form>
</div>
</div>
</template>
<script setup>
import useLogin from "@/hooks/login/useLogin";
// import usei18n from '@/hooks/login/usei18n';
let {
loginForm,
loginRules,
passwordType,
loading,
loginFromRef,
handleLogin,
onChangePwdType,
} = useLogin();
// let { test_login_title, switchLanguage } = usei18n();
</script>
<style lang="scss" scoped>
$bg: #2d3a4b;
$dark_gray: #889aa4;
$light_gray: #eee;
$cursor: #fff;
.login-container {
min-height: 100vh;
width: 100%;
background-color: $bg;
overflow: hidden;
.login-form {
position: relative;
width: 520px;
max-width: 100%;
padding: 160px 35px 0;
margin: 0 auto;
overflow: hidden;
:deep(.el-form-item) {
border: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(0, 0, 0, 0.1);
border-radius: 5px;
color: #454545;
margin-bottom: 50px;
}
:deep(.el-form-item__error) {
font-size: 14px;
left: 0px;
top: 62px;
}
:deep(.el-input__wrapper) {
background-color: rgba(0, 0, 0, 0);
box-shadow: none;
}
:deep(.el-input) {
display: inline-block;
height: 47px;
width: 85%;
input {
background: transparent;
border: 0px;
border-radius: 0px;
padding: 5px 5px 12px 15px;
color: $light_gray;
height: 47px;
caret-color: $cursor;
}
}
}
.tips {
font-size: 16px;
line-height: 28px;
color: #fff;
margin-bottom: 10px;
span {
&:first-of-type {
margin-right: 16px;
}
}
}
.svg-container {
padding: 6px 5px 6px 15px;
color: $dark_gray;
vertical-align: middle;
display: inline-block;
}
.title-container {
position: relative;
width: 100%;
height: 40px;
margin-bottom: 15px;
.title {
font-size: 26px;
color: $light_gray;
position: absolute;
left: 0px;
top: 0px;
width: 100%;
height: 40px;
text-align: center;
font-weight: bold;
}
.langselecticon {
position: absolute;
right: 0px;
top: 0px;
width: 48px;
height: 48px;
z-index: 2;
}
:deep(.lang-select) {
position: absolute;
top: 4px;
right: 0;
background-color: white;
font-size: 22px;
padding: 4px;
border-radius: 4px;
cursor: pointer;
}
}
.show-pwd {
position: absolute;
right: 10px;
top: 7px;
font-size: 16px;
color: $dark_gray;
cursor: pointer;
user-select: none;
}
}
</style>