国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Locale深度解析

taowen / 1891人閱讀

摘要:特別是開發(fā)一些只做國內(nèi)市場,只有中文的項(xiàng)目時(shí),可能就直接被忽視了。應(yīng)用場景的使用場景基本就是根據(jù)不同國家和語言,進(jìn)行不同的顯示。比如中解析時(shí),可以同時(shí)處理兩種格式。一組為,一組為。對于中文,英文,日文都有一個(gè)默認(rèn)的匹配。

摘要

Locale是日常開發(fā)中比較容易忽視的技術(shù)點(diǎn)。特別是開發(fā)一些只做國內(nèi)市場,只有中文的項(xiàng)目時(shí),Locale可能就直接被忽視了。而且在項(xiàng)目提出多語言支持的時(shí)候,因?yàn)闆]有很好的理解,可能給自己埋了很多坑。

什么是Locale

其實(shí)java.util.Locale的Java Doc有很詳細(xì)的解釋,我就不過多解釋。

A Locale object represents a specific geographical, political, or cultural region. An operation that requires a Locale to perform its task is called locale-sensitive and uses the Locale to tailor information for the user.

主要記住Locale實(shí)例包括以下信息就可以了。在多年的開發(fā)經(jīng)驗(yàn)中,script和variant基本沒有用到。就不過多介紹。

language

script

country (region)

variant

lanugage
ISO 639 alpha-2 or alpha-3 language code

在實(shí)際使用中,基本我們碰不到3位字母表示的語言。

country
ISO 3166 alpha-2 country code or UN M.49 numeric-3 area code.

同樣實(shí)際使用中,基本使用2位字母表示的國家

scirpt 和 variant

IANA Language Subtag Registry 定義了完整列表。
感覺script是地區(qū)的別稱,variant是方言。了解一下就好。

在實(shí)際使用中,大部分同學(xué)第一反應(yīng)可能是會(huì)寫出以下Locale。

zh_CN

en_US

ja_JP

如果你也是只想到這些,請打開你的瀏覽器->開發(fā)者工具->控制臺(tái)中輸入以下js

window.navigator.language

瀏覽器為中文,你又在國內(nèi)。輸出結(jié)果就是zh-CN
然后如果重新你設(shè)置瀏覽器語言,比如設(shè)置成英文。再執(zhí)行一下,輸出結(jié)果是en-CN
What?? en-CN?? 這是什么鬼? 首先通過這個(gè)Locale,我們可以知道country,是和你實(shí)際在哪個(gè)地區(qū)有關(guān)。
那該怎么處理? 后面詳細(xì)說怎么應(yīng)用。

應(yīng)用場景

Locale的使用場景基本就是根據(jù)不同國家和語言,進(jìn)行不同的顯示。實(shí)際經(jīng)驗(yàn)以下2點(diǎn)為主。

多語言 (下文會(huì)詳細(xì)說明)

金額顯示。

日期格式顯示。

以金額顯示為例,如果沒有類似開發(fā)經(jīng)驗(yàn)的話,你可以為會(huì)想,金額還有不同的格式。一般不都是 1,000,000.00。那你就錯(cuò)了。舉兩個(gè)例子。

日語。日本人金額是不帶小數(shù)點(diǎn)的。

法語。法語中千位分隔符為空格,小數(shù)點(diǎn)為逗號(hào)。比如 1 000 000,00

正確理解Locale,并正確使用可以寫出既規(guī)范,又簡練,質(zhì)量又高的代碼。而不是見招拆招,每個(gè)語言寫一個(gè)自己的實(shí)現(xiàn)。

創(chuàng)建Locale 實(shí)例的正確姿勢

使用正確的姿勢創(chuàng)建非常重要,這在后面Spring里應(yīng)用部分非常重要。

以下這段代碼是我見過最多的創(chuàng)建方式。

Locale locale = new Locale("zh_CN");

其中zh_CN可能是前端直接傳入,為了方便直接作為Locale構(gòu)造方法參數(shù)。其實(shí)這是一個(gè)錯(cuò)誤的用法。這樣的使用,創(chuàng)建出來的Locale.language就是zh_cn。

以下先列舉一下兩種正確姿勢。然后比較一下結(jié)果

Locale API

// 使用Locale構(gòu)造方法
// 如果前端傳入"zh_CN",此處需要自行解析并拆分
Locale locale = new Locale("zh", "CN");
// 使用Locale預(yù)置常量。請自行查看Locale源代碼。
Locale locale = Locale.SIMPLIFIED_CHINESE

