div.main {margin-left: 20pt; margin-right: 20pt}
Многоязычный интерфейс приложений в Delphi Автор: Денис
Колисниченко, dhsilabs@mail.ru Опубликовано:
08.02.2002 Оригинал: http://www.softerra.ru/review/program/15794/
Наверняка, вам хоть раз в жизни приходилось
разрабатывать многоязычное приложение. Например, вам нужно, чтобы ваше
приложение «ругалось» как на английском, так и на русском языке. В таком случае,
обычно, один язык встраивается в приложение, как правило, английский, а потом
пользователю предоставляется возможность выбрать язык интерфейса программы.
Для этих целей существует много коммерческих и бесплатных
компонент-переводчиков, однако использовать их довольно неудобно, поскольку,
необходимо помещать копию компонента на каждую форму приложения. Я предлагаю
совершенно другой подход, а именно – использовать модуль-переводчик, который
будет переводить все формы приложения. При достаточно высокой скорости перевода
интерфейса, размер программы увеличиться всего на 3Кб (именно столько «весит»
модуль) Алгоритм работы такой: функция TranslateForm обходит все компоненты
формы и переводит их на указанный язык, используя для этого специальный словарь.
Словарь имеет формат Ini-файла, поэтому, как и для всех остальных Ini-файлов,
для этого файла существует ограничение размера – не более 64 Кб, если я,
конечно, не ошибаюсь. Решить эту проблему можно достаточно просто – использовать
несколько словарей для разных языков. Приведу раздел объявления нашего
модуля (interface):
Пример 1 interface
uses SysUtils, Classes, Controls, Forms, Dialogs, Quickrpt, ... ;
function Translate(Text : string; Lang : string; Dict : TIniFile):string;
procedure TranslateForm(Form : TForm; Lang : string; DictFileName : string);
Процедура TranslateForm, как я уже писал,
обходит все компоненты формы, а функция Trasnlate – выполняет перевод.
Переводятся текстовые свойства компонент, например, Caption и Hint. При вызове
функции нужно указать следующие параметры: Form : TForm; Lang : string; DictFileName : string
Параметр Form определяет форму, которую нужно
перевести. Параметр Lang – это язык на который нужно перевести свойство
компонента. Тот язык, с которым работает программа в данный момент, будем
называть ключевым. Подразумевается, что в данный момент (до перевода) программа
работает с ключевым языком, потому что поиск (перевод) слов будет произведен с
использованием ключевого языка. Чтобы было понятнее, приведу пример словаря:
Пример 2 [Rus]
File=Файл
Open=Открыть
Translate=Перевести
Application=Приложение
New=Создать
Open=Открыть
Text=Текст
Save=Сохранить
Save As...=Сохранить как...
Print=Печать
Print Setup=Параметры печати
Exit=Выход
Edit=Правка
Cut=Вырезать
Copy=Копировать
Paste=Вставить
Undo=Отмена
View=Вид
Status bar=Панель состояния
Tool bar=Панель инструментов
Tools=Сервис
Settings=Параметры
...
Для перевода интерфейса приложения с английского
на русский язык нужно вызвать процедуру TrasnlateForm так: TranslateForm(Form1, 'Rus', 'trans.dic');При этом ключевым языком
считается английский (см. секцию Rus в примере 2). Аналогично можно создать
секцию Eng и использовать русский язык в качестве ключевого.
Для того, чтобы перевести все формы приложения
используйте следующие операторы: for i:=0 to Screen.FormCount-1 do
TranslateForm(Screen.Forms[i],'Rus','trans.dic');
Если вы хотите изменить язык приложения во время
его запуска, отредактируйте файл проекта так: for i:=0 to Screen.FormCount-1 do
TranslateForm(Screen.Forms[i],'Rus','trans.dic');
Application.Run;
То есть перевод форм нужно выполнить до
выполнения метода Application.Run;
Теперь рассмотрим весь исходный код
модуля-переводчика:
Пример 3. Файл trans.pas unit trans;
interface
uses SysUtils, Classes, Controls, Forms, Dialogs, Quickrpt, QRCtrls, StdCtrls,
Buttons, ComCtrls, ExtCtrls, DBCtrls, DB, DBGrids, Menus, Grids, Mask,
IniFiles;
function Translate(Text : string; Lang : string; Dict : TIniFile):string;
procedure TranslateForm(Form : TForm; Lang : string; DictFileName : string);
implementation
{ Непосредственный перевод текста }
function Translate(Text : string; Lang : string; Dict : TIniFile):string;
var s : string;
begin
Result:=Text;
S:=Dict.ReadString(Lang, Text, '');
if S='' then Dict.WriteString(Lang, Text, '');
if S<>'' then Result:=S;
end;
procedure TranslateForm(Form : TForm; Lang : string; DictFileName : string);
var Dict : TIniFile;
I,J : Integer;
Obj : TObject;
begin
{ Открываем словарь. Перед вызовом функции Translate словарь должен быть открыт! }
Dict:=TIniFile.Create(DictFileName);
if not fileexists(DictFileName) then
ShowMessage('No exists' + DictFileName);
Form.Caption:=Translate(Form.Caption, Lang, Dict);
Application.Title:=Translate(Application.Title, Lang, Dict);
{ Переводим компоненты формы}
For I:=0 to Form.ComponentCount-1 do
Begin
Obj:=Form.Components[i];
if Obj is TMenuItem then
begin
TMenuItem(Obj).Caption:=Translate(TMenuItem(Obj).Caption, Lang, Dict);
TMenuItem(Obj).Hint:=Translate(TMenuItem(Obj).Hint, Lang, Dict);
end;
if Obj is TButton then
begin
TButton(Obj).Caption:=Translate(TButton(Obj).Caption, Lang, Dict);
TButton(Obj).Hint:=Translate(TButton(Obj).Hint, Lang, Dict);
end;
if Obj is TBitBtn then
begin
TBitBtn(Obj).Caption:=Translate(TBitBtn(Obj).Caption, Lang, Dict);
TBitBtn(Obj).Hint:=Translate(TBitBtn(Obj).Hint, Lang, Dict);
end;
if Obj is TSpeedButton then
begin
TSpeedButton(Obj).Caption:=Translate(TSpeedButton(Obj).Caption, Lang, Dict);
TSpeedButton(Obj).Hint:=Translate(TSpeedButton(Obj).Hint, Lang, Dict);
end;
if Obj is TPanel then
begin
TPanel(Obj).Caption:=Translate(TPanel(Obj).Caption, Lang, Dict);
TPanel(Obj).Hint:=Translate(TPanel(Obj).Hint, Lang, Dict);
end;
if Obj is TGroupBox then
begin
TGroupBox(Obj).Caption:=Translate(TGroupBox(Obj).Caption, Lang, Dict);
TGroupBox(Obj).Hint:=Translate(TGroupBox(Obj).Hint, Lang, Dict);
end;
if Obj is TLabel then
begin
TLabel(Obj).Caption:=Translate(TLabel(Obj).Caption, Lang, Dict);
TLabel(Obj).Hint:=Translate(TLabel(Obj).Hint, Lang, Dict);
end;
if Obj is TStaticText then
begin
TStaticText(Obj).Caption:=Translate(TStaticText(Obj).Caption, Lang, Dict);
TStaticText(Obj).Hint:=Translate(TStaticText(Obj).Hint, Lang, Dict);
end;
if Obj is TQRLabel then
begin
TQRLabel(Obj).Caption:=Translate(TQRLabel(Obj).Caption, Lang, Dict);
TQRLabel(Obj).Hint:=Translate(TQRLabel(Obj).Hint, Lang, Dict);
end;
if Obj is TEdit then
TEdit(Obj).Hint:=Translate(TEdit(Obj).Hint, Lang, Dict);
if Obj is TMaskEdit then
TMaskEdit(Obj).Hint:=Translate(TMaskEdit(Obj).Hint, Lang, Dict);
if Obj is TMemo then
TMemo(Obj).Hint:=Translate(TMemo(Obj).Hint, Lang, Dict);
if Obj is TRadioGroup then
begin
TRadioGroup(Obj).Caption:=Translate(TRadioGroup(Obj).Caption, Lang, Dict);
TRadioGroup(Obj).Hint:=Translate(TRadioGroup(Obj).Hint, Lang, Dict);
for J:=0 to TRadioGroup(Obj).Items.Count-1 do
begin
TRadioGroup(Obj).Items[j]:=Translate(TRadioGroup(Obj).Items[j], Lang, Dict);
end;
end;
if Obj is TCheckBox then
begin
TCheckBox(Obj).Caption:=Translate(TCheckBox(Obj).Caption, Lang, Dict);
TCheckBox(Obj).Hint:=Translate(TCheckBox(Obj).Hint, Lang, Dict);
end;
if Obj is TField then
TField(Obj).DisplayLabel:=Translate(TField(Obj).DisplayLabel, Lang, Dict);
if Obj is TTabSheet then
begin
TTabSheet(Obj).Caption:=Translate(TTabSheet(Obj).Caption, Lang, Dict);
TTabSheet(Obj).Hint:=Translate(TTabSheet(Obj).Hint, Lang, Dict);
end;
if Obj is TOpenDialog then
TOpenDialog(Obj).Title:=Translate(TOpenDialog(Obj).Title, Lang, Dict);
if Obj is TSaveDialog then
TSaveDialog(Obj).Title:=Translate(TSaveDialog(Obj).Title, Lang, Dict);
if Obj is TPrintDialog then
TPrintDialog(Obj).Title:=Translate(TPrintDialog(Obj).Title, Lang, Dict);
if Obj is TPrinterSetupDialog then
TPrinterSetupDialog(Obj).Title:=Translate(TPrinterSetupDialog(Obj).Title, Lang, Dict);
End;
{ освобождаем память}
Dict.Free;
end;
end.
Естественно, перед использованием модуля его
нужно добавить в оператор uses: uses ..., trans;
Примечания
1. Теперь нужно отметить особенность функции
Translate. Если слова нет в словаре, она его автоматически добавляет. Потом вам
только останется самому ввести перевод этого слова!
2. Напомню, что поиск словаря, так как он
является ini-файлом, по умолчанию производится в каталоге C:Windows (точнее, в
каталоге, возвращаемом функцией GetWindowsDirectory), поэтому предварительно
нужно поместить туда словарь или явно указать имя файла. При этом удобно
использовать функцию ExtractFileDir так: ExtractFileDir(Application.EXEName+'trans.dic')
3. Исходный код модуля-переводчика может
распространятся согласно положениям лицензии GPL, текст которой вы можете
прочитать на моем сайте – http://dkws.narod.ru/.
Посмотрим, что у нас вышло, как говорится, «до»
(см. рисунок 1) и «после» (см. рисунок 2).
Рисунок 1. «До»
Рисунок 2. «После»
|