当前位置: 首页 > 后端技术 > Java

说说Java的国际化

时间:2023-04-02 01:31:28 Java

每个面向国际的语言都需要有自己的国际化解决方案。Java从一开始就使用Unicode来处理所有的字符串,这使得Java国际化的一个重要特征。除了提供Unicode之外,Java还需要处理不同语言环境的表示。Localejava.util包提供了Locale类来处理不同语言和地区的国际化问题。使用Locale类自定义一个区域的信息,Locale类提供了以下构造方法来构造Locale对象。publicfinalclassLocaleimplementsCloneable,Serializable{//根据语言、国家和变体构建语言环境publicLocale(Stringlanguage,Stringcountry,Stringvariant){···}//根据语言和国家构建语言环境publicLocale(Stringlanguage,Stringcountry){···}//根据语言代码构造localepublicLocale(Stringlanguage){···}}根据构造方法,构造Locale可以设置语言、国家或地区、变量body.语言用2或3个小写字母表示,如zh、en或de。可以在此处查看ISO-639-1语言代码标识符。Locale中预定义了大量的Locale语言。他们只设置语言而不设置国家,如下所示。//英语publicstaticfinalLocaleENGLISH=createConstant("en","");//法语publicstaticfinalLocaleFRENCH=createConstant("fr","");//德语publicstaticfinalLocaleGERMAN=createConstant("de","");//意大利语publicstaticfinalLocaleITALIAN=createConstant("it","");//日语publicstaticfinalLocaleJAPANESE=createConstant("ja","");//韩语publicstaticfinalLocaleKOREAN=createConstant("ko","");//中文publicstaticfinalLocaleCHINESE=createConstant("zh","");//简体中文publicstaticfinalLocaleSIMPLIFIED_CHINESE=createConstant("zh","CN");//繁体中文publicstaticfinalLocaleTRADITIONAL_CHINESE=createConstant("zh","TW");国家和地区也用2个字母或3个数字表示,如CN、US或DE。可在此处查看ISO-3166-1中的国家或地区名称。Locale中还为每个国家/地区预定义了Locale对象,如下所示。//法国publicstaticfinalLocaleFRANCE=createConstant("fr","FR");//德国publicstaticfinalLocaleGERMANY=createConstant("de","DE");//意大利publicstaticfinalLocaleITALY=createConstant("it","IT");//日本publicstaticfinalLocaleJAPAN=createConstant("ja","JP");//韩国publicstaticfinalLocaleKOREA=createConstant("ko","KR");//中国publicstaticfinalLocaleCHINA=SIMPLIFIED_CHINESE;//中华民国publicstaticfinalLocalePRC=SIMPLIFIED_CHINESE;//台湾publicstaticfinalLocaleTAIWAN=TRADITIONAL_CHINESE;//英国publicstaticfinalLocaleUK=createConstant("en","GB");//美国publicstaticfinalLocaleUS=createConstant("en","US");//加拿大publicstaticfinalLocaleCANADA=createConstant("en","CA");//加拿大法语publicstaticfinalLocaleCANADA_FRENCH=createConstant("fr","CA");//表示根区域设置的常量publicstaticfinalLocaleROOT=createConstant("","");variant,用于指定各种杂项特征,如果有多个变量值,每个变量值表示自己的语义,值应按重要性排序,并用下划线分隔。变体字段区分大小写。Locale除了可以构造Locale对象的构造方法外,JavaSE7还提供了forLanguageTag静态方法构造Locale对象,如下:LocalezhChinese=Locale.forLanguageTag("zh-CN");LocaletwChinese=Locale.forLanguageTag("zh-TW");System.out.println(zhChinese.getDisplayName());System.out.println(twChinese.getDisplayName());//Chinese(中国)//Chinese(台湾)Locale方法setDefault即可更改默认区域,并使用getDefault方法获取当前Locale对象,如下:getDefault());//en-USLocaleen-USLocale中提供的静态方法getAvailableLocale会返回一个由JVM识别的所有Locale组成的数组。ResourceBundle使用Locale设置好具体的语言和地区后,就可以使用ResourceBundle根据不同的Locale来加载资源了。资源需要放在resources资源包中,根据不同的Locales设置相应的资源文件。如下图,通过ResourceBundle类提供的getBundle静态方法,根据locale自动绑定对应的资源文件。Localelocale=Locale.CHINA;ResourceBundlebundle=ResourceBundle.getBundle("i18n",locale);要查找特定的字符串,可以调用Stringlanguage=bundle.getString("language");这里资源文件的名称是统一的命名规则,然后根据不同的区域,来标识其本地信息的附加部分。例如资源包名称为i18n,则对应中英文环境的资源如下图所示。这里可以把默认资源放在一个没有后缀的i18n文件中,然后getBundle方法定位到i18n_zh_CN时,会继续搜索i18n_zh和默认文件i18n这两个文件。如果这些文件存在,它们将成为资源层次父文件中的i18n_zh_CN。以后在查找资源的时候,如果在当前资源文件中没有找到,就会去查找它的父资源文件。在后缀为.properties的文件中,属性以=-分隔的键值对形式存在,如下所示:language=Chinesecolor=redResourceBundle是一个抽象类,如下所示。publicabstractclassResourceBundle{...}继承ResourceBundle的类有一个具体的实现类PropertyResourceBundle和一个抽象类ListResourceBundle。而PropertyResourceBundle是一个具体的子类,用于支持ResourceBundle读取properties资源文件,但不需要直接使用PropertyResourceBundle,ResourceBundle.getBundle会自动找到对应的property文件,并创建引用它的PropertyResourceBundle。但是properties资源文件提供的值只能是字符串。如果要提供其他资源,则需要继承ListResourceBundle抽象类,将所有资源放入一个对象数组中,并提供搜索功能,如下所示。publicclassI18NextendsListResourceBundle{@OverrideprotectedObject[][]getContents(){returnnewObject[][]{{"color","yellow"}};}}publicclassI18N_zhextendsListResourceBundle{@OverrideprotectedObject[][]getContents(){returnnewObject[][]{{"language",newString[]{"简体中文","繁体中文"}}};}}publicclassI18N_zh_CNextendsListResourceBundle{@OverrideprotectedObject[][]getContents(){returnnewObject[][]{{"language","简体中文"},{"color",newString[]{"红色","黄色","黑色"}}};}}这里的类命名规则也是使用标准的命名规则来命名的。然后使用getBundle方法加载对应的类:ResourceBundlebundle=ResourceBundle.getBundle("I18N",Locale.forLanguageTag("zh-CN"));System.out.println(bundle.getString("language"));System.out.println(Arrays.toString(bundle.getStringArray("color")));另外,资源包类也可以继承ResourceBundle类进行扩展,但是需要实现两个方法,一是枚举所有的键,二是使用给定的键找到对应的值:EnumerationgetKeys();对象句柄GetObject(Stringkey);ResourceBundle类的getObject方法将调用您提供的handleGetObject方法。NumberFormatjava.text包中的NumberFormat可以根据不同的Locales对值进行格式化和解析。使用getNumberInstance静态方法获取一个格式化解析数字的实例,然后对对应的数字进行格式化,看看对应的Locale实例的格式化有何不同。NumberFormatnumberFormat=NumberFormat.getNumberInstance(Locale.SIMPLIFIED_CHINESE);Stringresult=numberFormat.format(2021.0731);System.out.println(result);结果是2,021.073,换成美国和德国的结果分别是2,021.073和2.021,073。当数值为货币时,使用getCurrencyInstance静态方法,如下所示。NumberFormatcurrencyFormat=NumberFormat.getCurrencyInstance(Locale.SIMPLIFIED_CHINESE);Stringresult=currencyFormat.format(2021.0731);System.out.println(result);结果是¥2,021.07,换成美国和德国的结果分别是$2,021.07和2.021,07。在处理货币时,可以使用货币类来控制货币。可以通过Currency.getInstance静态方法传入一个货币ID,返回一个Currency对象,然后调用NumberFormat中的setCurrency方法。下面的例子是为德国用户设置人民币格式,如下图。NumberFormatcurrencyFormat=NumberFormat.getCurrencyInstance(Locale.SIMPLIFIED_CHINESE);currencyFormat.setCurrency(Currency.getInstance("CNY"));Stringresult=currencyFormat.format(2021.0731);System.out.println(result);//2.021,07CN¥货币标识符由ISO-4217定义。下面简单介绍几种货币标识符。货币价值标识货币价值标识U.S.DollarUSDChineseRenminbi(Yuan)CNYEuroEURIndianRupeeINRBritishPoundGBPRussianRubleRUBJapaneseYenJPYDateTimeFormatter各个国家和地区的日期和时间显示可能不一样。JavaSE8提供了java.time.DateTimeFormatter类来处理与Locale相关的日期和时间,格式化和解析以匹配本地日期和时间的表示。在DateTimeFormatter中使用withLocale来设置不同的Locale,如下所示。DateTimeFormatterdateFormatter=DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withLocale(Locale.SIMPLIFIED_CHINESE);之后,您可以格式化LocaleDate、LocaleDateTime、LocaleTime和ZonedDateTime。ZonedDateTimeappointment=ZonedDateTime.now();Stringformatted=formatter.format(appointment);输出结果为Saturday,July31,2021,被美国和德国替换的结果为Saturday,July31,2021andSamstag,31.Juli2021。输出一个地区的第一天时,可以通过设置语言环境,如下图。DayOfWeekfirst=WeekFields.of(locale).getFirstDayOfWeek();MessageFormat消息中的可变数据也会根据不同的Locales而变化。Java提供java.text.MessageFormat来格式化消息。以下段落:Stringmsg=“在{2},{0}摧毁了{1}所房屋并造成了{3}的损坏。”括号中的数字是占位符,实际值可以通过MessageFormat.format静态方法来替换占位符。这是一个可变参数方法,因此可以通过以下方式提供参数:Stringresult=MessageFormat.format(msg,"ahurricane",99,newGregorianCalendar(1999,0,1).getTime(),10.0E8);输出结果是:99年1月1日凌晨12:00,一场飓风摧毁了99所房屋并造成100,000,000的损失。上面的示例还可以为占位符提供可选的格式设置,使打印的内容更加细化。在{2,date,long},{0}摧毁了{1}所房屋并造成了{3,number,currency}的损失。输出为:1999年1月1日,一场飓风摧毁了99间房屋,造成1亿的损失。通常,占位符索引后可以跟有类型和样式,以逗号分隔。MessageFormat.format静态方法使用当前语言环境格式化值。要使用任意语言环境进行格式化,请为类提供可以使用的可变参数方法。您需要将要格式化的值放在一个Object[]数组中,如下所示。MessageFormatmf=newMessageFormat(pattern,locale);Stringmsg=mf.format(newObject[]{values});更多资讯请关注公众号「海人为记」