Подскажите, какой самый удобный компонент для локализации приложения?
Пробовал LanguageLoader из Globus Lib, но там неудобная структура файла словаря: Строка на языке 1=Строка на языке 2,
т.е. придется делать файлы словаря как RusToEng.lng, EngToRus.lng, RusToDe.lng и т.д. Или нужно было выставлять исходное значение свойства Caption, этим иожно было решить проблему, например:
for(int i=0;i<Form1->ComponentsCount; i++)
{
if(<Компонент имеет свойство Caption, но как это сделать?>)
Form1->Components[i]->Caption=Form1->Components[i]->Name; // <<<----- вот если бы так можно было
}
но так делать нельзя. замаялся уже. народ, помогите.
Здравствуйте, glitch, Вы писали:
G>Подскажите, какой самый удобный компонент для локализации приложения?
По моему, самый удобный — свой собственный. Есть вариант на основе ini-файлов Windows, есть на основе xml. Всё зависит от желания и возможностей.
G>for(int i=0;i<Form1->ComponentsCount; i++)
G>{
G>if(<Компонент имеет свойство Caption, но как это сделать?>)
G>Form1->Components[i]->Caption=Form1->Components[i]->Name; // <<<----- вот если бы так можно было
G>}
На Дельфи
type
TCrackControl = class (TControl)
published
property Caption;
end;
var
i: Integer;
C: TControl;
begin
for i := 0 to Form1.ComponentCount - 1 do
begin
C := Form1.Components[i];
if (C is TLabel) or (C is TForm) then
TCrackControl(C).Caption := 'Text';
end;
Есть две основные идеи: настраивать поля для каждого типа контролов отдельно, выделяя TLabel, TButton, etc., либо же определить своего потомка TControl, в котором следует изменить область видимости нужных для модификации свойств.
Вот, попробовал портировать код под CBuilder (я на нем пишу)
class TCrackControl : public TControl
{
__published:
__property Caption;
};
int i;
TComponent *Comp=new TComponent(this);
for(i;i<Form1->ComponentCount;i++)
{
Comp=Form1->Components[i];
if(AnsiString(Comp->ClassName())=="TLabel")
{
TCrackControl(Comp).Caption="text"; // строка на которую сыпятся все шишки
}
}
После компиляции выдает ошибку: Compiler could not generate default constructor for class 'TCrackControl'
И еще одну: VCL Classes must be constructed using operator 'new'
Попробовал заменить TCrackControl(Comp).Caption=="text"; на TControl(Comp).Caption=="text";
Ошибка: TControl::Caption is not accessible
Еще одна попытка, меняю сам класс:
class TCrackControl : public TControl
{
__published:
__property Caption;
public: __fastcall TCrackControl (TComponent *Comp)
};
Компилируется, но выдает ошибку Linker-а:
Unresolved external 'TCrackControl::' referenced from D:\BORLAND\CBUILDER6\PROJECTS\UNIT1.OBJ
Unresolved external '__fastcall TCrackControl::TCrackControl(Classes::TComponent *)' referenced from
D:BORLAND\CBUILDER6\PROJECTS\UNIT1.OBJ
The stars so gaily glistened... (Sat, 18 Oct 2003 13:58:31 GMT @623)
...while the fading voice of glitch whispered through the darkness:
g> Подскажите, какой самый удобный компонент для локализации приложения?
Есть XML-based в JVCL — хронически недоделанный.
Есть GNU GetText портированный на Delphi на SourceForge — не поддерживает
смену размеров кнопки, если надпись стала больше и прочее.
Есть нечто Глобусо-подобное в VG Lib 1 (www.vglib.com)
Наконец есть встроенная в Delphi система, но она не дает менять язык после
запуска программы.
А вообще — www.torry.ru — там их мнооого. И раз так много, значит
единственной и удобной нет.
--
If i had ears, i'd heard none: WinAMP de-instaled. http://Arioch.nm.ru/FL/Fidolook_SL.png Mail: the_Arioch<at>nm<dot>ru
Здравствуйте, glitch, Вы писали:
G>Подскажите, какой самый удобный компонент для локализации приложения?
Мне тоже придётся в ближайшем будущем столкнуться с такой задачей..
Мне видятся два варианта:
купить Multilizer: http://www.multilizer.com/
или обновить Delphi s Pro на Enterprise
Возникает вопрос: Пользовался кто-нибудь Мультилайзером и пользовался ли кто-нибудь встроенными в Delphi Enterprise средствами? Достаточно ли встроенных в Delphi средств? Можно ли разделить работу переводчика и программиста, как это сделано в Мультилайзере?
Здравствуйте, akasoft, Вы писали:
A>По моему, самый удобный — свой собственный. Есть вариант на основе ini-файлов Windows, есть на основе xml. Всё зависит от желания и возможностей.
A>
G>>for(int i=0;i<Form1->ComponentsCount; i++)
G>>{
G>>if(<Компонент имеет свойство Caption, но как это сделать?>)
G>>Form1->Components[i]->Caption=Form1->Components[i]->Name; // <<<----- вот если бы так можно было
G>>}
A>
A>На Дельфи
A>
A>type
A> TCrackControl = class (TControl)
A> published
A> property Caption;
A> end;
A>var
A> i: Integer;
A> C: TControl;
A>begin
A> for i := 0 to Form1.ComponentCount - 1 do
A> begin
A> C := Form1.Components[i];
A> if (C is TLabel) or (C is TForm) then
A> TCrackControl(C).Caption := 'Text';
A> end;
A>
A>Есть две основные идеи: настраивать поля для каждого типа контролов отдельно, выделяя TLabel, TButton, etc., либо же определить своего потомка TControl, в котором следует изменить область видимости нужных для модификации свойств.
Здравствуйте, 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
Здравствуйте, Dimonka, Вы писали:
D>Достаточно ли встроенных в Delphi средств?
Да.
D>Можно ли разделить работу переводчика и программиста, как это сделано в Мультилайзере?
Да. Внешнее приложение etmXX.exe. Предварительный просмотр форм (если нужно, например, расщирить/сузить размер компонетов, ...). Можно менять не только строки, но и, например, Font.CharecterSet.
Здравствуйте, Mystic, Вы писали:
D>>Можно ли разделить работу переводчика и программиста, как это сделано в Мультилайзере? M>Да. Внешнее приложение etmXX.exe. Предварительный просмотр форм (если нужно, например, расщирить/сузить размер компонетов, ...). Можно менять не только строки, но и, например, Font.CharecterSet.
Ещё один вопрос — с какой версии Дельпхи все эти чудеса доступны?