Nicht angemeldeter Benutzer - Bearbeiten von Seiten ist nur als angemeldeter Benutzer möglich.

Modul:Vorlage:lang: Unterschied zwischen den Versionen

Aus imedwiki
Zur Navigation springen Zur Suche springen
(2016-08-14)
(no wikibase)
 
(37 dazwischenliegende Versionen von 3 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
local Export = { serial = "2016-08-14",
+
local Export = { serial = "2019-10-19",
                 suite  = "lang" }
+
                 suite  = "lang",
 +
                item  = 26826825 }
 
--[=[
 
--[=[
Vorlage:lang und Sprachnamenvorlagen unterstützen
+
Vorlage:lang und Sprachnamenvorlagen usw. unterstützen
 
]=]
 
]=]
 +
local Failsafe  = Export
 +
local GlobalMod = Export
  
  
  
 
local Config = {
 
local Config = {
  self          = Export.suite,
+
   errCat       = false,
   errCat         = false,
+
   errClass     = "error_lang",
   errClass       = "error_lang",
+
   errClasses   = false,
   errClasses     = false,
+
   errHide       = true,
   errHide       = false,
+
   errNS         = false,
   errNS         = false,
+
   errDoubled   = { en = "Doubled:",
   errDoubled     = { en = "Doubled:",
+
                    de = "Doppelangabe:" },
                      de = "Doppelangabe:" },
+
  errEmpty      = { en = "Empty parameter value",
   errInvalid     = { en = "Invalid:",
+
                    de = "Parameterwert fehlt" },
                      de = "Ungültig:" },
+
   errInvalid   = { en = "Invalid:",
   errMissing     = { en = "Missing parameter",
+
                    de = "Ungültig:" },
                      de = "Parameter fehlt" },
+
   errMissing   = { en = "Missing parameter",
   errUnkown     = { en = "Unkown parameter:",
+
                    de = "Parameter fehlt" },
                      de = "Parameter unbekannt:" },
+
  errSuggest    = { en = "'%s' * probably '%s' intended",
   audio          = "Audio",
+
                    de = "'%s' * vermutlich ist '%s' gemeint" },
   ipa            = "IPA",
+
   errUnkown     = { en = "Unkown parameter:",
   params         = { "Text1",
+
                    de = "Parameter unbekannt:" },
                      "Audio",
+
   ipa          = "IPA",
                      "IPA",
+
   keyBase      = 100,
                      "style",
+
  keyProject    = 200,
                      "nachgestellt",
+
  keyAncient    = 300,
                      "demo",
+
  keyTranslate  = 400,
                      "NoCat" },
+
   params       = { "Text1",
   owns           = { de = "‚%s‘" },
+
                    "Audio",
   transcriptions =
+
                    "IPA",
      { Arab = { en = "[[Arabic alphabet|arabic]]",
+
                    "class",
                  de = "[[Arabisches Alphabet|arabisch]]" },
+
                    "lenient",
        Cyrl = { en = "[[Cyrillic alphabets|cyrillic]]",
+
                    "script",
                  de = "[[Kyrillisches Alphabet|kyrillisch]]" }
+
                    "style",
      }
+
                    "nachgestellt",
 +
                    "demo",
 +
                    "demo2",
 +
                    "demo3",
 +
                    "demo4",
 +
                    "NoCat" },
 +
  percents      = false,
 +
  orderOther    = { grc = 1,
 +
                    hbo = 2,
 +
                    la  = 3,
 +
                    en  = 9 },
 +
   owns         = { de = "‚%s‘" },
 +
   sepComma      = "Latn Armn Cyrl Grek Thai",
 +
  site          = "Latn",
 +
  tmplAudio    = false,    -- template for media player link
 +
  tmplLang      = false,    -- template for language name link
 +
  tmplStyles    = false,
 +
  wikidata      = { Multilingual      = 47541920,
 +
                    ISO15924          = 71584769,
 +
                    ["ISO15924/codes"] = 71840276,
 +
                    TemplUtl          = 52364930 }
 
}
 
}
 +
 +
 +
 +
local foreignModule = function ( access, advanced, append, alt, alert )
 +
    -- Fetch global module
 +
    -- Precondition:
 +
    --    access    -- string, with name of base module
 +
    --    advanced  -- true, for require(); else mw.loadData()
 +
    --    append    -- string, with subpage part, if any; or false
 +
    --    alt      -- number, of wikidata item of root; or false
 +
    --    alert    -- true, for throwing error on data problem
 +
    -- Postcondition:
 +
    --    Returns whatever, probably table
 +
    -- 2019-10-29
 +
    local storage = access
 +
    local finer = function ()
 +
                      if append then
 +
                          storage = string.format( "%s/%s",
 +
                                                  storage,
 +
                                                  append )
 +
                      end
 +
                  end
 +
    local fun, lucky, r, suited
 +
    if advanced then
 +
        fun = require
 +
    else
 +
        fun = mw.loadData
 +
    end
 +
    GlobalMod.globalModules = GlobalMod.globalModules or { }
 +
    suited = GlobalMod.globalModules[ access ]
 +
    if not suited then
 +
        finer()
 +
        lucky, r = pcall( fun,  "Module:" .. storage )
 +
    end
 +
    if not lucky then
 +
        if not suited  and
 +
          type( alt ) == "number"  and
 +
          alt > 0 then
 +
            suited = string.format( "Q%d", alt )
 +
            if mw.wikibase then
 +
              suited = mw.wikibase.getSitelink( suited )
 +
            end
 +
            GlobalMod.globalModules[ access ] = suited or true
 +
        end
 +
        if type( suited ) == "string" then
 +
            storage = suited
 +
            finer()
 +
            lucky, r = pcall( fun, storage )
 +
        end
 +
        if not lucky and alert then
 +
            error( "Missing or invalid page: " .. storage, 0 )
 +
        end
 +
    end
 +
    return r
 +
end -- foreignModule()
 +
 +
 +
 +
local function Fetch( ask )
 +
    -- Fetch module (require)
 +
    -- Parameter:
 +
    --    ask  -- string, with name
 +
    --                    "ISO15924"
 +
    --                    "Multilingual"
 +
    --                    "TemplUtl"
 +
    -- Returns string, with error message, if not available
 +
    local ext = Config[ ask ]
 +
    local r
 +
    if not ext  and  ext ~= false then
 +
        ext = foreignModule( ask,
 +
                            true,
 +
                            false,
 +
                            Config.wikidata[ ask ] )
 +
        if type( ext ) == "table" then
 +
            Config[ ask ] = ext
 +
            if type( ext[ ask ] ) == "function" then
 +
                Config[ ask ] = ext[ ask ]()
 +
            end
 +
        end
 +
        if type( Config[ ask ] ) ~= "table" then
 +
            Config[ ask ] = false
 +
            if not ext then
 +
                ext = "Invalid library *** Module:" .. ask
 +
            end
 +
            ext = mw.html.create( "span" )
 +
                        :attr( "class", "error" )
 +
                        :wikitext( ext )
 +
            r = tostring( ext )
 +
        end
 +
    end
 +
    return r
 +
end -- Fetch()
 +
 +
 +
 +
local function Frame()
 +
    -- Fetch current frame
 +
    -- Returns frame
 +
    if not Config.frame then
 +
        Config.frame = mw.getCurrentFrame()
 +
    end
 +
    return Config.frame
 +
end -- Frame()
 +
 +
 +
 +
local function Friend()
 +
    -- Fetch Module:ISO15924/codes
 +
    if not Config.codesISO15924 then
 +
        Config.codesISO15924 = foreignModule( "ISO15924",
 +
                                              false,
 +
                                              "codes",
 +
                                              Config.wikidata.ISO15924 )
 +
        if type( Config.codesISO15924 ) ~= "table" then
 +
            Config.codesISO15924 = { }
 +
        end
 +
    end
 +
    return Config.codesISO15924
 +
end -- Friend()
 +
 +
 +
 +
local function Fulfil( access, args )
 +
    -- Expand template
 +
    --    apply  -- string, with template name
 +
    --    args  -- table, with parameters
 +
    -- Returns string
 +
    -- Throws error, if template not existing
 +
    return Frame():expandTemplate{ title = access,
 +
                                  args  = args }
 +
end -- Fulfil()
  
  
Zeile 70: Zeile 224:
 
     --    apply  -- string, with message key
 
     --    apply  -- string, with message key
 
     -- Returns message text; at least english
 
     -- Returns message text; at least english
 +
    local entry = Config[ apply ]
 
     local r
 
     local r
    entry = Config[ apply ]
 
 
     if entry then
 
     if entry then
 
         r = entry[ facility() ]
 
         r = entry[ facility() ]
Zeile 78: Zeile 232:
 
         end
 
         end
 
     else
 
     else
         r = string.format( "<span class=\"error\">????.%s.????</span>",
+
         local e = mw.html.create( "span" )
                          apply )
+
                        :attr( "class", "error" )
 +
                        :wikitext( string.format( "????.%s.????",
 +
                                                  apply ) )
 +
        r = tostring( e )
 
     end
 
     end
 
     return r
 
     return r
Zeile 94: Zeile 251:
 
     if s == "string" then
 
     if s == "string" then
 
         r = mw.text.trim( adjust )
 
         r = mw.text.trim( adjust )
         r = ( r ~= ""  and  r ~= "0" )
+
         r = ( r ~= ""  and  r ~= "0"  and  r ~= "-" )
 
     elseif s == "boolean" then
 
     elseif s == "boolean" then
 
         r = adjust
 
         r = adjust
Zeile 105: Zeile 262:
  
  
local function fault( alert, about )
+
local function familiar( ask, assign )
 +
    -- Check whether valid transcription for context
 +
    --    ask    -- string, with transcription code
 +
    --    assign  -- string or nil, with language or scripting key
 +
    -- Returns boolean
 +
    local r
 +
    Fetch( "ISO15924" )
 +
    if Config.ISO15924 then
 +
        r = Config.ISO15924.isTrans( ask, assign, Config.site )
 +
    end
 +
    return r
 +
end -- familiar()
 +
 
 +
 
 +
 
 +
local function family()
 +
    -- attempt to load local config
 +
    if not Config.data then
 +
        local sub = string.format( "%s/config", Frame():getTitle() )
 +
        local lucky
 +
        lucky, Config.data = pcall( mw.loadData, sub )
 +
        if type( Config.data ) == "table" then
 +
            for k, v in pairs( Config.data ) do
 +
                Config[ k ] = v
 +
            end -- for k, v
 +
        else
 +
            Config.data = sub .. " not found"
 +
        end
 +
    end
 +
end -- family()
 +
 
 +
 
 +
 
 +
local function fault( alert, about, assign )
 
     -- Format message with class="error" or similar
 
     -- Format message with class="error" or similar
     --    alert -- string, with message key
+
     --    alert   -- string, with message key
     --    about -- string, with explanation
+
     --    about   -- string, with explanation
 +
    --    assign  -- true, when standard category to be fired
 
     -- Returns message with markup
 
     -- Returns message with markup
 
     local story = factory( alert )
 
     local story = factory( alert )
     local r, scope, style
+
    local env  = Frame():getParent()
     if Config.self then
+
    local err  = mw.html.create( "span" )
         story = string.format( "%s * %s", Config.self, story )
+
     local r
 +
    err:addClass( Config.errClass )
 +
      :css( { ["margin-left"]  = "1em",
 +
              ["margin-right"] = "1em" } )
 +
    family()
 +
     if env then
 +
         story = string.format( "[[%s]] &#8211; %s",
 +
                              env:getTitle(), story )
 
     end
 
     end
     if not Config.frame then
+
     if about then
         Config.frame = mw.getCurrentFrame()
+
         story = string.format( "%s %s", story, about )
    end
 
    if Config.frame:preprocess( "{{REVISIONID}}" ) == "" then
 
        Config.errCat  = false
 
        Config.errHide = false
 
        scope          = string.format( "%s error", Config.errClass )
 
    else
 
        scope = Config.errClass
 
    end
 
    if Config.errHide then
 
        style = "style='display:none'"
 
    else
 
        style = ""
 
 
     end
 
     end
 
     if Config.errClasses then
 
     if Config.errClasses then
         scope = string.format( "%s %s",
+
         err:addClass( Config.errClasses )
                              scope, Config.errClasses )
 
 
     end
 
     end
     r = string.format( "<span class=\"%s\" %s>%s</span>",
+
    err:wikitext( story )
                      scope, style, story )
+
     r = Fetch( "TemplUtl" )
     if about then
+
     if Config.TemplUtl then
         r = string.format( "%s %s", r, about )
+
         r = Config.TemplUtl.failure( tostring( err ),
 +
                                    not Config.errHide,
 +
                                    false,
 +
                                    Frame() )
 
     end
 
     end
     if Config.errCat then
+
     if assign  and  type( Config.errCat ) == "string" then
 
         if Config.errNS then
 
         if Config.errNS then
 
             local ns = mw.title.getCurrentTitle().namespace
 
             local ns = mw.title.getCurrentTitle().namespace
Zeile 167: Zeile 355:
  
  
local function fetch( auxilary )
+
local function features( apply, assign )
     -- Fetch module
+
     -- Equip element with script attributes
     --    auxilary -- Multilingual library, or false
+
     --    apply  -- mw.html element
     -- Returns table of library, or string with error message
+
    --    assign -- string, with script code
     local r = auxilary
+
    if type( Config.percents ) == "table" then
     if type( r ) ~= "table" then
+
        local more = Config.percents[ assign ]
         local lucky
+
        if more then
         lucky, r = pcall( require, "Module:Multilingual" )
+
            apply:css( "font-size", string.format( "%d%%", more ) )
 +
        end
 +
    end
 +
end -- features()
 +
 
 +
 
 +
 
 +
local function fill( apply )
 +
    -- Expand language name template
 +
    --    apply  -- string, with code
 +
     -- Returns string, identical apply in case of error
 +
     local r = apply
 +
    local template
 +
    family()
 +
    template = Config.tmplLang
 +
     if type( template ) == "table" then
 +
         local source = template.title
 +
        if type( source ) ~= "string" then
 +
            if type( template.namePat ) == "string"  and
 +
              template.namePat:find( "%s", 1, true ) then
 +
                source = string.format( template.namePat, apply )
 +
            end
 +
        end
 +
         if type( source ) == "string" then
 +
            local lucky, s = pcall( Fulfil, source )
 +
            if lucky then
 +
                r = s
 +
            end
 +
        end
 +
    end
 +
    return r
 +
end -- fill()
 +
 
 +
 
 +
 
 +
local function first( assign, apply )
 +
    -- Equip element with TemplateStyles
 +
    --    assign  -- string, with script code
 +
    --    apply  -- mw.html element, or false
 +
    -- Returns string, perhaps with tag
 +
    local r
 +
    if type( Config.tmplStyles ) == "table" then
 +
        local source = Config.tmplStyles[ assign ]
 +
        if source then
 +
            r = Frame():extensionTag( "templatestyles",
 +
                                      nil,
 +
                                      { src = source } )
 +
            if apply then
 +
                apply:wikitext( r )
 +
            end
 +
        end
 +
    end
 +
    return r or ""
 +
end -- first()
 +
 
 +
 
 +
 
 +
local function fit( acquire )
 +
    -- Retrieve script code for language
 +
    --    acquire  -- string, with language code
 +
    -- Returns string or false
 +
    local r
 +
    local iso639script = Friend().iso639script
 +
    if type( iso639script ) == "table" then
 +
        r = iso639script[ acquire ]
 
         if type( r ) == "table" then
 
         if type( r ) == "table" then
             r = r.Multilingual()
+
             r = r[ 1 ]
        else
 
            r = string.format( "<span class=\"error\">%s</span>", r )
 
 
         end
 
         end
 
     end
 
     end
 
     return r
 
     return r
end -- fetch()
+
end -- fit()
  
  
  
local function flat( argsF, argsT )
+
local function flag( already, apply )
     -- Invocation of basic language template
+
     -- Check whether space separated classes contain
     --    argsT -- table, with parameters
+
     --    already -- string or false, with classes
     -- Returns appropriate string
+
     --     apply    -- string or false, with single class
     local slang = argsT[ 1 ]
+
     -- Returns true, if apply is in already
    local show  = argsT[ 2 ]
 
 
     local r
 
     local r
     if argsF then
+
     if already then
         Config.errCat  = argsF.errCat
+
         if apply then
        Config.errHide = faculty( argsF.errHide )
+
            local classes = mw.text.split( already, "%s+" )
         Config.errNS  = argsF.errNS
+
            local plus    = mw.text.split( apply, "%s+" )
 +
            local single
 +
            for i = 1, #plus do
 +
                single = plus[ i ]
 +
                for k = 1, #classes do
 +
                    if classes[ k ] == single then
 +
                        single = false
 +
                        break -- for k
 +
                    end
 +
                end -- for k
 +
                if single then
 +
                    table.insert( classes, single )
 +
                end
 +
            end -- for i
 +
            r = table.concat( classes, " " )
 +
         else
 +
            r = already
 +
        end
 +
    else
 +
        r = apply
 
     end
 
     end
     if slang then
+
     return r
         slang = mw.text.trim( slang )
+
end -- flag()
         if slang == "" then
+
 
             slang = false
+
 
 +
 
 +
local function flatten( apply )
 +
    -- Trim any whitespace, even HTML encoded
 +
    --    apply  -- string
 +
    -- Returns string, or false if empty
 +
    local r = apply
 +
    if r:find( "&" ) then
 +
         r = r:gsub( "&nbsp;",    "&#160;" )
 +
            :gsub( "&thinsp;", "&#8201;" )
 +
            :gsub( "&zwnj;",  "&#8204;" )
 +
            :gsub( "&zwj;",    "&#8205;" )
 +
            :gsub( "&lrm;",    "&#8206;" )
 +
            :gsub( "&rlm;",    "&#8207;" )
 +
         if r:find( "&#" ) then
 +
            local f = function ( ax, an )
 +
                          local k
 +
                          if ax == "x" then
 +
                              k = 16
 +
                          else
 +
                              k = 10
 +
                          end
 +
                          return mw.ustring.char( tonumber( an, k ) )
 +
                      end
 +
             r = r:gsub( "&#(x?)(%x+);",  f )
 
         end
 
         end
 
     end
 
     end
     if show then
+
     if not Config.patternWS then
         show = mw.text.trim( show )
+
         Config.patternWS = mw.ustring.char(  91,
        if show == "" then
+
                                              1, 45, 32,
             show = false
+
                                            160,
 +
                                            8194, 45, 8207,
 +
                                            8239,
 +
                                              93,
 +
                                              43 )
 +
    end
 +
    r = mw.ustring.gsub( r,  "^" .. Config.patternWS,  "" )
 +
    r = mw.ustring.gsub( r,  Config.patternWS .. "$",  "" )
 +
    if r == "" then
 +
        r = false
 +
    end
 +
    return r
 +
end -- flatten()
 +
 
 +
 
 +
 
 +
local function follow( affine )
 +
    -- Retrieve appropriate separator
 +
    --    affine    -- string or nil, with code of script
 +
    -- Returns string, with separator (comma) or not
 +
    local r
 +
    if affine then
 +
        if Config.sepComma:find( affine, 1, true ) then
 +
             r = ","
 +
        else
 +
            r = ""
 
         end
 
         end
    end
 
    if slang and show then
 
        local e = mw.html.create( "span" )
 
                        :attr( "lang", slang )
 
                        :wikitext( show )
 
        r = tostring( e )
 
        -- syntax check on slang
 
 
     else
 
     else
         r = fault( "errMissing" )
+
         r = ","
        if show then
 
            r = show .. r
 
        end
 
 
     end
 
     end
 
     return r
 
     return r
end -- flat()
+
end -- follow()
  
  
  
local function foreign( apply, acquire, advanced )
+
local function foreign( apply, acquire, advanced, affine )
 
     -- Format text in some language
 
     -- Format text in some language
 
     --    apply    -- string, with text
 
     --    apply    -- string, with text
 
     --    acquire  -- string, with basic code of language
 
     --    acquire  -- string, with basic code of language
 
     --    advanced  -- string, with full code of language
 
     --    advanced  -- string, with full code of language
     -- Returns string, starting with comma
+
     --     affine    -- string or nil, with code of script
     local story = apply
+
    -- Returns string
 +
     local story = apply
 +
    local script = affine
 +
    local p = { ["font-weight"] = "normal" }
 
     local ltr, r
 
     local ltr, r
 
     if advanced == acquire then
 
     if advanced == acquire then
 
         ltr = not mw.language.new( acquire ):isRTL()
 
         ltr = not mw.language.new( acquire ):isRTL()
     else
+
     elseif not script  and  advanced:find( "-", 3, true ) then
         ltr = not ( advanced:match( "-Arab$" )  or
+
         local parts = mw.text.split( advanced, "-", true )
                    advanced:match( "-Hebr$" ) )
+
        if #parts > 1 and  parts[ 2 ]:match( "^%u%l%l%l$" ) then
 +
            script = parts[ 2 ]
 +
        end
 +
    end
 +
    if script then
 +
        local rtl = Friend().rtl
 +
        if type( rtl ) == "table" then
 +
            ltr = not rtl[ script ]
 +
        end
 
     end
 
     end
 
     if ltr then
 
     if ltr then
 
         local e = mw.html.create( "span" )
 
         local e = mw.html.create( "span" )
 
                         :attr( "lang", advanced )
 
                         :attr( "lang", advanced )
        local p = { ["font-weight"] = "normal" }
 
 
         local s = "normal"
 
         local s = "normal"
         if acquire == Config.standard
+
         if acquire == facility()
 
           and Config.owns[ acquire ]  then
 
           and Config.owns[ acquire ]  then
 
             story = string.format( Config.owns[ acquire ], apply )
 
             story = string.format( Config.owns[ acquire ], apply )
         elseif advanced == acquire  or
+
         elseif advanced == acquire  and  Config.site == "Latn"  or
 
               advanced == acquire .. "-Latn" then
 
               advanced == acquire .. "-Latn" then
 
             s = "italic"
 
             s = "italic"
Zeile 258: Zeile 575:
 
         r = tostring( e )
 
         r = tostring( e )
 
     else
 
     else
         r = frame():expandTemplate{ title = advanced,
+
        p["font-style"] = "normal"
                                    args  = { [1] = apply } }
+
         r = Export.fold( { css      = p,
 +
                          SCRIPTING = script },
 +
                        { [ 1 ] = acquire,
 +
                          [ 2 ] = apply,
 +
                          lang  = advanced } )
 
     end
 
     end
 
     return r
 
     return r
Zeile 266: Zeile 587:
  
  
local function foreigns( aliens )
+
local function foreigns( ahead, aliens, alone )
 
     -- Create list of translations
 
     -- Create list of translations
 +
    --    ahead  -- string, with leading separator
 
     --    aliens  -- sequence table, with assignment tables
 
     --    aliens  -- sequence table, with assignment tables
     -- Returns string, starting with comma
+
    --    alone  -- boolean, no other elements in collection yet
     local r = ""
+
     -- Returns string, starting with separator (comma)
     local s, t
+
    local pars = { }
 +
    local sep  = ahead
 +
    local lone = alone
 +
     local r   = ""
 +
     local k, lucky, s, t
 +
    family()
 
     facility()
 
     facility()
 +
    Fetch( "Multilingual" )
 
     for i = 1, #aliens do
 
     for i = 1, #aliens do
 
         t = aliens[ i ]
 
         t = aliens[ i ]
 
         if t.short == Config.standard then
 
         if t.short == Config.standard then
             t.n = 1
+
            t.m = Config.keyProject
         elseif t.short == "en" then
+
             t.n = 0
            t.n = 2
+
         else
 +
            k = Config.orderOther[ t.short ]
 +
            if k then
 +
                t.n = k
 +
                t.m = Config.keyAncient
 +
            end
 +
            lone = false
 
         end
 
         end
 +
        t.n = t.m + t.n
 
     end -- for i
 
     end -- for i
 
     table.sort( aliens,
 
     table.sort( aliens,
Zeile 287: Zeile 622:
 
     for i = 1, #aliens do
 
     for i = 1, #aliens do
 
         t = aliens[ i ]
 
         t = aliens[ i ]
         s = mw.language.fetchLanguageName( t.short, Config.standard )
+
         if lone then
        s = mw.ustring.lower( mw.ustring.sub( s, 1, 1 ) )
+
            s  = ""
            .. mw.ustring.sub( s, 2 )
+
            sep = ""
         r = string.format( "%s, %s %s",
+
        else
                          r,
+
            s = false
                          facet( s ),
+
            if t.short == Config.slang  and
                          foreign( t.story, t.short, t.slang ) )
+
              t.script  and
 +
              t.n > 0 then
 +
                Fetch( "ISO15924" )
 +
                if Config.ISO15924 then
 +
                    s = Config.ISO15924.scriptName( t.script )
 +
                    if s == t.script then
 +
                        s = false
 +
                    end
 +
                end
 +
            end
 +
            if not s  and  t.n > Config.keyProject then
 +
                s = fill( t.short )
 +
            end
 +
            if not s then
 +
                Fetch( "Multilingual" )
 +
                s = mw.language.fetchLanguageName( t.short,
 +
                                                  Config.standard )
 +
                if Config.Multilingual  and
 +
                  Config.Multilingual.isMinusculable( s ) then
 +
                    s = mw.ustring.lower( mw.ustring.sub( s, 1, 1 ) )
 +
                        .. mw.ustring.sub( s, 2 )
 +
                end
 +
            end
 +
        end
 +
         r   = string.format( "%s%s %s %s",
 +
                            r,
 +
                            sep,
 +
                            s,
 +
                            foreign( t.story,
 +
                                      t.short,
 +
                                      t.slang,
 +
                                      t.script ) )
 +
        sep = follow( t.script )
 
     end -- for i
 
     end -- for i
 
     return r
 
     return r
Zeile 300: Zeile 667:
  
  
local function frame()
+
local function friend( assigned, apply )
     -- Fetch current frame
+
     -- Transcription unit
 +
    --    assigned  -- string, transcription ID
 +
    --    apply    -- string, transcription text
 +
    -- Returns string
 +
    local e = mw.html.create( "span" )
 +
                    :addClass( Config.site )
 +
                    :attr( "lang",
 +
                            string.format( "%s-%s",
 +
                                          Config.slang,
 +
                                          Config.site ) )
 +
                    :css( { ["font-weight"] = "normal" } )
 +
                    :wikitext( apply )
 +
    local r, s
 +
    if Config.site == "Latn" then
 +
        s = "italic"
 +
    else
 +
        s = "normal"
 +
    end
 +
    e:css( { ["font-style"] = s } )
 +
    if type( Config.transys ) == "table"  and
 +
      type( Config.transys[ assigned ] ) == "table" then
 +
        local transys = Config.transys[ assigned ]
 +
        if transys.class then
 +
            e:addClass( transys.class )
 +
        end
 +
        if transys.show then
 +
            s = transys.show
 +
        else
 +
            s = assigned
 +
        end
 +
        if transys.support then
 +
            if s == transys.support then
 +
                s = string.format( "[[%s]]", s )
 +
            else
 +
                s = string.format( "[[%s|%s]]", transys.support, s )
 +
            end
 +
        end
 +
    else
 +
        s = assigned
 +
    end
 +
    r = string.format( "%s %s%s",
 +
                      s,  first( Config.site ),  tostring( e ) )
 +
    return r
 +
end -- friend()
 +
 
 +
 
 +
 
 +
local function frontend( action, argsF, argsT, about )
 +
    -- Template service
 +
    --    action  -- string, "flat" or "full" etc.
 +
    --    argsF  -- table, with #invoke parameters, or false
 +
    --    argsT  -- table, with template parameters
 +
    --    about  -- string or nil, invocation name
 
     -- Returns frame
 
     -- Returns frame
     if not Config.frame then
+
    local lucky, r
         Config.frame = mw.getCurrentFrame()
+
    lucky, r = pcall( Export[ action ], argsF, argsT )
 +
     if not lucky then
 +
         local e = mw.html.create( "span" )
 +
                        :attr( "class", "error" )
 +
        if about then
 +
            r = string.format( "&#123;{%s}&#125; %s",  about,  r )
 +
        end
 +
        e:wikitext( r )
 +
        r = tostring( e )
 
     end
 
     end
     return Config.frame
+
     return r
end -- frame()
+
end -- frontend()
 +
 
 +
 
 +
 
 +
local function frontier( frame, action )
 +
    -- Template transclusion
 +
    --    frame  -- object
 +
    --    action  -- string, "flat" or "full" etc.
 +
    -- Returns appropriate string
 +
    Config.frame = frame
 +
    return frontend( action,
 +
                    frame.args,
 +
                    frame:getParent().args,
 +
                    frame:getTitle() )
 +
end -- frontier()
  
  
  
 
local function full( arglist )
 
local function full( arglist )
     -- Invocation of language name template
+
     -- Finalize invocation of template
 
     --    arglist  -- table, with parameters
 
     --    arglist  -- table, with parameters
 
     -- Returns appropriate string
 
     -- Returns appropriate string
Zeile 318: Zeile 759:
 
     if arglist.Text1 then
 
     if arglist.Text1 then
 
         local slang = Config.slang
 
         local slang = Config.slang
         local params, s
+
         local lone  = true
         if Config.scripting == "Latn" then
+
        local s, sep
 +
        if not Config.scripting then
 +
            Config.scripting = fit( Config.slang )
 +
        end
 +
        sep = follow( Config.scripting )
 +
         if Config.scripting == Config.site then
 
             if slang == facility() then
 
             if slang == facility() then
 
                 arglist.style = false
 
                 arglist.style = false
             else
+
             elseif not arglist.style then
                 arglist.style = arglist.style or "font-style:italic"
+
                 arglist.style = "font-style:italic"
 
             end
 
             end
 +
            sep = follow( Config.site )
 
             if arglist.Text2 then
 
             if arglist.Text2 then
                 arglist.Text2 = fault( "errInvalid", "Latn+2=" )
+
                 arglist.Text2 = fault( "errInvalid",
 +
                                      Config.site .. "+2=",
 +
                                      true )
 
             end
 
             end
         else
+
         elseif not Config.low  and  not arglist.style then
             arglist.style = arglist.style or "font-style:normal"
+
             arglist.style = "font-style:normal"
 +
        end
 +
        if Config.state then
 +
            slang = string.format( "%s-%s", slang, Config.state )
 
         end
 
         end
         if Config.long and Config.scripting then
+
         if Config.scripting then
 
             slang = string.format( "%s-%s", slang, Config.scripting )
 
             slang = string.format( "%s-%s", slang, Config.scripting )
 
         end
 
         end
Zeile 337: Zeile 789:
 
                           arglist.Text1,
 
                           arglist.Text1,
 
                           arglist.style,
 
                           arglist.style,
                           arglist.Audio )
+
                           arglist.Audio,
 +
                          arglist.class )
 
         if arglist.Text2 then
 
         if arglist.Text2 then
             params = { lang = string.format( "%s-Latn",
+
             local e = mw.html.create( "span" )
                                              Config.slang ),
+
                            :addClass( Config.site )
                      style = "font-style:italic" }
+
                            :attr( "lang",
            s = mw.text.tag( "span", params, arglist.Text2 )
+
                                    string.format( "%s-%s",
             r = string.format( "%s %s", r, s )
+
                                                  Config.slang,
 +
                                                  Config.site ) )
 +
                            :css( { ["font-weight"] = "normal" } )
 +
                            :wikitext( arglist.Text2 )
 +
                            if Config.site == "Latn" then
 +
                                s = "italic"
 +
                            else
 +
                                s = "normal"
 +
                            end
 +
                            e:css( { ["font-style"] = s } )
 +
             r   = string.format( "%s %s%s",
 +
                                  r,
 +
                                  first( Config.site ),
 +
                                  tostring( e ) )
 +
            sep  = follow( Config.site )
 +
            lone = false
 
         end
 
         end
         if Config.scripting then
+
         if arglist.trans then
             s = arglist[ Config.scripting ]
+
             local e
             if s and
+
            for i = 1, #arglist.trans do
              faculty( s ) and
+
                e  = arglist.trans[ i ]
              not arglist.Text2 and
+
                r  = string.format( "%s%s %s",
              Config.transcriptions[ Config.scripting ] then
+
                                    r,
                s = facility()
+
                                    sep,
                 s = Config.transcriptions[ Config.scripting ][ s ]
+
                                    friend( e.system, e.story ) )
 +
                sep = follow( Config.site )
 +
            end  -- for i
 +
            lone = false
 +
        end
 +
        if not Config.low then
 +
             if Config.scripting then
 +
                s = false
 +
                if arglist[ Config.scripting ] and
 +
                  not arglist.Text2 then
 +
                    Fetch( "ISO15924" )
 +
                    if Config.ISO15924 then
 +
                        s = Config.ISO15924
 +
                                          .scriptName( Config.scripting )
 +
                    end
 +
                end
 +
                if not s  and  Config.service then
 +
                    s = facet( Config.service )
 +
                end
 +
            elseif Config.service then
 +
                 s = Config.service
 
             else
 
             else
                 s = facet( Config.service )
+
                 s = false
 +
            end
 +
            if s then
 +
                if arglist.later then
 +
                    r    = string.format( "%s (%s)", r, s )
 +
                    lone = false
 +
                else
 +
                    r = string.format( "%s %s", s, r )
 +
                end
 
             end
 
             end
        else
 
            s = Config.service
 
        end
 
        if arglist.later then
 
            r = string.format( "%s (%s)", r, s )
 
        else
 
            r = string.format( "%s %s", s, r )
 
 
         end
 
         end
 
         if arglist.IPA then
 
         if arglist.IPA then
             params = { [1] = arglist.IPA }
+
             local params = { [1] = arglist.IPA }
             s = frame():expandTemplate{ title = Config.ipa,
+
             s   = Frame():expandTemplate{ title = Config.ipa,
                                        args  = params }
+
                                          args  = params }
             r = string.format( "%s [%s]", r, s )
+
             r   = string.format( "%s [%s]", r, s )
        end
+
             sep  = follow()
        if arglist.Text3 then
+
            lone = false
             r = string.format( "%s, %s", r, arglist.Text3 )
 
 
         end
 
         end
 
         if arglist.trsl then
 
         if arglist.trsl then
             r = r .. foreigns( arglist.trsl )
+
             r = r .. foreigns( sep, arglist.trsl, lone )
 
         end
 
         end
 
     elseif arglist.Text2 then
 
     elseif arglist.Text2 then
         r = fault( "errInvalid", "2=" )
+
         r = fault( "errInvalid", "|1=|2=", true )
 
     else
 
     else
 
         if Config.sole then
 
         if Config.sole then
Zeile 390: Zeile 878:
  
  
Export.failsafe = function ( assert )
+
local function furnish( argsF, argsT )
    local r
+
     -- General entry point; basic argument consumption
    if not assert  or  assert <= Export.serial then
 
        r = Export.serial
 
    else
 
        r = false
 
    end
 
    return r
 
end -- Export.failsafe()
 
 
 
 
 
 
 
Export.format = function ( alien, apply, appear, audio )
 
    -- Markup foreign language text
 
    --    alien  -- string, with language code
 
    --    apply  -- string, with text
 
    --    appear  -- string, with additional CSS, or nil
 
    --    audio  -- string, with title of an audio file, or nil
 
    -- Returns appropriate string with HTML tag
 
    local params = { lang = alien }
 
    local r
 
    if appear then
 
        params.style = appear
 
    end
 
    r = mw.text.tag( "span", params, apply )
 
    if audio and Config.audio then
 
        params = { [1] = audio,
 
                  [2] = r }
 
        r = frame():expandTemplate{ title = Config.audio,
 
                                    args  = params }
 
    end
 
    return r
 
end -- Export.format()
 
 
 
 
 
 
 
Export.full = function ( argsF, argsT )
 
     -- Invocation of language name template
 
 
     --    argsF  -- table, with #invoke parameters, or false
 
     --    argsF  -- table, with #invoke parameters, or false
 
     --    argsT  -- table, with template parameters
 
     --    argsT  -- table, with template parameters
 
     -- Returns appropriate string
 
     -- Returns appropriate string
 +
    local parIgnore = { }
 
     local r = { }
 
     local r = { }
 
     local s
 
     local s
 
     if argsF then
 
     if argsF then
 +
        if argsF.errHide ~= nil then
 +
            Config.errHide = faculty( argsF.errHide )
 +
        end
 
         Config.errCat    = argsF.errCat
 
         Config.errCat    = argsF.errCat
 
         Config.errClasses = argsF.errClasses
 
         Config.errClasses = argsF.errClasses
        Config.errHide    = faculty( argsF.errHide )
 
 
         Config.errNS      = argsF.errNS
 
         Config.errNS      = argsF.errNS
         Config.long      = faculty( argsF.LONG )
+
         if argsF.ELEMENT and argsF.ELEMENT:match( "^%a+$" ) then
        Config.scripting  = argsF.SCRIPTING
+
            Config.scope = argsF.ELEMENT:lower()
         Config.service    = argsF.SERVICE
+
         end
        Config.slang      = argsF.CODE
 
        Config.sole      = argsF.SOLE
 
 
         if argsF.SUITABLE then
 
         if argsF.SUITABLE then
 
             local params = mw.text.split( argsF.SUITABLE, " ", true )
 
             local params = mw.text.split( argsF.SUITABLE, " ", true )
 
             for k, v in pairs( params ) do
 
             for k, v in pairs( params ) do
                 table.insert( Config.params, v )
+
                 parIgnore[ v ] = true
 
             end -- for k, v
 
             end -- for k, v
 
         end
 
         end
        if Config.scripting == "" then
+
    end
            Config.scripting = false
+
    if Config.scripting == "" then
        end
+
        Config.scripting = false
        if Config.scripting then
+
    end
            table.insert( Config.params, Config.scripting )
+
    if Config.scripting then
            if Config.scripting ~= "Latn" then
+
        table.insert( Config.params, Config.scripting )
                table.insert( Config.params, "Text2" )
 
                table.insert( Config.params, "Text3" )
 
            end
 
        end
 
        if Config["OBSOLETING-b"] then
 
            table.insert( Config.params, "b" )
 
        end
 
 
     end
 
     end
 
     if type( argsT ) == "table" then
 
     if type( argsT ) == "table" then
 
         local n = table.maxn( Config.params )
 
         local n = table.maxn( Config.params )
         local unknown
+
         local script, unknown
 
         for k, v in pairs( argsT ) do
 
         for k, v in pairs( argsT ) do
 +
            v = flatten( v )
 
             s = type( k )
 
             s = type( k )
 
             if s == "number" then
 
             if s == "number" then
                 if ( k <= 3 ) then
+
                 if Config.low then
                     v = mw.text.trim( v )
+
                    k = k - 1
                     k = string.format( "Text%d", k )
+
                end
 +
                if k <= 2 then
 +
                     if v then
 +
                        if k == 0 then
 +
                            k = false
 +
                        else
 +
                            if k == 1 then
 +
                                r.Text1 = v
 +
                                k      = false
 +
                            elseif Config.scripting == Config.site then
 +
                                k = "2"
 +
                            else
 +
                                r.Text2 = v
 +
                                k      = false
 +
                            end
 +
                        end
 +
                     else
 +
                        if not Config.lenient then
 +
                            -- LEGACY
 +
                            k = string.format( "%s %s, |%d=",
 +
                                              "Sprachvorlage:",
 +
                                              factory( "errEmpty" ),
 +
                                              k )
 +
                            mw.addWarning( k )
 +
                        end
 +
                        k = false
 +
                    end
 
                 else
 
                 else
 
                     k = tostring( k )
 
                     k = tostring( k )
 
                 end
 
                 end
             end
+
             elseif parIgnore[ k ] then
             if k:match( "^%l%l%l?-?" ) then
+
                k = false
 +
             elseif k:match( "^%l%l%l?%-?" ) then
 
                 s = k:match( "^(%l%l%l?)$" )  or
 
                 s = k:match( "^(%l%l%l?)$" )  or
                     k:match( "^(%l%l%l?)-%u%l%l%l$" )
+
                     k:match( "^(%l%l%l?)%-%u%u$" )  or
                 if s and
+
                    k:match( "^(%l%l%l?)%-%u%l%l%l$" )
                   s ~= Config.slang  and
+
                if v then
                  mw.language.isSupportedLanguage( s ) then
+
                    script = k:match( "^%l%l%l?%-(%u%l%l%l)$" )
 +
                else
 +
                    k = false
 +
                end
 +
                 if v  and  s   and
 +
                   ( s ~= Config.slang  or
 +
                    script ~= Config.scripting ) then
 +
                    local legal = mw.language.isSupportedLanguage( s )
 +
                    if not legal then
 +
                        legal = ( s ~= fill( s ) )
 +
                    end
 +
                    if legal then
 +
                        local state = k:match( "^%l%l%l?%-(%u%u)$" )
 +
                        local m
 +
                        if s == Config.slang then
 +
                            m = Config.keyBase
 +
                        else
 +
                            m = Config.keyTranslate
 +
                        end
 +
                        if not script then
 +
                            script = fit( s )
 +
                            if script then
 +
                                k = string.format( "%s-%s", s, script )
 +
                            end
 +
                        end
 +
                        if not r.trsl then
 +
                            r.trsl = { }
 +
                        end
 +
                        table.insert( r.trsl,
 +
                                      { m      = m,
 +
                                        n      = #r.trsl + 1,
 +
                                        script = script,
 +
                                        short  = s,
 +
                                        slang  = k,
 +
                                        state  = state,
 +
                                        story  = v } )
 +
                        k = false
 +
                    end
 +
                end
 +
            elseif k:match( "^%u%u+%d*%.?%d*%-?%u*%d*$" ) then
 +
                if familiar( k, Config.scripting )  or
 +
                  familiar( k, Config.slang ) then
 +
                    if v then
 +
                        if not r.trans then
 +
                            r.trans = { }
 +
                        end
 +
                        table.insert( r.trans,
 +
                                      { system = k,
 +
                                        story  = v } )
 +
                    end
 +
                    k = false
 +
                end
 +
            elseif k:match( "^%u%l%l%l$" ) then
 +
                if k == Config.scripting then
 +
                    if faculty( v ) then
 +
                        r[ k ] = true
 +
                    end
 +
                else
 
                     if not r.trsl then
 
                     if not r.trsl then
 
                         r.trsl = { }
 
                         r.trsl = { }
 
                     end
 
                     end
 
                     table.insert( r.trsl,
 
                     table.insert( r.trsl,
                                   { n     = #r.trsl + 3,
+
                                   { m      = 100,
                                     short = s,
+
                                    n     = #r.trsl + 1,
                                     slang = k,
+
                                    script = k,
                                     story = v } )
+
                                     short = Config.slang,
                    k = false
+
                                     slang = string.format( "%s-%s",
 +
                                                            Config.slang,
 +
                                                            k ),
 +
                                     story = v } )
 
                 end
 
                 end
 +
                k = false
 
             end
 
             end
 
             if k then
 
             if k then
 
                 for i = 1, n do
 
                 for i = 1, n do
 
                     if Config.params[ i ] == k then
 
                     if Config.params[ i ] == k then
                         if v ~= "" then
+
                         if v then
 
                             r[ k ] = v
 
                             r[ k ] = v
 
                         end
 
                         end
Zeile 512: Zeile 1.047:
 
         end -- for k, v
 
         end -- for k, v
 
         if r.demo  or  faculty( r.NoCat ) then
 
         if r.demo  or  faculty( r.NoCat ) then
             Config.errCat  = false
+
             Config.errCat  = 0
 
             Config.errHide = false
 
             Config.errHide = false
 
         end
 
         end
 
         r.later = faculty( r.nachgestellt )
 
         r.later = faculty( r.nachgestellt )
         if r.b and Config["OBSOLETING-b"] then
+
         if r.b and Config[ "OBSOLETING-bwd" ] then
 
             if r.de then
 
             if r.de then
                 r = fault( "errDoubled", "'de=' und 'b='" )
+
                 r = fault( "errDoubled", "'de=' und 'b='", true )
 
             else
 
             else
 
                 r.de = r.b
 
                 r.de = r.b
 +
            end
 +
        end
 +
        if r.w and Config[ "OBSOLETING-bwd" ] then
 +
            if r.Text2 then
 +
                r = fault( "errDoubled", "'2=' und 'w='", true )
 +
            else
 +
                r.Text2 = r.w
 
             end
 
             end
 
         end
 
         end
 
         if unknown then
 
         if unknown then
             r = string.format( "'<code>%s</code>' in Template:lang",
+
             local e = mw.html.create( "code" )
                              table.concat( unknown, " " ) )
+
                            :wikitext( table.concat( unknown, " " ) )
             r = fault( "errUnkown", r )
+
             r = fault( "errUnkown",
 +
                      string.format( "'%s'",  tostring( e ) ),
 +
                      true )
 
         end
 
         end
 
     end
 
     end
Zeile 533: Zeile 1.077:
 
     end
 
     end
 
     return r
 
     return r
 +
end -- furnish()
 +
 +
 +
 +
Export.flat = function ( argsF, argsT, auxilary )
 +
    -- Invocation of basic language template
 +
    --    argsF    -- table, with #invoke parameters, or false
 +
    --    argsT    -- table, with template parameters
 +
    --    auxilary  -- Multilingual library, or false
 +
    -- Returns appropriate string
 +
    local r
 +
    if type( auxilary ) == "table" then
 +
        Config.Multilingual = auxilary
 +
    else
 +
        r = Fetch( "Multilingual" )
 +
    end
 +
    if Config.Multilingual then
 +
        local slang = argsT[ 1 ]
 +
        local show  = argsT[ 2 ]
 +
        if slang then
 +
            slang = mw.text.trim( slang )
 +
            if slang == "" then
 +
                slang = false
 +
            end
 +
        end
 +
        if show then
 +
            show = flatten( show )
 +
        end
 +
        if slang and show then
 +
            local q = Config.Multilingual.getLang( slang )
 +
            if q and q.legal then
 +
                Config.lenient  = faculty( argsT.lenient )
 +
                Config.low      = true
 +
                Config.slang    = q.base
 +
                Config.state    = q.region
 +
                Config.scripting = q.script
 +
                r = furnish( argsF, argsT )
 +
            else
 +
                local e = mw.html.create( "span" )
 +
                                :attr( "lang", slang )
 +
                                :wikitext( show )
 +
                local list = ( q and q.scream )
 +
                local s
 +
                if q and q.suggest then
 +
                    local say = factory( "errSuggest" )
 +
                    s = string.format( say, slang, q.suggest )
 +
                else
 +
                    s = slang
 +
                end
 +
                r = tostring( e ) ..
 +
                    fault( "errInvalid",  s,  not list )
 +
                if list then
 +
                    r = string.format( "%s[[Category:%s]]", r, q.scream )
 +
                end
 +
            end
 +
        else
 +
            r = fault( "errMissing", false, true )
 +
            if show then
 +
                r = show .. r
 +
            end
 +
        end
 +
    end
 +
    return r
 +
end -- Export.flat()
 +
 +
 +
 +
Export.fold = function ( argsF, argsT )
 +
    -- Invocation of RTL template
 +
    --    argsF  -- table, with #invoke parameters, or false
 +
    --    argsT  -- table, with template parameters
 +
    -- Returns appropriate string, or nil
 +
    local params = { }
 +
    local r, s, slang
 +
    for k, v in pairs( argsT ) do
 +
        if v then
 +
            v = mw.text.trim( v )
 +
            if v ~= "" then
 +
                params[ k ] = v
 +
            end
 +
        end
 +
    end -- for k, v
 +
    if params[ 2 ] then
 +
        s = params[ 2 ]:gsub( mw.ustring.char( 0x202A ), "" )
 +
                      :gsub( mw.ustring.char( 0x202B ), "" )
 +
                      :gsub( mw.ustring.char( 0x202C ), "" )
 +
                      :gsub( mw.ustring.char( 0x202D ), "" )
 +
                      :gsub( mw.ustring.char( 0x202E ), "" )
 +
                      :gsub( mw.ustring.char( 0x2066 ), "" )
 +
                      :gsub( mw.ustring.char( 0x2067 ), "" )
 +
                      :gsub( mw.ustring.char( 0x2068 ), "" )
 +
                      :gsub( mw.ustring.char( 0x2069 ), "" )
 +
                      :gsub( mw.ustring.char( 8206 ), "&lrm;" )
 +
                      :gsub( "&#0*8206;",            "&lrm;" )
 +
                      :gsub( "&#x0*200[Ee];",        "&lrm;" )
 +
                      :gsub( mw.ustring.char( 8207 ), "&rlm;" )
 +
                      :gsub( "&#0*8207;",            "&rlm;" )
 +
                      :gsub( "&#x0*200[Ff];",        "&rlm;" )
 +
        if s:find( "&", 1, true ) then
 +
            local shift = "^&rlm;%s*"
 +
            while s:match( shift ) do
 +
                s = s:gsub( shift, "" )
 +
            end -- while
 +
            shift = "%s*&lrm;$"
 +
            while s:match( shift ) do
 +
                s = s:gsub( shift, "" )
 +
            end -- while
 +
            if s == "" then
 +
                s = false
 +
            end
 +
        end
 +
    end
 +
    if s  and
 +
      s:sub( 1, 5 ) == "<bdo "  and
 +
      s:find( "^<bdo [^<>]+><bdi [^<>]+>[^<>]+</bdi></bdo>$" ) then
 +
        r = s
 +
        s = false
 +
    end
 +
    if s then
 +
        local bdi    = mw.html.create( "bdi" )
 +
                              :attr( "dir", "rtl" )
 +
                              :css( "unicode-bidi", "isolate" )
 +
                              :wikitext( s )
 +
        local bdo    = mw.html.create( "bdo" )
 +
                              :attr( "dir", "ltr" )
 +
        local slang  = params[ 1 ]
 +
        local script = argsF.SCRIPTING
 +
        local state  = argsF.STATE
 +
        local selector
 +
        family()
 +
        if slang then
 +
            if slang:find( "-", 3, true ) then
 +
                local parts = mw.text.split( slang, "-", true )
 +
                slang = parts[ 1 ]
 +
                for i = 2, #parts do
 +
                    if parts[ i ]:match( "^%u%u$" ) then
 +
                        state = parts[ i ]
 +
                    elseif parts[ i ]:match( "^%u%l%l%l$" ) then
 +
                        script = parts[ i ]
 +
                    end
 +
                end -- for i
 +
            end
 +
            slang = slang:lower()
 +
        else
 +
            slang = "ar"
 +
        end
 +
        if script then
 +
            first( script, bdo )
 +
            features( bdi, script )
 +
            selector = script
 +
            if type( Config.classScript ) == "table" then
 +
                selector = flag( selector, Config.classScript[ script ] )
 +
            end
 +
            s = string.format( "%s-%s", slang, script )
 +
        else
 +
            s = slang
 +
        end
 +
        if state then
 +
            s = string.format( "%s-%s", s, state )
 +
        end
 +
        bdi:attr( "lang", s )
 +
        selector = flag( selector, argsF.class )
 +
        selector = flag( selector, params.class )
 +
        if selector then
 +
            bdi:addClass( selector )
 +
        end
 +
        if argsF.css then
 +
            bdi:css( argsF.css )
 +
        end
 +
        if argsF.style then
 +
            bdi:cssText( argsF.style )
 +
        end
 +
        if params.style then
 +
            bdi:cssText( params.style )
 +
        end
 +
        bdo:node( bdi )
 +
        r = tostring( bdo )
 +
    end
 +
    return r
 +
end -- Export.fold()
 +
 +
 +
 +
Export.format = function ( alien, apply, appear, audio, alike )
 +
    -- Markup foreign language text
 +
    --    alien  -- string, with language code
 +
    --    apply  -- string, with text
 +
    --    appear  -- string, with additional CSS, or nil
 +
    --    audio  -- string, with title of an audio file, or nil
 +
    --    alike  -- string, with additional class(es), or nil
 +
    -- Returns appropriate string with HTML tag
 +
    local ltr = true
 +
    local r, script, selector, slang, state
 +
    family()
 +
    if alien:find( "-", 3, true ) then
 +
        local parts = mw.text.split( alien, "-", true )
 +
        slang = parts[ 1 ]
 +
        for i = 2, #parts do
 +
            if parts[ i ]:match( "^%u%u$" ) then
 +
                state = parts[ i ]
 +
            elseif parts[ i ]:match( "^%u%l%l%l$" ) then
 +
                script = parts[ i ]
 +
            end
 +
        end -- for i
 +
    else
 +
        slang = alien
 +
    end
 +
    slang = slang:lower()
 +
    if not script then
 +
        script = fit( slang )
 +
    end
 +
    if script then
 +
        local rtl = Friend().rtl
 +
        if type( rtl ) == "table" then
 +
            ltr = not rtl[ script ]
 +
        end
 +
        if script ~= Config.site then
 +
            selector = script
 +
            if type( Config.classScript ) == "table" then
 +
                selector = flag( selector, Config.classScript[ script ] )
 +
            end
 +
        end
 +
    end
 +
    selector = flag( selector, alike )
 +
    if ltr then
 +
        local scope = Config.scope or "span"
 +
        local elem = mw.html.create( scope )
 +
        local story = apply
 +
        local set
 +
        if script then
 +
            set = string.format( "%s-%s", slang, script )
 +
            features( elem, script )
 +
        else
 +
            set = slang
 +
        end
 +
        if state then
 +
            set = string.format( "%s-%s", set, state )
 +
        end
 +
        elem:attr( "lang", set )
 +
        if selector then
 +
            elem:addClass( selector )
 +
        end
 +
        if appear then
 +
            elem:cssText( appear )
 +
        end
 +
        if scope == "span" then
 +
            story = story:gsub( "\n", " " )
 +
        end
 +
        elem:wikitext( story )
 +
        r = tostring( elem )
 +
        if script  and  script ~= Config.site then
 +
            local lucky, x = pcall( require,
 +
                                    "Module:Vorlage:lang/Zwiebelfisch" )
 +
            r = first( script ) .. r
 +
            if type( x ) == "table"  and
 +
              type( x.finder ) == "function" then
 +
                x = x.finder( apply, script )
 +
                if type( x ) == "string" then
 +
                    r = r .. x
 +
                end
 +
            end
 +
        end
 +
    else
 +
        r = Export.fold( { SCRIPTING = script },
 +
                        { [ 1 ] = slang,
 +
                          [ 2 ] = apply,
 +
                          class = selector,
 +
                          style = appear } )
 +
    end
 +
    if mw.text.unstrip( apply ):sub( 1, 1 ) == "<" then
 +
        local seek = "^(<([sd][paniv]+) [^>]+>)%1(.+)(</%2>)%4$"
 +
        local s, start, story, stop
 +
        start, s, story, stop = mw.text.unstrip( r ):match( seek )
 +
        if story then
 +
            r = Export.format( slang, story, appear, audio, alike )
 +
        end
 +
    end
 +
    if audio and Config.tmplAudio then
 +
        local params = { [ Config.tmplAudio.filepar ] = audio,
 +
                        [ Config.tmplAudio.textpar ] = r }
 +
        r = Frame():expandTemplate{ title = Config.tmplAudio.title,
 +
                                    args  = params }
 +
    end
 +
    return r or ""
 +
end -- Export.format()
 +
 +
 +
 +
Export.full = function ( argsF, argsT )
 +
    -- Invocation of language name template
 +
    --    argsF  -- table, with #invoke parameters, or false
 +
    --    argsT  -- table, with template parameters
 +
    -- Returns appropriate string
 +
    if argsF then
 +
        Config.lenient  = faculty( argsF.lenient )
 +
        Config.long      = faculty( argsF.LONG )
 +
        Config.scripting = argsF.SCRIPTING
 +
        Config.service  = argsF.SERVICE
 +
        Config.slang    = argsF.CODE
 +
        Config.sole      = argsF.SOLE
 +
        if argsF["OBSOLETING-bwd"] then
 +
            table.insert( Config.params, "b" )
 +
            table.insert( Config.params, "d" )
 +
            table.insert( Config.params, "w" )
 +
        end
 +
    end
 +
    Config.low = false
 +
    return furnish( argsF, argsT )
 
end -- Export.full()
 
end -- Export.full()
 +
 +
 +
 +
Failsafe.failsafe = function ( atleast )
 +
    -- Retrieve versioning and check for compliance
 +
    -- Precondition:
 +
    --    atleast  -- string, with required version or "wikidata" or "~"
 +
    --                or false
 +
    -- Postcondition:
 +
    --    Returns  string  -- with queried version, also if problem
 +
    --              false  -- if appropriate
 +
    local last  = ( atleast == "~" )
 +
    local since = atleast
 +
    local r
 +
    if last  or  since == "wikidata" then
 +
        local item = Failsafe.item
 +
        since = false
 +
        if type( item ) == "number"  and  item > 0 then
 +
            local entity = mw.wikibase.getEntity( string.format( "Q%d",
 +
                                                                item ) )
 +
            if type( entity ) == "table" then
 +
                local vsn = entity:formatPropertyValues( "P348" )
 +
                if type( vsn ) == "table"  and
 +
                  type( vsn.value ) == "string"  and
 +
                  vsn.value ~= "" then
 +
                    if last  and  vsn.value == Failsafe.serial then
 +
                        r = false
 +
                    else
 +
                        r = vsn.value
 +
                    end
 +
                end
 +
            end
 +
        end
 +
    end
 +
    if type( r ) == "nil" then
 +
        if not since  or  since <= Failsafe.serial then
 +
            r = Failsafe.serial
 +
        else
 +
            r = false
 +
        end
 +
    end
 +
    return r
 +
end -- Failsafe.failsafe()
  
  
Zeile 539: Zeile 1.434:
 
-- Export
 
-- Export
 
local p = { }
 
local p = { }
 
  
  
 
p.test = function ( action, argsF, argsT )
 
p.test = function ( action, argsF, argsT )
     --    action  -- string, "flat" or "full"
+
     --    action  -- string, "flat" or "full" etc.
 
     --    argsF  -- table, with #invoke parameters, or false
 
     --    argsF  -- table, with #invoke parameters, or false
 
     --    argsT  -- table, with template parameters
 
     --    argsT  -- table, with template parameters
     local r
+
     return frontend( action, argsF, argsT )
    if action == "flat" then
 
        r = flat( argsF, argsT )
 
    elseif action == "full" then
 
        r = Export.full( argsF, argsT )
 
    end
 
    return r
 
 
end -- p.test()
 
end -- p.test()
 
  
  
 
p.flat = function ( frame )
 
p.flat = function ( frame )
     return flat( frame.args, frame:getParent().args )
+
     return frontier( frame, "flat" )
 
end -- p.flat()
 
end -- p.flat()
  
 +
 +
p.fold = function ( frame )
 +
    return frontier( frame, "fold" )  or  ""
 +
end -- p.fold()
  
  
 
p.full = function ( frame )
 
p.full = function ( frame )
     local lucky, r
+
     return frontier( frame, "full" )
    Config.frame = frame
 
    lucky, r = pcall( Export.full, frame.args, frame:getParent().args )
 
    if not lucky then
 
        r = string.format( "<span class=\"error\">%s * %s</span>",
 
                          frame:getTitle(), r )
 
    end
 
    return r
 
 
end -- p.full()
 
end -- p.full()
  
Zeile 577: Zeile 1.461:
  
 
p.failsafe = function ( frame )
 
p.failsafe = function ( frame )
     local since = frame.args[ 1 ]
+
    -- Versioning interface
 +
    local s = type( frame )
 +
     local since
 +
    if s == "table" then
 +
        since = frame.args[ 1 ]
 +
    elseif s == "string" then
 +
        since = frame
 +
    end
 
     if since then
 
     if since then
 
         since = mw.text.trim( since )
 
         since = mw.text.trim( since )
Zeile 584: Zeile 1.475:
 
         end
 
         end
 
     end
 
     end
     return Export.failsafe( since )  or  ""
+
     return Failsafe.failsafe( since )  or  ""
end -- p.failsafe()
+
end -- p.failsafe
  
  

Aktuelle Version vom 31. Dezember 2019, 15:02 Uhr

Die Dokumentation für dieses Modul kann unter Modul:Vorlage:lang/Doku erstellt werden

local Export = { serial = "2019-10-19",
                 suite  = "lang",
                 item   = 26826825 }
--[=[
Vorlage:lang und Sprachnamenvorlagen usw. unterstützen
]=]
local Failsafe  = Export
local GlobalMod = Export



local Config = {
   errCat        = false,
   errClass      = "error_lang",
   errClasses    = false,
   errHide       = true,
   errNS         = false,
   errDoubled    = { en = "Doubled:",
                     de = "Doppelangabe:" },
   errEmpty      = { en = "Empty parameter value",
                     de = "Parameterwert fehlt" },
   errInvalid    = { en = "Invalid:",
                     de = "Ungültig:" },
   errMissing    = { en = "Missing parameter",
                     de = "Parameter fehlt" },
   errSuggest    = { en = "'%s' * probably '%s' intended",
                     de = "'%s' * vermutlich ist '%s' gemeint" },
   errUnkown     = { en = "Unkown parameter:",
                     de = "Parameter unbekannt:" },
   ipa           = "IPA",
   keyBase       = 100,
   keyProject    = 200,
   keyAncient    = 300,
   keyTranslate  = 400,
   params        = { "Text1",
                     "Audio",
                     "IPA",
                     "class",
                     "lenient",
                     "script",
                     "style",
                     "nachgestellt",
                     "demo",
                     "demo2",
                     "demo3",
                     "demo4",
                     "NoCat" },
   percents      = false,
   orderOther    = { grc = 1,
                     hbo = 2,
                     la  = 3,
                     en  = 9 },
   owns          = { de = "&#8218;%s&#8216;" },
   sepComma      = "Latn Armn Cyrl Grek Thai",
   site          = "Latn",
   tmplAudio     = false,    -- template for media player link
   tmplLang      = false,    -- template for language name link
   tmplStyles    = false,
   wikidata      = { Multilingual       = 47541920,
                     ISO15924           = 71584769,
                     ["ISO15924/codes"] = 71840276,
                     TemplUtl           = 52364930 }
}



local foreignModule = function ( access, advanced, append, alt, alert )
    -- Fetch global module
    -- Precondition:
    --     access    -- string, with name of base module
    --     advanced  -- true, for require(); else mw.loadData()
    --     append    -- string, with subpage part, if any; or false
    --     alt       -- number, of wikidata item of root; or false
    --     alert     -- true, for throwing error on data problem
    -- Postcondition:
    --     Returns whatever, probably table
    -- 2019-10-29
    local storage = access
    local finer = function ()
                      if append then
                          storage = string.format( "%s/%s",
                                                   storage,
                                                   append )
                      end
                  end
    local fun, lucky, r, suited
    if advanced then
        fun = require
    else
        fun = mw.loadData
    end
    GlobalMod.globalModules = GlobalMod.globalModules or { }
    suited = GlobalMod.globalModules[ access ]
    if not suited then
        finer()
        lucky, r = pcall( fun,  "Module:" .. storage )
    end
    if not lucky then
        if not suited  and
           type( alt ) == "number"  and
           alt > 0 then
            suited = string.format( "Q%d", alt )
            if mw.wikibase then
              suited = mw.wikibase.getSitelink( suited )
            end
            GlobalMod.globalModules[ access ] = suited or true
        end
        if type( suited ) == "string" then
            storage = suited
            finer()
            lucky, r = pcall( fun, storage )
        end
        if not lucky and alert then
            error( "Missing or invalid page: " .. storage, 0 )
        end
    end
    return r
end -- foreignModule()



local function Fetch( ask )
    -- Fetch module (require)
    -- Parameter:
    --     ask  -- string, with name
    --                     "ISO15924"
    --                     "Multilingual"
    --                     "TemplUtl"
    -- Returns string, with error message, if not available
    local ext = Config[ ask ]
    local r
    if not ext  and  ext ~= false then
        ext = foreignModule( ask,
                             true,
                             false,
                             Config.wikidata[ ask ] )
        if type( ext ) == "table" then
            Config[ ask ] = ext
            if type( ext[ ask ] ) == "function" then
                Config[ ask ] = ext[ ask ]()
            end
        end
        if type( Config[ ask ] ) ~= "table" then
            Config[ ask ] = false
            if not ext then
                ext = "Invalid library *** Module:" .. ask
            end
            ext = mw.html.create( "span" )
                         :attr( "class", "error" )
                         :wikitext( ext )
            r = tostring( ext )
        end
    end
    return r
end -- Fetch()



local function Frame()
    -- Fetch current frame
    -- Returns frame
    if not Config.frame then
        Config.frame = mw.getCurrentFrame()
    end
    return Config.frame
end -- Frame()



local function Friend()
    -- Fetch Module:ISO15924/codes
    if not Config.codesISO15924 then
        Config.codesISO15924 = foreignModule( "ISO15924",
                                              false,
                                              "codes",
                                              Config.wikidata.ISO15924 )
        if type( Config.codesISO15924 ) ~= "table" then
            Config.codesISO15924 = { }
        end
    end
    return Config.codesISO15924
end -- Friend()



local function Fulfil( access, args )
    -- Expand template
    --     apply  -- string, with template name
    --     args   -- table, with parameters
    -- Returns string
    -- Throws error, if template not existing
    return Frame():expandTemplate{ title = access,
                                   args  = args }
end -- Fulfil()



local function facet( assign )
    -- Format language name
    --     apply  -- string, with language name, might be linked
    -- Returns string
    local e = mw.html.create( "span" )
                     :css( { ["font-style"]  = "normal",
                             ["font-weight"] = "normal" } )
                     :wikitext( assign )
    return tostring( e )
end -- facet()



local function facility()
    -- Fetch current site language
    -- Returns language code
    if not Config.standard then
        Config.standard = mw.language.getContentLanguage():getCode()
    end
    return Config.standard
end -- facility()



local function factory( apply )
    -- Localization of messages
    --     apply  -- string, with message key
    -- Returns message text; at least english
    local entry = Config[ apply ]
    local r
    if entry then
        r = entry[ facility() ]
        if not r then
            r = entry.en
        end
    else
        local e = mw.html.create( "span" )
                         :attr( "class", "error" )
                         :wikitext( string.format( "????.%s.????",
                                                   apply ) )
        r = tostring( e )
    end
    return r
end -- factory()



local function faculty( adjust )
    -- Test template arg for boolean
    --     adjust  -- string or nil
    -- Returns boolean
    local s = type( adjust )
    local r
    if s == "string" then
        r = mw.text.trim( adjust )
        r = ( r ~= ""  and  r ~= "0"  and  r ~= "-" )
    elseif s == "boolean" then
        r = adjust
    else
        r = false
    end
    return r
end -- faculty()



local function familiar( ask, assign )
    -- Check whether valid transcription for context
    --     ask     -- string, with transcription code
    --     assign  -- string or nil, with language or scripting key
    -- Returns boolean
    local r
    Fetch( "ISO15924" )
    if Config.ISO15924 then
        r = Config.ISO15924.isTrans( ask, assign, Config.site )
    end
    return r
end -- familiar()



local function family()
    -- attempt to load local config
    if not Config.data then
        local sub = string.format( "%s/config", Frame():getTitle() )
        local lucky
        lucky, Config.data = pcall( mw.loadData, sub )
        if type( Config.data ) == "table" then
            for k, v in pairs( Config.data ) do
                Config[ k ] = v
            end -- for k, v
        else
            Config.data = sub .. " not found"
        end
    end
end -- family()



local function fault( alert, about, assign )
    -- Format message with class="error" or similar
    --     alert   -- string, with message key
    --     about   -- string, with explanation
    --     assign  -- true, when standard category to be fired
    -- Returns message with markup
    local story = factory( alert )
    local env   = Frame():getParent()
    local err   = mw.html.create( "span" )
    local r
    err:addClass( Config.errClass )
       :css( { ["margin-left"]  = "1em",
               ["margin-right"] = "1em" } )
    family()
    if env then
        story = string.format( "[[%s]] &#8211; %s",
                               env:getTitle(), story )
    end
    if about then
        story = string.format( "%s %s", story, about )
    end
    if Config.errClasses then
        err:addClass( Config.errClasses )
    end
    err:wikitext( story )
    r = Fetch( "TemplUtl" )
    if Config.TemplUtl then
        r = Config.TemplUtl.failure( tostring( err ),
                                     not Config.errHide,
                                     false,
                                     Frame() )
    end
    if assign  and  type( Config.errCat ) == "string" then
        if Config.errNS then
            local ns = mw.title.getCurrentTitle().namespace
            local st = type( Config.errNS )
            if st == "string" then
                local space  = string.format( ".*%%s%d%%s.*", ns )
                local spaces = string.format( " %s ", Config.errNS )
                if spaces:match( space ) then
                    Config.errNS = false
                end
            elseif st == "table" then
                for i = 1, #Config.errNS do
                    if Config.errNS[ i ] == ns then
                        Config.errNS = false
                        break    -- for i
                    end
                end -- for i
            end
        end
        if not Config.errNS then
            r = string.format( "%s[[Category:%s]]", r, Config.errCat )
        end
    end
    return r
end -- fault()



local function features( apply, assign )
    -- Equip element with script attributes
    --     apply   -- mw.html element
    --     assign  -- string, with script code
    if type( Config.percents ) == "table" then
        local more = Config.percents[ assign ]
        if more then
            apply:css( "font-size",  string.format( "%d%%", more ) )
        end
    end
end -- features()



local function fill( apply )
    -- Expand language name template
    --     apply   -- string, with code
    -- Returns string, identical apply in case of error
    local r = apply
    local template
    family()
    template = Config.tmplLang
    if type( template ) == "table" then
        local source = template.title
        if type( source ) ~= "string" then
            if type( template.namePat ) == "string"  and
               template.namePat:find( "%s", 1, true ) then
                source = string.format( template.namePat, apply )
            end
        end
        if type( source ) == "string" then
            local lucky, s = pcall( Fulfil, source )
            if lucky then
                r = s
            end
        end
    end
    return r
end -- fill()



local function first( assign, apply )
    -- Equip element with TemplateStyles
    --     assign  -- string, with script code
    --     apply   -- mw.html element, or false
    -- Returns string, perhaps with tag
    local r
    if type( Config.tmplStyles ) == "table" then
        local source = Config.tmplStyles[ assign ]
        if source then
            r = Frame():extensionTag( "templatestyles",
                                      nil,
                                      { src = source } )
            if apply then
                apply:wikitext( r )
            end
        end
    end
    return r or ""
end -- first()



local function fit( acquire )
    -- Retrieve script code for language
    --     acquire  -- string, with language code
    -- Returns string or false
    local r
    local iso639script = Friend().iso639script
    if type( iso639script ) == "table" then
        r = iso639script[ acquire ]
        if type( r ) == "table" then
            r = r[ 1 ]
        end
    end
    return r
end -- fit()



local function flag( already, apply )
    -- Check whether space separated classes contain
    --     already  -- string or false, with classes
    --     apply    -- string or false, with single class
    -- Returns true, if apply is in already
    local r
    if already then
        if apply then
            local classes = mw.text.split( already, "%s+" )
            local plus    = mw.text.split( apply, "%s+" )
            local single
            for i = 1, #plus do
                single = plus[ i ]
                for k = 1, #classes do
                    if classes[ k ] == single then
                        single = false
                        break -- for k
                    end
                end -- for k
                if single then
                    table.insert( classes, single )
                end
            end -- for i
            r = table.concat( classes, " " )
        else
            r = already
        end
    else
        r = apply
    end
    return r
end -- flag()



local function flatten( apply )
    -- Trim any whitespace, even HTML encoded
    --     apply   -- string
    -- Returns string, or false if empty
    local r = apply
    if r:find( "&" ) then
        r = r:gsub( "&nbsp;",    "&#160;" )
             :gsub( "&thinsp;", "&#8201;" )
             :gsub( "&zwnj;",   "&#8204;" )
             :gsub( "&zwj;",    "&#8205;" )
             :gsub( "&lrm;",    "&#8206;" )
             :gsub( "&rlm;",    "&#8207;" )
        if r:find( "&#" ) then
            local f = function ( ax, an )
                          local k
                          if ax == "x" then
                              k = 16
                          else
                              k = 10
                          end
                          return mw.ustring.char( tonumber( an, k ) )
                      end
            r = r:gsub( "&#(x?)(%x+);",  f )
        end
    end
    if not Config.patternWS then
        Config.patternWS = mw.ustring.char(   91,
                                               1, 45, 32,
                                             160,
                                            8194, 45, 8207,
                                            8239,
                                              93,
                                              43 )
    end
    r = mw.ustring.gsub( r,  "^" .. Config.patternWS,  "" )
    r = mw.ustring.gsub( r,  Config.patternWS .. "$",  "" )
    if r == "" then
        r = false
    end
    return r
end -- flatten()



local function follow( affine )
    -- Retrieve appropriate separator
    --     affine    -- string or nil, with code of script
    -- Returns string, with separator (comma) or not
    local r
    if affine then
        if Config.sepComma:find( affine, 1, true ) then
            r = ","
        else
            r = ""
        end
    else
        r = ","
    end
    return r
end -- follow()



local function foreign( apply, acquire, advanced, affine )
    -- Format text in some language
    --     apply     -- string, with text
    --     acquire   -- string, with basic code of language
    --     advanced  -- string, with full code of language
    --     affine    -- string or nil, with code of script
    -- Returns string
    local story  = apply
    local script = affine
    local p = { ["font-weight"] = "normal" }
    local ltr, r
    if advanced == acquire then
        ltr = not mw.language.new( acquire ):isRTL()
    elseif not script  and  advanced:find( "-", 3, true ) then
        local parts = mw.text.split( advanced, "-", true )
        if #parts > 1  and  parts[ 2 ]:match( "^%u%l%l%l$" ) then
            script = parts[ 2 ]
        end
    end
    if script then
        local rtl = Friend().rtl
        if type( rtl ) == "table" then
            ltr = not rtl[ script ]
        end
    end
    if ltr then
        local e = mw.html.create( "span" )
                         :attr( "lang", advanced )
        local s = "normal"
        if acquire == facility()
           and Config.owns[ acquire ]  then
            story = string.format( Config.owns[ acquire ], apply )
        elseif advanced == acquire  and  Config.site == "Latn"   or
               advanced == acquire .. "-Latn" then
            s = "italic"
        end
        p["font-style"] = s
        e:css( p )
         :wikitext( story )
        r = tostring( e )
    else
        p["font-style"] = "normal"
        r = Export.fold( { css       = p,
                           SCRIPTING = script },
                         { [ 1 ] = acquire,
                           [ 2 ] = apply,
                           lang  = advanced } )
    end
    return r
end -- foreign()



local function foreigns( ahead, aliens, alone )
    -- Create list of translations
    --     ahead   -- string, with leading separator
    --     aliens  -- sequence table, with assignment tables
    --     alone   -- boolean, no other elements in collection yet
    -- Returns string, starting with separator (comma)
    local pars = { }
    local sep  = ahead
    local lone = alone
    local r    = ""
    local k, lucky, s, t
    family()
    facility()
    Fetch( "Multilingual" )
    for i = 1, #aliens do
        t = aliens[ i ]
        if t.short == Config.standard then
            t.m = Config.keyProject
            t.n = 0
        else
            k = Config.orderOther[ t.short ]
            if k then
                t.n = k
                t.m = Config.keyAncient
            end
            lone = false
        end
        t.n = t.m + t.n
    end -- for i
    table.sort( aliens,
                function ( a1, a2 )
                    return ( a1.n < a2.n )
                end )
    for i = 1, #aliens do
        t = aliens[ i ]
        if lone then
            s   = ""
            sep = ""
        else
            s = false
            if t.short == Config.slang  and
               t.script  and
               t.n > 0 then
                Fetch( "ISO15924" )
                if Config.ISO15924 then
                    s = Config.ISO15924.scriptName( t.script )
                    if s == t.script then
                        s = false
                    end
                end
            end
            if not s  and  t.n > Config.keyProject then
                s = fill( t.short )
            end
            if not s then
                Fetch( "Multilingual" )
                s = mw.language.fetchLanguageName( t.short,
                                                   Config.standard )
                if Config.Multilingual  and
                   Config.Multilingual.isMinusculable( s ) then
                    s = mw.ustring.lower( mw.ustring.sub( s, 1, 1 ) )
                        .. mw.ustring.sub( s, 2 )
                end
            end
        end
        r   = string.format( "%s%s %s %s",
                             r,
                             sep,
                             s,
                             foreign( t.story,
                                      t.short,
                                      t.slang,
                                      t.script ) )
        sep = follow( t.script )
    end -- for i
    return r
end -- foreigns()



local function friend( assigned, apply )
    -- Transcription unit
    --     assigned  -- string, transcription ID
    --     apply     -- string, transcription text
    -- Returns string
    local e = mw.html.create( "span" )
                     :addClass( Config.site )
                     :attr( "lang",
                            string.format( "%s-%s",
                                           Config.slang,
                                           Config.site ) )
                     :css( { ["font-weight"] = "normal" } )
                     :wikitext( apply )
    local r, s
    if Config.site == "Latn" then
        s = "italic"
    else
        s = "normal"
    end
    e:css( { ["font-style"] = s } )
    if type( Config.transys ) == "table"  and
       type( Config.transys[ assigned ] ) == "table" then
        local transys = Config.transys[ assigned ]
        if transys.class then
            e:addClass( transys.class )
        end
        if transys.show then
            s = transys.show
        else
            s = assigned
        end
        if transys.support then
            if s == transys.support then
                s = string.format( "[[%s]]", s )
            else
                s = string.format( "[[%s|%s]]", transys.support, s )
            end
        end
    else
        s = assigned
    end
    r = string.format( "%s %s%s",
                       s,  first( Config.site ),  tostring( e ) )
    return r
end -- friend()



local function frontend( action, argsF, argsT, about )
    -- Template service
    --     action  -- string, "flat" or "full" etc.
    --     argsF   -- table, with #invoke parameters, or false
    --     argsT   -- table, with template parameters
    --     about   -- string or nil, invocation name
    -- Returns frame
    local lucky, r
    lucky, r = pcall( Export[ action ], argsF, argsT )
    if not lucky then
        local e = mw.html.create( "span" )
                         :attr( "class", "error" )
        if about then
            r = string.format( "&#123;{%s}&#125; %s",  about,  r )
        end
        e:wikitext( r )
        r = tostring( e )
    end
    return r
end -- frontend()



local function frontier( frame, action )
    -- Template transclusion
    --     frame   -- object
    --     action  -- string, "flat" or "full" etc.
    -- Returns appropriate string
    Config.frame = frame
    return frontend( action,
                     frame.args,
                     frame:getParent().args,
                     frame:getTitle() )
end -- frontier()



local function full( arglist )
    -- Finalize invocation of template
    --     arglist  -- table, with parameters
    -- Returns appropriate string
    local r
    if arglist.Text1 then
        local slang = Config.slang
        local lone  = true
        local s, sep
        if not Config.scripting then
            Config.scripting = fit( Config.slang )
        end
        sep = follow( Config.scripting )
        if Config.scripting == Config.site then
            if slang == facility() then
                arglist.style = false
            elseif not arglist.style then
                arglist.style = "font-style:italic"
            end
            sep = follow( Config.site )
            if arglist.Text2 then
                arglist.Text2 = fault( "errInvalid",
                                       Config.site .. "+2=",
                                       true )
            end
        elseif not Config.low  and  not arglist.style then
            arglist.style = "font-style:normal"
        end
        if Config.state then
            slang = string.format( "%s-%s", slang, Config.state )
        end
        if Config.scripting then
            slang = string.format( "%s-%s", slang, Config.scripting )
        end
        r = Export.format( slang,
                           arglist.Text1,
                           arglist.style,
                           arglist.Audio,
                           arglist.class )
        if arglist.Text2 then
            local e = mw.html.create( "span" )
                             :addClass( Config.site )
                             :attr( "lang",
                                    string.format( "%s-%s",
                                                   Config.slang,
                                                   Config.site ) )
                             :css( { ["font-weight"] = "normal" } )
                             :wikitext( arglist.Text2 )
                             if Config.site == "Latn" then
                                 s = "italic"
                             else
                                 s = "normal"
                             end
                             e:css( { ["font-style"] = s } )
            r    = string.format( "%s %s%s",
                                  r,
                                  first( Config.site ),
                                  tostring( e ) )
            sep  = follow( Config.site )
            lone = false
        end
        if arglist.trans then
            local e
            for i = 1, #arglist.trans do
                e   = arglist.trans[ i ]
                r   = string.format( "%s%s %s",
                                     r,
                                     sep,
                                     friend( e.system, e.story ) )
                sep = follow( Config.site )
            end   -- for i
            lone = false
        end
        if not Config.low then
            if Config.scripting then
                s = false
                if arglist[ Config.scripting ]  and
                   not arglist.Text2 then
                    Fetch( "ISO15924" )
                    if Config.ISO15924 then
                        s = Config.ISO15924
                                          .scriptName( Config.scripting )
                    end
                end
                if not s  and  Config.service then
                    s = facet( Config.service )
                end
            elseif Config.service then
                s = Config.service
            else
                s = false
            end
            if s then
                if arglist.later then
                    r    = string.format( "%s (%s)", r, s )
                    lone = false
                else
                    r = string.format( "%s %s", s, r )
                end
            end
        end
        if arglist.IPA then
            local params = { [1] = arglist.IPA }
            s    = Frame():expandTemplate{ title = Config.ipa,
                                           args  = params }
            r    = string.format( "%s [%s]", r, s )
            sep  = follow()
            lone = false
        end
        if arglist.trsl then
            r = r .. foreigns( sep, arglist.trsl, lone )
        end
    elseif arglist.Text2 then
        r = fault( "errInvalid", "|1=|2=", true )
    else
        if Config.sole then
            r = Config.sole
        else
            r = Config.service
        end
    end
    return r
end -- full()



local function furnish( argsF, argsT )
    -- General entry point; basic argument consumption
    --     argsF  -- table, with #invoke parameters, or false
    --     argsT  -- table, with template parameters
    -- Returns appropriate string
    local parIgnore = { }
    local r = { }
    local s
    if argsF then
        if argsF.errHide ~= nil then
            Config.errHide = faculty( argsF.errHide )
        end
        Config.errCat     = argsF.errCat
        Config.errClasses = argsF.errClasses
        Config.errNS      = argsF.errNS
        if argsF.ELEMENT and argsF.ELEMENT:match( "^%a+$" ) then
            Config.scope = argsF.ELEMENT:lower()
        end
        if argsF.SUITABLE then
            local params = mw.text.split( argsF.SUITABLE, " ", true )
            for k, v in pairs( params ) do
                parIgnore[ v ] = true
            end -- for k, v
        end
    end
    if Config.scripting == "" then
        Config.scripting = false
    end
    if Config.scripting then
        table.insert( Config.params, Config.scripting )
    end
    if type( argsT ) == "table" then
        local n = table.maxn( Config.params )
        local script, unknown
        for k, v in pairs( argsT ) do
            v = flatten( v )
            s = type( k )
            if s == "number" then
                if Config.low then
                    k = k - 1
                end
                if k <= 2 then
                    if v then
                        if k == 0 then
                            k = false
                        else
                            if k == 1 then
                                r.Text1 = v
                                k       = false
                            elseif Config.scripting == Config.site then
                                k = "2"
                            else
                                r.Text2 = v
                                k       = false
                            end
                        end
                    else
                        if not Config.lenient then
                            -- LEGACY
                            k = string.format( "%s %s, |%d=",
                                               "Sprachvorlage:",
                                               factory( "errEmpty" ),
                                               k )
                            mw.addWarning( k )
                        end
                        k = false
                    end
                else
                    k = tostring( k )
                end
            elseif parIgnore[ k ] then
                k = false
            elseif k:match( "^%l%l%l?%-?" ) then
                s = k:match( "^(%l%l%l?)$" )  or
                    k:match( "^(%l%l%l?)%-%u%u$" )  or
                    k:match( "^(%l%l%l?)%-%u%l%l%l$" )
                if v then
                    script = k:match( "^%l%l%l?%-(%u%l%l%l)$" )
                else
                    k = false
                end
                if v   and   s   and
                   ( s ~= Config.slang  or
                     script ~= Config.scripting ) then
                    local legal = mw.language.isSupportedLanguage( s )
                    if not legal then
                        legal = ( s ~= fill( s ) )
                    end
                    if legal then
                        local state = k:match( "^%l%l%l?%-(%u%u)$" )
                        local m
                        if s == Config.slang then
                            m = Config.keyBase
                        else
                            m = Config.keyTranslate
                        end
                        if not script then
                            script = fit( s )
                            if script then
                                k = string.format( "%s-%s", s, script )
                            end
                        end
                        if not r.trsl then
                            r.trsl = { }
                        end
                        table.insert( r.trsl,
                                      { m      = m,
                                        n      = #r.trsl + 1,
                                        script = script,
                                        short  = s,
                                        slang  = k,
                                        state  = state,
                                        story  = v } )
                        k = false
                    end
                end
            elseif k:match( "^%u%u+%d*%.?%d*%-?%u*%d*$" ) then
                if familiar( k, Config.scripting )  or
                   familiar( k, Config.slang ) then
                    if v then
                        if not r.trans then
                            r.trans = { }
                        end
                        table.insert( r.trans,
                                      { system = k,
                                        story  = v } )
                    end
                    k = false
                end
            elseif k:match( "^%u%l%l%l$" ) then
                if k == Config.scripting then
                    if faculty( v ) then
                        r[ k ] = true
                    end
                else
                    if not r.trsl then
                        r.trsl = { }
                    end
                    table.insert( r.trsl,
                                  { m      = 100,
                                    n      = #r.trsl + 1,
                                    script = k,
                                    short  = Config.slang,
                                    slang  = string.format( "%s-%s",
                                                            Config.slang,
                                                            k ),
                                    story  = v } )
                end
                k = false
            end
            if k then
                for i = 1, n do
                    if Config.params[ i ] == k then
                        if v then
                            r[ k ] = v
                        end
                        k = false
                        break -- for i
                    end
                end -- for i
            end
            if k then
                if not unknown then
                    unknown = { }
                end
                table.insert( unknown, k )
            end
        end -- for k, v
        if r.demo  or  faculty( r.NoCat ) then
            Config.errCat  = 0
            Config.errHide = false
        end
        r.later = faculty( r.nachgestellt )
        if r.b and Config[ "OBSOLETING-bwd" ] then
            if r.de then
                r = fault( "errDoubled", "'de=' und 'b='", true )
            else
                r.de = r.b
            end
        end
        if r.w and Config[ "OBSOLETING-bwd" ] then
            if r.Text2 then
                r = fault( "errDoubled", "'2=' und 'w='", true )
            else
                r.Text2 = r.w
            end
        end
        if unknown then
            local e = mw.html.create( "code" )
                             :wikitext( table.concat( unknown, " " ) )
            r = fault( "errUnkown",
                       string.format( "'%s'",  tostring( e ) ),
                       true )
        end
    end
    if type( r ) == "table" then
        r = full( r )
    end
    return r
end -- furnish()



Export.flat = function ( argsF, argsT, auxilary )
    -- Invocation of basic language template
    --     argsF     -- table, with #invoke parameters, or false
    --     argsT     -- table, with template parameters
    --     auxilary  -- Multilingual library, or false
    -- Returns appropriate string
    local r
    if type( auxilary ) == "table" then
        Config.Multilingual = auxilary
    else
        r = Fetch( "Multilingual" )
    end
    if Config.Multilingual then
        local slang = argsT[ 1 ]
        local show  = argsT[ 2 ]
        if slang then
            slang = mw.text.trim( slang )
            if slang == "" then
                slang = false
            end
        end
        if show then
            show = flatten( show )
        end
        if slang and show then
            local q = Config.Multilingual.getLang( slang )
            if q and q.legal then
                Config.lenient   = faculty( argsT.lenient )
                Config.low       = true
                Config.slang     = q.base
                Config.state     = q.region
                Config.scripting = q.script
                r = furnish( argsF, argsT )
            else
                local e = mw.html.create( "span" )
                                 :attr( "lang", slang )
                                 :wikitext( show )
                local list = ( q and q.scream )
                local s
                if q and q.suggest then
                    local say = factory( "errSuggest" )
                    s = string.format( say, slang, q.suggest )
                else
                    s = slang
                end
                r = tostring( e ) ..
                    fault( "errInvalid",  s,  not list )
                if list then
                    r = string.format( "%s[[Category:%s]]", r, q.scream )
                end
            end
        else
            r = fault( "errMissing", false, true )
            if show then
                r = show .. r
            end
        end
    end
    return r
end -- Export.flat()



Export.fold = function ( argsF, argsT )
    -- Invocation of RTL template
    --     argsF  -- table, with #invoke parameters, or false
    --     argsT  -- table, with template parameters
    -- Returns appropriate string, or nil
    local params = { }
    local r, s, slang
    for k, v in pairs( argsT ) do
        if v then
            v = mw.text.trim( v )
            if v ~= "" then
                params[ k ] = v
            end
        end
    end -- for k, v
    if params[ 2 ] then
        s = params[ 2 ]:gsub( mw.ustring.char( 0x202A ), "" )
                       :gsub( mw.ustring.char( 0x202B ), "" )
                       :gsub( mw.ustring.char( 0x202C ), "" )
                       :gsub( mw.ustring.char( 0x202D ), "" )
                       :gsub( mw.ustring.char( 0x202E ), "" )
                       :gsub( mw.ustring.char( 0x2066 ), "" )
                       :gsub( mw.ustring.char( 0x2067 ), "" )
                       :gsub( mw.ustring.char( 0x2068 ), "" )
                       :gsub( mw.ustring.char( 0x2069 ), "" )
                       :gsub( mw.ustring.char( 8206 ), "&lrm;" )
                       :gsub( "&#0*8206;",             "&lrm;" )
                       :gsub( "&#x0*200[Ee];",         "&lrm;" )
                       :gsub( mw.ustring.char( 8207 ), "&rlm;" )
                       :gsub( "&#0*8207;",             "&rlm;" )
                       :gsub( "&#x0*200[Ff];",         "&rlm;" )
        if s:find( "&", 1, true ) then
            local shift = "^&rlm;%s*"
            while s:match( shift ) do
                s = s:gsub( shift, "" )
            end -- while
            shift = "%s*&lrm;$"
            while s:match( shift ) do
                s = s:gsub( shift, "" )
            end -- while
            if s == "" then
                s = false
            end
        end
    end
    if s   and
       s:sub( 1, 5 ) == "<bdo "   and
       s:find( "^<bdo [^<>]+><bdi [^<>]+>[^<>]+</bdi></bdo>$" ) then
        r = s
        s = false
    end
    if s then
        local bdi    = mw.html.create( "bdi" )
                              :attr( "dir", "rtl" )
                              :css( "unicode-bidi", "isolate" )
                              :wikitext( s )
        local bdo    = mw.html.create( "bdo" )
                              :attr( "dir", "ltr" )
        local slang  = params[ 1 ]
        local script = argsF.SCRIPTING
        local state  = argsF.STATE
        local selector
        family()
        if slang then
            if slang:find( "-", 3, true ) then
                local parts = mw.text.split( slang, "-", true )
                slang = parts[ 1 ]
                for i = 2, #parts do
                    if parts[ i ]:match( "^%u%u$" ) then
                        state = parts[ i ]
                    elseif parts[ i ]:match( "^%u%l%l%l$" ) then
                        script = parts[ i ]
                    end
                end -- for i
            end
            slang = slang:lower()
        else
            slang = "ar"
        end
        if script then
            first( script, bdo )
            features( bdi, script )
            selector = script
            if type( Config.classScript ) == "table" then
                selector = flag( selector, Config.classScript[ script ] )
            end
            s = string.format( "%s-%s", slang, script )
        else
            s = slang
        end
        if state then
            s = string.format( "%s-%s", s, state )
        end
        bdi:attr( "lang", s )
        selector = flag( selector, argsF.class )
        selector = flag( selector, params.class )
        if selector then
            bdi:addClass( selector )
        end
        if argsF.css then
            bdi:css( argsF.css )
        end
        if argsF.style then
            bdi:cssText( argsF.style )
        end
        if params.style then
            bdi:cssText( params.style )
        end
        bdo:node( bdi )
        r = tostring( bdo )
    end
    return r
end -- Export.fold()



Export.format = function ( alien, apply, appear, audio, alike )
    -- Markup foreign language text
    --     alien   -- string, with language code
    --     apply   -- string, with text
    --     appear  -- string, with additional CSS, or nil
    --     audio   -- string, with title of an audio file, or nil
    --     alike   -- string, with additional class(es), or nil
    -- Returns appropriate string with HTML tag
    local ltr = true
    local r, script, selector, slang, state
    family()
    if alien:find( "-", 3, true ) then
        local parts = mw.text.split( alien, "-", true )
        slang = parts[ 1 ]
        for i = 2, #parts do
            if parts[ i ]:match( "^%u%u$" ) then
                state = parts[ i ]
            elseif parts[ i ]:match( "^%u%l%l%l$" ) then
                script = parts[ i ]
            end
        end -- for i
    else
        slang = alien
    end
    slang = slang:lower()
    if not script then
        script = fit( slang )
    end
    if script then
        local rtl = Friend().rtl
        if type( rtl ) == "table" then
            ltr = not rtl[ script ]
        end
        if script ~= Config.site then
            selector = script
            if type( Config.classScript ) == "table" then
                selector = flag( selector, Config.classScript[ script ] )
            end
        end
    end
    selector = flag( selector, alike )
    if ltr then
        local scope = Config.scope or "span"
        local elem = mw.html.create( scope )
        local story = apply
        local set
        if script then
            set = string.format( "%s-%s", slang, script )
            features( elem, script )
        else
            set = slang
        end
        if state then
            set = string.format( "%s-%s", set, state )
        end
        elem:attr( "lang", set )
        if selector then
            elem:addClass( selector )
        end
        if appear then
            elem:cssText( appear )
        end
        if scope == "span" then
            story = story:gsub( "\n", " " )
        end
        elem:wikitext( story )
        r = tostring( elem )
        if script  and  script ~= Config.site then
            local lucky, x = pcall( require,
                                    "Module:Vorlage:lang/Zwiebelfisch" )
            r = first( script ) .. r
            if type( x ) == "table"  and
               type( x.finder ) == "function" then
                x = x.finder( apply, script )
                if type( x ) == "string" then
                    r = r .. x
                end
            end
        end
    else
        r = Export.fold( { SCRIPTING = script },
                         { [ 1 ] = slang,
                           [ 2 ] = apply,
                           class = selector,
                           style = appear } )
    end
    if mw.text.unstrip( apply ):sub( 1, 1 ) == "<" then
        local seek = "^(<([sd][paniv]+) [^>]+>)%1(.+)(</%2>)%4$"
        local s, start, story, stop
        start, s, story, stop = mw.text.unstrip( r ):match( seek )
        if story then
            r = Export.format( slang, story, appear, audio, alike )
        end
    end
    if audio and Config.tmplAudio then
        local params = { [ Config.tmplAudio.filepar ] = audio,
                         [ Config.tmplAudio.textpar ] = r }
        r = Frame():expandTemplate{ title = Config.tmplAudio.title,
                                    args  = params }
    end
    return r or ""
end -- Export.format()



Export.full = function ( argsF, argsT )
    -- Invocation of language name template
    --     argsF  -- table, with #invoke parameters, or false
    --     argsT  -- table, with template parameters
    -- Returns appropriate string
    if argsF then
        Config.lenient   = faculty( argsF.lenient )
        Config.long      = faculty( argsF.LONG )
        Config.scripting = argsF.SCRIPTING
        Config.service   = argsF.SERVICE
        Config.slang     = argsF.CODE
        Config.sole      = argsF.SOLE
        if argsF["OBSOLETING-bwd"] then
            table.insert( Config.params, "b" )
            table.insert( Config.params, "d" )
            table.insert( Config.params, "w" )
        end
    end
    Config.low = false
    return furnish( argsF, argsT )
end -- Export.full()



Failsafe.failsafe = function ( atleast )
    -- Retrieve versioning and check for compliance
    -- Precondition:
    --     atleast  -- string, with required version or "wikidata" or "~"
    --                 or false
    -- Postcondition:
    --     Returns  string  -- with queried version, also if problem
    --              false   -- if appropriate
    local last  = ( atleast == "~" )
    local since = atleast
    local r
    if last  or  since == "wikidata" then
        local item = Failsafe.item
        since = false
        if type( item ) == "number"  and  item > 0 then
            local entity = mw.wikibase.getEntity( string.format( "Q%d",
                                                                 item ) )
            if type( entity ) == "table" then
                local vsn = entity:formatPropertyValues( "P348" )
                if type( vsn ) == "table"  and
                   type( vsn.value ) == "string"  and
                   vsn.value ~= "" then
                    if last  and  vsn.value == Failsafe.serial then
                        r = false
                    else
                        r = vsn.value
                    end
                end
            end
        end
    end
    if type( r ) == "nil" then
        if not since  or  since <= Failsafe.serial then
            r = Failsafe.serial
        else
            r = false
        end
    end
    return r
end -- Failsafe.failsafe()



-- Export
local p = { }


p.test = function ( action, argsF, argsT )
    --     action  -- string, "flat" or "full" etc.
    --     argsF   -- table, with #invoke parameters, or false
    --     argsT   -- table, with template parameters
    return frontend( action, argsF, argsT )
end -- p.test()


p.flat = function ( frame )
    return frontier( frame, "flat" )
end -- p.flat()


p.fold = function ( frame )
    return frontier( frame, "fold" )  or   ""
end -- p.fold()


p.full = function ( frame )
    return frontier( frame, "full" )
end -- p.full()



p.failsafe = function ( frame )
    -- Versioning interface
    local s = type( frame )
    local since
    if s == "table" then
        since = frame.args[ 1 ]
    elseif s == "string" then
        since = frame
    end
    if since then
        since = mw.text.trim( since )
        if since == "" then
            since = false
        end
    end
    return Failsafe.failsafe( since )  or  ""
end -- p.failsafe



p.lang = function ()
    return Export
end -- p.lang()

return p