Commons-Lang LocaleUtils.toLocale()

Locale locale = LocaleUtils.toLocale("zh_CN");

以上三種創(chuàng)建方式,可以創(chuàng)建出一樣的Locale object。
本人推薦使用Commons Lang3 LocaleUtils.toLocale()

下面我們的來對比一下錯(cuò)誤和正解方式創(chuàng)建的Locale有什么區(qū)別。

public class LocaleShowCase {
    public static void main(String[] args) {
        logLocale(new Locale("zh_CN"));
        logLocale(Locale.SIMPLIFIED_CHINESE);
    }

    private static void logLocale(Locale locale) {
        System.out.println("=================================");
        System.out.println(String.format("Locale.toString: %s", locale.toString()));
        System.out.println(String.format("Language: %s", locale.getLanguage()));
        System.out.println(String.format("Country: %s", locale.getCountry()));
        System.out.println(String.format("LanguageTag: %s", locale.toLanguageTag()));
        System.out.println("=================================");
    }
}

輸出結(jié)果

=================================
Locale.toString: zh_cn
Language: zh_cn
Country: 
LanguageTag: und
=================================
=================================
Locale.toString: zh_CN
Language: zh
Country: CN
LanguageTag: zh-CN
=================================

讓我們來分析一下結(jié)果

首先看一下數(shù)據(jù)。錯(cuò)誤的創(chuàng)建方式,其實(shí)是把zh_CN作為language。Country和LanguageTag為空

Language輸出時(shí)均為小寫

Country輸出時(shí)均為大寫

LanugageTag為Language和Country以"-"連接

Locale.toString則是Language和Country以"_"連接

zh_CN vs zh-CN

什么時(shí)候使用"_",什么時(shí)候使用"-",確實(shí)比較搞。
比如request.getLocale()中解析Locale時(shí),可以同時(shí)處理兩種格式。而Commons Lang3 LocaleUtils.toLocale()的入?yún)⒅恢С窒聞澗€格式。

不過我們可以定義這樣的規(guī)范,在后端服務(wù)中只使用"_"格式,而前端只使用"-"格式。

前端

前端框架太多,就只說一下最近在玩的umi+dva+react。

UMI Locale處理

umi開發(fā)的項(xiàng)目中使用umi-plugin-react/locale來處理Locale。

import { setLocale, getLocale } from "umi-plugin-react/locale";

setLocale(language, true);
getLocale();
多語言

資源文件使用"-"格式命名。

.
|-- en-US
|   |-- common.ts
|   `-- form.ts
|-- ja-JP
|   |-- common.ts
|   `-- form.ts
|-- zh-CN
|   |-- common.ts
|   `-- form.ts
|-- en-US.ts
|-- ja-JP.ts
`-- zh-CN.ts
顯示多語言
import { formatMessage } from "umi-plugin-react/locale";
formatMessage({id: "xxx"})
日期顯示
import { formatDate } from "umi-plugin-react/locale";
formatDate(new Date());
數(shù)字顯示
formatNumber(10000000.00);
后端服務(wù)

這里只介紹基于Spring Boot開發(fā)的Stateless Rest API。SpringMVC已經(jīng)過時(shí),就不做介紹。

Locale處理 如何確認(rèn)當(dāng)前API調(diào)用使用的Locale?

Spring Boot使用LocaleResolver來確定當(dāng)前API調(diào)用使用什么Locale。在LocaleResolver獲取Locale之后,將Locale存入LocaleContextHolder中。

Spring Boot提供了幾個(gè)標(biāo)準(zhǔn)實(shí)現(xiàn),主要區(qū)別是針對Locale存放的地方不一樣提供對應(yīng)獲取方式

AcceptHeaderLocaleResovler 從Request Header的Accept-Language中獲取

CookieLocaleResolver 從Cookie中獲取

FixedLocaleResolver 固定Locale,只使用系統(tǒng)配置的Locale

SessionLocaleResolver 從Session中獲取

雖然Spring已經(jīng)提供了多種獲取LocaleResolver實(shí)現(xiàn),但是在具體業(yè)務(wù)場景中會(huì)有更復(fù)雜的場景。比如需要根據(jù)當(dāng)前登錄用戶的語言設(shè)置。這個(gè)時(shí)間就需要我們自己實(shí)現(xiàn)一套LocaleResovler。

