Java 中文官方教程 2022 版(二十八)(4)

简介: Java 中文官方教程 2022 版(二十八)

Java 中文官方教程 2022 版(二十八)(3)https://developer.aliyun.com/article/1486870

在国际化之前

原文:docs.oracle.com/javase/tutorial/i18n/intro/before.html

假设你已经编写了一个显示三条消息的程序,如下所示:

public class NotI18N {
    static public void main(String[] args) {
        System.out.println("Hello.");
        System.out.println("How are you?");
        System.out.println("Goodbye.");
    }
}

你已经决定这个程序需要为居住在法国和德国的人显示相同的消息。不幸的是,你的编程人员不懂多种语言,所以你需要帮助将这些消息翻译成法语和德语。由于翻译人员不是程序员,你需要将消息从源代码中移出,放入文本文件供翻译人员编辑。此外,程序必须足够灵活,以便能够显示其他语言的消息,但目前没有人知道那些语言会是什么。

看起来这个程序需要国际化。

国际化后

原文:docs.oracle.com/javase/tutorial/i18n/intro/after.html

国际化程序的源代码如下。请注意,消息的文本未包含在软件代码中。

import java.util.*;
public class I18NSample {
    static public void main(String[] args) {
        String language;
        String country;
        if (args.length != 2) {
            language = new String("en");
            country = new String("US");
        } else {
            language = new String(args[0]);
            country = new String(args[1]);
        }
        Locale currentLocale;
        ResourceBundle messages;
        currentLocale = new Locale(language, country);
        messages = ResourceBundle.getBundle("MessagesBundle", currentLocale);
        System.out.println(messages.getString("greetings"));
        System.out.println(messages.getString("inquiry"));
        System.out.println(messages.getString("farewell"));
    }
}

要编译和运行此程序,您需要这些源文件:

  • I18NSample.java
  • MessagesBundle.properties
  • MessagesBundle_de_DE.properties
  • MessagesBundle_en_US.properties
  • MessagesBundle_fr_FR.properties

运行示例程序

原文:docs.oracle.com/javase/tutorial/i18n/intro/run.html

国际化程序是灵活的;它允许最终用户在命令行上指定语言和国家。在下面的示例中,语言代码是fr(法语),国家代码是FR(法国),因此程序会以法语显示消息:

% java I18NSample fr FR
Bonjour.
Comment allez-vous?
Au revoir.

在下一个示例中,语言代码是en(英语),国家代码是US(美国),因此程序会以英语显示消息:

% java I18NSample en US
Hello.
How are you?
Goodbye.

国际化示例程序

原文:docs.oracle.com/javase/tutorial/i18n/intro/steps.html

如果你查看国际化的源代码,你会注意到硬编码的英文消息已经被移除。因为消息不再是硬编码的,而且语言代码在运行时指定,同一个可执行文件可以在全球范围内分发。本地化不需要重新编译。该程序已经国际化。

你可能想知道消息的文本发生了什么变化,或者语言和国家代码的含义是什么。别担心。当你逐步学习国际化示例程序的过程中,你会了解这些概念。

1. 创建属性文件

一个属性文件存储了关于程序或环境特性的信息。属性文件是纯文本格式。你可以用几乎任何文本编辑器创建这个文件。

在示例中,属性文件存储了要显示的可翻译消息的文本。在程序国际化之前,这些文本的英文版本是硬编码在System.out.println语句中的。默认的属性文件名为MessagesBundle.properties,包含以下内容:

greetings = Hello
farewell = Goodbye
inquiry = How are you?

现在消息已经在一个属性文件中,它们可以被翻译成各种语言。不需要对源代码进行任何更改。法语翻译者创建了一个名为MessagesBundle_fr_FR.properties的属性文件,其中包含以下内容:

greetings = Bonjour.
farewell = Au revoir.
inquiry = Comment allez-vous?

注意等号右侧的值已经被翻译,但左侧的键没有改变。这些键不能改变,因为当你的程序获取翻译后的文本时会引用这些键。

属性文件的名称很重要。例如,MessagesBundle_fr_FR.properties文件的名称包含了fr语言代码和FR国家代码。在创建Locale对象时也会使用这些代码。

2. 定义 Locale

Locale对象标识特定的语言和国家。以下语句定义了一个Locale,其中语言为英语,国家为美国:

