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;     } }
   |