По същество цялата задача се състои в това да си подмениш елементите на интерфейса, които са специфични за езика (надписи, картинки и други). Когато използваш INI файлове най-лесно ще е да имаш по един файл за всеки език. Изборът на език за интерфейса може да става или като потребителят избира един от файловете като го преименува, поставя в определена папка или нещо подобно, или пък в конфигурацията на програмата се задава от кой файл да си чете "преводите".
Съдържанието на INI файла може да ти бъде нещо от сорта на:
[Form1]
Buton1.Caption=Затваряне
Buton1.Hint=Изход от приложението
Label1.Caption=Изход от програмата
Picture1=BG_Logo.bmp
и т.н.
"Превеждането" на интерфейса на приложението в нашия случай може да стане така (по най-тривиалния начин):
procedure TForm1.FormShow(Sender: TObject);
begin
Button1.Caption := iniTranslations.ReadString('Form1', 'Button1.Caption', 'Изход');
Button1.Hint := iniTranslations.ReadString('Form1', 'Button1.Hint', 'Изход от програмата');
Label1.Caption := iniTranslations.ReadString('Form1', 'Label1.Caption', 'Изход');
Picture1.LoadFromFile(iniTranslations.ReadString('Form1', 'Picture1', 'BG_Logo.bmp'));
end;
С този пример само демонстрирам принципа на "превода". За реални приложения той е практически неприложим. Основните му недостатъци са, че при добавянето на компонент във формата програмистът трябва да се сети и да коригира кода за превод, а също така и размерът на кода за една по-сложна форма се получава бая голям и трудно ще се поддържа.
Един възможен изход от ситуацията е всяка форма да може да се превежда сама себе си. Ако имаш обща базова форма (форма, на която останалите да са ти наследници) можеш да си дефинираш един виртуален метод, който да обхожда всички контроли по формата и да ги "превежда". Ако нямаш общ родител - дефинирай си една процедурка някъде в някакво модулче, която да приема за параметър форма и да я превежда.
Обхождането на контролите на формата може да стане, като се ползват пропъртитата Controls и ControlCount. Проблемът обаче е, че ако имаш някакви контейнери (TPanel, TGroupBox, вложени форми и т.н.) техните контроли не влизат в този списък. Решението е ако при обхождането на списъка с контроли попаднем на наследник на TWinControl да обходим и неговите Controls (рекурсивно обхождаме всички контроли по формата). Ето една процедурка, която върши тая работа:
type
TtcCallBackMethod = procedure(Section: String; Control: TControl);
procedure TraverseControls(Section: String; Container: TWinControl; CallBackFunction: TtcCallBackMethod);
var
i: Integer;
Comp: TControl;
begin
for i := 0 to Container.ControlCount - 1 do
begin
Comp := Container.Controls[ i ]; //Все го забравям тоя таг... :-/
if (Comp is TWinControl) and (not (Comp is TCustomForm)) then
TraverseControls(Section, TWinControl(Comp), CallBackFunction);
CallBackFunction(Section, Comp);
end;
end;
Тази процедура ще обходи всичките ти контроли в подадената й форма и за всеки един от тях ще ти извика твоя метод, който си подал като параметър.
Той от своя страна трябва да провери какъв е този контрол и съответно да извлече неговите "преводи" от INI файла. Например:
procedure TranslateControl(Section: String; Control: TControl);
begin
if Control is TButton then
begin
(Control as TButton).Caption := iniTranslations.ReadString(Section, Control.Name + '.Caption', '');
(Control as TButton).Hint := iniTranslations.ReadString(Section, Control.Name + '.Hint', '');
end
else if Control is TImage then
begin
(Control as TImage).Picture.LoadFromFile(iniTranslations.ReadString(Section, Control.Name, ''));
end
else ...
...
...
...
end;
По този начин за да преведеш една форма трябва просто някъде от нея (например в OnShow събитието) да извикаш:
TraverseControls(Name, Self, TranslateControl);
По този код има какво да се подобри. Например в процедурата за "превеждане" на контрол можеш да правиш проверка дали в INI файла има такъв запис и ако го няма - да отбележиш това (например такава е ситуацията, когато в едно "преведено" вече приложение добавиш контрол в някоя форма. Например добавиш нов бутон).
Това решение също така не отчита някои други фактори на професионално направения многоезичен интерфейс. Например ширината на бутоните и т.н. Типичен пример - бутон "OK" на английски и "Потвърждение" на български. Познай дали в българската локализация текста ще се събере в бутона
Надявам се, че не съм те отегчил твърде много
Успех!
Редактирано от andrew_nikoloff на 19.03.07 22:14.