[TUTO] Programme Multi-Langue

Informations pour bien débuter en PureBasic
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

Freak (l'auteur de l'IDE) explique sa méthode pour gérer un programme plurilingue.

Je recopie le code ici pour éviter les problèmes de liens :)

Code : Tout sélectionner

; -----------------------------------------------------------------
;   Example of a simple language management for programs
; -----------------------------------------------------------------
;
; Benefits of this solution:
;  - Strings are identified by a Group and Name string, which allows to
;    organize them with descriptive names and makes coding easier.
;
;  - Strings are sorted and indexed when they are loaded, which gives
;    a fast access even though they are accessed by name.
;
;  - A default language is defined in the code (DataSection), so even if
;    external language files are missing or outdated, there is always a
;    fallback string present.
;
;  - The list of strings is easy to extend. Simply add a new entry in the
;    DataSection and the language files and use the new Group and Name.
;
;  - Additional language files are in the PB Preference format which makes
;    them easy to maintain.
;
; Usage:
;  - define the default language in the DataSection like shown below
;  - Use LoadLanguage() at least once to load the default language or external file
;  - Use Language(Group$, Name$) to access the language strings
;
; -----------------------------------------------------------------

; Some misc stuff...
;
Global NbLanguageGroups, NbLanguageStrings

Structure LanguageGroup
  Name$
  GroupStart.l
  GroupEnd.l
  IndexTable.l[256]
EndStructure

; This procedure loads the language from a file, or the default language.
; It must be called at least once before using any language strings.
;
; It does this:
;  - load & sort the included default language
;  - load any additional language from file
;
; This way you always get a language string, even if the file is not found
; or a string entry is missing in the file. You will still get the default
; language when using tha Language() command.
;
; This function can be called multiple times to change the used language
; during runtime.
;
Procedure LoadLanguage(FileName$ = "")

  ; do a quick count in the datasection first:
  ;
  NbLanguageGroups = 0
  NbLanguageStrings = 0

  Restore Language
  Repeat

    Read Name$
    Read String$

    Name$ = UCase(Name$)

    If Name$ = "_GROUP_"
      NbLanguageGroups + 1
    ElseIf Name$ = "_END_"
      Break
    Else
      NbLanguageStrings + 1
    EndIf
   
  ForEver

  Global Dim LanguageGroups.LanguageGroup(NbLanguageGroups)  ; all one based here
  Global Dim LanguageStrings.s(NbLanguageStrings)
  Global Dim LanguageNames.s(NbLanguageStrings)

  ; Now load the standard language:
  ; 
  Group = 0
  StringIndex = 0 

  Restore Language
  Repeat

    Read Name$
    Read String$

    Name$ = UCase(Name$)

    If Name$ = "_GROUP_"
      LanguageGroups(Group)\GroupEnd   = StringIndex
      Group + 1

      LanguageGroups(Group)\Name$      = UCase(String$)
      LanguageGroups(Group)\GroupStart = StringIndex + 1
      For i = 0 To 255
        LanguageGroups(Group)\IndexTable[i] = 0
      Next i
     
    ElseIf Name$ = "_END_"
      Break

    Else
      StringIndex + 1
      LanguageNames(StringIndex)   = Name$ + Chr(1) + String$  ; keep name and string together for easier sorting

    EndIf
   
  ForEver

  LanguageGroups(Group)\GroupEnd   = StringIndex ; set end for the last group!
 
  ; Now do the sorting and the indexing for each group
  ;
  For Group = 1 To NbLanguageGroups
    If LanguageGroups(Group)\GroupStart <= LanguageGroups(Group)\GroupEnd  ; sanity check.. check for empty groups
     
      SortArray(LanguageNames(), 0, LanguageGroups(Group)\GroupStart, LanguageGroups(Group)\GroupEnd)
 
      char = 0
      For StringIndex = LanguageGroups(Group)\GroupStart To LanguageGroups(Group)\GroupEnd
        LanguageStrings(StringIndex) = StringField(LanguageNames(StringIndex), 2, Chr(1)) ; splitt the value from the name
        LanguageNames(StringIndex)   = StringField(LanguageNames(StringIndex), 1, Chr(1))

        If Asc(Left(LanguageNames(StringIndex), 1)) <> char
          char = Asc(Left(LanguageNames(StringIndex), 1))
          LanguageGroups(Group)\IndexTable[char] = StringIndex
        EndIf
      Next StringIndex
     
    EndIf
  Next Group

  ; Now try to load an external language file
  ;       
  If FileName$ <> ""
     
    If OpenPreferences(FileName$)
      For Group = 1 To NbLanguageGroups
        If LanguageGroups(Group)\GroupStart <= LanguageGroups(Group)\GroupEnd  ; sanity check.. check for empty groups
          PreferenceGroup(LanguageGroups(Group)\Name$)
         
          For StringIndex = LanguageGroups(Group)\GroupStart To LanguageGroups(Group)\GroupEnd
            LanguageStrings(StringIndex) = ReadPreferenceString(LanguageNames(StringIndex), LanguageStrings(StringIndex))
          Next StringIndex
        EndIf
      Next Group
      ClosePreferences()   
     
      ProcedureReturn #True
    EndIf   

  EndIf
 
  ProcedureReturn #True
