Как локализовать мидлет
Недавно с удивлением для себя обнаружил, что многие J2ME програмисты не используют properties файлы и вставляют строчки прямо в код. После чего имеют большие затруднения связанные с их редактированием и локализацией. Да стандартный J2MЕ не имеет в своем арсенале класс ResourseBundle, но написать свой класс предоставляющий подобные возможности не представляет большого труда.
Итак, давайте напишем такой класс Resourse. У нашего класса будет один конструктор и 3 public метода.
directory - имя директории в jar файле мидлета, в которой находятся ресурсы.
fileName - имя файла.
extenssion - расширение файла.
public Resources (String directory, String fileName, String extenssion)
Теперь перейдем к методам нашего класса.
public boolean load() public String get (String key) public void unload()
Метод load находит ресурс файл в jar файле, и загружает его. Если он не может этого сделать возвращает false.
Метод get (String key) возвращает ресурс.
Метод unload() освобождает все связанные c объектом Resources внутренние ресурсы.
Напишем сразу же небольшой мидлет который будет использовать класс Resources
package example; import javax.microedition.lcdui.*; import javax.microedition.midlet.*; import ru.mank.me.util.Resources; public final class Example extends MIDlet implements CommandListener { /*===============[ INSTANCE VARIABLES ]=========*/ private Command exitCommand = null; /*===============[ CLASS METHODS ]==============*/ protected void destroyApp (boolean unconditional) throws MIDletStateChangeException { exitMIDlet(); } private void exitMIDlet() { notifyDestroyed(); } protected void pauseApp(){} protected void startApp() throws MIDletStateChangeException { Resources resources = new Resources ("resources", "mymidlet", "properties"); Form form; if (resources.load()) { exitCommand = new Command (resources.get("exitCommand"), Command.EXIT, 1); form = new Form (resources.get ("title")); StringItem countryItem = new StringItem (resources.get ("country"), resources.get ("countryValue")); StringItem townItem = new StringItem (resources.get ("town"), resources.get ("townValue")); form.append (countryItem); form.append (townItem); resources.unload(); } else { form = new Form ("Error"); exitCommand = new Command ("Exit", Command.EXIT, 1); form.append ("Cannot load resource"); } form.addCommand (exitCommand); form.setCommandListener (this); Display.getDisplay (this).setCurrent (form); } public void commandAction (Command c, Displayable d) { exitMIDlet(); } /*============================*/ }
Cоздадим файлы mymidlet.properties и mymidlet_ru.properties и положим их в jar файл мидлета в директорию resources
mymidlet.properties:
exitCommand=Exit title=Example country=Country countryValue=Russia town=Town townValue=Pskov
mymidlet_ru.properties:
exitCommand=\u0412\u044b\u0445\u043e\u0434 title=\u041f\u0440\u0438\u043c\u0435\u0440 country=\u0421\u0442\u0440\u0430\u043d\u0430 countryValue=\u0420\u043e\u0441\u0441\u0438\u044f town=\u0413\u043e\u0440\u043e\u0434 townValue=\u041f\u0441\u043a\u043e\u0432
Файл mymidlet_ru.properties содержит руссифицированную версию представленную в Unicode.
Соберем наш мидлет и загрузим его в телефон. Установим в телефоне английский язык и запустим мидлет (Рис. 1).
Загрузка мидлета UTF-8 в телефон
После этого установим в телефоне русский язык и снова запустим мидлет. (Рис. 2).
Теперь когда нам ясно как можно работать с классом Resources, рассмотрим его по подробней
package ru.mank.me.util; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Hashtable; public class Resources { /*=============[ STATIC VARIABLES ]=============*/ public static final String LIMITER = "="; private static final int BUFFER_SIZE = 300; /*=============[ INSTANCE VARIABLES ]===========*/ private Hashtable hashtable; private char [] ac; private String fileName = null; private String directory; private String extenssion = ""; private String name; private boolean load = false; private boolean error = false; /*=============[ CONSTRUCTORS ]=================*/ public Resources (String directory, String name, String extenssion) { this.extenssion = extenssion; this.load = false; this.name = name; this.directory = '/' + (directory == null || directory.trim().length() == 0? "" : directory + '/'); } /*=============[ CLASS METHODS ]================*/ public boolean load() { //Если при предыдущей загрузке была ошибка, //то возвращаем false if (error) return false; InputStreamReader in = null; try { //Получаем InputStream ресурс файла InputStream inputStream = getInputStream(); if (inputStream == null) return false; //Создаем InputStreamReader in = new InputStreamReader (inputStream); //Создаем Hashtable в котором будем хранить //содержимое ресурс файла hashtable = new Hashtable(); ac = new char [BUFFER_SIZE]; String str; //Читаем весь файл построчно и заполняем Hashtable while ((str = = readLine (in)) != null) { int len = str.indexOf (LIMITER); if (len > 0) { String key = str.substring (0, len); String value = str.substring (len+1); hashtable.put (key, value); } } //Закрываем InputStream in.close(); ac = null; //Файл был загружен успешно load = true; return true; } catch (Exception io) { //Файл не был загружен успешно error = true; unload(); return false; } finally { //Закрываем InputStream if (in != null) try {in.close();} catch (IOException ex){} } } private InputStream getInputStream() { //Если при предыдущей загрузке была ошибка //то возвращаем null if (error) return null; if (fileName == null) { //Находим нужный нам файл InputStream in = null; String locale = System.getProperty ("microedition.locale"); //Читаем свойство microedition.locale, //которое представляет //текущий Locale (язык и страна). //К примеру если на телефоне текушим //является русский язык, то //locale будет равен "ru-RU". if (locale != null) { //Если locale не равен нулю //то заменяем символ '-' на '_'ю locale = locale.replace ('-', '_'); //Создаем fileName с представлением языка и страны //например fileName_ru_RU fileName = directory + name + "_" + locale + "." + extenssion; in = this.getClass().getResourceAsStream (fileName); if (in != null) { //Если ресурс найден, то возвращаем InputStream return in; } else { //Если ресурс не найден то создаем fileName //с представлением языка //например fileName_ru int i = locale.indexOf ('_'); if (i != -1) { locale = locale.substring (0, i); fileName = directory + name + "_" + locale + "." + extenssion; in = this.getClass().getResourceAsStream (fileName); if (in != null) { //Если ресурс найден, //то возвращаем InputStream return in; } } } } //Если ресурс не найден то создаем //fileName без представления языка и страны fileName = directory + name + "." + extenssion; in = this.getClass().getResourceAsStream (fileName); if (in == null) { //Ресурс не найден, возвращаем null error = true; unload(); return null; } else { //Если ресурс найден, то возвращаем InputStream return in; } } else { //Если ресурс ранее уже был загружен, //то возвращаем InputStream return this.getClass().getResourceAsStream (fileName); } } public String get (String name) { if (!load) { //Если файл с ресурсами не был загружен, //то загружаем его if (!load()) { //Если файл с ресурсами невозможно загрузить //возвращаем пустую строчку return ""; } } String str = (String) hashtable.get (name); if (str == null) { //Если ресурс не обнаружен возвращаем пустую строчку return ""; } else { //Ура! Вот ваш ресурс! return str; } } public void unload() { //Если объект Resources нам временно не нужен, //освобождаем все связанные с ним ресурсы, //позволяя Garbage Collector'у собрать их. hashtable = null; ac = null; if (fileName != null) { name = null; extenssion = null; directory = null; } load = false; } //Этот метод читает строчку из потока. private String readLine (InputStreamReader in) throws IOException { int j = 0; StringBuffer buffer = new StringBuffer(); int r = -1; while (j < ac.length && (r = in.read()) > 0 && r != 13) ac [j++] = (char)r; while (j > 0) { int copy = -1; for (int k = 0; k < j;) { if (ac [k] == '\\') { if (k >= BUFFER_SIZE - 6) { copy = k; break; } if (ac [k + 1] == 'u') { try { int l = Integer.parseInt (new String (ac, k + 2, 4), 16); k += 6; buffer.append (new String (new char[]{(char)l})); } catch (NumberFormatException ex){} } else { buffer.append (new String (ac, k, 1)); k++; } } else { buffer.append (new String (ac, k, 1)); k++; } } if (r == 13 || r < 0) break; if (copy != -1) { int limit = j; j = 0; for (int i = copy; i < BUFFER_SIZE && i < limit; i++) ac [j++] = ac[i]; } else j = 0; while (j < ac.length && (r = in.read()) > 0 && r != 13) ac [j++] = (char)r; } if (r == -1 && buffer.length() == 0) return null; else return buffer.toString().trim(); } } /*=====================*/
P.S. Прошу прощения за корявость языка, но просто сложно найти к устоявшиимся выражениям на английском языке, подходящий эквивалент на русском.
http://www.midlet.ru/