Springboot与国际化(i18n)

一、什么是国际化?

  • 国际化就是在不修改内部代码的情况下,根据不同语言及地区显示相应的语言界面。

  • i18n的由来→internationalization,数一下,首字母i和末位字母之间有18个字母。类似的命名还有很多,例如k8s。

  • Springboot已经对i18n国际化做了自动配置,自动配置类。

org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration

如果想自定义国际化,通过@Autowired配置使用MessageSource进行自定义。

二、前端联合后端实现国际化。

一图解释什么是国际化:

Springboot与国际化(i18n)_第1张图片

原理:由前端页面某个元素(中文/English)返回给后端一个标识,后端根据标识获取地域信息,Springboot框架内置的MessageSource会获取该标识(图中只有两种标识,因此只有两种语种)来进行语种转换。当然转换的前提是要提前通过messages.properties文件来配置相应语言。

  • 前端代码如下:(l='zh_CN’和l='en_US’就是标识)

  •   
      <html lang="en" xmlns:th="http://www.thymeleaf.org">
      	<head>
      		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      		<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
      		<meta name="description" content="">
      		<meta name="author" content="">
      		<title>Signin Template for Bootstraptitle>
      		
      		<link href="asserts/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/4.2.1/css/bootstrap.css}" rel="stylesheet">
      		
      		<link href="asserts/css/signin.css" rel="stylesheet">
      	head>
      
      	<body class="text-center">
      		<form class="form-signin" action="dashboard.html">
      			<img class="mb-4" src="asserts/img/bootstrap-solid.svg" alt="" width="72" height="72">
      			<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.btn}">Please sign inh1>
      			<label class="sr-only">Usernamelabel>
      			<input type="text" class="form-control" th:placeholder="#{login.username}" placeholder="Username" required="" autofocus="">
      			<label class="sr-only">Passwordlabel>
      			<input type="password" class="form-control" th:placeholder="#{login.password}" placeholder="Password" required="">
      			<div class="checkbox mb-3">
      				<label>
                <input type="checkbox" value="remember-me"> [[#{login.remember}]]
              label>
      			div>
      			<button class="btn btn-lg btn-primary btn-block" th:text="#{login.sign}" type="submit">Sign inbutton>
      			<p class="mt-5 mb-3 text-muted">© 2017-2018p>
      			<a class="btn btn-sm" th:href="@{/login.html(l='zh_CN')}">中文a>
      			<a class="btn btn-sm" th:href="@{/login.html(l='en_US')}">Englisha>
      		form>
      	body>
      html>
    
  • 后端代码:

  •   package com.example.bootstudy.component;
      
      import org.springframework.util.StringUtils;
      import org.springframework.web.servlet.LocaleResolver;
      
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.util.Locale;
      
      /**
       * ----------------------------------------------------------------
       * @description:   自定义Local地域的解析
       * @author: Create by Liu Wen at 2020-07-08 17:34
       * ----------------------------------------------------------------
       **/
      public class MyLocaleResolver implements LocaleResolver {
      
          @Override
          public Locale resolveLocale(HttpServletRequest httpServletRequest) {
              String l = httpServletRequest.getParameter("l");
              Locale locale = Locale.getDefault();
              if(!StringUtils.isEmpty(l)){
                  String[] atts = l.split("_");
                  locale = new Locale(atts[0],atts[1]);
              }
              return locale;
          }
      
          @Override
          public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
      
          }
      }
    
    package com.example.bootstudy.config;
    
    import com.example.bootstudy.component.MyLocaleResolver;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.LocaleResolver;
    import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    /**
     * ----------------------------------------------------------------
     * @description:   将自定义的MyLocaleResolver配置到Springboot框架中
     * @author: Create by Liu Wen at 2020-07-08 17:34
     * ----------------------------------------------------------------
     **/
    @Configuration
    public class MymvcConfig implements WebMvcConfigurer {
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
            registry.addViewController("/").setViewName("login");
            registry.addViewController("/login.html").setViewName("login");
        }
    
        @Bean
        public LocaleResolver localeResolver(){
            return new MyLocaleResolver();
        }
    }
    
  • login.properties文件配置

  •   #login_en_US.properties文件
          
      login.btn=\u8BF7\u767B\u5F55
      login.password=\u5BC6\u7801
      login.remember=\u8BB0\u4F4F\u6211
      login.sign=\u767B\u5F55
      login.username=\u7528\u6237\u540D
          
      #login_zh_CN.properties文件
      login.btn=Please sign in
      login.password=Password
      login.remember=Remember me
      login.sign=Sign in
      login.username=Username
    
  • application.yml配置

  •   spring:
        messages:
          basename: i18n/login
    

代码结构如图:

Springboot与国际化(i18n)_第2张图片

三、服务端国际化(Springboot内置国际化)

