Modul:Multilingual

aus Wikipedia, der freien Enzyklopädie
Zur Navigation springen Zur Suche springen

Diese Seite enthält Code in der Programmiersprache Lua. Einbindungszahl Cirrus

Dies ist die (produktive) Mutterversion eines global benutzten Lua-Moduls.
Wenn die serial-Information nicht übereinstimmt, müsste eine Kopie hiervon in das lokale Wiki geschrieben werden.
Versionsbezeichnung auf WikiData: 2025年03月05日

 local Multilingual = { suite = "Multilingual",
 serial = "2025年03月05日",
 item = 47541920,
 globals = { ISO15924 = 71584769,
 WLink = 19363224 }
 }
 --[=[
 Utilities for multilingual texts and ISO 639 (BCP47) issues etc.
 * fair()
 * fallback()
 * findCode()
 * fix()
 * format()
 * getArticle()
 * getBase()
 * getLang()
 * getName()
 * i18n()
 * int()
 * isLang()
 * isLangWiki()
 * isMinusculable()
 * isRTL()
 * linkArticle()
 * message()
 * sitelink()
 * tabData()
 * userLang()
 * userLangCode()
 * wikibase()
 * failsafe()
 loadData: Multilingual/config Multilingual/names
 loadJsonData: Module:Multilingual/articles.json
 ]=]
 local Failsafe = Multilingual
 local GlobalMod = Multilingual
 local GlobalData = Multilingual
 local User = { sniffer = "showpreview" }
 Multilingual.globals.Multilingual = Multilingual.item



 Multilingual.exotic = { simple = true,
 no = true }
 Multilingual.prefer = { cs = true,
 de = true,
 en = true,
 es = true,
 fr = true,
 it = true,
 nl = true,
 pt = true,
 ru = true,
 sv = true }
 Multilingual.support = "Module:Multilingual/articles.json"



 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
 -- 2020年01月01日
 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 )
 suited = mw.wikibase.getSitelink( suited )
 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 )
 end
 end
 return r
 end -- foreignModule()



 local fetchData = function ( access )
 -- Retrieve translated keyword from commons:Data:****.tab
 -- Precondition:
 -- access -- string, with page identification on Commons
 -- Returns table, with data, or string, with error message
 -- 2019年12月05日
 local storage = access
 local r
 if type( storage ) == "string" then
 local s
 storage = mw.text.trim( storage )
 s = storage:lower()
 if s:sub( 1, 2 ) == "c:" then
 storage = mw.text.trim( storage:sub( 3 ) )
 s = storage:lower()
 elseif s:sub( 1, 8 ) == "commons:" then
 storage = mw.text.trim( storage:sub( 9 ) )
 s = storage:lower()
 end
 if s:sub( 1, 5 ) == "data:" then
 storage = mw.text.trim( storage:sub( 6 ) )
 s = storage:lower()
 end
 if s == "" or s == ".tab" then
 storage = false
 elseif s:sub( -4 ) == ".tab" then
 storage = storage:sub( 1, -5 ) .. ".tab"
 else
 storage = storage .. ".tab"
 end
 end
 if type( storage ) == "string" then
 local data
 if type( GlobalData.TabDATA ) ~= "table" then
 GlobalData.TabDATA = { }
 end
 data = GlobalData.TabDATA[ storage ]
 if data then
 r = data
 else
 local lucky
 lucky, data = pcall( mw.ext.data.get, storage, "_" )
 if type( data ) == "table" then
 data = data.data
 if type( data ) == "table" then
 GlobalData.TabDATA[ storage ] = data
 else
 r = string.format( "%s [[%s%s]]",
 "INVALID Data:*.tab",
 "commons:Data:",
 storage )
 end
 else
 r = "BAD PAGE Data:*.tab – commons:" .. storage
 end
 if r then
 GlobalData.TabDATA[ storage ] = r
 data = false
 else
 r = data
 end
 end
 else
 r = "BAD PAGE commons:Data:*.tab"
 end
 return r
 end -- fetchData()



 local favorites = function ()
 -- Provide fallback codes
 -- Postcondition:
 -- Returns table with sequence of preferred languages
 -- * ahead elements
 -- * user (not yet accessible)
 -- * page content language (not yet accessible)
 -- * page name subpage
 -- * project
 -- * en
 local r = Multilingual.polyglott
 if not r then
 local self = mw.language.getContentLanguage():getCode():lower()
 local sub = mw.title.getCurrentTitle().subpageText
 local f = function ( add )
 local s = add
 for i = 1, #r do
 if r[ i ] == s then
 s = false
 break -- for i
 end
 end -- for i
 if s then
 table.insert( r, s )
 end
 end
 r = { }
 if sub:find( "/", 2, true ) then
 sub = sub:match( "/(%l%l%l?)$" )
 if sub then
 table.insert( r, sub )
 end
 elseif sub:find( "^%l%l%l?%-?%a?%a?%a?%a?$" ) and
 mw.language.isSupportedLanguage( sub ) then
 table.insert( r, sub )
 end
 f( self )
 f( "en" )
 Multilingual.polyglott = r
 end
 return r
 end -- favorites()



 local feasible = function ( ask, accept )
 -- Is ask to be supported by application?
 -- Precondition:
 -- ask -- lowercase code
 -- accept -- sequence table, with offered lowercase codes
 -- Postcondition:
 -- nil, or true
 local r
 for i = 1, #accept do
 if accept[ i ] == ask then
 r = true
 break -- for i
 end
 end -- for i
 return r
 end -- feasible()



 local fetch = function ( access, append )
 -- Attach config or library module
 -- Precondition:
 -- access -- module title
 -- append -- string, with subpage part of this; or false
 -- Postcondition:
 -- Returns: table, with library, or false
 local got, sign
 if append then
 sign = string.format( "%s/%s", access, append )
 else
 sign = access
 end
 if type( Multilingual.ext ) ~= "table" then
 Multilingual.ext = { }
 end
 got = Multilingual.ext[ sign ]
 if not got and got ~= false then
 local global = Multilingual.globals[ access ]
 local lib = not append
 got = foreignModule( access, lib, append, global )
 if type( got ) == "table" then
 if lib then
 local startup = got[ access ]
 if type( startup ) == "function" then
 got = startup()
 end
 end
 else
 got = false
 end
 Multilingual.ext[ sign ] = got
 end
 return got
 end -- fetch()



 local fetchISO639 = function ( access )
 -- Retrieve table from commons:Data:ISO639/***.tab
 -- Precondition:
 -- access -- string, with subpage identification
 -- Postcondition:
 -- Returns table, with data, even empty
 local r
 if type( Multilingual.iso639 ) ~= "table" then
 Multilingual.iso639 = { }
 end
 r = Multilingual.iso639[ access ]
 if type( r ) == "nil" then
 local raw = fetchData( "ISO639/" .. access )
 if type( raw ) == "table" then
 local t
 r = { }
 for i = 1, #raw do
 t = raw[ i ]
 if type( t ) == "table" and
 type( t[ 1 ] ) == "string" and
 type( t[ 2 ] ) == "string" then
 r[ t[ 1 ] ] = t[ 2 ]
 else
 break -- for i
 end
 end -- for i
 else
 r = false
 end
 Multilingual.iso639[ access ] = r
 end
 return r or { }
 end -- fetchISO639()



 local fill = function ( access, alien, frame )
 -- Expand language name template
 -- Precondition:
 -- access -- string, with language code
 -- alien -- language code for which to be generated
 -- frame -- frame, if available
 -- Postcondition:
 -- Returns string
 local template = Multilingual.tmplLang
 local r
 if type( template ) ~= "table" then
 local cnf = fetch( "Multilingual", "config" )
 if cnf then
 template = cnf.tmplLang
 end
 end
 if type( template ) == "table" then
 local source = template.title
 local f, lucky, s
 Multilingual.tmplLang = template
 if type( source ) ~= "string" and
 type( template.namePat ) == "string" and
 template.namePat:find( "%s", 1, true ) then
 source = string.format( template.namePat, access )
 end
 if type( source ) == "string" then
 if not Multilingual.frame then
 if frame then
 Multilingual.frame = frame
 else
 Multilingual.frame = mw.getCurrentFrame()
 end
 end
 f = function ( a )
 return Multilingual.frame:expandTemplate{ title = a }
 end
 lucky, s = pcall( f, source )
 if lucky then
 r = s
 end
 end
 end
 return r
 end -- fill()



 local find = function ( ask, alien )
 -- Derive language code from name
 -- Precondition:
 -- ask -- language name, downcased
 -- alien -- language code of ask
 -- Postcondition:
 -- nil, or string
 local codes = mw.language.fetchLanguageNames( alien, "all" )
 local r
 for k, v in pairs( codes ) do
 if mw.ustring.lower( v ) == ask then
 r = k
 break -- for k, v
 end
 end -- for k, v
 if not r then
 r = Multilingual.fair( ask )
 end
 return r
 end -- find()



 local fold = function ( frame )
 -- Merge template and #invoke arglist
 -- Precondition:
 -- frame -- template frame
 -- Postcondition:
 -- table, with combined arglist
 local r = { }
 local f = function ( apply )
 if type( apply ) == "table" and
 type( apply.args ) == "table" then
 for k, v in pairs( apply.args ) do
 v = mw.text.trim( v )
 if v ~= "" then
 r[ tostring( k ) ] = v
 end
 end -- for k, v
 end
 end -- f()
 f( frame:getParent() )
 f( frame )
 return r
 end -- fold()



 User.favorize = function ( accept, frame )
 -- Guess user language
 -- Precondition:
 -- accept -- sequence table, with offered ISO 639 etc. codes
 -- frame -- frame, if available
 -- Postcondition:
 -- Returns string with best code, or nil
 if not ( User.self or User.langs ) then
 if not User.trials then
 User.tell = mw.message.new( User.sniffer )
 if User.tell:exists() then
 User.trials = { }
 if not Multilingual.frame then
 if frame then
 Multilingual.frame = frame
 else
 Multilingual.frame = mw.getCurrentFrame()
 end
 end
 User.sin = Multilingual.frame:callParserFunction( "int",
 User.sniffer )
 else
 User.langs = true
 end
 end
 if User.sin then
 local order = { }
 local post = { }
 local three = { }
 local unfold = { }
 local s, sin
 for i = 1, #accept do
 s = accept[ i ]
 if not User.trials[ s ] then
 if #s > 2 then
 if s:find( "-", 3, true ) then
 table.insert( unfold, s )
 else
 table.insert( three, s )
 end
 else
 if Multilingual.prefer[ s ] then
 table.insert( order, s )
 else
 table.insert( post, s )
 end
 end
 end
 end -- for i
 for i = 1, #post do
 table.insert( order, post[ i ] )
 end -- for i
 for i = 1, #three do
 table.insert( order, three[ i ] )
 end -- for i
 for i = 1, #unfold do
 table.insert( order, unfold[ i ] )
 end -- for i
 for i = 1, #order do
 s = order[ i ]
 sin = User.tell:inLanguage( s ):plain()
 if sin == User.sin then
 User.self = s
 break -- for i
 else
 User.trials[ s ] = true
 end
 end -- for i
 end
 if not User.self then
 User.self = mw.language.getContentLanguage():getCode()
 :lower()
 end
 end
 return User.self
 end -- User.favorize()



 Multilingual.fair = function ( ask )
 -- Format language specification according to RFC 5646 etc.
 -- Precondition:
 -- ask -- string or table, as created by .getLang()
 -- Postcondition:
 -- Returns string, or false
 local s = type( ask )
 local q, r
 if s == "table" then
 q = ask
 elseif s == "string" then
 q = Multilingual.getLang( ask )
 end
 if q and
 q.legal and
 mw.language.isKnownLanguageTag( q.base ) then
 r = q.base
 if q.n > 1 then
 local order = { "extlang",
 "script",
 "region",
 "other",
 "extension" }
 for i = 1, #order do
 s = q[ order[ i ] ]
 if s then
 r = string.format( "%s-%s", r, s )
 end
 end -- for i
 end
 end
 return r or false
 end -- Multilingual.fair()



 Multilingual.fallback = function ( able, another )
 -- Is another language suitable as replacement?
 -- Precondition:
 -- able -- language version specifier to be supported
 -- another -- language specifier of a possible replacement,
 -- or not to retrieve a fallback table
 -- Postcondition:
 -- Returns boolean, or table with fallback codes
 local r
 if type( able ) == "string" and #able > 0 then
 if type( another ) == "string" and #another > 0 then
 if able == another then
 r = true
 else
 local s = Multilingual.getBase( able )
 if s == another then
 r = true
 else
 local others = mw.language.getFallbacksFor( s )
 r = feasible( another, others )
 end
 end
 else
 local s = Multilingual.getBase( able )
 if s then
 r = mw.language.getFallbacksFor( s )
 if r[ 1 ] == "en" then
 local d = fetchISO639( "fallback" )
 if type( d ) == "table" and
 type( d[ s ] ) == "string" then
 r = mw.text.split( d[ s ], "|" )
 table.insert( r, "en" )
 end
 end
 end
 end
 end
 return r or false
 end -- Multilingual.fallback()



 Multilingual.findCode = function ( ask )
 -- Retrieve code of local (current project or English) language name
 -- Precondition:
 -- ask -- string, with presumable language name
 -- A code itself will be identified, too.
 -- Postcondition:
 -- Returns string, or false
 local seek = mw.text.trim( ask )
 local r = false
 if #seek > 1 then
 if seek:find( "[", 1, true ) then
 local wlink = fetch( "WLink" )
 if wlink and
 type( wlink.getPlain ) == "function" then
 seek = wlink.getPlain( seek )
 end
 end
 seek = mw.ustring.lower( seek )
 if Multilingual.isLang( seek ) then
 r = Multilingual.fair( seek )
 else
 local collection = favorites()
 for i = 1, #collection do
 r = find( seek, collection[ i ] )
 if r then
 break -- for i
 end
 end -- for i
 end
 end
 return r
 end -- Multilingual.findCode()



 Multilingual.fix = function ( attempt )
 -- Fix frequently mistaken language code
 -- Precondition:
 -- attempt -- string, with presumable language code
 -- Postcondition:
 -- Returns string with correction, or false if no problem known
 local r = fetchISO639( "correction" )[ attempt:lower() ]
 return r or false
 end -- Multilingual.fix()



 Multilingual.format = function ( apply, alien, alter, active, alert,
 frame, assembly, adjacent, ahead )
 -- Format one or more languages
 -- Precondition:
 -- apply -- string with language list or item
 -- alien -- language of the answer
 -- -- nil, false, "*": native
 -- -- "!": current project
 -- -- "#": code, downcased, space separated
 -- -- "-": code, mixcase, space separated
 -- -- any valid code
 -- alter -- capitalize, if "c"; downcase all, if "d"
 -- capitalize first item only, if "f"
 -- downcase every first word only, if "m"
 -- active -- link items, if true
 -- alert -- string with category title in case of error
 -- frame -- if available
 -- assembly -- string with split pattern, if list expected
 -- adjacent -- string with list separator, else assembly
 -- ahead -- string to prepend first element, if any
 -- Postcondition:
 -- Returns string, or false if apply empty
 local r = false
 if apply then
 local slang
 if assembly then
 local bucket = mw.text.split( apply, assembly )
 local shift = alter
 local separator
 if adjacent then
 separator = adjacent
 elseif alien == "#" or alien == "-" then
 separator = " "
 else
 separator = assembly
 end
 for k, v in pairs( bucket ) do
 slang = Multilingual.format( v, alien, shift, active,
 alert )
 if slang then
 if r then
 r = string.format( "%s%s%s",
 r, separator, slang )
 else
 r = slang
 if shift == "f" then
 shift = "d"
 end
 end
 end
 end -- for k, v
 if r and ahead then
 r = ahead .. r
 end
 else
 local single = mw.text.trim( apply )
 if single == "" then
 r = false
 else
 local lapsus, slot
 slang = Multilingual.findCode( single )
 if slang then
 if alien == "-" then
 r = slang
 elseif alien == "#" then
 r = slang:lower()
 else
 r = Multilingual.getName( slang, alien )
 if active then
 slot = fill( slang, false, frame )
 if slot then
 local wlink = fetch( "WLink" )
 if wlink and
 type( wlink.getTarget )
 == "function" then
 slot = wlink.getTarget( slot )
 end
 else
 lapsus = alert
 end
 end
 end
 else
 r = single
 if active then
 local title = mw.title.makeTitle( 0, single )
 if title.exists then
 slot = single
 end
 end
 lapsus = alert
 end
 if not r then
 r = single
 elseif alter == "c" or alter == "f" then
 r = mw.ustring.upper( mw.ustring.sub( r, 1, 1 ) )
 .. mw.ustring.sub( r, 2 )
 elseif alter == "d" then
 if Multilingual.isMinusculable( slang, r ) then
 r = mw.ustring.lower( r )
 end
 elseif alter == "m" then
 if Multilingual.isMinusculable( slang, r ) then
 r = mw.ustring.lower( mw.ustring.sub( r, 1, 1 ) )
 .. mw.ustring.sub( r, 2 )
 end
 end
 if slot then
 if r == slot then
 r = string.format( "[[%s]]", r )
 else
 r = string.format( "[[%s|%s]]", slot, r )
 end
 end
 if lapsus and alert then
 r = string.format( "%s[[Category:%s]]", r, alert )
 end
 end
 end
 end
 return r
 end -- Multilingual.format()



 Multilingual.getArticle = function ( ask )
 -- Retrieve local article from BCP-47 language code
 -- Precondition:
 -- ask -- language code
 -- Postcondition:
 -- Returns string, with page name, or false
 local lucky, json
 local r
 lucky, json = pcall( mw.loadJsonData, Multilingual.support )
 if type( json ) == "table" and
 type( json.pages ) == "table" then
 if type( ask ) == "string" then
 local s = ask:lower()
 r = json.pages[ s ] or false
 else
 r = false
 end
 else
 r = "ERROR * bad page " .. Multilingual.support
 end
 return r
 end -- Multilingual.getArticle()



 Multilingual.getBase = function ( ask )
 -- Retrieve base language from possibly combined ISO language code
 -- Precondition:
 -- ask -- language code
 -- Postcondition:
 -- Returns string, or false
 local r
 if ask then
 local slang = ask:match( "^%s*(%a%a%a?)-?%a*%s*$" )
 if slang then
 r = slang:lower()
 else
 r = false
 end
 else
 r = false
 end
 return r
 end -- Multilingual.getBase()



 Multilingual.getLang = function ( ask )
 -- Retrieve components of a RFC 5646 language code
 -- Precondition:
 -- ask -- language code with subtags
 -- Postcondition:
 -- Returns table with formatted subtags
 -- .base
 -- .region
 -- .script
 -- .suggest
 -- .year
 -- .extension
 -- .other
 -- .n
 local tags = mw.text.split( ask, "-" )
 local s = tags[ 1 ]
 local r
 if s:match( "^%a%a%a?$" ) then
 r = { base = s:lower(),
 legal = true,
 n = #tags }
 for i = 2, r.n do
 s = tags[ i ]
 if #s == 2 then
 if r.region or not s:match( "%a%a" ) then
 r.legal = false
 else
 r.region = s:upper()
 end
 elseif #s == 4 then
 if s:match( "%a%a%a%a" ) then
 r.legal = ( not r.script )
 r.script = s:sub( 1, 1 ):upper() ..
 s:sub( 2 ):lower()
 elseif s:match( "20%d%d" ) or
 s:match( "1%d%d%d" ) then
 r.legal = ( not r.year )
 r.year = s
 else
 r.legal = false
 end
 elseif #s == 3 then
 if r.extlang or not s:match( "%a%a%a" ) then
 r.legal = false
 else
 r.extlang = s:lower()
 end
 elseif #s == 1 then
 s = s:lower()
 if s:match( "[tux]" ) then
 r.extension = s
 for k = i + 1, r.n do
 s = tags[ k ]
 if s:match( "^%w+$" ) then
 r.extension = string.format( "%s-%s",
 r.extension, s )
 else
 r.legal = false
 end
 end -- for k
 else
 r.legal = false
 end
 break -- for i
 else
 r.legal = ( not r.other ) and
 s:match( "%a%a%a" )
 r.other = s:lower()
 end
 if not r.legal then
 break -- for i
 end
 end -- for i
 if r.legal then
 r.suggest = Multilingual.fix( r.base )
 if r.suggest then
 r.legal = false
 end
 end
 else
 r = { legal = false }
 end
 if not r.legal then
 local cnf = fetch( "Multilingual", "config" )
 if cnf and type( cnf.scream ) == "string" then
 r.scream = cnf.scream
 end
 end
 return r
 end -- Multilingual.getLang()



 Multilingual.getName = function ( ask, alien )
 -- Which name is assigned to this language code?
 -- Precondition:
 -- ask -- language code
 -- alien -- language of the answer
 -- -- nil, false, "*": native
 -- -- "!": current project
 -- -- any valid code
 -- Postcondition:
 -- Returns string, or false
 local r
 if ask then
 local slang = alien
 local tLang
 if slang then
 if slang == "*" then
 slang = Multilingual.fair( ask )
 elseif slang == "!" then
 slang = favorites()[ 1 ]
 else
 slang = Multilingual.fair( slang )
 end
 else
 slang = Multilingual.fair( ask )
 end
 if not slang then
 slang = ask or "?????"
 end
 slang = slang:lower()
 tLang = fetch( "Multilingual", "names" )
 if tLang then
 tLang = tLang[ slang ]
 if tLang then
 r = tLang[ ask ]
 end
 end
 if not r then
 if not Multilingual.ext.tMW then
 Multilingual.ext.tMW = { }
 end
 tLang = Multilingual.ext.tMW[ slang ]
 if tLang == nil then
 tLang = mw.language.fetchLanguageNames( slang )
 if tLang then
 Multilingual.ext.tMW[ slang ] = tLang
 else
 Multilingual.ext.tMW[ slang ] = false
 end
 end
 if tLang then
 r = tLang[ ask ]
 end
 end
 if not r then
 r = mw.language.fetchLanguageName( ask:lower(), slang )
 if r == "" then
 r = false
 end
 end
 else
 r = false
 end
 return r
 end -- Multilingual.getName()



 Multilingual.i18n = function ( available, alt, frame )
 -- Select translatable message
 -- Precondition:
 -- available -- table, with mapping language code ./. text
 -- alt -- string|nil|false, with fallback text
 -- frame -- frame, if available
 -- Returns
 -- 1. string|nil|false, with selected message
 -- 2. string|nil|false, with language code
 local r1, r2
 if type( available ) == "table" then
 local codes = { }
 local trsl = { }
 local slang
 for k, v in pairs( available ) do
 if type( k ) == "string" and
 type( v ) == "string" then
 slang = mw.text.trim( k:lower() )
 table.insert( codes, slang )
 trsl[ slang ] = v
 end
 end -- for k, v
 slang = Multilingual.userLang( codes, frame )
 if slang and trsl[ slang ] then
 r1 = mw.text.trim( trsl[ slang ] )
 if r1 == "" then
 r1 = false
 else
 r2 = slang
 end
 end
 end
 if not r1 and type( alt ) == "string" then
 r1 = mw.text.trim( alt )
 if r1 == "" then
 r1 = false
 end
 end
 return r1, r2
 end -- Multilingual.i18n()



 Multilingual.int = function ( access, alien, apply )
 -- Translated system message
 -- Precondition:
 -- access -- message ID
 -- alien -- language code
 -- apply -- nil, or sequence table with parameters 1,ドル 2,ドル ...
 -- Postcondition:
 -- Returns string, or false
 local o = mw.message.new( access )
 local r
 if o:exists() then
 if type( alien ) == "string" then
 o:inLanguage( alien:lower() )
 end
 if type( apply ) == "table" then
 o:params( apply )
 end
 r = o:plain()
 end
 return r or false
 end -- Multilingual.int()



 Multilingual.isLang = function ( ask, additional )
 -- Could this be an ISO language code?
 -- Precondition:
 -- ask -- language code
 -- additional -- true, if Wiki codes like "simple" permitted
 -- Postcondition:
 -- Returns boolean
 local r, s
 if additional then
 s = ask
 else
 s = Multilingual.getBase( ask )
 end
 if s then
 r = mw.language.isKnownLanguageTag( s )
 if r then
 r = not Multilingual.fix( s )
 elseif additional then
 r = Multilingual.exotic[ s ] or false
 end
 else
 r = false
 end
 return r
 end -- Multilingual.isLang()



 Multilingual.isLangWiki = function ( ask )
 -- Could this be a Wiki language version?
 -- Precondition:
 -- ask -- language version specifier
 -- Postcondition:
 -- Returns boolean
 local r
 local s = Multilingual.getBase( ask )
 if s then
 r = mw.language.isSupportedLanguage( s ) or
 Multilingual.exotic[ ask ]
 else
 r = false
 end
 return r
 end -- Multilingual.isLangWiki()



 Multilingual.isMinusculable = function ( ask, assigned )
 -- Could this language name become downcased?
 -- Precondition:
 -- ask -- language code, or nil
 -- assigned -- language name, or nil
 -- Postcondition:
 -- Returns boolean
 local r = true
 if ask then
 local cnf = fetch( "Multilingual", "config" )
 if cnf then
 local s = string.format( " %s ", ask:lower() )
 if type( cnf.stopMinusculization ) == "string"
 and cnf.stopMinusculization:find( s, 1, true ) then
 r = false
 end
 if r and assigned
 and type( cnf.seekMinusculization ) == "string"
 and cnf.seekMinusculization:find( s, 1, true )
 and type( cnf.scanMinusculization ) == "string" then
 local scan = assigned:gsub( "[%(%)]", " " ) .. " "
 if not scan:find( cnf.scanMinusculization ) then
 r = false
 end
 end
 end
 end
 return r
 end -- Multilingual.isMinusculable()



 Multilingual.isRTL = function ( ask )
 -- Check whether language is written right-to-left
 -- Precondition:
 -- ask -- string, with language (or script) code
 -- Returns true, if right-to-left
 local r
 Multilingual.rtl = Multilingual.rtl or { }
 r = Multilingual.rtl[ ask ]
 if type( r ) ~= "boolean" then
 local bib = fetch( "ISO15924" )
 if type( bib ) == "table" and
 type( bib.isRTL ) == "function" then
 r = bib.isRTL( ask )
 else
 r = mw.language.new( ask ):isRTL()
 end
 Multilingual.rtl[ ask ] = r
 end
 return r
 end -- Multilingual.isRTL()



 Multilingual.linkArticle = function ( ask, about )
 -- Retrieve link to local article from BCP-47 language code
 -- Precondition:
 -- ask -- string, with language code
 -- about -- string, with link text, or not
 -- Postcondition:
 -- Returns string, with page name, or false
 local s = Multilingual.getArticle( ask )
 local r
 if s then
 if about == "" or about == s then
 r = string.format( "[[%s]]", s )
 else
 r = string.format( "[[%s|%s]]", s, about )
 end
 else
 r = about
 end
 return r or ""
 end -- Multilingual.linkArticle()



 Multilingual.message = function ( arglist, frame )
 -- Show text in best match of user language like system message
 -- Precondition:
 -- arglist -- template arguments
 -- frame -- frame, if available
 -- Postcondition:
 -- Returns string with appropriate text
 local r
 if type( arglist ) == "table" then
 local t = { }
 local m, p, save
 for k, v in pairs( arglist ) do
 if type( k ) == "string" and
 type( v ) == "string" then
 v = mw.text.trim( v )
 if v ~= "" then
 if k:match( "^%l%l" ) then
 t[ k ] = v
 elseif k:match( "^%$%d$" ) and k ~= "0ドル" then
 p = p or { }
 k = tonumber( k:match( "^%$(%d)$" ) )
 p[ k ] = v
 if not m or k > m then
 m = k
 end
 end
 end
 end
 end -- for k, v
 if type( arglist[ "-" ] ) == "string" then
 save = arglist[ arglist[ "-" ] ]
 end
 r = Multilingual.i18n( t, save, frame )
 if p and r and r:find( "$", 1, true ) then
 t = { }
 for i = 1, m do
 t[ i ] = p[ i ] or ""
 end -- for i
 r = mw.message.newRawMessage( r, t ):plain()
 end
 end
 return r or ""
 end -- Multilingual.message()



 Multilingual.sitelink = function ( all, frame )
 -- Make link at local or other site with optimal linktext translation
 -- Precondition:
 -- all -- string or table or number, item ID or entity
 -- frame -- frame, if available
 -- Postcondition:
 -- Returns string with any helpful internal link, or plain text
 local s = type( all )
 local object, r
 if s == "table" then
 object = all
 elseif s == "string" then
 object = mw.wikibase.getEntity( all )
 elseif s == "number" then
 object = mw.wikibase.getEntity( string.format( "Q%d", all ) )
 end
 if type( object ) == "table" then
 local collection = object.sitelinks
 local entry
 s = false
 if type( collection ) == "table" then
 Multilingual.site = Multilingual.site or
 mw.wikibase.getGlobalSiteId()
 entry = collection[ Multilingual.site ]
 if entry then
 s = ":" .. entry.title
 elseif collection.enwiki then
 s = "w:en:" .. collection.enwiki.title
 end
 end
 r = Multilingual.wikibase( object, "labels", frame )
 if s then
 if s == ":" .. r then
 r = string.format( "[[%s]]", s )
 else
 r = string.format( "[[%s|%s]]", s, r )
 end
 end
 end
 return r or ""
 end -- Multilingual.sitelink()



 Multilingual.tabData = function ( access, at, alt, frame )
 -- Retrieve translated keyword from commons:Data:****.tab
 -- Precondition:
 -- access -- string, with page identification on Commons
 -- at -- string, with keyword
 -- alt -- string|nil|false, with fallback text
 -- frame -- frame, if available
 -- Returns
 -- 1. string|nil|false, with selected message
 -- 2. language code, or "error"
 local data = fetchData( access )
 local r1, r2
 if type( data ) == "table" then
 if type( at ) == "string" then
 local seek = mw.text.trim( at )
 if seek == "" then
 r1 = "EMPTY Multilingual.tabData key"
 else
 local e, poly
 for i = 1, #data do
 e = data[ i ]
 if type( e ) == "table" then
 if e[ 1 ] == seek then
 if type( e[ 2 ] ) == "table" then
 poly = e[ 2 ]
 else
 r1 = "INVALID Multilingual.tabData bad #"
 .. tostring( i )
 end
 break -- for i
 end
 else
 break -- for i
 end
 end -- for i
 if poly then
 data = poly
 else
 r1 = "UNKNOWN Multilingual.tabData key: " .. seek
 end
 end
 else
 r1 = "INVALID Multilingual.tabData key"
 end
 else
 r1 = data
 end
 if r1 then
 r2 = "error"
 elseif data then
 r1, r2 = Multilingual.i18n( data, alt, frame )
 r2 = r2 or "error"
 end
 return r1, r2
 end -- Multilingual.tabData()



 Multilingual.userLang = function ( accept, frame )
 -- Try to support user language by application
 -- Precondition:
 -- accept -- string or table
 -- space separated list of available ISO 639 codes
 -- Default: project language, or English
 -- frame -- frame, if available
 -- Postcondition:
 -- Returns string with appropriate code
 local s = type( accept )
 local codes, r, slang
 if s == "string" then
 codes = mw.text.split( accept:lower(), "%s+" )
 elseif s == "table" then
 codes = { }
 for i = 1, #accept do
 s = accept[ i ]
 if type( s ) == "string" and
 s ~= "" then
 table.insert( codes, s:lower() )
 end
 end -- for i
 end
 slang = User.favorize( codes, frame )
 if slang then
 if feasible( slang, codes ) then
 r = slang
 elseif slang:find( "-", 1, true ) then
 slang = Multilingual.getBase( slang )
 if feasible( slang, codes ) then
 r = slang
 end
 end
 if not r then
 local others = mw.language.getFallbacksFor( slang )
 for i = 1, #others do
 s = others[ i ]
 if feasible( s, codes ) then
 r = s
 break -- for i
 end
 end -- for i
 end
 end
 if not r then
 local back = favorites()
 for i = 1, #back do
 s = back[ i ]
 if feasible( s, codes ) then
 r = s
 break -- for i
 end
 end -- for i
 if not r then
 if codes[ 1 ] and codes[ 1 ] ~= "" then
 r = codes[ 1 ]
 elseif slang then
 r = slang
 else
 r = mw.language.getContentLanguage():getCode():lower()
 end
 end
 end
 return r or favorites()[ 1 ]
 end -- Multilingual.userLang()



 Multilingual.userLangCode = function ()
 -- Guess a user language code
 -- Postcondition:
 -- Returns code of current best guess
 return User.self or favorites()[ 1 ]
 end -- Multilingual.userLangCode()



 Multilingual.wikibase = function ( all, about, attempt, frame )
 -- Optimal translation of wikibase component
 -- Precondition:
 -- all -- string or table, object ID or entity
 -- about -- boolean, true "descriptions" or false "labels"
 -- attempt -- string or not, code of preferred language
 -- frame -- frame, if available
 -- Postcondition:
 -- Returns
 -- 1. string, with selected message
 -- 2. string, with language code, or not
 local s = type( all )
 local object, r, r2
 if s == "table" then
 object = all
 elseif s == "string" then
 object = mw.wikibase.getEntity( all )
 end
 if type( object ) == "table" then
 if about and about ~= "labels" then
 s = "descriptions"
 else
 s = "labels"
 end
 object = object[ s ]
 if type( object ) == "table" then
 if object[ attempt ] then
 r = object[ attempt ].value
 r2 = attempt
 else
 local poly
 for k, v in pairs( object ) do
 poly = poly or { }
 poly[ k ] = v.value
 end -- for k, v
 if poly then
 r, r2 = Multilingual.i18n( poly, nil, frame )
 end
 end
 end
 end
 return r or "", r2
 end -- Multilingual.wikibase()



 Failsafe.failsafe = function ( atleast )
 -- Retrieve versioning and check for compliance
 -- Precondition:
 -- atleast -- string, with required version
 -- or wikidata|item|~|@ or false
 -- Postcondition:
 -- Returns string -- with queried version/item, also if problem
 -- false -- if appropriate
 -- 2020年08月17日
 local since = atleast
 local last = ( since == "~" )
 local linked = ( since == "@" )
 local link = ( since == "item" )
 local r
 if last or link or linked or since == "wikidata" then
 local item = Failsafe.item
 since = false
 if type( item ) == "number" and item > 0 then
 local suited = string.format( "Q%d", item )
 if link then
 r = suited
 else
 local entity = mw.wikibase.getEntity( suited )
 if type( entity ) == "table" then
 local seek = Failsafe.serialProperty or "P348"
 local vsn = entity:formatPropertyValues( seek )
 if type( vsn ) == "table" and
 type( vsn.value ) == "string" and
 vsn.value ~= "" then
 if last and vsn.value == Failsafe.serial then
 r = false
 elseif linked then
 if mw.title.getCurrentTitle().prefixedText
 == mw.wikibase.getSitelink( suited ) then
 r = false
 else
 r = suited
 end
 else
 r = vsn.value
 end
 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.fair = function ( frame )
 -- Format language code
 -- 1 -- language code
 local s = mw.text.trim( frame.args[ 1 ] or "" )
 return Multilingual.fair( s ) or ""
 end -- p.fair



 p.fallback = function ( frame )
 -- Is another language suitable as replacement?
 -- 1 -- language version specifier to be supported
 -- 2 -- language specifier of a possible replacement
 local s1 = mw.text.trim( frame.args[ 1 ] or "" )
 local s2 = mw.text.trim( frame.args[ 2 ] or "" )
 local r = Multilingual.fallback( s1, s2 )
 if type( r ) == "table" then
 r = r[ 1 ]
 else
 r = r and "1" or ""
 end
 return r
 end -- p.fallback



 p.findCode = function ( frame )
 -- Retrieve language code from language name
 -- 1 -- name in current project language
 local s = mw.text.trim( frame.args[ 1 ] or "" )
 return Multilingual.findCode( s ) or ""
 end -- p.findCode



 p.fix = function ( frame )
 local r = frame.args[ 1 ]
 if r then
 r = Multilingual.fix( mw.text.trim( r ) )
 end
 return r or ""
 end -- p.fix



 p.format = function ( frame )
 -- Format one or more languages
 -- 1 -- language list or item
 -- slang -- language of the answer, if not native
 -- * -- native
 -- ! -- current project
 -- any valid code
 -- shift -- capitalize, if "c"; downcase, if "d"
 -- capitalize first item only, if "f"
 -- link -- 1 -- link items
 -- scream -- category title in case of error
 -- split -- split pattern, if list expected
 -- separator -- list separator, else split
 -- start -- prepend first element, if any
 local r
 local link
 if frame.args.link == "1" then
 link = true
 end
 r = Multilingual.format( frame.args[ 1 ],
 frame.args.slang,
 frame.args.shift,
 link,
 frame.args.scream,
 frame,
 frame.args.split,
 frame.args.separator,
 frame.args.start )
 return r or ""
 end -- p.format



 p.getArticle = function ( frame )
 local s = mw.text.trim( frame.args[ 1 ] or "" )
 return Multilingual.getArticle( s )
 end -- p.getArticle



 p.getBase = function ( frame )
 -- Retrieve base language from possibly combined ISO language code
 -- 1 -- code
 local s = mw.text.trim( frame.args[ 1 ] or "" )
 return Multilingual.getBase( s ) or ""
 end -- p.getBase



 p.getName = function ( frame )
 -- Retrieve language name from ISO language code
 -- 1 -- code
 -- 2 -- language to be used for the answer, if not native
 -- ! -- current project
 -- * -- native
 -- any valid code
 local s = mw.text.trim( frame.args[ 1 ] or "" )
 local slang = frame.args[ 2 ]
 local r
 Multilingual.frame = frame
 if slang then
 slang = mw.text.trim( slang )
 end
 r = Multilingual.getName( s, slang )
 return r or ""
 end -- p.getName



 p.int = function ( frame )
 -- Translated system message
 -- 1 -- message ID
 -- lang -- language code
 -- 1,ドル 2,ドル ... -- parameters
 local sysMsg = frame.args[ 1 ]
 local r
 if sysMsg then
 sysMsg = mw.text.trim( sysMsg )
 if sysMsg ~= "" then
 local n = 0
 local slang = frame.args.lang
 local i, params, s
 if slang == "" then
 slang = false
 end
 for k, v in pairs( frame.args ) do
 if type( k ) == "string" then
 s = k:match( "^%$(%d+)$" )
 if s then
 i = tonumber( s )
 if i > n then
 n = i
 end
 end
 end
 end -- for k, v
 if n > 0 then
 local s
 params = { }
 for i = 1, n do
 s = frame.args[ "$" .. tostring( i ) ] or ""
 table.insert( params, s )
 end -- for i
 end
 r = Multilingual.int( sysMsg, slang, params )
 end
 end
 return r or ""
 end -- p.int



 p.isLang = function ( frame )
 -- Could this be an ISO language code?
 -- 1 -- code
 local s = mw.text.trim( frame.args[ 1 ] or "" )
 local lucky, r = pcall( Multilingual.isLang, s )
 return r and "1" or ""
 end -- p.isLang



 p.isLangWiki = function ( frame )
 -- Could this be a Wiki language version?
 -- 1 -- code
 -- Returns non-empty, if possibly language version
 local s = mw.text.trim( frame.args[ 1 ] or "" )
 local lucky, r = pcall( Multilingual.isLangWiki, s )
 return r and "1" or ""
 end -- p.isLangWiki



 p.isRTL = function ( frame )
 -- Check whether language is written right-to-left
 -- 1 -- string, with language code
 -- Returns non-empty, if right-to-left
 local s = mw.text.trim( frame.args[ 1 ] or "" )
 return Multilingual.isRTL( s ) and "1" or ""
 end -- p.isRTL()



 p.linkArticle = function ( frame )
 local s = mw.text.trim( frame.args[ 1 ] or "" )
 local show = mw.text.trim( frame.args[ 2 ] or "" )
 return Multilingual.linkArticle( s, show )
 end -- p.linkArticle



 p.message = function ( frame )
 -- Translation of text element
 return Multilingual.message( fold( frame ), frame )
 end -- p.message



 p.sitelink = function ( frame )
 -- Make link at local or other site with optimal linktext translation
 -- 1 -- item ID
 local s = mw.text.trim( frame.args[ 1 ] or "" )
 local r
 if s:match( "^%d+$") then
 r = tonumber( s )
 elseif s:match( "^Q%d+$") then
 r = s
 end
 if r then
 r = Multilingual.sitelink( r, frame )
 end
 return r or s
 end -- p.sitelink



 p.tabData = function ( frame )
 -- Retrieve best message text from Commons Data
 -- 1 -- page identification on Commons
 -- 2 -- keyword
 -- alt -- fallback text
 local suite = frame.args[ 1 ]
 local seek = frame.args[ 2 ]
 local salt = frame.args.alt
 local r = Multilingual.tabData( suite, seek, salt, frame )
 return r
 end -- p.tabData



 p.userLang = function ( frame )
 -- Which language does the current user prefer?
 -- 1 -- space separated list of available ISO 639 codes
 local s = mw.text.trim( frame.args[ 1 ] or "" )
 return Multilingual.userLang( s, frame )
 end -- p.userLang



 p.wikibase = function ( frame )
 -- Optimal translation of wikibase component
 -- 1 -- object ID
 -- 2 -- 1 for "descriptions", 0 for "labels".
 -- or either "descriptions" or "labels"
 local r
 local s = mw.text.trim( frame.args[ 1 ] or "" )
 if s ~= "" then
 local s2 = mw.text.trim( frame.args[ 2 ] or "0" )
 local slang = mw.text.trim( frame.args.lang or "" )
 local large = ( s2 ~= "" and s2 ~= "0" )
 if slang == "" then
 slang = false
 end
 r = Multilingual.wikibase( s, large, slang, frame )
 end
 return r or ""
 end -- p.wikibase



 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.Multilingual = function ()
 return Multilingual
 end -- p.Multilingual

 setmetatable( p, { __call = function ( func, ... )
 setmetatable( p, nil )
 return Failsafe
 end } )

 return p
Abgerufen von „https://de.wikipedia.org/w/index.php?title=Modul:Multilingual&oldid=253960624"