Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Многоязычный интерфейс приложений в Delphi

Автор: Денис Колисниченко, dhsilabs@mail.ru
Оригинал: www.softerra.ru

Наверняка, вам хоть раз в жизни приходилось разрабатывать многоязычное приложение. Например, вам нужно, чтобы ваше приложение "ругалось" как на английском, так и на русском языке. В таком случае, обычно, один язык встраивается в приложение, как правило, английский, а потом пользователю предоставляется возможность выбрать язык интерфейса программы.

Для этих целей существует много коммерческих и бесплатных компонент-переводчиков, однако использовать их довольно неудобно, поскольку, необходимо помещать копию компонента на каждую форму приложения. Я предлагаю совершенно другой подход, а именно - использовать модуль-переводчик, который будет переводить все формы приложения. При достаточно высокой скорости перевода интерфейса, размер программы увеличиться всего на 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. "После"

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
91K
17 августа 2013 года
Андрей Криль
0 / / 17.08.2013
Мне нравитсяМне не нравится
17 августа 2013, 19:45:47
идея супер. ещё статьи!
2.
Аноним
Мне нравитсяМне не нравится
7 апреля 2006, 03:45:23
...я писал прогу с языковой поддержкой интерфейса на трех (!!!) языках. Также использовал ini-файлы... но в моем случае можно было менять язык в любое время выполнения программы... было использовано что-то вроде словаря...
3.
Аноним
Мне нравитсяМне не нравится
13 марта 2006, 15:37:20
с английского на русский переключились.. а обратно на английский?
а если языков несколько?
Идея правильная, только требует доработки
4.
Аноним
+1 / -0
Мне нравитсяМне не нравится
10 марта 2006, 13:29:40
А попроще ничего не вышло выдумать? Словари составлять... Проще сохранить все сообщения програмы и менюшки в txt, или dll файле, а потом подгружать соответствующий языку файл при клике на кнопке смены языка...
5.
Аноним
+0 / -1
Мне нравитсяМне не нравится
3 марта 2006, 15:23:21
Выглядит внугительно надо будет позаимствовать идейку....;)
6.
Аноним
+1 / -1
Мне нравитсяМне не нравится
26 мая 2005, 21:58:41
Чувак ты молодец, продолжай в том же духе!!!
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог