【SpringBoot學習(四) 使用 thymeleaf實現國際化功能】

Moluuu發表於2020-12-11

國際化

國際化(internationalization),是設計和製造 適應不同區域要求的產品的一種方式。

它要求從產品中抽離所有地域語言,國家/地區和文化相關的元素。

換言之,應用程式的功能和程式碼設計考慮在不同地區執行的需要,其程式碼簡化了不同本地版本的生產。

開發這樣的程式的過程,就稱為國際化。

國際化又叫 i18n,為什麼叫這個呢 因為英文太長了......

國際化支援應該是所有的做國際化網站都需要考慮的一個問題,Spring Boot為國際化提供了強有力的支援。

SpringBoot國際化

SpringBoot 天然支援國際化,我們可以嘗試在 resources資原始檔目錄下新建 i18n資料夾。

在該資料夾下建立兩個不同的 properties檔案。(也可以直接建立Resource Bundel資料夾)

第二個檔名中如果存在"_語言_國家" 英文縮寫字尾 ,則兩個檔案 會被合併至 Resource Bundel ‘檔名相同部分’ 資料夾下。

未新增 "_語言_國家"字尾的檔案,會被視為預設語言。

這麼說可能有點難以理解,可以看看下面這個 gif圖 來理解這段話。

我們右擊 該自動生成的資料夾,可以很方便的生成其他 _語言_國家英文字尾的 properties檔案

如下 gif:

建立好對應的 properties檔案後,我們雙擊 Resource Bundel 'xxxxxx’資料夾。

新建一個 property

建立property後,右邊會讓我們分別輸入 預設版本的 login.tip value值、中文版本的value值、英文版…

輸入後檢視對應的 properties檔案

會發現 key和 value都已經分別寫入了

properties檔案搞定後,我們還需要在 SpringBoot配置檔案中繫結這些 properties檔案。

# 關閉 thymeleaf的快取
spring:
  thymeleaf:
    cache: false
# 繫結國際化相關的 properties檔案
  messages:
    basename: i18n.login

使用 spring.message.basename=資料夾.properties檔案相同部分的方式繫結。上述程式碼為 yaml格式

繫結好了我們還需要在 HTML檔案中,將原本的登入提示元素進行修改,需要用到 thymeleaf。

在 thymeleaf中,國際化的訊息表示式為 #{property}

<!--
	這裡 h1標籤中的文字內容 為 Please sign in,
	如果繫結沒出問題的話 登入頁面的 h1標籤文字內容應該會替換為 login.tip預設value "請登入"
-->
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>

我們啟動 SpringBoot專案驗證一下繫結是否正常。

確實替換成了 login.tip預設的 value "請登入",也就是說繫結沒有問題。

沒有問題的話,我們可以再多寫幾個 property,並分別在對應元素標籤內書寫 thymeleaf表示式。

效果如下:

當然,這並不能達到我們想要的效果,我們還需要寫一個按鈕,讓其可以中英文自由切換。

只有中文或只有英文,並不滿足國際化的要求。

LocaleResolver介面

實現該功能我們需要寫一個 實現了 " Spring地區解析器 "(LocaleResolver)介面的類

實現該介面需要重寫兩個方法

public class MyLocaleResolver implements LocaleResolver {
    @Override
    // 獲取當前地區
    public Locale resolveLocale(HttpServletRequest request) {
        return null;
    }
	// 修改地區
    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }
}

AcceptHeaderLocaleResolver實現類

resolveLocale有四個實現類,我們看其中最簡單的一個,也就是 AcceptHeaderLocaleResolver

@Override
public Locale resolveLocale(HttpServletRequest request) {
    // 獲取預設設定,可在配置 AcceptHeaderLocaleResolver Bean中配置 defaultLocale屬性 
    Locale defaultLocale = getDefaultLocale();
    // 如果通過請求獲取的 Accept-Language頭資訊為空,且配置了預設地區 則使用預設的地區
    if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
        return defaultLocale;
    }
    // 通過請求資訊獲得使用者當前的地區
    Locale requestLocale = request.getLocale();
    // 從配置中獲取支援的地區集合,可在 AcceptHeaderLocaleResolver Bean中配置 supportedLocales屬性
    List<Locale> supportedLocales = getSupportedLocales();
    // 未設定supportedLocales或者supportedLocales中包括請求Locale,則使用請求Locale
    if (supportedLocales.isEmpty() || supportedLocales.contains(requestLocale)) {
        return requestLocale;
    }
    // 確認配置的地區集合中是否有請求的地區
    Locale supportedLocale = findSupportedLocale(request, supportedLocales);
    if (supportedLocale != null) {
        return supportedLocale;
    }
    return (defaultLocale != null ? defaultLocale : requestLocale);
}
}
// 該實現不支援 設定地區
public void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale) {
    throw new UnsupportedOperationException(
            "Cannot change HTTP accept header - use a different locale resolution strategy");
}

重寫 resolveLocale();方法

大概知道其邏輯後,我們重寫 resolveLocale();方法。

重寫該方法之前,我們先編寫攜帶地區引數的 a標籤

我們使用 th:href,實現了一次請求 請求的路徑為當前路徑 攜帶的引數為地區引數。

<button type="button" style="margin: 10px">
    <a th:href="@{/(l='en_US')}" id="a1">English</a>
    <a th:href="@{/(l='zh_CN')}" id="a2">中文</a>
</button>

重寫 resolveLocale();方法。

public class MyLocaleResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        // 獲取 請求(a標籤)中攜帶的地區引數。
        String language = request.getParameter("l");
        // 獲取預設的地區引數
        Locale locale = Locale.getDefault();
        // 如果不為空地區引數為獲取的地區引數
        if (!StringUtils.isEmpty(language)){
            String[] split = language.split("_");
            locale = new Locale(split[0],split[1]);
        }
        return locale;
    }
    // 這個不寫
    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
    }
}

寫完該方法,我們還需要將該類注入到 Spring中

@Configuration
// 擴充套件 MVC
public class MyMvcConfig implements WebMvcConfigurer {

    @Override
    // 檢視跳轉
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
    }

    // 將自定義的國際化元件注入到 Spring
    @Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }
}

測試:

沒有問題,實現了我們想要的效果

本來呢,是準備寫一個 a標籤的 實現那種點一下從 "English" 切換為"中文的效果"。

這個倒是知道怎麼寫,問題出在了不知道怎麼用 JavaScript來操作 th:href 中攜帶的引數,查了一晚上也沒有查到有幫助的部落格文章.....

沒辦法了,只能寫出這種比較 low的效果。如果有朋友知道如何使用 JavaScript操作 thymeleaf的話還望指點一二。


放鬆一下眼睛

原圖P站地址

畫師主頁


相關文章