30.2. MVC

 
[Page 881 ( continued )]

26.5. (Optional) Resource Bundles

The NumberFormatDemo in the preceding example displays the numbers , currencies, and percentages in local customs , but displays all the message strings, titles, and button labels in English. In this section, you will learn how to use resource bundles to localize message strings, titles, button labels, and so on.

A resource bundle is a Java class file or text file that provides locale-specific information. This information can be accessed by Java programs dynamically. When a locale-specific resource is needed ”a message string, for example ”your program can load it from the resource bundle appropriate for the desired locale. In this way, you can write program code that is largely independent of the user 's locale, isolating most, if not all, of the locale-specific information in resource bundles.

With resource bundles, you can write programs that separate the locale-sensitive part of your code from the locale-independent part. The programs can easily handle multiple locales, and can easily be modified later to support even more locales.

The resources are placed inside the classes that extend the ResourceBundle class or a subclass of ResourceBundle . Resource bundles contain key/value pairs. Each key uniquely identifies a locale-specific object in the bundle. You can use the key to retrieve the object. ListResourceBundle is a convenient subclass of ResourceBundle that is often used to simplify the creation of resource bundles. Here is an example of a resource bundle that contains four keys using ListResourceBundle :

  // MyResource.java: resource file    public class   MyResource   extends   java.util.ListResourceBundle {   static final   Object[][] contents = { 

[Page 882]
 {   "nationalFlag"   ,   "us.gif"   }, {   "nationalAnthem"   ,   "us.au"   }, {   "nationalColor"   , Color .red}, {   "annualGrowthRate"   , new Double(   7.8   )} };   public   Object[][] getContents() {   return   contents; } } 

Keys are case-sensitive strings. In this example, the keys are nationalFlag , nationalAnthem , nationalColor , and annualGrowthRate . The values can be any type of Object .

If all the resources are strings, they can be placed in a convenient text file with the extension .properties. A typical property file would look like this:

 #Wed Jul 01 07:23:24 EST 1998 nationalFlag=us.gif nationalAnthem=us.au 

To retrieve values from a ResourceBundle in a program, you first need to create an instance of ResourceBundle using one of the following two static methods :

   public static final   ResourceBundle getBundle(String baseName)   throws   MissingResourceException   public static final   ResourceBundle getBundle (String baseName, Locale locale)   throws   MissingResourceException 

The first method returns a ResourceBundle for the default locale, and the second method returns a ResourceBundle for the specified locale. baseName is the base name for a set of classes, each of which describes the information for a given locale. These classes are named in Table 26.3.

Table 26.3. Resource Bundle Naming Conventions
1. BaseName_language_country_variant.class
2. BaseName_language_country.class
3. BaseName_language.class
4. BaseName.class
5. BaseName_language_country_variant.properties
6. BaseName_language_country.properties
7. BaseName_language.properties
8. BaseName.properties

For example, MyResource_en_BR.class stores resources specific to the United Kingdom, MyResource_en_US.class stores resources specific to the United States, and MyResource_en.class stores resources specific to all the English-speaking countries .

The getBundle method attempts to load the class that matches the specified locale by language, country, and variant by searching the file names in the order shown in Table 26.3. The files searched in this order form a resource chain . If no file is found in the resource chain, the getBundle method raises a MissingResourceException , a subclass of RuntimeException .


[Page 883]

Once a resource bundle object is created, you can use the getObject method to retrieve the value according to the key. For example,

 ResourceBundle res = ResourceBundle.getBundle(   "MyResource"   ); String flagFile = (String)res.getObject(   "nationalFlag"   ); String anthemFile = (String)res.getObject(   "nationalAnthem"   ); Color color = (Color)res.getObject(   "nationalColor"   );   double   growthRate = (Double)res.getObject(   "annualGrowthRate"   ).doubleValue(); 

Tip

If the resource value is a string, the convenient getString method can be used to replace the getObject method. The getString method simply casts the value returned by getObject to a string.


What happens if a resource object you are looking for is not defined in the resource bundle? Java employs an intelligent look-up scheme that searches the object in the parent file along the resource chain. This search is repeated until the object is found or all the parent files in the resource chain have been searched. A MissingResourceException is raised if the search is unsuccessful .

Let us modify the NumberFormatDemo program in the preceding example so that it displays messages, title, and button labels in multiple languages, as shown in Figure 26.10.

