BlackBerry 应用程序开发者指南 第一卷:基础--第8章 本地化应用程序


作者:Confach 发表于2006-04-28 21:43 pm
版权信息:可以任意转载, 转载时请务必以超链接形式标明文章原始出处 和作者信息.
http://www.cnblogs.com/confach/articles/387909.html

8

8 本地化应用程序



资源文件

为应用程序加入本地化支持

从资源文件获取字符串

为应用程序套件管理资源文件

资源文件

将应用程序设计为在代码不改变的情况下它们可以本地化(适合指定的语言以及区域)。为了代替在你的源代码中包含原文元素,将文本字符串存储到一个独立的资源文件中。在你的源代码例中,使用唯一的标志符映射到合适的资源。

 

在独立的资源文件中存储文本字符串有2个好处:

  • 文本翻译有更高的效率,因为一个给定位置(locale)的所有文本字符串都存储在一个单独的文件中,这个文件在你的源代码之外。
  • 基于用户的位置,应用程序可以动态的获得合适的文本显示给用户。

BlackBerry JDE包含了一个内置的资源机制来创建字符串资源。本地化(LocalizationAPI包含在net.rim.device.api.i18n包里。

MIDP应用程序不支持本地化。

一个给定的位置的资源存贮在一个ResourceBundle对象中。一个ResourceBundleFamily对象包括了一个ResourceBundle的集合,它将应用程序的资源进行分组。在不需要新的资源包下,应用程序可以切换语言,这依赖于用户的位置。

BlackBerry JDE将每个资源包编译为一个独立已编译的.cod文件。你可以为应用程序将其他.cod文件和适合的.cod文件一起加载到BlackBerry设备上。

本地化需要的文件

描述

例子

资源头文件

这个文件为每个本地字符串定义具有描述性的键。

BlackBerry编译一个项目时,它创建一个以Resource加到.rrh文件名末作为文件名的资源接口。例如,如果你创建AppName.rhh,接口就是AppNameResouce

AppName.rrh

资源内容文件(根位置)

文件为根(全局)位置将资源键映射到字符串值。它和资源头文件有相同的名字。

AppName.rrc

资源内容文件(指定的位置)

文件为指定的位置(语言和国家)将资源键映射到字符串值。文件和资源头文件有相同的名字,跟在后面的是下划线(_)和语言代码,然后是可选的,一个下划线和国家代码。

2个字母的语言代码和国家代码分别在ISO-639以及ISO3166有描述。

AppName_en.rrc

AppName_en_GB_rrc

AppName_fr.rrc

初始化文件

文件初始化资源包机制。仅当资源作为一个独立的工程编译时本文件为才需要

Init.java

资源继承

在一个基于继承的层次里组织资源。若一个字符串在一个位置里没有定义,下一个最靠近的字符串会被使用。

为应用程序加入本地化支持

增加资源头文件

  1. BlackBerry IDE,打开File菜单,点击New
  2. Source file name里,键入一个文件名。
  3. 点击Browse
  4. 选择一个包含文件的文件夹。
  5. 点击OK
  6. 在域里,键入包的名字,例如:com.rim.samples.docs.countryinfo.
  7. 点击OK
  8. 点击Yes
  9. 除了包文件的描述,保留出现在文本编辑器的文件。
  10. 在右边的区域里,右击加入文件到项目中,然后点击Insert into project

加入资源内容文件

在相同的文件夹下创建3个资源内容文件,在这里,ContryInfo.java有:CountryInfo.rrc(根位置),CountryInfo_en.rrc(English),以及CountryInfo_fr.rrc(French).

  1. File菜单,点击New
  2. 键入文件名以及位置。
  3. 点击OK
  4. 点击Yes
  5. 保留文件为空。
  6. 为加入.rrc文件到你的应用程序项目中,在右边右击文件。
  7. 点击Insert into project

加入资源

  1. BlackBerry IDE,双击一个资源头文件。
  2. Root标签,键入资源键和应用程序的每个字符串或字符串数组的值。

每行定义了单个资源。Keys列为资源显示了一个具有描述性的名字。它是在你代码中使用它获得本地化文本的名字。Values列为某个指定位置的资源显示文本。

:为单个资源键增加一组值,在资源编辑器中,右击一个资源,电解Convert to Multiple Values。加入一个或多个值到数组。

  3.         为指定一个其他位置里的不同文本字符串,选择位置的标签,例如法语是fr.

  4.         在资源的Value单元格里,为locale输入文本字符串。如果你没有为一个特定locale的资源定义一个值,root的值将会使用。

    :直接输入unicode字符到Value单元格中。访问http://ww.unicode.org获得更多信息。

  5.        设置应用程序标题。

 

你可以提供一个本地化的应用程序标题显示在主屏幕(Home Screen)上。如果你没有为应用程序标题提供一个资源,将会使用项目属性窗口上的Application标签里的Title域的输入值。

1.       在资源编辑器中,为应用程序标题增加一个资源,例如APPLICATION_TITLE.

2.         在你支持的每个locale,为这个资源输入一个值。

 :为了为一个应用程序创建一个快捷键,在你用来作为快捷键的字符后加入unicode下划线字符(\u0332)。一个快捷键就是一个在主屏幕上你可以按此键启动应用程序的键。

3.         BlackBerry IDE中,右击应用程序项目,然后点击Properties

4.         点击Resource标签。

5.         选择Title Resource Available选项。

6.         Resource Bundle下拉列表中,为此应用程序选择资源头文件名。

7.         Title Id下拉列表中,为应用程序的标题选择资源,例如APPLICATION_TITLE.

8.         Description ID下拉列表中,选择一个描述性的ID

代码实例

为了指定的locale,而不是在代码里直接提供文本字符串,CountryInfo.java实例描述了如何在单独的资源文件中存储文本字符串。在你的源代码中,从资源里获取字符串为用户locale显示合适的文本。


 

例,CountryInfo.java

/**

* CountryInfo.java

* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.

*/

package com.rim.samples.docs.countryinfo;

import net.rim.device.api.ui.*;

import net.rim.device.api.ui.component.*;

import net.rim.device.api.ui.container.*;

import net.rim.device.api.system.*;

import net.rim.device.api.i18n.*;

import com.rim.samples.docs.resource.*;

 

/* This sample demonstrates how to store text strings in separate resource

files for specific locales rather than providing text strings directly

in the code. In your source code, you retrieve the string from the resource

to display the appropriate text for the user locale. */

 

public class CountryInfo extends UiApplication

{

    public static void main(String[] args) {

       CountryInfo theApp = new CountryInfo();

       theApp.enterEventDispatcher();

       }

   

    public CountryInfo() {

       pushScreen(new HelloWorldScreen());

       }

}

 

 

final class HelloWorldScreen extends MainScreen implements CountryInfoResource {

    private InfoScreen _infoScreen;

    private ObjectChoiceField choiceField;

    private int select;

    private static ResourceBundle _resources = ResourceBundle.getBundle(

           CountryInfoResource.BUNDLE_ID, CountryInfoResource.BUNDLE_NAME);

   

    public HelloWorldScreen() {

       super();

       LabelField title = new LabelField(_resources.getString(APPLICATION_TITLE),

              LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);

       setTitle(title);

       add(new RichTextField(_resources.getString(FIELD_TITLE)));

       String choices[] = _resources.getStringArray(FIELD_COUNTRIES);

       choiceField = new ObjectChoiceField(_resources.getString(FIELD_CHOICE), choices);

       add(choiceField);

       }

      

    public boolean onClose() {

           Dialog.alert(_resources.getString(CLOSE));

           System.exit(0);

           return true;

           }

 

    private MenuItem _viewItem = new MenuItem(_resources, MENUITEM_VIEW, 110, 10) {

       public void run() {

           select = choiceField.getSelectedIndex();

           _infoScreen = new InfoScreen();

           UiApplication.getUiApplication().pushScreen(_infoScreen);

           }

       };

 

    private MenuItem _closeItem = new MenuItem(_resources, MENUITEM_CLOSE,200000, 10)

    {

       public void run() {

           onClose();

           }

       };

 

    protected void makeMenu( Menu menu, int instance ) {

           menu.add(_viewItem);

           menu.add(_closeItem);

           }

      

 

    private class InfoScreen extends MainScreen {

       public InfoScreen() {

           super();

           LabelField lf = new LabelField();

           BasicEditField popField = new BasicEditField(

                  _resources.getString(FIELD_POP), null, 20, Field.READONLY);

           BasicEditField langField = new BasicEditField(

                  _resources.getString(FIELD_LANG), null, 20, Field.READONLY);

           BasicEditField citiesField = new BasicEditField(

                  _resources.getString(FIELD_CITIES), null, 50, Field.READONLY);

           add(lf);

           add(new SeparatorField());

           add(popField);

           add(langField);

           add(citiesField);

           if (select == 0) {

              lf.setText(_resources.getString(FIELD_US));

              popField.setText(_resources.getString(FIELD_US_POP));

              langField.setText(_resources.getString(FIELD_US_LANG));

              citiesField.setText(_resources.getString(FIELD_US_CITIES));

              }

           else if (select == 1) {

              lf.setText(_resources.getString(FIELD_CHINA));

              popField.setText(_resources.getString(FIELD_CHINA_POP));

              langField.setText(_resources.getString(FIELD_CHINA_LANG));

              citiesField.setText(_resources.getString(FIELD_CHINA_CITIES));

              }

           else if (select == 2) {

              lf.setText(_resources.getString(FIELD_GERMANY));

              popField.setText(_resources.getString(FIELD_GERMANY_POP));

              langField.setText(_resources.getString(FIELD_GERMANY_LANG));

              citiesField.setText(

                     _resources.getString(FIELD_GERMANY_CITIES));

              }

           }

       }

    }


从资源文件中获取字符串

实现资源接口

为支持国际化,实现合适的资源接口。BlackBerry IDE自动编译这个资源头文件(.rhh)的接口。接口的名字是加入Resource.rrh文件名称

public class HelloWorldScreen extends MainScreen

implements CountryInfoResource

{

...

 }

 

获取资源包(bundle

为此应用程序声明一个类变量来保持资源包。一个ResourceBundle对象为应用程序包含了所有本地资源,例如字符串。一个应用程序可以在运行时根据它的locale选择合适的包。

private static ResourceBundle _resources = ResourceBundle.getBundle(BUNDLE_ID, BUNDLE_NAME);

为获取合适的包族(bundle family),调用getBundle()。当它创建资源接口作为项目的一部分时,BlackBerry IDE创建BUNDLE_ID以及BUNDLE_NAME常数。

使用资源创建菜单项

为了使用资源创建MenuItem对象,使用MenuItem的构造子,这个构造子为了菜单项的名字,接受一个资源包以及一个资源来代替字符串。不要实现toString(),因为菜单项的文本由资源提供。

private MenuItem _viewItem = new MenuItem(_resources, MENUITEM_VIEW, 110, 10)

{

    public void run() {

       select = choiceField.getSelectedIndex();

       _infoScreen = new InfoScreen();

       UiApplication.getUiApplication().pushScreen(_infoScreen);

       }

    }

用合适的资源替代文本字符串

为每个出现在屏幕上的field,用合适的资源替代文本字符串。调用getString(),或者getStringArray()为适合的语言来获取字符串。

LabelField title = new LabelField(_resources.getString(APPLICATION_TITLE),

       LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);

add(new RichTextField(_resources.getString(FIELD_TITLE)));

String choices[] = _resources.getStringArray(FIELD_COUNTRIES);

choiceField = new ObjectChoiceField(_resources.getString(FIELD_CHOICE), choices);

代码实例

下面的例子修改CountryInfo.java实例,以从资源中获取字符串。


例:CountryInfo.java(支持本地化)

/**

* CountryInfo.java

* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.

*/

package com.rim.samples.docs.localization;

import net.rim.device.api.ui.*;

import net.rim.device.api.ui.component.*;

import net.rim.device.api.ui.container.*;

import net.rim.device.api.system.*;

import net.rim.device.api.i18n.*;

import com.rim.samples.docs.resource.*;

 

public class CountryInfo extends UiApplication {

    public static void main(String[] args) {

       CountryInfo theApp = new CountryInfo();

       theApp.enterEventDispatcher();

       }

   

    public CountryInfo() {

       pushScreen(new HelloWorldScreen());

       }

}

 

final class HelloWorldScreen extends MainScreen implements CountryInfoResource {

    private InfoScreen _infoScreen;

    private ObjectChoiceField choiceField;

    private int select;

    private static ResourceBundle _resources =

       ResourceBundle.getBundle( BUNDLE_ID, BUNDLE_NAME );

   

    public HelloWorldScreen() {

       super();

       LabelField title = new LabelField(_resources.getString(APPLICATION_TITLE),

              LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);

      

       setTitle(title);

       add(new RichTextField(_resources.getString(FIELD_TITLE)));

       String choices[] = _resources.getStringArray(FIELD_COUNTRIES);

       choiceField = new ObjectChoiceField(_resources.getString(FIELD_CHOICE), choices);

       add(choiceField);

       }

   

    public boolean onClose() {

       Dialog.alert(_resources.getString(CLOSE));

       System.exit(0);

       return true;

       }

   

    private MenuItem _viewItem = new MenuItem(_resources, MENUITEM_VIEW, 110, 10) {

       public void run() {

           select = choiceField.getSelectedIndex();

           _infoScreen = new InfoScreen();

           UiApplication.getUiApplication().pushScreen(_infoScreen);

           }

       };

      

    private MenuItem _closeItem = new MenuItem(_resources, MENUITEM_CLOSE, 200000, 10) {

       public void run() {

           onClose();

           }

       };

      

    protected void makeMenu( Menu menu, int instance ) {

       menu.add(_viewItem);

       menu.add(_closeItem);

       }

   

    private class InfoScreen extends MainScreen {

       public InfoScreen() {

           super();

           LabelField lf = new LabelField();

           BasicEditField popField = new BasicEditField(

                  _resources.getString(FIELD_POP), null, 20, Field.READONLY);

           BasicEditField langField = new BasicEditField(

                  _resources.getString(FIELD_LANG), null, 20, Field.READONLY);

           BasicEditField citiesField = new BasicEditField(

                  _resources.getString(FIELD_CITIES), null, 50, Field.READONLY);

           add(lf);

           add(new SeparatorField());

           add(popField);

           add(langField);

           add(citiesField);

           if (select == 0) {

              lf.setText(_resources.getString(FIELD_US));

              popField.setText(_resources.getString(FIELD_US_POP));

              langField.setText(_resources.getString(FIELD_US_LANG));

              citiesField.setText(_resources.getString(FIELD_US_CITIES));

              }

           else if (select == 1) {

              lf.setText(_resources.getString(FIELD_CHINA));

              popField.setText(_resources.getString(FIELD_CHINA_POP));

              langField.setText(_resources.getString(FIELD_CHINA_LANG));

              citiesField.setText(_resources.getString(FIELD_CHINA_CITIES));

              }

           else if (select == 2) {

              lf.setText(_resources.getString(FIELD_GERMANY));

              popField.setText(_resources.getString(FIELD_GERMANY_POP));

              langField.setText(_resources.getString(FIELD_GERMANY_LANG));

              citiesField.setText(_resources.getString(FIELD_GERMANY_CITIES));

              }

           }

       }

    }


 

为应用程序组(suite)管理资源文件

你可以将资源加入到你的应用程序项目中,或者如果你正在创建一组应用程序,对每个locale将资源组织为单独的工程。

创建资源项目

为每个资源包(locale)创建一个项目,包含root locale

为每个locale给项目一个和root locale项目相同的名称,紧跟随一个双下划线(__,语言编码,以及一个可选的在国家编码后的下划线。例如,,如果root locale项目命名为com_company_app,那么每个locale的项目可以明明为com_company_app__en, com_company_app__en_GB, com_company_app__fr.

指定输出文件名

  1. 右击项目,点击Properties
  2. 点击Build标签。
  3. Output file name域,为编译文件输入一个没有文件扩展名的名字。
    :所有资源locale项目的输出文件名,必须和root locale一样,跟随一个双下划线,合适的语言以及国家编码。例如,如果root locale的输出名为com_company_app,法语locale的输出文件名必须为com_company_app__fr.

创建初始化文件

当在一个独立项目中编译资源时,创建一个初始化文件(例如,init.java.BlackBerry IDE提供一个内置的初始化机制,一时你仅需要创建一个空main()函数的空初始化类。

package com.rim.samples.device.resource;

import net.rim.device.api.i18n.*;

public class init {

public static void main (String[] args) { }

}

增加文件到合适的资源项目中

为每个应用程序创建一个头文件,为每个应用程序,每个支持的locale创建一个资源文件。组织资源文件到项目中。

  1. 为增加资源头文件到每个应用程序的项目中以及每个资源项目中。定义应用程序项目以及它他的资源项目之间的依赖性是有必要的。
  2. 在每资源项目中,右击每个.rrh文件,然后点击Properties
  3. 选择Dependency OnlyDo not build
  4. 增加资源内容文件(.rrc)到合适locale的项目中。

:如果你支持大量的locale,为所有资源头文件(.rrh)创建一个单库,并且设置项目类型为Library.对于每个项目中资源locale,定义项目之间的依赖。


  • Last Updated:2007年1月11日
  • Last Updated:2006年4月28日

posted @ 2006-04-28 21:43  张太国  阅读(2491)  评论(0编辑  收藏  举报