UNPKG

epubjs

Version:

Render ePub documents in the browser, across many devices

121 lines (117 loc) 16.6 kB
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <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>