服务端的国际化一般用于信息提示。不集成前端。

可以直接使用默认的Springboot内置国际化,也可以自定义。代码如下:

  • messages.properties文件配置

  •   #messages_zh_CN.properties文件
      MSGFM00100001=\u8282\u70B9(id:{0})\u4E0D\u5B58\u5728.
      MSGFM00100002=\u8282\u70B9(id:{0})\u4E0D\u662F\u6D41\u7A0B\uFF0C\u6240\u4EE5\u5E76\u6CA1\u6709\u6D41\u7A0B\u56FE.
      MSGFM00100003=\u9879\u76EE(id:{0})\u5DF2\u7ECF\u5B58\u5728\u8BE5\u8282\u70B9.
      MSGFM00100004=\u9879\u76EE(id:{0})\u7684\u6839\u8282\u70B9\u4E0D\u5B58\u5728.
      MSGFM00100005=\u8282\u70B9(id:{0})\u7684\u7236\u8282\u70B9\u4E0D\u5B58\u5728.
      
      #messages_en_US.properties文件
      MSGFM00100001=The node(id:{0}) does not exist.
      MSGFM00100002=The node(id:{0}) is not a "FLOW" node, so it can not have a graph.
      MSGFM00100003=The project(id:{0}) has already got a root node.
      MSGFM00100004=The root node of project(id:{0}) does not exist.
      MSGFM00100005=The parent node(id:{0}) does not exist.
    
  • 自定义MessageSource工具:

  •   package com.sample.utils;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.context.MessageSource;
      import org.springframework.context.i18n.LocaleContextHolder;
      import org.springframework.stereotype.Component;
      
      import java.util.Locale;
      
      /**
       * MessageSource工具
       * 依賴{@link MessageSource}
       *
       * @author Catscan
       * @date 2019-06-07
       */
      @Component
      public class MessageSourceUtil {
      
          @Autowired
          private MessageSource messageSource;
      
          public String getMessage(String code) {
              return getMessage(code, null);
          }
      
          public String getMessage(String code, Object[] args) {
              return getMessage(code, args, "");
          }
      
          public String getMessage(String code, Object[] args, String defaultMsg) {
              // 這裡可以使用一些比較trick的方法動態設定語言
              // 可以做全站全局、單個request,當然,方法需要根據不同情況修改
              Locale locale = LocaleContextHolder.getLocale();
              return messageSource.getMessage(code, args, defaultMsg, locale);
          }
      }
    
  • 测试内置的国际化与自定义的国际化

  •   package com.sample.controller;
      
      import com.sample.utils.MessageSourceUtil;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.context.MessageSource;
      import org.springframework.http.ResponseEntity;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.HashMap;
      import java.util.Locale;
      import java.util.Map;
      
      /**
       * 測試用的Controller
       *
       * @author Catscan
       * @date 2019-06-07
       */
      @RestController
      @RequestMapping("/")
      public class MessageController {
          @Autowired
          private MessageSourceUtil messageSourceUtil;
      
          @Autowired
          private MessageSource messageSource;
      
          /**
           * 測試使用{@link MessageSource}
           *
           * @return {@link ResponseEntity}
           */
          @RequestMapping("/message")
          public ResponseEntity pingResource(){
              Map<String ,String> result = new HashMap<>(3);
      
              result.put("default",messageSource.getMessage("hello", null, "", null));
              result.put("en_US",messageSource.getMessage("hello", null, "", Locale.US));
              result.put("zh_CN",messageSource.getMessage("hello", null, "", Locale.SIMPLIFIED_CHINESE));
      
              return ResponseEntity.ok(result);
          }
      
      
          /**
           * 測試使用{@link MessageSourceUtil}
           *
           * @return {@link ResponseEntity}
           */
          @RequestMapping("/util")
          public ResponseEntity pingUtil(){
              return ResponseEntity.ok(messageSourceUtil.getMessage("hello"));
          }
      }
    

    多语言环境是定义在java.util.Locale类中的,如:

    ...
    static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN");
    static public final Locale CHINA = SIMPLIFIED_CHINESE;
    static public final Locale UK = createConstant("en", "GB");
    static public final Locale US = createConstant("en", "US");
    static public final Locale CANADA = createConstant("en", "CA");
    ...
    

    分析:在MessageSource.getMessage(...)所有方法中,都有Locale参数,指定区域信息。
    当调用时,要如果指定位置为:Locale.CHINA,这时ResourceBundelMessageSource会从messages_zh_CN.properties中寻找对应的键值。
    当给出Locale参数值为null,空的区域信息;或者对应的properties文件中没有找到对应的键值对,那么ResourceBundelMessageSource默认会从messages.properties中寻找键,当都找不到的时候,会返回空字符串。

你可能感兴趣的:(我的工作笔记,四.Java项目篇)