前言
什麼是國際化呢?國際慣例,來時來一段官方介紹:
- 國際化(internationalization)是設計和製造容易適應不同區域要求的產品的一種方式。
- 它要求從產品中抽離所有地域語言,國家/地區和文化相關的元素。
- 換言之,應用程序的功能和代碼設計考慮在不同地區運行的需要,其代碼簡化了不同本地版本的生產。
- 開發這樣的程序的過程,就稱為國際化。
在我們實際開發中,一個web應用可能要在多個地區使用,面對不同地區的不同語言,為了適應不同的用戶,我們可以嘗試在前端頁面實現多語言的支持,那麼同樣對於後端返回的一些提示信息,異常信息等,我們後端也可以根據不同的語言環境來進行國際化處理,返回相應的信息。
開發工具
IDEA、Maven、SpringBoot2.0.5、Jdk1.8、google瀏覽器
SpringBoot中的國際化
原理:
想要使應用支持國際化,首先需要知道用戶的語言環境,即用戶想要看到的語言,我們設想在用戶每次請求時告訴服務器自己的語言環境,服務器收到請求後,根據不同的語言環境返回不同的信息來實現國際化。在spring應用中,用戶的語言環境是通過區域解析器來識別的,而區域解析器有分為好幾種(後面詳細說),在我們不做配置修改時,spring使用AcceptHeaderLocaleResolver作為默認的區域解析器,它是根據HTTP請求 Header中的Accept-language的值來解析,當然區域解析器我們也可以自定義配置。
springboot默認就支持國際化。我們只需要只需要作相應的配置即可。
1.首先你需要一個springboot項目。IDEA中分分鐘創建好一個項目。
2.在resources下定義國際化配置文件,注意名稱必須以messages開始。(在springboot中,當我們不修改配置時默認去解析名稱以message開始的properties文件)
messages.properties (默認環境,無法確定語言環境時,解析該文件中的相應信息)
messages_zh_CN.properties(中文語言環境時,解析該文件中的相應信息)
messages_en_US.properties(英文語言環境時,解析該文件中的相應信息)
在三個配置文件中分別以Key = Value形式存儲如下三條信息,如下:
welcome = 這是一個支持國際化的項目。
welcome = 這是一個支持國際化的項目。
3.創建thymeleaf頁面
加入thymeleaf依賴
-
org.springframework.boot -
spring-boot-starter-thymeleaf
在resources/templates目錄下創建hello.html頁面:
嘗試在不同的語言環境下,通過#{welcome}獲取信息
-
demo
4.創建訪問頁面的controller
注意這裡controller的註解時@Controller
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- /**
- * 描述:
- *
- * @author zhengql
- * @date 2018/9/25 19:28
- */
- @Controller
- public class BaseController {
- @RequestMapping("/hi")
- public String hello() {
- return "/hello";
- }
- }
測試國際化效果
這裡使用google瀏覽器進行測試,測試之前需要安裝插件Language Switcher
Language Switcher : 可以改變當前請求的語言環境(根據自己的選擇)
啟動我們的springboot項目,google瀏覽器訪問 http://127.0.0.1:8080/hi ,可以看到如下頁面:
通過Language Switcher切換語言環境為English - United States,重新訪問 http://127.0.0.1:8080/hi ,可以看到如下頁面:
ok,大功告成,到此一個簡單的國際化項目就完成了。
擴展國際化
通過上面的小栗子,我們可以看到一個簡單的國際化使用,但是在開發中中還需要我們進行一定的配置,來滿足我們不同情況下的使用。
在返回結果中獲取國際化信息
很多時候,後端接收到一個請求後,需要返回一個提示信息,而此時我們可以使這個返回信息支持國際化
這裡就用到了org.springframework.context.MessageSource接口,MessageSource提供了三個方法
@Nullable//參數字段可為空
- String getMessage(String var1, @Nullable Object[] var2, @Nullable String var3, Locale var4);
- String getMessage(String var1, @Nullable Object[] var2, Locale var3) throws NoSuchMessageException;
- String getMessage(MessageSourceResolvable var1, Locale var2) throws NoSuchMessageException;
String getMessage(String var1, @Nullable Object[] var2, @Nullable String var3, Locale var4):用來從MessageSource獲取消息的基本方法。如果在指定的locale中沒有找到消息,則使用默認的消息。var2中的參數將使用標準類庫中的MessageFormat來作消息中替換值。
String getMessage(String code, Object[] args, Locale loc):本質上和上一個方法相同,其區別在:沒有指定默認值,如果沒找到消息,會拋出一個NoSuchMessageException異常。
String getMessage(MessageSourceResolvable resolvable, Locale locale):上面方法中所使用的屬性都封裝到一個MessageSourceResolvable實現中,而本方法可以指定MessageSourceResolvable實現。
下面我們實踐一下:
1.創建一個以json返回格式的controller,注入MessageSource,注意controller的註解為@RestController
在這裡首先我們需要獲取到當前請求的Locale,有兩種方法:
- Locale locale = LocaleContextHolder.getLocale();
- Locale locale = RequestContextUtils.getLocale(request);
兩種方式根據情況選擇使用,下面是controller代碼
- package com.example.i18n.controller;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.MessageSource;
- import org.springframework.context.i18n.LocaleContextHolder;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- /**
- * 描述:
- *
- * @author zhengql
- * @date 2018/9/21 10:54
- */
- @RestController
- public class JsonController {
- @Autowired
- private MessageSource messageSource;
- @RequestMapping("/ha")
- public String ha() {
- return messageSource.getMessage("welcome", null, LocaleContextHolder.getLocale());
- }
- }
2.啟動項目訪問 http://127.0.0.1:8080/ha ,可以看到相應語言環境的返回信息
通過Language Switcher切換語言環境為English - United States,重新訪問http://127.0.0.1:8080/ha,可以看到如下頁面:
支持佔位符國際化信息返回
我們經常會遇到這樣一個場景,登錄賬號需要驗證碼,填寫完手機號獲取驗證碼後會收到一條類似於尊敬的用戶13099999999您好,您的驗證碼是6666,這種信息,其實就是一個模板,通過改變參數,重複使用。我們通過國際化資源文件中的佔位符,配合MessageSource提供的api也可以實現。
資源文件中加入如下屬性:
messages.properties,messages_zh_CN.properties
- hello=你好:{0} , 你的驗證碼為 :{1}
messages_en_US.properties
- hello=Hello: {0}, your verification code is: {1}
我們在JsonController中,創建一個測試接口
- @RequestMapping("/haha")
- public String haha() {
- return messageSource.getMessage("hello", new Object[]{"zhangsan","123456"}, LocaleContextHolder.getLocale());
- }
啟動項目直接,訪問 http://127.0.0.1:8080/haha 可以看到相應語言環境的返回信息
通過Language Switcher切換語言環境為English - United States,重新訪問 http://127.0.0.1:8080/haha ,可以看到如下頁面:
支持國際化的枚舉類
既然返回信息可以實現國際化,那我們的枚舉類同樣也可以實現國際化咯
創建一個枚舉類EnumSuccessOrError.java
- /**
- * 描述:枚舉類舉例
- *
- * @author zhengql
- * @date 2018/9/26 20:52
- */
- public enum EnumSuccessOrError {
- SUCCESS(0, "操作成功"),
- ERROR(1, "操作失敗");
- /**
- * 返回狀態碼
- */
- private int statusCode;
- /**
- * 返回狀態信息
- */
- private String statusMsg;
- EnumSuccessOrError(int statusCode, String statusMsg) {
- this.statusCode = statusCode;
- this.statusMsg = statusMsg;
- }
- /**
- * @return the statusCode
- */
- public int getStatusCode() {
- return statusCode;
- }
- /**
- * @return the statusMsg
- */
- public String getStatusMsg() {
- return statusMsg;
- }
- }
如上,剛剛創建的枚舉類是不支持國際化的,我們呢需要改造他,當調用getStatusMsg方法時根據語言環境返回相應的國際化字符串。可以從如下兩個點著手:
getStatusMsg方法改造
資源文件中添加不同語言環境對應的返回值
先在三個資源文件中加入不同環境的返回值:
messages.properties,messages_zh_CN.properties
- SUCCESS = 操作成功
- ERROR = 操作失敗
messages_en_US.properties
- SUCCESS=success
- ERROR=error
改造後的枚舉如下:
- public enum EnumSuccessOrError {
- SUCCESS(0, "SUCCESS"),
- ERROR(1, "ERROR");
- /**
- * 返回狀態碼
- */
- private int statusCode;
- /**
- * 返回狀態信息
- */
- private String statusMsg;
- EnumSuccessOrError(int statusCode, String statusMsg) {
- this.statusCode = statusCode;
- this.statusMsg = statusMsg;
- }
- private MessageSource messageSource;
- public EnumSuccessOrError setMessageSource(MessageSource messageSource) {
- this.messageSource = messageSource;
- return this;
- }
- //通過靜態內部類的方式注入bean,並賦值到枚舉中
- @Component
- public static class ReportTypeServiceInjector {
- @Autowired
- private MessageSource messageSource;
- @PostConstruct
- public void postConstruct() {
- for (EnumSuccessOrError rt : EnumSet.allOf(EnumSuccessOrError.class))
- rt.setMessageSource(messageSource);
- }
- }
- /**
- * @return the statusCode
- */
- public int getStatusCode() {
- return statusCode;
- }
- /**
- * @return the statusMsg,根據語言環境返回國際化字符串
- */
- public String getStatusMsg() {
- return messageSource.getMessage(statusMsg,null,statusMsg, LocaleContextHolder.getLocale());
- }
此時我們在JsonController中,再創建一個測試接口
- @RequestMapping("/enumDemo")
- public String enumDemo() {
- return EnumSuccessOrError.SUCCESS.getStatusMsg();
- }
啟動項目直接,訪問 http://127.0.0.1:8080/enumDemo 可以看到相應語言環境的返回信息。
閱讀更多 java程序員工程師 的文章