Module:Multilingual and Module:Multilingual/sandbox: Difference between pages
(Difference between pages)
imported>Sdrqaz m Protected "Module:Multilingual": High-risk Lua module: Requested by Pppery at RfPP. Used in Module:Format TemplateData, which is semi-protected and has 516 transclusions ([Edit=Require autoconfirmed or confirmed access] (indefinite)) |
imported>Lemondoge Simplifications, and MASSIVE formatting improvements - especially removing excess whitespace and replacing quadruple spaces with tabs, in accordance to mw:Manual:Coding conventions/Lua |
||
Line 1: | Line 1: | ||
local Multilingual = { suite = "Multilingual", | local Multilingual = { suite = "Multilingual", | ||
serial = "2020-12-10", | |||
item = 47541920, | |||
globals = { ISO15924 = 71584769, | |||
WLink = 19363224 } | |||
} | |||
--[=[ | --[=[ | ||
Utilities for multilingual texts and ISO 639 (BCP47) issues etc. | Utilities for multilingual texts and ISO 639 (BCP47) issues etc. | ||
Line 33: | Line 33: | ||
local GlobalMod = Multilingual | local GlobalMod = Multilingual | ||
local GlobalData = Multilingual | local GlobalData = Multilingual | ||
local User | local User = { sniffer = "showpreview" } | ||
Multilingual.globals.Multilingual = Multilingual.item | Multilingual.globals.Multilingual = Multilingual.item | ||
Line 39: | Line 39: | ||
Multilingual.exotic = { simple = true, | Multilingual.exotic = { simple = true, | ||
no = true } | |||
Multilingual.prefer = { cs = true, | Multilingual.prefer = { cs = true, | ||
de = true, | |||
en = true, | |||
es = true, | |||
fr = true, | |||
it = true, | |||
nl = true, | |||
pt = true, | |||
ru = true, | |||
sv = true } | |||
local foreignModule = function(access, advanced, append, alt, alert) | |||
-- Fetch global module | |||
local foreignModule = function ( access, advanced, append, alt, alert ) | -- 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() | end -- foreignModule() | ||
local fetchData = function(access) | |||
-- Retrieve translated keyword from commons:Data:****.tab | |||
local fetchData = function ( access ) | -- 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() | end -- fetchData() | ||
local favorites = function() | |||
-- Provide fallback codes | |||
local favorites = function () | -- 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() | end -- favorites() | ||
local feasible = function(ask, accept) | |||
-- Is ask to be supported by application? | |||
local feasible = function ( ask, accept ) | -- 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() | end -- feasible() | ||
local fetch = function(access, append) | |||
-- Attach config or library module | |||
local fetch = function ( access, append ) | -- 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 got == nil then | |||
local global = Multilingual.globals[access] | |||
local lib = (not append or append == "config") | |||
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() | end -- fetch() | ||
local fetchISO639 = function(access) | |||
-- Retrieve table from commons:Data:ISO639/***.tab | |||
local fetchISO639 = function ( access ) | -- 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() | end -- fetchISO639() | ||
local fill = function(access, alien, frame) | |||
-- Expand language name template | |||
local fill = function ( access, alien, frame ) | -- 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 | |||
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 | |||
Multilingual.frame = frame or mw.getCurrentFrame() | |||
end | |||
f = function(a) | |||
return Multilingual.frame:expandTemplate{ title = a } | |||
end | |||
lucky, s = pcall(f, source) | |||
if lucky then | |||
return s | |||
end | |||
end | |||
end | |||
return nil | |||
end -- fill() | end -- fill() | ||
local find = function(ask, alien) | |||
-- Derive language code from name | |||
local find = function ( ask, alien ) | -- 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() | end -- find() | ||
local fold = function ( frame ) | 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() | end -- fold() | ||
User.favorize = function(accept, frame) | |||
-- Guess user language | |||
User.favorize = function ( accept, frame ) | -- 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 | |||
elseif Multilingual.prefer[s] then | |||
table.insert(order, s) | |||
else | |||
table.insert(post, s) | |||
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 | |||
end | |||
return User.self | |||
end -- User.favorize() | end -- User.favorize() | ||
Multilingual.fair = function(ask) | |||
-- Format language specification according to RFC 5646 etc. | |||
Multilingual.fair = function ( ask ) | -- 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() | end -- Multilingual.fair() | ||
Multilingual.fallback = function(able, another) | |||
-- Is another language suitable as replacement? | |||
Multilingual.fallback = function ( able, another ) | -- 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() | end -- Multilingual.fallback() | ||
Multilingual.findCode = function(ask) | |||
-- Retrieve code of local (current project or English) language name | |||
Multilingual.findCode = function ( ask ) | -- 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() | end -- Multilingual.findCode() | ||
Multilingual.fix = function(attempt) | |||
-- Fix frequently mistaken language code | |||
Multilingual.fix = function ( attempt ) | -- 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() | end -- Multilingual.fix() | ||
Multilingual.format = function(apply, alien, alter, active, alert, | |||
frame, assembly, adjacent, ahead) | |||
Multilingual.format = function ( apply, alien, alter, active, alert, | -- 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() | end -- Multilingual.format() | ||
Multilingual.getBase = function(ask) | |||
-- Retrieve base language from possibly combined ISO language code | |||
Multilingual.getBase = function ( ask ) | -- 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() | end -- Multilingual.getBase() | ||
Multilingual.getLang = function(ask) | |||
-- Retrieve components of a RFC 5646 language code | |||
Multilingual.getLang = function ( ask ) | -- 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() | end -- Multilingual.getLang() | ||
Multilingual.getName = function(ask, alien) | |||
-- Which name is assigned to this language code? | |||
Multilingual.getName = function ( ask, alien ) | -- 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() | end -- Multilingual.getName() | ||
Multilingual.i18n = function(available, alt, frame) | |||
-- Select translatable message | |||
Multilingual.i18n = function ( available, alt, frame ) | -- 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() | end -- Multilingual.i18n() | ||
Multilingual.int = function(access, alien, apply) | |||
-- Translated system message | |||
Multilingual.int = function ( access, alien, apply ) | -- 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() | end -- Multilingual.int() | ||
Multilingual.isLang = function(ask, additional) | |||
-- Could this be an ISO language code? | |||
Multilingual.isLang = function ( ask, additional ) | -- 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() | end -- Multilingual.isLang() | ||
Multilingual.isLangWiki = function(ask) | |||
-- Could this be a Wiki language version? | |||
Multilingual.isLangWiki = function ( ask ) | -- 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() | end -- Multilingual.isLangWiki() | ||
Multilingual.isMinusculable = function(ask, assigned) | |||
-- Could this language name become downcased? | |||
Multilingual.isMinusculable = function ( ask, assigned ) | -- 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() | end -- Multilingual.isMinusculable() | ||
Multilingual.isRTL = function(ask) | |||
-- Check whether language is written right-to-left | |||
Multilingual.isRTL = function ( ask ) | -- 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() | end -- Multilingual.isRTL() | ||
Multilingual.message = function(arglist, frame) | |||
-- Show text in best match of user language like system message | |||
Multilingual.message = function ( arglist, frame ) | -- 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() | end -- Multilingual.message() | ||
Multilingual.sitelink = function(all, frame) | |||
-- Make link at local or other site with optimal linktext translation | |||
Multilingual.sitelink = function ( all, frame ) | -- 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() | end -- Multilingual.sitelink() | ||
Multilingual.tabData = function(access, at, alt, frame) | |||
-- Retrieve translated keyword from commons:Data:****.tab | |||
Multilingual.tabData = function ( access, at, alt, frame ) | -- 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() | end -- Multilingual.tabData() | ||
Multilingual.userLang = function(accept, frame) | |||
-- Try to support user language by application | |||
Multilingual.userLang = function ( accept, frame ) | -- 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 | |||
slang = others[i] | |||
if feasible(slang, codes) then | |||
r = slang | |||
break -- for i | |||
end | |||
end -- for i | |||
end | |||
end | |||
if not r then | |||
local back = favorites() | |||
for i = 1, #back do | |||
slang = back[i] | |||
if feasible(slang, codes) then | |||
r = slang | |||
break -- for i | |||
end | |||
end -- for i | |||
if not r and codes[1] then | |||
r = codes[1] | |||
end | |||
end | |||
return r or favorites()[1] | |||
end -- Multilingual.userLang() | end -- Multilingual.userLang() | ||
Multilingual.userLangCode = function() | |||
-- Guess a user language code | |||
Multilingual.userLangCode = function () | -- Postcondition: | ||
-- Returns code of current best guess | |||
return User.self or favorites()[1] | |||
end -- Multilingual.userLangCode() | end -- Multilingual.userLangCode() | ||
Multilingual.wikibase = function(all, about, attempt, frame) | |||
-- Optimal translation of wikibase component | |||
Multilingual.wikibase = function ( all, about, attempt, frame ) | -- 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() | end -- Multilingual.wikibase() | ||
Failsafe.failsafe = function(atleast) | |||
-- Retrieve versioning and check for compliance | |||
Failsafe.failsafe = function ( atleast ) | -- 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() | end -- Failsafe.failsafe() | ||
-- Export | -- Export | ||
local p = { } | local p = {} | ||
p.fair = function(frame) | |||
-- Format language code | |||
p.fair = function ( frame ) | -- 1 -- language code | ||
local s = mw.text.trim(frame.args[1] or "") | |||
return Multilingual.fair(s) or "" | |||
end -- p.fair | end -- p.fair | ||
p.fallback = function(frame) | |||
-- Is another language suitable as replacement? | |||
p.fallback = function ( frame ) | -- 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 | end -- p.fallback | ||
p.findCode = function(frame) | |||
-- Retrieve language code from language name | |||
p.findCode = function ( frame ) | -- 1 -- name in current project language | ||
local s = mw.text.trim(frame.args[1] or "") | |||
return Multilingual.findCode(s) or "" | |||
end -- p.findCode | end -- p.findCode | ||
p.fix = function(frame) | |||
local r = frame.args[1] | |||
p.fix = function ( frame ) | if r then | ||
r = Multilingual.fix(mw.text.trim(r)) | |||
end | |||
return r or "" | |||
end -- p.fix | end -- p.fix | ||
p.format = function(frame) | |||
-- Format one or more languages | |||
p.format = function ( frame ) | -- 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 | end -- p.format | ||
p.getBase = function(frame) | |||
-- Retrieve base language from possibly combined ISO language code | |||
p.getBase = function ( frame ) | -- 1 -- code | ||
local s = mw.text.trim(frame.args[1] or "") | |||
return Multilingual.getBase(s) or "" | |||
end -- p.getBase | end -- p.getBase | ||
p.getName = function(frame) | |||
-- Retrieve language name from ISO language code | |||
p.getName = function ( frame ) | -- 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 | end -- p.getName | ||
p.int = function(frame) | |||
-- Translated system message | |||
p.int = function ( frame ) | -- 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 | end -- p.int | ||
p.isLang = function(frame) | |||
-- Could this be an ISO language code? | |||
p.isLang = function ( frame ) | -- 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 | end -- p.isLang | ||
p.isLangWiki = function(frame) | |||
-- Could this be a Wiki language version? | |||
p.isLangWiki = function ( frame ) | -- 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 | end -- p.isLangWiki | ||
p.isRTL = function(frame) | |||
-- Check whether language is written right-to-left | |||
p.isRTL = function ( frame ) | -- 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() | end -- p.isRTL() | ||
p.message = function(frame) | |||
-- Translation of text element | |||
p.message = function ( frame ) | return Multilingual.message(fold(frame), frame) | ||
end -- p.message | end -- p.message | ||
p.sitelink = function(frame) | |||
-- Make link at local or other site with optimal linktext translation | |||
p.sitelink = function ( frame ) | -- 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 | end -- p.sitelink | ||
p.tabData = function(frame) | |||
-- Retrieve best message text from Commons Data | |||
p.tabData = function ( frame ) | -- 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 | end -- p.tabData | ||
p.userLang = function(frame) | |||
-- Which language does the current user prefer? | |||
p.userLang = function ( frame ) | -- 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 | end -- p.userLang | ||
p.wikibase = function(frame) | |||
-- Optimal translation of wikibase component | |||
p.wikibase = function ( frame ) | -- 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 | end -- p.wikibase | ||
p.failsafe = function(frame) | |||
-- Versioning interface | |||
p.failsafe = function ( frame ) | 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() | end -- p.failsafe() | ||
p.Multilingual = function() | |||
return Multilingual | |||
p.Multilingual = function () | |||
end -- p.Multilingual | end -- p.Multilingual | ||
return p | return p |