09、国际化

  • Java 编程语言是第一种设计成为全面支持国际化的语言。
    • Java 从一开始就具备了进行有效的国际化所必需的一个重要特性
      • 使用 Unicode 来处理所有字符串
  • 由于支持 Unicode,在 Java 编程语言中编写程序来操作多种语言字符串变得异常方便
  • 国际化一个程序所要做的事情绝不仅仅是提供 Unicode 支持。
    • 在世界的不同地方,日期、时间、货币甚至数字的格式都不相同。
    • 你需要用一种简单的方法来为不同的语言配置菜单按钮名字消息字符串快捷键

一、locale


1、为什么需要 local


  • 当你提供程序的国际化版本时,所有程序消息都需要转换为本地语言
    • 当然,直接翻译用户界面的文本是不够的,还有许多更细微的差异

细微差异:

  • 1、数字格式差异:小数点十进制数的逗号分隔符的角色是相反的
    • 德国:123.456,78
    • 英国:123,456.78
  • 2、日期格式差异:在日期的显示上也有相似的变化
    • 美国:月/日/年。
    • 德国:日/月/年。
    • 中国:年/月/日。

  • locale 捕获了像上面这类偏好特征。
    • 无论何时,只要表示数字、日期、货币值以及其它格式会随 语言地点 发生变化的项。
    • 都需要使用 locale 感知的 API

2、指定 locale


  • 在 Java 中,Locale 是用于表示特定地理、政治、文化区域的类,其核心组成部分包括以下内容:

  • 可以用 Locale.getlSOLanguages() 获取所有语言代码
  • 可以用 Locale.getlSOCountries() 获取所有 国家地区 代码

1. 语言(Language)-- 基于 ISO 639 标准语言 代码

  • 格式:2 或 3 个小写字母。
  • 示例
    • en(英语)、zh(中文)、ja(日语)
  • 作用标识资源文件的基础语言。

2. 国家/地区(Country/Region)-- 基于 ISO 3166 标准国家地区 代码

  • 格式:2 个大写字母 或 3 个数字表示。
  • 示例
    • CN(中国)、US(美国)、DE(德国)、CH(瑞士)
  • 作用:区分同一语言的不同地区变体(如 en-USen-GB)。

3. 变体(Variant) – 自定义的附加标识符,用于进一步细分区域

  • 格式:自由定义的字符串(通常大写字母或数字组合)。
  • 示例
    • POSIX(表示 POSIX 兼容格式)、NY(纽约方言)、
    • 1996(表示遵循 1996 年拼写改革)
  • 作用:处理特殊场景(如:技术规范、方言、拼写规则)。
  • 已经很少使用了

4. 脚本(Script)-- 基于 ISO 15924 标准文字系统 代码

  • 格式:4 个字母(首字母大写,其余小写)。
  • 示例
    • Hans(简体中文)、Hant(繁体中文)、Latn(拉丁字母)
  • 作用:区分同一语言的不同书写系统(如:中文简繁体)。

5. 扩展(Extensions)-- 基于 BCP 47 标准 的附加键值对,用于表示区域的技术扩展

  • 格式
    • Unicode 扩展:以 u- 开头(如日历、货币格式)。
    • 私有扩展:以 x- 开头(自定义用途)。
  • 示例
    • u-ca-buddhist(使用佛历)
    • x-lvariant-jp(自定义日本区域变体)
  • 作用:处理复杂的区域需求(如:特殊日历、数字、货币规则)。

public class LocaleExample {
    public static void main(String[] args) {
        // 1、使用 Builder 模式创建包含所有部分的 Locale
        Locale locale = new Locale.Builder()
                // 语言(中文)
                .setLanguage("zh")
                // 国家(中国)
                .setRegion("CN")
                // 变体(POSIX 兼容)
                .setVariant("POSIX")
                // 脚本(简体中文)
                .setScript("Hans")
                // Unicode 扩展(佛历)
                .setExtension('u', "ca-buddhist")
                .build();

        // 输出 Locale 详细信息
            // Locale 完整标识: zh-Hans-CN-POSIX-u-ca-buddhist
        System.out.println("Locale 完整标识: " + locale.toLanguageTag());

        // 解析各组成部分
            // 语言: zh
        System.out.println("语言: " + locale.getLanguage());
            // 国家: CN
        System.out.println("国家: " + locale.getCountry());
            // 变体: POSIX
        System.out.println("变体: " + locale.getVariant());
            // 脚本: Hans
        System.out.println("脚本: " + locale.getScript());
            // 扩展: ca-buddhist
        System.out.println("扩展: " + locale.getExtension('u'));
    }
}