Figure 26.10. The program displays the strings in multiple languages.

You need to provide a resource bundle for each language. Suppose the program supports three languages: English (default), Chinese, and French. The resource bundle for the English language, named MyResource.properties, is given as follows :

 #MyResource.properties for English language Number_Of_Years=Years Total_Payment=French Total\ Payment Enter_Interest_Rate=Enter\ Interest\ Rate,\ Years ,\ and\ Loan\ Amount Payment=Payment Compute=Compute Annual_Interest_Rate=Interest\ Rate Number_Formatting=Number\ Formatting\ Demo Loan_Amount=Loan\ Amount 

[Page 884]
 Choose_a_Locale=Choose\ a\ Locale Monthly_Payment=Monthly\ Payment 

The resource bundle for the Chinese language, named MyResource_zh.properties, is given as follows:

  #MyResource_zh.properties for Chinese language Choose_a_Locale = \u9078\u64c7\u570b\u5bb6 Enter_Interest_Rate = \u8f38\u5165\u5229\u7387,\u5e74\u9650,\u8cb8\u6b3e\u7e3d\u984d Annual_Interest_Rate = \u5229\u7387 Number_Of_Years = \u5e74\u9650 Loan_Amount = \u8cb8\u6b3e\u984d\u5ea6 Payment = \u4ed8\u606f Monthly_Payment = \u6708\u4ed8 Total_Payment = \u7e3d\u984d Compute = \u8a08\u7b97\u8cb8\u6b3e\u5229\u606f  

The resource bundle for the French language, named MyResource_fr.properties, is given as follows:

  #MyResourse_fr.properties for French language Number_Of_Years=annees Annual_Interest_Rate=le taux d'interet Loan_Amount=Le montant du pret Enter_Interest_Rate=inscrire le taux d'interet, les annees, et le montant du pret Payment=paiement Compute=Calculer l'hypotheque Number_Formatting=demonstration du formatting des chiffres Choose_a_Locale=Choisir la localite Monthly_Payment=versement mensuel Total_Payment=reglement total  

The program is given in Listing 26.7.

