epubjs
Version:
Render ePub documents in the browser, across many devices
121 lines (117 loc) • 16.6 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Internationalization</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="Internationalization"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-10-SECT-3"/>Internationalization</h1></div></div></div><p>The Java VM lets us write code that executes in the same way on any
Java platform. But in a global marketplace, that is only half the battle.
A big question remains: will the application content and data be
understandable to end users worldwide? Must users know English to use your
application? The answer is that Java provides thorough support for
<a id="I_indexterm10_id726992" class="indexterm"/><span class="emphasis"><em>localizing</em></span> the text of your application
for most modern languages and dialects. In this section, we’ll talk about
the concepts of internationalization (often abbreviated “I18N”) and the
classes that support them.</p><div class="sect2" title="The java.util.Locale Class"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-10-SECT-3.1"/>The java.util.Locale Class</h2></div></div></div><p><a id="idx10525" class="indexterm"/> <a id="idx10529" class="indexterm"/> <a id="idx10579" class="indexterm"/>Internationalization programming revolves around the
<code class="literal">Locale</code> class. The class itself is
very simple; it encapsulates a country code, a language code, and a
rarely used variant code. Commonly used languages and countries are
defined as constants in the <code class="literal">Locale</code>
class. (Maybe it’s ironic that these names are all in English.) You can
retrieve the codes or readable names, as follows:</p><a id="I_10_tt579"/><pre class="programlisting"> <code class="n">Locale</code> <code class="n">l</code> <code class="o">=</code> <code class="n">Locale</code><code class="o">.</code><code class="na">ITALIAN</code><code class="o">;</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="n">l</code><code class="o">.</code><code class="na">getCountry</code><code class="o">());</code> <code class="c1">// IT</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="n">l</code><code class="o">.</code><code class="na">getDisplayCountry</code><code class="o">());</code> <code class="c1">// Italy</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="n">l</code><code class="o">.</code><code class="na">getLanguage</code><code class="o">());</code> <code class="c1">// it</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="n">l</code><code class="o">.</code><code class="na">getDisplayLanguage</code><code class="o">());</code> <code class="c1">// Italian</code></pre><p><a id="I_indexterm10_id727077" class="indexterm"/> <a id="I_indexterm10_id727083" class="indexterm"/>The country codes comply with ISO 3166. You will find a
complete list of country codes at the <a class="ulink" href="http://bit.ly/182iHGn">RIPE Network Coordination Centre</a>.
The language codes comply with ISO 639. A complete list of language
codes is online at <a class="ulink" href="http://1.usa.gov/14iSOkR">the US
government website</a>. There is no official set of variant codes;
they are designated as vendor-specific or platform-specific. You can get
an array of all supported <code class="literal">Locale</code>s
with the static <a id="I_indexterm10_id727110" class="indexterm"/><code class="literal">getAvailableLocales()</code>
method (which you might use to let your users choose). Or you can
retrieve the default <code class="literal">Locale</code> for the
location where your code is running with the static <a id="I_indexterm10_id727128" class="indexterm"/><code class="literal">Locale.getDefault()</code>
method and let the system decide for you.</p><p>Many classes throughout the Java API use a <code class="literal">Locale</code> to decide how to represent text. We ran
into one earlier when talking about sorting text with the <code class="literal">Collator</code> class. We’ll see more later in this
chapter used to format numbers and currency strings, and again in the
next chapter with the <code class="literal">DateFormat</code>
class, which uses <code class="literal">Locale</code>s to
determine how to format and parse dates and times. Without getting into
the details yet, here is a quick example:</p><a id="I_10_tt580"/><pre class="programlisting"> <code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">printf</code><code class="o">(</code> <code class="n">Locale</code><code class="o">.</code><code class="na">ITALIAN</code><code class="o">,</code> <code class="s">"%f\n"</code><code class="o">,</code> <code class="mf">3.14</code> <code class="o">);</code> <code class="c1">// "3,14"</code></pre><p>The preceding statement uses the Italian <code class="literal">Locale</code> to indicate that the decimal number
3.14 should be formatted as it would in Italian, using a comma instead
of a decimal point. We’ll talk more about formatting text later in this
chapter.<a id="I_indexterm10_id727188" class="indexterm"/><a id="I_indexterm10_id727195" class="indexterm"/><a id="I_indexterm10_id727202" class="indexterm"/></p></div><div class="sect2" title="Resource Bundles"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-10-SECT-3.2"/>Resource Bundles</h2></div></div></div><p><a id="idx10526" class="indexterm"/> <a id="idx10563" class="indexterm"/> <a id="idx10580" class="indexterm"/>Before we move on to the details of formatting messages
and values, we might take a step back and ask a bigger question: what
about the messages themselves? How can we write and manage applications
that are truly multilingual in their user interfaces and in all the
messages they display to the user? We can discover our locale, but how
do we manage all of the application text in our code? The <a id="I_indexterm10_id727259" class="indexterm"/><code class="literal">ResourceBundle</code> class
offers a clean, flexible solution for factoring out the text and
resources of your application into language-specific classes or text
files.</p><p>A <code class="literal">ResourceBundle</code> is a
collection of objects that your application can access by name. It acts
much like the <code class="literal">Hashtable</code> or <code class="literal">Map</code> collections we’ll discuss in <a class="xref" href="ch11.html" title="Chapter 11. Core Utilities">Chapter 11</a>, looking up objects based on <code class="literal">String</code>s that serve as keys. A <code class="literal">ResourceBundle</code> of a given name may be defined
for many different <code class="literal">Locale</code>s. To get a
particular <code class="literal">ResourceBundle</code>, call the
factory method <code class="literal">ResourceBundle.getBundle()</code>, which accepts the
name of the <code class="literal">ResourceBundle</code> and a
<code class="literal">Locale</code>. The following example gets
the <code class="literal">ResourceBundle</code> named “Message”
for two <code class="literal">Locale</code>s; from each bundle, it
retrieves the message whose key is “HelloMessage” and prints the
message:</p><a id="I_10_tt581"/><pre class="programlisting"> <code class="kn">import</code> <code class="nn">java.util.*</code><code class="o">;</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">Hello</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kd">static</code> <code class="kt">void</code> <code class="nf">main</code><code class="o">(</code><code class="n">String</code><code class="o">[]</code> <code class="n">args</code><code class="o">)</code> <code class="o">{</code>
<code class="n">ResourceBundle</code> <code class="n">bun</code><code class="o">;</code>
<code class="n">bun</code> <code class="o">=</code> <code class="n">ResourceBundle</code><code class="o">.</code><code class="na">getBundle</code><code class="o">(</code><code class="s">"Message"</code><code class="o">,</code> <code class="n">Locale</code><code class="o">.</code><code class="na">ITALY</code><code class="o">);</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="n">bun</code><code class="o">.</code><code class="na">getString</code><code class="o">(</code><code class="s">"HelloMessage"</code><code class="o">));</code>
<code class="n">bun</code> <code class="o">=</code> <code class="n">ResourceBundle</code><code class="o">.</code><code class="na">getBundle</code><code class="o">(</code><code class="s">"Message"</code><code class="o">,</code> <code class="n">Locale</code><code class="o">.</code><code class="na">US</code><code class="o">);</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="n">bun</code><code class="o">.</code><code class="na">getString</code><code class="o">(</code><code class="s">"HelloMessage"</code><code class="o">));</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>The <a id="I_indexterm10_id727361" class="indexterm"/><code class="literal">getBundle()</code> method
throws the runtime exception <a id="I_indexterm10_id727373" class="indexterm"/><code class="literal">MissingResourceException</code> if an appropriate
<code class="literal">ResourceBundle</code> cannot be
located.</p><p>You can provide <code class="literal">ResourceBundle</code>s
in two ways: either as compiled Java classes (hard-coded Java) or as
simple property files. Resource bundles implemented as classes are
either subclasses of <a id="I_indexterm10_id727399" class="indexterm"/><code class="literal">ListResourceBundle</code> or
direct implementations of <code class="literal">ResourceBundle</code>. Resource bundles backed by a
property file are represented at runtime by a <a id="I_indexterm10_id727416" class="indexterm"/><code class="literal">PropertyResourceBundle</code>
object. <code class="literal">ResourceBundle.getBundle()</code>
returns either a matching class or an instance of <code class="literal">PropertyResourceBundle</code> corresponding to a
matching property file. The algorithm used by <code class="literal">getBundle()</code> is based on appending the country
and language codes of the requested <code class="literal">Locale</code> to the name of the resource.
Specifically, it searches for resources in this order:</p><a id="I_10_tt582"/><pre class="programlisting"> <code class="n">name_language_country_variant</code>
<code class="n">name_language_country</code>
<code class="n">name_language</code>
<code class="n">name</code>
<code class="n">name_default</code><code class="o">-</code><code class="n">language_default</code><code class="o">-</code><code class="n">country_default</code><code class="o">-</code><code class="n">variant</code>
<code class="n">name_default</code><code class="o">-</code><code class="n">language_default</code><code class="o">-</code><code class="n">country</code>
<code class="n">name_default</code><code class="o">-</code><code class="n">language</code></pre><p>In this example, when we try to get the <code class="literal">ResourceBundle</code> named <code class="literal">Message</code>, specific to <code class="literal">Locale.ITALY</code>, it searches for the following
names (no variant codes are in the <code class="literal">Locale</code>s we are using):</p><a id="I_10_tt583"/><pre class="programlisting"> <code class="n">Message_it_IT</code>
<code class="n">Message_it</code>
<code class="n">Message</code>
<code class="n">Message_en_US</code>
<code class="n">Message_en</code></pre><p>Let’s define the <code class="literal">Message_it_IT
ResourceBundle</code> as a hardcoded class, a subclass of <code class="literal">ListResourceBundle</code>:</p><a id="I_10_tt584"/><pre class="programlisting"> <code class="kn">import</code> <code class="nn">java.util.*</code><code class="o">;</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">Message_it_IT</code> <code class="kd">extends</code> <code class="n">ListResourceBundle</code> <code class="o">{</code>
<code class="kd">public</code> <code class="n">Object</code><code class="o">[][]</code> <code class="nf">getContents</code><code class="o">()</code> <code class="o">{</code>
<code class="k">return</code> <code class="n">contents</code><code class="o">;</code>
<code class="o">}</code>
<code class="kd">static</code> <code class="kd">final</code> <code class="n">Object</code><code class="o">[][]</code> <code class="n">contents</code> <code class="o">=</code> <code class="o">{</code>
<code class="o">{</code><code class="s">"HelloMessage"</code><code class="o">,</code> <code class="s">"Buon giorno, world!"</code><code class="o">},</code>
<code class="o">{</code><code class="s">"OtherMessage"</code><code class="o">,</code> <code class="s">"Ciao."</code><code class="o">},</code>
<code class="o">};</code>
<code class="o">}</code></pre><p><code class="literal">ListResourceBundle</code> makes it
easy to define a <code class="literal">ResourceBundle</code>
class; all we have to do is override the <a id="I_indexterm10_id727533" class="indexterm"/><code class="literal">getContents()</code> method.
This method simply returns a two-dimensional array containing the names
and values of its resources. In this example, <code class="literal">contents[1][0]</code> is the second key (<code class="literal">OtherMessage</code>), and <code class="literal">contents [1][1]</code> is the corresponding message
(<code class="literal">Ciao.</code>).</p><p>Let’s define a <code class="literal">ResourceBundle</code>
for <code class="literal">Locale.US</code>. This time, we’ll take
the easy way and make a property file. Save the following data in a file
called <em class="filename">Message_en_US.properties</em>:</p><a id="I_10_tt585"/><pre class="programlisting"> <code class="n">HelloMessage</code><code class="o">=</code><code class="n">Hello</code><code class="o">,</code> <code class="n">world</code><code class="o">!</code>
<code class="n">OtherMessage</code><code class="o">=</code><code class="n">Bye</code><code class="o">.</code></pre><p>So what happens if somebody runs your program in <code class="literal">Locale.FRANCE</code> and no <code class="literal">ResourceBundle</code> is defined for that <code class="literal">Locale</code>? To avoid a runtime <code class="literal">MissingResourceException</code>, it’s a good idea to
define a default <code class="literal">ResourceBundle</code>. In
our example, you can change the name of the property file to <em class="filename">Message.properties</em>. That way, if a language-
or country-specific <code class="literal">ResourceBundle</code>
cannot be found, your application can still run (by falling back to this
English representation).<a id="I_indexterm10_id727640" class="indexterm"/><a id="I_indexterm10_id727647" class="indexterm"/><a id="I_indexterm10_id727654" class="indexterm"/></p></div></div></body></html>