多語言 資源文件

在Spring中,我們可以添加properties文件來做多語言支持。

.
|-- java
....
`-- resources
    `-- i18n
        |-- messages.properties
        |-- messages_ja.properties
        |-- messages_ja_JP.properties
        |-- messages_xx.properties
        |-- messages_zh.properties
        |-- messages_zh_CN.properties
        |-- another.properties
        |-- another_zh_CN.properties
        |-- another_zh_TW.properties
        |-- another_en.properties
        `-- another_ja.properties

可以看到在例子

有兩組資源文件。一組為message,一組為anthor。在項(xiàng)目中可以這種方式進(jìn)行模塊化管理。

每組資源文件可以有自己支持的locale列表

每個(gè)文件定義對應(yīng)locale的翻譯

沒有l(wèi)ocale資源文件為默認(rèn)語言。如messages.properties, another.properties。當(dāng)沒有l(wèi)ocale匹配時(shí),使用默認(rèn)資源文件內(nèi)容。

messages_xx.properties? 這是合法的。但建議使用,也基本不會(huì)碰到。這里是說明一下,框架是支持的。用new Locale("xx")可以創(chuàng)建language為xx的Locale。

Locale匹配優(yōu)先級(jí)

language+country+variant > language+country > lanaguage

以message*.properties為例:

zh_CN -> messages_zh_CN.properties

zh或zh_JP -> messages_zh.properties

en_US -> messages.properties.

配置MessageSource
@Configuration
public class MessageConfiguration {
    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setDefaultEncoding("UTF-8");
        messageSource.setBasenames("classpath:i18n/messages", "classpath:i18n/another");
        return messageSource;
    }
}

這里注意messageSource.setBasenames("classpath:i18n/messages", "classpath:i18n/another")BaseName就是資源文件的組名。

使用方式
@Service
public class XXXService {
    private final MessageSource messageSource;
    public XXXService(MessageSource messageSource) {
        this.messageSource = messageSource;
    }
    public String getI18N(String key, Object[] params) {
        return messageSource.getMessage(key, params, LocaleContextHolder.getLocale())
    }
}
日期顯示
DateFormat fullDF = DateFormat.getDateInstance(DateFormat.FULL, locale);
System.out.println(fullDF.format(new Date()));
數(shù)字顯示
System.out.println(NumberFormat.getInstance(locale).format(10000000));
實(shí)際場景中的應(yīng)用

一般產(chǎn)品基本需要用戶登錄,在LocaleResovler中也提到。我們可以根據(jù)當(dāng)前用戶的語言設(shè)置作為使用Locale。這樣比較好控制服務(wù)接收到的Locale。而且我們在開發(fā)時(shí)可以定義好系統(tǒng)支持的語言,比如支持zh_CN, en_US, ja_JP。這樣在用戶登錄后的API調(diào)用就不用擔(dān)心接收到不支持的Locale。而因?yàn)樾枰褂糜脩粼O(shè)置語言,我們需要自己實(shí)現(xiàn)一個(gè)LocaleResovler。

@Data
public class Principal {
    private String username;
    private String language;
    ...
}
public class CustomLocaleResolver implements LocaleResolver {
    private Locale defaultLocale;

    public CustomLocaleResolver(Locale defaultLocale) {
        this.defaultLocale = defaultLocale;
    }

    public Locale resolveLocale(HttpServletRequest request) {
        Principal principal = (Principal) SecurityContextHolder.getContext().getAuthentication();
        if (principal != null && !StringUtils.isEmpty(principal.getLanguage())) {
            return LocaleUtils.toLocale(principal.getLanguage());
        } else {
            return request.getHeader("Accept-Language") != null ? request.getLocale() : this.defaultLocale;
        }
    }

    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
        throw new UnsupportedOperationException("Cannot change Principal data - use a different locale resolution strategy");
    }
}

@Configuration
public class LocaleConfiguration {
    @Bean
    public CustomLocaleResolver localeResolver(@Value("${default-language:zh_CN}") String defaultLanguage) {
        return new CustomLocaleResolver(LocaleUtils.toLocale(defaultLanguage));
    }
}

而用戶沒有登錄之前,而前端不做任何處理時(shí),后端會(huì)接收到類似en_CN的Locale,而無法匹配資源文件。如果按以下資源文件設(shè)計(jì),給每個(gè)語言設(shè)置一個(gè)默認(rèn)翻譯,則可以解決接收到不規(guī)則Locale問題。

.
|-- java
....
`-- resources
    `-- i18n
        |-- messages.properties
        |-- messages_ja.properties
        |-- messages_ja_JP.properties
        |-- messages_en.properties
        |-- messages_en_US.properties
        |-- messages_en_GB.properties
        |-- messages_zh.properties
        |-- messages_zh_CN.properties
        `-- messages_zh_TW.properties

