📄 gnugettext.pas
字号:
end;
function TGnuGettextInstance.dgettext(const szDomain: string;
const szMsgId: widestring): widestring;
begin
if not Enabled then begin
Result:=szMsgId;
exit;
end;
if DLLisLoaded then begin
{$ifdef LINUX}
Result := utf8decode(StrPas(Libc.dgettext(PChar(szDomain), PChar(utf8encode(szMsgId)))));
{$endif}
{$ifdef MSWINDOWS}
Result := utf8decode(LF2LineBreakA(StrPas(pdgettext(PChar(szDomain), PChar(StripCR(utf8encode((szMsgId))))))));
{$endif}
end else begin
Result:=UTF8Decode(LF2LineBreakA(getdomain(domainlist,szDomain,DefaultDomainDirectory,CurLang).gettext(StripCR(utf8encode(szMsgId)))));
end;
if (szMsgId<>'') and (Result='') then
raise Exception.Create (Format('Error: Could not translate %s. Probably because the mo file doesn''t contain utf-8 encoded translations.',[szMsgId]));
if (Result = szMsgId) and (szDomain = DefaultTextDomain) then
SaveCheck(szMsgId);
end;
function TGnuGettextInstance.GetCurrentLanguage: string;
begin
Result:=curlang;
end;
function TGnuGettextInstance.getcurrenttextdomain: string;
begin
if DLLisLoaded then begin
{$ifdef LINUX}
Result := StrPas(Libc.textdomain(nil));
{$endif}
{$ifdef MSWINDOWS}
Result := StrPas(ptextdomain(nil));
{$endif}
end else
Result := curmsgdomain;
end;
function TGnuGettextInstance.gettext(
const szMsgId: widestring): widestring;
begin
Result := dgettext(curmsgdomain, szMsgId);
end;
procedure TGnuGettextInstance.SaveCheck(szMsgId: widestring);
var
i: integer;
begin
savefileCS.BeginWrite;
try
if (savememory <> nil) and (szMsgId <> '') then begin
if not savememory.Find(szMsgId, i) then begin
savememory.Add(szMsgId);
Writeln(savefile, 'msgid ' + string2csyntax(utf8encode(szMsgId)));
writeln(savefile, 'msgstr ""');
writeln(savefile);
end;
end;
finally
savefileCS.EndWrite;
end;
end;
procedure TGnuGettextInstance.SaveUntranslatedMsgids(filename: string);
begin
// If this happens, it is an internal error made by the programmer.
if savememory <> nil then
raise Exception.Create(_('You may not call SaveUntranslatedMsgids twice in this program.'));
AssignFile(savefile, filename);
Rewrite(savefile);
writeln(savefile, 'msgid ""');
writeln(savefile, 'msgstr ""');
writeln(savefile);
savememory := TStringList.Create;
savememory.Sorted := true;
end;
procedure TGnuGettextInstance.textdomain(const szDomain: string);
begin
curmsgdomain := szDomain;
{$ifdef LINUX}
Libc.textdomain(PChar(szDomain));
{$endif}
{$ifdef MSWINDOWS}
if DLLisLoaded then begin
ptextdomain(PChar(szDomain));
end;
{$endif}
end;
function TGnuGettextInstance.TP_CreateRetranslator : TExecutable;
var
ttpr:TTP_Retranslator;
begin
ttpr:=TTP_Retranslator.Create;
ttpr.Instance:=self;
TP_Retranslator:=ttpr;
Result:=ttpr;
end;
procedure TGnuGettextInstance.TP_GlobalHandleClass(HClass: TClass;
Handler: TTranslator);
var
cm:TClassMode;
i:integer;
begin
for i:=0 to TP_ClassHandling.Count-1 do begin
cm:=TObject(TP_ClassHandling.Items[i]) as TClassMode;
if cm.HClass=HClass then
raise Exception.Create ('You cannot set a handler for a class that has already been assigned otherwise.');
if HClass.InheritsFrom(cm.HClass) then begin
// This is the place to insert this class
cm:=TClassMode.Create;
cm.HClass:=HClass;
cm.SpecialHandler:=Handler;
TP_ClassHandling.Insert(i,cm);
exit;
end;
end;
cm:=TClassMode.Create;
cm.HClass:=HClass;
cm.SpecialHandler:=Handler;
TP_ClassHandling.Add(cm);
end;
procedure TGnuGettextInstance.TP_GlobalIgnoreClass(IgnClass: TClass);
var
cm:TClassMode;
i:integer;
begin
for i:=0 to TP_ClassHandling.Count-1 do begin
cm:=TObject(TP_ClassHandling.Items[i]) as TClassMode;
if cm.HClass=IgnClass then
raise Exception.Create ('You cannot add a class to the ignore list that is already on that list: '+IgnClass.ClassName);
if IgnClass.InheritsFrom(cm.HClass) then begin
// This is the place to insert this class
cm:=TClassMode.Create;
cm.HClass:=IgnClass;
TP_ClassHandling.Insert(i,cm);
exit;
end;
end;
cm:=TClassMode.Create;
cm.HClass:=IgnClass;
TP_ClassHandling.Add(cm);
end;
procedure TGnuGettextInstance.TP_GlobalIgnoreClassProperty(
IgnClass: TClass; propertyname: string);
var
cm:TClassMode;
i:integer;
begin
propertyname:=uppercase(propertyname);
for i:=0 to TP_ClassHandling.Count-1 do begin
cm:=TObject(TP_ClassHandling.Items[i]) as TClassMode;
if cm.HClass=IgnClass then begin
if Assigned(cm.SpecialHandler) then
raise Exception.Create ('You cannot ignore a class property for a class that has a handler set.');
cm.PropertiesToIgnore.Add(propertyname);
exit;
end;
if IgnClass.InheritsFrom(cm.HClass) then begin
// This is the place to insert this class
cm:=TClassMode.Create;
cm.HClass:=IgnClass;
cm.PropertiesToIgnore.Add(propertyname);
TP_ClassHandling.Insert(i,cm);
exit;
end;
end;
cm:=TClassMode.Create;
cm.HClass:=IgnClass;
cm.PropertiesToIgnore.Add(propertyname);
TP_ClassHandling.Add(cm);
end;
procedure TGnuGettextInstance.TP_Ignore(AnObject: TObject;
const name: string);
begin
TP_IgnoreList.Add(uppercase(name));
end;
procedure TGnuGettextInstance.TranslateComponent(AnObject: TComponent;
TextDomain: string);
var
comp:TGnuGettextComponentMarker;
begin
comp:=AnObject.FindComponent('GNUgettextMarker') as TGnuGettextComponentMarker;
if comp=nil then begin
comp:=TGnuGettextComponentMarker.Create (nil);
comp.Name:='GNUgettextMarker';
comp.Retranslator:=TP_CreateRetranslator;
TranslateProperties (AnObject, TextDomain);
AnObject.InsertComponent(comp);
end else begin
if comp.LastLanguage<>curlang then begin
comp.Retranslator.Execute;
end;
end;
comp.LastLanguage:=curlang;
end;
procedure TGnuGettextInstance.TranslateProperty (AnObject:TObject; PropInfo:PPropInfo; TodoList:TStrings; TextDomain:string);
var
ppi:PPropInfo;
ws: WideString;
old: WideString;
obj:TObject;
sl:TStrings;
i, k:integer;
Propname:string;
begin
PropName:=PropInfo^.Name;
try
// Translate certain types of properties
case PropInfo^.PropType^.Kind of
tkString, tkLString, tkWString:
begin
old := GetWideStrProp(AnObject, PropName);
if (old <> '') and (IsWriteProp(PropInfo)) then begin
if TP_Retranslator<>nil then
(TP_Retranslator as TTP_Retranslator).Remember(AnObject, PropName, old);
ws := dgettext(textdomain,old);
if ws <> old then begin
ppi:=GetPropInfo(AnObject, Propname);
if ppi=nil then
raise Exception.Create ('Property disappeared...');
SetWideStrProp(AnObject, ppi, ws);
end;
end;
end { case item };
tkClass:
begin
obj:=GetObjectProp(AnObject, PropName);
if obj<>nil then begin
// Check the global class ignore list
for k:=0 to TP_ClassHandling.Count-1 do begin
if AnObject.InheritsFrom(TClass(TP_ClassHandling.Items[k])) then
exit;
end;
// Check for TStrings translation
if obj is TStrings then begin
sl:=obj as TStrings;
if (sl.Text<>'') and (TP_Retranslator<>nil) then
(TP_Retranslator as TTP_Retranslator).Remember(obj, 'Text', sl.Text);
TranslateStrings (sl,TextDomain);
end else
// Check for TCollection
if obj is TCollection then
for i := 0 to TCollection(obj).Count - 1 do
TodoList.AddObject('',TCollection(obj).Items[i]);
// Check for TComponent
if obj is TComponent then
TodoList.AddObject ('',obj);
end { if not nil };
end { case item };
end { case };
except
on E:Exception do
raise Exception.Create ('Property cannot be translated.'+sLineBreak+
'Use TP_GlobalIgnoreClassProperty('+AnObject.ClassName+','+PropName+') or'+sLineBreak+
'TP_Ignore (self,''.'+PropName+''') to prevent this message.'+sLineBreak+
'Reason: '+e.Message);
end;
end;
procedure TGnuGettextInstance.TranslateProperties(AnObject: TObject; textdomain:string='');
var
TodoList:TStringList; // List of Name/TObject's that is to be processed
DoneList:TStringList; // List of hex codes representing pointers to objects that have been done
i, j, Count: integer;
PropList: PPropList;
UPropName: string;
PropInfo: PPropInfo;
comp:TComponent;
cm,currentcm:TClassMode;
ObjectPropertyIgnoreList:TStringList;
objid, Name:string;
begin
if textdomain='' then
textdomain:=curmsgdomain;
if TP_Retranslator<>nil then
(TP_Retranslator as TTP_Retranslator).TextDomain:=textdomain;
DoneList:=TStringList.Create;
TodoList:=TStringList.Create;
ObjectPropertyIgnoreList:=TStringList.Create;
try
TodoList.AddObject('', AnObject);
DoneList.Sorted:=True;
ObjectPropertyIgnoreList.Sorted:=True;
ObjectPropertyIgnoreList.Duplicates:=dupIgnore;
ObjectPropertyIgnoreList.CaseSensitive:=False;
DoneList.Duplicates:=dupError;
DoneList.CaseSensitive:=True;
while TodoList.Count<>0 do begin
AnObject:=TodoList.Objects[0];
Name:=TodoList.Strings[0];
TodoList.Delete(0);
if AnObject<>nil then begin
// Make sure each object is only translated once
Assert (sizeof(integer)=sizeof(TObject));
objid:=IntToHex(integer(AnObject),8);
if DoneList.Find(objid,i) then begin
continue;
end else begin
DoneList.Add(objid);
end;
ObjectPropertyIgnoreList.Clear;
// Find out if there is special handling of this object
currentcm:=nil;
for j:=0 to TP_ClassHandling.Count-1 do begin
cm:=TObject(TP_ClassHandling.Items[j]) as TClassMode;
if AnObject.InheritsFrom(cm.HClass) then begin
if cm.PropertiesToIgnore.Count<>0 then begin
ObjectPropertyIgnoreList.AddStrings(cm.PropertiesToIgnore);
end else begin
currentcm:=cm;
break;
end;
end;
end;
if currentcm<>nil then begin
ObjectPropertyIgnoreList.Clear;
// Ignore or use special handler
if Assigned(currentcm.SpecialHandler) then
currentcm.SpecialHandler (AnObject);
continue;
end;
Count := GetPropList(AnObject, PropList);
try
for j := 0 to Count - 1 do begin
PropInfo := PropList[j];
UPropName:=uppercase(PropInfo^.Name);
// Ignore properties that are meant to be ignored
if ((currentcm=nil) or (not currentcm.PropertiesToIgnore.Find(UPropName,i))) and
(not TP_IgnoreList.Find(Name+'.'+UPropName,i)) and
(not ObjectPropertyIgnoreList.Find(UPropName,i)) then begin
TranslateProperty (AnObject,PropInfo,TodoList,TextDomain);
end; // if
end; // for
finally
if Count<>0 then
FreeMem (PropList);
end;
if AnObject is TStrings then begin
TranslateStrings (AnObject as TStrings,TextDomain);
end;
if AnObject is TComponent then
for i := 0 to TComponent(AnObject).ComponentCount - 1 do begin
comp:=TComponent(AnObject).Components[i];
if not TP_IgnoreList.Find(uppercase(comp.Name),j) then begin
TodoList.AddObject(uppercase(comp.Name),comp);
end;
end;
end { if AnObject<>nil };
end { while todolist.count<>0 };
finally
FreeAndNil (todolist);
FreeAndNil (ObjectPropertyIgnoreList);
FreeAndNil (DoneList);
end;
TP_IgnoreList.Clear;
TP_Retranslator:=nil;
end;
procedure TGnuGettextInstance.UseLanguage(LanguageCode: string);
var
i,p:integer;
dom:TDomain;
l2:string[2];
begin
if LanguageCode='' then begin
LanguageCode:=GGGetEnvironmentVariable('LANG');
{$ifdef MSWINDOWS}
if LanguageCode='' then
LanguageCode:=GetWindowsLanguage;
{$endif}
p:=pos('.',LanguageCode);
if p<>0 then
LanguageCode:=copy(LanguageCode,1,p-1);
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -