Приветствую Вас Гость | RSS

Меню сайта

Реклама

Категории раздела
BIOS [8]
DOS и Консоль [0]
Kylix [0]
Windows [0]
Аудиокарта и Видеокарта [0]
Буфер обмена [0]
Драйвера [1]
Клавиши [0]
Компьютер [0]
Монитор и Экран [0]
Мышка и Курсор [0]
Переменные окружения [0]
Принтеры и Печать [0]
Процессор [0]
Реестр [0]
Сканер [0]
Сообщения Windows [0]
Справочник по сообщениям [0]
Язык [17]

Наш опрос
Какие компоненты добавлять больше?
Всего ответов: 46

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Форма входа

Главная » Статьи » ОС и Железо » Язык

Поддержка многоязычного интерфейса

Подчас бывает актуально встроить в разрабатываемую программу поддержку нескольких языков. Существует множество средств и компонентов для осуществления подобных задач. У всех этих средств один недостаток - они слишком сложны и тяжеловесны. Предлагаем рассмотреть, как можно обеспечить поддержку многоязычности используя более простой и прозрачный метод.

Первое, что нужно выяснить - это язык, на котором разрабатывать интерфейс первоначально. Есть веские причины за то, чтобы использовать для этого именно тот язык, на котором написана эта статья. Дело в том, что русский язык менее лаконичен других европейских языков. При переводе на английский или немецкий 90% фраз будет компактнее и интерфейс вашей программы искажен не будет.

Для поддержки нескольких языков предлагается следующий простой подход. Интерфейс оформляется на родном языке - русском. Для всех остальных языков составляется словарь в виде:


Строка на языке 1=Строка на языке 2
Строка на языке 1=Строка на языке 2

Например:


Файл=File
Выход=Exit
Отмена=Cancel

И так для всех ресурсов приложения. Словарь поместим в отдельный текстовый файл.

Далее, нам необходимо для каждого текстового свойства любого компонента приложения поискать перевод в нашем словаре. Здесь не обойтись без Delphi RTTI. Через Component.ClassInfo получим ссылку на информацию типа, а затем GetTypeData(TypeInf) даст нам указатель на структуру с его описанием.


TypeInf := Component.ClassInfo;
AName := TypeInf^.name;
TypeData := GetTypeData(TypeInf);
NumProps := TypeData^.PropCount;

Далее проходимся по всем свойствам данного (классового) типа:


GetMem(PropList, NumProps * sizeof(pointer));

try
GetPropInfos(TypeInf, PropList);

for i := 0 to NumProps-1 do
begin
PropName := PropList^[i]^.name;

PropTypeInf := PropList^[i]^.PropType^;
PropInfo := PropList^[i];


case PropTypeInf^.Kind of
tkString, tkLString: //... это то, что нам нужно
if PropName <> 'Name' then { Переводить свойство Name не следует }
begin
{ Получение значения свойства и поиск перевода в словаре }
StringPropValue := GetStrProp(Component, PropInfo);
SetStrProp(Component, PropInfo, TranslateString(StringPropValue));
end;
...
...

Отдельный случай - списки TStrings и коллекции типа TTReeNodes и TListItems. Их придется обработать персонально.


tkClass:
begin
PropObject := GetObjectProp(Component, PropInfo{, TPersistent});

if Assigned(PropObject)then
begin
{ Для дочерних свойств-классов вызов просмотра свойств }
if (PropObject is TPersistent) then
UpdateComponent(PropObject as TPersistent);

{ Индивидуальный подход к некоторым классам }
if (PropObject is TStrings) then
begin
for j := 0 to (PropObject as TStrings).Count-1 do
TStrings(PropObject)[j] := TranslateString(TStrings(PropObject)[j]);
end;
if (PropObject is TTreeNodes) then
begin
for j := 0 to (PropObject as TTreeNodes).Count-1 do
TTreeNodes(PropObject).Item[j].Text :=
TranslateString(TTreeNodes(PropObject).Item[j].Text);
end;
if (PropObject is TListItems) then
begin
for j := 0 to (PropObject as TListItems).Count-1 do
TListItems(PropObject).Item[j].Caption
:= TranslateString(TListItems(PropObject).Item[j].Caption);
end;
{ Здесь можно добавить обработку остальных классов }
end;

end;

Объединяя все написанное, получим компонент для перевода строковых ресурсов.


unit glLanguageLoader;

interface
{$I glDEF.INC}

uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs, comctrls, grids;

type
TLanguageLoaderOptions = set of (lofTrimSpaces);
{опция удаления начальных и завершающих пробелов}

TglLanguageLoader = class(TComponent)
private
sl: TStringList;
FOptions: TLanguageLoaderOptions;
function TranslateString(sString: string): string;
protected
procedure UpdateComponent(Component: TPersistent); virtual;
public
{main function}
procedure LoadLanguage(Component: TComponent; FileName: string);
published
property Options: TLanguageLoaderOptions read FOptions write FOptions;
end;

procedure LoadLanguage(Component: TComponent; FileName: string;
Options: TLanguageLoaderOptions);
procedure register;

implementation

uses
TypInfo, dsgnintf;

procedure register;
begin
RegisterComponents('Gl Components', [TglLanguageLoader]);
end;

{Ф-ия для загрузки словаря без предварительного создания компонента}
procedure LoadLanguage(Component: TComponent; FileName: string;
Options: TLanguageLoaderOptions);
var
LanguageLoader: TglLanguageLoader;
begin
LanguageLoader := TglLanguageLoader.Create(nil);
try
LanguageLoader.LoadLanguage(Component, FileName);
finally
LanguageLoader.Free;
end;
end;

{ TglLanguageLoader }

{ Загрузка словаря, обход указанного компонента и }
{ всех его дочерних компонентов }
procedure TglLanguageLoader.LoadLanguage(Component: TComponent; FileName: string);

procedure UpdateAllComponents(Component: TComponent);
var
i: integer;
begin
{ обработка своцств компонента }
UpdateComponent(Component);
for i := 0 to Component.ComponentCount-1 do
UpdateAllComponents(Component.Components[i]);
end;

begin
sl := TStringList.Create;
try
{ Загрузка словаря из заданного файла }
sl.LoadFromFile(FileName);
sl.Sorted := true;
UpdateAllComponents(Component);
finally
sl.Free;
end;
end;

{ Проход по всем свойствам компонента }
{ Для всех строковых свойств - загрузка перевода из сооваря }
procedure TglLanguageLoader.UpdateComponent(Component: TPersistent);
var
PropInfo: PPropInfo;
TypeInf, PropTypeInf: PTypeInfo;
TypeData: PTypeData;
i, j: integer;
AName, PropName, StringPropValue: string;
PropList: PPropList;
NumProps: word;
PropObject: TObject;
begin
{ Playing with RTTI }
TypeInf := Component.ClassInfo;
AName := TypeInf^.name;
TypeData := GetTypeData(TypeInf);
NumProps := TypeData^.PropCount;

GetMem(PropList, NumProps*sizeof(pointer));

try
GetPropInfos(TypeInf, PropList);

for i := 0 to NumProps-1 do
begin
PropName := PropList^[i]^.name;

PropTypeInf := PropList^[i]^.PropType^;
PropInfo := PropList^[i];


case PropTypeInf^.Kind of
tkString, tkLString:
if PropName <> 'Name' then { Переводить свойство Name не следует }
begin
{ Получение значения свойства и поиск перевода в словаре }
StringPropValue := GetStrProp( Component, PropInfo );
SetStrProp( Component, PropInfo, TranslateString(StringPropValue) );
end;
tkClass:
begin
PropObject := GetObjectProp(Component, PropInfo{, TPersistent});
if Assigned(PropObject)then
begin
{ Для дочерних свойств-классов вызов просмотра свойств }
if (PropObject is TPersistent) then
UpdateComponent(PropObject as TPersistent);

{ Индивидуальный подход к некоторым классам }
if (PropObject is TStrings) then
begin
for j := 0 to (PropObject as TStrings).Count-1 do
TStrings(PropObject)[j] := TranslateString(TStrings(PropObject)[j]);
end;
if (PropObject is TTreeNodes) then
begin
for j := 0 to (PropObject as TTreeNodes).Count-1 do
TTreeNodes(PropObject).Item[j].Text :=
TranslateString(TTreeNodes(PropObject).Item[j].Text);
end;
if (PropObject is TListItems) then
begin
for j := 0 to (PropObject as TListItems).Count-1 do
TListItems(PropObject).Item[j].Caption :=
TranslateString(TListItems(PropObject).Item[j].Caption);
end;
{ Здесь можно добавить обработку остальных классов }
end;
end;
end;
end;
finally
FreeMem(PropList, NumProps*sizeof(pointer));
end;
end;

{ Поиск перевода для заданной строки в словаре }
function TglLanguageLoader.TranslateString(sString: string): string;
begin
if lofTrimSpaces in Options then
sString := trim(sString);
if sString = '' then
begin
Result := '';
exit;
end;
if sl.IndexOfName(sString) <> -1 then
Result := sl.Values[sString]
else
Result := sString;
end;

end.

Категория: Язык | Добавил: Skinner (11.09.2008)
Просмотров: 766 | Рейтинг: 5.0/1
  Delphi Lab   Главная   Регистрация   Вход  
Интересная Цитата

Поиск

Магазин


Copyright MyCorp © 2024 Хостинг от uCoz