這樣的編排方式,不管你在什么國家。對于中文,英文,日文都有一個(gè)默認(rèn)的匹配。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/75580.html

相關(guān)文章

  • Locale深度解析

    摘要:特別是開發(fā)一些只做國內(nèi)市場,只有中文的項(xiàng)目時(shí),可能就直接被忽視了。應(yīng)用場景的使用場景基本就是根據(jù)不同國家和語言,進(jìn)行不同的顯示。比如中解析時(shí),可以同時(shí)處理兩種格式。一組為,一組為。對于中文,英文,日文都有一個(gè)默認(rèn)的匹配。 摘要 Locale是日常開發(fā)中比較容易忽視的技術(shù)點(diǎn)。特別是開發(fā)一些只做國內(nèi)市場,只有中文的項(xiàng)目時(shí),Locale可能就直接被忽視了。而且在項(xiàng)目提出多語言支持的時(shí)候,因?yàn)?..

    spacewander 評(píng)論0 收藏0
  • SpringMVC之源碼分析--LocaleResolver(一)

    摘要:概述為我們提供國際化支持,通過設(shè)置系統(tǒng)的環(huán)境,根據(jù)運(yùn)行環(huán)境使用不同的語言顯示。提供接口的作用是解析客戶端使用的地區(qū),目的是為了根據(jù)這些信息實(shí)現(xiàn)視圖多語言即國際化。接口繼承接口,增加時(shí)區(qū)支持。 概述 Spring MVC為我們提供國際化支持,通過設(shè)置系統(tǒng)的環(huán)境,根據(jù)運(yùn)行環(huán)境使用不同的語言顯示。Spring提供LocaleResolver接口的作用是解析客戶端使用的地區(qū)(Locale),目...

    HtmlCssJs 評(píng)論0 收藏0
  • SpringMVC之源碼分析--ViewResolver(六)

    摘要:與一樣,該類繼承抽象類,并且通過外部的屬性文件定義邏輯視圖名稱與真正的視圖對象的關(guān)系,屬性文件默認(rèn)是下的,可以通過或?qū)傩詠碇付ǎ搶傩灾傅氖俏募幕Q,也就是說以屬性值開頭的屬性文件。 概述 本章再學(xué)習(xí)另外兩個(gè)ViewResolver,分別是XmlViewResolver和ResourceBundleViewResolver,從功能上說,這兩個(gè)視圖解析器都是從外部資源文件中查找視圖V...

    alighters 評(píng)論0 收藏0
  • SpringMVC之源碼分析--LocaleResolver(二)

    摘要:概述上一篇就默認(rèn)的進(jìn)行了分析,詳細(xì)請參考,本節(jié)我們繼續(xù)分析學(xué)習(xí),主要分析解析器類繼承關(guān)系如下圖由上面類圖可知,繼承并實(shí)現(xiàn)接口,主要是操作的工具類,繼承接口,增加了信息操作。即通過實(shí)現(xiàn)的選擇。 概述 上一篇就Spring MVC默認(rèn)的LocaleResovler(AcceptHeaderLocaleResolver)進(jìn)行了分析,詳細(xì)請參考https://segmentfault.com/...

    RichardXG 評(píng)論0 收藏0
  • SpringMVC之源碼分析--ViewResolver(五)

    摘要:此解析器與差不多,更改下配置文件中的類全路徑即可。總結(jié)本章介紹了以及三個(gè)視圖解析器。這部分內(nèi)容有點(diǎn)兒多,我會(huì)盡快結(jié)束。 概述 通過上幾篇的學(xué)習(xí),我們分析了并試驗(yàn)了ViewResolverComposite、BeanNameViewResolver和ContentNegotiatingViewResolver,這三個(gè)類都直接實(shí)現(xiàn)ViewResolver接口。Spring MVC提供了很多...

    klinson 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<