📄 gnugettext.pas
字号:
function GetPluralForm3PL(Number: Integer): Integer;
var
n1,n2:byte;
begin
Number:=abs(Number);
n1:=Number mod 10;
n2:=Number mod 100;
if n1=1 then Result:=0
else if (n1>=2) and (n1<=4) and ((n2<10) or (n2>=20)) then Result:=1
else Result:=2;
end;
function GetPluralForm3RU(Number: Integer): Integer;
var
n1,n2:byte;
begin
Number:=abs(Number);
n1:=Number mod 10;
n2:=Number mod 100;
if (n1=1) and (n2<>11) then
Result:=0
else
if (n1>=2) and (n1<=4) and ((n2<10) or (n2>=20)) then Result:=1
else Result:=2;
end;
function GetPluralForm4SL(Number: Integer): Integer;
var
n2:byte;
begin
Number:=abs(Number);
n2:=Number mod 100;
if n2=1 then Result:=0
else
if n2=2 then Result:=1
else
if (n2=3) or (n2=4) then Result:=2
else
Result:=3;
end;
procedure TDomain.GetListOfLanguages(list: TStrings);
var
sr:TSearchRec;
more:boolean;
filename, path, langcode:string;
i, j:integer;
begin
list.Clear;
// Iterate through filesystem
more:=FindFirst (Directory+'*',faAnyFile,sr)=0;
try
while more do begin
if (sr.Attr and faDirectory<>0) and (sr.name<>'.') and (sr.name<>'..') then begin
filename := Directory + sr.Name + PathDelim + 'LC_MESSAGES' + PathDelim + domain + '.mo';
if fileexists(filename) then begin
langcode:=lowercase(sr.name);
if list.IndexOf(langcode)=-1 then
list.Add(langcode);
end;
end;
more:=FindNext (sr)=0;
end;
finally
FindClose (sr);
end;
// Iterate through embedded files
for i:=0 to FileLocator.filelist.Count-1 do begin
filename:=FileLocator.basedirectory+FileLocator.filelist.Strings[i];
path:=Directory;
{$ifdef MSWINDOWS}
path:=uppercase(path);
filename:=uppercase(filename);
{$endif}
j:=length(path);
if copy(filename,1,j)=path then begin
path:=PathDelim + 'LC_MESSAGES' + PathDelim + domain + '.mo';
{$ifdef MSWINDOWS}
path:=uppercase(path);
{$endif}
if copy(filename,length(filename)-length(path)+1,length(path))=path then begin
langcode:=lowercase(copy(filename,j+1,length(filename)-length(path)-j));
langcode:=copy(langcode,1,3)+uppercase(copy(langcode,4,maxint));
if list.IndexOf(langcode)=-1 then
list.Add(langcode);
end;
end;
end;
end;
procedure TDomain.SetFilename(const filename: string);
begin
CloseMoFile;
vDirectory := '';
SpecificFilename:=filename;
end;
function TDomain.gettext(const msgid: ansistring): ansistring;
var
found:boolean;
begin
if not Enabled then begin
Result:=msgid;
exit;
end;
if (mofile=nil) and (not OpenHasFailedBefore) then
OpenMoFile;
if mofile=nil then begin
{$ifdef DXGETTEXTDEBUG}
DebugLogger('.mo file is not open. Not translating "'+msgid+'"');
{$endif}
Result := msgid;
end else begin
Result:=mofile.gettext(msgid,found);
{$ifdef DXGETTEXTDEBUG}
if found then
DebugLogger ('Found in .mo ('+Domain+'): "'+utf8encode(msgid)+'"->"'+utf8encode(Result)+'"')
else
DebugLogger ('Translation not found in .mo file ('+Domain+') : "'+utf8encode(msgid)+'"');
{$endif}
end;
end;
constructor TDomain.Create;
begin
inherited Create;
Enabled:=True;
end;
{ TGnuGettextInstance }
procedure TGnuGettextInstance.bindtextdomain(const szDomain,
szDirectory: string);
var
dir:string;
begin
dir:=IncludeTrailingPathDelimiter(szDirectory);
{$ifdef DXGETTEXTDEBUG}
DebugWriteln ('Text domain "'+szDomain+'" is now located at "'+dir+'"');
{$endif}
getdomain(szDomain,DefaultDomainDirectory,CurLang).Directory := dir;
WhenNewDomainDirectory (szDomain, szDirectory);
end;
constructor TGnuGettextInstance.Create;
begin
CreatorThread:=GetCurrentThreadId;
{$ifdef MSWindows}
DesignTimeCodePage:=CP_ACP;
{$endif}
{$ifdef DXGETTEXTDEBUG}
DebugLogCS:=TMultiReadExclusiveWriteSynchronizer.Create;
DebugLog:=TMemoryStream.Create;
DebugWriteln('Debug log started '+DateTimeToStr(Now));
DebugWriteln('GNU gettext module version: '+VCSVersion);
DebugWriteln('');
{$endif}
curGetPluralForm:=GetPluralForm2EN;
Enabled:=True;
curmsgdomain:=DefaultTextDomain;
savefileCS := TMultiReadExclusiveWriteSynchronizer.Create;
domainlist := TStringList.Create;
TP_IgnoreList:=TStringList.Create;
TP_IgnoreList.Sorted:=True;
TP_GlobalClassHandling:=TList.Create;
TP_ClassHandling:=TList.Create;
// Set some settings
DefaultDomainDirectory := IncludeTrailingPathDelimiter(extractfilepath(ExecutableFilename))+'locale';
UseLanguage('');
bindtextdomain(DefaultTextDomain, DefaultDomainDirectory);
textdomain(DefaultTextDomain);
// Add default properties to ignore
TP_GlobalIgnoreClassProperty(TComponent,'Name');
TP_GlobalIgnoreClassProperty(TCollection,'PropName');
end;
destructor TGnuGettextInstance.Destroy;
begin
if savememory <> nil then begin
savefileCS.BeginWrite;
try
CloseFile(savefile);
finally
savefileCS.EndWrite;
end;
FreeAndNil(savememory);
end;
FreeAndNil (savefileCS);
FreeAndNil (TP_IgnoreList);
while TP_GlobalClassHandling.Count<>0 do begin
TObject(TP_GlobalClassHandling.Items[0]).Free;
TP_GlobalClassHandling.Delete(0);
end;
FreeAndNil (TP_GlobalClassHandling);
FreeTP_ClassHandlingItems;
FreeAndNil (TP_ClassHandling);
while domainlist.Count <> 0 do begin
domainlist.Objects[0].Free;
domainlist.Delete(0);
end;
FreeAndNil(domainlist);
{$ifdef DXGETTEXTDEBUG}
FreeAndNil (DebugLog);
FreeAndNil (DebugLogCS);
{$endif}
inherited;
end;
function TGnuGettextInstance.dgettext(const szDomain: string; const szMsgId: ansistring): widestring;
begin
Result:=dgettext(szDomain, ansi2wideDTCP(szMsgId));
end;
function TGnuGettextInstance.dgettext(const szDomain: string;
const szMsgId: widestring): widestring;
begin
if not Enabled then begin
{$ifdef DXGETTEXTDEBUG}
DebugWriteln ('Translation has been disabled. Text is not being translated: '+szMsgid);
{$endif}
Result:=szMsgId;
end else begin
Result:=UTF8Decode(LF2LineBreakA(getdomain(szDomain,DefaultDomainDirectory,CurLang).gettext(StripCR(utf8encode(szMsgId)))));
{$ifdef DXGETTEXTDEBUG}
if (szMsgId<>'') and (Result='') then
DebugWriteln (Format('Error: Translation of %s was an empty string. This may never occur.',[szMsgId]));
{$endif}
end;
end;
function TGnuGettextInstance.GetCurrentLanguage: string;
begin
Result:=curlang;
end;
function TGnuGettextInstance.getcurrenttextdomain: string;
begin
Result := curmsgdomain;
end;
function TGnuGettextInstance.gettext(
const szMsgId: ansistring): widestring;
begin
Result := dgettext(curmsgdomain, szMsgId);
end;
function TGnuGettextInstance.gettext(
const szMsgId: widestring): widestring;
begin
Result := dgettext(curmsgdomain, szMsgId);
end;
procedure TGnuGettextInstance.textdomain(const szDomain: string);
begin
{$ifdef DXGETTEXTDEBUG}
DebugWriteln ('Changed text domain to "'+szDomain+'"');
{$endif}
curmsgdomain := szDomain;
WhenNewDomain (szDomain);
end;
function TGnuGettextInstance.TP_CreateRetranslator : TExecutable;
var
ttpr:TTP_Retranslator;
begin
ttpr:=TTP_Retranslator.Create;
ttpr.Instance:=self;
TP_Retranslator:=ttpr;
Result:=ttpr;
{$ifdef DXGETTEXTDEBUG}
DebugWriteln ('A retranslator was created.');
{$endif}
end;
procedure TGnuGettextInstance.TP_GlobalHandleClass(HClass: TClass;
Handler: TTranslator);
var
cm:TClassMode;
i:integer;
begin
for i:=0 to TP_GlobalClassHandling.Count-1 do begin
cm:=TObject(TP_GlobalClassHandling.Items[i]) as TClassMode;
if cm.HClass=HClass then
raise EGGProgrammingError.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_GlobalClassHandling.Insert(i,cm);
{$ifdef DXGETTEXTDEBUG}
DebugWriteln ('A handler was set for class '+HClass.ClassName+'.');
{$endif}
exit;
end;
end;
cm:=TClassMode.Create;
cm.HClass:=HClass;
cm.SpecialHandler:=Handler;
TP_GlobalClassHandling.Add(cm);
{$ifdef DXGETTEXTDEBUG}
DebugWriteln ('A handler was set for class '+HClass.ClassName+'.');
{$endif}
end;
procedure TGnuGettextInstance.TP_GlobalIgnoreClass(IgnClass: TClass);
var
cm:TClassMode;
i:integer;
begin
for i:=0 to TP_GlobalClassHandling.Count-1 do begin
cm:=TObject(TP_GlobalClassHandling.Items[i]) as TClassMode;
if cm.HClass=IgnClass then
raise EGGProgrammingError.Create ('You cannot add a class to the ignore list that is already on that list: '+IgnClass.ClassName+'. You should keep all TP_Global functions in one place in your source code.');
if IgnClass.InheritsFrom(cm.HClass) then begin
// This is the place to insert this class
cm:=TClassMode.Create;
cm.HClass:=IgnClass;
TP_GlobalClassHandling.Insert(i,cm);
{$ifdef DXGETTEXTDEBUG}
DebugWriteln ('Globally, class '+IgnClass.ClassName+' is being ignored.');
{$endif}
exit;
end;
end;
cm:=TClassMode.Create;
cm.HClass:=IgnClass;
TP_GlobalClassHandling.Add(cm);
{$ifdef DXGETTEXTDEBUG}
DebugWriteln ('Globally, class '+IgnClass.ClassName+' is being ignored.');
{$endif}
end;
procedure TGnuGettextInstance.TP_GlobalIgnoreClassProperty(
IgnClass: TClass; propertyname: string);
var
cm:TClassMode;
i,idx:integer;
begin
propertyname:=uppercase(propertyname);
for i:=0 to TP_GlobalClassHandling.Count-1 do begin
cm:=TObject(TP_GlobalClassHandling.Items[i]) as TClassMode;
if cm.HClass=IgnClass then begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -