场景
这里简单用一个详情页面开始我们的国际化讲解
这个场景中, logo 需要国际化, tab 以及面包屑的文字需要国际化, 详情需要国际化, 动态详情以及动态详情中的文字需要国际化 经过总结, 国际化数据会有四种类型
后台管理配置的动态数据
服务端渲染的静态的文字
js 渲染的静态文字
静态的图片
后台管理配置的动态数据
场景图中详情数据是通过一个后台管理系统管理, 数据通过语言隔离的方式管理, 接口设计大致如下 语言管理
创建语种 [POST] /m/languages
更新语种 [PUT] /m/languages/{id}
查询语种 [GET] /c/languages/{id}
查询语种列表 [GET] /c/languages?$offset = 偏移量 &$limit = 数量 &$count=true&state=1
数据管理
创精文章 [POST] /m/languages/{language_id}/articles
更新文章 [PUT] /m/languages/articles/{article_id}
删除文章 [DELETE] /m/languages/articles/{article_id}
查询文章 [GET] /c/languages/articles/{article_id}
查询文章列表 [GET]/c/languages/{language_id}/articles?$offset = 偏移量 &$limit = 数量 &$count=true
服务端渲染的静态的文字
如场景图中面包屑, 比如面包屑文字首页 ->详情, 像这种固定的文字不适合在后台管理由运维人员配置用文件统一存储这些国际化的文件比较合适这里采用 SpringMVC 自带的国际化解决方案 配置 ResourceBundleMessageSource
- @Configuration
- public class I18nConfig {
- @Bean
- public ResourceBundleMessageSource messageSource() {
- ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
- messageSource.setBasename("i18n");
- messageSource.setUseCodeAsDefaultMessage(true);
- messageSource.setDefaultEncoding("UTF-8");
- return messageSource;
- }
- }
基于 Cookie 的国际化实现
- @Bean
- public CookieLocaleResolver localeResolver() {
- CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
- cookieLocaleResolver.setCookieName("lang");
- return cookieLocaleResolver;
- }
SpringMVC 国际化的的 resolver 有很多, 用法也很多样, 可以参考这篇博客, 这里就不造轮子了(^^)
国际化语言拦截器
- @Component
- public class I18nInterceptor extends HandlerInterceptorAdapter {
- public static final String DEFAULT_PARAM_NAME = "lang";
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws ServletException {
- String newLocale = request.getParameter(DEFAULT_PARAM_NAME);
- if (newLocale != null) {
- LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
- if (localeResolver == null) {
- throw new IllegalStateException("No LocaleResolver found: not in a DispatcherServlet request?");
- }
- localeResolver.setLocale(request, response, StringUtils.parseLocaleString(newLocale));
- }
- // Proceed in any case.
- return true;
- }
- }
这里拦截器显示多语言路由的实现是通过改变参数来实现语言切换
- http://i18n.example.com?lang=en
- http://i18n.example.com?lang=cn
费些功夫通过改写这个拦截器的实现以及路由的设计, 可以把国际化的路由改写成这样子
- http://i18n.example.com/en
- http://i18n.example.com/cn
在 resources 中配置配置国际化语言文件
i18n.properties 默认
i18n_en.properties 英文
i18n_cn.properties 中文
添加 el 表达式
- public static String i18n(String key) {
- RequestContext requestContext = new RequestContext(SpringUtil.getRequest());
- return requestContext.getMessage(key);
- }
在 tld 配置
- <function>
- <description > 国际化</description>
- <name>i18n</name>
- <function-class>com.example.utils.ElFuncUtil
- </function-class>
- <function-signature>java.lang.String i18n(java.lang.String))</function-signature>
- <example>${elf:i18n(key)}</example>
- </function>
使用
<span>${elf:i18n("详情")}</span>
很遗憾, Spring 自带的国际化方案有一个缺陷: 配置文件是内置在项目代码中的, 无法剥离到后台统一管理, 这样子如果新增一种语言, 就必须动到项目代码 有能力的同学可以尝试改写 ResourceBundleMessageSource, 能支持读取远端的配置文件, 这样就完美了
js 渲染的静态的文字
场景图中动态推荐部分是用 js 渲染出来的, 其中会出现全部等一些静态的文本这些文本也需要国际化我在项目中使用现在最受欢迎的 js 框架 vue 配合使用 (vue-i18n)[http://kazupon.github.io/vue-i18n/en/started.html] 进行国际化 引入 vue-i18n
- import Vue from 'vue'
- import VueI18n from 'vue-i18n'
- import messages from './message.json'
- import { langCode } from '../lang'
- Vue.use(VueI18n)
- export default new VueI18n({
- locale: langCode,
- messages
- })
- message.json
- "cn": {
- "全部": "全部"
- },
- "en": {
- "全部": "All"
- }
使用
- vueI18n.t('全部')
- // 或者, 在 template 模板中
- <p>{{ $t("全部") }}</p>
静态的图片
场景图中的 logo 根据不同语言也需要不同, 这样的图片需要直接其访问其图片路径, 我们约定图片的访问路径规则
<img src="/images/logo_${lang}.svg" onerror='this.src="${ctx}/images/logo_en.svg"'/>
抽取配置的自动化脚本
国际化的文本处于各个代码文件中, 手动拷贝到配置文件是一件效率相当底下且容易出错的事情故写个自动化脚本溜起来 抽取国际化文本成 json 文件的自动化脚本实现 抽取国际化文本成 properties 文件的自动化脚本实现 把 properties 中的文件转移到 xlsx 文件中的自动化脚本实现
结语
随着咱国家的国力不断强盛, 国际影响力不断扩大会有更多更好的产品走向世界, 国际化已经成为势不可挡的趋势
来源: https://juejin.im/post/5aa89c706fb9a028c14a281c