mirror of
https://gitlab.com/freepascal.org/fpc/pas2js.git
synced 2025-04-06 10:37:49 +02:00
* Show how to translate resource strings
This commit is contained in:
parent
0b21ea3b26
commit
a99f117940
13
demo/translate/dutch.json
Normal file
13
demo/translate/dutch.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"program" : {
|
||||
"URLTitle":"Vertaling met resourcestrings - URL API"
|
||||
},
|
||||
"mystrings": {
|
||||
"Button":"Vertaal deze pagina",
|
||||
"Header":"Vertaling met resourcestrings",
|
||||
"Paragraph":"Deze tekst wordt vertaald.",
|
||||
"TranslateDirect":"De directe API wordt gebruikt voor dit voorbeeld.",
|
||||
"TranslateJSON":"Een JSON object wordt gebruikt voor dit voorbeeld.",
|
||||
"TranslateURL":"Een URL wordt gebruikt voor dit voorbeeld."
|
||||
}
|
||||
}
|
18
demo/translate/mystrings.pp
Normal file
18
demo/translate/mystrings.pp
Normal file
@ -0,0 +1,18 @@
|
||||
unit mystrings;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
interface
|
||||
|
||||
Resourcestring
|
||||
Header = 'Translation using resource strings';
|
||||
Paragraph = 'This text will be translated.';
|
||||
TranslateDirect = 'The direct API is used for this example.';
|
||||
TranslateJSON = 'A JSON object is used for this example.';
|
||||
TranslateURL = 'A URL is used for this example.';
|
||||
Button = 'Translate this page';
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
||||
|
259
demo/translate/rstranslate.pp
Normal file
259
demo/translate/rstranslate.pp
Normal file
@ -0,0 +1,259 @@
|
||||
{
|
||||
This file is part of the Pas2JS run time library.
|
||||
Copyright (c) 2019 by Michael Van Canneyt
|
||||
|
||||
See the file COPYING.FPC, included in this distribution,
|
||||
for details about the copyright.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
**********************************************************************}
|
||||
unit rstranslate;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
SysUtils, JS, web;
|
||||
|
||||
Type
|
||||
|
||||
{ TResourceTranslator }
|
||||
TLoadFailEvent = Reference to Procedure (Sender : TObject; aCode : Integer; aError : String);
|
||||
TOnTranslatedEvent = Reference to Procedure (Sender : TObject; aURL : String);
|
||||
|
||||
TResourceTranslator = Class
|
||||
Private
|
||||
FOnLoadFail: TLoadFailEvent;
|
||||
FOnURLTranslated: TOnTranslatedEvent;
|
||||
class var FInstance : TResourceTranslator;
|
||||
function GetUnitResources(const aUnit: string): TJSOBject;
|
||||
Protected
|
||||
procedure ResetTranslation(aUnitResources: TJSObject; AString: String); virtual;
|
||||
procedure Translate(aUnitResources: TJSObject; AString, aTranslation: String); virtual;
|
||||
Public
|
||||
Class Function Instance : TResourceTranslator;
|
||||
Procedure Translate(Const aUnit,aString,aTranslation : String); overload;
|
||||
Procedure Translate(Const aTranslations : TJSOBject); overload;
|
||||
Procedure ResetTranslation(Const aUnit : String; const aString : String = ''); overload;
|
||||
procedure Translate(const aURL: string; aOnTranslated : TOnTranslatedEvent = Nil); overload;
|
||||
Property OnLoadFail : TLoadFailEvent Read FOnLoadFail Write FOnLoadFail;
|
||||
Property OnURLTranslated : TOnTranslatedEvent Read FOnURLTranslated Write FOnURLTranslated;
|
||||
end;
|
||||
|
||||
Function ResourceTranslator : TResourceTranslator;
|
||||
Procedure Translate(Const aURL : String; aOnTranslated : TOnTranslatedEvent = Nil);
|
||||
Procedure Translate(Const aUnit,aString,aTranslation : String);
|
||||
Procedure Translate(Const aTranslations : TJSOBject);
|
||||
Procedure ResetTranslation(Const aUnit : String; Const aString : String = '');
|
||||
|
||||
implementation
|
||||
|
||||
Const
|
||||
SCurrent = 'current';
|
||||
|
||||
var
|
||||
Pas : TJSObject; external name 'pas';
|
||||
|
||||
{ TResourceTranslator }
|
||||
|
||||
|
||||
procedure TResourceTranslator.Translate(aUnitResources: TJSObject; AString, aTranslation: String);
|
||||
|
||||
Var
|
||||
res: JSValue;
|
||||
|
||||
begin
|
||||
res:=aUnitResources[aString];
|
||||
if Assigned(Res) then
|
||||
TJSOBject(Res)[SCurrent]:=aTranslation;
|
||||
end;
|
||||
|
||||
procedure TResourceTranslator.ResetTranslation(aUnitResources: TJSObject; AString: String);
|
||||
|
||||
Var
|
||||
res: JSValue;
|
||||
|
||||
begin
|
||||
res:=aUnitResources[aString];
|
||||
if Assigned(Res) then
|
||||
TJSOBject(Res)[SCurrent]:=undefined;
|
||||
end;
|
||||
|
||||
|
||||
function TResourceTranslator.GetUnitResources(const aUnit: string): TJSOBject;
|
||||
|
||||
var
|
||||
jsMod,res : JSValue;
|
||||
|
||||
begin
|
||||
Result:=Nil;
|
||||
jsMod:=Pas[aUnit];
|
||||
if assigned(jsMod) then
|
||||
begin
|
||||
res:=(TJSObject(jsMod)['$resourcestrings']);
|
||||
if Assigned(res) then
|
||||
Result:=TJSObject(res);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TResourceTranslator.Translate(const aTranslations: TJSOBject);
|
||||
|
||||
var
|
||||
aUnitName,aStringName : String;
|
||||
aUnit,Res : TJSObject;
|
||||
V : JSValue;
|
||||
|
||||
begin
|
||||
for aUnitName in TJSObject.getOwnPropertyNames(aTranslations) do
|
||||
if IsValidIdent(aUnitName,True) and isObject(aTranslations[aUnitName]) then
|
||||
begin
|
||||
aUnit:=TJSObject(aTranslations[aUnitName]);
|
||||
Res:=GetUnitResources(aUnitName);
|
||||
if Assigned(Res) then
|
||||
For aStringName in TJSObject.getOwnPropertyNames(aUnit) do
|
||||
begin
|
||||
V:=aUnit[aStringName];
|
||||
if IsString(V) then
|
||||
Translate(Res,aStringName,String(V));
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TResourceTranslator.Translate(const aUnit, aString, aTranslation: String);
|
||||
|
||||
Var
|
||||
jsmod : TJSObject;
|
||||
|
||||
begin
|
||||
jsMod:=GetUnitResources(aUnit);
|
||||
if Assigned(jsMod) then
|
||||
Translate(jsMod, aString,aTranslation);
|
||||
end;
|
||||
|
||||
procedure TResourceTranslator.ResetTranslation(const aUnit: String; const aString: String);
|
||||
|
||||
Var
|
||||
jsmod : TJSObject;
|
||||
S : String;
|
||||
|
||||
begin
|
||||
jsMod:=GetUnitResources(aUnit);
|
||||
if Assigned(jsMod) then
|
||||
if (aString<>'') then
|
||||
ResetTranslation(jsMod, aString)
|
||||
else
|
||||
for S in TJSOBject.getOwnPropertyNames(TJSObject(jsMod)) do
|
||||
ResetTranslation(jsMod, S);
|
||||
end;
|
||||
|
||||
Type
|
||||
|
||||
{ TURLTranslator }
|
||||
|
||||
TURLTranslator = Class
|
||||
Private
|
||||
FTranslator : TResourceTranslator;
|
||||
FURL : String;
|
||||
FXHR : TJSXMLHttpRequest;
|
||||
FOnTranslated : TOnTranslatedEvent;
|
||||
procedure DoStateChange;
|
||||
Public
|
||||
Constructor Create(aUrl : String; ATranslator : TResourceTranslator;aOnTranslated : TOnTranslatedEvent);
|
||||
Procedure Translate;
|
||||
end;
|
||||
|
||||
{ TURLTranslator }
|
||||
|
||||
procedure TURLTranslator.DoStateChange;
|
||||
|
||||
Var
|
||||
O : TJSObject;
|
||||
|
||||
begin
|
||||
if (FXHR.ReadyState=TJSXMLHttpRequest.DONE) then
|
||||
if ((FXHR.Status div 100)=2) then
|
||||
begin
|
||||
try
|
||||
O:=TJSJSON.parseObject(FXHR.responseText);
|
||||
FTranslator.Translate(O);
|
||||
if Assigned(FOnTranslated) then
|
||||
FOnTranslated(FTranslator,FURL);
|
||||
if Assigned(FTranslator.OnURLTranslated) then
|
||||
FTranslator.OnURLTranslated(FTranslator,FURL);
|
||||
except
|
||||
if Assigned(FTranslator.OnLoadFail) then
|
||||
FTranslator.OnLoadFail(FTranslator,0,'Invalid JSON')
|
||||
end
|
||||
end
|
||||
else
|
||||
if Assigned(FTranslator.OnLoadFail) then
|
||||
FTranslator.OnLoadFail(FTranslator,FXHR.Status,FXHR.StatusText);
|
||||
end;
|
||||
|
||||
constructor TURLTranslator.Create(aUrl: String; ATranslator: TResourceTranslator;aOnTranslated : TOnTranslatedEvent);
|
||||
begin
|
||||
FURL:=aURL;
|
||||
FTranslator:=ATranslator;
|
||||
FOnTranslated:=aOnTranslated;
|
||||
end;
|
||||
|
||||
procedure TURLTranslator.Translate;
|
||||
begin
|
||||
FXHR:=TJSXMLHttpRequest.new;
|
||||
FXHR.open('GET',fURL);
|
||||
FXHR.onreadystatechange:=@DoStateChange;
|
||||
FXHR.responseType:='text';
|
||||
FXHR.send;
|
||||
end;
|
||||
|
||||
procedure TResourceTranslator.Translate(const aURL : string;aOnTranslated : TOnTranslatedEvent = Nil);
|
||||
|
||||
begin
|
||||
With TURLTranslator.Create(aURL,Self,aOnTranslated) do
|
||||
Translate;
|
||||
end;
|
||||
|
||||
class function TResourceTranslator.Instance: TResourceTranslator;
|
||||
begin
|
||||
if FInstance=Nil then
|
||||
FInstance:=TResourceTranslator.Create;
|
||||
Result:=FInstance;
|
||||
end;
|
||||
|
||||
{ ---------------------------------------------------------------------
|
||||
Procedural access
|
||||
---------------------------------------------------------------------}
|
||||
|
||||
Procedure Translate(Const aURL : String; aOnTranslated : TOnTranslatedEvent = Nil);
|
||||
|
||||
begin
|
||||
TResourceTranslator.Instance.Translate(aURL,aOnTranslated);
|
||||
end;
|
||||
|
||||
Procedure Translate(Const aTranslations : TJSOBject);
|
||||
|
||||
begin
|
||||
TResourceTranslator.Instance.Translate(aTranslations);
|
||||
end;
|
||||
|
||||
procedure Translate(const aUnit, aString, aTranslation: String);
|
||||
begin
|
||||
TResourceTranslator.Instance.Translate(aUnit,aString,aTranslation);
|
||||
end;
|
||||
|
||||
Procedure ResetTranslation(Const aUnit : String; Const aString : String = '');
|
||||
begin
|
||||
TResourceTranslator.Instance.ResetTranslation(aUnit,Astring);
|
||||
end;
|
||||
|
||||
Function ResourceTranslator : TResourceTranslator;
|
||||
begin
|
||||
Result:=TResourceTranslator.Instance;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
17
demo/translate/translate_basic.html
Normal file
17
demo/translate/translate_basic.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Translation using resource strings - Basic API</title>
|
||||
<script src="translate_basic.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h2 id="translate-header"></h2>
|
||||
<p id="translate-text"></p>
|
||||
<button id="btn-translate" class="btn btn-primary"></button>
|
||||
<script>
|
||||
rtl.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
95
demo/translate/translate_basic.lpi
Normal file
95
demo/translate/translate_basic.lpi
Normal file
@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CONFIG>
|
||||
<ProjectOptions>
|
||||
<Version Value="12"/>
|
||||
<General>
|
||||
<Flags>
|
||||
<MainUnitHasCreateFormStatements Value="False"/>
|
||||
<MainUnitHasTitleStatement Value="False"/>
|
||||
<MainUnitHasScaledStatement Value="False"/>
|
||||
<Runnable Value="False"/>
|
||||
</Flags>
|
||||
<SessionStorage Value="InProjectDir"/>
|
||||
<Title Value="translate_basic"/>
|
||||
<UseAppBundle Value="False"/>
|
||||
<ResourceType Value="res"/>
|
||||
</General>
|
||||
<CustomData Count="4">
|
||||
<Item0 Name="MaintainHTML" Value="1"/>
|
||||
<Item1 Name="PasJSHTMLFile" Value="project1.html"/>
|
||||
<Item2 Name="PasJSPort" Value="0"/>
|
||||
<Item3 Name="PasJSWebBrowserProject" Value="1"/>
|
||||
</CustomData>
|
||||
<BuildModes>
|
||||
<Item Name="Default" Default="True"/>
|
||||
</BuildModes>
|
||||
<PublishOptions>
|
||||
<Version Value="2"/>
|
||||
<UseFileFilters Value="True"/>
|
||||
</PublishOptions>
|
||||
<RunParams>
|
||||
<FormatVersion Value="2"/>
|
||||
<Modes Count="0"/>
|
||||
</RunParams>
|
||||
<Units>
|
||||
<Unit>
|
||||
<Filename Value="translate_basic.lpr"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="translate_basic.html"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<CustomData Count="1">
|
||||
<Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
|
||||
</CustomData>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="mystrings.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
<Version Value="11"/>
|
||||
<Target FileExt=".js">
|
||||
<Filename Value="translate_basic"/>
|
||||
</Target>
|
||||
<SearchPaths>
|
||||
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||
<UnitOutputDirectory Value="js"/>
|
||||
</SearchPaths>
|
||||
<Parsing>
|
||||
<SyntaxOptions>
|
||||
<AllowLabel Value="False"/>
|
||||
<CPPInline Value="False"/>
|
||||
<UseAnsiStrings Value="False"/>
|
||||
</SyntaxOptions>
|
||||
</Parsing>
|
||||
<CodeGeneration>
|
||||
<TargetOS Value="browser"/>
|
||||
</CodeGeneration>
|
||||
<Linking>
|
||||
<Debugging>
|
||||
<GenerateDebugInfo Value="False"/>
|
||||
<UseLineInfoUnit Value="False"/>
|
||||
</Debugging>
|
||||
</Linking>
|
||||
<Other>
|
||||
<CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -Jminclude"/>
|
||||
<CompilerPath Value="$(pas2js)"/>
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
<Exceptions Count="3">
|
||||
<Item1>
|
||||
<Name Value="EAbort"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<Name Value="ECodetoolError"/>
|
||||
</Item2>
|
||||
<Item3>
|
||||
<Name Value="EFOpenError"/>
|
||||
</Item3>
|
||||
</Exceptions>
|
||||
</Debugging>
|
||||
</CONFIG>
|
91
demo/translate/translate_basic.lpr
Normal file
91
demo/translate/translate_basic.lpr
Normal file
@ -0,0 +1,91 @@
|
||||
program translate_basic;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
uses
|
||||
JS, Web, mystrings, rstranslate;
|
||||
|
||||
Resourcestring
|
||||
BasicTitle = 'Translation using resource strings - Basic API';
|
||||
|
||||
Type
|
||||
|
||||
{ TTranslateApp }
|
||||
|
||||
TTranslateApp = Class
|
||||
FHeader : TJSHTMLELement;
|
||||
FPar : TJSHTMLELement;
|
||||
FButton : TJSHTMLButtonELement;
|
||||
FIsDutch : Boolean;
|
||||
Constructor Create;
|
||||
Function GetEl(const aName : string) : TJSHTMLELement;
|
||||
Procedure Bind;
|
||||
Procedure SetTexts;
|
||||
private
|
||||
function DoTranslation(aEvent: TJSMouseEvent): boolean;
|
||||
procedure TranslateStrings;
|
||||
end;
|
||||
|
||||
{ TTranslateApp }
|
||||
|
||||
constructor TTranslateApp.Create;
|
||||
begin
|
||||
Bind;
|
||||
end;
|
||||
|
||||
function TTranslateApp.GetEl(const aName: string): TJSHTMLELement;
|
||||
begin
|
||||
Result:=TJSHTMLELement(Document.getElementById(aName));
|
||||
end;
|
||||
|
||||
procedure TTranslateApp.Bind;
|
||||
begin
|
||||
FHeader:=GetEl('translate-header');
|
||||
FPar:=GetEl('translate-text');
|
||||
FButton:=TJSHTMLButtonELement(GetEl('btn-translate'));
|
||||
FButton.onclick:=@DoTranslation;
|
||||
end;
|
||||
|
||||
procedure TTranslateApp.SetTexts;
|
||||
begin
|
||||
FHeader.InnerHTML:=Header;
|
||||
FButton.InnerHTML:=Button;
|
||||
FPar.InnerHtml:=Paragraph+' '+TranslateDirect;
|
||||
document.title:=BasicTitle;
|
||||
// window. title:=BasicTitle;
|
||||
end;
|
||||
|
||||
procedure TTranslateApp.TranslateStrings;
|
||||
|
||||
begin
|
||||
FIsDutch:=Not FIsDutch;
|
||||
if FIsDutch then
|
||||
begin
|
||||
Translate('program','BasicTitle','Vertaling met resourcestrings - directe API');
|
||||
Translate('mystrings','Button','Vertaal deze pagina');
|
||||
Translate('mystrings','Header','Vertaling met resourcestrings');
|
||||
Translate('mystrings','Paragraph','Deze tekst wordt vertaald.');
|
||||
Translate('mystrings','TranslateDirect','De directe API wordt gebruikt voor dit voorbeeld.');
|
||||
Translate('mystrings','TranslateJSON','Een JSON object wordt gebruikt voor dit voorbeeld.');
|
||||
Translate('mystrings','TranslateURL','Een URL wordt gebruikt voor dit voorbeeld.');
|
||||
end
|
||||
else
|
||||
begin
|
||||
// Single string of a module
|
||||
ResetTranslation('program','BasicTitle');
|
||||
// All strings in a module
|
||||
ResetTranslation('mystrings');
|
||||
end;
|
||||
end;
|
||||
|
||||
function TTranslateApp.DoTranslation(aEvent: TJSMouseEvent): boolean;
|
||||
begin
|
||||
TranslateStrings;
|
||||
SetTexts;
|
||||
Result:=True;
|
||||
end;
|
||||
|
||||
begin
|
||||
With TTranslateApp.Create do
|
||||
SetTexts;
|
||||
end.
|
17
demo/translate/translate_object.html
Normal file
17
demo/translate/translate_object.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Translation using resource strings - Object API</title>
|
||||
<script src="translate_object.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h2 id="translate-header"></h2>
|
||||
<p id="translate-text"></p>
|
||||
<button id="btn-translate" class="btn btn-primary"></button>
|
||||
<script>
|
||||
rtl.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
95
demo/translate/translate_object.lpi
Normal file
95
demo/translate/translate_object.lpi
Normal file
@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CONFIG>
|
||||
<ProjectOptions>
|
||||
<Version Value="12"/>
|
||||
<General>
|
||||
<Flags>
|
||||
<MainUnitHasCreateFormStatements Value="False"/>
|
||||
<MainUnitHasTitleStatement Value="False"/>
|
||||
<MainUnitHasScaledStatement Value="False"/>
|
||||
<Runnable Value="False"/>
|
||||
</Flags>
|
||||
<SessionStorage Value="InProjectDir"/>
|
||||
<Title Value="translate_object"/>
|
||||
<UseAppBundle Value="False"/>
|
||||
<ResourceType Value="res"/>
|
||||
</General>
|
||||
<CustomData Count="4">
|
||||
<Item0 Name="MaintainHTML" Value="1"/>
|
||||
<Item1 Name="PasJSHTMLFile" Value="translate_object.html"/>
|
||||
<Item2 Name="PasJSPort" Value="0"/>
|
||||
<Item3 Name="PasJSWebBrowserProject" Value="1"/>
|
||||
</CustomData>
|
||||
<BuildModes>
|
||||
<Item Name="Default" Default="True"/>
|
||||
</BuildModes>
|
||||
<PublishOptions>
|
||||
<Version Value="2"/>
|
||||
<UseFileFilters Value="True"/>
|
||||
</PublishOptions>
|
||||
<RunParams>
|
||||
<FormatVersion Value="2"/>
|
||||
<Modes Count="0"/>
|
||||
</RunParams>
|
||||
<Units>
|
||||
<Unit>
|
||||
<Filename Value="translate_object.lpr"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="translate_object.html"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<CustomData Count="1">
|
||||
<Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
|
||||
</CustomData>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="mystrings.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
<Version Value="11"/>
|
||||
<Target FileExt=".js">
|
||||
<Filename Value="translate_object"/>
|
||||
</Target>
|
||||
<SearchPaths>
|
||||
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||
<UnitOutputDirectory Value="js"/>
|
||||
</SearchPaths>
|
||||
<Parsing>
|
||||
<SyntaxOptions>
|
||||
<AllowLabel Value="False"/>
|
||||
<CPPInline Value="False"/>
|
||||
<UseAnsiStrings Value="False"/>
|
||||
</SyntaxOptions>
|
||||
</Parsing>
|
||||
<CodeGeneration>
|
||||
<TargetOS Value="browser"/>
|
||||
</CodeGeneration>
|
||||
<Linking>
|
||||
<Debugging>
|
||||
<GenerateDebugInfo Value="False"/>
|
||||
<UseLineInfoUnit Value="False"/>
|
||||
</Debugging>
|
||||
</Linking>
|
||||
<Other>
|
||||
<CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -Jminclude"/>
|
||||
<CompilerPath Value="$(pas2js)"/>
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
<Exceptions Count="3">
|
||||
<Item1>
|
||||
<Name Value="EAbort"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<Name Value="ECodetoolError"/>
|
||||
</Item2>
|
||||
<Item3>
|
||||
<Name Value="EFOpenError"/>
|
||||
</Item3>
|
||||
</Exceptions>
|
||||
</Debugging>
|
||||
</CONFIG>
|
97
demo/translate/translate_object.lpr
Normal file
97
demo/translate/translate_object.lpr
Normal file
@ -0,0 +1,97 @@
|
||||
program translate_object;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
uses
|
||||
JS, Web, mystrings, rstranslate;
|
||||
|
||||
Resourcestring
|
||||
ObjectTitle = 'Translation using resource strings - Object API';
|
||||
|
||||
Type
|
||||
|
||||
{ TTranslateApp }
|
||||
|
||||
TTranslateApp = Class
|
||||
FDutch : TJSObject;
|
||||
FHeader : TJSHTMLELement;
|
||||
FPar : TJSHTMLELement;
|
||||
FButton : TJSHTMLButtonELement;
|
||||
FIsDutch : Boolean;
|
||||
Constructor Create;
|
||||
Function GetEl(const aName : string) : TJSHTMLELement;
|
||||
Procedure Bind;
|
||||
Procedure SetTexts;
|
||||
private
|
||||
function DoTranslation(aEvent: TJSMouseEvent): boolean;
|
||||
procedure TranslateStrings;
|
||||
end;
|
||||
|
||||
{ TTranslateApp }
|
||||
|
||||
constructor TTranslateApp.Create;
|
||||
begin
|
||||
Bind;
|
||||
FDutch:=New([
|
||||
'program',new([
|
||||
'BasicTitle','Vertaling met resourcestrings - directe API'
|
||||
]),
|
||||
'mystrings', new([
|
||||
'Button','Vertaal deze pagina',
|
||||
'Header','Vertaling met resourcestrings',
|
||||
'Paragraph','Deze tekst wordt vertaald.',
|
||||
'TranslateDirect','De directe API wordt gebruikt voor dit voorbeeld.',
|
||||
'TranslateJSON','Een JSON object wordt gebruikt voor dit voorbeeld.',
|
||||
'TranslateURL','Een URL wordt gebruikt voor dit voorbeeld.'
|
||||
])
|
||||
]);
|
||||
end;
|
||||
|
||||
function TTranslateApp.GetEl(const aName: string): TJSHTMLELement;
|
||||
begin
|
||||
Result:=TJSHTMLELement(Document.getElementById(aName));
|
||||
end;
|
||||
|
||||
procedure TTranslateApp.Bind;
|
||||
begin
|
||||
FHeader:=GetEl('translate-header');
|
||||
FPar:=GetEl('translate-text');
|
||||
FButton:=TJSHTMLButtonELement(GetEl('btn-translate'));
|
||||
FButton.onclick:=@DoTranslation;
|
||||
end;
|
||||
|
||||
procedure TTranslateApp.SetTexts;
|
||||
begin
|
||||
FHeader.InnerHTML:=Header;
|
||||
FButton.InnerHTML:=Button;
|
||||
FPar.InnerHtml:=Paragraph+' '+TranslateJSON;
|
||||
document.title:=ObjectTitle;
|
||||
end;
|
||||
|
||||
|
||||
procedure TTranslateApp.TranslateStrings;
|
||||
|
||||
begin
|
||||
FIsDutch:=Not FIsDutch;
|
||||
if FIsDutch then
|
||||
Translate(FDutch)
|
||||
else
|
||||
begin
|
||||
// Single string of a module
|
||||
ResetTranslation('program','BasicTitle');
|
||||
// All strings in a module
|
||||
ResetTranslation('mystrings');
|
||||
end;
|
||||
end;
|
||||
|
||||
function TTranslateApp.DoTranslation(aEvent: TJSMouseEvent): boolean;
|
||||
begin
|
||||
TranslateStrings;
|
||||
SetTexts;
|
||||
Result:=True;
|
||||
end;
|
||||
|
||||
begin
|
||||
With TTranslateApp.Create do
|
||||
SetTexts;
|
||||
end.
|
17
demo/translate/translate_url.html
Normal file
17
demo/translate/translate_url.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Translation using resource strings - URL API</title>
|
||||
<script src="translate_url.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h2 id="translate-header"></h2>
|
||||
<p id="translate-text"></p>
|
||||
<button id="btn-translate" class="btn btn-primary"></button>
|
||||
<script>
|
||||
rtl.run();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
95
demo/translate/translate_url.lpi
Normal file
95
demo/translate/translate_url.lpi
Normal file
@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CONFIG>
|
||||
<ProjectOptions>
|
||||
<Version Value="12"/>
|
||||
<General>
|
||||
<Flags>
|
||||
<MainUnitHasCreateFormStatements Value="False"/>
|
||||
<MainUnitHasTitleStatement Value="False"/>
|
||||
<MainUnitHasScaledStatement Value="False"/>
|
||||
<Runnable Value="False"/>
|
||||
</Flags>
|
||||
<SessionStorage Value="InProjectDir"/>
|
||||
<Title Value="translate_url"/>
|
||||
<UseAppBundle Value="False"/>
|
||||
<ResourceType Value="res"/>
|
||||
</General>
|
||||
<CustomData Count="4">
|
||||
<Item0 Name="MaintainHTML" Value="1"/>
|
||||
<Item1 Name="PasJSHTMLFile" Value="translate_url.html"/>
|
||||
<Item2 Name="PasJSPort" Value="0"/>
|
||||
<Item3 Name="PasJSWebBrowserProject" Value="1"/>
|
||||
</CustomData>
|
||||
<BuildModes>
|
||||
<Item Name="Default" Default="True"/>
|
||||
</BuildModes>
|
||||
<PublishOptions>
|
||||
<Version Value="2"/>
|
||||
<UseFileFilters Value="True"/>
|
||||
</PublishOptions>
|
||||
<RunParams>
|
||||
<FormatVersion Value="2"/>
|
||||
<Modes Count="0"/>
|
||||
</RunParams>
|
||||
<Units>
|
||||
<Unit>
|
||||
<Filename Value="translate_url.lpr"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="translate_url.html"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<CustomData Count="1">
|
||||
<Item0 Name="PasJSIsProjectHTMLFile" Value="1"/>
|
||||
</CustomData>
|
||||
</Unit>
|
||||
<Unit>
|
||||
<Filename Value="mystrings.pp"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
</Unit>
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
<Version Value="11"/>
|
||||
<Target FileExt=".js">
|
||||
<Filename Value="translate_url"/>
|
||||
</Target>
|
||||
<SearchPaths>
|
||||
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||
<UnitOutputDirectory Value="js"/>
|
||||
</SearchPaths>
|
||||
<Parsing>
|
||||
<SyntaxOptions>
|
||||
<AllowLabel Value="False"/>
|
||||
<CPPInline Value="False"/>
|
||||
<UseAnsiStrings Value="False"/>
|
||||
</SyntaxOptions>
|
||||
</Parsing>
|
||||
<CodeGeneration>
|
||||
<TargetOS Value="browser"/>
|
||||
</CodeGeneration>
|
||||
<Linking>
|
||||
<Debugging>
|
||||
<GenerateDebugInfo Value="False"/>
|
||||
<UseLineInfoUnit Value="False"/>
|
||||
</Debugging>
|
||||
</Linking>
|
||||
<Other>
|
||||
<CustomOptions Value="-Jeutf-8 -Jirtl.js -Jc -Jminclude"/>
|
||||
<CompilerPath Value="$(pas2js)"/>
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
<Exceptions Count="3">
|
||||
<Item1>
|
||||
<Name Value="EAbort"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<Name Value="ECodetoolError"/>
|
||||
</Item2>
|
||||
<Item3>
|
||||
<Name Value="EFOpenError"/>
|
||||
</Item3>
|
||||
</Exceptions>
|
||||
</Debugging>
|
||||
</CONFIG>
|
89
demo/translate/translate_url.lpr
Normal file
89
demo/translate/translate_url.lpr
Normal file
@ -0,0 +1,89 @@
|
||||
program translate_url;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
uses
|
||||
JS, Web, rstranslate, mystrings;
|
||||
|
||||
Resourcestring
|
||||
URLTitle = 'Translation using resource strings - URL API';
|
||||
|
||||
Type
|
||||
|
||||
{ TTranslateApp }
|
||||
|
||||
TTranslateApp = Class
|
||||
FHeader : TJSHTMLELement;
|
||||
FPar : TJSHTMLELement;
|
||||
FButton : TJSHTMLButtonELement;
|
||||
FIsDutch : Boolean;
|
||||
Constructor Create;
|
||||
Function GetEl(const aName : string) : TJSHTMLELement;
|
||||
Procedure Bind;
|
||||
Procedure SetTexts;
|
||||
private
|
||||
procedure DoneTranslation(Sender: TObject; aURL: String);
|
||||
function DoTranslation(aEvent: TJSMouseEvent): boolean;
|
||||
procedure TranslateStrings;
|
||||
end;
|
||||
|
||||
{ TTranslateApp }
|
||||
|
||||
constructor TTranslateApp.Create;
|
||||
begin
|
||||
Bind;
|
||||
end;
|
||||
|
||||
function TTranslateApp.GetEl(const aName: string): TJSHTMLELement;
|
||||
begin
|
||||
Result:=TJSHTMLELement(Document.getElementById(aName));
|
||||
end;
|
||||
|
||||
procedure TTranslateApp.Bind;
|
||||
begin
|
||||
FHeader:=GetEl('translate-header');
|
||||
FPar:=GetEl('translate-text');
|
||||
FButton:=TJSHTMLButtonELement(GetEl('btn-translate'));
|
||||
FButton.onclick:=@DoTranslation;
|
||||
end;
|
||||
|
||||
procedure TTranslateApp.SetTexts;
|
||||
begin
|
||||
FHeader.InnerHTML:=Header;
|
||||
FButton.InnerHTML:=Button;
|
||||
FPar.InnerHtml:=Paragraph+' '+TranslateURL;
|
||||
document.title:=URLTitle;
|
||||
end;
|
||||
|
||||
procedure TTranslateApp.DoneTranslation(Sender : TObject; aURL : String);
|
||||
|
||||
begin
|
||||
SetTexts;
|
||||
end;
|
||||
|
||||
procedure TTranslateApp.TranslateStrings;
|
||||
|
||||
begin
|
||||
FIsDutch:=Not FIsDutch;
|
||||
if FIsDutch then
|
||||
Translate('dutch.json',@DoneTranslation)
|
||||
else
|
||||
begin
|
||||
// Single string of a module
|
||||
ResetTranslation('program','URLTitle');
|
||||
// All strings in a module
|
||||
ResetTranslation('mystrings');
|
||||
end;
|
||||
end;
|
||||
|
||||
function TTranslateApp.DoTranslation(aEvent: TJSMouseEvent): boolean;
|
||||
begin
|
||||
TranslateStrings;
|
||||
SetTexts;
|
||||
Result:=True;
|
||||
end;
|
||||
|
||||
begin
|
||||
With TTranslateApp.Create do
|
||||
SetTexts;
|
||||
end.
|
247
packages/rtl/rstranslate.pp
Normal file
247
packages/rtl/rstranslate.pp
Normal file
@ -0,0 +1,247 @@
|
||||
unit rstranslate;
|
||||
|
||||
{$mode objfpc}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
SysUtils, JS, web;
|
||||
|
||||
Type
|
||||
|
||||
{ TResourceTranslator }
|
||||
TLoadFailEvent = Reference to Procedure (Sender : TObject; aCode : Integer; aError : String);
|
||||
TOnTranslatedEvent = Reference to Procedure (Sender : TObject; aURL : String);
|
||||
|
||||
TResourceTranslator = Class
|
||||
Private
|
||||
FOnLoadFail: TLoadFailEvent;
|
||||
FOnURLTranslated: TOnTranslatedEvent;
|
||||
class var FInstance : TResourceTranslator;
|
||||
function GetUnitResources(const aUnit: string): TJSOBject;
|
||||
Protected
|
||||
procedure ResetTranslation(aUnitResources: TJSObject; AString: String); virtual;
|
||||
procedure Translate(aUnitResources: TJSObject; AString, aTranslation: String); virtual;
|
||||
Public
|
||||
Class Function Instance : TResourceTranslator;
|
||||
Procedure Translate(Const aUnit,aString,aTranslation : String); overload;
|
||||
Procedure Translate(Const aTranslations : TJSOBject); overload;
|
||||
Procedure ResetTranslation(Const aUnit : String; const aString : String = ''); overload;
|
||||
procedure Translate(const aURL: string; aOnTranslated : TOnTranslatedEvent = Nil); overload;
|
||||
Property OnLoadFail : TLoadFailEvent Read FOnLoadFail Write FOnLoadFail;
|
||||
Property OnURLTranslated : TOnTranslatedEvent Read FOnURLTranslated Write FOnURLTranslated;
|
||||
end;
|
||||
|
||||
Function ResourceTranslator : TResourceTranslator;
|
||||
Procedure Translate(Const aURL : String; aOnTranslated : TOnTranslatedEvent = Nil);
|
||||
Procedure Translate(Const aUnit,aString,aTranslation : String);
|
||||
Procedure Translate(Const aTranslations : TJSOBject);
|
||||
Procedure ResetTranslation(Const aUnit : String; Const aString : String = '');
|
||||
|
||||
implementation
|
||||
|
||||
Const
|
||||
SCurrent = 'current';
|
||||
|
||||
var
|
||||
Pas : TJSObject; external name 'pas';
|
||||
|
||||
{ TResourceTranslator }
|
||||
|
||||
|
||||
procedure TResourceTranslator.Translate(aUnitResources: TJSObject; AString, aTranslation: String);
|
||||
|
||||
Var
|
||||
res: JSValue;
|
||||
|
||||
begin
|
||||
res:=aUnitResources[aString];
|
||||
if Assigned(Res) then
|
||||
TJSOBject(Res)[SCurrent]:=aTranslation;
|
||||
end;
|
||||
|
||||
procedure TResourceTranslator.ResetTranslation(aUnitResources: TJSObject; AString: String);
|
||||
|
||||
Var
|
||||
res: JSValue;
|
||||
|
||||
begin
|
||||
res:=aUnitResources[aString];
|
||||
if Assigned(Res) then
|
||||
TJSOBject(Res)[SCurrent]:=undefined;
|
||||
end;
|
||||
|
||||
|
||||
function TResourceTranslator.GetUnitResources(const aUnit: string): TJSOBject;
|
||||
|
||||
var
|
||||
jsMod,res : JSValue;
|
||||
|
||||
begin
|
||||
Result:=Nil;
|
||||
jsMod:=Pas[aUnit];
|
||||
if assigned(jsMod) then
|
||||
begin
|
||||
res:=(TJSObject(jsMod)['$resourcestrings']);
|
||||
if Assigned(res) then
|
||||
Result:=TJSObject(res);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TResourceTranslator.Translate(const aTranslations: TJSOBject);
|
||||
|
||||
var
|
||||
aUnitName,aStringName : String;
|
||||
aUnit,Res : TJSObject;
|
||||
V : JSValue;
|
||||
|
||||
begin
|
||||
for aUnitName in TJSObject.getOwnPropertyNames(aTranslations) do
|
||||
if IsValidIdent(aUnitName,True) and isObject(aTranslations[aUnitName]) then
|
||||
begin
|
||||
aUnit:=TJSObject(aTranslations[aUnitName]);
|
||||
Res:=GetUnitResources(aUnitName);
|
||||
if Assigned(Res) then
|
||||
For aStringName in TJSObject.getOwnPropertyNames(aUnit) do
|
||||
begin
|
||||
V:=aUnit[aStringName];
|
||||
if IsString(V) then
|
||||
Translate(Res,aStringName,String(V));
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TResourceTranslator.Translate(const aUnit, aString, aTranslation: String);
|
||||
|
||||
Var
|
||||
jsmod : TJSObject;
|
||||
|
||||
begin
|
||||
jsMod:=GetUnitResources(aUnit);
|
||||
if Assigned(jsMod) then
|
||||
Translate(jsMod, aString,aTranslation);
|
||||
end;
|
||||
|
||||
procedure TResourceTranslator.ResetTranslation(const aUnit: String; const aString: String);
|
||||
|
||||
Var
|
||||
jsmod : TJSObject;
|
||||
S : String;
|
||||
|
||||
begin
|
||||
jsMod:=GetUnitResources(aUnit);
|
||||
if Assigned(jsMod) then
|
||||
if (aString<>'') then
|
||||
ResetTranslation(jsMod, aString)
|
||||
else
|
||||
for S in TJSOBject.getOwnPropertyNames(TJSObject(jsMod)) do
|
||||
ResetTranslation(jsMod, S);
|
||||
end;
|
||||
|
||||
Type
|
||||
|
||||
{ TURLTranslator }
|
||||
|
||||
TURLTranslator = Class
|
||||
Private
|
||||
FTranslator : TResourceTranslator;
|
||||
FURL : String;
|
||||
FXHR : TJSXMLHttpRequest;
|
||||
FOnTranslated : TOnTranslatedEvent;
|
||||
procedure DoStateChange;
|
||||
Public
|
||||
Constructor Create(aUrl : String; ATranslator : TResourceTranslator;aOnTranslated : TOnTranslatedEvent);
|
||||
Procedure Translate;
|
||||
end;
|
||||
|
||||
{ TURLTranslator }
|
||||
|
||||
procedure TURLTranslator.DoStateChange;
|
||||
|
||||
Var
|
||||
O : TJSObject;
|
||||
|
||||
begin
|
||||
if (FXHR.ReadyState=TJSXMLHttpRequest.DONE) then
|
||||
if ((FXHR.Status div 100)=2) then
|
||||
begin
|
||||
try
|
||||
O:=TJSJSON.parseObject(FXHR.responseText);
|
||||
FTranslator.Translate(O);
|
||||
if Assigned(FOnTranslated) then
|
||||
FOnTranslated(FTranslator,FURL);
|
||||
if Assigned(FTranslator.OnURLTranslated) then
|
||||
FTranslator.OnURLTranslated(FTranslator,FURL);
|
||||
except
|
||||
if Assigned(FTranslator.OnLoadFail) then
|
||||
FTranslator.OnLoadFail(FTranslator,0,'Invalid JSON')
|
||||
end
|
||||
end
|
||||
else
|
||||
if Assigned(FTranslator.OnLoadFail) then
|
||||
FTranslator.OnLoadFail(FTranslator,FXHR.Status,FXHR.StatusText);
|
||||
end;
|
||||
|
||||
constructor TURLTranslator.Create(aUrl: String; ATranslator: TResourceTranslator;aOnTranslated : TOnTranslatedEvent);
|
||||
begin
|
||||
FURL:=aURL;
|
||||
FTranslator:=ATranslator;
|
||||
FOnTranslated:=aOnTranslated;
|
||||
end;
|
||||
|
||||
procedure TURLTranslator.Translate;
|
||||
begin
|
||||
FXHR:=TJSXMLHttpRequest.new;
|
||||
FXHR.open('GET',fURL);
|
||||
FXHR.onreadystatechange:=@DoStateChange;
|
||||
FXHR.responseType:='text';
|
||||
FXHR.send;
|
||||
end;
|
||||
|
||||
procedure TResourceTranslator.Translate(const aURL : string;aOnTranslated : TOnTranslatedEvent = Nil);
|
||||
|
||||
begin
|
||||
With TURLTranslator.Create(aURL,Self,aOnTranslated) do
|
||||
Translate;
|
||||
end;
|
||||
|
||||
class function TResourceTranslator.Instance: TResourceTranslator;
|
||||
begin
|
||||
if FInstance=Nil then
|
||||
FInstance:=TResourceTranslator.Create;
|
||||
Result:=FInstance;
|
||||
end;
|
||||
|
||||
{ ---------------------------------------------------------------------
|
||||
Procedural access
|
||||
---------------------------------------------------------------------}
|
||||
|
||||
Procedure Translate(Const aURL : String; aOnTranslated : TOnTranslatedEvent = Nil);
|
||||
|
||||
begin
|
||||
TResourceTranslator.Instance.Translate(aURL,aOnTranslated);
|
||||
end;
|
||||
|
||||
Procedure Translate(Const aTranslations : TJSOBject);
|
||||
|
||||
begin
|
||||
TResourceTranslator.Instance.Translate(aTranslations);
|
||||
end;
|
||||
|
||||
procedure Translate(const aUnit, aString, aTranslation: String);
|
||||
begin
|
||||
TResourceTranslator.Instance.Translate(aUnit,aString,aTranslation);
|
||||
end;
|
||||
|
||||
Procedure ResetTranslation(Const aUnit : String; Const aString : String = '');
|
||||
begin
|
||||
TResourceTranslator.Instance.ResetTranslation(aUnit,Astring);
|
||||
end;
|
||||
|
||||
Function ResourceTranslator : TResourceTranslator;
|
||||
begin
|
||||
Result:=TResourceTranslator.Instance;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user