3、默认 locale


  • Locale.Category 包含以下两个枚举常量,分别对应不同的 本地化场景
枚举常量说明
DISPLAY控制用户界面(UI)本地化显示。(如:菜单、按钮、标签等)
依赖的资源文件(如:messages_xx.properties)。
FORMAT控制数据格式化本地化行为。(如:日期、时间、数字、货币格式化方式)。
  • Locale 类的静态 getDefault 方法可以获得作为本地操作系统一部分存储的默认 locale。
  • 可以调用 setDefault改变默认的 Java locale。
    • 这种改变只对你的程序有效, 不会对操作系统产生影响。
public static void main(String[] args) {
    // 1、获取操作系统默认语言环境
    Locale defaultLocale = Locale.getDefault();
        // zh_CN_#Hans
        /*
            zh:语言(中文)
            CN:国家(中国)
            Hans:脚本(简体中文)
         */
    System.out.println(defaultLocale);

        // zh_CN
    System.out.println(Locale.CHINA);
        // zh
    System.out.println(Locale.CHINESE);

    // 2、设置默认 Locale 为中文(中国)
    Locale.setDefault(Locale.CHINA);
    defaultLocale = Locale.getDefault();
        // zh_CN
    System.out.println(defaultLocale);
    
    // 3、设置默认 Locale 为中文
    Locale.setDefault(Locale.CHINESE);
    defaultLocale = Locale.getDefault();
        // zh
    System.out.println(defaultLocale);
}

  • 有些操作系统允许用户为显示消息格式化指定不同的 locale。
    • 如:生活在美国的说法语的人菜单法语的,但是货币值是用美元来表示的。
    • 即:界面显示为法语,但数据格式(日期、数字)使用美国标准。
public static void main(String[] args) {
    // 1、设置 DISPLAY 类别为法语(界面显示)
    Locale.setDefault(Locale.Category.DISPLAY, Locale.FRANCE);
    // 2、设置 FORMAT 类别为美国英语(数据格式化)
    Locale.setDefault(Locale.Category.FORMAT, Locale.US);

    // 3、获取 Locale.Category.DISPLAY 类别的 Locale
    displayLocale = Locale.getDefault(Locale.Category.DISPLAY);
        // fr_FR
    System.out.println(displayLocale);
    // 4、获取 Locale.Category.FORMAT 类别的 Locale
    forwatLocale = Locale.getDefault(Locale.Category.FORMAT);
        // en_US
    System.out.println(forwatLocale);

    // 5、加载国际化资源文件<baseName> 包(使用 Locale.Category.DISPLAY 类别的 Locale)
    ResourceBundle bundle = ResourceBundle.getBundle("messages");
        // 输出: Bonjour!
    System.out.println("本地化问候语: " + bundle.getString("greeting"));

    // 6、格式化日期(使用 Locale.Category.FORMAT 类别的 Locale)
    DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.FULL);
    String formattedDate = dateFormat.format(new Date());
        // 格式化日期: Thursday, May 22, 2025
    System.out.println("格式化日期: " + formattedDate);

    // 7、格式化数字(使用 Locale.Category.FORMAT 类别的 Locale)
    NumberFormat numberFormat = NumberFormat.getNumberInstance();
    String formattedNumber = numberFormat.format(1234.56);
        // 格式化数字: 1,234.56
    System.out.println("格式化数字: " + formattedNumber);
}
  • 获取系统默认的偏好设置,可以调用。
public static void main(String[] args) {
    Locale displayLocale = Locale.getDefault(Locale.Category.DISPLAY);
    // zh_CN_#Hans
    System.out.println(displayLocale);
    Locale forwatLocale = Locale.getDefault(Locale.Category.FORMAT);
    // zh_CN_#Hans
    System.out.println(forwatLocale);
}

4、Locale 的应用


  • 获取所有可用的 Locale 。
public static void main(String[] args) {
    // 1、获取 Java 语言支持的所有的 Locale
    Locale[] locales = Locale.getAvailableLocales();
    for (Locale locale: locales) {
        System.out.println(String.format("%10s\t\t%10s\t%10s", locale.getDisplayCountry(),locale.getLanguage(),locale.getCountry()));
    }
}

  • 创建 Locale 对象
// 1. 仅语言(如:中文)
Locale localeZh = new Locale("zh");
    // zh
System.out.println(localeZh);


// 2. 语言 + 国家(如:中文-中国)
Locale localeZhCn = new Locale("zh", "CN");
    // zh_CN
