⼀篇⽂章解决springboot+thymeleaf多语⾔国际化
1.前⾔
博主最近在写⼀个多语⾔的项⽬,因为之前没实际接触过多语⾔的设计,所以写这篇⽂章记录下这次多语⾔开发的过程。
博主的开发环境是:Springboot1.5.6 + thymeleaf,需要注意的是,springboot 1.x和2.x有⽐较⼤的差别。
⽂章实现的主要功能:
1. springboot+thymeleaf最基本的国际化配置
2. ⾃定义配置国际化,区域解析器sumif函数的使用方法求平均年龄
3. 读取多个分类的国际化⽂件;
4. 后台设置前端页⾯显⽰国际化信息的⽂件
5. 利⽤和注解⾃动设置前端页⾯显⽰国际化信息的⽂件
6. 前端js中怎么实现国际化
2.springboot+thymeleaf最基本的国际化配置
如果国际化需求不是很复杂,使⽤简单的配置就能完成,下⾯的代码展⽰的就是springboot+thymeleaf最基本的国际化配置。
⾸先,我们先定义国际化资源⽂件,就是放每个语⾔资源的⽂件。springboot默认就⽀持国际化的,⽽且不需要你过多的做什么配置,只需要在 resources/ 下定义国际化配置⽂件即可,默认的⽂件名称是messages.properties,其他语⾔的⽂件名格式则是messages_国家语⾔编码.properties,如简体中⽂是messages_zh_CN.properties、英语是messages_en_US.properties.
各个语⾔的⽂件名格式
资源⽂件中采⽤键值对格式
配置好国际化资源⽂件后,我们编写⼀个配置类WebMvcConfig.java,它继承WebMvcConfigurerAdapter。该类中定义了⼀
个CookieLocaleResolver,采⽤cookie来控制国际化的语⾔,同样的也可以定义SessionLocaleResolver,它是将国际化信息放在session中,另外AcceptHeaderLocaleResolver则是将国际化信息放在请求头中传递。下⾯还设置⼀个LocaleChangeInterceptor来拦截国际化语⾔的变化。
/**
* 基本配置
*
* @author Nelson(mr_caitw @ 163)
* @date 2020/7/3 10:24
*/
c语言大学实用教程第四版pdf
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
/**
* 配置使⽤cookie存储国际化相关配置信息
* @return
*/
@Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver clr = new CookieLocaleResolver();
//设置默认语⾔为繁体中⽂
clr.setDefaultLocale(Locale.TAIWAN);
//最⼤有效时间
clr.setCookieMaxAge(3600);
//设置存储的Cookie的name为Language
clr.setCookieName("language");
return clr;
}
/
**
小程序面试题* 配置
*
* @param registry动画效果在哪
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
//国际化配置
registry.addInterceptor(localeChangeInterceptor()).addPathPatterns("/**");
super.addInterceptors(registry);
}
}
就这样最简单国际化后台配置就完成了,下⾯我们看看页⾯怎么使⽤国际化,前端只要使⽤ th:text="#{多语⾔key}" 就能完成多语⾔⽂字的渲染。我们编写⼀个hello.html,内容如下:
<!DOCTYPE html>
<html xmlns="/1999/xhtml" xmlns:th="">
<head>
<title>springboot + thymeleaf国际化!</title>
</head>
<body>
<!-- 操作成功 -->
<h1 th:text="#{success_code_0}"></h1>
<!-- 未知错误,请联系管理员 -->
<h3 th:text="#{error_code_-1}"></h3>
</body>
</html>
以上就完成了最简单的多语⾔的实现,是不是不需要做过多的处理就能完成多语⾔开发?哈哈哈哈,springboot开发就是这么⽅便快捷!
在博主的项⽬⾥,简单的多语⾔还不符合我的需求,所以后⾯我写的是⾃定义国际化配置,要复杂很多,⼀起来看看吧!
3.进阶:⾃定义国际化配置和区域解析器
3.1 配置国际化资源路径
前⾯我提到过,springboot是默认⽀持国际化的,默认在 resources/ 下定义国际化配置⽂件即可,现在我们来⾃定义资源⽂件的路径。⾃定义资源⽂件路径需要在application.properties中定义。
⽂件结构
application.properties中的i18n配置
如图,我将多语⾔的资源⽂件放到了static下⾯(⾄于这⾥我为什么要放在static下⾯,后⾯再解释)。
3.2 实现国际化资源⽂件⾃动加载
在我们实际项⽬中肯定不会只有⼏个国际化信息那么少,通常都是成千上百个的,那我们肯定不能把这么多的国际化信息都放
在messages.properties⼀个⽂件中,通常都是把国际化信息分类存放在⼏个⽂件中。但是当项⽬⼤了以后,这些国际化⽂件也会越来越多,这时候在application.properties⽂件中⼀个个的去配置这个⽂件也是不⽅便的,所以现在我们实现⼀个功能⾃动加载制定⽬录下所有的国际化⽂件。
在项⽬下创建⼀个类MessageResourceExtension.java继承ResourceBundleMessageSource或
者ReloadableResourceBundleMessageSource。并且注⼊到bean中起名为messageSource,这⾥我们继承ResourceBundleMessageSource。需要注意的是bean的名字必须是messageSource不能改,因为在初始化ApplicationContext的时候,会查bean名为'messageSource'的bean。这个过程在AbstractApplicationContext.java中。
/**
/**
* 配置国际化⽂件⾃动匹配获取
* @Author Nelson (mr_caitw@163)
* @Date 2020/6/28 17:51
*/
@Slf4j
@Component("messageSource")
public class MessageResourceExtension extends ResourceBundleMessageSource {
properties是什么文件/**
* 指定的国际化⽂件⽬录
*/
@Value(value = "${ssages.baseFolder}")
private String baseFolder;
/**
* ⽗MessageSource指定的国际化⽂件
*/
@Value(value = "${ssages.basename}")
private String basename;
public static String I18N_ATTRIBUTE = "i18n_attribute";
@PostConstruct
public void init() {
log.info("");
if (!StringUtils.isEmpty(baseFolder)) {
try {
this.setBasenames(getAllBaseNames(baseFolder));
} catch (IOException e) {
<(e.getMessage());
}
}
//设置⽗MessageSource
ResourceBundleMessageSource parent = new ResourceBundleMessageSource();
//是否是多个⽬录
if (basename.indexOf(",") > 0) {
parent.setBasenames(basename.split(","));
} else {
parent.setBasename(basename);
}
/
/设置⽂件编码
parent.setDefaultEncoding("UTF-8");
this.setParentMessageSource(parent);
}
/**
* 获取国际化资源
* @param code 资源code
* @param locale 语⾔编码
* @return
*/
@Override
protected String resolveCodeWithoutArguments(String code, Locale locale) {
// 获取request中设置的指定国际化⽂件名
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();        final String i18File = (String) Attribute(I18N_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
if (!StringUtils.isEmpty(i18File)) {
//获取在basenameSet中匹配的国际化⽂件名
String basename = "";
String[] baseNameArr = getBasenameSet().toArray(new String[]{});
for (String aBaseNameArr : baseNameArr) {
if (dsWithIgnoreCase(aBaseNameArr, i18File)) {
basename = aBaseNameArr;
break;
}
}
}
if (!StringUtils.isEmpty(basename)) {
//得到指定的国际化⽂件资源
ResourceBundle bundle = getResourceBundle(basename, locale);
if (bundle != null) {
return getStringOrNull(bundle, code);
}
}
}
//如果指定i18⽂件夹中没有该国际化字段,返回null会在ParentMessageSource中查
return null;
}
/**
* 获取⽂件夹下所有的国际化⽂件名
*
* @param folderName ⽂件夹名
* @return
* @throws IOException
*/
public String[] getAllBaseNames(final String folderName) throws IOException {
URL url = Thread.currentThread().getContextClassLoader()
.getResource(folderName);
if (null == url) {
throw new RuntimeException("⽆法获取资源⽂件路径");
}
List<String> baseNames = new ArrayList<>();
if (Protocol().equalsIgnoreCase("file")) {
// ⽂件夹形式,⽤File获取资源路径
File file = new File());
if (ists() && file.isDirectory()) {
baseNames = Files.Path())
.filter(path -> File().isFile())
.map(Path::toString)
.map(path -> path.substring(path.indexOf(folderName)))
.map(this::getI18FileName)
.distinct()
.List());
} else {
羊了个羊急招后端开发("指定的baseFile不存在或者不是⽂件夹");
}
} else if (Protocol().equalsIgnoreCase("jar")) {
/
/ jar包形式,⽤JarEntry获取资源路径
String jarPath = File().File().indexOf(":") + 2, File().indexOf("!"));            JarFile jarFile = new JarFile(new File(jarPath));
List<String> baseJars = jarFile.stream()
.map(ZipEntry::toString)
.filter(jar -> dsWith(folderName + "/")).List());
jarFile.
if (baseJars.isEmpty()) {
log.info("不存在{}资源⽂件夹", folderName);
return new String[0];
}
baseNames = jarFile.stream().map(ZipEntry::toString)
.filter(jar -> baseJars.stream().anyMatch(jar::startsWith))
.filter(jar -> dsWith(".properties"))
.map(jar -> jar.substring(jar.indexOf(folderName)))
.map(this::getI18FileName)
.distinct()
.List());
}
Array(new String[0]);

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。