Module:Multilang module tools
Documentation for this module may be created at Module:Multilang module tools/doc
local p = {}
--Version 2020-07-10
local SA = require "Module:SimpleArgs"
local SD = require "Module:SimpleDebug"
local WD = require "Module:Wikidades"
----------------------------------------
p.prior_key = ''
function p.ChkFunc (func_name, params)
--Used in debug of a function, where:
--params is a parameter table, where each item is {name, value, type}
--the type can be any of the following in the table and integer ("i") or non-empty string ("x")
--adding "r", then the parameter is required.
local types = {
["b"] = 'boolean',
["f"] = 'function',
["n"] = 'number',
["s"] = 'string', --string with a values or not
["t"] = 'table',
}
for i, par in ipairs(params) do
local req = false
if (par[1] == '') or (par[3] == '') then
error ('Incomplete call to ChkFunc in #'..i..' parameter of '..func_name)
end
if string.len (par[3]) == 2 then
par[3] = string.sub (par[3], 1, 1)
req = true
end
local typ = par[3]
function mess_begin ()
return 'In a call to "'..func_name..'" parameter #'..i..' (= "'..par[1]..'")'
end
if typ == 'a' then --any
if req and (par[2] == nil) then
error (mess_begin ()..' must have a value', 0)
end
elseif typ == 'k' then -- a key = string with a value
local key = par[2]
if (key == nil) or (key == '') or (type(key) ~= 'string') then
if p.prior_key == '' then
error (mess_begin()..', not set (or correctly typed) a key, perhaps, the call from first key') --Don't translate, for debug
else
error (mess_begin()..', not set (or correctly typed) a key after the key "'..p.prior_key..'", or, perhaps, the call from the first key') --Don't translate, for debug
end
else
p.prior_key = key
end
elseif typ == 'x' then -- a string with a value
if par[2] == nil then
if req then
error (mess_begin ()..' must have a string', 0)
end
elseif par[2] == "" then
error (mess_begin ()..' must have a non-empty string', 0)
end
else
if typ == 'i' then
typ = 'n'
end
local t = types[typ]
function error_mes (mes)
error (mess_begin ()..' must be a '..t..', but '..mes, 0)
end
if req and (par[2] == nil) then
error_mes ('not found a value')
elseif par[2] ~= nil then
if type(par[2]) ~= t then
SD.vtos (par[2])
error_mes ('found '..SD.s)
elseif par[3] == 'i' then
if par[2] ~= math.floor(par[2]) then
t = 'integer number'
error_mes ('found '..par[2])
end
end
end
end
end
end -- ChkFunc
----------------------------------------
local RS = {
DuplicateArgs = 'DuplicateArgs',
}
local i18n = {
[RS.DuplicateArgs]= "Duplicate parameters:",
}
i18n = SA.loadI18n ('Multilang module tools', i18n)
p.arg = {
demo = 'demo',
item = 'item',
lang = 'lang',
}
function p.DemoItemLang()
return {p.arg.demo, p.arg.item, p.arg.lang}
end
p.k = { --labels to define translatable strings
Args = 'Args', --arguments or parameters
Labels = 'Labels', --text to display usually
MsgError = 'MsgError', --warning or information or error messages contains the next
Msgs = 'Msgs', --warning or information messages
Errors = 'Errors', --error messages
}
SA.OKEmptyVal = false -- Empty values ("") = nil.
----------------------------------------
--Language functions
----------------------------------------
p.lang = nil -- Used for demos for other languages.
p.compare_lang = 'en'
p.LangIsRTL = nil
local LangsDifDirect = false
local WDirect = 'ltr'
function p.SetLang (args)
local lang_now = args[p.arg.lang]
if lang_now ~= nil then
SA.lang_to_use = SA.get_lang (lang_now)
end
end --SetLang
function p.LangsDifWriteDirect ()
return LangsDifDirect
end
function p.WriteDirect ()
return WDirect
end
local function _IsRTL (lang)
return mw.getLanguage(lang):getDir() == 'rtl'
end
function p.IsRTL (frame)
local args, NArgs = SA.GetArgs (frame)
local lang = SA.RStr_Par (args, 1)
return _IsRTL (lang)
end --IsRTL
function p.IniLang (frame, args)
p.lang = SA.Str_Par (args, p.arg.lang)
local CurrLang = mw.language.getContentLanguage().code
if p.lang == nil or (p.lang == CurrLang) then
p.LangIsRTL = _IsRTL (CurrLang)
elseif (p.lang ~= nil) and (p.lang ~= CurrLang) then
p.LangIsRTL = _IsRTL (p.lang)
local ContentLangIsRTL = _IsRTL (CurrLang)
if p.LangIsRTL then
WDirect = 'rtl'
end
LangsDifDirect = p.LangIsRTL ~= ContentLangIsRTL
end
end --IniLang
----------------------------------------
local error_t = {}
local dupli_args = {}
----------------------------------------
function p.SendErrors (errors)
if errors ~= nil then
for _, i in ipairs(errors) do
table.insert (error_t, i)
end
end
end --SendErrors
function p.CheckParams (args, ArgsPoss, OtherArgs, SetArgs, ArgNamesIn1)
local errors, dupli
if SetArgs then
ArgsPoss2 = {}
for i, v in ipairs(ArgsPoss) do
if ArgsPoss[i][p.k.Args] == nil then
SD.vtos (ArgsPoss)
error ('Expected table without "'..p.k.Args..'":</br>'..SD.s)
end
table.insert (ArgsPoss2, ArgsPoss[i][p.k.Args])
end
errors, dupli = SA.CheckParamsM (args, ArgsPoss2, OtherArgs, ArgNamesIn1)
else
errors, dupli = SA.CheckParamsM (args, ArgsPoss, OtherArgs, ArgNamesIn1)
end
if SA.Error.handle then
p.SendErrors (errors)
if dupli ~= nil then
for _, i in ipairs(dupli) do
table.insert (dupli_args, i)
end
end
end
end --CheckParams
----------------------------------------
function p.MN (ModuleName)
return '[[Module:'..ModuleName..']]'
end
function p.MNi18n (ModuleName)
return p.MN (ModuleName..'/i18n')
end
function p.MNi (ModuleName)
return p.MN (ModuleName..'/items')
end
----------------------------------------
local function exists_in_tab_main (ModuleName, key, tab_main, what)
if tab_main[key] == nil then
error ('Not found "'..key..'" in items table (of '..p.MN(ModuleName)..'), as '..what, 0) --for debug, don't translate
end
end --exists_in_tab_main
local function correct_tab_main (ModuleName, key, tab_main, n, for_what)
if (n == 1) and (type(tab_main[key]) == 'table') then
SD.vtos (tab_main[key])
error ('Invalid items table (from '..p.MN(ModuleName)..') for key "'..key..'". No tables allowed'..for_what..' (now = '..SD.s..')', 0)
elseif (n == 2) and (type(tab_main[key]) ~= 'table') then
error ('Invalid items table (from '..p.MN(ModuleName)..') for key "'..key..'". Table is required'..for_what..' (only = '..tab_main[key]..')', 0)
end
end --correct_tab_main
local function exists_in_tab_main_1_to_1or2 (ModuleName, key, tab_main, tab_lang, n) --for debug, don't translate
local for_what = ' for a label or message!'
exists_in_tab_main (ModuleName, key, tab_main, 'label or message key')
if type(tab_lang[key]) == 'table' then
SD.vtos (tab_lang[key])
error ('Invalid items table (from '..p.MNi18n(ModuleName)..') for key '..key..'. No tables allowed'..for_what..' (now = '..SD.s..')', 0)
else
correct_tab_main (ModuleName, key, tab_main, n, for_what)
end
end --exists_in_tab_main_1_to_1or2
local function exists_in_tab_main_1or2 (ModuleName, key, tab_main, n) --for debug, don't translate
exists_in_tab_main (ModuleName, key, tab_main, 'parameter key')
end
local function tableMergeReplace (ModuleName, tab_main, tab_lang)
for k, v in pairs(tab_lang) do
exists_in_tab_main_1_to_1or2 (ModuleName, k, tab_main, tab_lang, 1)
if v ~= '' then
tab_main[k] = v
end
end
return tab_main
end --tableMergeReplace
local function tableMergeReplace1 (ModuleName, tab_main, tab_lang)
for k, v in pairs(tab_lang) do
exists_in_tab_main_1_to_1or2 (ModuleName, k, tab_main, tab_lang, 2)
if v ~= '' then
tab_main[k][1] = v
end
end
return tab_main
end --tableMergeReplace1
local function tableMergeAppend (ModuleName, tab_main, tab_lang)
for k, v in pairs(tab_lang) do
exists_in_tab_main_1or2 (ModuleName, k, tab_main, 1)
if v == '' then
else
found = {}
local tab = {}
if type(v) == "table" then
tab = v
for kk, vv in ipairs(v) do
found[vv] = 0
end
else
table.insert (tab, v)
found[v] = 0
end
local n = tab_main[k]
function perhapsAdd (s)
if found[s] == nil then
found[s] = 0
table.insert (tab, s)
end
end
if type(n) == "table" then
for _,vv in pairs(n) do
perhapsAdd (vv)
end
else
perhapsAdd (n)
end
tab_main[k] = tab
end
end
return tab_main
end --tableMergeAppend
local function tableMergeAppend1 (ModuleName, tab_main, tab_lang)
for k, v in pairs(tab_lang) do
exists_in_tab_main_1or2 (ModuleName, k, tab_main, 2)
if v == '' then
else
found = {}
local tab = {}
if type(v) == "table" then
tab = v
for kk, vv in ipairs(v) do
found[vv] = 0
end
else
table.insert (tab, v)
found[v] = 0
end
local n = tab_main[k][1]
function perhapsAdd (s)
if found[s] == nil then
found[s] = 0
table.insert (tab, s)
end
end
if type(n) == "table" then
for _,vv in pairs(n) do
perhapsAdd (vv)
end
else
perhapsAdd (n)
end
tab_main[k][1] = tab
end
end
return tab_main
end --tableMergeAppend1
function p.tableMerge (ModuleName, tab_main, tab_lang, TargetFirst)
if p.lang == nil then
local z1 = SA.deep_copy_table (tab_main)
local z2 = SA.deep_copy_table (tab_lang)
if z1[p.k.Args][SA.HasChild] then
for x, v in pairs(tab_lang[p.k.Args]) do
if x ~= SA.HasChild then
if TargetFirst == true then
z1[p.k.Args][x] = tableMergeAppend1 (ModuleName, z1[p.k.Args][x], z2[p.k.Args][x])
else
z1[p.k.Args][x] = tableMergeAppend (ModuleName, z1[p.k.Args][x], z2[p.k.Args][x])
end
end
end
else
if TargetFirst == true then
z1[p.k.Args] = tableMergeAppend1 (ModuleName, z1[p.k.Args], z2[p.k.Args])
else
z1[p.k.Args] = tableMergeAppend (ModuleName, z1[p.k.Args], z2[p.k.Args])
end
end
for _, wd in pairs(p.k) do --Labels, Msgs and Errors
if wd ~= p.k.Args then
if (z1[wd] ~= nil) and (z2[wd] ~= nil) then
if wd == p.k.MsgError then
for _, v in pairs(tab_lang[p.k.MsgError]) do
z1[p.k.MsgError][v] = tableMergeReplace (ModuleName, z1[p.k.MsgError][v], z2[p.k.MsgError][v])
end
end
z1[wd] = tableMergeReplace (ModuleName, z1[wd], z2[wd])
--[[]
if (wd == p.k.Labels) and (TargetFirst == true) then
z1[wd] = tableMergeReplace1 (ModuleName, z1[wd], z2[wd])
else
z1[wd] = tableMergeReplace (ModuleName, z1[wd], z2[wd])
end
--]]
end
end
end
return z1
else
return tab_main
end
end --tableMerge
function p.SetAttribToArgs (tab, tab_lims)
local tab2
function GetArgType (key)
if key == nil then
return nil
end
if tab2 ~= nil then
for iv, v in ipairs(tab2) do
if v[1] == key then
table.remove (tab2, iv)
return v[2]
end
end
end
return p.IT.s
end --GetArgType
function For1(tab_h)
local Args = {}
for j, k in pairs(tab_h) do
local item = {k}
table.insert (item, GetArgType(j))
Args[j] = item
end
return Args
end
local new_tab = {}
if tab[p.k.Args][SA.HasChild] == nil then
tab2 = SA.deep_copy_table (tab_lims)
local Args = For1(tab[p.k.Args])
new_tab[p.k.Args] = Args
else
local Args = {}
for j, k in pairs(tab[p.k.Args]) do
if j == SA.HasChild then
Args[SA.HasChild] = true -- = Args[j] = k
else
tab2 = SA.deep_copy_table (tab_lims[j])
Args[j] = For1(k)
end
end
new_tab[p.k.Args] = Args
end
new_tab[p.k.Labels] = tab[p.k.Labels]
new_tab[p.k.Msgs] = tab[p.k.Msgs]
new_tab[p.k.Errors] = tab[p.k.Errors]
return new_tab
end --SetAttribToArgs
function p.SetAttribToArgsGr (tab, tab_lims)
--Warning: not to be confused with "Multilang infotable tools.SetAttribToArgsGr"
local new_tab = {}
for j, k in pairs(tab) do
new_tab[j] = p.SetAttribToArgs (tab[j], tab_lims[j])
end
return new_tab
end --SetAttribToArgsGr
----------------------------------------
local function CheckKeyInTab (tab, key) --Only for debug
if tab[p.k.Labels] == nil then
error ('Table not has "'..p.k.Labels..'"')
elseif tab[p.k.Labels][key] == nil then
error ('Not found in table "'..p.k.Labels..'" the key "'..key..'"')
end
end --CheckKeyInTab
function p.GetLabelL (tab, key, lang)
p.ChkFunc ("GetLabelL", {{"tab",tab,"tr"},{"key",key,"k"},{"lang",lang,"s"},})
CheckKeyInTab (tab, key)
key = SA.CheckIsStr (tab[p.k.Labels][key], key)
if string.sub(key,1,1) == '_' then --uses properties (_Pn) or qualifiers (_Qn) from Wikidata to define labels
key = string.sub(key,2)
return WD.getLabel({key, ['lang']=lang}), key
else
return key, ''
end
end --GetLabelL
function p.GetLabel (tab, key)
return p.GetLabelL (tab, key, p.lang)
end
function p.GetLabelX (mod_abbrev, key, tab_main, tab_lang)
local wd_main, lnk = p.GetLabelL (tab_main, key, p.compare_lang)
local wd_lang = tab_lang[p.k.Labels][key]
return mod_abbrev, key, wd_main, wd_lang, lnk
end --GetLabelX
function p.GetLabelL3 (tab, key, lang)
p.ChkFunc ("GetLabelL3", {{"tab",tab,"tr"},{"key",key,"k"},{"lang",lang,"s"},})
local val = tab[p.k.Labels][key]
if val == nil then
return '', ''
else
key = SA.CheckIsStr (tab[p.k.Labels][key], key)
if string.sub(key,1,1) == '_' then --uses properties (_Pn) or qualifiers (_Qn) from Wikidata to define labels
key = string.sub(key,2)
return WD.getLabel({key, ['lang']=lang}), key
else
return key, ''
end
end
end --GetLabelL3
function p.GetLabelL2 (wd_main_l, key)
local key = SA.CheckIsStr (wd_main_l, key)
if string.sub(key,1,1) == '_' then --uses properties (_Pn) or qualifiers (_Qn) from Wikidata to define labels
key = string.sub(key,2)
return WD.getLabel({key, ['lang']=SA.lang_to_use}), key
else
return key, ''
end
end --GetLabelL2
function p.GetMsgErrorX (option, mod_abbrev, key, tab_main, tab_lang)
p.ChkFunc ("GetMsgErrorX", {{"option",option,"xr"},{"mod_abbrev",mod_abbrev,"xr"},
{"key",key,"k"},{"tab_main",tab_main,"tr"},{"tab_lang",tab_lang,"tr"},})
local wd_main = tab_main[option][key]
local wd_lang = tab_lang[option][key]
return mod_abbrev, wd_main, wd_lang
end --GetMsgError
----------------------------------------
function p.IsReserv (key)
p.ChkFunc ("IsReserv", {{"key",key,"xr"},})
return string.sub (key, 1, 3) == 'rs_'
end
function p.GetRequired (key, tab)
if tab ~= nil then
for _, v in ipairs(tab) do
if v == key then
return true
end
end
end
return false
end --GetRequired
function p.GetRequiredGrp (grp, key, tab)
return p.GetRequired (key, tab[grp])
end
p.IT = { --argument types
s = 's', --string
i = 'i', --integer
ipos = 'i+', --positive integer
n = 'n', --number
npos = 'n+', --positive number
d = 'd', --date
b = 'b', --boolean
sz = 'sz', --size
a = 'a', --array
}
local function AlreadyExists (tab, key)
--It cheks if a "key" already exist in tab['Args']
for _, v in pairs(tab[p.k.Args]) do
if type(v[1]) == 'table' then
for _, j in ipairs(v[1]) do
if j == key then
return true
end
end
elseif v[1] == key then
return true
end
end
return false
end --AlreadyExists
function p.split_item_type_req_vals (item_type_req)
if item_type_req == nil then
return p.IT.s, false, nil
else
local item_type = item_type_req
local values = nil
if type(item_type) == 'table' then --when item_type = {'a', {'AM',PM'}} or {'i', {1,10}}
values = item_type[2]
item_type = item_type[1]
end
if item_type == nil then
SD.vtos (item_type_req)
error (SD.s)
end
local required = string.sub (item_type,-1) == 'r'
if required then
item_type = string.sub (item_type, 1, string.len(item_type)-1)
end
return item_type, required, values
end
end --split_item_type_req_vals
function p.split_item_type_req_vals2 (lims, key)
if lims == nil then
return p.IT.s, false, nil
else
return p.split_item_type_req_vals (lims[key])
end
end --split_item_type_req_vals2
function p.split_item_type_req_vals_forList (item_type_req)
item_type, required, values = p.split_item_type_req_vals (item_type_req)
if values ~= nil then
if item_type == p.IT.a then
sep = ', '
else
sep = '-'
end
values = '<small>('..table.concat (values, sep)..')</small>'
end
return item_type, required, values
end --split_item_type_req_vals_forList
function p.item_type_req_vals_prep (item_type_req)
item_type, required, values = p.split_item_type_req_vals_forList (item_type_req)
return p.IT_required_vals (item_type, required, values)
end
function p.split_item_type_req (item_type_req)
local item_type = item_type_req
if type(item_type) == 'table' then --when item_type = {'a', {'AM',PM'}} or {'i', {1,10}}
item_type = item_type[1]
end
local required = string.sub (item_type,-1) == 'r'
if required then
item_type = string.sub (item_type, 1, string.len(item_type)-1)
end
return item_type, required
end --split_item_type_req
function p.InvalidType (type_req)
--It cheks if "type_req" is valid
--if i.g. type_req=='i+r' first it gets 'i+', and second it checks if 'i+' is in "p.IT"
type_req = p.split_item_type_req (type_req)
for _, i in pairs(p.IT) do
if i == type_req then
return false -- = is valid type
end
end
return true
end --InvalidType
function p.ParamVal (args, ParId, arg_type, required, DefVal, params)
--it read a parameter "ParId" (i.g. {'name1',Name1}) of an "arg_type" (according "p.IT") and "required"
--if the parameter isn't found a defaul values is returned
--if there is an error, it is added to the "error_t"
val = nil
if required == true then
if (arg_type == p.IT.s) or (arg_type == p.IT.d) then
val = SA.RStr_Par (args, ParId)
elseif arg_type == p.IT.i then
if params == nil then
val = SA.RInt_Par (args, ParId)
else
val = SA.RInt_Par (args, ParId, params[1], params[2])
end
elseif arg_type == p.IT.ipos then
val = SA.RPosInt_Par (args, ParId)
elseif arg_type == p.IT.n then
if params == nil then
val = SA.RNum_Par (args, ParId)
else
val = SA.RNum_Par (args, ParId, params[1], params[2])
end
elseif arg_type == p.IT.npos then
val = SA.RPosNum_Par (args, ParId)
elseif arg_type == p.IT.b then
val = SA.RBool_Par (args, ParId)
elseif arg_type == p.IT.sz then
val = SA.RSize_Par (args, ParId)
elseif arg_type == p.IT.a then
val = SA.RStrChkTab_Par (args, ParId, params)
end
else
if (arg_type == p.IT.s) or (arg_type == p.IT.d) then
val = SA.Str_Par (args, ParId, DefVal)
elseif arg_type == p.IT.i then
if params == nil then
val = SA.Int_Par (args, ParId)
else
val = SA.Int_Par (args, ParId, nil, params[1], params[2])
end
elseif arg_type == p.IT.ipos then
val = SA.PosInt_Par (args, ParId, DefVal)
elseif arg_type == p.IT.n then
if params == nil then
val = SA.Num_Par (args, ParId, DefVal)
else
val = SA.Num_Par (args, ParId, nil, params[1], params[2])
end
elseif arg_type == p.IT.npos then
val = SA.PosNum_Par (args, ParId, DefVal)
elseif arg_type == p.IT.b then
val = SA.Bool_Par (args, ParId, DefVal)
elseif arg_type == p.IT.sz then
val = SA.Size_Par (args, ParId, DefVal)
elseif arg_type == p.IT.a then
val = SA.StrChkTab_Par (args, ParId, params)
end
end
if SA.Error.yes then
table.insert (error_t, SA.GetAndClearError())
end
return val
end --ParamVal
function p.ErrorMsgs (frame, args, tab)
--if (exists parameter errors) and (in Show Preview mode of infotable)
--it prepare the messages to display them at infobox table
local res_2 = nil
if ((#error_t > 0) or (#dupli_args > 0)) and (frame:preprocess( "{{REVISIONID}}" ) == "") then
local error_str = table.concat (error_t, '</br>')
local dupli_str = ''
if #dupli_args > 0 then
dupli_str = i18n[RS.DuplicateArgs]..' '..table.concat (dupli_args, ', ')
end
local res = {}
if error_str ~= '' then
table.insert (res, error_str)
end
if dupli_str ~= '' then
table.insert (res, dupli_str)
end
res_2 = table.concat (res, '</br>')
end
return res_2, #error_t > 0, #dupli_args > 0
end --ErrorMsgs
----------------------------------------
-- List options and functions
----------------------------------------
local AT_TD = { --TemplateData strings according argument types
[p.IT.s] = 'line',
[p.IT.n] = 'number',
[p.IT.d] = 'date',
[p.IT.b] = 'boolean',
}
p.AT_Read = { --Displayed argument types
[p.IT.s] = 'string',
[p.IT.i] = 'integer',
[p.IT.ipos] = 'positive integer',
[p.IT.n] = 'number',
[p.IT.npos] = 'positive number',
[p.IT.d] = 'date (=string)',
[p.IT.b] = 'boolean',
[p.IT.sz] = 'size',
[p.IT.a] = 'array',
}
local function ConvToTemplateDate (arg)
-- return a valid type for TemplateData
if (arg == p.IT.i) or (arg == p.IT.ipos) or (arg == p.IT.npos) then
return p.IT.n
elseif (arg == p.IT.sz) or (arg == p.IT.a) then
return p.IT.s
else
return arg
end
end --ConvToTemplateDate
local all_items = "allitems"
p.LOpt = { --Display list options, id p.l
list = 'list',
params = 'params',
template = 'template', --TemplateData
labels = 'labels',
msgs = 'msgs',
errors = 'errors',
}
p.with_pos_col = false --if true displays a position column.
p.uses_QP_for_labels = false --if true displays in labels list a column with Qualifiers or Properties of Wikidata for labels
p.with_arg_prop = false --if true displays in labels list a last columns with used properties of Wikidata for load the values.
function p.all_items_opt (args, opt)
return SA.StrChkTab_Par (args, all_items, opt)
end
p.tab_items = {}
local arg_types_used = {}
p.mod_used = {} --modules used, each item: {id, name}
local mod_used_in_class = {} --modules used in arguments or label lists
function p.add_used (tab, wd)
if wd ~= '' then
local found = false
for _, i in ipairs(tab) do
if i == wd then
found = true
break
end
end
if not found then
table.insert (tab, wd)
end
end
return tab
end --p.add_used
function p.add_mod_used (abbrev, name)
table.insert (p.mod_used, {abbrev, name})
end
function p.add_arg_types_used (item_type)
arg_types_used = p.add_used (arg_types_used, item_type)
end
function p.add_mod_used_in_class (item_type)
mod_used_in_class = p.add_used (mod_used_in_class, item_type)
end
local function perhaps_mod_used ()
function lnk (m)
return ' [[Module:'..m[2]..'/i18n]]'
end
if #p.mod_used > 0 then
local S = 'You can change the localizated text in:'
if #p.mod_used == 1 then
S = S..lnk (p.mod_used[1])
else
S = S..'<ul>'
for _, m in ipairs(p.mod_used) do
found = false
for _, m2 in ipairs(mod_used_in_class) do
if m[1] == m2 then
found = true
break
end
end
if found then
S = S..'<li>'..m[1]..':'..lnk(m)..'</li>'
end
end
S = S..'</ul>'
end
table.insert (p.tab_items, S)
end
end --perhaps_mod_used
function p.begin_headers ()
local ini = ''
if #p.mod_used > 1 then
ini = '<th>M.</th>'
end
if p.with_pos_col then
ini = ini..'<th>P.</th>'
end
return ini..'<th>Key</th>'
end --p.begin_headers
function p.append_mod_item (mod_abbrev, res)
if #p.mod_used > 1 then
return '<td>'..mod_abbrev..'</td>'..res
else
return res
end
end --p.append_mod_item
function p.ins_tab_row (S)
table.insert (p.tab_items, '<tr>'..S..'</tr>')
end
local pos_for_item = 1
function p.add_pos (res)
if p.with_pos_col then
res = '<td>'..pos_for_item..'</td>'
end
pos_for_item = pos_for_item + 1
return res
end --p.add_pos
local function begin_foot (in_labels)
table.insert (p.tab_items, '</table>')
res = {}
if #p.mod_used > 1 then
table.insert (res, 'M.: Abbreviation of the used module/s')
end
if p.with_pos_col then
table.insert (res, 'P.: Position according to the appearance order in the infobox')
end
if in_labels and p.uses_QP_for_labels then
table.insert (res, 'WD: Wikidata')
end
if #res > 0 then
table.insert (p.tab_items, table.concat (res, '. ')..'</br>')
end
end --begin_foot
local has_required = false
function p.IT_required_vals (item_type, required, vals)
if (item_type ~= '') and required then
item_type = item_type..'-R'
has_required = true
end
if SA.HasValue (vals) then
item_type = item_type..' '..vals
end
return item_type
end --p.IT_required_vals
function p.IsHeader (key)
p.ChkFunc ("IsHeader", {{"key",key,"xr"},})
if string.find (key,'hd_') == 1 then
return true
else
return false
end
end --IsHeader
function p.PerhapsDsplKeyMode (key)
if p.IsHeader (key) then
return '<b>'..key..'</b>'
else
return key
end
end --PerhapsDsplKeyMode
local tab = '	'
local function add_arg_item (option, mod_abbrev, key, wd_main, wd_lang, prop, item_type_req)
if p.IsReserv (key) then return end
if key == nil then
error ('Not set key') --for debug
end
if wd_main == nil then
error ('Not wd_main for key = "'..key..'"') --for debug
end
if wd_lang == nil then
wd_lang = ''
end
local item_type, required, vals = p.split_item_type_req_vals_forList (item_type_req)
if option == p.LOpt.params then
function concat_wd (A)
if type(A) == 'table' then
for i, j in pairs(A) do
if type(j) == 'table' then
SD.vtos (j)
error ('Error in table design and key = "'..key..'":'..SD.s..' must be a string') --for debug
end
end
A = table.concat (A, ', ')
end
if A == nil then
error ('Not set variable for key = "'..key..'"') --for debug
end
return A
end
p.add_mod_used_in_class (mod_abbrev)
local row = ''
row = p.add_pos (row)
row = row..'<td>'..p.PerhapsDsplKeyMode(key)..'</td><td>'..concat_wd(wd_main)..'</td><td>'..concat_wd(wd_lang)..'</td>'
if p.with_arg_prop then
if SA.HasValue (prop) then
if prop == true then
row = row..'<td>true</td><td></td>'
elseif prop == false then
row = row..'<td>false</td><td></td>'
elseif type(prop) == 'table' then
local props = prop["property"]
if props == nil then
--Prop contains a pattern to format a manual value
row = row..'<td></td><td></td>'
else
local sep = ''
if string.find(props, ' OR ') then
sep = ' OR '
props = mw.text.split (props,sep)
sep = '<small>'..sep..'</small>'
elseif string.find(props, '/') then
sep = '/'
props = mw.text.split (props,sep)
end
if type(props) == 'table' then
local trans = {}
for k, w in ipairs(props) do
props[k] = '[[:wikidata:Property:'..w..'|'..w..']]'
local wd = WD.getLabel({w, ['lang']=p.lang})
if wd ~= nil then
table.insert (trans, wd)
end
end
row = row..'<td><span style="font-size:50%">WD </span>'..table.concat(props,sep)..'</td><td>'..table.concat(trans,', ')..'</td>'
else
local wd = WD.getLabel({props, ['lang']=p.lang})
row = row..'<td><span style="font-size:50%">WD </span>'..props..'</td><td>'..wd..'</td>'
end
end
elseif string.sub (prop,1,1) == '_' then
local props = mw.text.split(string.sub (prop,2), '-')
local trans = {}
for k, w in ipairs(props) do
if string.sub (w,1,1) == 'Q' then
props[k] = '[[:wikidata:'..w..'|'..w..']]'
else
props[k] = '[[:wikidata:Property:'..w..'|'..w..']]'
end
local wd = WD.getLabel({w, ['lang']=p.lang})
if wd ~= nil then
table.insert (trans, wd)
end
end
row = row..'<td><span style="font-size:50%">WD </span>'..table.concat(props,',')..'</td><td>'..table.concat(trans,', ')..'</td>'
elseif string.sub (prop,1,5) == 'Color:' then
local color = string.sub (prop,6)
row = row..'<td><span style="background-color:'..color..'">'..color..'</span></td><td></td>'
else
row = row..'<td>'..prop..'</td><td></td>'
end
else
row = row..'<td></td><td></td>'
end
end
row = p.append_mod_item (mod_abbrev, row)
p.add_arg_types_used (item_type)
item_type = p.IT_required_vals (item_type, required, vals)
p.ins_tab_row (row..'<td>'..item_type..'</td>')
elseif option == p.LOpt.template then
item_type = tab..tab..tab..'"type": "'..AT_TD[ConvToTemplateDate(item_type)]..'"'
local wd = ''
local alias = {}
function get_wd_alias (A)
if type(A) == 'table' then
wd = A[1]
for i = 2, #A do
table.insert (alias, A[i])
end
else
wd = A
end
end
if wd_lang == '' then
get_wd_alias (wd_main)
else
get_wd_alias (wd_lang)
if type(wd_main) == 'table' then
for _, w in ipairs(wd_main) do
table.insert (alias, w)
end
else
table.insert (alias, wd_main)
end
end
if #alias > 0 then
table.insert (p.tab_items, tab..tab..'"'..wd..'": {')
table.insert (p.tab_items, tab..tab..tab..'"aliases": [')
function PresAlias (S)
local N = tonumber(S)
if not N then
return '"'..S..'"'
else
return '["'..S..'"]'
end
end
for i = 1, (#alias-1) do
table.insert (p.tab_items, tab..tab..tab..tab..PresAlias(alias[i])..',')
end
table.insert (p.tab_items, tab..tab..tab..tab..PresAlias (alias[#alias]))
table.insert (p.tab_items, tab..tab..tab..'],')
else
table.insert (p.tab_items, tab..tab..'"'..wd..'": {')
end
if required then
item_type = item_type..','
end
table.insert (p.tab_items, item_type)
if required then
table.insert (p.tab_items, tab..tab..tab..'"required": true')
end
table.insert (p.tab_items, tab..tab..'},')
end
end --add_arg_item
function p.GetITRFromLims (lims, key)
if lims == nil then
return p.IT.s
else
return lims[key]
end
end --GetITRFromLims
function p.GetITRFromLimsGr (lims, grp, key)
if lims[grp] == nil then
return p.IT.s
else
return lims[grp][key]
end
end --GetITRFromLimsGr
function p.add_arg_item (option, mod_abbrev, key, wd_main, wd_lang, lims)
local prop = nil
local item_type_req = p.GetITRFromLims (lims, key)
if p.with_arg_prop then
prop = wd_main[p.k.Args][key][2]
wd_main = wd_main[p.k.Args][key][1]
else
wd_main = wd_main[p.k.Args][key][1]
end
wd_lang = wd_lang[p.k.Args][key]
add_arg_item (option, mod_abbrev, key, wd_main, wd_lang, prop, item_type_req)
end --add_arg_item
function p.add_arg_item_grp (option, mod_abbrev, grp, key, wd_main, wd_lang, lims)
local prop = nil
local item_type_req = p.GetITRFromLims (lims, grp, key)
if p.with_arg_prop then
prop = wd_main[p.k.Args][grp][key][2]
wd_main = wd_main[p.k.Args][grp][key][1]
else
wd_main = wd_main[p.k.Args][grp][key][1]
end
wd_lang = wd_lang[p.k.Args][grp][key]
add_arg_item (option, mod_abbrev, grp..'.'..key, wd_main, wd_lang, prop, item_type_req)
end --add_arg_item_grp
local function CheckIdx0 (tab)
if tab == nil then
error ('List not assigned') --Don't translate, for debug
elseif not SA.TableWithItems(tab) then
error ('List without items') --Don't translate, for debug
end
end --CheckIdx0
function p.CheckIdx (tab)
--checks that table of {'a','b'..} is assigned, contents items.
CheckIdx0 (tab)
local s = #tab
local pos = 0
local old_val = ""
for _, key in ipairs(tab) do
pos = pos + 1
old_val = key
end
if pos ~= #tab then
error ('List error in the key after key "'..old_val..'"') --Don't translate, for debug
end
end --CheckIdx
function p.CheckLims0 (ModuleName, tab)
local s = #tab
for key, lims in pairs(tab) do
local found = false
local tt
local k
for t, i in pairs(p.IT) do
k = lims
if type(k) == 'table' then
k = k[1]
end
if i == k then
found = true
tt = t
break
end
end
function key_lims ()
return '"'..key..'" (from '..ModuleName..')'
end
if not found then
error ('Invalid argument type ("'..k..'") for '..key_lims())
end
if type(lims) == 'table' then
function CheckKeyN ()
if #lims ~= 2 then
error ('Two parameters (now '..#lims..') are required for '..key_lims())
end
end
if lims[1] == 'a' then --array
CheckKeyN ()
local count = 0
for _,i in ipairs(lims[2]) do
if type(i) ~= 'string' then
SD.vtos (i)
error ('An array item ('..SD.s..') is not a string. For '..key_lims())
end
count = count + 1
end
if count < 2 then
error ('More than 1 items ara required for '..lims[1]..' '..key_lims())
end
else --numeric with limits
function ParFor (n)
return 'Parameter for '..lims[1]..' '..key_lims()
end
function CheckOrder ()
if tonumber(lims[2][1]) > tonumber(lims[2][2]) then
error ('Invalid order for limits for '..key_lims())
end
end
if tt == p.IT.i then
CheckKeyN ()
SA.CheckSIsInt (lims[2][1], ParFor(2))
SA.CheckSIsInt (lims[2][2], ParFor(3))
CheckOrder ()
elseif tt == p.IT.n then
CheckKeyN ()
SA.CheckSIsNum (lims[2][1], ParFor(2))
SA.CheckSIsNum (lims[2][2], ParFor(3))
CheckOrder ()
else
error ('No parameters allowed for argument type "'..tt..'" for '..key_lims())
end
end
end
end
end --CheckLims0
function p.CheckLims (ModuleName, tab)
p.CheckLims0 (ModuleName, tab)
end
function p.foot_for_args ()
begin_foot (false)
perhaps_mod_used ()
if (#arg_types_used > 1) or has_required then
local item_types = {}
for _, i in ipairs(arg_types_used) do
table.insert (item_types, i..' ('..p.AT_Read[i]..')')
end
local row = 'Used argument types: '..table.concat(item_types,', ')
if has_required then
row = row..'. "-R" indicates required arguments.'
end
table.insert (p.tab_items, row)
end
return table.concat (p.tab_items, '')
end --foot_for_args
function p.show_arg_items (option, idx, func, tab_modname_func)
if option == p.LOpt.template then
table.insert (p.tab_items, '<pre>')
table.insert (p.tab_items, '<templatedata>')
table.insert (p.tab_items, '{')
table.insert (p.tab_items, tab..'"params": {')
else
table.insert (p.tab_items, '<table class="wikitable sortable">')
row = p.begin_headers()..'<th>Default names</th><th>Localized names (i18n)</th>'
if p.with_arg_prop then
row = row..'<th>Values</th><th>WD content ('..SA.lang_to_use..')</th>'
end
p.ins_tab_row (row..'<th>T.</th>')
end
p.CheckIdx (idx)
function WhenMod (k)
for _, j in ipairs (tab_modname_func) do
if (j[1] == '') or (j[1] == k) then
j[2] (option, k)
break
end
end
end --WhenMod
function WhenMain (k)
local mod_abbrev, wd_main, wd_lang, lims = func (k)
p.add_arg_item (option, mod_abbrev, k, wd_main, wd_lang, lims)
end
function WhenModGr (grp, k)
for _, j in ipairs (tab_modname_func) do
if (j[1] == '') or (j[1] == k) then
j[2] (option, grp, k)
break
end
end
end --WhenModGr
function WhenMainGr (grp, k)
local mod_abbrev, wd_main, wd_lang, lims = func (grp, k)
p.add_arg_item_grp (option, mod_abbrev, grp, k, wd_main, wd_lang, lims)
end
if idx[SA.HasChild] == nil then
for _, key in ipairs(idx) do
if type(key) == 'table' then -- key = {type, key}; when type, any value of {'al', 'a', 'l', '-'}
if key[1] == '-' then
WhenMod (key[2])
elseif string.find (key[1],'a') then
WhenMain (key[2])
end
else
if string.sub (key,1,1) == '_' then
WhenMod (string.sub (key,2))
else
WhenMain (key)
end
end
end
else
for _, grp in ipairs(idx) do
for _, key in ipairs(idx[grp]) do
if type(key) == 'table' then -- key = {type, key}; when type, any value of {'al', 'a', 'l', '-'}
if key[1] == '-' then
WhenModGr (grp, key[2])
elseif string.find (key[1],'a') then --'a' of argument
WhenMainGr (grp, key[2])
end
else
if string.sub (key,1,1) == '_' then
WhenModGr (grp, string.sub (key,2))
else
WhenMainGr (grp, key)
end
end
end
end
end
if option == p.LOpt.template then
local S = p.tab_items[#p.tab_items]
p.tab_items[#p.tab_items] = string.sub (S, 1, string.len(S)-1)
table.insert (p.tab_items, tab..'},')
table.insert (p.tab_items, tab..'"format": "block"')
table.insert (p.tab_items, '}')
table.insert (p.tab_items, '</templatedata>')
table.insert (p.tab_items, '</pre>')
return table.concat (p.tab_items, '</br>')
else
return p.foot_for_args ()
end
end --show_arg_items
local function add_lab_item (mod_abbrev, key, wd_main, wd_lang, lnk)
p.add_mod_used_in_class (mod_abbrev)
if wd_lang == nil then --not translated
wd_lang = ''
end
local row = ''
row = p.add_pos (row)
row = row..'<td>'..p.PerhapsDsplKeyMode(key)..'</td><td>'..wd_main..'</td>'
row = p.append_mod_item (mod_abbrev, row)
if p.uses_QP_for_labels then
if lnk ~= '' then
local lnk1 = lnk
if string.sub (lnk,1,1) == 'P' then
lnk1 = 'Property:'..lnk1
end
row = row..'<td>[[:wikidata:'..lnk1..'|'..lnk..']]</td><td>'..WD.getLabel({lnk, ['lang']=p.lang})..'</td>'
else
row = row..'<td></td><td></td>'
end
end
row = row..'<td>'..wd_lang..'</td>'
p.ins_tab_row (row)
end --add_lab_item
function p.add_lab_item (mod_abbrev, key, wd_main, wd_lang, lnk)
add_lab_item (mod_abbrev, key, wd_main, wd_lang, lnk)
end
function p.add_lab_item_grp (mod_abbrev, grp, key, wd_main, wd_lang, lnk)
add_lab_item (mod_abbrev, grp..'.'..key, wd_main, wd_lang, lnk)
end
function p.show_lab_items (idx, func, tab_modname_func)
table.insert (p.tab_items, '<table class="wikitable sortable">')
local row = ''
if p.uses_QP_for_labels then
row = '<th>Source/WD content (en)</th>'
else
row = '<th>Source</th>'
end
row = p.begin_headers()..row
if p.uses_QP_for_labels then
row = row..'<th>WD</th><th>WD content ('..SA.lang_to_use..')</th>'
end
row = row..'<th>Localization (i18n)</th>'
p.ins_tab_row (row)
p.CheckIdx (idx)
function WhenMod (key)
if tab_modname_func ~= nil then
for _, j in ipairs (tab_modname_func) do
if (j[1] == "") or (j[1] == key) then
j[2](key)
break
end
end
end
end --WhenMod
function WhenMain (k)
local mod_abbrev, key, wd_main, wd_lang, lnk = func (k)
p.add_lab_item (mod_abbrev, k, wd_main, wd_lang, lnk)
end
function WhenModGr (grp, key)
if tab_modname_func ~= nil then
for _, j in ipairs (tab_modname_func) do
if (j[1] == "") or (j[1] == key) then
j[2](grp, key)
break
end
end
end
end --WhenModGr
function WhenMainGr (grp, k)
local mod_abbrev, key, wd_main, wd_lang, lnk = func (grp, k)
p.add_lab_item_grp (mod_abbrev, grp, k, wd_main, wd_lang, lnk)
end
function HasLabel (key)
return (string.find (key,'l')) or (key == 'L')
end
if idx[SA.HasChild] == nil then
for _, key in ipairs(idx) do
if type(key) == 'table' then -- key = {type, key}; when type, any value of {'al', 'a', 'l', '-'}
if key[1] == '-' then
WhenMod (key[2])
elseif HasLabel (key[1]) then
WhenMain (key[2])
end
else
if string.sub (key,1,1) == '_' then
WhenMod (string.sub (key,2))
else
WhenMain (key)
end
end
end
else
for _, grp in ipairs(idx) do
for _, key in ipairs(idx[grp]) do
if type(key) == 'table' then -- key = {type, key}; when type, any value of {'al', 'a', 'l', '-'}
if key[1] == '-' then
WhenModGr (grp, key[2])
elseif HasLabel (key[1]) then
WhenMainGr (grp, key[2])
end
else
if string.sub (key,1,1) == '_' then
WhenModGr (grp, string.sub (key,2))
else
WhenMainGr (grp, key)
end
end
end
end
end
begin_foot (true)
perhaps_mod_used ()
return table.concat (p.tab_items, '')
end --show_lab_items
local function add_msg_error_item (mod_abbrev, key, wd_main, wd_lang)
if wd_lang == nil then
wd_lang = ''
end
p.add_mod_used_in_class (mod_abbrev)
local any = '<td>'..key..'</td><td>'..wd_main..'</td><td>'..wd_lang..'</td>'
any = p.append_mod_item (mod_abbrev, any)
p.ins_tab_row (any)
end --add_msg_error_item
function p.add_msg_error_item (mod_abbrev, key, wd_main, wd_lang)
add_msg_error_item (mod_abbrev, key, wd_main, wd_lang)
end
function p.add_msg_error_item_grp (mod_abbrev, grp, key, wd_main, wd_lang)
add_msg_error_item (mod_abbrev, grp..'.'..key, wd_main, wd_lang)
end
function p.show_msgs_errors (idx, func, tab_modname_func)
table.insert (p.tab_items, '<table class="wikitable sortable">')
local row = '<th>Source</th><th>Translation</th>'
p.ins_tab_row (p.begin_headers()..row)
p.CheckIdx (idx)
if idx[SA.HasChild] == nil then
for _, key in ipairs(idx) do
if key[1] == '-' then
key = key[2]
for _, j in ipairs (tab_modname_func) do
if (j[1] == "") or (j[1] == key) then
j[2](key)
break
end
end
else
local mod_abbrev, key, tab_main, tab_lang = func (key[2])
p.add_msg_error_item (mod_abbrev, key, tab_main, tab_lang)
end
end
else
for _, grp in ipairs(idx) do
for _, key in ipairs(idx[grp]) do
if key[1] == '-' then
key = key[2]
for _, j in ipairs (tab_modname_func) do
if (j[1] == "") or (j[1] == key) then
j[2](grp, key)
break
end
end
else
local mod_abbrev, key, tab_main, tab_lang = func (grp, key[2])
p.add_msg_error_item_grp (mod_abbrev, grp, key, tab_main, tab_lang)
end
end
end
end
table.insert (p.tab_items, '</table>')
perhaps_mod_used ()
return table.concat (p.tab_items, '')
end --show_msgs_errors
return p