aLocale = new Locale("en","US");

下一个示例创建了法语语言在加拿大和法国的Locale对象:

caLocale = new Locale("fr","CA");
frLocale = new Locale("fr","FR");

该程序是灵活的。程序不再使用硬编码的语言和国家代码,而是在运行时从命令行获取它们:

String language = new String(args[0]);
String country = new String(args[1]);
currentLocale = new Locale(language, country);

Locale对象只是标识符。在定义了一个Locale之后,你可以将它传递给执行有用任务的其他对象,比如格式化日期和数字。这些对象是区域敏感的,因为它们的行为根据Locale的不同而变化。ResourceBundle就是一个区域敏感的对象的例子。

3. 创建 ResourceBundle

ResourceBundle对象包含特定于区域设置的对象。你可以使用ResourceBundle对象来隔离与区域设置相关的数据,比如可翻译的文本。在示例程序中,ResourceBundle由包含我们想要显示的消息文本的属性文件支持。

ResourceBundle的创建方式如下:

messages = ResourceBundle.getBundle("MessagesBundle", currentLocale);

传递给getBundle方法的参数标识将要访问的属性文件。第一个参数MessagesBundle指的是这一系列属性文件:

MessagesBundle_en_US.properties
MessagesBundle_fr_FR.properties
MessagesBundle_de_DE.properties

LocalegetBundle的第二个参数,指定了选择哪个MessagesBundle文件。创建Locale时,语言代码和国家代码被传递给其构造函数。请注意,语言和国家代码在属性文件的名称中跟随MessagesBundle

现在你只需要从ResourceBundle中获取翻译后的消息即可。

4. 从 ResourceBundle 中获取文本

属性文件包含键值对。值包含了程序将显示的翻译文本。在从ResourceBundle中获取翻译后的消息时,你需要使用getString方法指定键。例如,要检索由greetings键标识的消息,你可以这样调用getString

String msg1 = messages.getString("greetings");

示例程序使用了键greetings,因为它反映了消息的内容,但也可以使用另一个String,比如s1msg1。只需记住,键是硬编码在程序中的,必须存在于属性文件中。如果你的翻译人员意外修改了属性文件中的键,getString将无法找到消息。

结论

这就是全部。正如你所看到的,国际化一个程序并不太困难。它需要一些规划和一点额外的编码,但好处是巨大的。为了让你了解国际化过程的概况,本课程中的示例程序被故意保持简单。在接下来的课程中,你将了解 Java 编程语言更高级的国际化特性。

检查表

原文:docs.oracle.com/javase/tutorial/i18n/intro/checklist.html

许多程序在最初编写时并未国际化。这些程序可能最初是原型,或者可能并非用于国际分发。如果你必须国际化现有程序,请执行以下步骤:

识别文化相关数据

文本消息是随文化变化最明显的数据形式。然而,其他类型的数据可能会随地区或语言而变化。以下列表包含了文化相关数据的例子:

  • 消息
  • GUI 组件上的标签
  • 在线帮助
  • 声音
  • 颜色
  • 图形
  • 图标
  • 日期
  • 时间
  • 数字
  • 货币
  • 测量
  • 电话号码
  • 敬语和个人头衔
  • 邮政地址
  • 页面布局

在资源包中隔离可翻译文本

翻译是昂贵的。你可以通过将必须翻译的文本隔离在ResourceBundle对象中来帮助降低成本。可翻译的文本包括状态消息、错误消息、日志文件条目和 GUI 组件标签。这些文本包含在尚未国际化的程序中。你需要找到所有显示给最终用户的包含文本的出现。例如,你应该清理这样的代码:

String buttonLabel = "OK";
// ...
JButton okButton = new JButton(buttonLabel);

详细信息请参见隔离特定区域数据部分。

处理复合消息

复合消息包含可变数据。在消息"The disk contains 1100 files."中,整数 1100 可能会变化。这个消息很难翻译,因为整数在句子中的位置在所有语言中都不相同。下面的消息是不可翻译的,因为句子元素的顺序是由串联固定的:

Integer fileCount;
// ...
String diskStatus = "The disk contains " + fileCount.toString() + " files";

