spring实现
先上代码结构
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
| ➜ i18n-demo tree . ├── pom.xml └── src ├── main │ ├── java │ │ └── cn │ │ └── idea360 │ │ └── i18n │ │ ├── I18nDemoApplication.java │ │ ├── config │ │ │ └── MvcConfig.java │ │ └── web │ │ └── HelloController.java │ └── resources │ ├── application.properties │ ├── i18n │ │ ├── messages.properties │ │ ├── messages_en_US.properties │ │ └── messages_zh_CN.properties │ ├── static │ └── templates └── test └── java └── cn └── idea360 └── i18n └── I18nDemoApplicationTests.java
|
messages.properties可以为空, 但不能没有
pom.xml
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
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.14</version> <relativePath/> </parent> <groupId>cn.idea360</groupId> <artifactId>i18n-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>i18n-demo</name> <description>i18n-demo</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build>
</project>
|
application.properties
1 2 3
| spring.messages.basename=i18n/messages spring.messages.cache-duration=1 spring.messages.encoding=UTF-8
|
properties文件注意需要 UTF-8
编码, 避免中文乱码
i18n配置文件
messages_en_US.properties
messages_zh_CN.properties
默认国际化
默认情况下会根据请求头中的 Accept-Language
来切换locale, 具体实现参见 AcceptHeaderLocaleResolver
.
1 2 3 4 5 6 7 8 9 10 11
| @Configuration public class LocaleConfiguration {
@Bean public LocaleResolver localeResolver() { AcceptHeaderLocaleResolver resolver = new AcceptHeaderLocaleResolver(); resolver.setDefaultLocale(Locale.US); return resolver; } }
|
自定义国际化
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
| package cn.idea360.i18n.config;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import java.util.Locale;
@Configuration public class MvcConfig implements WebMvcConfigurer {
@Bean public LocaleResolver localeResolver() { SessionLocaleResolver slr = new SessionLocaleResolver(); slr.setDefaultLocale(Locale.SIMPLIFIED_CHINESE); return slr; }
@Bean public LocaleChangeInterceptor localeChangeInterceptor() { LocaleChangeInterceptor lci = new LocaleChangeInterceptor(); lci.setParamName("lang"); return lci; }
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(localeChangeInterceptor()); } }
|
测试
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
| package cn.idea360.i18n.web;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController public class HelloController {
@Resource private MessageSource messageSource;
@GetMapping("/hello") public String hello() { return messageSource.getMessage("user.name", null, LocaleContextHolder.getLocale()); } }
|
其他国际化测试
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
| package cn.idea360.i18n;
import org.junit.jupiter.api.Test;
import java.text.DateFormat; import java.text.MessageFormat; import java.text.NumberFormat; import java.time.LocalDateTime; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; import java.util.Date; import java.util.Locale; import java.util.ResourceBundle;
public class I18nTest {
@Test void displayName_test() { Locale locale=new Locale("en","US"); System.out.println(locale.getDisplayName()); System.out.println(locale.getDisplayName(Locale.US)); }
@Test void numberFormat_test() { Locale localeEn = new Locale("en", "US"); Locale localeZh = new Locale("zh", "CN"); NumberFormat formatEn = NumberFormat.getNumberInstance(localeEn); NumberFormat formatZh = NumberFormat.getNumberInstance(localeZh); double num = 123456.78; System.out.println(formatEn.format(num)); System.out.println(formatZh.format(num)); }
@Test void currencyFormat_test() { Locale localeEn = new Locale("en", "US"); Locale localeZh = new Locale("zh", "CN"); NumberFormat formatEn = NumberFormat.getCurrencyInstance(localeEn); NumberFormat formatZh = NumberFormat.getCurrencyInstance(localeZh); double num = 123456.78; System.out.println(formatEn.format(num)); System.out.println(formatZh.format(num)); }
@Test void percentFormat_test() { Locale localeEn = new Locale("en", "US"); Locale localeZh = new Locale("zh", "CN"); NumberFormat formatEn = NumberFormat.getPercentInstance(localeEn); NumberFormat formatZh = NumberFormat.getPercentInstance(localeZh); double num = 0.2; System.out.println(formatEn.format(num)); System.out.println(formatZh.format(num)); }
@Test void messageFormat_test() { Locale localeEn = new Locale("en", "US"); Locale localeZh = new Locale("zh", "CN"); ResourceBundle enResource = ResourceBundle.getBundle("i18n/messages", localeEn); MessageFormat enFormat = new MessageFormat(enResource.getString("user.name")); ResourceBundle zhResource = ResourceBundle.getBundle("i18n/messages", localeZh); MessageFormat zhFormat = new MessageFormat(zhResource.getString("user.name")); System.out.println(enFormat.format(null)); System.out.println(zhFormat.format(null)); }
@Test void dateFormat_test() { Date date = new Date(); DateFormat df1 = DateFormat.getDateInstance(DateFormat.LONG, new Locale("en", "US")); DateFormat df2 = DateFormat.getDateInstance(DateFormat.LONG, new Locale("zh", "CN")); System.out.println(df1.format(date)); System.out.println(df2.format(date)); }
@Test void localDateTimeFormat_test() { LocalDateTime localDateTime = LocalDateTime.now(); DateTimeFormatter df1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.US); DateTimeFormatter df2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.CHINA); System.out.println(df1.format(localDateTime)); System.out.println(df2.format(localDateTime)); }
@Test void zonedDateTimeFormat_test() { ZonedDateTime zonedDateTime = ZonedDateTime.now(); DateTimeFormatter df1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG).withLocale(Locale.US); DateTimeFormatter df2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG).withLocale(Locale.CHINA); System.out.println(df1.format(zonedDateTime)); System.out.println(df2.format(zonedDateTime)); } }
|
自定义简单轮子
pom.xml
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
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.idea360</groupId> <artifactId>i18n-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>i18n-demo</name> <description>i18n-demo</description> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.6.13</spring-boot.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency>
</dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <configuration> <mainClass>cn.idea360.i18ndemo.I18nDemoApplication</mainClass> <skip>true</skip> </configuration> <executions> <execution> <id>repackage</id> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
</project>
|
resources
在 resources/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 28 29 30 31 32 33 34 35 36 37 38 39 40
| package cn.idea360.i18ndemo.web;
import org.apache.commons.io.IOUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController;
import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Properties;
@RestController @RequestMapping public class I18nController {
@GetMapping("/locale") public Object getLocale(@RequestParam("lang") String lang) throws Exception { InputStream inputStream = I18nController.class.getResourceAsStream("/application.properties"); Properties properties = new Properties(); properties.load(inputStream); properties.forEach((k, v) -> System.out.println(k + "=" + v));
String locale = String.format("/i18n/message_%s.properties", lang); List<String> lines = IOUtils.readLines(I18nController.class.getResourceAsStream(locale), StandardCharsets. UTF_8); lines.forEach(System.out::println); return lines; } }
|