| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- Strict
- Import Brl.Map
- Import Brl.TextStream
- Rem
- bbdoc: Create a new empty language to be used with MaxGUI's localization system.
- about: This function is provided in case it is necessary to create a new language from scratch.
- In the majority of cases, languages should instead be loaded from INI files using #LoadLanguage.
- Use the #DefineLanguageToken, #RemoveLanguageToken and #ClearLanguageTokens commands to add to and
- modify the returned language. #SetLanguageName and #LanguageName may also be useful.
- See Also: #LoadLanguage, #SetLocalizationLanguage, #LocalizeString and #LocalizeGadget.
- EndRem
- Function CreateLanguage:TMaxGuiLanguage( name$ )
- Return New TMaxGuiLanguage.Create(name)
- EndFunction
- Rem
- bbdoc: Load a language from an INI text stream.
- about: @{url} can be a filepath or any other readable #TStream object.
- The INI text stream must contain, at minimum, an INI section labelled '[LanguageDefinition]' and
- a 'LanguageID' token which should be assigned an appropriate language name.
- A typical language INI file may look something like:
- {{
- [LanguageDefinition]
- LanguageID = Français (French)
- LanguageVersion = v0.1
- LanguageAuthor = Various Sources
- ; Toolbar Tips
- tb_new = "Nouveau"
- tb_open = "Ouvrir"
- tb_close = "Fermer"
- tb_save = "Enregistrer"
- tb_cut = "Couper"
- tb_copy = "Copier"
- tb_paste = "Coller"
- ...
- tb_home = "Page d'Accueil"
- tb_back = "Précédente"
- tb_forward = "Suivante"
- ; Tabs
- tab_help = "Aide"
- tab_output = "Sortie"
- tab_locked:%1 = "construction:%1"
- ; Time Format, by example: 13:09:02
- ; h = 1 (12 hour clock) hh = 13 (24 hour clock)
- ; m = 9 (without leading 0) mm = 09 (including leading 0)
- ; s = 2 (without leading 0) ss = 02 (including leading 0)
- ; pp = {{pm}} (or '{{am}}' from 00:00 -> 11:59)
- longtime = hh:mm:ss pp
- shorttime = {{longtime}} ; We want short time to be formatted exactly like {{longtime}}
- ; Date Format, by example: 9th June 2009
- ; d = 9 dd = 09 ddd = {{Wed}} dddd = {{Wednesday}}
- ; m = 6 mm = 06 mmm = {{Jun}} mmmm = {{June}}
- ; yy = 09 yyyy = 2009 oo = {{9th}}
- longdate = dddd oo mmmm dddd ; e.g. Wednesday 9th June 2009
- shortdate = dd/mm/yy ; e.g. 09/06/09
- ; AM / PM
- am = AM
- pm = PM
- ; Ordinals
- 1st = 1e
- 2nd = 2er
- 3rd = 3e
- 4th = 4e
- ; etc.
- ; Days of the week
- Monday = "Lundi"
- Mon = "Lun"
- Tueday = "Mardi"
- Tue = "Mar"
- Wednesday = "Mercredi"
- Wed = "Mer"
- Thursday = "Jeudi"
- Thu = "Jeu"
- Friday = "Vendredi"
- Fri = "Ven"
- Saturday = "Samedi"
- Sat = "Sam"
- Sunday = "Dimanche"
- Sun = "Dim"
- }}
- Note how a semicolon ';' is used to mark the start of a line comment.
- INI files support the following escape sequence characters:
- [ @{INI Escape Sequence} | @{BlitzMax Equivalent}
- * \\ | ~\
- * \r | ~~r
- * \n | ~~n
- * \t | ~~t
- * \# | ~#
- * \; | ;
- * \: | :
- ]
- The bottom three escape sequences are only strictly required if the value of the INI key is not enclosed
- in quotes. For example, the following definitions are expected to evaluate to the same string ( ~#;: ).
- {{
- MyToken = \#\;\:
- MyToken = "#;:"
- MyToken = "\#\;\:"
- }}
- Use the #DefineLanguageToken, #RemoveLanguageToken and #ClearLanguageTokens commands to add to and
- modify the returned language. #SetLanguageName and #LanguageName may also be useful.
- To construct a new language from scratch, use the #CreateLanguage command instead.
- See Also: #SetLocalizationLanguage, #SaveLanguage, #LocalizeString and #LocalizeGadget.
- EndRem
- Function LoadLanguage:TMaxGuiLanguage( url:Object )
- Return TMaxGuiLanguage.LoadLanguage(url)
- EndFunction
- Rem
- bbdoc: Saves a language as an INI section to the supplied stream.
- about: @{url} can be a filepath or any other writable #TStream object.
- If @{url} is a string ending in "/" or "\", it is assumed that @{url} is a directory path and a default filename
- will be appended like so:
- {{
- url = String(url) + LanguageName(language).Split(" ")[0] + ".language.ini"
- }}
- WARNING: This command will automatically overwrite any existing file at the supplied/resulting file path.
- See Also: #LoadLanguage, #SetLocalizationLanguage, #LocalizeString and #LocalizeGadget.
- EndRem
- Function SaveLanguage( language:TMaxGuiLanguage, url:Object )
- If Not TStream(url) And (String(url).EndsWith("/") Or String(url).EndsWith("\")) Then
- url = String(url) + language.GetName().Split(" ")[0] + ".language.ini"
- EndIf
- SaveText( language.Serialize(), url )
- EndFunction
- Rem
- bbdoc: Redefine a language's name.
- about: See Also: #LanguageName, #LoadLanguage, #CreateLanguage and #SetLocalizationLanguage.
- EndRem
- Function SetLanguageName( language:TMaxGuiLanguage, name$ )
- language.SetName(name)
- EndFunction
- Rem
- bbdoc: Returns a language's name.
- about: See Also: #SetLanguageName, #LoadLanguage, #CreateLanguage and #SetLocalizationLanguage.
- EndRem
- Function LanguageName$( language:TMaxGuiLanguage )
- Return language.GetName()
- EndFunction
- Rem
- bbdoc: Define a language-specific value for a localization token.
- about: Localization tokens are case insensitive, and if a token definition already exists in the language
- the token value will be overwritten with this most recent @{value$}.
- See Also: #LoadLanguage, #CreateLanguage, #SaveLanguage and #SetLocalizationLanguage.
- EndRem
- Function DefineLanguageToken( language:TMaxGuiLanguage, token$, value$ )
- language.DefineToken(token,value)
- EndFunction
- Rem
- bbdoc: Look-up the value of a token for a specific language.
- about: Localization tokens are case insensitive, and are either loaded in with the language or defined
- using the #DefineLanguageToken command.
- If an explicit token definition is not found in the language, the @{token$} string is returned as it was passed.
- See Also: #LoadLanguage, #CreateLanguage, #SaveLanguage and #SetLocalizationLanguage.
- EndRem
- Function LanguageTokenDefinition$( language:TMaxGuiLanguage, token$ )
- Return language.LookupToken(token)
- EndFunction
- Rem
- bbdoc: Remove a token definition from a language.
- about: The only token which cannot be removed is 'LanguageID' as every language requires this one token to be defined -
- it defines the language name. If a matching token isn't already defined, then the command returns silently.
- Note: Localization tokens are case insensitive so the following commands are all requesting the same token to be removed:
- {{
- RemoveLanguageToken( language, "WelcomeMessage" )
- RemoveLanguageToken( language, "WELCOMEMESSAGE" )
- RemoveLanguageToken( language, "welcomemessage" )
- RemoveLanguageToken( language, "WeLcOmEmEsSaGe" )
- }}
- See Also: #ClearLanguageTokens, #DefineLanguageToken, #LoadLanguage, #CreateLanguage, #SaveLanguage and #SetLocalizationLanguage.
- EndRem
- Function RemoveLanguageToken( language:TMaxGuiLanguage, token$ )
- language.RemoveToken(token)
- EndFunction
- Rem
- bbdoc: Removes all the tokens defined in a language.
- about: The only token which will not be removed is 'LanguageID' as every language requires this one token to be defined -
- it defines the language name.
- See Also: #RemoveLanguageToken, #DefineLanguageToken, #LoadLanguage, #CreateLanguage, #SaveLanguage and #SetLocalizationLanguage.
- EndRem
- Function ClearLanguageTokens( language:TMaxGuiLanguage )
- language.ClearTokens()
- EndFunction
- Type TMaxGuiLanguage
-
- ?Win32
- Const CARRIAGE_RETURN:String = "~r~n"
- ?Not Win32
- Const CARRIAGE_RETURN:String = "~n"
- ?
-
- Const SECTION_HEADER:String = "LanguageDefinition"
- Const LANGUAGENAME_TOKEN:String = "LanguageId"
-
- Field strName:String = "Unknown Language"
- Field mapDictionary:TMap = CreateMap()
-
- Method Create:TMaxGuiLanguage(name$)
- SetName(name)
- Return Self
- EndMethod
-
- Method SetName(pName$)
- DefineToken( LANGUAGENAME_TOKEN, pName )
- EndMethod
-
- Method GetName$()
- Return strName
- EndMethod
-
- Method DefineToken( pToken:String, pText:String )
- If pToken Then
- If pToken = LANGUAGENAME_TOKEN Then strName = pText
- MapInsert( mapDictionary, pToken.ToLower(), Prepare(pText) )
- EndIf
- EndMethod
-
- Method RemoveToken( pToken:String )
- If pToken And pToken.ToLower() <> LANGUAGENAME_TOKEN.ToLower() Then MapRemove( mapDictionary, pToken.ToLower() )
- EndMethod
-
- Method LookupToken$(pToken$)
- Local tmpValue$ = String(MapValueForKey( mapDictionary, pToken.ToLower() ))
- If tmpValue Then Return Prepare(tmpValue) Else Return pToken
- EndMethod
-
- Method ClearTokens()
- ClearMap mapDictionary
- SetName(GetName())
- EndMethod
-
- Method LoadEntriesFromText( text:String )
-
- 'Very rough INI section parser
-
- Local tmpIndex:Int, tmpStage:Int = 0
-
- For Local tmpLine:String = EachIn text.Split("~n")
-
- tmpStage = 0
-
- 'Search for valid ';' comment
- For tmpIndex = 0 Until tmpLine.length
- Select tmpLine[tmpIndex]
- Case Asc("~q");If tmpStage <> 0 Then tmpStage = 2
- Case Asc("=");If tmpStage = 0 Then tmpStage = 1
- Case Asc(";")
- If tmpStage = 0 Or tmpStage = 1 Then
- Exit
- Else
- If tmpLine[tmpIndex-1] <> Asc("\") Then tmpStage = 0-(tmpIndex)
- EndIf
- EndSelect
- Next
-
- 'Strip the comment if ';' was the last character
- If tmpStage < 0 Then tmpLine = tmpLine[..Abs(tmpStage)]
-
- 'Strip any whitespace
- tmpLine = StripWhitespace(tmpLine[..tmpIndex])
- If Not tmpLine Then Continue
-
- 'Test for a new section header
- If tmpLine[0] = "["[0] Then Exit
-
- 'Slow but easy code to handle any escape characters
- tmpLine = tmpLine.Replace("\\","~0").Replace("\r","~r").Replace("\n","~n").Replace("\;",";").Replace("\#","#").Replace("\:",":").Replace("\t","~t").Replace("~0","\")
-
- 'Find the separator
- tmpIndex = tmpLine.Find("=")
-
- 'If we have a key/value pair, define a new key in our dictionary.
- If tmpIndex > 0 Then DefineToken( StripWhitespace(tmpLine[..tmpIndex],True), StripWhitespace(tmpLine[tmpIndex+1..],True) )
- Next
-
- EndMethod
-
- Method Serialize:String()
-
- Local tmpString:String = "["+SECTION_HEADER+"]" + CARRIAGE_RETURN + LANGUAGENAME_TOKEN + " = ~q" + GetName() + "~q" + CARRIAGE_RETURN
- For Local tmpKey:String = EachIn MapKeys(mapDictionary)
- If tmpKey <> LANGUAGENAME_TOKEN Then
- tmpString:+tmpKey+" = ~q"+String(MapValueForKey(mapDictionary,tmpKey))+"~q"+CARRIAGE_RETURN
- EndIf
- Next
- Return tmpString
-
- EndMethod
-
- Method Deserialize:TMaxGuiLanguage(pString$)
-
- Local tmpIndex:Int = pString.Find("["+SECTION_HEADER+"]")
- If tmpIndex < 0 Then Return Null
-
- tmpIndex = pString.Find("~n",tmpIndex+SECTION_HEADER.length+2)
- If tmpIndex < 0 Then Return Null
-
- If pString.ToLower().Find(LANGUAGENAME_TOKEN.ToLower(),tmpIndex+1) < 0 Then Return Null
-
- ClearMap mapDictionary
- LoadEntriesFromText( pString[tmpIndex..] )
-
- Return Self
- EndMethod
-
- Function LoadLanguage:TMaxGUILanguage( stream:Object )
-
- Return New TMaxGuiLanguage.Deserialize( LoadText(stream) )
-
- EndFunction
-
- Function StripWhitespace:String( text$, pStripQuotes:Int = False )
- Local i:Int, j:Int
- For i = 0 Until text.length
- If text[i] = " "[0] Or text[i] = "~t"[0] Then Continue
- Exit
- Next
- For j = text.length-1 To i Step -1
- If text[j] = " "[0] Or text[j] = "~t"[0] Or text[j] = "~r"[0] Then Continue
- Exit
- Next
- If pStripQuotes And (j-i)>0 And text[i] = "~q"[0] And text[j] = "~q"[0] Then
- i:+1;j:-1
- EndIf
- Return text[i..j+1]
- EndFunction
-
- Function Prepare$(text$)
- If text="~0" Then Return "" ElseIf text="" Then Return "~0"
- Return text
- EndFunction
-
- EndType
|