国际化支持
# 国际化支持
在现代Web应用中,国际化(i18n)支持是非常重要的,尤其是当应用需要面向多个国家或地区的用户时。通过国际化支持,可以根据用户的语言偏好显示相应的文本内容。本文将详细介绍如何在若依框架中实现国际化支持,包括后台和前端的配置步骤。
# 一、后台国际化流程
首先,需要在后端提供一个接口,用于切换语言并保存用户的语言选择。
# 1. 在 SysLoginController.java
中新增语言切换方法
import com.ruoyi.common.core.domain.AjaxResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 系统登录控制器
*/
@RestController
public class SysLoginController {
/**
* 切换语言
*
* @param lang 语言代码(如 "zh_CN" 或 "en_US")
* @return 操作结果
*/
@GetMapping("/changeLanguage")
public AjaxResult changeLanguage(String lang) {
// 在此处可以添加保存用户语言偏好的逻辑,如存入数据库或会话
return AjaxResult.success("语言切换成功");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 2. 在 SecurityConfig.java
中允许匿名访问语言切换方法
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/changeLanguage").permitAll() // 允许匿名访问
.anyRequest().authenticated();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 二、前端国际化流程
前端的国际化支持主要通过 vue-i18n
插件实现。
# 1. 安装 vue-i18n
依赖
在项目的 package.json
中的 dependencies
节点添加 vue-i18n
,并指定版本号。
"vue-i18n": "7.3.2"
1
然后运行 npm install
进行安装。
# 2. 创建国际化文件
在 src
目录下创建一个 lang
目录,用于存放国际化相关的文件。此处我们需要创建三个文件:index.js
、zh.js
和 en.js
。
- index.js:用于配置和初始化
vue-i18n
。
import Vue from 'vue';
import VueI18n from 'vue-i18n';
import Cookies from 'js-cookie';
import elementEnLocale from 'element-ui/lib/locale/lang/en'; // Element UI 英文语言包
import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN'; // Element UI 中文语言包
import enLocale from './en';
import zhLocale from './zh';
Vue.use(VueI18n);
const messages = {
en_US: {
...enLocale,
...elementEnLocale
},
zh_CN: {
...zhLocale,
...elementZhLocale
}
};
const i18n = new VueI18n({
locale: Cookies.get('language') || 'zh_CN', // 从 Cookie 中获取语言设置
messages
});
export default i18n;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- zh.js:存放中文翻译内容。
export default {
login: {
title: '若依后台管理系统',
logIn: '登录',
username: '账号',
password: '密码',
code: '验证码',
rememberMe: '记住密码'
},
tagsView: {
refresh: '刷新',
close: '关闭',
closeOthers: '关闭其它',
closeAll: '关闭所有'
},
settings: {
title: '系统布局配置',
theme: '主题色',
tagsView: '开启 Tags-View',
fixedHeader: '固定 Header',
sidebarLogo: '侧边栏 Logo'
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- en.js:存放英文翻译内容。
export default {
login: {
title: 'RuoYi Login Form',
logIn: 'Login in',
username: 'Username',
password: 'Password',
code: 'Code',
rememberMe: 'Remember Me'
},
tagsView: {
refresh: 'Refresh',
close: 'Close',
closeOthers: 'Close Others',
closeAll: 'Close All'
},
settings: {
title: 'Page style setting',
theme: 'Theme Color',
tagsView: 'Open Tags-View',
fixedHeader: 'Fixed Header',
sidebarLogo: 'Sidebar Logo'
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 3. 在 main.js
中引入并配置 i18n
在 src/main.js
中引入 i18n
,并将其添加到 Vue 实例中。
import Vue from 'vue';
import Element from 'element-ui';
import i18n from './lang'; // 引入国际化配置
Vue.use(Element, {
i18n: (key, value) => i18n.t(key, value),
size: Cookies.get('size') || 'medium'
});
Vue.config.productionTip = false;
new Vue({
el: '#app',
router,
store,
i18n, // 将 i18n 注入 Vue 实例
render: h => h(App)
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 4. 在 Vuex 中添加语言状态管理
在 src/store/modules/app.js
中管理语言状态,通过 Vuex 存储和更新语言设置。
import Cookies from 'js-cookie';
const state = {
language: Cookies.get('language') || 'en_US'
};
const mutations = {
SET_LANGUAGE: (state, language) => {
state.language = language;
Cookies.set('language', language);
}
};
const actions = {
setLanguage({ commit }, language) {
commit('SET_LANGUAGE', language);
}
};
export default {
namespaced: true,
state,
mutations,
actions
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 5. 创建语言切换组件
在 src/components/LangSelect/index.vue
中创建语言切换组件。
<template>
<el-dropdown trigger="click" class="international" @command="handleSetLanguage">
<div>
<svg-icon class-name="international-icon" icon-class="language" />
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :disabled="language==='zh_CN'" command="zh_CN">中文</el-dropdown-item>
<el-dropdown-item :disabled="language==='en_US'" command="en_US">English</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
import { changeLanguage } from "@/api/login";
export default {
computed: {
language() {
return this.$store.getters.language;
}
},
methods: {
handleSetLanguage(value) {
this.$i18n.locale = value;
this.$store.dispatch('app/setLanguage', value);
this.$message({ message: '设置语言成功', type: 'success' });
changeLanguage(value).then(() => {
window.location.reload();
});
}
}
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 6. 修改登录页面以支持国际化
在 src/views/login/index.vue
中使用国际化文本。
<template>
<div class="login">
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
<h3 class="title">{{ $t('login.title') }}</h3>
<lang-select class="set-language" />
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
type="text"
auto-complete="off"
:placeholder="$t('login.username')"
>
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
auto-complete="off"
:placeholder="$t('login.password')"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input
v-model="loginForm.code"
auto-complete="off"
:placeholder="$t('login.code')"
style="width: 63%"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px
;">{{ $t('login.rememberMe') }}</el-checkbox>
<el-form-item style="width:100%;">
<el-button
:loading="loading"
size="medium"
type="primary"
style="width:100%;"
@click.native.prevent="handleLogin"
>
<span v-if="!loading">{{ $t('login.logIn') }}</span>
<span v-else>登 录 中...</span>
</el-button>
<div style="float: right;" v-if="register">
<router-link class="link-type" :to="'/register'">立即注册</router-link>
</div>
</el-form-item>
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2018-2024 ruoyi.vip All Rights Reserved.</span>
</div>
</div>
</template>
<script>
import LangSelect from '@/components/LangSelect'
import { getCodeImg } from "@/api/login";
import Cookies from "js-cookie";
import { encrypt, decrypt } from '@/utils/jsencrypt'
export default {
name: "Login",
components: { LangSelect },
data() {
return {
codeUrl: "",
loginForm: {
username: "admin",
password: "admin123",
rememberMe: false,
code: "",
uuid: ""
},
loginRules: {
username: [
{ required: true, trigger: "blur", message: "请输入您的账号" }
],
password: [
{ required: true, trigger: "blur", message: "请输入您的密码" }
],
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
},
loading: false,
captchaEnabled: true,
register: false,
redirect: undefined
};
},
watch: {
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect;
},
immediate: true
}
},
created() {
this.getCode();
this.getCookie();
},
methods: {
getCode() {
getCodeImg().then(res => {
this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled;
if (this.captchaEnabled) {
this.codeUrl = "data:image/gif;base64," + res.img;
this.loginForm.uuid = res.uuid;
}
});
},
getCookie() {
const username = Cookies.get("username");
const password = Cookies.get("password");
const rememberMe = Cookies.get('rememberMe')
this.loginForm = {
username: username === undefined ? this.loginForm.username : username,
password: password === undefined ? this.loginForm.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
};
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true;
if (this.loginForm.rememberMe) {
Cookies.set("username", this.loginForm.username, { expires: 30 });
Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });
Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
} else {
Cookies.remove("username");
Cookies.remove("password");
Cookies.remove('rememberMe');
}
this.$store.dispatch("Login", this.loginForm).then(() => {
this.$router.push({ path: this.redirect || "/" }).catch(()=>{});
}).catch(() => {
this.loading = false;
if (this.captchaEnabled) {
this.getCode();
}
});
}
});
}
}
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# 7. 接口调用中的国际化支持
在 src/api/login.js
中新增语言切换方法,供前端组件调用。
import request from '@/utils/request'
// 修改语言
export function changeLanguage(lang) {
return request({
url: '/changeLanguage',
method: 'get',
headers: {
isToken: false,
},
params: {
lang: lang
}
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 三、总结
通过上述步骤,我们可以轻松地为若依框架的前后端分离项目添加国际化支持。前端使用 vue-i18n
插件结合 Vuex 管理语言状态,并在需要国际化支持的组件中使用翻译函数 $t
进行文本渲染。后端提供了一个简单的接口,用于切换用户的语言偏好。
- 灵活性:支持动态切换语言,用户可以根据需求选择适合自己的语言环境。
- 易于扩展:可以轻松地添加更多语言支持,只需在前端的
lang
目录中添加相应的语言文件即可。 - 集成性:与 Element UI 组件库紧密集成,国际化配置可统一管理,避免了多处重复配置的问题。
编辑此页 (opens new window)
上次更新: 2024/12/28, 18:32:08