Modul:Multilingual: Unterschied zwischen den Versionen
Aus WiiDatabase Wiki
Zur Navigation springenZur Suche springen
Inhalt gelöscht Inhalt hinzugefügt
ICON (Diskussion | Beiträge) Die Seite wurde neu angelegt: „local Multilingual = { suite = "Multilingual", serial = "2018-04-16", item = 47541920 } local User = { sniffer…“ |
ICON (Diskussion | Beiträge) K 1 Version importiert |
||
| (Eine dazwischenliegende Version von einem anderen Benutzer wird nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
local Multilingual = { suite = "Multilingual", |
local Multilingual = { suite = "Multilingual", |
||
serial = " |
serial = "2020-12-10", |
||
item = 47541920 |
item = 47541920, |
||
globals = { ISO15924 = 71584769, |
|||
local User = { sniffer = "publishchanges" } |
|||
WLink = 19363224 } |
|||
} |
|||
--[=[ |
|||
Utilities for multilingual texts and ISO 639 (BCP47) issues etc. |
|||
* fair() |
|||
* fallback() |
|||
* findCode() |
|||
* fix() |
|||
* format() |
|||
* getBase() |
|||
* getLang() |
|||
* getName() |
|||
* i18n() |
|||
* int() |
|||
* isLang() |
|||
* isLangWiki() |
|||
* isMinusculable() |
|||
* isRTL() |
|||
* message() |
|||
* sitelink() |
|||
* tabData() |
|||
* userLang() |
|||
* userLangCode() |
|||
* wikibase() |
|||
* failsafe() |
|||
loadData: Multilingual/config Multilingual/names |
|||
]=] |
|||
local Failsafe = Multilingual |
|||
local GlobalMod = Multilingual |
|||
local GlobalData = Multilingual |
|||
local User = { sniffer = "showpreview" } |
|||
Multilingual.globals.Multilingual = Multilingual.item |
|||
| Zeile 8: | Zeile 40: | ||
Multilingual.exotic = { simple = true, |
Multilingual.exotic = { simple = true, |
||
no = 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 } |
|||
local |
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: |
-- Postcondition: |
||
-- Returns |
-- Returns whatever, probably table |
||
-- 2020-01-01 |
|||
if not Multilingual.self then |
|||
local storage = access |
|||
Multilingual.self = mw.language.getContentLanguage():getCode() |
|||
local finer = function () |
|||
:lower() |
|||
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 |
end |
||
GlobalMod.globalModules = GlobalMod.globalModules or { } |
|||
return Multilingual.self |
|||
suited = GlobalMod.globalModules[ access ] |
|||
end -- favorite() |
|||
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? |
-- Is ask to be supported by application? |
||
-- Precondition: |
-- Precondition: |
||
| Zeile 42: | Zeile 240: | ||
local fetch = function ( access, |
local fetch = function ( access, append ) |
||
-- Attach config or library module |
-- Attach config or library module |
||
-- Precondition: |
-- Precondition: |
||
-- access -- module title |
-- access -- module title |
||
-- |
-- append -- string, with subpage part of this; or false |
||
-- Postcondition: |
-- Postcondition: |
||
-- Returns table |
-- Returns: table, with library, or false |
||
local got, sign |
|||
-- Throws error, if not available |
|||
if append then |
|||
sign = string.format( "%s/%s", access, append ) |
|||
else |
|||
sign = access |
|||
end |
|||
if type( Multilingual.ext ) ~= "table" then |
if type( Multilingual.ext ) ~= "table" then |
||
Multilingual.ext = { } |
Multilingual.ext = { } |
||
end |
end |
||
got = Multilingual.ext[ sign ] |
|||
if not got and got ~= false then |
|||
local |
local global = Multilingual.globals[ access ] |
||
local lib = ( not append or append == "config" ) |
|||
if lucky then |
|||
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 |
||
end |
end |
||
else |
|||
got = false |
|||
end |
end |
||
Multilingual.ext[ sign ] = got |
|||
end |
|||
if allow then |
|||
return got |
|||
Multilingual.ext[ access ] = false |
|||
end -- fetch() |
|||
else |
|||
got = string.format( "Module:%s invalid", access ) |
|||
error( got, 0 ) |
|||
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 |
end |
||
end |
end |
||
return |
return r |
||
end -- |
end -- fill() |
||
local find = function ( ask, alien ) |
|||
-- Derive language code from name |
-- Derive language code from name |
||
-- Precondition: |
-- Precondition: |
||
| Zeile 98: | Zeile 381: | ||
return r |
return r |
||
end -- find() |
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() |
|||
| Zeile 127: | Zeile 435: | ||
end |
end |
||
if User.sin then |
if User.sin then |
||
local order = { } |
|||
local post = { } |
|||
local three = { } |
|||
local unfold = { } |
|||
local s, sin |
local s, sin |
||
for i = 1, #accept do |
for i = 1, #accept do |
||
s = accept[ i ] |
s = accept[ i ] |
||
if not User.trials[ s ] then |
if not User.trials[ s ] then |
||
if #s > 2 then |
|||
if |
if s:find( "-", 3, true ) then |
||
table.insert( unfold, s ) |
|||
else |
|||
table.insert( three, s ) |
|||
end |
|||
else |
else |
||
if Multilingual.prefer[ s ] then |
|||
table.insert( order, s ) |
|||
else |
|||
table.insert( post, s ) |
|||
end |
|||
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 |
||
end -- for i |
end -- for i |
||
| Zeile 187: | Zeile 524: | ||
-- Precondition: |
-- Precondition: |
||
-- able -- language version specifier to be supported |
-- able -- language version specifier to be supported |
||
-- another -- language specifier of a possible replacement |
-- another -- language specifier of a possible replacement, |
||
-- or not to retrieve a fallback table |
|||
-- Postcondition: |
-- Postcondition: |
||
-- Returns boolean |
-- Returns boolean, or table with fallback codes |
||
local r |
local r |
||
if type( able ) == "string" and |
if type( able ) == "string" and #able > 0 then |
||
type( another ) == "string" then |
if type( another ) == "string" and #another > 0 then |
||
if able == another then |
if able == another then |
||
r = true |
|||
else |
|||
local s = Multilingual.getBase( able ) |
|||
if s == another then |
|||
r = true |
r = true |
||
else |
else |
||
local |
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 |
end |
||
| Zeile 221: | Zeile 573: | ||
if #seek > 1 then |
if #seek > 1 then |
||
if seek:find( "[", 1, true ) 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 |
end |
||
seek = mw.ustring.lower( seek ) |
seek = mw.ustring.lower( seek ) |
||
| Zeile 227: | Zeile 583: | ||
r = Multilingual.fair( seek ) |
r = Multilingual.fair( seek ) |
||
else |
else |
||
local |
local collection = favorites() |
||
for i = 1, #collection do |
|||
r = find( seek, collection[ i ] ) |
|||
r |
if r then |
||
break -- for i |
|||
end |
|||
end -- for i |
|||
end |
end |
||
end |
end |
||
return r |
return r |
||
end -- Multilingual.findCode() |
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() |
|||
| Zeile 308: | Zeile 678: | ||
r = Multilingual.getName( slang, alien ) |
r = Multilingual.getName( slang, alien ) |
||
if active then |
if active then |
||
slot = fill( slang, false, frame ) |
|||
if slot then |
|||
local wlink = fetch( "WLink" ) |
|||
if wlink and |
|||
type( wlink.getTarget ) |
|||
== "function" then |
|||
Multilingual.frame = frame |
|||
else |
|||
Multilingual.frame |
|||
= mw.getCurrentFrame() |
|||
end |
|||
end |
|||
slot = cnf.getLink( slang, |
|||
Multilingual.frame ) |
|||
if slot then |
|||
local wlink = fetch( "WLink" ) |
|||
slot = wlink.getTarget( slot ) |
slot = wlink.getTarget( slot ) |
||
else |
|||
lapsus = alert |
|||
end |
end |
||
else |
|||
lapsus = alert |
|||
end |
end |
||
end |
end |
||
| Zeile 405: | Zeile 765: | ||
-- .region |
-- .region |
||
-- .script |
-- .script |
||
-- .suggest |
|||
-- .year |
-- .year |
||
-- .extension |
-- .extension |
||
| Zeile 468: | Zeile 829: | ||
end |
end |
||
end -- for i |
end -- for i |
||
if r.legal then |
|||
r.suggest = Multilingual.fix( r.base ) |
|||
if r.suggest then |
|||
r.legal = false |
|||
end |
|||
end |
|||
else |
else |
||
r = { legal = false } |
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 |
end |
||
return r |
return r |
||
| Zeile 489: | Zeile 862: | ||
if ask then |
if ask then |
||
local slang = alien |
local slang = alien |
||
local support = "Multilingual/names" |
|||
local tLang |
local tLang |
||
if slang then |
if slang then |
||
| Zeile 495: | Zeile 867: | ||
slang = Multilingual.fair( ask ) |
slang = Multilingual.fair( ask ) |
||
elseif slang == "!" then |
elseif slang == "!" then |
||
slang = |
slang = favorites()[ 1 ] |
||
else |
else |
||
slang = Multilingual.fair( slang ) |
slang = Multilingual.fair( slang ) |
||
| Zeile 506: | Zeile 878: | ||
end |
end |
||
slang = slang:lower() |
slang = slang:lower() |
||
tLang = fetch( |
tLang = fetch( "Multilingual", "names" ) |
||
if tLang then |
if tLang then |
||
tLang = tLang[ slang ] |
tLang = tLang[ slang ] |
||
| Zeile 541: | Zeile 913: | ||
return r |
return r |
||
end -- Multilingual.getName() |
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() |
|||
| Zeile 583: | Zeile 998: | ||
if s then |
if s then |
||
r = mw.language.isKnownLanguageTag( s ) |
r = mw.language.isKnownLanguageTag( s ) |
||
if |
if r then |
||
r = not Multilingual.fix( s ) |
|||
elseif additional then |
|||
r = Multilingual.exotic[ s ] or false |
r = Multilingual.exotic[ s ] or false |
||
end |
end |
||
| Zeile 620: | Zeile 1.037: | ||
-- Postcondition: |
-- Postcondition: |
||
-- Returns boolean |
-- Returns boolean |
||
local r |
local r = true |
||
if ask then |
if ask then |
||
local cnf = fetch( "Multilingual |
local cnf = fetch( "Multilingual", "config" ) |
||
if cnf then |
if cnf then |
||
local s = string.format( " %s ", ask:lower() ) |
local s = string.format( " %s ", ask:lower() ) |
||
| Zeile 642: | Zeile 1.059: | ||
return r |
return r |
||
end -- Multilingual.isMinusculable() |
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.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() |
|||
| Zeile 648: | Zeile 1.236: | ||
-- Try to support user language by application |
-- Try to support user language by application |
||
-- Precondition: |
-- Precondition: |
||
-- accept -- |
-- accept -- string or table |
||
-- space separated list of available ISO 639 codes |
|||
-- Default: project language, or English |
-- Default: project language, or English |
||
-- frame -- frame, if available |
-- frame -- frame, if available |
||
| Zeile 656: | Zeile 1.245: | ||
local codes, r, slang |
local codes, r, slang |
||
if s == "string" then |
if s == "string" then |
||
codes = mw.text.split( accept:lower(), " |
codes = mw.text.split( accept:lower(), "%s+" ) |
||
elseif s == "table" then |
elseif s == "table" then |
||
codes = { } |
codes = { } |
||
for i = 1, #accept do |
for i = 1, #accept do |
||
s = accept[ i ] |
s = accept[ i ] |
||
if type( s ) == "string" |
if type( s ) == "string" and |
||
s ~= "" then |
|||
table.insert( codes, s:lower() ) |
table.insert( codes, s:lower() ) |
||
end |
end |
||
end -- for i |
end -- for i |
||
else |
|||
codes = { } |
|||
slang = favorite() |
|||
if mw.language.isKnownLanguageTag( slang ) then |
|||
table.insert( codes, slang ) |
|||
end |
|||
end |
end |
||
slang = User.favorize( codes, frame ) |
slang = User.favorize( codes, frame ) |
||
if |
if slang then |
||
slang = favorite() or "en" |
|||
end |
|||
if feasible( slang, codes ) then |
|||
r = slang |
|||
elseif slang:find( "-", 1, true ) then |
|||
slang = Multilingual.getBase( slang ) |
|||
if feasible( slang, codes ) then |
if feasible( slang, codes ) then |
||
r = slang |
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 |
||
end |
end |
||
if not r then |
if not r then |
||
local |
local back = favorites() |
||
for i = 1, # |
for i = 1, #back do |
||
slang = |
slang = back[ i ] |
||
if feasible( slang, codes ) then |
if feasible( slang, codes ) then |
||
r = slang |
r = slang |
||
| Zeile 693: | Zeile 1.286: | ||
end |
end |
||
end -- for i |
end -- for i |
||
if not r then |
if not r and codes[ 1 ] then |
||
r = codes[ 1 ] |
|||
r = "en" |
|||
else |
|||
r = codes[ 1 ] |
|||
end |
|||
end |
end |
||
end |
end |
||
return r |
return r or favorites()[ 1 ] |
||
end -- Multilingual.userLang() |
end -- Multilingual.userLang() |
||
| Zeile 710: | Zeile 1.299: | ||
-- Postcondition: |
-- Postcondition: |
||
-- Returns code of current best guess |
-- Returns code of current best guess |
||
return User.self or |
return User.self or favorites()[ 1 ] |
||
end -- Multilingual.userLangCode() |
end -- Multilingual.userLangCode() |
||
Multilingual. |
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 |
-- Retrieve versioning and check for compliance |
||
-- Precondition: |
-- Precondition: |
||
-- |
-- atleast -- string, with required version |
||
-- or false |
-- or wikidata|item|~|@ or false |
||
-- Postcondition: |
-- Postcondition: |
||
-- Returns string with |
-- Returns string -- with queried version/item, also if problem |
||
-- false -- if appropriate |
|||
local since = assert |
|||
-- 2020-08-17 |
|||
local since = atleast |
|||
local last = ( since == "~" ) |
|||
local linked = ( since == "@" ) |
|||
local link = ( since == "item" ) |
|||
local r |
local r |
||
if since == "wikidata" then |
if last or link or linked or since == "wikidata" then |
||
local item = |
local item = Failsafe.item |
||
since = false |
since = false |
||
if type( item ) == "number" and item > 0 then |
if type( item ) == "number" and item > 0 then |
||
local |
local suited = string.format( "Q%d", item ) |
||
if link then |
|||
item ) ) |
|||
r = suited |
|||
else |
|||
local vsn = entity:formatPropertyValues( "P348" ) |
|||
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 |
||
end |
end |
||
end |
end |
||
if |
if type( r ) == "nil" then |
||
if not since or since <= |
if not since or since <= Failsafe.serial then |
||
r = |
r = Failsafe.serial |
||
else |
else |
||
r = false |
r = false |
||
| Zeile 748: | Zeile 1.404: | ||
end |
end |
||
return r |
return r |
||
end -- |
end -- Failsafe.failsafe() |
||
| Zeile 760: | Zeile 1.416: | ||
-- Format language code |
-- Format language code |
||
-- 1 -- language code |
-- 1 -- language code |
||
local s = mw.text.trim( frame.args[ 1 ] or "" ) |
|||
return Multilingual.fair( s ) or "" |
|||
end -- p.fair |
end -- p.fair |
||
| Zeile 769: | Zeile 1.426: | ||
-- 1 -- language version specifier to be supported |
-- 1 -- language version specifier to be supported |
||
-- 2 -- language specifier of a possible replacement |
-- 2 -- language specifier of a possible replacement |
||
local |
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 |
||
| Zeile 778: | Zeile 1.442: | ||
-- Retrieve language code from language name |
-- Retrieve language code from language name |
||
-- 1 -- name in current project language |
-- 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 ] |
|||
if r then |
|||
r = Multilingual.fix( mw.text.trim( r ) ) |
|||
end |
|||
return r or "" |
|||
end -- p.fix |
|||
| Zeile 819: | Zeile 1.494: | ||
-- Retrieve base language from possibly combined ISO language code |
-- Retrieve base language from possibly combined ISO language code |
||
-- 1 -- code |
-- 1 -- code |
||
local s = mw.text.trim( frame.args[ 1 ] or "" ) |
|||
return Multilingual.getBase( s ) or "" |
|||
end -- p.getBase |
end -- p.getBase |
||
| Zeile 831: | Zeile 1.507: | ||
-- * -- native |
-- * -- native |
||
-- any valid code |
-- any valid code |
||
local s = mw.text.trim( frame.args[ 1 ] or "" ) |
|||
local slang = frame.args[ 2 ] |
local slang = frame.args[ 2 ] |
||
local r |
local r |
||
Multilingual.frame = frame |
|||
if slang then |
if slang then |
||
slang = mw.text.trim( slang ) |
slang = mw.text.trim( slang ) |
||
end |
end |
||
r = Multilingual.getName( |
r = Multilingual.getName( s, slang ) |
||
return r or "" |
return r or "" |
||
end -- p.getName |
end -- p.getName |
||
| Zeile 888: | Zeile 1.566: | ||
-- Could this be an ISO language code? |
-- Could this be an ISO language code? |
||
-- 1 -- code |
-- 1 -- code |
||
local |
local s = mw.text.trim( frame.args[ 1 ] or "" ) |
||
local lucky, r = pcall( Multilingual.isLang, s ) |
|||
return r and "1" or "" |
return r and "1" or "" |
||
end -- p.isLang |
end -- p.isLang |
||
| Zeile 898: | Zeile 1.576: | ||
-- Could this be a Wiki language version? |
-- Could this be a Wiki language version? |
||
-- 1 -- code |
-- 1 -- code |
||
-- Returns non-empty, if possibly language version |
|||
local lucky, r = pcall( Multilingual.isLangWiki, |
|||
local s = mw.text.trim( frame.args[ 1 ] or "" ) |
|||
local lucky, r = pcall( Multilingual.isLangWiki, s ) |
|||
return r and "1" or "" |
return r and "1" or "" |
||
end -- p.isLangWiki |
end -- p.isLangWiki |
||
| Zeile 905: | Zeile 1.584: | ||
p. |
p.isRTL = function ( frame ) |
||
-- Check whether language is written right-to-left |
|||
-- Kann man mit diesem Sprachcode deutsch verstehen? |
|||
-- 1 -- code |
-- 1 -- string, with language code |
||
-- Returns non-empty, if right-to-left |
|||
local r = Multilingual.fallback( frame.args[ 1 ], "de" ) |
|||
local s = mw.text.trim( frame.args[ 1 ] or "" ) |
|||
return Multilingual.isRTL( s ) and "1" or "" |
|||
end -- p.kannDeutsch |
|||
end -- p.isRTL() |
|||
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 |
|||
| Zeile 917: | Zeile 1.636: | ||
-- Which language does the current user prefer? |
-- Which language does the current user prefer? |
||
-- 1 -- space separated list of available ISO 639 codes |
-- 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 |
|||
-- 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 |
|||
| Zeile 937: | Zeile 1.678: | ||
end |
end |
||
end |
end |
||
return |
return Failsafe.failsafe( since ) or "" |
||
end -- p.failsafe() |
end -- p.failsafe() |
||
Aktuelle Version vom 30. September 2022, 21:11 Uhr
Die Dokumentation für dieses Modul kann unter Modul:Multilingual/Doku erstellt werden
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.
* fair()
* fallback()
* findCode()
* fix()
* format()
* getBase()
* getLang()
* getName()
* i18n()
* int()
* isLang()
* isLangWiki()
* isMinusculable()
* isRTL()
* message()
* sitelink()
* tabData()
* userLang()
* userLangCode()
* wikibase()
* failsafe()
loadData: Multilingual/config Multilingual/names
]=]
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 }
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 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()
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
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.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.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
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()
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.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.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
return p