EndProcedure


; This function returns a string in the current language
; Each string is identified by a Group and a Name (both case insensitive)
;
; If the string is not found (not even in the included default language), the
; return is "##### String not found! #####" which helps to spot errors in the
; language code easily.
;
Procedure.s Language(Group$, Name$)
  Static Group.l  ; for quicker access when using the same group more than once
  Protected String$, StringIndex, Result

  Group$  = UCase(Group$)
  Name$   = UCase(Name$)
  String$ = "##### String not found! #####"  ; to help find bugs

  If LanguageGroups(Group)\Name$ <> Group$  ; check if it is the same group as last time   
    For Group = 1 To NbLanguageGroups
      If Group$ = LanguageGroups(Group)\Name$
        Break
      EndIf
    Next Group

    If Group > NbLanguageGroups  ; check if group was found
      Group = 0
    EndIf
  EndIf
 
  If Group <> 0
    StringIndex = LanguageGroups(Group)\IndexTable[ Asc(Left(Name$, 1)) ]
    If StringIndex <> 0

      Repeat
        Result = CompareMemoryString(@Name$, @LanguageNames(StringIndex))

        If Result = 0
          String$ = LanguageStrings(StringIndex)
          Break

        ElseIf Result = -1 ; string not found!
          Break

        EndIf

        StringIndex + 1
      Until StringIndex > LanguageGroups(Group)\GroupEnd

    EndIf

  EndIf

  ProcedureReturn String$
EndProcedure


DataSection

  ; Here the default language is specified. It is a list of Group, Name pairs,
  ; with some special keywords for the Group:
  ;
  ; "_GROUP_" will indicate a new group in the datasection, the second value is the group name
  ; "_END_" will indicate the end of the language list (as there is no fixed number)
  ;
  ; Note: The identifier strings are case insensitive to make live easier :)
 
  Language:

    ; ===================================================
    Data$ "_GROUP_",            "MenuTitle"
    ; ===================================================

      Data$ "File",             "File"
      Data$ "Edit",             "Edit"
                       
    ; ===================================================
    Data$ "_GROUP_",            "MenuItem"
    ; ===================================================

      Data$ "New",              "New"
      Data$ "Open",             "Open..."
      Data$ "Save",             "Save"
         
    ; ===================================================
    Data$ "_END_",              ""
    ; ===================================================

EndDataSection

; -----------------------------------------------------------------
; Example:
; -----------------------------------------------------------------

LoadLanguage()                ; load default language
;LoadLanguage("german.prefs") ; uncomment this to load the german file

; get some language strings
;
Debug Language("MenuTitle", "Edit")
Debug Language("MenuItem", "Save")

; -----------------------------------------------------------------
le fichier german.prefs pourrait ressembler à ça:

Code : Tout sélectionner

[MenuTitle]
File = Datei
Edit = Bearbeiten

[MenuItem]
New  = Neu
Open = Öffnen
Save = Speichern 

Source de l'information
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
kerkael
Messages : 97
Inscription : mer. 03/sept./2008 21:08

Message par kerkael »

Dommage que le format utilisé soit systématiquement de la forme Group,Name
Vu qu'une grande partie du code repose sur un regroupement des entrées, je n'arrive pas à le modifier pour ne garder qu'une simple liste de mots à traduire.
Ce n'est pas tant dans le fichier prefs appelé que dans la syntaxe à utiliser à chaque appel dans le programme principal :

Code : Tout sélectionner

Language("MenuTitle", "Game")
c'est plus lourd qu'un simple

Code : Tout sélectionner

Language("Game")
Avatar de l’utilisateur
Ar-S
Messages : 9539
Inscription : dim. 09/oct./2005 16:51
Contact :

Message par Ar-S »

En utilisant un fichier Prefs avec CreatePreferences c'est maintenant du gâteau de faire un prog multilangue !

On inclus le fichier langue dans l'exe

Code : Tout sélectionner

Path$=GetCurrentDirectory

DataSection
  StartFile0:
  IncludeBinary "F:\monfichierlangue.xxx"
  EndFile0:
enddatasection
A l'exécution du logiciel, si les prefs n'existent pas, il les extrait de lui même.

Code : Tout sélectionner

Pref=OpenPreferences(path$+"monfichierlangue.xxx")
If Pref=0 ; comme ça il ne le fait pas à chaque fois !
  Size=?EndFile0-?StartFile0 
  CreateFile(0,Path$+"monfichierlangue.xxx")
  WriteData(0, ?StartFile0,Size)
  CloseFile(0)
