Текущий архив: 2006.05.07;
Скачать: CL | DM;
ВнизМультиязычность приложения Найти похожие ветки
← →
tria © (2006-04-12 16:20) [0]Задумался собственно над данной темой.
В голове пока один вариант решения:
1. Создаем текстовый файл с нумерованными строками. Под каждым номерм - собственно текст (заголовки, сообщения).
2. При запуске приложения грузим файл в память в массив.
3. В OnCreate любой формы задаем Caption,Hint всех объектов формы по номеру из массива.
4. В меню приложения делаем пункт language. При его выборе сканируем наличие языковых файлов и собственно предлагаем выбор.
Так вот вопрос. Не велосипед ли я изобретаю? Или все же лучше управляемый ручками велосипед, чем что-то стороннее.
Вопрос возник в свете желания перенести приложение в Лазарус.
Может кто-то поделится своим опытом?
← →
isasa © (2006-04-12 16:24) [1]Примерно так-же, только строковые ресурсы хранить в DLL (stringtable), ну и вынимать, соответственно.
Есть, где-то среди примеров "родная", но там сложнее готовить сам текстовый ресурс(нужна сама Дельфи).
← →
Игорь Шевченко © (2006-04-12 16:25) [2]
> Не велосипед ли я изобретаю?
Его. Называется ресурс, конкретно Stringtable. Насколько я помню, в линуксе мультиязычность уже каким-то образом реализована, не лучше ли посмотреть, каким ?
← →
isasa © (2006-04-12 16:26) [3]Да, не уточнил. Для каждого языка, своя DLL. Синхронизация языковых конструкций(во задвинул), по номеру строки.
← →
oldman © (2006-04-12 16:28) [4]:)
Можно еще кучу форм состряпать.
Одна по русски, другие по-нерусски.
И FormN.Show в зависимости от выбора языка
:)
← →
isasa © (2006-04-12 16:40) [5]oldman © (12.04.06 16:28) [4]
Не, ну это сильно наворочено. :)
Кстати, в D для идентификации Контрол<->номер строки ресурса, очень хорошо подходит поле TComponent.Tag: Longint.
← →
tria © (2006-04-12 16:46) [6]Почитал немного про Stringtable.
Что-то я не увидел особой выгоды по сравнению с моим способом. В чем выгода хранить тексты в ресурсах по сравнению с отдельным файлом?
Я лично вижу в отдельных файлах такие плюсы:
1. Перевод на другой язык может выполнять любой специалист/пользователь. В том числе и "под себя".
2. Новый язык может быть добавлен без изменения самого приложения.
3. Размер программы не зависит от числа поддерживаемых языков.
← →
Игорь Шевченко © (2006-04-12 16:50) [7]
> Что-то я не увидел особой выгоды по сравнению с моим способом.
> В чем выгода хранить тексты в ресурсах по сравнению с отдельным
> файлом?
Ресурсы совмещаются с исполняемым файлом программы, плюс оптимизованный поиск нужной строки по ее идентификатору. Тебе ведь в файле тоже искать надо будет нужную строку ?
← →
tria © (2006-04-12 16:51) [8]>Кстати, в D для идентификации Контрол<->номер строки ресурса, очень хорошо подходит поле TComponent.Tag: Longint.
А потом перебрать все контролы формы и присвоить Caption-ы согласно тегам. Одна стандартная процедурина на все формы :)
Только с хинтами проблема. И с другими текстовыми полями.
← →
isasa © (2006-04-12 16:55) [9]tria © (12.04.06 16:46) [6]
Без проблем. В случае DLL п.2,3 работают.
С п.1 я бы не горячился, есть такие "переводчики"
А вообще, хранение дело рук самого хранящего. Хочешь быть модным - храни в xml. :)
← →
tria © (2006-04-12 16:55) [10]>Ресурсы совмещаются с исполняемым файлом программы, плюс оптимизованный поиск нужной строки по ее идентификатору. Тебе ведь в файле тоже искать надо будет нужную строку ?
Простое решение в лоб: массив строк. Правда поиск не по идентификатору, а по номеру. Зато очень просто, быстро и надежно.
← →
isasa © (2006-04-12 16:58) [11]tria © (12.04.06 16:51) [8]
Так тебе-же доступно RTTI. Смотри тип объекта и, соответственно, заполняй его поля.
if (Component[i] is TEdit) then ...
if (Component[i] is TLabel) then ...
← →
tria © (2006-04-12 17:01) [12]>А вообще, хранение дело рук самого хранящего. Хочешь быть модным - храни в xml. :)
Не, я лучше буду использовать маленький такой sql-серверок :).
← →
tria © (2006-04-12 17:07) [13]>Так тебе-же доступно RTTI. Смотри тип объекта и, соответственно, заполняй его поля.
if (Component[i] is TEdit) then ...
if (Component[i] is TLabel) then ...
Это понятно. Но тег один на компонент. А текст заголовка и подсказки, чаще всего, отличается.
Разве что завести что-то наподобие двумерного массива. Первая колонка - Caption, вторая - Hint.
Учитывая, что для пустого String уйдет 4 байта (или сколько там), то 2/3 пустых хинтов - это не критично.
← →
isasa © (2006-04-12 17:07) [14]:)
Я к чему.
В варианте с DLL(stringtable) ничего делать не надо.
Береш(даешь) у переводчика(у) таблицу - номер строки, русский текст, англ. текст, укр. текст, .... . Выгружаешь в csv-файл с разделителем запятая номер строки и нужную колонку(расширение rc), ствишь в начале
stringtable {
в конце }, компилируешь. Библиотека готова. Перевод сделан сторонним лицом.
← →
antonn © (2006-04-12 17:13) [15]inifiles?
← →
isasa © (2006-04-12 17:18) [16]antonn © (12.04.06 17:13) [15]
Текущий язык и соответствие язык<->имя dll - YES! Или реестр.
← →
tria © (2006-04-12 17:20) [17]>inifiles
Да собственно говоря, формировать свой файл в каком-то формате - это же не проблема. Работы на пол дня. И ни с кем ни к чему не привязан, почти полная кросс-платформенность.
← →
antonn © (2006-04-12 17:22) [18]isasa © (12.04.06 17:18) [16]
Или реестр.
Фу:)
ини-файл может сделать любой, кто с блокнотом работает, куда уж проще:) значит с этой стороны препятствий нет, что способствует переводу сторонних лиц:)
← →
antonn © (2006-04-12 17:25) [19]а вообще в одной своей программке я так и делаю:)
> 2. При запуске приложения грузим файл в память в
>массив.
> 3. В OnCreate любой формы задаем Caption,Hint всех
>объектов формы по номеру из массива.
> 4. В меню приложения делаем пункт language. При его
> выборе сканируем наличие языковых файлов и собственно
> предлагаем выбор.
← →
Desdechado © (2006-04-12 17:54) [20]мультиязычность подразумевает не только перевод текста, например:
- надписи справа налево
- надписи на картинках
- изобразительная символика
- звуковая символика
- если работа с БД, то предусмотреть возможность перевода данных, недоступных пользователю на редактирование
← →
Desdechado © (2006-04-12 17:56) [21]ITE в дельфи, кстати, все это и делает
зачем велосипеды?
есть, кстати, множество бесплатных решений в виде компонентов и целых пакетов
я, например, иногда пользую DeLoc
← →
tria © (2006-04-12 17:56) [22]Или еще идея: в Caption, Hint и прочие необходимые строковые поля заносим номер строки в массиве переводов. При открытии перебираемвсе контролы формы и присваиваем перевод согласно указанному номеру.
Полная автоматизация :)
Один минус: нельзя использовать заголовки, содержащие только числа.
← →
iZEN_ (2006-04-13 11:38) [23]Вот ещё одна реализация (данные локалей, русской и английской, хранятся в классе):
public class I18NResources {
public static final int ID_GAME_NEW = 0;
public static final int ID_GAME_OPTIONS = 1;
public static final int ID_GAME_HIGHSCORES = 2;
public static final int ID_GAME_INSTRUCTIONS = 3;
public static final int ID_GAME_ABOUT = 4;
public static final int ID_GAME_CONTINUE = 5;
public static final int ID_COMMAND_GAME_BACK = 6;
public static final int ID_COMMAND_GAME_MORE = 7;
public static final int ID_COMMAND_GAME_EXIT = 8;
public static final int ID_GAME_LEVEL = 9;
public static final int ID_GAME_SOUNDS = 10;
public static final int ID_GAME_VIBRA = 11;
public static final int ID_GAME_NAME = 12;
public static final int ID_COMMAND_GAME_START = 13;
public static final int ID_COMMAND_GAME_PAUSE = 14;
public static final int ID_COMMAND_SETTINGS_OK = 15;
public static final int ID_COMMAND_SETTINGS_CANCEL = 16;
public static final int ID_GAME_SPEED = 17;
/**
* Список поддерживаемых локалей.
* Название локалей специфичны для устройств Nokia
* и определены в системном свойстве "microedition.locale".
* Для устройств других производителей названия локалей может не совпадать
* с представленными, тем не менее метод вывода смягчает этот недостаток.
*/
private static final String[] supportedLocales = {"en", "ru-RU"};
/**
* NOTE: первым представлен список строк языка по умолчанию,
* метод getString использует его, если не может найти соответствующую локаль.
* Строки для каждой локали индексированы в соответствии с поддерживаемыми локалями.
*/
private static final String[][] strings = {
{"New game", "Settings", "High scores", "Instructions", "About",
"Continue", "Back", "More", "Exit", "Level", "Sounds", "Shakes",
"Launch Ball!", "Start", "Pause", "OK", "Cancel", "Speed"},
{"Новая игра", "Установки", "Рекорды", "Справка", "О программе",
"Продолжить", "Назад", "Далее", "Выход", "Уровень", "Звук",
"Вибра", "Запусти шарик!", "Старт", "Пауза", "ОК", "Отмена",
"Скорость"}};
/**
* Возвращает строку, соответствующую ключу.
* @param ключ типа Integer для строки
* @return строка
*/
public static String getString(int key) {
String locale = System.getProperty("microedition.locale");
//System.out.println("microedition.locale = " + locale);
if (locale == null) {
locale = "en";//принимается по умолчанию
}
/* поиск индекса соответствия локали */
int localeIndex = -1;
for (int i = 0; i < supportedLocales.length; i++) {
/* if (locale.equals(supportedLocales[i])) {
* - это НЕ работает на некоторых устройствах.
* Поэтому лучше так:
*/
if (supportedLocales[i].startsWith(locale)) {
localeIndex = i;
break;
}
}
/* если не найдена подходящая локаль, используется первая из списка */
if (localeIndex == -1) { return strings[0][key]; }
return strings[localeIndex][key];
}
}
Использование:
public class SettingsForm extends Form {
//...
/**
* Конструктор без параметров.
*/
public SettingsForm() {
super(I18NResources.getString(I18NResources.ID_GAME_OPTIONS));
this.okCommand = new Command(I18NResources.getString(I18NResources.ID_COMMAND_SETTINGS_OK), Command.OK, 1);
this.cancelCommand = new Command(I18NResources.getString(I18NResources.ID_COMMAND_SETTINGS_CANCEL), Command.CANCEL, 2);
this.addCommand(okCommand);
this.addCommand(cancelCommand);
score = new Gauge(I18NResources.getString(I18NResources.ID_GAME_SPEED), true, Ball.SCORE_MAX, Ball.SCORE_MIN);
this.append(score);
}
//...
А вообще экономически выгодно хранить локализацию в отдельных текстовых файлах (ресурсах) и подгружать только то, что будет использоваться (может зависеть как от локализации операционной системы, так и выбора пользователя).
Главное хранилище имеет ассоциативную структуру (Хэш-таблица, которая может быть реализована массивом): целочисленный_идентификатор -> название_на_выбранном_языке.
Чтобы не путаться, целочисленный_идентификатор имеет вполне "человеческое" имя.
Страницы: 1 вся ветка
Текущий архив: 2006.05.07;
Скачать: CL | DM;
Память: 0.53 MB
Время: 0.009 c