My DialogDesign0R uses that since the beginning, I thought it's time to introduce that feature.
This module is very tiny, but there is not more to do.
When you extend your dialog, extend the JSON file(s), no need to change any code, all will be done in the JSON files from then on.
The example code will create an english.lan and german.lan file in your temp folder.
I thought this might be more straight forward for all those guys, hating to copy/paste code, create files, name them accordingly, ...
Bad side is, the example code got longer than the module itself
Enough, here we go:
Code: Select all
;/------------------
;|
;| DialogMultiLAN.pbi
;|
;| (c) HeX0R 2021
;|
;| V 1.00
;|
;| very tiny Module to add multi language support to your dialogs
;|
;| all you have to do is creating language files, in fact those are json files
;| Load() it with this module, and call Set() to set all phrases automatically
;| Both, the dialog and the language phrases are completely separated
;| Create dialogs without even thinking about multilanguage support.
;| Than add *.lan files, and that Module will do anything for you.
;|
;| The example code will create an english.lan and a german.lan file in your temp folder
;| This is for the lazy guys, just open it and examine it, expand it, do whatever you like.
;| Those files have to be UTF8 encoded!
;|
;/-------------------
; ----------------------------------------------------------------------------
; "THE BEER-WARE LICENSE":
; <HeX0R@coderbu.de> wrote this file. as long as you retain this notice you
; can do whatever you want with this stuff. If we meet some day, and you think
; this stuff is worth it, you can buy me a beer in return
; (see address on https://hex0rs.coderbu.de/).
; Or just go out and drink a few on your own/with your friends ;)
;=============================================================================
DeclareModule LANG
Enumeration
#MODE_Names
#MODE_IDs
EndEnumeration
Declare SetPathToLAN(Path.s)
Declare.s Load(Language.s = "english")
Declare Set(Mode = #MODE_IDs)
EndDeclareModule
Module LANG
Structure _LAN_
Text.s
ToolTipp.s
EndStructure
Structure _LAN_DIAGS_
Title.s
Map Gadget._LAN_()
EndStructure
Global NewMap LAN._LAN_DIAGS_()
Global PathToLAN.s
Procedure SetPathToLAN(Path.s)
If Right(Path, 1) <> #PS$
Path + #PS$
EndIf
PathToLAN = Path
EndProcedure
Procedure.s Load(Language.s = "english")
Protected JSON, Result.s
If FileSize(PathToLAN + Language + ".lan") = -1
Language = "english"
EndIf
If FileSize(PathToLAN + Language + ".lan") = -1
ProcedureReturn "File not found, forgot to call SetPathToLAN() maybe?"
EndIf
JSON = LoadJSON(#PB_Any, PathToLAN + Language + ".lan")
If JSON
ExtractJSONMap(JSONValue(JSON), LAN())
FreeJSON(JSON)
Else
Result = "Error while parsing '" + Language + ~".lan'!\r\n"
Result + "Error: " + JSONErrorMessage() + #CRLF$
Result + "Line: " + Str(JSONErrorLine()) + #CRLF$
Result + "Pos: " + Str(JSONErrorPosition())
EndIf
ProcedureReturn Result
EndProcedure
Procedure Set(Mode = #MODE_IDs)
Protected DialogID$, GadgetID$, Dialog, Gadget
ForEach LAN()
DialogID$ = MapKey(LAN())
If IsRuntime(DialogID$)
Dialog = GetRuntimeInteger(DialogID$)
If IsDialog(Dialog) And DialogWindow(Dialog) <> -1
If LAN()\Title
SetWindowTitle(DialogWindow(Dialog), LAN()\Title)
EndIf
ForEach LAN()\Gadget()
GadgetID$ = MapKey(LAN()\Gadget())
Gadget = -1
If Mode = #MODE_IDs
If IsRuntime(GadgetID$)
Gadget = GetRuntimeInteger(GadgetID$)
EndIf
Else
Gadget = DialogGadget(Dialog, GadgetID$)
EndIf
If Gadget <> -1 And IsGadget(Gadget)
If LAN()\Gadget()\Text
SetGadgetText(Gadget, LAN()\Gadget()\Text)
EndIf
If LAN()\Gadget()\ToolTipp
GadgetToolTip(Gadget, LAN()\Gadget()\ToolTipp)
EndIf
EndIf
Next
RefreshDialog(Dialog)
EndIf
EndIf
Next
EndProcedure
EndModule
;---- Module End
CompilerIf #PB_Compiler_IsMainFile
Runtime Enumeration ;<-- the only thing you have to be aware of is, our dialogs must be runtime constants!
#Dialog_1
#Dialog_2
EndEnumeration
Runtime Enumeration
#check_2
#string_2
#button_2
EndEnumeration
#DIALOG_USES_Names = 1 ;<- Dialog_1 uses names as Gadget identifiers, Dialog_2 uses IDs, this is just to demonstrate both options are supported
Global UsedLANG.s = "english"
Procedure.s GetXMLString()
Protected XML$
XML$ + "<?xml version='1.0' encoding='UTF-16'?>"
XML$ + ""
XML$ + "<dialogs>"
XML$ + " <window name='win_1' flags='#PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_ScreenCentered' minwidth='250'>"
XML$ + " <vbox>"
XML$ + " <checkbox name='check_1'/>"
XML$ + " <string name='string_1'/>"
XML$ + " <button onevent='ChangeLang()' name='button_1'/>"
XML$ + " </vbox>"
XML$ + " </window>"
XML$ + " <window name='win_2' flags='#PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_ScreenCentered' minwidth='250'>"
XML$ + " <vbox>"
XML$ + " <checkbox id='#check_2'/>"
XML$ + " <string id='#string_2'/>"
XML$ + " <button onevent='ChangeLang()' id='#button_2'/>"
XML$ + " </vbox>"
XML$ + " </window>"
XML$ + "</dialogs><!--DDesign0R Definition: PureBasic|1|1|1|_|example_with_declares-->"
XML$ + ""
ProcedureReturn XML$
EndProcedure
Runtime Procedure ChangeLang()
If UsedLANG = "english"
UsedLANG = "german"
Else
UsedLANG = "english"
EndIf
LANG::Load(UsedLANG)
CompilerIf #DIALOG_USES_Names
LANG::Set(LANG::#MODE_Names)
CompilerElse
LANG::Set()
CompilerEndIf
EndProcedure
a$ = GetXMLString()
If ParseXML(0, a$) And XMLStatus(0) = #PB_XML_Success
CompilerIf #DIALOG_USES_Names
CreateDialog(#Dialog_1)
OpenXMLDialog(#Dialog_1, 0, "win_1") ;<- win_1 uses gadget names
CompilerElse
CreateDialog(#Dialog_2)
OpenXMLDialog(#Dialog_2, 0, "win_2") ;<- win_2 used gadget ids
CompilerEndIf
;create example lan files
Restore english
CreateFile(0, GetTemporaryDirectory() + "english.lan", #PB_UTF8)
Repeat
Read.s a$
If a$
WriteString(0, a$)
EndIf
Until a$ = ""
CloseFile(0)
Restore german
CreateFile(0, GetTemporaryDirectory() + "german.lan", #PB_UTF8)
Repeat
Read.s a$
If a$
WriteString(0, a$)
EndIf
Until a$ = ""
CloseFile(0)
Lang::SetPathToLAN(GetTemporaryDirectory())
b$ = LANG::Load()
If b$
;JSON parsing error
Debug b$
Else
CompilerIf #DIALOG_USES_Names
LANG::Set(LANG::#MODE_Names)
CompilerElse
LANG::Set()
CompilerEndIf
EndIf
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
DataSection
english:
Data.s ~"{\r\n"
Data.s ~" \"#Dialog_1\" : {\r\n"
Data.s ~" \"Title\" : \"Just a Window (Dialog 1)\",\r\n"
Data.s ~" \"Gadget\": {\r\n"
Data.s ~" \"check_1\" : {\r\n"
Data.s ~" \"Text\" : \"a stupid CheckBox\",\r\n"
Data.s ~" \"ToolTipp\": \"Checkbox ToolTipp\"\r\n"
Data.s ~" },\r\n"
Data.s ~" \"string_1\" : {\r\n"
Data.s ~" \"Text\" : \"a stupid StringGadget\",\r\n"
Data.s ~" \"ToolTipp\": \"String ToolTipp\"\r\n"
Data.s ~" },\r\n"
Data.s ~" \"button_1\" : {\r\n"
Data.s ~" \"Text\" : \"Change Language\",\r\n"
Data.s ~" \"ToolTipp\": \"Click to change language\"\r\n"
Data.s ~" }\r\n"
Data.s ~" }\r\n"
Data.s ~" },\r\n"
Data.s ~" \"#Dialog_2\" : {\r\n"
Data.s ~" \"Title\" : \"Just a Window (Dialog 2)\",\r\n"
Data.s ~" \"Gadget\": {\r\n"
Data.s ~" \"#check_2\" : {\r\n"
Data.s ~" \"Text\" : \"a stupid CheckBox\",\r\n"
Data.s ~" \"ToolTipp\": \"Checkbox ToolTipp\"\r\n"
Data.s ~" },\r\n"
Data.s ~" \"#string_2\" : {\r\n"
Data.s ~" \"Text\" : \"a stupid StringGadget\",\r\n"
Data.s ~" \"ToolTipp\": \"String ToolTipp\"\r\n"
Data.s ~" },\r\n"
Data.s ~" \"#button_2\" : {\r\n"
Data.s ~" \"Text\" : \"Change Language\",\r\n"
Data.s ~" \"ToolTipp\": \"Click to change language\"\r\n"
Data.s ~" }\r\n"
Data.s ~" }\r\n"
Data.s ~" }\r\n"
Data.s ~"}\r\n"
Data.s ""
german:
Data.s ~"{\r\n"
Data.s ~" \"#Dialog_1\" : {\r\n"
Data.s ~" \"Title\" : \"Nur ein doofes Window (Dialog 1)\",\r\n"
Data.s ~" \"Gadget\": {\r\n"
Data.s ~" \"check_1\" : {\r\n"
Data.s ~" \"Text\" : \"eine komische CheckBox\",\r\n"
Data.s ~" \"ToolTipp\": \"Checkbox ToolTipp auf deutsch\"\r\n"
Data.s ~" },\r\n"
Data.s ~" \"string_1\" : {\r\n"
Data.s ~" \"Text\" : \"ein komisches StringGadget\",\r\n"
Data.s ~" \"ToolTipp\": \"String ToolTipp auf deutsch\"\r\n"
Data.s ~" },\r\n"
Data.s ~" \"button_1\" : {\r\n"
Data.s ~" \"Text\" : \"Sprache ändern\",\r\n"
Data.s ~" \"ToolTipp\": \"Klicken um die Sprache zu ändern\"\r\n"
Data.s ~" }\r\n"
Data.s ~" }\r\n"
Data.s ~" },\r\n"
Data.s ~" \"#Dialog_2\" : {\r\n"
Data.s ~" \"Title\" : \"Nur ein doofes Window (Dialog 1)\",\r\n"
Data.s ~" \"Gadget\": {\r\n"
Data.s ~" \"#check_2\" : {\r\n"
Data.s ~" \"Text\" : \"eine komische CheckBox\",\r\n"
Data.s ~" \"ToolTipp\": \"Checkbox ToolTipp auf deutsch\"\r\n"
Data.s ~" },\r\n"
Data.s ~" \"#string_2\" : {\r\n"
Data.s ~" \"Text\" : \"ein komisches StringGadget\",\r\n"
Data.s ~" \"ToolTipp\": \"String ToolTipp auf deutsch\"\r\n"
Data.s ~" },\r\n"
Data.s ~" \"#button_2\" : {\r\n"
Data.s ~" \"Text\" : \"Sprache ändern\",\r\n"
Data.s ~" \"ToolTipp\": \"Klicken um die Sprache zu ändern\"\r\n"
Data.s ~" }\r\n"
Data.s ~" }\r\n"
Data.s ~" }\r\n"
Data.s ~"}\r\n"
Data.s ""
EndDataSection
CompilerEndIf