Listing 26.7. ResourceBundleDemo.java
(This item is displayed on pages 884 - 888 in the print version)
 1   import   java.awt.*; 2   import   java.awt.event.*; 3   import   javax.swing.*; 4   import   javax.swing.border.*; 5   import   java.util.*; 6   import   java.text.NumberFormat; 7 8   public class   ResourceBundleDemo   extends   JApplet { 9  // Combo box for selecting available locales  10   private   JComboBox jcboLocale =   new   JComboBox(); 11    private   ResourceBundle res = ResourceBundle.getBundle(   "MyResource"   );  12 13  // Create labels  14   private   JLabel jlblInterestRate = 15   new   JLabel(  res.getString(   "Annual_Interest_Rate"   )  ); 16   private   JLabel jlblNumberOfYears = 17   new   JLabel(  res.getString(   "Number_Of_Years"   )  ); 18   private   JLabel jlblLoanAmount =   new   JLabel 19 (  res.getString(   "Loan_Amount"   )  ); 20   private   JLabel jlblMonthlyPayment = 21   new   JLabel(res.getString(   "Monthly_Payment"   )); 

[Page 885]
 22   private   JLabel jlblTotalPayment = 23   new   JLabel(  res.getString(   "Total_Payment"   )  ); 24 25  // Create titled borders  26   private   TitledBorder comboBoxTitle = 27   new   TitledBorder(  res.getString(   "Choose_a_Locale"   )  ); 28   private   TitledBorder inputTitle =   new   TitledBorder 29 (  res.getString(   "Enter_Interest_Rate"   )  ); 30   private   TitledBorder paymentTitle = 31   new   TitledBorder(  res.getString(   "Payment"   )  ); 32 33  // Text fields for interest rate, year, loan amount,  34   private   JTextField jtfInterestRate =   new   JTextField(   "6.75"   ); 35   private   JTextField jtfNumberOfYears =   new   JTextField(   "15"   ); 36   private   JTextField jtfLoanAmount =   new   JTextField(   "107000"   ); 37   private   JTextField jtfFormattedInterestRate =   new   JTextField(   10   ); 38   private   JTextField jtfFormattedNumberOfYears =   new   JTextField(   10   ); 39   private   JTextField jtfFormattedLoanAmount =   new   JTextField(   10   ); 40 41  // Text fields for monthly payment and total payment  42   private   JTextField jtfTotalPayment =   new   JTextField(); 43   private   JTextField jtfMonthlyPayment =   new   JTextField(); 44 45  // Compute button  46   private   JButton jbtCompute =   new   JButton(res.getString(   "Compute"   )); 47 48  // Current locale  49   private   Locale locale = Locale.getDefault(); 50 51  // Declare locales to store available locales  52   private   Locale locales[] = Calendar.getAvailableLocales(); 53 54  /** Initialize the combo box */  55   public void   initializeComboBox() { 56  // Add locale names to the combo box  57   for   (   int   i =     ; i < locales.length; i++) 58 jcboLocale.addItem(locales[i].getDisplayName()); 59 } 60 61  /** Initialize the applet */  62   public void   init() { 63  // Panel p1 to hold the combo box for selecting locales  64 JPanel p1 =   new   JPanel(); 65 p1.setLayout(   new   FlowLayout()); 66 p1.add(jcboLocale); 67 initializeComboBox(); 68 p1.setBorder(comboBoxTitle); 69 70  // Panel p2 to hold the input for annual interest rate,  71  // number of years and loan amount  72 JPanel p2 =   new   JPanel(); 73 p2.setLayout(   new   GridLayout(   3   ,   3   )); 74 p2.add(jlblInterestRate); 75 p2.add(jtfInterestRate); 76 p2.add(jtfFormattedInterestRate); 77 p2.add(jlblNumberOfYears); 78 p2.add(jtfNumberOfYears); 79 p2.add(jtfFormattedNumberOfYears); 80 p2.add(jlblLoanAmount); 81 p2.add(jtfLoanAmount); 

[Page 886]
 82 p2.add(jtfFormattedLoanAmount); 83 p2.setBorder(inputTitle); 84 85  // Panel p3 to hold the payment  86 JPanel p3 =   new   JPanel(); 87 p3.setLayout(   new   GridLayout(   2   ,   2   )); 88 p3.setBorder(paymentTitle); 89 p3.add(jlblMonthlyPayment); 90 p3.add(jtfMonthlyPayment); 91 p3.add(jlblTotalPayment); 92 p3.add(jtfTotalPayment); 93 94  // Set text field alignment  95 jtfFormattedInterestRate.setHorizontalAlignment 96 (JTextField.RIGHT); 97 jtfFormattedNumberOfYears.setHorizontalAlignment 98 (JTextField.RIGHT); 99 jtfFormattedLoanAmount.setHorizontalAlignment(JTextField.RIGHT); 100 jtfTotalPayment.setHorizontalAlignment(JTextField.RIGHT); 101 jtfMonthlyPayment.setHorizontalAlignment(JTextField.RIGHT); 102 103  // Set editable false  104 jtfFormattedInterestRate.setEditable(   false   ); 105 jtfFormattedNumberOfYears.setEditable(   false   ); 106 jtfFormattedLoanAmount.setEditable(   false   ); 107 jtfTotalPayment.setEditable(   false   ); 108 jtfMonthlyPayment.setEditable(   false   ); 109 110  // Panel p4 to hold result payments and a button  111 JPanel p4 =   new   JPanel(); 112 p4.setLayout(   new   BorderLayout()); 113 p4.add(p3, BorderLayout.CENTER); 114 p4.add(jbtCompute, BorderLayout.SOUTH); 115 116  // Place panels to the applet  117 add(p1, BorderLayout.NORTH); 118 add(p2, BorderLayout.CENTER); 119 add(p4, BorderLayout.SOUTH); 120 121  // Register listeners  122 jcboLocale.addActionListener(   new   ActionListener() { 123   public void   actionPerformed(ActionEvent e) { 124 locale = locales[jcboLocale.getSelectedIndex()]; 125 updateStrings(); 126 computeLoan(); 127 } 128 }); 129 130 jbtCompute.addActionListener(   new   ActionListener() { 131   public void   actionPerformed(ActionEvent e) { 132 computeLoan(); 133 } 134 }); 135 } 136 137  /** Compute payments and display results locale-sensitive format */  138   private void   computeLoan() { 139  // Retrieve input from user  140   double   loan =   new   Double(jtfLoanAmount.getText()).doubleValue(); 141   double   interestRate = 142   new   Double(jtfInterestRate.getText()).doubleValue() /   1240   ; 

[Page 887]
 143   int   numberOfYears = 144   new   Integer(jtfNumberOfYears.getText()).intValue(); 145 146  // Calculate payments  147   double   monthlyPayment = loan * interestRate/ 148 (   1   - (Math.pow(   1   / (   1   + interestRate), numberOfYears *   12   ))); 149   double   totalPayment = monthlyPayment * numberOfYears *   12   ; 150 151  // Get formatters  152 NumberFormat percentFormatter = 153 NumberFormat.getPercentInstance(locale); 154 NumberFormat currencyForm = 155 NumberFormat.getCurrencyInstance(locale); 156 NumberFormat numberForm = NumberFormat.getNumberInstance(locale); 157 percentFormatter.setMinimumFractionDigits(   2   ); 158 159  // Display formatted input  160 jtfFormattedInterestRate.setText( 161 percentFormatter.format(interestRate *   12   )); 162 jtfFormattedNumberOfYears.setText 163 (numberForm.format(numberOfYears)); 164 jtfFormattedLoanAmount.setText(currencyForm.format(loan)); 165 166  // Display results in currency format  167 jtfMonthlyPayment.setText(currencyForm.format(monthlyPayment)); 168 jtfTotalPayment.setText(currencyForm.format(totalPayment)); 169 } 170 171  /** Update resource strings */  172   private void   updateStrings() { 173  res = ResourceBundle.getBundle(   "MyResource"   , locale);  174 jlblInterestRate.setText(  res.getString(   "Annual_Interest_Rate"   )  ); 175 jlblNumberOfYears.setText(  res.getString(   "Number_Of_Years"   )  ); 176 jlblLoanAmount.setText(  res.getString(   "Loan_Amount"   )  ); 177 jlblTotalPayment.setText(  res.getString(   "Total_Payment"   )  ); 178 jlblMonthlyPayment.setText(  res.getString(   "Monthly_Payment"   )  ); 179 jbtCompute.setText(  res.getString(   "Compute"   )  ); 180 comboBoxTitle.setTitle(  res.getString(   "Choose_a_Locale"   )  ); 181 inputTitle.setTitle(  res.getString(   "Enter_Interest_Rate"   )  ); 182 paymentTitle.setTitle(  res.getString(   "Payment"   )  ); 183 184  // Make sure the new labels are displayed  185 repaint(); 186 } 187 188  /** Main method */  189   public static void   main(String[] args) { 190  // Create an instance of the applet  191 ResourceBundleDemo applet =   new   ResourceBundleDemo(); 192 193  // Create a frame with a resource string  194 JFrame frame =   new   JFrame( 195 applet.  res  .getString(   "Number_Formatting"   )); 196 197  // Add the applet instance to the frame  198 frame.add(applet, BorderLayout.CENTER); 199 200  // Invoke init() and start()  201 applet.init(); 202 applet.start(); 

[Page 888]
 203 204  // Display the frame  205 frame.setSize(   400   ,   300   ); 206 frame.setLocationRelativeTo(   null   ); 207 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 208 frame.setVisible(   true   ); 209 } 210 } 

Property resource bundles are implemented as text files with a .properties extension, and are placed in the same location as the class files for the application or applet. ListResourceBundles are provided as Java class files. Because they are implemented using Java source code, new and modified ListResourceBundles need to be recompiled for deployment. With PropertyResourceBundles , there is no need for recompilation when translations are modified or added to the application. Nevertheless, ListResourceBundles provide considerably better performance than PropertyResourceBundles .

If the resource bundle is not found or a resource object is not found in the resource bundle, a MissingResourceException is raised. Since MissingResourceException is a subclass of RuntimeException , you do not need to catch the exception explicitly in the code.

This example is the same as Listing 26.6, NumberFormatDemo.java, except that the program contains the code for handling resource strings. The updateString method (lines 172 “186) is responsible for displaying the locale-sensitive strings. This method is invoked when a new locale is selected in the combo box. Since the variable res of the ResourceBundle class is an instance variable in ResourceBundleDemo , it cannot be directly used in the main method, because the main method is static. To fix the problem, create applet as an instance of ResourceBundleDemo and you will then be able to reference res using applet.res .

 


Introduction to Java Programming-Comprehensive Version
Introduction to Java Programming-Comprehensive Version (6th Edition)
ISBN: B000ONFLUM
EAN: N/A
Year: 2004
Pages: 503

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net