Gettext für PB

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
ParkL
Beiträge: 17
Registriert: 02.11.2004 16:13
Wohnort: Ruhrpott
Kontaktdaten:

Gettext für PB

Beitrag von ParkL »

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:

Code: Alles auswählen

myFunnyString.s = GetText("Hello World !")
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 ...

Code: Alles auswählen

# Easy Gettext Language File. Please use '\n' to signal a line feed !
GETTEXT
Language
Languagecode
OK
*
Cancel
*
Options
*
uswusf.

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
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

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

Zuletzt geändert von ParkL am 14.01.2005 14:53, insgesamt 1-mal geändert.
Benutzeravatar
bluejoke
Beiträge: 1244
Registriert: 08.09.2004 16:33
Kontaktdaten:

Beitrag von bluejoke »

Fette Sache!
optional wär mir aber eine UserLib super recht!
Ich bin Ausländer - fast überall
Windows XP Pro SP2 - PB 4.00
Antworten