But the following source is the easiest way there is, super fast using array instead of list, and simple to use constants as id's.
Your program will always have a default built in language! (I suggest using English for that)
It automatically enumerates the constants for you!
It automatically uses the default text if a translation is missing!
It automatically uses the default text if a translation is outdated or for the wrong version of your program!
It is not possible for the wrong text to be used for the wrong thing due to id confusion!
You can choose the constants naming your self (some consistency is advised though obviously)!
The XML layout is designed to be easy to edit by hand and understand!
It's very easy to make a simple language editor if your program needs a lot of translations or have a lot of text to translate!
The source is hereby placed in the Public Domain have fun PureBasic community, you no longer have any excuse not to support other languages.

There are some comments in the source, however you really just need to read the text between the ***************** comments!
Code: Select all
Structure _language
org$
trans$
EndStructure
Global Dim Lang.s(0)
Enumeration 0
EndEnumeration
Macro _lang(_constant,_text)
Enumeration #PB_Compiler_EnumerationValue
_constant
EndEnumeration
AddElement(_language())
_language()\org$=_text
EndMacro
; lang(#PB_Compiler_EnumerationValue)\id=_id
; lang(#PB_Compiler_EnumerationValue)\text$=_text
Procedure LoadLanguage(filepath$="",programtitle$="")
Protected NewList _language._language(),i.i=0,l.i,xmlfile.i,xmlok.i=#False
Protected *MainNode,*ItemNode,text$,org$
ClearList(_language()) ;needed in case this is a language reloading or language change.
;***************** The following part is the only part you need to worry about *****************
;Define and add default language text entries here, at least 1 must be added.
_lang(#Lang_Test,"Test")
_lang(#Lang_Another_Test,"Another Test")
;To use the language text in the program just use for example:
;Debug Lang(#Lang_Test) ;Very simple right? And much faster than a list as well.
;The XML file should be made to match, uncomment the next few lines to generate a template for it:
;Debug "<?xml version="+#DQUOTE$+"1.0"+#DQUOTE$+" encoding="+#DQUOTE$+"UTF-8"+#DQUOTE$+"?>"
;Debug "" ;version/translator/url is just for reference to make translation easier and credit translators.
;Debug "<language version="+#DQUOTE$+"1.0"+#DQUOTE$+" translator="+#DQUOTE$+"Roger Hågensen"+#DQUOTE$+" url="+#DQUOTE$+"http://EmSai.net/"+#DQUOTE$+">"
;ForEach _language()
; Debug " <lang org="+#DQUOTE$+_language()\org$+#DQUOTE$+" trans="+#DQUOTE$+#DQUOTE$+"/>" ;Translators must leave org alone and enter text in trans only.
;Next
;Debug "</language>"
;Note!
;It might be best to provide a simple editing tool to ensure character escaping and UTF8 is properly done when editing the file instead.
;If a future version of the program changes it's org text and the translation file is not up-to-date,
;then the default text is used instead of the translation, this ensures that there never is an outdated translation text shown in the program.
;***************** That's it, the rest is just the magic code doing all the work for you. *****************
;Size the lang() array per the number of entries defined above.
l=ListSize(_language())
If ArraySize(Lang())<>l ;No point in ReDim'ing if we did so previously.
ReDim lang(l-1)
EndIf
;Load language xml and copy text entries that are supported (defined previously above)
If filepath$
If FileSize(filepath$)>-1 ;if it's missing it's no error, we'll just use the default text later below instead.
xmlfile=LoadXML(#PB_Any,filepath$)
If xmlfile And IsXML(xmlfile)
If XMLStatus(xmlfile)=#PB_XML_Success
*MainNode=MainXMLNode(xmlfile)
If *MainNode
If XMLNodeType(*MainNode)=#PB_XML_Normal
If "language"=GetXMLNodeName(*MainNode)
*ItemNode=ChildXMLNode(*MainNode)
While *ItemNode
If XMLNodeType(*ItemNode)=#PB_XML_Normal
text$=Trim(GetXMLNodeName(*ItemNode))
If text$="text"
org$=Trim(GetXMLAttribute(*ItemNode,"org"))
text$=Trim(GetXMLAttribute(*ItemNode,"trans"))
If org$ And text$
ForEach _language()
If _language()\org$=org$
_language()\trans$=text$
EndIf
Next
EndIf
EndIf
EndIf
*ItemNode=NextXMLNode(*ItemNode)
Wend
EndIf
EndIf
EndIf
Else
text$="There was a error in the XML language file:"+#CR$
text$+XMLError(xmlfile)+#CR$
text$+"On line "+Str(XMLErrorLine(xmlfile))+" at position "+Str(XMLErrorPosition(xmlfile))+"."
If programtitle$
MessageRequester(programtitle$+" Error!",text$)
Else
MessageRequester("XML Error!",text$)
EndIf
EndIf
FreeXML(xmlfile)
Else
MessageRequester(programtitle$+" Error!","Unable to open language file.")
EndIf
EndIf
EndIf
;Copy translated text or default text from language() list to lang() array.
ForEach _language()
If _language()\trans$
lang(i)=_language()\trans$
Else
lang(i)=_language()\org$
EndIf
i+1
Next
EndProcedure
Code: Select all
;Example (default language only)
LoadLanguage()
Debug Lang(#Lang_Test)