尽可能避免构建复合消息,因为它们很难翻译。然而,如果你的应用程序需要复合消息,你可以使用消息部分中描述的技术来处理它们。

格式化数字和货币

如果你的应用程序显示数字和货币,你必须以与地区无关的方式格式化它们。以下代码尚未国际化,因为它在所有国家中都不会正确显示数字:

Double amount;
TextField amountField;
// ...
String displayAmount = amount.toString();
amountField.setText(displayAmount);

你应该用一个能正确格式化数字的例程替换前面的代码。Java 编程语言提供了几个格式化数字和货币的类。这些类在数字和货币部分有讨论。

格式化日期和时间

日期和时间格式因地区和语言而异。如果你的代码包含如下语句,你需要进行更改:

Date currentDate = new Date();
TextField dateField;
// ...
String dateString = currentDate.toString();
dateField.setText(dateString);

如果你使用日期格式化类,你的应用程序可以在全球范围内正确显示日期和时间。有关示例和说明,请参见日期和时间部分。

使用 Unicode 字符属性

以下代码尝试验证一个字符是否为字母:

char ch;
// This code is incorrect
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))

注意类似这样的代码,因为它在除英语以外的语言中无法正常工作。例如,if语句在德语单词 Grün 中漏掉了字符ü。

Character比较方法使用 Unicode 标准来识别字符属性。因此,您应该用以下代码替换先前的代码:

char ch;
// ...
if (Character.isLetter(ch))

有关Character比较方法的更多信息,请参阅检查字符属性部分。

正确比较字符串

在对文本进行排序时,通常需要比较字符串。如果文本是显示的,您不应该使用String类的比较方法。一个未国际化的程序可能会这样比较字符串:

