Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 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.55 MB
Время: 0.026 c
2-1145178040
MZUser
2006-04-16 13:00
2006.05.07
Как запустить EXE файл из памяти?


2-1145495035
humanlife
2006-04-20 05:03
2006.05.07
radiogrup


1-1144056323
Gear
2006-04-03 13:25
2006.05.07
функция StrToDate и формат времени.


4-1140074397
leonidus
2006-02-16 10:19
2006.05.07
Не получается скомпилировать dll с хуком


15-1144923413
Бугага
2006-04-13 14:16
2006.05.07
Работа с Карт Ридером