Использование атрибутов МID-лета для определения локализованных ресурсов
Как вы знаете, вы можете размещать определяемые пользователем атрибуты в файле JAD вашего приложения. Это означает, что вы можете использовать файл JAD для определения атрибутов MID-лета, которые представляют локализованные ресурсы, используемые вашим приложением.
В данном подходе программы больше не вставляют ресурсы (например, текстовую строку) в приложение. Вместо этого программы размещают ресурсы в файле JAD. Программа ищет ресурс, извлекая значение некоторого атрибута. Программист определяет имена атрибутов так, чтобы они содержали компонент, который представляет контекст региональной настройки. Таким образом программы могут извлекать версию ресурса, который совместим с их контекстом региональной настройки среды исполнения.
Для демонстрации данного подхода я вновь использовал демонстрационную программу HelloWorld из главы 3. Приложение переименовано на IISNDemo для отличия его от оригинальной версии.
В листинге 9.1 показан файл дескриптора приложения, используемый программой IISNDemo. Несколько новых атрибутов были добавлены в файл JAD. Они представляют собой текстовые строки, которые пользователь видит во время исполнения приложения. Обратите внимание, что существует две версии каждой из данных строк: одна английская и одна французская. Этот файл поддерживает выполнение приложения в английской и французской языковых средах.
Листинг 9.1. Файл JAD содержит один атрибут на строку приложения на поддерживаемую региональную настройку
I18NDerao-alert-en_US: Alert
I18NDemo-alert-fr_FR: Alerce
H8NDemo-alert_text-en_US: The button was pressed
I18NDemo-alert_text-f£_FR: Le bouton a ete presse
I18NDemo-alert_title-en_US: Button Pressed
I18NDemo-alert_title-fr_FR: Eouton a ete Presse
I18NDemo-cancel-en_US: Cancel !18NDemo-cancel-fr_FR: Quitter
I18NDemo-exit-en_US: Exit IlSNDemo-exit-fr_FR: Sortie
I18NDemo-greeting-en_US: Another MIDlet!
I18NDerao-greeting-fr_FR: Un autre MIDlet!
I18NDemo-help-en_US: Help I18NDemo-help-fr_FR: Aider
I18NDemo-item-en_US: Item I18NDemo-item-fr_FR: Item,
I18NDemo-menu-en US: Menu
I18NDemo-menu-fr_Fr: Menu
I18NDemo-ok-en_US: OK
I18NDemo-ok-fr_FR: OK
I18NDe:r.o-sayhi-en_US: Say hi
I18NDemo-sayhi-fr_FR: Dis bonjour
I18NDemo-screen-en_US: Screen
I18NDemc-screen-fr_FR: Ecran I18NDemo-stop-en_US: Stop
I18NDemo-stop-fr_FR: Arreter I18NDemo-title-en_US: Hello, World
I18NDemo-title-fr_FR: A116, tout le Monde MIDlet-1: I18N Demo 1,
I18n.png, I18NDemo MIDlet-Info-URL:
MIDlet-Jar-Size: 19101 MIDlet-Jar-URL: ilSn.jar MIDlet-Name:
I18n MIDlet-Vendor: Vartan Piroumian MIDlet-Version: 1.0
Имена атрибутов в файле JAD, показанные в листинге 9.1, приобретают следующую форму:
<название МID-лета>-<ключ>-<обозначение региональной настройки>
Например, следующие два атрибута определяют заголовок MID-лета на английском и французском языках:
I18NDemo-title-en_US: Hello, World .
I18NDemo-title-fr_FR: A116, tout le Monde
В листингах 9.2 и 9.3 показаны два файла, которые составляют исходный код приложения. Они определяют и реализуют схему поиска атрибутов, отражаемую именами атрибутов в файле JAD. Программа извлекает версию атрибута, связанного с контекстом региональной настройки, в котором приложение работает.
Проектирование интернационализации обуславливает использование указанной схемы для того, чтобы приложение было способно найти локализованные ресурсы в файле JAD. Данный пример демонстрирует, как разработка решения интернационализации вовлекает конфигурирование локализованных ресурсов и присваивание имен атрибутам.
Листинг 9.2. Измененный класс HelloWorld называется IlSNDemo. Он использует схему поиска для извлечения правильной версии атрибутов строки приложения, базируясь на региональной настройке
1 import javax.microedition.midlet.MIDlet;
2
3 import javax.microedition.Icdui.Display;
4 import javax.microedition.Icdui.Displayable;
5 import javax.microedition.Icdui.Form;
6
7 /**
8 Первая версия приложения IlSNDemo.
9
10 <р>Данная версия демонстрирует простейший подход к
11 загрузке локализованных ресурсов из файла JAD MID-лета.
12 этот подход быстро становится непригодным при большом
13 количестве ресурсов. И он полезен только для текстовых
14 сообщений, но не для других видов локализованных
15 ресурсов.
16 */
17 public class IlSNDemo extends MIDlet
18 {
19 // Региональная настройка, указанная для выполнения в
20 // данном MID-лете.
21 private String locale;
22
23 // Displayable. Этот компонент отображается
24 // на экране.
25 private HelloForm form;
26
27 // Экземпляр Display. Данный объект управляет всеми
28 // компонентами Displayable данного MID-лета.
29 private Display display;
30
31 // Экземпляр MID-лета.
32 private static IlSNDemo instance;
33
34 // Префикс имен атрибутов локализуемых
35 // ресурсов.
36 String attrPrefix = new String("I18NDemo-");
37
38 /**
39 Конструктор No-arg.
40 */
41 public I18NDemo()
42 {
43 super();
44 instance = this;
45 }
46
47 /*
48 Получает экземпляр данного класса, который существует в
49 работающем приложении.
50
51 Звоззращает экземпляр, созданный при запуске
52 приложения.
53 */
54 public static IlSNDemo getlnstance()
55 {
56 if (instance == null)
57 {
58 instance = new IlSNDemo ();
59 }
60 return instance;
61 }
62
63 /**
64 Запускает .MID-лет. Получает текущую региональную
65 настройку для реализации. Использует ее для
66 создания префикса ключей атрибутов всех
67 локализованных ресурсов. Названия локализованных
68 ресурсов в файле JAD соответствуют
69 совместимой схеме имен.
70 */
71 public void startApp()
72 {
73 // Извлекает региональную настройку из программного
74 // обеспечения AMS. Региональная настройка должна быть
75 // установлена прежде, чем данный MID-лет начнет выполняться.
76 locale =
77 System.get Property("microedition.locale");
78
79 // Создает элемент Displayable. Получает локализованную
80 // String, которая представляет заголовок
81 // Form, из определенных пользователем атрибутов файла
82 // JAD. Получает все локализованные строки таким
83 // образом.
84 String formTitle = getResource("title");
85 form = new HelloForm(formTitle);
86
87 // Это приложение просто отображает единственную форму,
88 // созданную ранее.
89 display = Display.getDisplay(this);
90 display.setCurrent(form);
91 }
92
93 /**
94 Выдает значение, связанное с указанным
95 ключом из списка определяемых пользователем
96 ресурсов MID-лета в файле JAD приложения.
97
98 @param key - ключ пары «ключ-значение».
99
100 @выдает значение, связанное с указанным
101 ключом.
102 */
103 public String getResource(String key)
104 {
105 StringBuffer index = new
106 StringBuffer(«ttrPrefix);
107 String value;
108
109 index.append(key);
110 index.append('-');
111 index.append(locale);
112
113 value = getAppProperty(index.toString ());
114 return value;
115 }
116
117 /**
118 Закрываем приложение. Уведомляем
119 реализацию о выходе.
120 */
121 public void quit() ,
122 {
123 notifyDestroyed ();
124 }
125
126 public void destroyApp(boolean destroy)
127 {
128
129 }
130
131 public void pauseApp()
132 (
133
134 }
135 }
Листинг 9.З. Класс HelloForm определяет объект формы и использует ту же самую схему, что и основной класс МID-лета
1 import javax.raicroedition.midlet.MIDlet;
2
3 import javax.microedition.Icdui.Alert;
4 import javax.microedition.Icdui.AlertType;
5 import javax.microedition.Icdui.Command;
6 import javax.microedition.Icdui.CommandListener;
7 import javax.microedition.Icdui.Display;
8 import javax.microedition.Icdui.Displayable;
9 import javax.microedition.Icdui.Form;
10
11 /*
12 Данный класс определяет Form, которая отображает
13 простой текст и меню команд. Цель данного класса
14 заключается в демонстрации i18n и 110n
15 видимых пользователю атрибутов. Класс извлекает
16 локализованные ресурсы из программного обеспечения
17 управления приложениями.
18 */
19 открытый HelloForm дополняет Form
20 {
21 // Заголовок данной Form, устанавливаемый по умолчанию.
22 private static final String DEFAULT_TITLE =
23 "Hello, World";
24
25 // Блок прослушивания команд, который обрабатывает
26 // командные события в данной Form.
27 private MyCommandListener cl = new
28 MyCommandListener ();
29
30 //. Экземпляр дисплея, связанный с
31 // данным MID-летом.
32 Display display;
33
34 // Ссылка на связанный с данным объектом
35 // объект MID-лета.
36 I18NDemo midlet;
37
38 // Уведомление, отображаемое в ответ на
39 // активацию некоторых команд данной Form.
40 Alert alert;
41
42 // Команды, размещаемые в данной форме.
43 private Command showAlert;
44 private Command sayHi;
45 private Command cancel;
46 private Command exit;
47 private Command help;
48 private Command item;
49 private Command ok;
50 private Command screen;
51 private Command stop;
52
53 /**
54 Конструктор No-arg. Устанавливает заголовок по умолчанию
55 для данной формы.
56 */
57 HelloForm()
58 {
59 this(DEFAULT_TITLE);
60 }
61
62 /**
63 Конструктор.
64
65 @param title - заголовок Form.
66 */
67 HelloForm(String title)
68 {
69 super(title);
70
71 midlet = IISNDemo.get Instance()
72
73 // Добавляет строковый элемент в форму.
74 String msg = midlet.getResource("greeting" );
75 append(msg);
76
77 display = Display.getDisplay(midlet);
78
79 // Добавляет MyCommandListener в Form для прослушивания
80 // события нажатия клавиши «Back», которое должно
81 // создавать всплывающее диалоговое уведомление Alert.
82 setCommandListener(cl);
83
84 showAlert = new
85 Command(midlet.getRe source("alert") ,
86 Command.SCREEN, 1);
87 addCommand(showAlert);
88
89 sayHi = new .
90 Command(midiet.getResource("sayhi"),
91 Command.SCREEN, 1);
92 addCommand(sayHi);
93
94 cancel = new
95 Command{midlet.getResource("cancel"),
96 Command. SCREEN,, 1) ;
97 addCommand(cancel) ;
98
99 exit = new
100 Command(midlet.getResource("exit") ,
101 Command.SCREEN, 1);
102 addCommand(exit);
103
104 help = new
105 Command(midlet.getResource("help"),
106 Command.SCREEN,, 1);
107 addCommand(help) ;
108
109 item = new
110 Command(midiet.getResource("item"),
111 Command.SCREEN, 1);
112 addCommand(item);
113
114 ok = new
115 Command(midlet.getResource("ok"),
116 Command.SCREEN, 1);
117 addCommand(ok) ;
118
119 screen = new
120 Command(midlet.getResource("screen"),
121 Command.SCREEN, 1);
122 addCommand(screen);
123
124 stop = new
125 Command(midlet.getResource("stop"),
126 Command.SCREEN, 1);
127 addCommand(stop) ;
128 }
129
130 // Данный класс просто прослушивает активацию
131 // какой-либо команды. Экземпляр HelloForm
132 // устанавливает экземпляр данного класса как
133 // свой блок прослушивания команд. Экземпляр
134 // объекта не проверяет информацию команды, а
135 // просто отображает модальное Ale показывающее,
136 // что экранная клавиша была активирована пользователем.
137 private class MyCoramandListener
138 implements CommandLister.er
139 {
140 public void commandAction(Command c,
141 Displayable d)
142 {
143 String title =
144 midlet.getResource("alert_title") ;
145 String msg = null;
146
147 if (c == showAlert)
148 {
149 msg = midlet.getResource("alert_text");
150 alert = new Alert(title,
151 msg,
152 null, AlertType.INFO);
153 alert.setTimeout(Alert.FOREVER);
154 display .setCurrer.t (alert, HelloForm.this);
155 }
156 else if (c == sayHi)
157 {
158 alert = new Alert("Button pressed",
159 msg,
160 r.ull, AlertType.INFO);
161 alert.setTimeout(Alert.FOREVER);
162 display.setCurrent(alert, HelloForm.this);
163 }
164
165 if (c == exit)
166 {
167 IISNDemo.get Instance().destroyApp (true);
168 }
169 }
170 }
171 }
Проблема разработки интернационализации заключается в схеме поиска, используемой для нахождения локализованных строк в файле JAD. Программно определяемый метод getResource (String key), заданный в строках с 103 по 115, на самом деле определяет и реализует схему поиска. Чтобы обнаружить ресурс, метод getResource (String key) создает имя атрибута, а затем ищет сам атрибут.
Например, следующие два оператора, показанные в строках 84 и 85, выбирают строку заголовка Form, использующейся в приложении.
String formTitle = getResource("title");
form = new HelloForm(formTitle);
Метод создает полное имя атрибута, объединяя три строки: 118NDemo - префикс атрибута для данного приложения, идентификатор атрибута ресурса без какой-либо меняющейся в зависимости от региональной настройки информации и обозначение региональной настройки. Параметр строки title является идентификатором атрибута ресурса, а не заголовком формы.
В строке 36 MID-лет определяет префикс атрибута I18NDemo-. Метод startApp() извлекает информацию о контексте региональной настройки, в котором исполняется приложение, из системного свойства microedition.locale и сохраняет его как экземпляр атрибута.
Объект HelloForm использует значение, выданное вызовом getResource(), как его заголовок. Класс HelloForm в листинге 9.3 повторяет этот сценарий. Он просто вызывает getResource() для поиска локализованных значений всех текстов, которые пользователь видит во время исполнения приложения.
Поскольку реализации MIDP будут, скорее всего, поддерживать только одну региональную настройку, возможно, будет лучше для приложений сделать центральной ссылку региональной настройки, которую, как вы знаете, поддерживает ваше устройство, вместо того чтобы извлекать региональную информацию из свойств системы.
Альтернативный подход заключается в создании нескольких версий файла JAD приложения так, чтобы каждая версия содержала атрибуты для каждой региональной настройки. Добавьте соответствующую версию JAD для требуемого контекста региональной настройки. Конечно, вам понадобится определить контекст локальной настройки, в которой будет использоваться телефон, или просто местные настройки пользователя.
В листинге 9.2 используется системное свойство microedition.locale для извлечения региональной настройки для того, чтобы акцентировать внимание на понятии динамически определяемого контекста региональной настройки и ресурсов, связанных с контекстами региональных настроек. Разграничение ресурсов для различных региональных настроек может помочь пониманию вашей разработки и сделать ваше программное обеспечение более восстанавливаемым. Не забывайте, что в будущем, когда устройства станут более мощными, реализации MIDP смогут очень хорошо поддерживать множество региональных настроек. Когда это произойдет, подход, показанный в листинге 9.2, станет более предпочтительным.
Взглянув на метод getResource(), показанный в строчках с 103 по 115, вы увидите, что он использует метод MIDlet.getAppProperty() для извлечения ресурсов из файла дескриптора приложения и файла манифеста. Если атрибут существует в обоих файлах с абсолютно одинаковыми именами ключа, тогда значение извлекается из файла дескриптора приложения и значение в файле манифеста игнорируется. Если не найдено ни одного атрибута или если для ключа не найдено ни одного значения, выдается значение ноль. Если вводимый ключ не найден, сбрасывается NullPointerException.
Значения атрибутов в файле JAD (или манифеста) должны быть кодированы с помощью символьной кодировки, которая поддерживает нужный язык. Существует два способа выполнения этого:
Листинг 9.2 включает поддержку английской и французской региональных настроек. Символьная кодировка ISO8859-1 может представлять английский и французский алфавиты. Если вы желаете локализовать данное приложение на языки, не поддерживаемые семейством ISO8859 (китайский, например), вам придется кодировать значения атрибутов с помощью соответствующей многобайтовой символьной кодировки.
Если вы выбрали первый из только что описанных подходов (кодирование с помощью символьной кодировки, предназначенной для языка региональной настройки), вам понадобится найти текстовой редактор, который поддерживает методы ввода китайского языка и записывает символы в соответствующую кодировку. Либо вы можете использовать второй подход и вводить последовательности переключения уникода Java для каждого символа. Просто найдите точку кодирования уникода для каждого символа в вашей строке. Этот подход работает, поскольку класс Java.lang.String знает, как создавать строковые объекты из последовательностей переключения уникода. Ваше приложение может затем считывать значения атрибутов и создавать из них объекты String.
Вы можете определить имена атрибутов с помощью панели Settings J2MEWTK. Поскольку WTK не поддерживает ввод не-ASCII текста, однако, вы не можете определить не английский локализованный текст значений атрибутов. Чтобы ввести не английские символы, вам придется использовать текстовой редактор для ввода символов непосредственно в файл JAD. Вы можете использовать тот, что поддерживает редакторы методов ввода (IME) для назначенного языка, или вводить последовательности переключения уникода.
Хотя эта разработка интернационализации и локализации, как кажется, работает прекрасно, у нее есть несколько проблем. Прежде всего, пример, который вы только что видели, обращается только к строковым ресурсам. Вам необходимо будет выполнить немного дополнительной работы для осуществления поддержки локализации других типов ресурсов, таких, как календари, средства задания формата даты и времени или даже изображения и цвета.
Чтобы поддерживать нестроковые локализованные ресурсы - например, чувствительный к региональной настройке числовой форматер, - вы можете установить значение атрибута на имя класса, который реализует ваш форматер. Например, вы можете определить атрибут следующим образом:
I18NDemo-number_forraat-fr_FR: NumberFormat_FR
Вы извлекаете значение атрибута, а затем создаете экземпляр данного класса. Следующий фрагмент кода показывает способ, с помощью которого ваш MID-лет может это сделать.
...
try
{
String name =
getAppProperty("I18NDemo-number_format-fr_FR");
// "name" теперь эквивалентно "NumberFormat_FR"
Class с = Class.forName(name);
NumberFormat_FR nf =
(NumberFormat_FR) с.new Instance();
}
catch (InstantiationException ie)
{
...
}
catch (IllegalAccessException iae)
{
...
catch (ClassNotFoundException cnfe)
{
...
}
...
Конечно, вы должны предоставить MIDP-совместим'ый классификационный файл Java с файлом JAR вашего приложения для того, чтобы эта схема работала.
Другой недостаток использования дескрипторов приложения заключается в том, что они неправильно обращаются с файлами JAD и манифеста для программно определяемых свойств. Вы, возможно, думаете, что это просто философское размышление, но это отражается на производительности. Чтобы прочитать файлы JAD или манифеста, вы должны привлечь помощь AMS. Единственный вызов вовлекает несколько компонентов реализации. Файл JAD на самом деле не предназначен для подобного частого доступа. Вы могли заметить, что происходит снижение производительности при попытке прочесть большой файл локализованных ресурсов - или любого другого типа программно определяемых ресурсов.
Кроме того, этот единственный файл JAD должен соответствовать всем МЮ-летам в наборе MID-летов, что делает его еще больше. При использовании файла JAD не в простой демонстрационной программе, а где-либо еще он станет слишком громоздким, так как число атрибутов вырастет.
Другой проблемой является место для указателя ошибок. Разработчик, вручную локализующий файл JAD, легко может сделать незаметные опечатки в указанных атрибутах. А файл JAD не поддерживает вставку комментариев, которые могут помочь людям понять использование атрибута в приложении.