Page 1 of 1

GUI Translation without restart

Posted: Mon Sep 05, 2011 10:51 am
by beo6
Hello everyone.

I messed around with some way to make a multi-language application without the need to restart the application.
I used that method in this application:
http://sascha.loeffler.gs/downloads/webcamget20.php

so here are the functions:

this is to create the dynamic popup menu of all languages found in the language.xml

Code: Select all

Procedure createLanguagePopupMenu(Menu, countFrom, countTo, languageListString$ = "german")
  Define i, singleLanguage$, langcount
  ;langcount = CountString(languageListString$, ",")
  langcount = 1
  
  If IsMenu(Menu)
    FreeMenu(Menu)
  EndIf
  
  If CreatePopupMenu(Menu)
    If countFrom < countTo
      For i = countFrom To countTo
        singleLanguage$ = LCase( StringField(languageListString$, langcount, ",") )
        MenuItem(i, singleLanguage$)
        If languageSet$ = singleLanguage$
          DisableMenuItem(Menu, i, 1)
        EndIf
        langcount = langcount + 1
      Next
    Else
      MenuItem( countFrom, LCase(languageListString$) )
      If languageSet$ = LCase(languageListString$)
        DisableMenuItem(Menu, countFrom, 1)
      EndIf
    EndIf
  EndIf
EndProcedure
this is to load the language.xml:

Code: Select all

