diff --git a/ChangeLog.txt b/ChangeLog.txt index 3d89166106..ce46bcf303 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -10,6 +10,27 @@ * Change, ! Fix, % Optimization, + Addition, - Removal, ; Comment */ +2013-04-02 00:00 UTC+0200 Viktor Szakats (harbour syenar.net) + * config/lang.hb + + now requires the target project to be passed on cmdline + + now pulls configuration from .hbp files. + See .hbp changes in this very commit. + + generalized the 'hbrun' special case in 'doc_make' mode + + generalized doc output type (so can be other than .md now) + % doesn't require hbrun tool anymore + ; it means the tool is now more or less generic and can + support else than hbmk2 + + * contrib/hbrun/hbrun.hbp + * utils/hbmk2/hbmk2.hbp + + added configuration options for lang.hb + + * utils/hbi18n/hbi18n.prg + + steps to make it better translatable + + * utils/hbmk2/hbmk2.prg + + provisions to enable context in hb_i18n_*() API usage + 2013-04-01 23:45 UTC+0200 Viktor Szakats (harbour syenar.net) * utils/hbmk2/lang.hb -> config/lang.hb * moved to global location diff --git a/config/lang.hb b/config/lang.hb index 3ce5bb7706..ff451cd6ee 100644 --- a/config/lang.hb +++ b/config/lang.hb @@ -23,7 +23,10 @@ */ /* - * Requires: curl (built with SSL) and Harbour in PATH + * Requires: + * - curl (built with SSL) + * - hbmk2 and hbi18n in PATH + * - the target .prg be runnable as script (for doc_make only) * Reference: http://help.transifex.com/features/api/api-v2.1.html */ @@ -31,7 +34,7 @@ #include "directry.ch" -PROCEDURE Main( cCommand, ... ) +PROCEDURE Main( cCommand, cMain, ... ) LOCAL hCommand := { ; "doc_make" => @doc_make(), ; /* Generate doc files for all languages */ @@ -39,62 +42,53 @@ PROCEDURE Main( cCommand, ... ) "trs_pull" => @trs_pull(), ; /* Download translations from Transifex localization service */ "trs_push" => @trs_push() } /* Upload local translations to Transifex localization service */ - IF ! Empty( cCommand ) .AND. cCommand $ hCommand + IF ! Empty( cCommand ) .AND. cCommand $ hCommand .AND. HB_ISSTRING( cMain ) Set( _SET_DEFEXTENSIONS, .F. ) - Eval( hCommand[ cCommand ], ... ) + Eval( ; + hCommand[ cCommand ], ; + hb_PathJoin( hb_DirBase(), iif( Empty( hb_FNameName( cMain := hb_DirSepToOS( cMain ) ) ), cMain + hb_FNameName( hb_DirSepDel( cMain ) ) + ".prg", cMain ) ), ; + ... ) ELSE - ? "unknown command" + ? "unknown command or missing target" ENDIF RETURN /* --------------------------------------------- */ -STATIC PROCEDURE doc_make() +STATIC PROCEDURE doc_make( cMain ) - LOCAL cBase := hb_DirBase() + LOCAL hPar := LoadPar( cMain ) LOCAL file LOCAL cLang - LOCAL cTemp + LOCAL cTempHRB - LOCAL cMain := cBase + "hbmk2.prg" /* must be runnable as script */ - LOCAL cDocOptions := "-lang={LANG} -longhelpmd" - LOCAL cBaseLang := "en" - LOCAL cPO_Dir := cBase + hb_DirSepToOS( "po/" ) - LOCAL cDoc_Dir := cBase + hb_DirSepToOS( "doc/" ) + IF ! Empty( hPar[ "docoption" ] ) - IF ! Empty( cDocOptions ) - - cTemp := hb_FNameExtSet( cMain, ".hrb" ) + cTempHRB := hb_FNameExtSet( hPar[ "entry" ], ".hrb" ) ? "generating documentation:" - hb_run( hb_StrFormat( "hbmk2 -hbraw -q0 %1$s -gh -o%2$s", cMain, cTemp ) ) + hb_run( hb_StrFormat( "hbmk2 -hbraw -q0 %1$s -gh -o%2$s", hPar[ "entry" ], cTempHRB ) ) - FOR EACH cLang IN hb_ATokens( cBaseLang + "," + hb_regexAll( "-lng=([a-zA-Z0-9_\-,]*)", hb_MemoRead( hb_FNameExtSet( cMain, ".hbp" ) ),,,,, .T. )[ 1 ][ 2 ], "," ) + FOR EACH cLang IN hb_AIns( hPar[ "langs" ], 1, hPar[ "baselang" ], .T. ) ?? "", cLang hb_run( hb_StrFormat( "hbi18n -q -g %1$s -o%2$s", ; - cPO_Dir + hb_FNameName( cMain ) + "." + cLang + ".po", ; - hb_FNameDir( cMain ) + hb_FNameName( cMain ) + "." + cLang + ".hbl" ) ) + hPar[ "po" ] + hb_FNameName( hPar[ "entry" ] ) + "." + cLang + ".po", ; + hb_FNameDir( hPar[ "entry" ] ) + hb_FNameName( hPar[ "entry" ] ) + "." + cLang + ".hbl" ) ) - file := cDoc_Dir + hb_FNameName( cMain ) + "." + cLang + ".md" - hb_run( hb_StrFormat( "hbrun %1$s %2$s > %3$s", cTemp, StrTran( cDocOptions, "{LANG}", cLang ), file ) ) + file := hb_FNameExtSet( hPar[ "doc" ] + hPar[ "name" ] + "." + cLang, hPar[ "docext" ] ) + hb_run( hb_StrFormat( "hbmk2 %1$s %2$s > %3$s", ; + cTempHRB, StrTran( ArrayToList( hPar[ "docoption" ] ), "{LNG}", cLang ), file ) ) FToNativeEOL( file ) - /* special case */ - IF hb_FNameName( cMain ) == "hbmk2" - file := hb_FNameDir( cMain ) + hb_DirSepToOS( "../../contrib/hbrun/doc/" ) + "hbrun" + "." + cLang + ".md" - hb_run( hb_StrFormat( "hbrun %1$s %2$s > %3$s", cTemp, StrTran( "-lang={LANG} -longhelpmdsh", "{LANG}", cLang ), file ) ) - FToNativeEOL( file ) - ENDIF - - FErase( hb_FNameDir( cMain ) + hb_FNameName( cMain ) + "." + cLang + ".hbl" ) + FErase( hb_FNameDir( hPar[ "entry" ] ) + hb_FNameName( hPar[ "entry" ] ) + "." + cLang + ".hbl" ) NEXT - FErase( cTemp ) + FErase( cTempHRB ) ENDIF RETURN @@ -104,31 +98,23 @@ STATIC FUNCTION FToNativeEOL( cFile ) /* --------------------------------------------- */ -STATIC PROCEDURE src_push( cLogin ) +STATIC PROCEDURE src_push( cMain ) - LOCAL cBase := hb_DirBase() + LOCAL hPar := LoadPar( cMain ) LOCAL json - LOCAL cTemp, cTemp2 + LOCAL cTempContent + LOCAL cTempResult LOCAL cContent - LOCAL cProject := "harbour" - LOCAL cMain := cBase + "hbmk2.prg" - LOCAL cBaseLang := "en" - LOCAL cPO_Dir := cBase + hb_DirSepToOS( "po/" ) - - IF Empty( cLogin ) - cLogin := GetEnv( "HB_TRANSIFEX_LOGIN" ) /* Format: username:password */ - ENDIF - - FClose( hb_FTempCreateEx( @cTemp, , , ".pot" ) ) - FClose( hb_FTempCreateEx( @cTemp2 ) ) + FClose( hb_FTempCreateEx( @cTempContent, , , ".pot" ) ) + FClose( hb_FTempCreateEx( @cTempResult ) ) ? "generating translation source" - hb_run( hb_StrFormat( "hbmk2 -hbraw -q0 %1$s -j%2$s -s", cMain, cTemp ) ) + hb_run( hb_StrFormat( "hbmk2 -hbraw -q0 %1$s -j%2$s -s", hPar[ "entry" ], cTempContent ) ) - POT_Sort( cTemp ) + POT_Sort( cTempContent ) ? "saving locally" @@ -140,30 +126,31 @@ STATIC PROCEDURE src_push( cLogin ) '"Language: %2$s\n"' + hb_eol() + ; '"MIME-Version: 1.0\n"' + hb_eol() + ; '"Content-Type: text/plain; charset=UTF-8\n"' + hb_eol() + ; - '"Content-Transfer-Encoding: 8bit\n"', hb_FNameName( cMain ), cBaseLang ) + hb_eol() + ; + '"Content-Transfer-Encoding: 8bit\n"', hb_FNameName( hPar[ "entry" ] ), hPar[ "baselang" ] ) + hb_eol() + ; hb_eol() + ; - hb_MemoRead( cTemp ) + hb_MemoRead( cTempContent ) - hb_MemoWrit( cPO_Dir + hb_FNameName( cMain ) + "." + cBaseLang + ".po", cContent ) + hb_MemoWrit( hPar[ "po" ] + hb_FNameName( hPar[ "entry" ] ) + "." + hPar[ "baselang" ] + ".po", cContent ) ? "uploading", "size", hb_ntos( Len( cContent ) ) - hb_MemoWrit( cTemp, hb_jsonEncode( { "content" => StrTran( cContent, hb_eol(), e"\n" ) } ) ) + hb_MemoWrit( cTempContent, hb_jsonEncode( { "content" => StrTran( cContent, hb_eol(), e"\n" ) } ) ) hb_run( hb_StrFormat( 'curl -s -i -L --user %1$s -X ' + ; 'PUT -d @%2$s -H "Content-Type: application/json" ' + ; 'https://www.transifex.com/api/2/project/%3$s/resource/%4$s/content/' + ; ' -o %5$s', ; - cLogin, cTemp, cProject, hb_FNameName( cMain ), cTemp2 ) ) + hPar[ "login" ], cTempContent, hPar[ "project" ], ; + hb_FNameName( hPar[ "entry" ] ), cTempResult ) ) - IF hb_jsonDecode( GetJSON( hb_MemoRead( cTemp2 ) ), @json ) > 0 + IF hb_jsonDecode( GetJSON( hb_MemoRead( cTempResult ) ), @json ) > 0 ? hb_ValToExp( json ) ELSE ? "API error" ENDIF - FErase( cTemp ) - FErase( cTemp2 ) + FErase( cTempContent ) + FErase( cTempResult ) RETURN @@ -183,50 +170,44 @@ STATIC FUNCTION POT_Sort( cFileName ) /* --------------------------------------------- */ -STATIC PROCEDURE trs_pull( cLogin ) +STATIC PROCEDURE trs_pull( cMain ) - LOCAL cBase := hb_DirBase() + LOCAL hPar := LoadPar( cMain ) LOCAL json LOCAL cLang - LOCAL cTemp + LOCAL cTempResult - LOCAL cProject := "harbour" - LOCAL cMain := cBase + "hbmk2.prg" - LOCAL cPO_Dir := cBase + hb_DirSepToOS( "po/" ) - - IF Empty( cLogin ) - cLogin := GetEnv( "HB_TRANSIFEX_LOGIN" ) /* Format: username:password */ - ENDIF - - FClose( hb_FTempCreateEx( @cTemp ) ) + FClose( hb_FTempCreateEx( @cTempResult ) ) ? "pulling translations:" - FOR EACH cLang IN hb_ATokens( hb_regexAll( "-lng=([a-zA-Z0-9_\-,]*)", hb_MemoRead( hb_FNameExtSet( cMain, ".hbp" ) ),,,,, .T. )[ 1 ][ 2 ], "," ) + FOR EACH cLang IN hPar[ "langs" ] ?? "", cLang hb_run( hb_StrFormat( "curl -s -i -L --user %1$s -X " + ; "GET https://www.transifex.com/api/2/project/%2$s/resource/%3$s/translation/%4$s/" + ; " -o %5$s", ; - cLogin, cProject, hb_FNameName( cMain ), cLang, cTemp ) ) + hPar[ "login" ], hPar[ "project" ], ; + hb_FNameName( hPar[ "entry" ] ), cLang, cTempResult ) ) - IF hb_jsonDecode( GetJSON( hb_MemoRead( cTemp ) ), @json ) > 0 - hb_MemoWrit( cTemp, json[ "content" ] ) - POT_Sort( cTemp ) + IF hb_jsonDecode( GetJSON( hb_MemoRead( cTempResult ) ), @json ) > 0 + hb_MemoWrit( cTempResult, json[ "content" ] ) + POT_Sort( cTempResult ) /* should only do this if the translation is primarily done on Transifex website. This encouraged and probably the case in practice. Delete source information, delete empty translations and apply some automatic transformation for common translation mistakes. */ - PO_Clean( cTemp, cPO_Dir + hb_FNameName( cMain ) + "." + cLang + ".po", .F., .F., @DoctorTranslation() ) + PO_Clean( cTempResult, hPar[ "po" ] + hb_FNameName( hPar[ "entry" ] ) + "." + cLang + ".po", ; + .F., .F., @DoctorTranslation() ) ELSE ? "API error" ENDIF NEXT - FErase( cTemp ) + FErase( cTempResult ) RETURN @@ -305,49 +286,43 @@ STATIC FUNCTION PO_Clean( cFNSource, cFNTarget, ... ) /* --------------------------------------------- */ -STATIC PROCEDURE trs_push( cLogin ) +STATIC PROCEDURE trs_push( cMain ) - LOCAL cBase := hb_DirBase() + LOCAL hPar := LoadPar( cMain ) LOCAL json - LOCAL cTemp, cTemp2 + LOCAL cLang + LOCAL cTempContent + LOCAL cTempResult LOCAL cContent - LOCAL cProject := "harbour" - LOCAL cMain := cBase + "hbmk2.prg" - LOCAL cLang - LOCAL cPO_Dir := cBase + hb_DirSepToOS( "po/" ) + FClose( hb_FTempCreateEx( @cTempContent ) ) + FClose( hb_FTempCreateEx( @cTempResult ) ) - IF Empty( cLogin ) - cLogin := GetEnv( "HB_TRANSIFEX_LOGIN" ) /* Format: username:password */ - ENDIF + FOR EACH cLang IN hPar[ "langs" ] - FClose( hb_FTempCreateEx( @cTemp ) ) - FClose( hb_FTempCreateEx( @cTemp2 ) ) - - FOR EACH cLang IN hb_ATokens( hb_regexAll( "-lng=([a-zA-Z0-9_\-,]*)", hb_MemoRead( hb_FNameExtSet( cMain, ".hbp" ) ),,,,, .T. )[ 1 ][ 2 ], "," ) - - cContent := hb_MemoRead( cPO_Dir + hb_FNameName( cMain ) + "." + cLang + ".po" ) + cContent := hb_MemoRead( hPar[ "po" ] + hb_FNameName( hPar[ "entry" ] ) + "." + cLang + ".po" ) ? "uploading translation", "size", Len( cContent ) - hb_MemoWrit( cTemp, hb_jsonEncode( { "content" => StrTran( cContent, hb_eol(), e"\n" ) } ) ) + hb_MemoWrit( cTempContent, hb_jsonEncode( { "content" => StrTran( cContent, hb_eol(), e"\n" ) } ) ) hb_run( hb_StrFormat( 'curl -s -i -L --user %1$s -X ' + ; 'PUT -d @%2$s -H "Content-Type: application/json" ' + ; 'https://www.transifex.com/api/2/project/%3$s/resource/%4$s/translation/%5$s/' + ; ' -o %6$s', ; - cLogin, cTemp, cProject, hb_FNameName( cMain ), cLang, cTemp2 ) ) + hPar[ "login" ], cTempContent, hPar[ "project" ], ; + hb_FNameName( hPar[ "entry" ] ), cLang, cTempResult ) ) - IF hb_jsonDecode( GetJSON( hb_MemoRead( cTemp2 ) ), @json ) > 0 + IF hb_jsonDecode( GetJSON( hb_MemoRead( cTempResult ) ), @json ) > 0 ? hb_ValToExp( json ) ELSE ? "API error" ENDIF NEXT - FErase( cTemp ) - FErase( cTemp2 ) + FErase( cTempContent ) + FErase( cTempResult ) RETURN @@ -359,3 +334,71 @@ STATIC FUNCTION GetJSON( cString ) cString := Left( cString, RAt( "}", cString ) ) RETURN cString + +STATIC FUNCTION ArrayToList( array ) + + LOCAL cString := "" + LOCAL tmp + + FOR EACH tmp IN array + cString += tmp + IF ! tmp:__enumIsLast() + cString += " " + ENDIF + NEXT + + RETURN cString + +STATIC FUNCTION _HAGetDef( xContainer, xDefault, ... ) + + LOCAL item + + IF PCount() > 2 + FOR EACH item IN { ... } + IF ( HB_ISHASHKEY( item ) .AND. HB_ISHASH( xContainer ) .AND. item $ xContainer ) .OR. ; + ( HB_ISNUMERIC( item ) .AND. HB_ISARRAY( xContainer ) .AND. item >= 1 .AND. item <= Len( xContainer ) ) + xContainer := xContainer[ item ] + ELSE + RETURN xDefault + ENDIF + NEXT + RETURN xContainer + ENDIF + + RETURN xDefault + +STATIC FUNCTION LoadPar( cMain ) + + LOCAL hPar := { => } + + LOCAL cConfig + LOCAL item + + hPar[ "entry" ] := cMain + + cConfig := hb_MemoRead( hb_FNameExtSet( hPar[ "entry" ], ".hbp" ) ) + + hPar[ "project" ] := "harbour" + hPar[ "login" ] := GetEnv( "HB_TRANSIFEX_LOGIN" ) /* Format: username:password */ + hPar[ "name" ] := hb_FNameName( hPar[ "entry" ] ) + hPar[ "doc" ] := hb_FNameDir( hPar[ "entry" ] ) + hb_DirSepToOS( "doc/" ) + hPar[ "docext" ] := _HAGetDef( hb_regexAll( "-3rd=_hblang_docext=([\S]*)", cConfig,,,,, .T. ), ".txt", 1, 2 ) + hPar[ "docoption" ] := {} + FOR EACH item IN hb_regexAll( "-3rd=_hblang_docoption=([\S]*)", cConfig,,,,, .T. ) + AAdd( hPar[ "docoption" ], item[ 2 ] ) + NEXT + + item := hb_PathJoin( hb_DirBase(), _HAGetDef( hb_regexAll( "-3rd=_hblang_entry=([\S]*)", cConfig,,,,, .T. ), NIL, 1, 2 ) ) + IF item != NIL + item := hb_FNameDir( hPar[ "entry" ] ) + hb_DirSepToOS( item ) + hPar[ "entry" ] := iif( Empty( hb_FNameName( item ) ), item + hb_FNameName( hb_DirSepDel( item ) ) + ".prg", item ) + ENDIF + + cConfig := hb_MemoRead( hb_FNameExtSet( hPar[ "entry" ], ".hbp" ) ) + + hPar[ "langs" ] := hb_ATokens( _HAGetDef( hb_regexAll( "-lng=([\w,]*)", cConfig,,,,, .T. ), "", 1, 2 ), "," ) + hPar[ "baselang" ] := _HAGetDef( hb_regexAll( "-3rd=_hblang_base=([\w]*)", cConfig,,,,, .T. ), "en", 1, 2 ) + + hPar[ "po" ] := hb_FNameDir( hPar[ "entry" ] ) + hb_DirSepToOS( "po/" ) + + RETURN hPar diff --git a/contrib/hbrun/hbrun.hbp b/contrib/hbrun/hbrun.hbp index 72636b98a2..ca0f22fdc8 100644 --- a/contrib/hbrun/hbrun.hbp +++ b/contrib/hbrun/hbrun.hbp @@ -27,3 +27,9 @@ {!(__HBMKDYN='yes')}hbnetio.hbc {!(__HBMKDYN='yes')}-request=__HBEXTERN__HBNETIO__ {!(__HBMKDYN='yes')&unix}hbunix.hbc {!(__HBMKDYN='yes')&unix}-request=__HBEXTERN__HBUNIX__ {!(__HBMKDYN='yes')&allwin}hbwin.hbc {!(__HBMKDYN='yes')&allwin}-request=__HBEXTERN__HBWIN__ + +# localization (automatization) +-3rd=_hblang_entry=../../utils/hbmk2/ +-3rd=_hblang_docext=.md +-3rd=_hblang_docoption=-lang={LNG} +-3rd=_hblang_docoption=-longhelpmdsh diff --git a/utils/hbi18n/hbi18n.prg b/utils/hbi18n/hbi18n.prg index a0378e67fb..c78ee2de57 100644 --- a/utils/hbi18n/hbi18n.prg +++ b/utils/hbi18n/hbi18n.prg @@ -174,18 +174,16 @@ STATIC PROCEDURE Logo() STATIC PROCEDURE Syntax() Logo() - OutStd( I_( ; - "Syntax: hbi18n -m | -g | -a [-o] [-e] [-q] " + hb_eol() + ; + OutStd( ; + I_( "Syntax: hbi18n -m | -g | -a [-o] [-e] [-q] " ) + hb_eol() + ; hb_eol() + ; - " -m merge given .pot files" + hb_eol() + ; - " -g generate .hbl file from given .pot files" + hb_eol() + ; - " -a add automatic translations to 1-st .pot file using" + hb_eol() + ; - " translations from other .pot or .hbl files" + hb_eol() + ; - " -o output file name" + hb_eol() + ; - " default is first .pot file name with" + hb_eol() + ; - " .po (merge) or .hbl extension" + hb_eol() + ; - " -e do not strip empty translation rules from .hbl files" + hb_eol() + ; - " -q quiet mode" + hb_eol() ) + ; + " -m " + I_( "merge given .pot files" ) + hb_eol() + ; + " -g " + I_( "generate .hbl file from given .pot files" ) + hb_eol() + ; + " -a " + I_( "add automatic translations to 1st .pot file using translations from other .pot/.hbl files" ) + hb_eol() + ; + " -o " + I_( "output file name" ) + hb_eol() + ; + " " + I_( "default is first .pot file name with .po (merge) or .hbl extension" ) + hb_eol() + ; + " -e " + I_( "do not strip empty translation rules from .hbl files" ) + hb_eol() + ; + " -q " + I_( "quiet mode" ) + hb_eol() + ; hb_eol() ) IF hb_gtInfo( HB_GTI_ISGRAPHIC ) diff --git a/utils/hbmk2/hbmk2.hbp b/utils/hbmk2/hbmk2.hbp index 4f4848bf7f..b198f6bd3c 100644 --- a/utils/hbmk2/hbmk2.hbp +++ b/utils/hbmk2/hbmk2.hbp @@ -20,13 +20,18 @@ hbmk2.prg -lhbpmcom{dos} -po/hbmk2.%{hb_lng}.po --hbl=hbmk2.%{hb_lng}.hbl - --lng=el,es_419,es_ES,fr_FR,hu,it,pt_BR - # not using these together with .rc input, because some compilers (mingw) # do not support multiple .rc inputs #-icon={allwin}../../package/harb_win.ico #-icon={os2}../../package/harb_os2.ico hbmk2.rc + +# localization +po/hbmk2.%{hb_lng}.po +-hbl=hbmk2.%{hb_lng}.hbl +-lng=el,es_419,es_ES,fr_FR,hu,it,pt_BR + +# localization (automatization) +-3rd=_hblang_docext=.md +-3rd=_hblang_docoption=-lang={LNG} +-3rd=_hblang_docoption=-longhelpmd diff --git a/utils/hbmk2/hbmk2.prg b/utils/hbmk2/hbmk2.prg index 866e9a2b4e..8c53568429 100644 --- a/utils/hbmk2/hbmk2.prg +++ b/utils/hbmk2/hbmk2.prg @@ -188,7 +188,7 @@ EXTERNAL hbmk_KEYW #define _SELF_NAME_ "hbmk2" -#define I_( x ) hb_UTF8ToStr( hb_i18n_gettext( x ) ) +#define I_( x ) hb_UTF8ToStr( hb_i18n_gettext( x /*, _SELF_NAME_ */ ) ) #define R_( x ) ( x ) /* marking for regexps */ #define _TARG_PLAT 1 @@ -15629,8 +15629,8 @@ STATIC PROCEDURE ShowHeader( hbmk ) Eval( hbmk[ _HBMK_bOut ], cText ) IF !( Lower( Left( hbmk[ _HBMK_cUILNG ], 2 ) ) == "en" ) - cTrsText := hb_i18n_gettext_noop( "Translation (%1$s): (add your name here)" ) - cTrsTextI := I_( cTrsText ) + cTrsText := hb_i18n_gettext_noop( "Translation (%1$s): (add your name here)" /*, _SELF_NAME_ */ ) + cTrsTextI := hb_UTF8ToStr( hb_i18n_gettext( cTrsText ) ) IF !( cTrsText == cTrsTextI ) .AND. ! Empty( cTrsTextI ) cText := hb_StrFormat( cTrsTextI, hbmk[ _HBMK_cUILNG ] ) + e"\n" IF hbmk[ _HBMK_lMarkdown ]