Gettext für PB
Verfasst: 13.01.2005 20:25
Hallo !
Ich habe ein kleines Multi-Language Tool für PB geschrieben, das sich an der bekannten GetText Bibliothek für C orientiert.
Das Prinzip funktioniert so:
Man lädt eine Sprachdatei mit der Funktion GetText_LoadLanguage(file.s)
Wenn man dann dynamische Textpassagen verwendet, läßt man sich diese als Rückgabewert der Funktion GetText liefern.
Beispiel:
Die GetText Funktion überprüft, ob für diesen String ein Eintrag vorhanden ist. Wenn ja, gibt sie die passende Übersetzung zurück. Falls nein, gibt sie das Original zurück.
Der "Clou" ist aber folgendes:
Schaltet man #GETTEXT_CREATE_TEMPLATE auf 1 so sammelt die GetText Funktion alle Keys ein, an denen sie aufgerufen wird und schreibt sie in eine Liste. Wird danach GetText_WriteLanguage(file.s) aufgerufen, wird ein file.s erzeugt, das ein Template für eine Übersetzung enthält.
In Etwa so ...
uswusf.
Das ersetzen wir dann durch sowas:
Dann speichern wir das ganze unter "deutsch.txt" oder so und wir haben unser languagefile, das wir dann mit GetText_LoadLanguage("deutsch.txt") laden können.
Für gute Performance benutzt das Teil Quicksort (O(n log n)) und binäre suche O(log n). Die Vergleiche werden über den vorberechneten CRC32 des Textes gemacht. Das sollte also hinreichend zackig gehen.
Phiel Phergnügen
Ich habe ein kleines Multi-Language Tool für PB geschrieben, das sich an der bekannten GetText Bibliothek für C orientiert.
Das Prinzip funktioniert so:
Man lädt eine Sprachdatei mit der Funktion GetText_LoadLanguage(file.s)
Wenn man dann dynamische Textpassagen verwendet, läßt man sich diese als Rückgabewert der Funktion GetText liefern.
Beispiel:
Code: Alles auswählen
myFunnyString.s = GetText("Hello World !")
Der "Clou" ist aber folgendes:
Schaltet man #GETTEXT_CREATE_TEMPLATE auf 1 so sammelt die GetText Funktion alle Keys ein, an denen sie aufgerufen wird und schreibt sie in eine Liste. Wird danach GetText_WriteLanguage(file.s) aufgerufen, wird ein file.s erzeugt, das ein Template für eine Übersetzung enthält.
In Etwa so ...
Code: Alles auswählen
# Easy Gettext Language File. Please use '\n' to signal a line feed !
GETTEXT
Language
Languagecode
OK
*
Cancel
*
Options
*
Das ersetzen wir dann durch sowas:
Code: Alles auswählen
# Easy Gettext Language File. Please use '\n' to signal a line feed !
GETTEXT
Deutsch
de
OK
Okay\n(Ich geb zu das ist bescheuert)
Cancel
Abbrechen
Options
Optionen
Für gute Performance benutzt das Teil Quicksort (O(n log n)) und binäre suche O(log n). Die Vergleiche werden über den vorberechneten CRC32 des Textes gemacht. Das sollte also hinreichend zackig gehen.
Phiel Phergnügen
Code: Alles auswählen
;/ Gettext for PB by ParkL
;/
;/ USAGE:
;/ Whenever you use a string that's supposed to be internationalized use the GetText function.
;/
;/ Example:
;/ mytext.s = "Blah Blah Blah" --> mytext.s = GetText("Blah Blah Blah")
;/
;/ If the string you pass is in the translation list, the translated text will be returned.
;/ If it isn't in the list, the initial string you passed to GetText() will be returned.
;/
;/ To Load a language file use the GetText_LoadLanguage(file.s) function.
;/
;/ To create a language template file for your programm set the #GETTEXT_CREATE_TEMPLATE
;/ constant to 1. GetText() will now "collect" the strings you pass in a seperate list. Play around
;/ until you're sure gettext has collected all strings you want to be on your
;/ translation template (duplicates will be skipped). Then call GetText_WriteLanguage(file.s).
;/
;/ compilerif #GETTEXT_CREATE_TEMPLATE
;/ GetText_WriteLanguage("template.txt")
;/ compilerendif
;/ end
;/
;/ Note:
;/
;/ To create a template file #GETTEXT_CREATE_TEMPLATE must be true or the GetText_WriteLanguage()
;/ function simply won't exist because of the compiler directives.
#GETTEXT_CREATE_TEMPLATE = 0 ;If you want to create a template file set this to 1
Structure _GetText_KeyValuePair
Key.l
Value.s
StructureUnion
language.s
languagecode.s
EndStructureUnion
EndStructure
CompilerIf #PB_Compiler_OS = #PB_OS_Windows ;OK, let's use CRLF as a Newline Symbol for Win
GetText_newline.s = Chr(13)+Chr(10)
CompilerElse ; LF for the other platforms
GetText_newline.s = Chr(10)
CompilerEndIf
NewList _GetText_ReadList._GetText_KeyValuePair() ;Temporary List for loading the language file.
Dim _GetText_List._GetText_KeyValuePair(0) ;The list we'll be sorting and searching
Global _GetText_ListCount.l ;Internal Var with the list-count
CompilerIf #GETTEXT_CREATE_TEMPLATE ;OK, we need 2 more functions if we'd like to create a template
NewList GetText_Keys.s()
Procedure _GetText_InList(text.s) ; PRIVATE, don't worry about this one
ForEach GetText_Keys()
If GetText_Keys() = text
ProcedureReturn 1
EndIf
Next
ProcedureReturn 0
EndProcedure
Procedure GetText_WriteLanguage(file.s) ;file is the filename of the template file you want to write. Returns 0 on fail !
Protected fhnd.l
fhnd = CreateFile(#PB_Any, file)
If fhnd
WriteStringN("# Easy Gettext Language File. Please use '\n' to signal a line feed !")
WriteStringN("GETTEXT")
WriteStringN("Language")
WriteStringN("Langcode")
ForEach GetText_Keys()
WriteStringN(GetText_Keys())
WriteStringN("*")
Next
CloseFile(fhnd)
ProcedureReturn 1
EndIf
ProcedureReturn 0
EndProcedure
CompilerEndIf
Procedure _GetText_Search(search.s) ; PRIVATE, binary search for the text's CRC
Protected pivot, searchcrc, success.l, fe.l, le.l
fe = 0
le = _GetText_ListCount-1
success = 0
searchcrc = CRC32Fingerprint(search, Len(search))
Repeat
pivot = (fe+le)/2
If _GetText_List(pivot)\Key = searchcrc
success = 1
Else
If searchcrc < _GetText_List(pivot)\Key
le = pivot -1
Else
fe = pivot +1
EndIf
EndIf
Until success Or fe > le
If success
ProcedureReturn pivot
Else
ProcedureReturn 0
EndIf
EndProcedure
Procedure _GetText_Quicksort_Divide(left, right) ; PRIVATE, little QS-Divide Function
Protected pivot, swap.l
pivot = _GetText_List((left + right)/2)\Key
While left<right
While _GetText_List(left)\Key < pivot And left<right
left+1
Wend
While _GetText_List(right)\Key > pivot And left < right
right-1
Wend
swap = AllocateMemory(SizeOf(_GetText_KeyValuePair))
CopyMemory(@_GetText_List(left), swap, SizeOf(_GetText_KeyValuePair))
CopyMemory(@_GetText_List(right), @_GetText_List(left), SizeOf(_GetText_KeyValuePair))
CopyMemory(swap, @_GetText_List(right), SizeOf(_GetText_KeyValuePair))
FreeMemory(swap)
Wend
ProcedureReturn left
EndProcedure
Procedure _GetText_Quicksort(left, right) ; PRIVATE, little QS
Protected division
If right > left
division = _GetText_Quicksort_Divide(left, right)
_GetText_Quicksort(left, division)
_GetText_Quicksort(division+1, right)
EndIf
EndProcedure
Procedure.s GetText_GetLanguage() ;Returns the Name of the Language else ""
If _GetText_ListCount
ProcedureReturn _GetText_List(0)\language
Else
ProcedureReturn ""
EndIf
EndProcedure
Procedure.s GetText_GetLanguageCode() ;Returns the Code of the Language else ""
If _GetText_ListCount
ProcedureReturn _GetText_List(0)\languagecode
Else
ProcedureReturn ""
EndIf
EndProcedure
Procedure GetText_LoadLanguage(file.s) ;Load a language file. Will return 0 on fail.
Protected fhnd.l, i.l, strin.s, lang.s, langcode.s
fhnd = ReadFile(#PB_Any, file)
If fhnd
ClearList(_GetText_ReadList())
i=0
While Eof(fhnd) = 0
strin = ReadString()
If Mid(Trim(strin), 0, 1) <> "#"
Select i
Case 0
If strin<>"GETTEXT"
ProcedureReturn 0
EndIf
Case 1
lang = strin
Case 2
langcode = strin
Default
If (i%2)=1
AddElement(_GetText_ReadList())
_GetText_ReadList()\Key = CRC32Fingerprint(strin, Len(strin))
Else
_GetText_ReadList()\Value = strin
EndIf
EndSelect
i+1
EndIf
Wend
CloseFile(fhnd)
_GetText_ListCount = CountList(_GetText_ReadList())
If _GetText_ListCount
_GetText_ReadList()\language = lang
_GetText_ReadList()\languagecode = langcode
Dim _GetText_List._GetText_KeyValuePair(_GetText_ListCount)
i=0
ForEach _GetText_ReadList()
CopyMemory(@_GetText_ReadList(), @_GetText_List(i), SizeOf(_GetText_KeyValuePair))
i+1
Next
EndIf
;Sort our List to CRC asc for Binary Search later
_GetText_Quicksort(0, _GetText_ListCount-1)
ProcedureReturn _GetText_ListCount
EndIf
ProcedureReturn 0
EndProcedure
Procedure.s GetText(text.s) ; Returns text.s's translation, if text.s isn't found in the translation list it returns text.s
Shared GetText_newline.s
Protected i, searchtext.s
CompilerIf #GETTEXT_CREATE_TEMPLATE
If _GetText_InList(text) = 0
AddElement(GetText_Keys())
GetText_Keys() = text
EndIf
CompilerEndIf
searchtext = ReplaceString(text, GetText_newline, "\n")
i = _GetText_Search(searchtext)
If i
ProcedureReturn ReplaceString(_GetText_List(i)\Value, "\n", GetText_newline)
Else
ProcedureReturn text
EndIf
EndProcedure
;- Example
If OpenConsole()
If GetText_LoadLanguage("c:\langtest.txt")
PrintN("Lang-File found.")
Else
PrintN("Lang-File not found. Using standard texts.")
EndIf
PrintN(GetText("This is a test ! ;)"))
PrintN(GetText("Another test !"))
CompilerIf #GETTEXT_CREATE_TEMPLATE
GetText_WriteLanguage("langtemplate.txt")
CompilerEndIf
Input()
CloseConsole()
EndIf