Здравствуйте, glitch, Вы писали:
G>Подскажите, какой самый удобный компонент для локализации приложения?
G>Пробовал LanguageLoader из Globus Lib, но там неудобная структура файла словаря: Строка на языке 1=Строка на языке 2,
G>т.е. придется делать файлы словаря как RusToEng.lng, EngToRus.lng, RusToDe.lng и т.д. Или нужно было выставлять исходное значение свойства Caption, этим иожно было решить проблему, например:
G>for(int i=0;i<Form1->ComponentsCount; i++)
G>{
G>if(<Компонент имеет свойство Caption, но как это сделать?>)
G>Form1->Components[i]->Caption=Form1->Components[i]->Name; // <<<----- вот если бы так можно было
G>}
G>но так делать нельзя. замаялся уже. народ, помогите.
Попробуйте использовать RTTI + маленько фантазии
приведу пример — готовый рабочий юнит, автоматизированный перевод формы без всяких заморочек
unit translate;
interface
uses SysUtils, Classes, Forms, IniFiles, ActnList;
function TranslateProp(Dict : TIniFile; ASection, AIdent1, AIdent2 : string;
var AValue : string): boolean;
procedure TranslateFormControls(AForm : TForm; ADictFileName : string;
isTranslateCaption : boolean = True);
implementation
uses TypInfo, Msg;
//Возвращаем строку где ## заменяются назад как и було ентерами(переводами строк)
function GetTextWithReturn(AText: String): string;
begin
Result:=StringReplace(AText, '##', #13+#10,[rfReplaceAll]+[rfIgnoreCase]);
end;
//если в строке есть перевод каретки то его заменяем на ##
// для чего - в ини-файл без этого никак
function SetTextWithReturn(AText: String): string;
begin
Result:=StringReplace(AText, #13+#10, '##',[rfReplaceAll]+[rfIgnoreCase]);
end;
function TranslateProp(Dict : TIniFile; ASection, AIdent1, AIdent2 : string;
var AValue : string): boolean;
begin
Result:=False;
try
if AIdent1='' then Exit;
AValue:=Dict.ReadString(ASection, AIdent1+'.'+AIdent2, '');
if AValue='' then Dict.WriteString(ASection, AIdent1+'.'+AIdent2, '')
else Result:=True;
except
end;
end;
procedure TranslateFormControls(AForm : TForm; ADictFileName : string;
isTranslateCaption : boolean = True);
var Dict : TIniFile;
I : Integer;
Obj : TComponent;
PropInfo1 : PPropInfo;
PropInfo2 : PPropInfo;
AValue : string;
begin
try
Dict:=TIniFile.Create(ExtractFilePath(ParamStr(0))+ADictFileName);
if not FileExists(ExtractFilePath(ParamStr(0))+ADictFileName) then Exit;
{Если нужно переводить заголовок формы то}
if isTranslateCaption and TranslateProp(Dict, AForm.Name ,'Form','Caption', AValue) then
AForm.Caption:=AValue;
{ Переводим заголовки компонентов формы}
for I:=0 to AForm.ComponentCount-1 do
begin
Obj:=AForm.Components[i];
PropInfo1:=GetPropInfo(Obj.ClassInfo, 'Action');
if (PropInfo1=nil) or
((PropInfo1<>nil) and (PropInfo1.PropType^.Kind = tkClass)
and (GetObjectProp(Obj, 'Action', TAction)=nil)) then
begin
PropInfo2:=GetPropInfo(Obj.ClassInfo, 'Caption');
if PropInfo2<>nil then
begin
if (PropInfo2^.PropType^.Kind=tkLString) and ((GetStrProp(Obj, 'Caption')<>'')
and (GetStrProp(Obj, 'Caption')<>'-')) then
if TranslateProp(Dict, AForm.Name ,Obj.Name, 'Caption', AValue) then
SetStrProp(Obj, PropInfo2, AValue);
end;
PropInfo2:=GetPropInfo(Obj.ClassInfo, 'Hint');
if PropInfo2<>nil then
begin
if (PropInfo2^.PropType^.Kind=tkLString) and (GetStrProp(Obj, 'Hint')<>'')then
if TranslateProp(Dict, AForm.Name ,Obj.Name,'Hint', AValue) then
SetStrProp(Obj, PropInfo2, GetTextWithReturn(AValue));
end;
end;
PropInfo2:=GetPropInfo(Obj.ClassInfo, 'Title');
if PropInfo2<>nil then
begin
if (PropInfo2^.PropType^.Kind=tkLString) and (GetStrProp(Obj, 'Title')<>'')then
if TranslateProp(Dict, AForm.Name ,Obj.Name,'Title', AValue) then
SetStrProp(Obj, PropInfo2, AValue);
end;
PropInfo2:=GetPropInfo(Obj.ClassInfo, 'Filter');
if PropInfo2<>nil then
begin
if (PropInfo2^.PropType^.Kind=tkLString) and (GetStrProp(Obj, 'Filter')<>'')then
if TranslateProp(Dict, AForm.Name ,Obj.Name,'Filter', AValue) then
SetStrProp(Obj, PropInfo2, AValue);
end;
end;
Dict.Free;
except
// ShowMessage('Language file is not loaded!');
end;
end;
Для перевода формы в OnCreate вставьте
TranslateFormControls(Self,LanguageFileName);
//procedure TranslateFormControls(AForm : TForm; ADictFileName : string;
// isTranslateCaption : boolean = True);
где
LanguageFileName — имя файла с переводом, должен находится в том же каталоге что и EXE
параметр isTranslateCaption нужен для того чтобы заголовок формы не переводить (иногда нужно)
Файл перевода — это обычный ини-файл, имя и расширение — по вашему вкусу
откомпилите и запустите программу,для того чтобы в с файлом перевода что-то произошло нужно открыть ту форму в которой есть вызов TranslateFormControls (если это главная форма, то все естественно произойдет при запуске)
потом откройте файл с названием LanguageFileName текстовым редактором.
откройте и увидите: о чудо, перед вами заготовка для перевода
а смысл процедуры такой, она проверяет если у контрола есть свойство Caption то она считывает одноименный параметр из файла перевода, если в такого параметра в файле перевода нет, то она его создаст с пустым значением,
и так с некоторыми другими свойствами
потом открываете текстовым редактором и вперед, даешь перевод,
исключение здесь составляет только следующее:
процедура не переводит объекты с Caption:='-', то есть сепараторы в меню // зачем их переводить
и если у объекта есть не пустое свойство Action, // она все равно Actionы все переведет, нет смысла переводит control который Caption и некоторые другие свойства получает от Action
Пользуйте однако!
Примечание: Юнит приведен маленько в подрезанном виде //убраны специфичные функции, абсолютно здесь не нужные.
если что и не работает подправьте, а то я мог чего-нибудь вырезать лишнего
на
http://www.galera.narod.ru программа CDBase использует этот юнит
юнит написан недавно как раз для целей перевода, но несколько не удобен в плане
если называть объекты по своему, то переводчик не разберет чего и где
если называть понятно для переводчика, то программисту неудобно
(в CDBase как раз второй случай, сильно запущенный)
поэтому юнит хочется переделать, есть несколько задумок,
если кто хочет присоединиться, буду рад обменяться дельными мысля'ми.
пишите galera@narod.ru