String target;
String candidate;
// ...
if (target.equals(candidate)) {
// ...
if (target.compareTo(candidate) < 0) {
// ...

String.equalsString.compareTo方法执行二进制比较,在大多数语言中排序时效率低下。相反,您应该使用Collator类,该类在比较字符串部分有描述。

转换非 Unicode 文本

Java 编程语言中的字符是以 Unicode 编码的。如果您的应用程序处理非 Unicode 文本,您可能需要将其转换为 Unicode。有关更多信息,请参阅转换非 Unicode 文本部分。

课程:设置区域设置

原文:docs.oracle.com/javase/tutorial/i18n/locale/index.html

一个国际化的程序可以在世界各地以不同方式显示信息。例如,该程序将在巴黎、东京和纽约显示不同的消息。如果本地化过程已经经过精细调整,该程序将显示不同的消息在纽约和伦敦,以考虑美式英语和英式英语之间的差异。一个国际化的程序如何识别其最终用户的适当语言和地区?简单。它引用一个Locale对象。

一个Locale对象是特定语言和地区组合的标识符。如果一个类根据Locale变化其行为,那么它被称为区域敏感。例如,NumberFormat类是区域敏感的;它返回的数字格式取决于Locale。因此,NumberFormat可能会将数字返回为 902 300(法国)、902.300(德国)或 902,300(美国)。Locale对象只是标识符。真正的工作,比如格式化和检测单词边界,是由区域敏感类的方法执行的。

以下各节解释了如何使用Locale对象:

创建一个 Locale

在创建Locale对象时,通常会指定语言代码和国家代码。第三个参数,变体,是可选的。

BCP 47 扩展

本节向您展示如何向Locale添加 Unicode 区域扩展或私有使用扩展。

识别可用的 Locale

区域敏感类仅支持特定的Locale定义。本节将向您展示如何确定支持哪些Locale定义。

语言标签过滤和查找

本节描述了语言标签、语言标签过滤和语言标签查找的国际化支持。

Locale 的范围

在 Java 平台上,您不需要通过在运行应用程序之前设置环境变量来指定全局Locale。相反,您要么依赖于默认 Locale,要么为每个区域敏感对象分配一个Locale

区域敏感服务 SPI

本节解释了如何启用依赖于区域设置的数据和服务的插件。这些 SPI(服务提供者接口)提供了对当前可用区域设置之外更多区域设置的支持。

创建 Locale

原文:docs.oracle.com/javase/tutorial/i18n/locale/create.html

有几种方法可以创建 Locale 对象。无论使用哪种技术,创建可以简单地指定语言代码。但是,您还可以通过设置区域(也称为“国家”)和变体代码来进一步区分区域。如果您使用 JDK 7 发布或更高版本,还可以指定脚本代码和 Unicode 区域扩展。

创建 Locale 对象的四种方法是:

  • Locale.Builder
  • Locale 构造函数
  • Locale.forLanguageTag 工厂方法
  • Locale 常量

版本说明: Locale.Builder 类和 forLanguageTag 方法是在 Java SE 7 发布中添加的。


LocaleBuilder

Locale.Builder 实用类可用于构造符合 IETF BCP 47 语法的 Locale 对象。例如,要指定法语和加拿大国家,您可以调用 Locale.Builder 构造函数,然后链接设置器方法如下:

Locale aLocale = new Locale.Builder().setLanguage("fr").setRegion("CA").build();

下一个示例创建了英语在美国和英国的 Locale 对象:

Locale bLocale = new Locale.Builder().setLanguage("en").setRegion("US").build();
Locale cLocale = new Locale.Builder().setLanguage("en").setRegion("GB").build();

最后一个示例创建了俄语的 Locale 对象:

Locale dLocale = new Locale.Builder().setLanguage("ru").setScript("Cyrl").build();

Locale 构造函数

Locale 类有三个可用的构造函数用于创建 Locale 对象:

以下示例创建了法语在加拿大,英语在美国和英国,以及俄语的 Locale 对象。

aLocale = new Locale("fr", "CA");
bLocale = new Locale("en", "US");
cLocale = new Locale("en", "GB");
dLocale = new Locale("ru");

在 JDK 7 之前的版本中,无法在 Locale 对象上设置脚本代码。

forLanguageTag 工厂方法

如果您有符合 IETF BCP 47 标准的语言标记字符串,可以使用在 Java SE 7 发布中引入的 forLanguageTag(String) 工厂方法。例如:

Locale aLocale = Locale.forLanguageTag("en-US");
Locale bLocale = Locale.forLanguageTag("ja-JP-u-ca-japanese");

Locale 常量

为了方便起见,Locale 类为一些语言和国家提供了常量。例如:

cLocale = Locale.JAPAN;
dLocale = Locale.CANADA_FRENCH;

当您指定语言常量时,Locale 的区域部分是未定义的。下面的三个语句创建等效的 Locale 对象:

j1Locale = Locale.JAPANESE;
j2Locale = new Locale.Builder().setLanguage("ja").build();
j3Locale = new Locale("ja");

由以下三个语句创建的Locale对象也是等效的:

j4Locale = Locale.JAPAN;
j5Locale = new Locale.Builder().setLanguage("ja").setRegion("JP").build();
j6Locale = new Locale("ja", "JP");

代码

以下部分讨论语言代码和可选的脚本、地区和变体代码。

语言代码

语言代码是符合 ISO 639 标准的两个或三个小写字母。您可以在www.loc.gov/standards/iso639-2/php/code_list.php找到 ISO 639 代码的完整列表。

以下表格列出了一些语言代码。

示例语言代码

语言代码 描述
de 德语
en 英语
fr 法语
ru 俄语
ja 日语
jv 爪哇语
ko 韩语
zh 中文

脚本代码

脚本代码以大写字母开头,后跟三个小写字母,并符合 ISO 15924 标准。您可以在unicode.org/iso15924/iso15924-codes.html找到 ISO 15924 代码的完整列表。

以下表格列出了一些脚本代码。

示例脚本代码

脚本代码 描述
Arab 阿拉伯语
Cyrl 西里尔字母
Kana 片假名
Latn 拉丁字母

有三种方法可以检索Locale的脚本信息:

  • getScript() – 返回Locale对象的 4 字母脚本代码。如果未为区域设置定义脚本,则返回空字符串。
  • getDisplayScript() – 返回适合显示给用户的区域设置脚本的名称。如果可能,名称将针对默认区域设置进行本地化。因此,例如,如果脚本代码是"Latn",则返回的显示脚本名称将在英语语言区域设置下为"Latin"。
  • getDisplayScript(Locale) – 返回指定Locale的显示名称,如果可能的话进行本地化。

地区代码

地区(国家)代码由符合 ISO 3166 标准的两个或三个大写字母组成,或者符合 UN M.49 标准的三个数字。代码的副本可以在www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html找到。

以下表格包含几个示例国家和地区代码。

示例地区代码

A-2 代码 A-3 代码 数字代码 描述
AU AUS 036 澳大利亚
BR BRA 076 巴西
CA CAN 124 加拿大
CN CHN 156 中国
DE DEU 276 德国
FR FRA 250 法国
IN IND 356 印度
RU RUS 643 俄罗斯联邦
US USA 840 美国

变体代码

可选的variant代码可用于进一步区分您的Locale。例如,变体代码可用于指示区域代码未涵盖的方言差异。


版本说明: 在 Java SE 7 发布之前,变体代码有时用于标识不特定于语言或区域的差异。例如,它可能已用于标识计算平台之间的差异,如 Windows 或 UNIX。根据 IETF BCP 47 标准,不鼓励此用法。

要定义与您的环境相关的非语言特定变体,请使用扩展机制,如 BCP 47 扩展中所解释的那样。


自 Java SE 7 发布以来,符合 IETF BCP 47 标准的变体代码专门用于指示定义语言或其方言的附加变体。IETF BCP 47 标准对变体子标记施加了语法限制。您可以在www.iana.org/assignments/language-subtag-registry上查看变体代码列表(搜索变体)。

例如,Java SE 使用变体代码支持泰语。按照惯例,thth_TH 区域设置的NumberFormat对象将使用常见的阿拉伯数字形状或阿拉伯数字来格式化泰国数字。然而,th_TH_TH 区域设置的NumberFormat将使用泰国数字形状。ThaiDigits.java中的摘录演示了这一点:

String outputString = new String();
Locale[] thaiLocale = {
             new Locale("th"),
             new Locale("th", "TH"),
             new Locale("th", "TH", "TH")
         };
for (Locale locale : thaiLocale) {
    NumberFormat nf = NumberFormat.getNumberInstance(locale);
    outputString = outputString + locale.toString() + ": ";
    outputString = outputString + nf.format(573.34) + "\n";
}

以下是此示例的屏幕截图:



相关文章
|
9天前
|
Java 测试技术 Python
《手把手教你》系列技巧篇(二十九)-java+ selenium自动化测试- Actions的相关操作上篇(详解教程)
【4月更文挑战第21天】本文介绍了Selenium中处理特殊测试场景的方法,如鼠标悬停。Selenium的Actions类提供了鼠标悬停功能,用于模拟用户在网页元素上的悬停行为。文中通过实例展示了如何使用Actions悬停并展开下拉菜单,以及在搜索时选择自动补全的字段。代码示例包括了打开百度首页,悬停在“更多”元素上显示下拉菜单并点击“音乐”,以及在搜索框输入关键词并自动补全的过程。
33 0
|
2天前
|
Java 测试技术 Python
《手把手教你》系列技巧篇(三十六)-java+ selenium自动化测试-单选和多选按钮操作-番外篇(详解教程)
【4月更文挑战第28天】本文简要介绍了自动化测试的实战应用,通过一个在线问卷调查(&lt;https://www.sojump.com/m/2792226.aspx/&gt;)为例,展示了如何遍历并点击问卷中的选项。测试思路包括找到单选和多选按钮的共性以定位元素,然后使用for循环进行点击操作。代码设计方面,提供了Java+Selenium的示例代码,通过WebDriver实现自动答题。运行代码后,可以看到控制台输出和浏览器的相应动作。文章最后做了简单的小结,强调了本次实践是对之前单选多选操作的巩固。
11 0
|
2天前
|
Java 测试技术 项目管理
Java基础教程(22)-构建工具Maven的基本使用
【4月更文挑战第22天】Maven是Java项目管理及构建工具,简化构建、测试、打包和部署等任务。遵循约定优于配置原则,核心是`pom.xml`配置文件,用于管理依赖和项目信息。安装涉及下载、解压、配置环境变量。在IDEA中使用Maven创建项目,通过`pom.xml`添加依赖和管理版本。常用命令包括`clean`、`compile`、`test`、`package`、`install`和`deploy`。IDEA支持直接执行这些命令。
|
2天前
|
NoSQL Java 关系型数据库
Java基础教程(21)-Java连接MongoDB
【4月更文挑战第21天】MongoDB是开源的NoSQL数据库,强调高性能和灵活性。Java应用通过MongoDB Java驱动与之交互,涉及MongoClient、MongoDatabase、MongoCollection和Document等组件。连接MongoDB的步骤包括:配置连接字符串、创建MongoClient、选择数据库和集合。伪代码示例展示了如何建立连接、插入和查询数据。
|
3天前
|
存储 前端开发 测试技术
《手把手教你》系列技巧篇(三十五)-java+ selenium自动化测试-单选和多选按钮操作-下篇(详解教程)
【4月更文挑战第27天】本文介绍了使用Java+Selenium进行Web自动化测试时,如何遍历和操作多选按钮的方法。文章分为两个部分,首先是一个本地HTML页面的示例,展示了多选按钮的HTML代码和页面效果,并详细解释了遍历多选按钮的思路:找到所有多选按钮的共同点,通过定位这些元素并放入list容器中,然后使用for循环遍历并操作。 第二部分介绍了在JQueryUI网站上的实战,给出了被测网址,展示了代码设计,同样使用了findElements()方法获取所有多选按钮并存储到list中,然后遍历并进行点击操作。最后,文章对整个过程进行了小结,并推荐了作者的其他自动化测试教程资源。
12 0
|
3天前
|
Java 关系型数据库 MySQL
Java基础教程(20)-Java连接mysql数据库CURD
【4月更文挑战第19天】MySQL是流行的关系型数据库管理系统,支持SQL语法。在IDEA中加载jar包到项目类路径:右击项目,选择“Open Module Settings”,添加库文件。使用JDBC连接MySQL,首先下载JDBC驱动,然后通过`Class.forName()`加载驱动,`DriverManager.getConnection()`建立连接。执行CRUD操作,例如创建表、插入数据和查询,使用`Statement`或`PreparedStatement`,并确保正确关闭数据库资源。
|
4天前
|
设计模式 算法 Java
Java基础教程(19)-设计模式简述
【4月更文挑战第19天】设计模式是软件设计中反复使用的代码设计经验,旨在提升代码的可重用性、可扩展性和可维护性。23种模式分为创建型、结构型和行为型三类。创建型模式如工厂方法、抽象工厂、建造者、原型和单例,关注对象创建与使用的分离。结构型模式涉及对象组合,如适配器、装饰器、外观等,增强结构灵活性。行为型模式专注于对象间职责分配和算法合作,包括责任链、命令、观察者等。设计模式提供标准化解决方案,促进代码交流和复用。
|
5天前
|
前端开发 测试技术 Python
《手把手教你》系列技巧篇(三十三)-java+ selenium自动化测试-单选和多选按钮操作-上篇(详解教程)
【4月更文挑战第25天】本文介绍了自动化测试中如何处理单选和多选按钮的操作,包括它们的定义、HTML代码示例以及如何判断和操作这些元素。文章通过一个简单的HTML页面展示了单选和多选框的示例,并提供了Java+Selenium实现的代码示例,演示了如何检查单选框是否选中以及如何进行全选操作。
11 0
|
5天前
|
网络协议 Java 网络架构
Java基础教程(18)-Java中的网络编程
【4月更文挑战第18天】Java网络编程简化了底层协议处理,利用Java标准库接口进行TCP/IP通信。TCP协议提供可靠传输,常用于HTTP、SMTP等协议;UDP协议则更高效但不保证可靠性。在TCP编程中,ServerSocket用于监听客户端连接,Socket实现双进程间通信。UDP编程中,DatagramSocket处理无连接的数据报文。HTTP编程可以通过HttpURLConnection发送请求并接收响应。
|
6天前
|
前端开发 Java 测试技术
《手把手教你》系列技巧篇(三十二)-java+ selenium自动化测试-select 下拉框(详解教程)
【4月更文挑战第24天】本文介绍了在自动化测试中处理HTML下拉选择(select)的方法。使用Selenium的Select类,可以通过index、value或visible text三种方式选择选项,并提供了相应的取消选择的方法。此外,文章还提供了一个示例HTML页面(select.html)和相关代码实战,演示了如何使用Selenium进行选择和取消选择操作。最后,文章提到了现代网页中类似下拉框的新设计,如12306网站的出发地选择,并给出了相应的代码示例,展示了如何定位并选择特定选项。
16 0