System.out.println(localeZhCn);


// 3. 语言+国家+变体(如:中文-中国-电话号码格式)
Locale localeZhCnPhone = new Locale("zh", "CN", "phonebook");
    // zh_CN_phonebook
System.out.println(localeZhCnPhone);


// 4、获取操作系统默认语言环境
Locale defaultLocale = Locale.getDefault();
    // zh_CN_#Hans
    /*
        zh:语言(中文)
        CN:国家(中国)
        Hans:脚本(简体中文)
     */
System.out.println(defaultLocale);


// 5、使用 Builder 模式创建包含所有部分的 Locale
Locale locale = new Locale.Builder()
        // 语言(中文)
        .setLanguage("zh")
        // 国家(中国)
        .setRegion("CN")
        // 变体(POSIX 兼容)
        .setVariant("POSIX")
        // 脚本(简体中文)
        .setScript("Hans")
        // Unicode 扩展(佛历)
        .setExtension('u', "ca-buddhist")
        .build();

// 输出 Locale 详细信息
    // Locale 完整标识: zh-Hans-CN-POSIX-u-ca-buddhist
System.out.println("Locale 完整标识: " + locale.toLanguageTag());

应用场景

public static void main(String[] args) {
    // 使用佛历(Unicode 扩展)
        // 创建支持佛历的 Locale(泰国)
    Locale thaiLocale = new Locale.Builder()
            .setLanguage("th")
            .setRegion("TH")
                // Unicode 扩展指定佛历
            .setExtension('u', "ca-buddhist")
            .build();
        //  获取当前日期(佛历)
    ThaiBuddhistDate buddhistDate = ThaiBuddhistDate.now();
        // 创建格式化器并应用佛历
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
            .withLocale(thaiLocale)
            .withChronology(buddhistDate.getChronology());
    String date = formatter.format(LocalDate.now());
    // 2568-05-21
    System.out.println(date);
}

二、国际化


1、什么是国际化 – 本质就是:“查找,替换”


  • 资源文件:负责为程序提供国际化消息。
    • 资源文件的文件名必须满足 _语言代码_国家代码.properties
    • 如果资源文件中包含非西欧字符,需要使用 native2ascii 工具类处理这个文件。
    • native2ascii 要处理的文件生成的新文件名

2、国际化用到的类


  • Locale 类:代表语言、国家环境。
  • ResourceBundle:负责加载国际化资源文件,而且帮我们查找替换
  • MessageFormat:负责为消息中的占位符填充参数。
    • format(String patern, Object… arguments)
    • 该方法中 auguments 参数就负责一次替换每个占位符

3、国际化的步骤:


  • 1、提供资源文件
    • 负责为程序提供国际化消息
  • 2、使用 ResourceBundle 加载 国际化资源文件
    • getBundle(baseName, 语言代码_国家代码); 来搜索资源文件的顺序;
      • baseName_语言代码_国家代码.properties
      • baseName_语言代码.properties
      • baseName.properties
  • 调用 ResourceBundle 的 getMessage() 方法输出国际化消息。
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;

public class I18NHello {
	public static void main(String[] args) {
		// 1、获取 Java 语言支持的所有的 Locale
		Locale[] locales = Locale.getAvailableLocales();
		for (Locale locale: locales) {
			System.out.println(String.format("%10s\t\t%10s\t%10s", locale.getDisplayCountry(),locale.getLanguage(),locale.getCountry()));
		}

		// 2、获取当前计算机的语言、环境。
			// 假如操作系统是简体中文环境,currentLocale就相当于返回了zh_CN
		Locale currentLocale = Locale.getDefault();
		System.out.println(currentLocale);
			// 加载国际化资源文件 <baseName>_语言_国家.properties 文件
			// 如:zxw_zh_CN.properties
		//ResourceBundle bundle = ResourceBundle.getBundle("zxw",currentLocale);
		ResourceBundle bundle = ResourceBundle.getBundle("zxw_zh_CN");
			// 从 bundle 所加载的文件查找 hi 对应字符串进行替换。
		System.out.println(bundle.getString("hello"));

			// 李四,欢迎来到国际化!
		System.out.println(MessageFormat.format(bundle.getString("welcome"),"张三","李四","王二"));
	}
}
hello=欢迎您,国际化真简单\!
# {1} 表示:会使用传入的第二个参数,即 李四。
welcome={1},欢迎来到国际化!
hello=Hello World!
# {0} 表示:会使用传入的第一个参数,即 张三。
welcome={0},welcome to I18N.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值