EndIf
Pour ce qui est du fichier langue lui-même je fais un fichier texte tel quel :

Code : Tout sélectionner

[FR]
Panel1 = Réseau
Panel2 = Securité
Panel3 = A Propos
[UK]
Panel1 = Lan
Panel2 = Security
Panel3 = About
tout simplement.

Ainsi on n'a qu'à utiliser PreferenceGroup("FR") ou PreferenceGroup("UK") pour choisir sa langue.

Le contenu du Panel un par exemple sera appelé de la sorte : textePanel1$=ReadPreferenceString("Panel1","")

Je trouve ça très sympa comme système.
Avatar de l’utilisateur
venom
Messages : 3128
Inscription : jeu. 29/juil./2004 16:33
Localisation : Klyntar
Contact :

Message par venom »

oui moi aussi je me sert des fichiers preferences :wink:

voici un exemple avec la source ( pas eu le temps de commenter mais ce soir c'est bon ) :wink: . et 2 fichiers langues.

telecharger
voila




@++
kerkael
Messages : 97
Inscription : mer. 03/sept./2008 21:08

Message par kerkael »

Tiens, j'ai pas pu télécharger/ouvrir le fichier avec winzip.
7zip non plus.
Seul winrar m'a permis de récupérer le code ... bizarre, non ?

Sinon dans ton code, tu fais 2 fois la définition de tes menus selon la langue FR ou UK ... l'intérêt au départ c'est quand même de ne pas avoir à faire autant de lignes que de langues, non ?

Mais j'ai compris le principe, et je me suis rajouté une procédure Affiche_Menu() qui redéfinit le menu à chaque fois qu'on appelle l'OptionLangue.

(Je reprends le code de Venom, puisse-t'il me pardonner mon impatience.)

Code : Tout sélectionner

    Select EventGadget()      

      Case #MENU_15
        FreeMenu(#MenuBar_0)
         OpenPreferences("languefr.txt")
          If CreateMenu(#MenuBar_0, WindowID(#Window_0))
            affiche_menu()
          EndIf 
         ClosePreferences()

      Case #MENU_16
        FreeMenu(#MenuBar_0)
         OpenPreferences("langueuk.txt")
          If CreateMenu(#MenuBar_0, WindowID(#Window_0))
           affiche_menu()
          EndIf 
         ClosePreferences()

       Case #MENU_7
         End 
      EndSelect
Et pour la procédure (que je préfère appeler depuis un fichier Include, et dont l'énumération serait sinon en tête du main.pb, mais là c'est du copié-collé du code Venom):

Code : Tout sélectionner

 Enumeration
  #MENU_3
  #MENU_4
  #MENU_5
  #MenuBar_0
  #MENU_7
  #MENU_9
  #MENU_10
  #MENU_11
  #MENU_12
  #MENU_13
  #MENU_15
  #MENU_16
EndEnumeration

 Procedure Affiche_menu()
 MenuTitle(ReadPreferenceString("0", ""))
      MenuItem(#MENU_3, ReadPreferenceString("1", ""))
      MenuItem(#MENU_4, ReadPreferenceString("2", ""))
      MenuItem(#MENU_5, ReadPreferenceString("3", ""))
      MenuBar()
      MenuItem(#MENU_7, ReadPreferenceString("4", ""))
      MenuTitle(ReadPreferenceString("5", ""))
      MenuItem(#MENU_9, ReadPreferenceString("6", ""))
      MenuItem(#MENU_10, ReadPreferenceString("7", ""))
      MenuItem(#MENU_11, ReadPreferenceString("8", ""))
      MenuTitle(ReadPreferenceString("9", ""))
      MenuItem(#MENU_12, ReadPreferenceString("10", ""))
      MenuItem(#MENU_13, ReadPreferenceString("11", ""))
      MenuTitle(ReadPreferenceString("12", ""))
      MenuItem(#MENU_15, ReadPreferenceString("13", ""))
      MenuItem(#MENU_16, ReadPreferenceString("14", ""))
 EndProcedure
Avatar de l’utilisateur
venom
Messages : 3128
Inscription : jeu. 29/juil./2004 16:33
Localisation : Klyntar
Contact :

Message par venom »

Salut kerkael ,

oui ce matin j'ai coder sa en 15 min avant d'aller au taf j'ai même pas pu me raser du coup :D , si non je serai passer par procédure mais c'était juste pour montrée comment faire facilement un multi langues.

je vais re modifier ma source avec ta procédure :wink:

ps: pour le dézippage je ne sais pas je me sert que de winrar :D

pss: le code a etait ajouté et modifier au zip, j'ai meme ajouté une fonction qui coche la langue choisis dans le menu pour le FUN :)




@++
Répondre