Procedure.s loadLanguageFile ( xmlNode, elementPfad$, attributName$ )
  Define *MainNode, *ChildNode
    If XMLStatus(#XML) = #PB_XML_Success
      *MainNode = MainXMLNode(xmlNode)
      If XMLNodeType(*MainNode) = #PB_XML_Normal
        ;Debug GetXMLNodeName(*MainNode)
        *ChildNode = XMLNodeFromPath(*MainNode, elementPfad$)
        ;Debug GetXMLNodeName(*ChildNode)
        If *ChildNode <> 0
          ProcedureReturn GetXMLAttribute(*ChildNode, attributName$)
        Else
          ProcedureReturn ""
        EndIf
      EndIf
    EndIf
EndProcedure
This is the Macro to set all translations:
All variables that are set there are for all strings where no setgatgettext can be used.

Code: Select all

Macro setLanguageFull(filename)
  If LoadXML(#XML, filename, #PB_UTF8)
    languageListing$ = setLanguage ( languageSet$ )
    languageAnzahl = CountString(languageListing$, ",")
    createLanguagePopupMenu(#langMenu, startLanguageMenuEventID, startLanguageMenuEventID+languageAnzahl, languageListing$)
    
    startButtonImageText_add$ = loadLanguageFile ( #XML, languageSet$+"/textAddSaveCam", "textAdd" )
    startButtonImageText_save$ = loadLanguageFile ( #XML, languageSet$+"/textAddSaveCam", "textSave" )
    
    messageWrongContent_title$ = loadLanguageFile ( #XML, languageSet$+"/messageWrongContent", "title" )
    messageWrongContent_text$ = loadLanguageFile ( #XML, languageSet$+"/messageWrongContent", "text" )
    
    messageNoValidPath_title$ = loadLanguageFile ( #XML, languageSet$+"/messageNoValidPath", "title" )
    messageNoValidPath_text$ = loadLanguageFile ( #XML, languageSet$+"/messageNoValidPath", "text" )
    
    messageRemoveAllItems_title$ = loadLanguageFile ( #XML, languageSet$+"/messageRemoveAllItems", "title" )
    messageRemoveAllItems_text$ = loadLanguageFile ( #XML, languageSet$+"/messageRemoveAllItems", "text" )
    
    messageNoHelpFile_title$ = loadLanguageFile ( #XML, languageSet$+"/messageNoHelpFile", "title" )
    messageNoHelpFile_text$ = loadLanguageFile ( #XML, languageSet$+"/messageNoHelpFile", "text" )
    
    messageError_title$ = loadLanguageFile ( #XML, languageSet$+"/messageError", "title" )
    messagePathNotCreated_text$ = loadLanguageFile ( #XML, languageSet$+"/messagePathNotCreated", "text" )
    messageSetValidPath_text$ = loadLanguageFile ( #XML, languageSet$+"/messageSetValidPath", "text" )
    
    pathRequesterSetPath_title$ = loadLanguageFile ( #XML, languageSet$+"/pathRequesterSetPath", "title" )
    
    windowImageList_title$ = loadLanguageFile ( #XML, languageSet$+"/windowImageList", "title" )
    
  Else
    MessageRequester("Information", "No Language File found. Please make sure you extracted the full archive or redownload it from http://sascha.loeffler.gs/", #PB_MessageRequester_Ok)
    quit = 1
  EndIf
EndMacro
this is to load the language file and set all gadget translations (cut a bit so it is not too long):

Code: Select all

Procedure.s setLanguage ( language$ )
  Define languagelist$, langcount, i
  Define translation$
   languagelist$ = LCase(loadLanguageFile ( #XML, "languages", "list" ))
   langcount = CountString(languagelist$, ",") + 1
   
   For i = 1 To langcount
    If ( LCase( StringField(languagelist$, i, ",") ) = language$ ) Or ( langcount = 1 And languagelist$ = LCase(language$) )
      ;set translations
        translation$ = loadLanguageFile ( #XML, language$+"/popupDelete", "text" )
        SetMenuItemText(#popupMenu, 1, translation$)
        translation$ = loadLanguageFile ( #XML, language$+"/popupDeActivate", "text" )
        SetMenuItemText(#popupMenu, 3, translation$)
        translation$ = loadLanguageFile ( #XML, language$+"/popupDeleteAll", "text" )
        SetMenuItemText(#popupMenu, 5, translation$)
        translation$ = loadLanguageFile ( #XML, language$+"/popupLanguage", "text" )
        SetMenuItemText(#popupMenu, 7, translation$)
        translation$ = loadLanguageFile ( #XML, language$+"/popupHelp", "text" )
        SetMenuItemText(#popupMenu, 9, translation$)
        
     ;... (removed a bit here because it would be too long)
        
        ;translation$ = loadLanguageFile ( #XML, language$+"/textSaveCam", "text" )
        ;SetGadgetText(#previewCheckBox, translation$)
      ;endset translations
    EndIf
   Next
   
   ProcedureReturn languagelist$
EndProcedure

at the #PB_Event_Menu you only need to do

Code: Select all

For i = startLanguageMenuEventID To startLanguageMenuEventID+languageAnzahl
            If EventMenu() = i
              If GetMenuItemText(#langMenu, i) <> languageSet$
                languageSet$ = GetMenuItemText(#langMenu, i)
                setLanguageFull("webcam_lang.xml")
              EndIf
            EndIf
          Next
then you only need the start of your MenuEventID of the language Menu items so it will not use a ID of an already existing MenuItem:

Code: Select all

#XML = 100 ; Language XML Constant
  Global startLanguageMenuEventID
  startLanguageMenuEventID = 11
the XML file (cut a bit so it is not too long):

Code: Select all

<translation>
  <languages list="english,german" />
  <english>
    <popupDelete text="Delete&#09;Entf" />
    <popupDeActivate text="de/activate all&#09;Strg+A" />
    <popupDeleteAll text="delete all&#09;Strg+D" />
    <popupLanguage text="choose language&#09;Strg+L" />
    <popupHelp text="Help&#09;F1" />
	
    <listWebcamUrl text="Webcam URL" />
    <listSavepath text="Savepath" />
    <listFilename text="Filename" />
    <listIntervall text="Intervall" />
    <listTime text="Time" />
    <listBeginEnd text="Begin / End" />
    <listCounter text="Counter" />
    <listDeleteDoubles text="no doubles" />
    <listImageNr text="Image No." />
  </english>
  <german>
    <popupDelete text="Löschen&#09;Entf" />
    <popupDeActivate text="Alle de/aktivieren&#09;Strg+A" />
    <popupDeleteAll text="Alle löschen&#09;Strg+D" />
    <popupLanguage text="Sprache wählen&#09;Strg+L" />
    <popupHelp text="Hilfe&#09;F1" />
	
    <listWebcamUrl text="Webcam URL" />
    <listSavepath text="Speicherpfad" />
    <listFilename text="Dateiname" />
    <listIntervall text="Intervall" />
    <listTime text="Zeit" />
    <listBeginEnd text="Beginn / Ende" />
    <listCounter text="Zähler" />
    <listDeleteDoubles text="keine Doppelten" />
	<listImageNr text="Bild Nr." />
  </german>
</translation>
It is still a bit hard to implement especial if you don't start to implement it when you begin coding.
But maybe someone have a better idea and i am just too stupid. :)

i hope i have not forgotten something important for this to work.
If someone is still unsure how to implement i could release the full source code of the application.

Re: GUI Translation without restart

Posted: Mon Sep 05, 2011 5:32 pm
by graph100
I had seen a post speaking about gui translation, but can't remember where.

For one of my apps I use the following system : A map contain all the displayed texts, and you use the map to load the differents texts.

Exemple : (I included the language file editor for more easiness)

Code: Select all


;{ Support MultiLangage

Global LANGAGE.s
Global NewMap Langue.s()

Procedure ChargementLangue(langue.s)
	
	;{ chargement d'autre langue que le français
	If langue <> "Français"
		If ReadFile(0, langue + ".lang")
			
			LANGAGE = langue
			
			a = ReadLong(0)
			
			For b = 1 To a
				key.s = ReadString(0)
				
				lenght = ReadWord(0)
				donnee.s = Space(lenght)
				ReadData(0, @donnee, lenght)
				
				Langue(key) = donnee
			Next
			
			CloseFile(0)
			
		Else
			MessageRequester("Error", "Impossible To Read the language file :" + Chr(13) + langue + ".lang" + Chr(13) + "The Default language 'French' will be loaded instead.")
			langue = "Français"
		EndIf
	EndIf
	;}
	
	; essayez de décrire la clé en 3 mots MAX
	
	If langue = "Français"
		
		LANGAGE = "Français"
		
		;{ LANGUE FR en natif sans fichiers
		
		Langue("win title") = "Titre en Français !!"
		Langue("langue change") = "Changer la langue"
		
		
		;}
		
	EndIf
	
	
	ProcedureReturn 1
EndProcedure

Procedure EditeurLangue()
	
	;{ ouverture de la fentre
	
	If OpenWindow(0, 0, 0, 800, 600, "Langage Editor for ScMangwa", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
		ListViewGadget(0, 5, 5, 200, WindowHeight(0) - 10)
		
		EditorGadget(1, 210, 5, 585, 263, #PB_Editor_ReadOnly)
		ButtonGadget(10, 210, 273, 200, 20, "Load the default language 'French'")
		ButtonGadget(11, 415, 273, 200, 20, "Load an existing language file")
		StringGadget(13, 655, 273, 100, 20, "Français", #PB_String_ReadOnly)
		
		TextGadget(26, 210, 305, 400, 16, "Strike [Return] to save the text, use [Shift] + [Return] to insert a newline")
		EditorGadget(2, 210, 322, 585, 248)
		ButtonGadget(20, 210, 575, 110, 20, "Save new language")
		ButtonGadget(25, 325, 575, 150, 20, "Load an existing language file")
		TextGadget(23, 555, 578, 90, 20, "Language name :")
		StringGadget(24, 645, 575, 100, 20, "")
		
		AddKeyboardShortcut(0, #PB_Shortcut_Escape, 0)
		AddKeyboardShortcut(0, #PB_Shortcut_Return, 1)
	Else
		End
	EndIf
	
	;}
	
	;{ init
	
	NewMap Langue_new.s()
	
	ChargementLangue("Français")
	ClearGadgetItems(0)
	
	ForEach Langue()
		AddGadgetItem(0, -1, MapKey(Langue()))
	Next
	
	SetGadgetState(0, 0) ; sélection du premier élément
	
	If GetGadgetState(0) > -1
		FindMapElement(Langue(), GetGadgetText(0))
		
		SetGadgetText(1, Langue())
	EndIf
	
	;}
	
	;{ boucle principale
	
	Repeat
		event = WaitWindowEvent()
		
		;{ event gadget
		
		If event = #PB_Event_Gadget
			ok.b = #False
			
			Select EventGadget()
					
					;{ click sur la listview
				Case 0
					If GetGadgetState(0) > -1
						FindMapElement(Langue(), GetGadgetText(0))
						
						SetGadgetText(1, Langue())
						
						If FindMapElement(Langue_new(), GetGadgetText(0))
							SetGadgetText(2, Langue_new())
						Else
							SetGadgetText(2, "")
						EndIf
					EndIf
					;}
					
					;{ bouton charger la langue par défaut
				Case 10
					ChargementLangue("Français")
					SetGadgetText(13, "Français")
					ok = #True
					;}
					
					;{ bouton charger une autre langue
				Case 11
					file.s = OpenFileRequester("Open a ScMangwa language file", "", "Language files *.lang|*.lang", 0)
					
					If file
						If ChargementLangue(Left(GetFilePart(file), Len(GetFilePart(file)) - 5)) = 0
							MessageRequester("Error", "This language file is not valid. The default language 'French' will be loaded instead.")
							
							ChargementLangue("Français")
							SetGadgetText(13, "Français")
						EndIf
						
						ok = #True
					EndIf
					;}
					
					;{ Sauver le nouveau fichier de langue
				Case 20
					file.s = GetGadgetText(24)
					
					path$ = PathRequester("Path where to save the language file", "")
					
					If CreateFile(0, path$ + file + ".lang")
						
						;{ écriture du fichier de langage
						
						WriteLong(0, MapSize(Langue_new()))
						
						ForEach Langue_new()
							WriteStringN(0, MapKey(Langue_new()))
							
							tmp.s = Langue_new()
							WriteWord(0, Len(tmp))
							
							WriteData(0, @tmp, Len(tmp))
						Next
						
						;}
						
						CloseFile(0)
					Else
						MessageRequester("Error", "Impossible to save the file : " + Chr(13) + path$ + file + ".lang" + Chr(13) + "Try by launching the programme with Admin right.")
					EndIf
					;}
					
					;{ bouton ouvrir un fichier de langue pour l'éditer
				Case 25
					file.s = OpenFileRequester("Open a ScMangwa language file", "", "Language files *.lang|*.lang", 0)
					
					If file
						If ReadFile(0, file)
							
							a = ReadLong(0)
							
							ClearMap(Langue_new())
							For b = 1 To a
								key.s = ReadString(0)
								
								lenght = ReadWord(0)
								donnee.s = Space(lenght)
								ReadData(0, @donnee, lenght)
								
								Langue_new(key) = donnee
							Next
							
							SetGadgetText(24, Left(GetFilePart(file), Len(GetFilePart(file)) - 5))
							
							CloseFile(0)
						EndIf
					EndIf
					;}
					
			EndSelect
			
			;{ remplissage de la listview
			
			If ok = #True And (EventGadget() = 10 Or EventGadget() = 11)
				
				ClearGadgetItems(0)
				
				ForEach Langue()
					AddGadgetItem(0, -1, MapKey(Langue()))
				Next
				
				SetGadgetState(0, 0) ; sélection du premier élément
				
				If GetGadgetState(0) > -1
					FindMapElement(Langue(), GetGadgetText(0))
					
					SetGadgetText(1, Langue())
				EndIf
				
			EndIf
			
			;}
			
		EndIf
		
		;}
		
		;{ menu event
		
		If event = #PB_Event_Menu
			Select EventMenu()
				Case 0
					event = #PB_Event_CloseWindow
					
				Case 1
					If GetActiveGadget() = 2
						If GetGadgetState(0) > -1
							
							Langue_new(GetGadgetText(0)) = GetGadgetText(2)
							SetGadgetState(0, GetGadgetState(0) + 1)
							
							If FindMapElement(Langue_new(), GetGadgetText(0))
								SetGadgetText(2, Langue_new())
							Else
								SetGadgetText(2, "")
							EndIf
							
							If GetGadgetState(0) > -1
								FindMapElement(Langue(), GetGadgetText(0))
								
								SetGadgetText(1, Langue())
							EndIf
						EndIf
					EndIf
					
			EndSelect
			EndIf
		
		;}
		
		
	Until event = #PB_Event_CloseWindow
	
	;}
	
	;{ fermeture
	
	CloseWindow(0)
	End
	
	;}
	
EndProcedure

; initialisation de la langue, au cas ou un fichier de langue ne serais pas complet.
ChargementLangue("Français")

;}


If 0 ; CHANGE THIS VALUE TO ACCES THE EXAMPLE (or the editor), after creating the "English" language file 
	EditeurLangue() ; juste for the example, in an apps, use a command line options to access this from the main program (for example)
EndIf


Procedure Reload()
	SetWindowTitle(0, Langue("win title"))
	
	SetGadgetText(0, Langue("langue change"))
EndProcedure


If OpenWindow(0, 0, 0, 500, 300, Langue("win title"), #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	ButtonGadget(0, 10, 10, 200, 20, Langue("langue change"))
	
EndIf


Repeat
	event = WaitWindowEvent()
	
	If event = #PB_Event_Gadget And EventGadget() = 0
		ChargementLangue("English")
		
		Reload()
	EndIf
	
Until event = #PB_Event_CloseWindow

End
the English.lang file must be created be you first by accessing the editor (change the "If 0" into "If 1")