123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
- <script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_L10N" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
- REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
- REM === Full documentation is available on https://help.libreoffice.org/ ===
- REM =======================================================================================================================
- Option Compatible
- Option ClassModule
- 'Option Private Module
- Option Explicit
- '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
- ''' L10N (aka SF_L10N)
- ''' ====
- ''' Implementation of a Basic class for providing a number of services
- ''' related to the translation of user interfaces into a huge number of languages
- ''' with a minimal impact on the program code itself
- '''
- ''' The design choices of this module are based on so-called PO-files
- ''' PO-files (portable object files) have long been promoted in the free software industry
- ''' as a mean of providing multilingual UIs. This is accomplished through the use of human-readable
- ''' text files with a well defined structure that specifies, for any given language,
- ''' the source language string and the localized string
- '''
- ''' To read more about the PO format and its ecosystem of associated toolsets:
- ''' https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html#PO-Files
- ''' and, IMHO, a very good tutorial:
- ''' http://pology.nedohodnik.net/doc/user/en_US/ch-about.html
- '''
- ''' The main advantage of the PO format is the complete dissociation between the two
- ''' very different profiles, i.e. the programmer and the translator(s).
- ''' Being independent text files, one per language to support, the programmer may give away
- ''' pristine PO template files (known as POT-files) for a translator to process.
- '''
- ''' This class implements mainly 3 mechanisms:
- ''' - AddText: for the programmer to build a set of words or sentences
- ''' meant for being translated later
- ''' - ExportToPOTFile: All the above texts are exported into a pristine POT-file
- ''' - GetText: At runtime get the text in the user language
- ''' Note that the first two are optional: POT and PO-files may be built with a simple text editor
- '''
- ''' Several instances of the L10N class may coexist
- ' The constraint however is that each instance should find its PO-files
- ''' in a separate directory
- ''' PO-files must be named with the targeted locale: f.i. "en-US.po" or "fr-BE.po"
- '''
- ''' Service invocation syntax
- ''' CreateScriptService("L10N"[, FolderName[, Locale]])
- ''' FolderName: the folder containing the PO-files (in SF_FileSystem.FileNaming notation)
- ''' Locale: in the form la-CO (language-COUNTRY)
- ''' Service invocation examples:
- ''' Dim myPO As Variant
- ''' myPO = CreateScriptService("L10N") ' AddText and ExportToPOTFile are allowed
- ''' myPO = CreateScriptService("L10N", "C:\myPOFiles\", "fr-BE")
- ''' 'All functionalities are available
- '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
- REM =============================================================== PRIVATE TYPES
- ''' The recognized elements of an entry in a PO file are (other elements are ignored) :
- ''' #. Extracted comments (given by the programmer to the translator)
- ''' #, flag (the kde-format flag when the string contains tokens)
- ''' msgctxt Context (to store an acronym associated with the message, this is a distortion of the norm)
- ''' msgid untranslated-string
- ''' msgstr translated-string
- ''' NB: plural forms are not supported
- Type POEntry
- Comment As String
- Flag As String
- Context As String
- MsgId As String
- MsgStr As String
- End Type
- REM ================================================================== EXCEPTIONS
- Const DUPLICATEKEYERROR = "DUPLICATEKEYERROR"
- REM ============================================================= PRIVATE MEMBERS
- Private [Me] As Object
- Private [_Parent] As Object
- Private ObjectType As String ' Must be "L10N"
- Private ServiceName As String
- Private _POFolder As String ' PO files container
- Private _Locale As String ' la-CO
- Private _POFile As String ' PO file in URL format
- Private _Encoding As String ' Used to open the PO file, default = UTF-8
- Private _Dictionary As Object ' SF_Dictionary
- REM ===================================================== CONSTRUCTOR/DESTRUCTOR
- REM -----------------------------------------------------------------------------
- Private Sub Class_Initialize()
- Set [Me] = Nothing
- Set [_Parent] = Nothing
- ObjectType = "L10N"
- ServiceName = "ScriptForge.L10N"
- _POFolder = ""
- _Locale = ""
- _POFile = ""
- Set _Dictionary = Nothing
- End Sub ' ScriptForge.SF_L10N Constructor
- REM -----------------------------------------------------------------------------
- Private Sub Class_Terminate()
-
- If Not IsNull(_Dictionary) Then Set _Dictionary = _Dictionary.Dispose()
- Call Class_Initialize()
- End Sub ' ScriptForge.SF_L10N Destructor
- REM -----------------------------------------------------------------------------
- Public Function Dispose() As Variant
- Call Class_Terminate()
- Set Dispose = Nothing
- End Function ' ScriptForge.SF_L10N Explicit Destructor
- REM ================================================================== PROPERTIES
- REM -----------------------------------------------------------------------------
- Property Get Folder() As String
- ''' Returns the FolderName containing the PO-files expressed as given by the current FileNaming
- ''' property of the SF_FileSystem service. Default = URL format
- ''' May be empty
- ''' Example:
- ''' myPO.Folder
- Folder = _PropertyGet("Folder")
- End Property ' ScriptForge.SF_L10N.Folder
- REM -----------------------------------------------------------------------------
- Property Get Languages() As Variant
- ''' Returns a zero-based array listing all the BaseNames of the PO-files found in Folder,
- ''' Example:
- ''' myPO.Languages
- Languages = _PropertyGet("Languages")
- End Property ' ScriptForge.SF_L10N.Languages
- REM -----------------------------------------------------------------------------
- Property Get Locale() As String
- ''' Returns the currently active language-COUNTRY combination. May be empty
- ''' Example:
- ''' myPO.Locale
- Locale = _PropertyGet("Locale")
- End Property ' ScriptForge.SF_L10N.Locale
- REM ===================================================================== METHODS
- REM -----------------------------------------------------------------------------
- Public Function AddText(Optional ByVal Context As Variant _
- , Optional ByVal MsgId As Variant _
- , Optional ByVal Comment As Variant _
- , Optional ByVal MsgStr As Variant _
- ) As Boolean
- ''' Add a new entry in the list of localizable text strings
- ''' Args:
- ''' Context: when not empty, the key to retrieve the translated string via GetText. Default = ""
- ''' MsgId: the untranslated string, i.e. the text appearing in the program code. Must not be empty
- ''' The key to retrieve the translated string via GetText when Context is empty
- ''' May contain placeholders (%1 ... %9) for dynamic arguments to be inserted in the text at run-time
- ''' If the string spans multiple lines, insert escape sequences (\n) where relevant
- ''' Comment: the so-called "extracted-comments" intended to inform/help translators
- ''' If the string spans multiple lines, insert escape sequences (\n) where relevant
- ''' MsgStr: (internal use only) the translated string
- ''' If the string spans multiple lines, insert escape sequences (\n) where relevant
- ''' Returns:
- ''' True if successful
- ''' Exceptions:
- ''' DUPLICATEKEYERROR: such a key exists already
- ''' Examples:
- ''' myPO.AddText(, "This is a text to be included in a POT file")
- Dim bAdd As Boolean ' Output buffer
- Dim sKey As String ' The key part of the new entry in the dictionary
- Dim vItem As POEntry ' The item part of the new entry in the dictionary
- Const cstPipe = "|" ' Pipe forbidden in MsgId's
- Const cstThisSub = "L10N.AddText"
- Const cstSubArgs = "[Context=""""], MsgId, [Comment=""""]"
- If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
- bAdd = False
- Check:
- If IsMissing(Context) Or IsMissing(Context) Then Context = ""
- If IsMissing(Comment) Or IsMissing(Comment) Then Comment = ""
- If IsMissing(MsgStr) Or IsMissing(MsgStr) Then MsgStr = ""
- If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
- If Not SF_Utils._Validate(Context, "Context", V_STRING) Then GoTo Finally
- If Not SF_Utils._Validate(MsgId, "MsgId", V_STRING) Then GoTo Finally
- If Not SF_Utils._Validate(Comment, "Comment", V_STRING) Then GoTo Finally
- If Not SF_Utils._Validate(MsgStr, "MsgStr", V_STRING) Then GoTo Finally
- End If
- If Len(MsgId) = 0 Then GoTo Finally
- Try:
- If Len(Context) > 0 Then sKey = Context Else sKey = MsgId
- If _Dictionary.Exists(sKey) Then GoTo CatchDuplicate
- With vItem
- .Comment = Comment
- If InStr(MsgId, "%") > 0 Then .Flag = "kde-format" Else .Flag = ""
- .Context = Replace(Context, cstPipe, " ")
- .MsgId = Replace(MsgId, cstPipe, " ")
- .MsgStr = MsgStr
- End With
- _Dictionary.Add(sKey, vItem)
- Finally:
- AddText = bAdd
- SF_Utils._ExitFunction(cstThisSub)
- Exit Function
- Catch:
- GoTo Finally
- CatchDuplicate:
- SF_Exception.RaiseFatal(DUPLICATEKEYERROR, Iif(Len(Context) > 0, "Context", "MsgId"), sKey)
- GoTo Finally
- End Function ' ScriptForge.SF_L10N.AddText
- REM -----------------------------------------------------------------------------
- Public Function ExportToPOTFile(Optional ByVal FileName As Variant _
- , Optional ByVal Header As Variant _
- , Optional ByVal Encoding As Variant _
- ) As Boolean
- ''' Export a set of untranslated strings as a POT file
- ''' The set of strings has been built either by a succession of AddText() methods
- ''' or by a successful invocation of the L10N service with the FolderName argument
- ''' The generated file should pass successfully the "msgfmt --check 'the pofile'" GNU command
- ''' Args:
- ''' FileName: the complete file name to export to. If it exists, is overwritten without warning
- ''' Header: Comments that will appear on top of the generated file. Do not include any leading "#"
- ''' If the string spans multiple lines, insert escape sequences (\n) where relevant
- ''' A standard header will be added anyway
- ''' Encoding: The character set that should be used
- ''' Use one of the Names listed in https://www.iana.org/assignments/character-sets/character-sets.xhtml
- ''' Note that LibreOffice probably does not implement all existing sets
- ''' Default = UTF-8
- ''' Returns:
- ''' True if successful
- ''' Examples:
- ''' myPO.ExportToPOTFile("myFile.pot", Header := "Top comment\nSecond line of top comment")
- Dim bExport As Boolean ' Return value
- Dim oFile As Object ' Generated file handler
- Dim vLines As Variant ' Wrapped lines
- Dim sLine As String ' A single line
- Dim vItems As Variant ' Array of dictionary items
- Dim vItem As Variant ' POEntry type
- Const cstSharp = "# ", cstSharpDot = "#. ", cstFlag = "#, kde-format"
- Const cstTabSize = 4
- Const cstWrap = 70
- Const cstThisSub = "L10N.ExportToPOTFile"
- Const cstSubArgs = "FileName, [Header=""""], [Encoding=""UTF-8"""
- If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
- bExport = False
- Check:
- If IsMissing(Header) Or IsMissing(Header) Then Header = ""
- If IsMissing(Encoding) Or IsMissing(Encoding) Then Encoding = "UTF-8"
- If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
- If Not SF_Utils._ValidateFile(FileName, "FileName") Then GoTo Finally
- If Not SF_Utils._Validate(Header, "Header", V_STRING) Then GoTo Finally
- If Not SF_Utils._Validate(Encoding, "Encoding", V_STRING) Then GoTo Finally
- End If
- Try:
- Set oFile = SF_FileSystem.CreateTextFile(FileName, Overwrite := True, Encoding := Encoding)
- If Not IsNull(oFile) Then
- With oFile
- ' Standard header
- .WriteLine(cstSharp)
- .WriteLine(cstSharp & "This pristine POT file has been generated by LibreOffice/ScriptForge")
- .WriteLine(cstSharp & "Full documentation is available on https://help.libreoffice.org/")
- ' User header
- If Len(Header) > 0 Then
- .WriteLine(cstSharp)
- vLines = SF_String.Wrap(Header, cstWrap, cstTabSize)
- For Each sLine In vLines
- .WriteLine(cstSharp & Replace(sLine, SF_String.sfLF, ""))
- Next sLine
- End If
- ' Standard header
- .WriteLine(cstSharp)
- .WriteLine("msgid """"")
- .WriteLine("msgstr """"")
- .WriteLine(SF_String.Quote("Project-Id-Version: PACKAGE VERSION\n"))
- .WriteLine(SF_String.Quote("Report-Msgid-Bugs-To: " _
- & "https://bugs.libreoffice.org/enter_bug.cgi?product=LibreOffice&bug_status=UNCONFIRMED&component=UI\n"))
- .WriteLine(SF_String.Quote("POT-Creation-Date: " & SF_STring.Represent(Now()) & "\n"))
- .WriteLine(SF_String.Quote("PO-Revision-Date: YYYY-MM-DD HH:MM:SS\n"))
- .WriteLine(SF_String.Quote("Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"))
- .WriteLine(SF_String.Quote("Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"))
- .WriteLine(SF_String.Quote("Language: en_US\n"))
- .WriteLine(SF_String.Quote("MIME-Version: 1.0\n"))
- .WriteLine(SF_String.Quote("Content-Type: text/plain; charset=" & Encoding & "\n"))
- .WriteLine(SF_String.Quote("Content-Transfer-Encoding: 8bit\n"))
- .WriteLine(SF_String.Quote("Plural-Forms: nplurals=2; plural=n > 1;\n"))
- .WriteLine(SF_String.Quote("X-Generator: LibreOffice - ScriptForge\n"))
- .WriteLine(SF_String.Quote("X-Accelerator-Marker: ~\n"))
- ' Individual translatable strings
- vItems = _Dictionary.Items()
- For Each vItem in vItems
- .WriteBlankLines(1)
- ' Comments
- vLines = Split(vItem.Comment, "\n")
- For Each sLine In vLines
- .WriteLine(cstSharpDot & SF_String.ExpandTabs(SF_String.Unescape(sLine), cstTabSize))
- Next sLine
- ' Flag
- If InStr(vItem.MsgId, "%") > 0 Then .WriteLine(cstFlag)
- ' Context
- If Len(vItem.Context) > 0 Then
- .WriteLine("msgctxt " & SF_String.Quote(vItem.Context))
- End If
- ' MsgId
- vLines = SF_String.Wrap(vItem.MsgId, cstWrap, cstTabSize)
- If UBound(vLines) = 0 Then
- .WriteLine("msgid " & SF_String.Quote(SF_String.Escape(vLines(0))))
- Else
- .WriteLine("msgid """"")
- For Each sLine in vLines
- .WriteLine(SF_String.Quote(SF_String.Escape(sLine)))
- Next sLine
- End If
- ' MsgStr
- .WriteLine("msgstr """"")
- Next vItem
- .CloseFile()
- End With
- End If
- bExport = True
- Finally:
- If Not IsNull(oFile) Then Set oFile = oFile.Dispose()
- ExportToPOTFile = bExport
- SF_Utils._ExitFunction(cstThisSub)
- Exit Function
- Catch:
- GoTo Finally
- End Function ' ScriptForge.SF_L10N.ExportToPOTFile
- REM -----------------------------------------------------------------------------
- Public Function GetProperty(Optional ByVal PropertyName As Variant) As Variant
- ''' Return the actual value of the given property
- ''' Args:
- ''' PropertyName: the name of the property as a string
- ''' Returns:
- ''' The actual value of the property
- ''' If the property does not exist, returns Null
- ''' Exceptions:
- ''' ARGUMENTERROR The property does not exist
- ''' Examples:
- ''' myL10N.GetProperty("MyProperty")
- Const cstThisSub = "L10N.GetProperty"
- Const cstSubArgs = ""
- If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
- GetProperty = Null
- Check:
- If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
- If Not SF_Utils._Validate(PropertyName, "PropertyName", V_STRING, Properties()) Then GoTo Catch
- End If
- Try:
- GetProperty = _PropertyGet(PropertyName)
- Finally:
- SF_Utils._ExitFunction(cstThisSub)
- Exit Function
- Catch:
- GoTo Finally
- End Function ' ScriptForge.SF_L10N.GetProperty
- REM -----------------------------------------------------------------------------
- Public Function GetText(Optional ByVal MsgId As Variant _
- , ParamArray pvArgs As Variant _
- ) As String
- ''' Get the translated string corresponding with the given argument
- ''' Args:
- ''' MsgId: the identifier of the string or the untranslated string
- ''' Either - the untranslated text (MsgId)
- ''' - the reference to the untranslated text (Context)
- ''' - both (Context|MsgId) : the pipe character is essential
- ''' pvArgs(): a list of arguments present as %1, %2, ... in the (un)translated string)
- ''' to be substituted in the returned string
- ''' Any type is admitted but only strings, numbers or dates are relevant
- ''' Returns:
- ''' The translated string
- ''' If not found the MsgId string or the Context string
- ''' Anyway the substitution is done
- ''' Examples:
- ''' myPO.GetText("This is a text to be included in a POT file")
- ''' ' Ceci est un text à inclure dans un fichier POT
- Dim sText As String ' Output buffer
- Dim sContext As String ' Context part of argument
- Dim sMsgId As String ' MsgId part of argument
- Dim vItem As POEntry ' Entry in the dictionary
- Dim vMsgId As Variant ' MsgId split on pipe
- Dim sKey As String ' Key of dictionary
- Dim sPercent As String ' %1, %2, ... placeholders
- Dim i As Long
- Const cstPipe = "|"
- Const cstThisSub = "L10N.GetText"
- Const cstSubArgs = "MsgId, [Arg0, Arg1, ...]"
- If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
- sText = ""
- Check:
- If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
- If Not SF_Utils._Validate(MsgId, "MsgId", V_STRING) Then GoTo Finally
- End If
- If Len(Trim(MsgId)) = 0 Then GoTo Finally
- sText = MsgId
- Try:
- ' Find and load entry from dictionary
- If Left(MsgId, 1) = cstPipe then MsgId = Mid(MsgId, 2)
- vMsgId = Split(MsgId, cstPipe)
- sKey = vMsgId(0)
- If Not _Dictionary.Exists(sKey) Then ' Not found
- If UBound(vMsgId) = 0 Then sText = vMsgId(0) Else sText = Mid(MsgId, InStr(MsgId, cstPipe) + 1)
- Else
- vItem = _Dictionary.Item(sKey)
- If Len(vItem.MsgStr) > 0 Then sText = vItem.MsgStr Else sText = vItem.MsgId
- End If
- ' Substitute %i placeholders
- For i = UBound(pvArgs) To 0 Step -1 ' Go downwards to not have a limit in number of args
- sPercent = "%" & (i + 1)
- sText = Replace(sText, sPercent, SF_String.Represent(pvArgs(i)))
- Next i
- Finally:
- GetText = sText
- SF_Utils._ExitFunction(cstThisSub)
- Exit Function
- Catch:
- GoTo Finally
- End Function ' ScriptForge.SF_L10N.GetText
- REM - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Public Function _(Optional ByVal MsgId As Variant _
- , ParamArray pvArgs As Variant _
- ) As String
- ''' Get the translated string corresponding with the given argument
- ''' Alias of GetText() - See above
- ''' Examples:
- ''' myPO._("This is a text to be included in a POT file")
- ''' ' Ceci est un text à inclure dans un fichier POT
- Dim sText As String ' Output buffer
- Dim sPercent As String ' %1, %2, ... placeholders
- Dim i As Long
- Const cstPipe = "|"
- Const cstThisSub = "L10N._"
- Const cstSubArgs = "MsgId, [Arg0, Arg1, ...]"
- If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
- sText = ""
- Check:
- If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
- If Not SF_Utils._Validate(MsgId, "MsgId", V_STRING) Then GoTo Finally
- End If
- If Len(Trim(MsgId)) = 0 Then GoTo Finally
- Try:
- ' Find and load entry from dictionary
- sText = GetText(MsgId)
- ' Substitute %i placeholders - done here, not in GetText(), because # of arguments is undefined
- For i = 0 To UBound(pvArgs)
- sPercent = "%" & (i + 1)
- sText = Replace(sText, sPercent, SF_String.Represent(pvArgs(i)))
- Next i
- Finally:
- _ = sText
- SF_Utils._ExitFunction(cstThisSub)
- Exit Function
- Catch:
- GoTo Finally
- End Function ' ScriptForge.SF_L10N._
- REM -----------------------------------------------------------------------------
- Public Function Methods() As Variant
- ''' Return the list of public methods of the L10N service as an array
- Methods = Array( _
- "AddText" _
- , "ExportToPOTFile" _
- , "GetText" _
- , "_" _
- )
- End Function ' ScriptForge.SF_L10N.Methods
- REM -----------------------------------------------------------------------------
- Public Function Properties() As Variant
- ''' Return the list or properties of the Timer class as an array
- Properties = Array( _
- "Folder" _
- , "Languages" _
- , "Locale" _
- )
- End Function ' ScriptForge.SF_L10N.Properties
- REM -----------------------------------------------------------------------------
- Public Function SetProperty(Optional ByVal PropertyName As Variant _
- , Optional ByRef Value As Variant _
- ) As Boolean
- ''' Set a new value to the given property
- ''' Args:
- ''' PropertyName: the name of the property as a string
- ''' Value: its new value
- ''' Exceptions
- ''' ARGUMENTERROR The property does not exist
- Const cstThisSub = "L10N.SetProperty"
- Const cstSubArgs = "PropertyName, Value"
- If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
- SetProperty = False
- Check:
- If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
- If Not SF_Utils._Validate(PropertyName, "PropertyName", V_STRING, Properties()) Then GoTo Catch
- End If
- Try:
- Select Case UCase(PropertyName)
- Case Else
- End Select
- Finally:
- SF_Utils._ExitFunction(cstThisSub)
- Exit Function
- Catch:
- GoTo Finally
- End Function ' ScriptForge.SF_L10N.SetProperty
- REM =========================================================== PRIVATE FUNCTIONS
- REM -----------------------------------------------------------------------------
- Public Sub _Initialize(ByVal psPOFile As String _
- , ByVal Encoding As String _
- )
- ''' Completes initialization of the current instance requested from CreateScriptService()
- ''' Load the POFile in the dictionary, otherwise leave the dictionary empty
- ''' Args:
- ''' psPOFile: the file to load the translated strings from
- ''' Encoding: The character set that should be used. Default = UTF-8
- Dim oFile As Object ' PO file handler
- Dim sContext As String ' Collected context string
- Dim sMsgId As String ' Collected untranslated string
- Dim sComment As String ' Collected comment string
- Dim sMsgStr As String ' Collected translated string
- Dim sLine As String ' Last line read
- Dim iContinue As Integer ' 0 = None, 1 = MsgId, 2 = MsgStr
- Const cstMsgId = 1, cstMsgStr = 2
- Try:
- ' Initialize dictionary anyway
- Set _Dictionary = SF_Services.CreateScriptService("Dictionary")
- Set _Dictionary.[_Parent] = [Me]
- ' Load PO file
- If Len(psPOFile) > 0 Then
- With SF_FileSystem
- _POFolder = ._ConvertToUrl(.GetParentFolderName(psPOFile))
- _Locale = .GetBaseName(psPOFile)
- _POFile = ._ConvertToUrl(psPOFile)
- End With
- ' Load PO file
- Set oFile = SF_FileSystem.OpenTextFile(psPOFile, IOMode := SF_FileSystem.ForReading, Encoding := Encoding)
- If Not IsNull(oFile) Then
- With oFile
- ' The PO file is presumed valid => syntax check is not very strict
- sContext = "" : sMsgId = "" : sComment = "" : sMsgStr = ""
- Do While Not .AtEndOfStream
- sLine = Trim(.ReadLine())
- ' Trivial examination of line header
- Select Case True
- Case sLine = ""
- If Len(sMsgId) > 0 Then AddText(sContext, sMsgId, sComment, sMsgStr)
- sContext = "" : sMsgId = "" : sComment = "" : sMsgStr = ""
- iContinue = 0
- Case Left(sLine, 3) = "#. "
- sComment = sComment & Iif(Len(sComment) > 0, "\n", "") & Trim(Mid(sLine, 4))
- iContinue = 0
- Case Left(sLine, 8) = "msgctxt "
- sContext = SF_String.Unquote(Trim(Mid(sLine, 9)))
- iContinue = 0
- Case Left(sLine, 6) = "msgid "
- sMsgId = SF_String.Unquote(Trim(Mid(sLine, 7)))
- iContinue = cstMsgId
- Case Left(sLine, 7) = "msgstr "
- sMsgStr = sMsgStr & SF_String.Unquote(Trim(Mid(sLine, 8)))
- iContinue = cstMsgStr
- Case Left(sLine, 1) = """"
- If iContinue = cstMsgId Then
- sMsgId = sMsgId & SF_String.Unquote(sLine)
- ElseIf iContinue = cstMsgStr Then
- sMsgStr = sMsgStr & SF_String.Unquote(sLine)
- Else
- iContinue = 0
- End If
- Case Else ' Skip line
- iContinue = 0
- End Select
- Loop
- ' Be sure to store the last entry
- If Len(sMsgId) > 0 Then AddText(sContext, sMsgId, sComment, sMsgStr)
- .CloseFile()
- Set oFile = .Dispose()
- End With
- End If
- Else
- _POFolder = ""
- _Locale = ""
- _POFile = ""
- End If
- Finally:
- Exit Sub
- End Sub ' ScriptForge.SF_L10N._Initialize
- REM -----------------------------------------------------------------------------
- Private Function _PropertyGet(Optional ByVal psProperty As String)
- ''' Return the value of the named property
- ''' Args:
- ''' psProperty: the name of the property
- Dim vFiles As Variant ' Array of PO-files
- Dim i As Long
- Dim cstThisSub As String
- Dim cstSubArgs As String
- cstThisSub = "SF_L10N.get" & psProperty
- cstSubArgs = ""
- SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
- With SF_FileSystem
- Select Case psProperty
- Case "Folder"
- If Len(_POFolder) > 0 Then _PropertyGet = ._ConvertFromUrl(_POFolder) Else _PropertyGet = ""
- Case "Languages"
- If Len(_POFolder) > 0 Then
- vFiles = .Files(._ConvertFromUrl(_POFolder), "??-??.po")
- For i = 0 To UBound(vFiles)
- vFiles(i) = SF_FileSystem.GetBaseName(vFiles(i))
- Next i
- Else
- vFiles = Array()
- End If
- _PropertyGet = vFiles
- Case "Locale"
- _PropertyGet = _Locale
- Case Else
- _PropertyGet = Null
- End Select
- End With
- Finally:
- SF_Utils._ExitFunction(cstThisSub)
- Exit Function
- End Function ' ScriptForge.SF_L10N._PropertyGet
- REM -----------------------------------------------------------------------------
- Private Function _Repr() As String
- ''' Convert the L10N instance to a readable string, typically for debugging purposes (DebugPrint ...)
- ''' Args:
- ''' Return:
- ''' "[L10N]: PO file"
- _Repr = "[L10N]: " & _POFile
- End Function ' ScriptForge.SF_L10N._Repr
- REM ============================================ END OF SCRIPTFORGE.SF_L10N
- </script:module>
|