Module:Multilingual description/sort/testcases
Appearance
Ordered by direction (all LTR scripts first, then RTL scripts), then by script, then alphabetically (by name) in each script.
- Latin, Latin or Cyrillic, Cyrillic, Greek, Other LTR alphabets, Indic, Other South Asian, Syllabaries, Hangul, Japanese scripts, Sinograms, vertical scripts (rendered horizontally LTR, unless explicitly rotated by style), (RTL) Hebrew, Arabic, Divehi, N'Ko.
You can see a comprehensive test of rendering (and other checks) of language codes and native names on Module talk:Multilingual description/sort/testcases: the table will be sorted accordingly (If you see green rows at the bottom, there are missing languages to add into this sort list).
Additionally you should map the writing directions ("rtl" or "ltr") of all these languages in Module:Dir/RTL overrides to avoid fallbacks to a costly MediaWiki API (if it knows the language) or a last-chance fallback to "ltr" (which may be incorrect).
local p = {}
local char = string.char
local floor = math.floor
local insert = table.insert
local ustring = require('mw.ustring')
local sub = ustring.sub
local upper = ustring.upper
local lower = ustring.lower
local format = string.format
local langs = require('Module:Multilingual description/sort')
local dir = require('Module:Dir')
local function toUTF8(code)
-- Note: this function is stricter than the builtin function of the Lua library, but it
-- detects without error invalid codes (which are "escaped" insterad of returning an error)
if code >= 0 and code == floor(code) then
if code <= 0x7F then -- use 1-byte UTF-8 for ASCII (including C0 controls)
return char(code)
elseif code <= 0x7FF then -- use 2-byte UTF-8 for characters in the lowest alphabetic part of the BMP (C1 controls, generic diacritics, and most frequently used characters for Latin, Greek, Cyrillic, Armenian, Hebrew, Arabic, Syriac, Thaana or N'Ko scripts)
return char(0xC0 + floor(code / 64)) .. char(0x80 + code % 64)
elseif code <= 0xFFFF then -- use 3-byte UTF-8 for the rest of the BMP
if code <= 0xD7FF
or code >= 0xE000 and code <= 0xFFCF
or code >= 0xFFF0 and code <= 0xFFFD then -- (excluding surrogate code points and non-characters)
return char(0xE0 + floor(code / 64 / 64)) .. char(0x80 + floor(code / 64) % 64) .. char(0x80 + code % 64)
end
elseif code <= 0x10FFFF then -- use 4-byte UTF-8 for supplementary characters
if code % 0x10000 <= 0xFFFD then -- (excluding non-characters)
return char(0xF0 + floor(code / 64 / 64 / 64)) .. char(0x80 + floor(code / 64 / 64) % 64) .. char(0x80 + floor(code / 64) % 64) .. char(0x80 + code % 64)
end
end
end
return format('&U%04X;', code) -- not a valid Unicode code point, or non-character
end
local nce = { -- used in the first pass of htmlize(wikitext) for converting some known named character entities to UTF-8
quot = '"',
amp = '&',
apos = "'",
lt = '<',
gt = '>',
nbsp = toUTF8(0xA0),
shy = toUTF8(0xAD),
enquad = toUTF8(0x2000),
emquad = toUTF8(0x2001),
ensp = toUTF8(0x2002),
emsp = toUTF8(0x2003),
emsp13 = toUTF8(0x2004),
emsp14 = toUTF8(0x2005),
emsp16 = toUTF8(0x2006),
numsp = toUTF8(0x2007),
puncsp = toUTF8(0x2008),
thinsp = toUTF8(0x2009),
hairsp = toUTF8(0x200A),
zwsp = toUTF8(0x200B),
zwnj = toUTF8(0x200C),
zwj = toUTF8(0x200D),
lrm = toUTF8(0x200E),
rlm = toUTF8(0x200F),
lsep = toUTF8(0x2028),
psep = toUTF8(0x2029),
lre = toUTF8(0x202A),
rle = toUTF8(0x202B),
pdf = toUTF8(0x202C),
lro = toUTF8(0x202D),
rlo = toUTF8(0x202E),
nnbsp = toUTF8(0x202F),
mathsp = toUTF8(0x205F),
wj = toUTF8(0x2060), NoBreak = toUTF8(0x2060),
lri = toUTF8(0x2066),
rli = toUTF8(0x2067),
fsi = toUTF8(0x2068),
pdi = toUTF8(0x2069),
iss = toUTF8(0x206A),
ass = toUTF8(0x206B),
iafs = toUTF8(0x206C),
aafs = toUTF8(0x206D),
natds = toUTF8(0x206E),
nomds = toUTF8(0x206F),
idsp = toUTF8(0x3000),
zwnbsp = toUTF8(0xFEFF),
}
local codemap = { -- will generate a stringmap used in the second pass htmlize(wikitext) for visual sanity check of the UTF-8 encoding of isolated characters
-- Indexed by Unicode codepoint:
-- Non-ASCII codepoints will be added to a stringmap (from their multibyte UTF-8 encoding), in an unspecified order of code point values, to replace them first by visual strings.
-- ASCII codepoints will be converted using a single character pattern, after mapping all other non-ASCII codepoints from this table.
[0x00] = '&U0000;', -- <control> <NUL> invalid in HTML (%z class in patterns)
[0x01] = '&U0001;', -- <control> <SOH> invalid in HTML
[0x02] = '&U0002;', -- <control> <STX> invalid in HTML
[0x03] = '&U0003;', -- <control> <ETX> invalid in HTML
[0x04] = '&U0004;', -- <control> <EOT> invalid in HTML
[0x05] = '&U0005;', -- <control> <ENQ> invalid in HTML
[0x06] = '&U0006;', -- <control> <ACK> invalid in HTML
[0x07] = '&U0007;', -- <control> <BEL> '\a' invalid in HTML
[0x08] = '&U0008;', -- <control> <BS> '\b' invalid in HTML
[0x09] = '	', -- <control> <HT> '\t' valid in HTML (use source form, can be interpreted)
[0x0A] = ' ', -- <control> <LF> '\n' valid in HTML (use source form, can be interpreted)
[0x0B] = '&U000B;', -- <control> <VT> '\v' invalid in HTML
[0x0C] = '&U000C;', -- <control> <FF> '\f' invalid in HTML
[0x0D] = ' ', -- <control> <CR> '\r' valid in HTML (use source form, can be interpreted)
[0x0E] = '&U000E;', -- <control> <SO> invalid in HTML
[0x0F] = '&U000F;', -- <control> <SI> invalid in HTML
[0x10] = '&U0010;', -- <control> <DLE> invalid in HTML
[0x11] = '&U0011;', -- <control> <DC1> invalid in HTML
[0x12] = '&U0012;', -- <control> <DC2> invalid in HTML
[0x13] = '&U0013;', -- <control> <DC3> invalid in HTML
[0x14] = '&U0014;', -- <control> <DC4> invalid in HTML
[0x15] = '&U0015;', -- <control> <NAK> invalid in HTML
[0x16] = '&U0016;', -- <control> <SYN> invalid in HTML
[0x17] = '&U0017;', -- <control> <ETB> invalid in HTML
[0x18] = '&U0018;', -- <control> <CAN> invalid in HTML
[0x19] = '&U0019;', -- <control> <EM> invalid in HTML
[0x1A] = '&U001A;', -- <control> <SUB> invalid in HTML
[0x1B] = '&U001B;', -- <control> <ESC> '\E' invalid in HTML
[0x1C] = '&U001C;', -- <control> <FS> invalid in HTML
[0x1D] = '&U001D;', -- <control> <GS> invalid in HTML
[0x1E] = '&U001E;', -- <control> <RS> invalid in HTML
[0x1F] = '&U001F;', -- <control> <US> invalid in HTML
[0x20] = ' ', -- make sure it is visible and not stripped (use source form, can be interpreted)
[0x22] = '"', -- '"' HTML escape
[0x26] = '&', -- '&' HTML escape
[0x3C] = '<', -- '<' HTML escape
[0x3E] = '>', -- '>' HTML escape
[0x5B] = '[', -- '[' Wiki escape
[0x5C] = '\\\\', -- '\\' make sure it is distinguished visually from an escape for invalid controls in HTML
[0x5D] = ']', -- ']' Wiki escape
[0x7B] = '{', -- '{' Wiki escape
[0x7C] = '|', -- '|' Wiki escape
[0x7D] = '}', -- '}' Wiki escape
[0x7F] = '&U007F;', -- <control> <DEL> invalid in HTML
[0x80] = '&U0080;', -- <control> <PAD> invalid in HTML
[0x81] = '&U0081;', -- <control> <HOP> invalid in HTML
[0x82] = '&U0082;', -- <control> <BPH> invalid in HTML
[0x83] = '&U0083;', -- <control> <NBH> invalid in HTML
[0x84] = '&U0084;', -- <control> <IND> invalid in HTML
[0x85] = '…', -- <control> <NEL> valid in HTML
[0x86] = '&U0086;', -- <control> <SSA> invalid in HTML
[0x87] = '&U0087;', -- <control> <ESA> invalid in HTML
[0x88] = '&U0088;', -- <control> <HTS> invalid in HTML
[0x89] = '&U0089;', -- <control> <HTJ> invalid in HTML
[0x8A] = '&U008A;', -- <control> <LTS> invalid in HTML
[0x8B] = '&U008B;', -- <control> <PLD> invalid in HTML
[0x8C] = '&U008C;', -- <control> <PLU> invalid in HTML
[0x8D] = '&U008D;', -- <control> <RI> invalid in HTML
[0x8E] = '&U008E;', -- <control> <SS2> invalid in HTML
[0x8F] = '&U008F;', -- <control> <SS3> invalid in HTML
[0x90] = '&U0090;', -- <control> <DCS> invalid in HTML
[0x91] = '&U0091;', -- <control> <PU1> invalid in HTML
[0x92] = '&U0092;', -- <control> <PU2> invalid in HTML
[0x93] = '&U0093;', -- <control> <STS> invalid in HTML
[0x94] = '&U0094;', -- <control> <CCH> invalid in HTML
[0x95] = '&U0095;', -- <control> <MW> invalid in HTML
[0x96] = '&U0096;', -- <control> <SPA> invalid in HTML
[0x97] = '&U0097;', -- <control> <EPA> invalid in HTML
[0x98] = '&U0098;', -- <control> <SOS> invalid in HTML
[0x99] = '&U0099;', -- <control> <SGCI> invalid in HTML
[0x9A] = '&U009A;', -- <control> <SCI> invalid in HTML
[0x9B] = '&U009B;', -- <control> <CSI> invalid in HTML
[0x9C] = '&U009C;', -- <control> <ST> invalid in HTML
[0x9D] = '&U009D;', -- <control> <OSC> invalid in HTML
[0x9E] = '&U009E;', -- <control> <PM> invalid in HTML
[0x9F] = '&U009F;', -- <control> <APC> invalid in HTML
[0xA0] = ' ', -- <NON-BREAKING SPACE> HTML escape
[0xAD] = '­', -- <SOFT HYPHEN> HTML escape
[0x2000] = '&enquad;', -- <EN QUAD> HTML escape
[0x2001] = '&emquad;', -- <EN QUAD> HTML escape
[0x2002] = ' ', -- <EN SPACE> HTML escape
[0x2003] = ' ', -- <EM SPACE> HTML escape
[0x2004] = ' ', -- <THREE-PER-EM SPACE> HTML escape
[0x2005] = ' ', -- <FOUR-PER-EM SPACE> HTML escape
[0x2006] = '&emsp16;', -- <SIX-PER-EM SPACE> HTML escape
[0x2007] = ' ', -- <FIGURE SPACE> HTML escape
[0x2008] = ' ', -- <PUNCTUATION SPACE> HTML escape
[0x2009] = ' ', -- <THIN SPACE> HTML escape
[0x200A] = ' ', -- <HAIRY SPACE> HTML escape
[0x200B] = '&zwsp;', -- <ZERO-WIDTH SPACE> HTML escape
[0x200C] = '‌', -- <ZERO-WIDTH NON-JOINER> HTML escape
[0x200D] = '‍', -- <ZERO-WIDTH JOINER> HTML escape
[0x200E] = '‎', -- <LEFT TO RIGHT MARK> HTML escape (deprecated)
[0x200F] = '‏', -- <RIGHT TO LEFT MARK> HTML escape (deprecated)
[0x2028] = '&lsep;', -- <LINE SEPARATOR> HTML escape
[0x2029] = '&psep;', -- <PARAGRAPH SEPARATOR> HTML escape
[0x202A] = '&lre;', -- <LEFT-TO-RIGHT EMBEDDING> HTML escape, like <bde dir="ltr"> (deprecated)
[0x202B] = '&rle;', -- <RIGHT-TO-LEFT EMBEDDING> HTML escape, like <bde dir="rtl"> (deprecated)
[0x202C] = '&pdf;', -- <POP DIRECTIONAL FORMATTING> HTML escape, like </bde> or </bdo> (deprecated)
[0x202D] = '&lro;', -- <LEFT-TO-RIGHT OVERRIDE> HTML escape, like <bdo dir="ltr"> (deprecated)
[0x202E] = '&rlo;', -- <RIGHT-TO-LEFT OVERRIDE> HTML escape, like <bdo dir="rtl"> (deprecated)
[0x202F] = '&nnbsp;', -- <NARROW NON-BREAKING SPACE> HTML escape
[0x205F] = '&mathsp;', -- <MATHEMATICAL MEAN SPACE> HTML escape
[0x2060] = '&wj;', -- <WORD JOINER> HTML escape
[0x2066] = '&lri;', -- <LEFT-TO-RIGHT ISOLATE> HTML escape, like <bdi dir="ltr"> (recommended)
[0x2067] = '&rli;', -- <RIGHT-TO-LEFT ISOLATE> HTML escape, like <bdi dir="rtl"> (recommended)
[0x2068] = '&fsi;', -- <FIRST STRONG ISOLATE> HTML escape, like <bdi dir="auto"> or <bdi> (recommended)
[0x2069] = '&pdi;', -- <POP DIRECTIONAL ISOLATE> HTML escape, like </bdi> (recommended)
[0x206A] = '&iss;', -- <INHIBIT SYMMETRIC SWAPPING> HTML escape
[0x206B] = '&ass;', -- <ACTIVATE SYMMETRIC SWAPPING> HTML escape
[0x206C] = '&iafs;', -- <INHIBIT ARABIC FORM SHAPING> HTML escape
[0x206D] = '&aafs;', -- <ACTIVATE ARABIC FORM SHAPING> HTML escape
[0x206E] = '&natds;', -- <NATIONAL DIGIT SHAPES> HTML escape (deprecated)
[0x206F] = '&nomds;', -- <NOMINAL DIGIT SHAPES> HTML escape (deprecated)
[0x3000] = '&idsp;', -- <IDEOGRAPHIC SPACE> HTML escape
[0xFEFF] = '&zwnbsp;', -- <ZERO-WIDTH NON-BREAKING SPACE> HTML escape (deprecated)
[0xFFFC] = '&objr;', -- <OBJECT REPLACEMENT CHARACTER> HTML escape (deprecated)
[0xFFFD] = '&repl;', -- <REPLACEMENT CHARACTER> HTML escape (deprecated)
}
-- There's no way to handle multibyte strings in a single gsub(), because Lua patterns do not support alternation with '|'.
-- Instead we build a character class for fast 1-to-1 substitutions. This only works for single-byte ASCII, not for
-- substituting multibyte UTF-8. For others, we generate separate gsub() patterns.
local charsubst, stringmap = {}, {}
for code, subst in pairs(codemap) do
local pattern = toUTF8(code)
if #pattern == 1 then
charsubst[pattern] = subst
else
pattern = pattern:gsub('^^', '%%^'):gsub('$$', '%%$'):gsub('[%%()*+%-.?%[]','%%%1') -- magic characters in search patterns
subst = subst:gsub('%%', '%%%%') -- magic characters in substitutions
insert(stringmap, { pattern, subst })
end
end
insert(stringmap, { '&' , '&' }) -- HTML escape (standard)
insert(stringmap, { '<' , '<' }) -- HTML escape (standard)
insert(stringmap, { '>' , '>' }) -- HTML escape (standard)
insert(stringmap, { '^ ' , ' ' }) -- Wiki escape (reserved for monospaced line)
insert(stringmap, { "''" , "''" }) -- Wiki escape (reserved for italic or bold styles)
insert(stringmap, { '^!' , '!' }) -- Wiki escape (reserved for table header start)
insert(stringmap, { '!!' , '!!' }) -- Wiki escape (reserved for table header middle)
insert(stringmap, { '^#' , '#' }) -- Wiki escape (reserved for item of numbered lists)
insert(stringmap, { '^%*' , '*' }) -- Wiki escape (reserved for item of bulleted lists)
insert(stringmap, { ':' , ':' }) -- Wiki escape (reserved for definition item of definition list)
insert(stringmap, { '^;' , ';' }) -- Wiki escape (reserved for term item of of definition list)
insert(stringmap, { '^=' , '=' }) -- Wiki escape (reserved for section headings)
insert(stringmap, { "%[" , "[" }) -- Wiki escape (reserved for external links or wikilinks)
insert(stringmap, { "%]" , "\" }) -- Wiki escape (reserved for external links or wikilinks)
insert(stringmap, { "{{" , "{{" }) -- Wiki escape (reserved for transcluding templates, calling parser functions, or replacing a template parameter value)
insert(stringmap, { "^{|" , "{|" }) -- Wiki escape (reserved for tables)
insert(stringmap, { "|" , "|" }) -- Wiki escape (reserved between table cells, or parameters of template transclusion or parser functions)
insert(stringmap, { "}}" , "}}" }) -- Wiki escape (reserved for transcluding templates, calling parser functions, or replacing a template parameter value)
insert(stringmap, { '~~~' , '~~~' }) -- Wiki escape (reserved for user signatures)
local function htmlize(wikitext)
wikitext = wikitext
:gsub('&([#%w]+);', function(s)
if s:sub(1, 1) == '#' then
s = s:sub(2, 2) == 'x' and tonumber(s:sub(3), 16) or tonumber(s:sub(2), 10)
if s ~= nil then return toUTF8(s) end
return nil
end
return nce[s]
end)
:gsub('.', charsubst)
for _, map in ipairs(stringmap) do
wikitext = wikitext:gsub(map[1], map[2])
end
return wikitext
end
function p.test_order()
local names = mw.language.fetchLanguageNames()
local seen, result = {}, {}
insert(result, '<div lang="en" dir="ltr" class="plainlinks" style="font-size:smaller;float:right;margin-left:.5em">[ [' .. mw.getCurrentFrame():preprocess('{{FULLURL:{{FULLPAGENAME}}}}') .. '?action=purge Refresh this page] ]</div>')
insert(result, '<table lang="en" dir="ltr" class="wikitable sortable" style="font-family:\'Noto Sans\',\'Segoe UI\',\'Noto Sans Historic\',\'Segoe UI Historic\',Robo,sans-serif">')
insert(result, '<caption>' ..
'Check display order (native names grouped by direction, script, then sorted in locale-neutral UCA order)<br />' ..
'<small>If you see green lines at bottom of this table, these languages added to MediaWiki are missing in the [[Module:Multilingual description/sort|sort order]] (check also their assigned [[Module:Dir/RTL overrides|direction]])</small>' ..
'</caption>')
-- <thead>
insert(result, '<tr>')
insert(result, '<th scope="col">#</th>')
insert(result, '<th scope="col">Code</th>')
insert(result, '<th scope="col">Valid<br />Code,<br /> Valid<br />BuiltIn<br />Code?')
insert(result, '<th scope="col">Known<br /> Language<br/> Tag <small>(by</br> <code>{{#language:|en}}</code>)</small></th>')
insert(result, '<th scope="col">Native<br /> language<br />name?</th>')
insert(result, '<th scope="col">Direction, <br /> Sorting<br /> initial<br/> <small>(uppercased)</small></th>')
insert(result, '<th scope="col">Native name<br /> <small>(lowercase initial is often preferred)</small></th>')
insert(result, '<th scope="col">Full<br /> localisation<br /> supported?</th>')
insert(result, '<th scope="col">Known fallbacks<br/> <small>(on this wiki)</small></th>')
insert(result, '<th scope="col">English name (HTML-encoded)<br /> <ul style="text-align:left;font-size:smaller"><li>Yellow: same as native?<br /> <small>(not necessarily wrong)</small></li><li>Red: non-Basic Latin, incorrect encoding or missing data<br /> <small>(report bug in MediaWiki #language)</small></li></ul></th>')
insert(result, '</tr>')
-- </thead>
-- <tbody>
local bgOrange, bgRed, bgYellow, bgWhite =
'background:#8F0;color:#000',
'background:#FCC;color:#000',
'background:#FFC;color:#000',
'background:#F7F8FF;color:#202122'
local rank = 0
for _,lang in pairs(langs) do
if type(lang) == 'string' then
rank = rank + 1
local nameStatus = 'OK'
local validCode = mw.language.isValidCode(lang)
local validBuiltInCode = mw.language.isValidBuiltInCode(lang)
local knownLanguageTag = mw.language.isKnownLanguageTag(lang)
local englishName = mw.language.fetchLanguageName(lang, 'en')
if seen[lang] then
nameStatus = '<b>Duplicate code</b>'
else
seen[lang] = true
nativeName = names[lang]
if nativeName == nil then
nameStatus = '<b>No</b>'
nativeName = mw.language.fetchLanguageName(lang)
end
end
local nativeDir = dir.select(lang, 'rtl', 'ltr')
local initialLetter = sub(upper(lower(nativeName)), 1, 1)
local supportedLanguage = mw.language.isSupportedLanguage(lang)
--
insert(result, '<tr style="' .. (supportedLanguage and bgWhite or knownLanguageTag and bgYellow or bgRed) .. '>')
insert(result, '<th scope="row" style="text-align:right">' .. rank .. '</th>')
insert(result, '<td><code>' .. lang .. '</code></td>')
insert(result, '<td style="text-align:center">' .. (validCode and 'Yes' or '<b>No</b>') ..
', ' .. (validBuiltInCode and 'Yes' or '<b>No</b>') .. '</td>')
insert(result, '<td style="text-align:center">' .. (knownLanguageTag and 'Yes' or '<b>No</b>') .. '</td>')
insert(result, '<td style="text-align:center">' .. nameStatus .. '</td>')
insert(result, '<td style="text-align:center">' .. nativeDir .. ', ' .. initialLetter .. '</td>')
insert(result, '<td dir="' .. nativeDir .. '">' .. nativeName .. '</td>')
insert(result, '<td style="text-align:center">' .. (supportedLanguage and 'Yes' or '<b>No</b>') .. '</td>')
insert(result, '<td><code>' .. table.concat(mw.language.getFallbacksFor(lang), ', ') .. '</code></td>')
insert(result, '<td style="' ..
(nativeName == englishName and (englishName:find("^[A-Z][ '()%-/0-9A-Za-z]*['()%-/0-9A-Za-z]$") and bgYellow or bgRed)
or bgWhite) .. '">' .. htmlize(englishName) .. '</td>')
insert(result, '</tr>')
end
end
-- Other languages not seen
langs = {}
for lang, _ in pairs(names) do
if not seen[lang] then
insert(langs, lang)
end
end
table.sort(langs, function(lang1, lang2)
return upper(lower(names[lang1])) < upper(lower(names[lang2]))
end)
for _, lang in pairs(langs) do
if type(lang) == 'string' then
rank = rank + 1
local nameStatus = '<b>Still not sorted</b>'
local validCode = mw.language.isValidCode(lang)
local validBuiltInCode = mw.language.isValidBuiltInCode(lang)
local knownLanguageTag = mw.language.isKnownLanguageTag(lang)
local englishName = mw.language.fetchLanguageName(lang, 'en')
local nativeName = names[lang]
local nativeDir = dir.select(lang, 'rtl', 'ltr')
local initialLetter = sub(upper(lower(nativeName)), 1, 1)
local supportedLanguage = mw.language.isSupportedLanguage(lang)
--
insert(result, '<tr style="' .. (supportedLanguage and bgOrange or knownLanguageTag and bgYellow or bgRed) .. '">')
insert(result, '<th scope="row" style="text-align:right">' .. rank .. '</th>')
insert(result, '<td><code>' .. lang .. '</code></td>')
insert(result, '<td style="text-align:center">' .. (validCode and 'Yes' or '<b>No</b>') ..
', ' .. (validBuiltInCode and 'Yes' or '<b>No</b>') .. '</td>')
insert(result, '<td style="text-align:center">' .. (knownLanguageTag and 'Yes' or '<b>No</b>') .. '</td>')
insert(result, '<td style="text-align:center">' .. nameStatus .. '</td>')
insert(result, '<td style="text-align:center">' .. nativeDir .. ', ' .. initialLetter .. '</td>')
insert(result, '<td dir="' .. nativeDir .. '">' .. nativeName .. '</td>')
insert(result, '<td style="text-align:center">' .. (supportedLanguage and 'Yes' or '<b>No</b>') .. '</td>')
insert(result, '<td><code>' .. table.concat(mw.language.getFallbacksFor(lang), ', ') .. '</code></td>')
insert(result, '<td style="' ..
(nativeName == englishName and (englishName:find("^[A-Z][ '()%-/0-9A-Za-z]*['()%-/0-9A-Za-z]$") and bgYellow or bgRed)
or bgWhite) .. '">' .. htmlize(englishName) .. '</td>')
insert(result, '</tr>')
end
end
-- </tbody>
insert(result, '</table>')
return table.concat(result)
end
-- Tricky test functions, needed during search of solutions for the severly limited methods of MediaWiki "frame" objects
-- that now no longer not support any kind of expansion for MediaWiki special tags (except "nowiki" tags).
-- May be we'll have some Lua extension library for supporting some special tags (such libraries exist now for Wikidata, and for "#expr").
local function show(title, text)
return '<b>' .. title .. ':</b> "<tt>' .. htmlize(text) .. '</tt>"'
end
function p.test_prefix(...)
local args = { ... }
local frame
if type(args[1]) == 'table' and type(args[1].args) == 'table' and type(args[1].getParent) == 'function' then
frame = args[1]
local pframe = frame:getParent() or frame
local args = frame.args or pframe.args or {}
else
frame = mw.getCurrentFrame()
end
local text = args.text or ''
local preprocessed = frame:preprocess(text)
local expanded = mw.text.unstrip(preprocessed)
return show('text', text) .. ',<br /> '
.. show('preprocessed', preprocessed) .. ',<br /> '
.. show('expanded', expanded) .. '.'
end
--p.test_tag(frame) -- {{#invoke:...|test_tag|1=tag|2=content|option1=value1|option2=value2...}}
--p.test_tag('tag','content')
--p.test_tag{'tag','content'}
--p.test_tag('tag', nil, { option1 = "value1", option2 = "value2"... })
--p.test_tag('tag','content', { option1 = "value1", option2 = "value2"... })
--p.test_tag{'tag', option1 = "value1", option2 = "value2"... }
--p.test_tag{'tag','content', option1 = "value1", option2 = "value2"... }
function p.test_tag(...)
local args = { ... }
local frame
if type(args[1]) == 'table' and type(args[1].args) == 'table' and type(args[1].getParent) == 'function' then
frame = args[1]
local pframe = frame:getParent() or frame
local args = frame.args or pframe.args or {}
else
frame = mw.getCurrentFrame()
end
local tag, content = args[1] or '', args[2] or ''
if type(tag) == 'table' then
args = tag
tag, content = args[1] or '', args[2] or ''
table.remove(args, 2)
table.remove(args, 1)
elseif type(args[3]) == 'table' then
args = args[3]
else
table.remove(args, 2)
table.remove(args, 1)
end
local text = '{{#tag:' .. tag .. '|' .. content
for k, v in pairs(args) do
if type(v) == 'string' or type(v) == 'number' then
text = text .. '|' .. k .. '=' .. v
end
end
text = text .. '}}'
local preprocessed = frame:extensionTag{name=tag, content=content, args=args}
local expanded = mw.text.unstrip(preprocessed)
return show('text', text) .. ',<br /> '
.. show('preprocessed', preprocessed) .. ',<br /> '
.. show('expanded', expanded) .. '.'
end
return p