For the recent mobile FMX application development, I had a challenge, do not use any service from my full-featured cross-platform framework, to minimize application bloat, besides, FMX framework itself is rather big piece of cake.
One of the cornerstones is a I18N support which in my framework is based upon custom implementation of gettext. In current case, I decided to wrap I18N manager coode around FMX's TLang. As far as TLang may use, besides its binary stoarage, the plain text files as well, formatted as key=value pair.
So, the goal was to convert gettext *.po files after standard gettext porocedure - string extraction, concatenation, and localization, into key=value plain text files, ready to be loaded in TLang. The quickest way I chose, to implement this in my esscript DSL, and use scripting host shell to compile and run it from the command line.
PO to TLang TXT converter script
const c_msgidPfxLen = 6;
const c_msgstrPfxLen = 7;
enum PoParserState {
Idle = 0;
MsgId = 1;
MsgStr = 2;
}
// gettext *.po to TLang's *.txt converter
//
function po2txt(po)
var path, file, poFile, txtFile,
tok, pos, msgId, msgStr, state = PoParserState$$Idle,
parsed = new EsAssocContainer(), parsedNode,
poLine, cwd = EsPath::cwdGet();
{
path = EsPath::createFromFilePath(po);
if( "po" != path$fileExt )
throw "Improper input file type. PO expected, got '" + path$fileExt + "'";
poFile = path.pathGet(EsPathFlag$$Default, cwd);
if( !path.fileExists("") )
throw "Input PO file '" + poFile + "' does not exist";
path$fileExt = "txt";
txtFile = path.pathGet(EsPathFlag$$Default, cwd);
file = new EsFile(
poFile,
EsFileFlag$$Read|EsFileFlag$$Text
);
if( !file.open() )
throw "Could not open input file '" + poFile + "'";
tok = new EsStringTokenizer();
tok$skipMultipleSeparators = false;
tok$separators = "\n\r";
tok$text = file.readAllAsString();
file.close();
while( tok$moreTokens )
{
poLine = tok$nextToken;
//EsScriptDebug::log("Analyzing line: %s", poLine);
if( PoParserState$$Idle == state )
{
pos = poLine#find( "msgid " );
if( !pos#isEmpty() && 0 == pos )
{
state = PoParserState$$MsgId;
msgId = poLine#sliceGet(
c_msgidPfxLen,
poLine#countGet()
);
msgId = EsStr::fromString(
msgId,
EsStrFlag$$Quote|
EsStrFlag$$NoCEscape
);
//EsScriptDebug::log("msgId started: %s", msgId);
}
}
else if( PoParserState$$MsgId == state )
{
if( poLine#countGet() && '"' == poLine[0] )
msgId += EsStr::fromString(
poLine,
EsStrFlag$$Quote|
EsStrFlag$$NoCEscape
);
else
{
pos = poLine#find( "msgstr " );
if( !pos#isEmpty() && 0 == pos )
{
state = PoParserState$$MsgStr;
msgStr = poLine#sliceGet(
c_msgstrPfxLen,
poLine#countGet()
);
msgStr = EsStr::fromString(
msgStr,
EsStrFlag$$Quote|
EsStrFlag$$NoCEscape
);
//EsScriptDebug::log("msgStr started: %s", msgStr);
}
else
state = PoParserState$$Idle;
}
}
else if( PoParserState$$MsgStr == state )
{
if( poLine#countGet() && '"' == poLine[0] )
msgStr += EsStr::fromString(
poLine,
EsStrFlag$$Quote|
EsStrFlag$$NoCEscape
);
else
{
state = PoParserState$$Idle;
//EsScriptDebug::log("msg=[%s][%s]", msgId, msgStr);
if( msgId#countGet() && msgStr#countGet() )
parsed.newValueSet(msgId, msgStr);
}
}
}
// Complete building the last msgStr, if needed
if( PoParserState$$MsgStr == state )
{
if( poLine#countGet() && '"' == poLine[0] )
msgStr += EsStr::fromString(
poLine,
EsStrFlag$$Quote|
EsStrFlag$$NoCEscape
);
//EsScriptDebug::log("msg=[%s][%s]", msgId, msgStr);
if( msgId#countGet() && msgStr#countGet() )
parsed.newValueSet(msgId, msgStr);
}
file$name = txtFile;
file$flags = EsFileFlag$$Write|EsFileFlag$$Text;
if( !file.open() )
throw "Could not create output file '" + txtFile + "'";
poLine = "";
foreach( parsedNode in parsed )
{
poLine +=
parsedNode[0] + "=" +
parsedNode[1] + "\n";
}
file.writeAllAsString( poLine );
}
PO2TXT converter batch launcher
echo OFF
rem Find scripting console
set CURPATH=%cd%
set ESSCON1=d:\Programs\Eco-Electronics\ess-console\ess-console.exe
set ESSCON2=%CURPATH%\..\bin\Win32\Debug\ess-console_ecc18.exe
set ESSCON3=%CURPATH%\..\bin\Win32\Release\ess-console_ecc18.exe
if exist "%ESSCON1%" (
set ESSCON="%ESSCON1%"
goto main
)
if exist "%ESSCON2%" (
set ESSCON="%ESSCON2%"
goto main
)
if exist "%ESSCON3%" (
set ESSCON="%ESSCON3%"
goto main
)
echo Could not find ess-console.exe
goto exit
:main
rem Check if hex converter present, and if not, compile it
set CESSE=%CURPATH%\po2txt.cesse
if not exist "%CESSE%" (
%ESSCON% -f po2txt.ess -o "%CESSE%" -c -x
)
set SCRIPT=%CESSE%
rem execute binary converter _1 - input po file
%ESSCON% -f "%SCRIPT%" -e po2txt;"%1" -x
rem %ESSCON% -f "%SCRIPT%" -e po2txt;"%1"
:exit