Modul:Wikidata.Ca
Pendokumenan untuk modul ini boleh diciptakan di Modul:Wikidata.Ca/doc
-- version 20230810 from master @cawiki-- Modul ini diadaptasi daripada [[Mòdul:Wikidades]] di Wikipedia bahasa Catalonialocal p = {}-- Initialization of variables --------------------local i18n = {-- internationalisation at [[Module:Wikidata/i18n]]["errors"] = {["property-not-found"] = "Sifat tidak dijumpai.",["qualifier-not-found"] = "Penerang tidak dijumpai.",},["datetime"] = {-- $1 is a placeholder for the actual number["beforenow"] = "$1 BCE",-- how to format negative numbers for precisions 0 to 5["afternow"] = "$1 CE",-- how to format positive numbers for precisions 0 to 5["bc"] = "$1 BCE",-- how print negative years["ad"] = "$1",-- how print 1st century AD dates[0] = "$1 bilion tahun",-- precision: billion years[1] = "$100 juta tahun",-- precision: hundred million years[2] = "$10 juta tahun", -- precision: ten million years[3] = "$1 juta tahun", -- precision: million years[4] = "$100000 tahun",-- precision: hundred thousand years; thousand separators added afterwards[5] = "$10000 tahun",-- precision: ten thousand years; thousand separators added afterwards[6] = "$1 alaf", -- precision: millennium[7] = "$1 kurun",-- precision: century[8] = "$1 dasawarsa",-- precision: decade-- the following use the format of #time parser function[9] = "Y",-- precision: year, [10] = "F Y",-- precision: month[11] = "F j, Y",-- precision: day["hms"] = {["jam"] = "h", ["minit"] = "m", ["saat"] = "s"},-- duration: xh xm xs},["tahun"] = {"", ""},-- year(s) old, as in {{PLURAL:$1|singular|plural}}-- two values for most languages, up to six values for some languages-- see documentation of PLURAL magic word in your language, examples:-- ["years-old"] = {"singular", "paucal", "plural"} in Russian and other Slavic languages-- ["years-old"] = {"zero", "one", "two", "few 3-10", "many 11-99", "other 100-102"} in Arabic["cite"] = {-- cite parameters["title"] = "title",["author"] = "author",["date"] = "date",["pages"] = "pages",["language"] = "language",-- cite web parameters["url"] = "url",["website"] = "website",["access-date"] = "access-date",["archive-url"] = "archive-url",["archive-date"] = "archive-date",["publisher"] = "publisher",["quote"] = "quote",-- cite journal parameters["work"] = "work",["issue"] = "issue",["issn"] = "issn",["doi"] = "doi"},-- default local wiki settings["addpencil"] = false, -- adds a pencil icon linked to Wikidata statement, planned to overwrite by Wikidata Bridge["categorylabels"] = "", -- Category:Pages with Wikidata labels not translated (void for no local category)["categoryprop"] = "", -- Category:Pages using Wikidata property $1 (void for no local category)["categoryref"] = "", -- Category:Pages with references from Wikidata (void for no local category)["addfallback"] = {}, -- additional fallback language codes["suppressids"] = {}, -- list of Qid values to suppress["qidlabels"] = true -- show labels as Qid if no fallback translation is available}local cases = {} -- functions for local grammatical cases defined at [[Module:Wikidata/i18n]]local required = ... -- variadic arguments from require functionlocal wiki = {langcode = mw.language.getContentLanguage().code,module_title = required or mw.getCurrentFrame():getTitle()}local untranslated -- used in infobox modules: nil or truelocal _ -- variable for unused returned values, avoiding globals-- Module local functions ---------------------------------------------- Credit to http://stackoverflow.com/a/1283608/2644759, cc-by-sa 3.0local function tableMerge(t1, t2)for k, v in pairs(t2) doif type(v) == "table" thenif type(t1[k] or false) == "table" thentableMerge(t1[k] or {}, t2[k] or {})elset1[k] = vendelset1[k] = vendendreturn t1endlocal function loadI18n(lang)local exist, res = pcall(require, wiki.module_title .. "/i18n")if exist and next(res) ~= nil thentableMerge(i18n, res.i18n)cases = res.casesendif lang ~= wiki.langcode thenexist, res = pcall(require, wiki.module_title .. "/i18n/" .. lang)if exist and next(res) ~= nil thentableMerge(i18n, res.i18n)tableMerge(cases, res.cases)endendi18n.suppress = {}for _, id in ipairs(i18n.suppressids) doi18n.suppress[id] = trueendend-- Table of language codes: requested or default and its fallbackslocal function findLang(langcode)if mw.language.isKnownLanguageTag(langcode or '') == false thenlocal cframe = mw.getCurrentFrame()local pframe = cframe:getParent()langcode = pframe and pframe.args.langif mw.language.isKnownLanguageTag(langcode or '') == false thenif not mw.title.getCurrentTitle().isContentPage thenlangcode = cframe:callParserFunction('int', {'lang'})endif mw.language.isKnownLanguageTag(langcode or '') == false thenlangcode = wiki.langcodeendendendloadI18n(langcode)local languages = mw.language.getFallbacksFor(langcode)table.insert(languages, 1, langcode)if langcode == wiki.langcode thenfor _, l in ipairs(i18n.addfallback) dotable.insert(languages, l)endendreturn languagesend-- Argument is 'set' when it exists (not nil) or when it is not an empty string.local function isSet(var)return not (var == nil or (type(var) == 'string' and mw.text.trim(var) == ''))end-- Set local case to a labellocal function case(localcase, label, ...)if not isSet(label) then return label endif type(localcase) == "function" thenreturn localcase(label)elseif localcase == "smallcaps" thenreturn '<span style="font-variant: small-caps;">' .. label .. '</span>'elseif cases[localcase] thenreturn cases[localcase](label, ...)endreturn labelend-- get safely a serialized snaklocal function getSnak(statement, snaks)local ret = statementfor i, v in ipairs(snaks) doif not ret then return endret = ret[v]endreturn retend-- mw.wikibase.getLabelWithLang or getLabelByLang with a table of languageslocal function getLabelByLangs(id, languages)local labellocal langfor _, l in ipairs(languages) doif l == wiki.langcode then-- using getLabelWithLang when possible instead of getLabelByLanglabel, l = mw.wikibase.getLabelWithLang(id)elselabel = mw.wikibase.getLabelByLang(id, l)endif label thenlang = lbreakendendreturn label, langend-- getBestStatements if bestrank=true, else getAllStatements with no deprecatedlocal function getStatements(entityId, property, bestrank)local claims = {}if not (entityId and mw.ustring.match(property, "^P%d+$")) then return claims endif bestrank thenclaims = mw.wikibase.getBestStatements(entityId, property)elselocal allclaims = mw.wikibase.getAllStatements(entityId, property)for _, c in ipairs(allclaims) doif c.rank ~= "deprecated" thentable.insert(claims, c)endendendreturn claimsend-- Is gender femenine? true or falselocal function feminineGender(id)local claims = mw.wikibase.getBestStatements(id or mw.wikibase.getEntityIdForCurrentPage(),'P21')local gender_id = getSnak(claims, {1, "mainsnak", "datavalue", "value", "id"})if gender_id == "Q6581072" or gender_id == "Q1052281" or gender_id == "Q43445" then -- female, transgender female, female organismreturn trueendreturn falseend-- Fetch female form of labellocal function feminineForm(id, lang)local feminine_claims = getStatements(id, 'P2521')for _, feminine_claim in ipairs(feminine_claims) doif getSnak(feminine_claim, {'mainsnak', 'datavalue', 'value', 'language'}) == lang thenreturn feminine_claim.mainsnak.datavalue.value.textendendend-- Add an icon for no label in requested languagelocal function addLabelIcon(label_id, lang, uselang, icon)local ret_lang, ret_icon = '', ''if icon thenif lang and lang ~= uselang thenret_lang = " <sup>(" .. lang .. ")</sup>"endif label_id and (lang == nil or lang ~= uselang) thenlocal namespace = ''if string.sub(label_id, 1, 1) == 'P' thennamespace = 'Property:'endret_icon = " [[Fail:Noun Project label icon 1116097 cc mirror.svg|10px|baseline|".. mw.message.new('Translate-taction-translate'):inLanguage(uselang):plain().. "|link=https://www.wikidata.org/wiki/" .. namespace .. label_id .. "?uselang=ms]]"untranslated = trueendif isSet(i18n.categorylabels) and lang ~= uselang and uselang == wiki.langcode thenret_icon = ret_icon .. '[[' .. i18n.categorylabels .. (lang and ']]' or '/Q]]')endendreturn ret_lang .. ret_iconend-- editicon values: true/false (no=false), right, void defaults to i18n.addpencil-- labelicon only by parameterlocal function setIcons(arg, parg)local val = arg == nil and parg or arglocal edit_icon, label_iconif not isSet(val) thenedit_icon, label_icon = i18n.addpencil, trueelseif val == false or val == "false" or val == "no" thenedit_icon, label_icon = false, falseelseedit_icon, label_icon = val, trueendreturn edit_icon, label_iconend-- Add an icon for editing a statement with requirements for future Wikidata Bridgelocal function addEditIcon(parameters)local ret = ''if parameters.editicon and parameters.id and parameters.property thenlocal bridge_flow = parameters.editbridge and ' data-bridge-edit-flow="single-best-value"' or ''local icon_style = parameters.editicon == "right" and ' style="float: right;"' or ''ret = ' <span class="penicon"' .. bridge_flow .. icon_style .. '>'.. "[[Fail:OOjs UI icon edit-ltr-progressive.svg|10px|baseline|".. string.gsub(mw.message.new('Wikibase-client-data-bridge-bailout-suggestion-go-to-repo-button'):inLanguage(parameters.lang[1]):plain(), '{{WBREPONAME}}', 'Wikidata').. "|link=https://www.wikidata.org/wiki/" .. parameters.id .. "?uselang=" .. parameters.lang[1] .. "#" .. parameters.property .. "]]".. "</span>"if isSet(i18n.categoryprop) thenret = ret .. "[[" .. string.gsub(i18n.categoryprop, '$1', parameters.property) .. "]]"endendreturn retend-- add edit icon to the last element of a tablelocal function addEditIconTable(thetable, parameters)if #thetable == 0 or parameters.editicon == false thenreturn thetableendlocal last_element = thetable[#thetable]local the_icon = addEditIcon(parameters)-- add it before last html closing tagslocal tags = ''local rev_element = string.reverse(last_element)for tag in string.gmatch(rev_element, '(>%l+/<)') doif string.match(rev_element, '^' .. tags .. tag) thentags = tags .. tagelsebreakendendlocal last_tags = string.reverse(tags)local offset = string.find(last_element, last_tags .. '$')if offset thenthetable[#thetable] = string.sub(last_element, 1, offset - 1) .. the_icon .. last_tagselsethetable[#thetable] = last_element .. the_iconendreturn thetableend-- Escape Lua captureslocal function captureEscapes(text)return mw.ustring.gsub(text, "(%%%d)", "%%%1")end-- expandTemplate or callParserFunctionlocal function expandBraces(text, formatting)if text == nil or formatting == nil then return text end-- only expand braces if provided in argument, not included in value as in Q1164668if mw.ustring.find(formatting, '{{', 1, true) == nil then return text endif type(text) ~= "string" thentext = tostring(text)endfor braces in mw.ustring.gmatch(text, "{{(.-)}}") dolocal parts = mw.text.split(braces, "|")local title_part = parts[1]local parameters = {}for i = 2, #parts dolocal subparts = mw.ustring.find(parts[i], "=")if subparts thenlocal param_name = mw.ustring.sub(parts[i], 1, subparts - 1)local param_value = mw.ustring.sub(parts[i], subparts + 1, -1)-- reconstruct broken links by partsif i < #parts and mw.ustring.find(param_value, "[[", 1, true) and not mw.ustring.find(param_value, "]]", 1, true) thenparameters[param_name] = param_valuelocal part_next = i + 1while parts[part_next] and mw.ustring.find(parts[part_next], "]]", 1, true) doparameters[param_name] = parameters[param_name] .. "|" .. parts[part_next]part_next = part_next + 1endelseparameters[param_name] = param_valueendelseif not mw.ustring.find(parts[i], "]]", 1, true) thentable.insert(parameters, parts[i])endendlocal braces_expandedif mw.ustring.find(title_part, ":")and mw.text.split(title_part, ":")[1] ~= mw.site.namespaces[10].name -- not a prefix Template:thenbraces_expanded = mw.getCurrentFrame():callParserFunction{name=title_part, args=parameters}elsebraces_expanded = mw.getCurrentFrame():expandTemplate{title=title_part, args=parameters}endbraces = mw.ustring.gsub(braces, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1") -- escape magic charactersbraces_expanded = captureEscapes(braces_expanded)text = mw.ustring.gsub(text, "{{" .. braces .. "}}", braces_expanded)endreturn textend-- format data type mathlocal function printDatatypeMath(data)return mw.getCurrentFrame():callParserFunction('#tag:math', data)end-- format data type musical-notationlocal function printDatatypeMusical(data, formatting)local attr = {}if formatting == 'sound' thenattr.sound = 1endreturn mw.getCurrentFrame():extensionTag('score', data, attr)end-- format data type stringlocal function printDatatypeString(data, parameters)if mw.ustring.find((parameters.formatting or ''), '$1', 1, true) then -- formatting = a patternreturn expandBraces(mw.ustring.gsub(parameters.formatting, '$1', {['$1'] = data}), parameters.formatting)elseif parameters.case thenreturn case(parameters.case, data, parameters.lang[1], feminineGender(parameters.id))endlocal data_number = string.match(data, "^%d+")if data_number then -- sort key by initial number and remaining stringlocal sortkey = string.format("%019d", data_number * 1000)return data, sortkey .. string.sub(data, #data_number + 1)endreturn dataend-- format data type tabular-datalocal function printDatatypeTabular(data, parameters)local iconif parameters.formatting == 'raw' thenicon = "no-icon"data = string.gsub(data, '^Data:', '') -- remove prefix, i.e. see Module:Tabular dataendreturn printDatatypeString(data, parameters), iconend-- format data type urllocal function printDatatypeUrl(data, parameters)if parameters.formatting == 'weblink' thenlocal label_parts = mw.text.split(string.gsub(data, '/$', ''), '/')local label = string.gsub(label_parts[3], '^www%.', '')if #label_parts > 3 thenlabel = label .. '…'endreturn '[' .. data .. ' ' .. label .. ']'endreturn printDatatypeString(data, parameters)end-- format data type external-idlocal function printDatatypeExternal(data, parameters)if parameters.formatting == 'externalid' thenlocal p_stat = mw.wikibase.getBestStatements(parameters.property, 'P1630') -- formatter URLlocal p_link_pattern = getSnak(p_stat, {1, "mainsnak", "datavalue", "value"})if p_link_pattern thenlocal p_link = mw.ustring.gsub(p_link_pattern, '$1', {['$1'] = data})return '[' .. p_link .. ' ' .. data .. ']'endendreturn printDatatypeString(data, parameters)end-- format data type commonsMedia and geo-shapelocal function printDatatypeMedia(data, parameters)local iconif not string.find((parameters.formatting or ''), '$1', 1, true) thenicon = "no-icon"if not string.find(data, '^Data:') thendata = mw.uri.encode(data, 'PATH') -- encode special characters in filenameendendreturn printDatatypeString(data, parameters), iconend-- format data type globe-coordinatelocal function printDatatypeCoordinate(data, formatting)local function globes(globe_id)local globes = {['Q3134']='callisto',['Q596']='ceres',['Q15040']='dione',['Q2']='earth',['Q3303']='enceladus',['Q3143']='europa',['Q17975']='phoebe',['Q3169']='ganymede',['Q3123']='io',['Q17958']='iapetus',['Q308']='mercury',['Q15034']='mimas',['Q405']='moon',['Q15050']='rhea',['Q15047']='tethys',['Q111']='mars',['Q2565']='titan',['Q3359']='triton',['Q313']='venus',['Q3030']='vesta'}return globes[globe_id]endlocal function roundPrecision(num, prec)if prec == nil or prec <= 0 then return num endlocal sig = 10^math.floor(math.log10(prec)+.5) -- significant figure from sexagesimal precision: 0.00123 -> 0.001return math.floor(num / sig + 0.5) * sigendlocal precision = data.precisionlocal latitude = roundPrecision(data.latitude, precision)local longitude = roundPrecision(data.longitude, precision)if formatting and string.find(formatting, '$lat', 1, true) and string.find(formatting, '$lon', 1, true) thenlocal ret = mw.ustring.gsub(formatting, '$l[ao][tn]', {['$lat'] = latitude, ['$lon'] = longitude})if string.find(formatting, '$globe', 1, true) thenlocal myglobe = 'earth'if isSet(data.globe) thenlocal globenum = mw.text.split(data.globe, 'entity/')[2] -- http://www.wikidata.org/wiki/Q2myglobe = globes(globenum) or 'earth'endret = mw.ustring.gsub(ret, '$globe', myglobe)endreturn expandBraces(ret, formatting)elseif formatting == 'latitude' thenreturn latitude, "no-icon"elseif formatting == 'longitude' thenreturn longitude, "no-icon"elseif formatting == 'dimension' thenreturn data.dimension, "no-icon"else --default formatting='globe'if isSet(data.globe) == false or data.globe == 'http://www.wikidata.org/entity/Q2' thenreturn 'earth', "no-icon"elselocal globenum = mw.text.split(data.globe, 'entity/')[2]return globes(globenum) or globenum, "no-icon"endendend-- Local functions for data value quantitylocal function unitSymbol(id, lang) -- get unit symbol or codelocal unit_symbol = ''if lang == wiki.langcode and pcall(require, wiki.module_title .. "/Units") thenunit_symbol = require(wiki.module_title .. "/Units").getUnit(0, '', id, true)endif unit_symbol == '' then-- fetch itlocal claims = mw.wikibase.getBestStatements(id, 'P5061')if #claims > 0 thenlocal langclaims = {}table.insert(lang, 'mul') -- multilingual as last tryfor _, snak in ipairs(claims) dolocal snak_language = getSnak(snak, {"mainsnak", "datavalue", "value", "language"})if snak_language and not langclaims[snak_language] then -- just the first one by languagelangclaims[snak_language] = snak.mainsnak.datavalue.value.textendendfor _, l in ipairs(lang) doif langclaims[l] thenreturn langclaims[l]endendendendreturn unit_symbolendlocal function getUnit(amount, id, parameters) -- get unit symbol or namelocal suffix = ''if string.sub(parameters.formatting or '', 1, 8) == "unitcode" then-- get unit symbollocal unit_symbol = unitSymbol(id, parameters.lang)if isSet(unit_symbol) thenif string.sub(parameters.formatting or '', -6) == "linked" thensuffix = "[[" .. (mw.wikibase.getSitelink(id) or "d:" .. id) .. "|" .. unit_symbol .. "]]"elsesuffix = unit_symbolendendendif suffix == '' then -- formatting=unit, or formatting=unitcode not found-- get unit labellocal unit_label, lang = getLabelByLangs(id, parameters.lang)if lang == wiki.langcode and pcall(require, wiki.module_title .. "/Units") thensuffix = require(wiki.module_title .. "/Units").getUnit(amount, unit_label, id, false)if string.sub(parameters.formatting or '', -6) == "linked" thensuffix = "[[" .. (mw.wikibase.getSitelink(id) or "d:" .. id) .. "|" .. suffix .. "]]"endelsesuffix = (unit_label or id) .. addLabelIcon(id, lang, parameters.lang[1], parameters.labelicon)endendif suffix ~= '' thensuffix = ' ' .. suffixendreturn suffixendlocal function roundDefPrecision(in_num, factor)-- rounds out_num with significant figures of in_num (default precision)local out_num = in_num * factorif factor/60 == math.floor(factor/60) or out_num == 0 then -- sexagesimal integer or avoiding NaNreturn out_numend-- first, count digits after decimal mark, handling cases like '12.345e6'local exponent, preclocal integer, dot, decimals, expstr = in_num:match('^(%d*)(%.?)(%d*)(.*)')local e = expstr:sub(1, 1)if e == 'e' or e == 'E' thenexponent = tonumber(expstr:sub(2))endif dot == '' thenprec = -integer:match('0*$'):len()elseprec = #decimalsendif exponent then-- So '1230' and '1.23e3' both give prec = -1, and '0.00123' and '1.23e-3' give 5.prec = prec - exponentend-- significant figureslocal in_bracket = 10^-prec -- -1 -> 10, 5 -> 0.00001local out_bracket = in_bracket * out_num / in_numout_bracket = 10^math.floor(math.log10(out_bracket)+.5) -- 1230 -> 1000, 0.00123 -> 0.001-- round it (credit to Luc Bloom from http://lua-users.org/wiki/SimpleRound)return math.floor(out_num/out_bracket + (out_num >=0 and 1 or -1) * 0.5) * out_bracketend-- format data type quantitylocal function printDatatypeQuantity(data, parameters)local amount = data.amountamount = mw.ustring.gsub(amount, "%+", "")local suffix = ""local conv_amount, conv_suffixif string.sub(parameters.formatting or '', 1, 4) == "unit" or string.sub(parameters.formatting or '', 1, 8) == "duration" or parameters.convert thenlocal unit_id = data.unitunit_id = mw.ustring.sub(unit_id, mw.ustring.find(unit_id, "Q"), -1)if string.sub(unit_id, 1, 1) == "Q" thensuffix = getUnit(amount, unit_id, parameters)local convert_toif parameters.convert == "default" or parameters.convert == "default2" thenlocal exist, units = pcall(require, wiki.module_title .. "/Units")if exist and units.convert_default and next(units.convert_default) ~= nil thenconvert_to = units.convert_default[unit_id]endelseif string.sub(parameters.convert or '', 1, 1) == "Q" thenconvert_to = parameters.convertelseif string.sub(parameters.formatting or '', 1, 8) == "duration" thenconvert_to = 'Q11574' -- secondsendif convert_to and convert_to ~= unit_id then-- convert unitslocal conv_temp = { -- formulae for temperatures ºC, ºF, ªK: [from] = {[to] = 'formula'}['Q25267'] = {['Q42289'] = '$1*1.8+32', ['Q11597'] = '$1+273.15'},['Q42289'] = {['Q25267'] = '($1-32)/1.8', ['Q11597'] = '($1+459.67)*5/9'},['Q11597'] = {['Q25267'] = '$1-273.15', ['Q42289'] = '($1-273.15)*1.8000+32.00'}}if conv_temp[unit_id] and conv_temp[unit_id][convert_to] thenlocal amount_f = mw.getCurrentFrame():callParserFunction('#expr', mw.ustring.gsub(conv_temp[unit_id][convert_to], "$1", amount))conv_amount = math.floor(tonumber(amount_f) + 0.5)elselocal conversions = getStatements(unit_id, 'P2442') -- conversion to standard unittable.insert(conversions, mw.wikibase.getBestStatements(unit_id, 'P2370')[1]) -- conversion to SI unitfor _, conv in ipairs(conversions) doif conv.mainsnak.snaktype == 'value' then -- no somevalue nor novalueif conv.mainsnak.datavalue.value.unit == "http://www.wikidata.org/entity/" .. convert_to thenconv_amount = roundDefPrecision(amount, tonumber(conv.mainsnak.datavalue.value.amount))breakendendendendif conv_amount thenconv_suffix = getUnit(conv_amount, convert_to, parameters)endelseif parameters.convert == 'M' and tonumber(amount) > 10^8 thenconv_amount = math.floor(amount/10^6 + 0.5)conv_suffix = ' M' .. string.sub(suffix, 2)endif conv_amount and parameters.formatting == 'raw' thenamount = conv_amountsuffix = ""conv_amount = nilendendendlocal lang_obj = mw.language.new(parameters.lang[1])local sortkey = string.format("%019d", tonumber(amount) * 1000)if string.sub(parameters.formatting or '', 1, 8) == "duration" thenlocal sec = tonumber(conv_amount or amount)if parameters.formatting == 'duration' thenreturn lang_obj:formatDuration(sec)elseif parameters.formatting == 'durationm:s' thenlocal mm = math.floor(sec / 60)local ss = sec - (mm * 60)return string.format("%02d:%02d", mm, ss)else -- durationhms or durationh:m:slocal intervals = {"hours", "minutes", "seconds"}local sec2table = lang_obj:getDurationIntervals(sec, intervals)sec2table["seconds"] = (sec2table["seconds"] or 0) + tonumber("." .. (tostring(sec):match("%.(%d+)") or "0")) -- add decimalslocal duration = ''for i, v in ipairs(intervals) doif parameters.formatting == 'durationh:m:s' thenif i == 1 and sec2table[v] thenduration = duration .. sec2table[v] .. ":"elseif i == 2 thenduration = duration .. string.format("%02d", sec2table[v] or 0) .. ":"elseif i == 3 thenlocal sec_str = tostring(lang_obj:formatNum(sec2table[v] or 0))duration = duration .. (sec2table[v] < 10 and "0" or "") .. sec_strendelseif sec2table[v] thenduration = duration .. lang_obj:formatNum(sec2table[v]) .. i18n.datetime.hms[v] .. (i < 3 and " " or "")endendreturn durationendendif parameters.case thenamount = case(parameters.case, amount, parameters.lang[1], feminineGender(parameters.id))elseif parameters.formatting ~= 'raw' thenif parameters.numformat thenamount = lang_obj:formatNum(tonumber(string.format(parameters.numformat, amount)))elseamount = lang_obj:formatNum(tonumber(amount))endendif conv_amount thenlocal conv_sortkey = string.format("%019d", conv_amount * 1000)conv_amount = lang_obj:formatNum(conv_amount)if parameters.convert == 'default2' thenreturn conv_amount .. conv_suffix .. ' (' .. amount .. suffix .. ')', conv_sortkeyelsereturn conv_amount .. conv_suffix, conv_sortkeyendelseif mw.ustring.find((parameters.formatting or ''), '$1', 1, true) then -- formatting with patternamount = mw.ustring.gsub(parameters.formatting, '$1', {['$1'] = amount})endreturn amount .. suffix, sortkeyend-- format data type timelocal function printDatatypeTime(data, parameters)-- Dates and times are stored in ISO 8601 formatlocal timestamp = data.timelocal post_formatlocal calendar_add = ""local precision = data.precision or 11if string.sub(timestamp, 1, 1) == '-' thenpost_format = i18n.datetime["bc"]elseif string.sub(timestamp, 2, 3) == '00' thenpost_format = i18n.datetime["ad"]elseif precision > 8 then-- calendar modellocal calendar_model = {["Q12138"] = "gregorian", ["Q1985727"] = "gregorian", ["Q11184"] = "julian", ["Q1985786"] = "julian"}local calendar_id = mw.text.split(data.calendarmodel, 'entity/')[2]if (timestamp < "+1582-10-15T00:00:00Z" and calendar_model[calendar_id] == "gregorian")or (timestamp > "+1582-10-04T00:00:00Z" and calendar_model[calendar_id] == "julian")thencalendar_add = " <sup>(" .. mw.message.new('Wikibase-time-calendar-' .. calendar_model[calendar_id]):inLanguage(parameters.lang[1]):plain() .. ")</sup>"endendlocal function formatTime(form, stamp)local patternif type(form) == "function" thenpattern = form(stamp)elsepattern = formendstamp = tostring(stamp)if mw.ustring.find(pattern, "$1") thenreturn mw.ustring.gsub(pattern, "$1", stamp)elseif string.sub(stamp, 1, 1) == '-' then -- formatDate() only supports years from 0stamp = '+' .. string.sub(stamp, 2)elseif string.sub(stamp, 1, 1) ~= '+' then -- not a valid timestamp, it is a numberstamp = string.format("%04d", stamp)endlocal ret = mw.language.new(parameters.lang[1]):formatDate(pattern, stamp)ret = string.gsub(ret, "^(%[?%[?)0+", "%1") -- suppress leading zerosret = string.gsub(ret, "( %[?%[?)0+", "%1")return retendlocal function postFormat(t)if post_format and mw.ustring.find(post_format, "$1") thenreturn mw.ustring.gsub(post_format, "$1", t)endreturn tendlocal intyear = tonumber(string.match(timestamp, "[+-](%d+)"))local ret = ""if precision <= 5 then -- precision is 10000 years or morelocal factor = 10 ^ ((5 - precision) + 4)local y2 = math.ceil(math.abs(intyear) / factor)local relative = formatTime(i18n.datetime[precision], y2)if post_format == i18n.datetime["bc"] thenret = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative)elseret = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative)endlocal ret_number = string.match(ret, "%d+")if ret_number ~= nil thenret = mw.ustring.gsub(ret, ret_number, mw.language.new(parameters.lang[1]):formatNum(tonumber(ret_number)))endelseif precision == 6 or precision == 7 then -- millennia or centurieslocal card = math.floor((intyear - 1) / 10^(9 - precision)) + 1ret = formatTime(i18n.datetime[precision], card)ret = postFormat(ret)elseif precision == 8 then -- decadeslocal card = math.floor(math.abs(intyear) / 10) * 10ret = formatTime(i18n.datetime[8], card)ret = postFormat(ret)elseif intyear > 9999 then -- not a valid timestampreturnelseif precision == 9 or parameters.formatting == 'Y' then -- precision is yearret = formatTime(i18n.datetime[9], intyear)ret = postFormat(ret) .. calendar_addelseif precision == 10 then -- monthret = formatTime(i18n.datetime[10], timestamp .. " + 1 day") -- formatDate yyyy-mm-00 returns the previous monthret = postFormat(ret) .. calendar_addelse -- precision 11, dayret = formatTime(parameters.formatting or i18n.datetime[11], timestamp)ret = postFormat(ret) .. calendar_addendreturn ret, timestampend-- format data value wikibase-entityid with data types wikibase-item or wikibase-propertylocal function printDatatypeEntity(data, parameters)local entity_id = data['id']if parameters.formatting == 'raw' thenreturn entity_id, entity_idendlocal entity_page = 'Special:EntityPage/' .. entity_idlocal label, lang = getLabelByLangs(entity_id, parameters.lang)local sitelink = mw.wikibase.getSitelink(entity_id)local parameter = parameters.formattinglocal labelcase = label or sitelinkif parameters.gender == 'feminineform' thenlabelcase = feminineForm(entity_id, lang) or labelcaseendif parameters.case ~= 'gender' thenlabelcase = case(parameters.case, labelcase, lang, parameters.lang[1], entity_id, parameters.id)endif labelcase == nil and i18n.qidlabels == false thenreturnendlocal ret1, ret2if parameter == 'label' thenret1 = labelcase or entity_idret2 = labelcase or entity_idelseif parameter == 'sitelink' thenret1 = (sitelink or 'd:' .. entity_page)ret2 = sitelink or entity_idelseif mw.ustring.find((parameter or ''), '$1', 1, true) then -- formatting = a patternret1 = mw.ustring.gsub(parameter, '$1', labelcase or entity_id)ret1 = expandBraces(ret1, parameter)ret2 = labelcase or entity_idelseif parameter == "ucfirst" or parameter == "ucinternallink" thenif labelcase and lang thenlabelcase = mw.language.new(lang):ucfirst(labelcase)end-- only first of a list, reset formatting for next onesif parameter == "ucinterlanllink" thenparameters.formatting = 'internallink'elseparameters.formatting = nil -- default formatendendif sitelink thenret1 = '[[' .. sitelink .. '|' .. labelcase .. ']]'ret2 = labelcaseelseif label and string.match(parameter or '', 'internallink$') and not mw.wikibase.getEntityIdForTitle(label) thenret1 = '[[' .. label .. '|' .. labelcase .. ']]'ret2 = labelcaseelseret1 = '[[d:' .. entity_page .. '|<span style="color:#5f9cbb;">' .. (labelcase or entity_id) .. '</span>]]'ret2 = labelcase or entity_idendendreturn ret1 .. addLabelIcon(entity_id, lang, parameters.lang[1], parameters.labelicon), ret2end-- format data type wikibase-lexemelocal function printDatatypeLexeme(data, parameters)local entity_id = data['id']if parameters.formatting == 'raw' thenreturn entity_id, entity_idendlocal lemmas = mw.wikibase.getEntity(entity_id):getLemmas()if parameters.list == 'lang' and lemmas[1][2] ~= parameters.lang[1] thenreturnendlocal ret = '[[d:Special:EntityPage/' .. entity_id .. '|<span style="color:#5f9cbb;">' .. lemmas[1][1] .. '</span>]]'if parameters.list ~= 'lang' or (parameters.list == 'lang' and lemmas[1][2] ~= wiki.langcode) thenret = ret .. " <sup>(" .. lemmas[1][2] .. ")</sup>"endreturn ret, entity_idend-- format data type monolingualtextlocal function printDatatypeMonolingual(data, parameters)-- data fields: language [string], text [string]if parameters.list == "lang" and data["language"] ~= parameters.lang[1] thenreturnelseif parameters.list == "notlang" and data["language"] == parameters.lang[1] thenreturnelseif parameters.formatting == "language" or parameters.formatting == "text" thenreturn data[parameters.formatting]endlocal result = data["text"]if data["language"] ~= wiki.langcode thenresult = mw.ustring.gsub('<span lang="$1">$2</span>', '$[12]', {["$1"]=data["language"], ["$2"]=data["text"]})endif mw.ustring.find((parameters.formatting or ''), '$', 1, true) then-- output format defined with $text, $languageresult = mw.ustring.gsub(parameters.formatting, '$text', result)result = mw.ustring.gsub(result, '$language', data["language"])endreturn resultendlocal function getSnakValue(snak, parameters)parameters.editbridge = falseif snak.snaktype == 'value' then -- see Special:ListDatatypes-- data value stringif snak.datatype == "string" thenparameters.editbridge = true -- Wikidata Bridge currently only for string valuesreturn printDatatypeString(snak.datavalue.value, parameters)elseif snak.datatype == "commonsMedia" or snak.datatype == "geo-shape" thenreturn printDatatypeMedia(snak.datavalue.value, parameters)elseif snak.datatype == "tabular-data" thenreturn printDatatypeTabular(snak.datavalue.value, parameters)elseif snak.datatype == "url" thenreturn printDatatypeUrl(snak.datavalue.value, parameters)elseif snak.datatype == "external-id" thenreturn printDatatypeExternal(snak.datavalue.value, parameters)elseif snak.datatype == 'math' thenreturn printDatatypeMath(snak.datavalue.value)elseif snak.datatype == 'musical-notation' thenreturn printDatatypeMusical(snak.datavalue.value, parameters.formatting)-- data types other than string valueelseif snak.datatype == 'wikibase-item' or snak.datatype == 'wikibase-property' thenif i18n.suppress[snak.datavalue.value.id] thenreturnendreturn printDatatypeEntity(snak.datavalue.value, parameters)elseif snak.datatype == 'wikibase-lexeme' thenreturn printDatatypeLexeme(snak.datavalue.value, parameters)elseif snak.datatype == 'monolingualtext' thenreturn printDatatypeMonolingual(snak.datavalue.value, parameters)elseif snak.datatype == "globe-coordinate" thenreturn printDatatypeCoordinate(snak.datavalue.value, parameters.formatting)elseif snak.datatype == "quantity" thenreturn printDatatypeQuantity(snak.datavalue.value, parameters)elseif snak.datatype == "time" thenreturn printDatatypeTime(snak.datavalue.value, parameters)endelseif snak.snaktype == 'novalue' thenif parameters.formatting == 'raw' or parameters.shownovalue == false then return endreturn mw.message.new('Wikibase-snakview-snaktypeselector-novalue'):inLanguage(parameters.lang[1]):plain()elseif snak.snaktype == 'somevalue' thenif parameters.formatting == 'raw' or parameters.showsomevalue == false then return endreturn mw.message.new('Wikibase-snakview-snaktypeselector-somevalue'):inLanguage(parameters.lang[1]):plain()endreturn mw.wikibase.renderSnak(snak)endlocal function printError(key)return '<span class="error">' .. i18n.errors[key] .. '</span>'endlocal function getQualifierSnak(claim, qualifierId, parameters)-- a "snak" is Wikidata terminology for a typed key/value pair-- a claim consists of a main snak holding the main information of this claim,-- as well as a list of attribute snaks and a list of references snaksif qualifierId then-- search the attribute snak with the given qualifier as keyif claim.qualifiers thenlocal qualifier = claim.qualifiers[qualifierId]if qualifier thenif qualifier[1].datatype == "monolingualtext" then-- iterate over monolingualtext qualifiers to get local languagefor idx in pairs(qualifier) doif getSnak(qualifier[idx], {"datavalue", "value", "language"}) == parameters.lang[1] thenreturn qualifier[idx]endendelseif parameters.list thenreturn qualifierelsereturn qualifier[1]endendendreturn nil, printError("qualifier-not-found")else-- otherwise return the main snakreturn claim.mainsnakendendlocal function getValueOfClaim(claim, qualifierId, parameters)local snak, error = getQualifierSnak(claim, qualifierId, parameters)if not snak thenreturn nil, nil, errorelseif snak[1] then -- a multi qualifierlocal result, sortkey = {}, {}local maxvals = tonumber(parameters.listmax)for idx in pairs(snak) doresult[#result + 1], sortkey[#sortkey + 1] = getSnakValue(snak[idx], parameters)if maxvals and maxvals == #result then break endendreturn mw.text.listToText(result, parameters.qseparator, parameters.qconjunction), sortkey[1]else -- a property or a qualifierreturn getSnakValue(snak, parameters)endendlocal function getValueOfParentClaim(claim, qualifierId, parameters)local qids = mw.text.split(qualifierId, '/', true)local value, sortkey, valueraw = {}, {}, {}local parent_raw, value_textif qids[1] == parameters.property thenparent_raw, _, _ = getValueOfClaim(claim, nil, {["formatting"]="raw", ["lang"]=parameters.lang})elseparent_raw, _, _ = getValueOfClaim(claim, qids[1], {["formatting"]="raw", ["lang"]=parameters.lang, ["list"]=true, ["qseparator"]='/', ["qconjunction"]='/'})endif string.sub(parent_raw or '', 1, 1) == "Q" then -- protection for 'no value'local parent_qids = mw.text.split(parent_raw, '/', true)for idx, p_qid in ipairs(parent_qids) dolocal parent_claims = mw.wikibase.getBestStatements(p_qid, qids[2])if parent_claims[1] thenvalue[idx], sortkey[idx], _ = getValueOfClaim(parent_claims[1], nil, parameters)-- raw parent value needed for while/black lists, lang for avoiding an error on types other than entityvalueraw[idx], _, _ = getValueOfClaim(parent_claims[1], nil, {["formatting"]="raw", ["lang"]=parameters.lang})endendendif value[1] thenvalue_text = mw.text.listToText(value, parameters.qseparator, parameters.qconjunction)endreturn value_text, sortkey[1], valueraw[1]end-- see d:Help:Sourceslocal function getReferences(claim, parameters)if not (parameters.references or parameters.onlysourced) thenreturn '', falseendlocal lang = parameters.langlocal maxrefs = tonumber(parameters.references) or 1local notproperref = {["P143"] = true, -- imported from["P3452"] = true, -- inferred from["P887"] = true, -- based on heuristic["P4656"] = true -- Wikimedia import URL}local result = {}-- traverse through all referencesfor ref in pairs(claim.references or {}) dolocal refpartslocal refs = {}local validref = truelocal ref_id-- traverse through all parts of the current referencefor snakkey, snakval in pairs(claim.references[ref].snaks or {}) dofor partkey, _ in pairs(claim.references[ref].snaks[snakkey] or {}) doif notproperref[snakkey] then -- not a proper referencevalidref = falsebreakendendif validref thenfor snakidx = 1, #snakval doif snakidx > 1 then refparts = refparts .. ", " endif snakval[snakidx].datatype == 'external-id' thenrefparts = refparts or '' .. (getSnakValue(snakval[snakidx], {formatting='externalid', property=snakval[snakidx].property, lang=lang}) or '')elserefparts = refparts or '' .. (getSnakValue(snakval[snakidx], {lang=lang}) or '')endendrefs[snakkey] = refpartsrefparts = nilif snakkey == "P248" then -- stated inref_id = getSnak(snakval, {1, "datavalue", "value", "id"})endendend-- fill missing values with parent itemif ref_id thenlocal function refParent(qid, pid, formatting)local snak = getSnak(mw.wikibase.getBestStatements(qid, pid), {1, "mainsnak"})return snak and getSnakValue(snak, {formatting=formatting, lang=lang})endrefs['P50'] = refs['P50'] or refParent(ref_id, 'P50', 'label') -- authorrefs['P407'] = refs['P407'] or refParent(ref_id, 'P407', 'label') -- language of workrefs['P123'] = refs['P123'] or refParent(ref_id, 'P123', 'label') -- publisherrefs['P577'] = refs['P577'] or refParent(ref_id, 'P577') -- daterefs['P1433'] = refs['P1433'] or refParent(ref_id, 'P1433', 'label') -- published inrefs['P304'] = refs['P304'] or refParent(ref_id, 'P304') -- page(s)refs['P433'] = refs['P433'] or refParent(ref_id, 'P433') -- issuerefs['P236'] = refs['P236'] or refParent(ref_id, 'P236') -- ISSNrefs['P356'] = refs['P356'] or refParent(ref_id, 'P356') -- DOIend-- get title of local templates for citing referenceslocal template_web = mw.wikibase.getSitelink('Q5637226') or ""template_web = mw.text.split(template_web, ":")[2] -- split off namespace from frontlocal template_journal = mw.wikibase.getSitelink('Q5624899') or ""template_journal = mw.text.split(template_journal, ":")[2]local citeParams = {}if refs['P854'] and (refs['P1476'] or refs['P248']) and template_web then-- if both "reference URL" and "title" (or "stated in") are present, then use cite web templateciteParams[i18n['cite']['url']] = refs['P854']if refs['P248'] and refs['P1476'] == nil thenciteParams[i18n['cite']['title']] = refs['P248']:match("^%[%[.-|(.-)%]%]")elseciteParams[i18n['cite']['title']] = refs['P1476']citeParams[i18n['cite']['website']] = refs['P248']endciteParams[i18n['cite']['author']] = refs['P50']citeParams[i18n['cite']['language']] = refs['P407']citeParams[i18n['cite']['publisher']] = refs['P123']citeParams[i18n['cite']['date']] = refs['P577']citeParams[i18n['cite']['pages']] = refs['P304']citeParams[i18n['cite']['access-date']] = refs['P813']citeParams[i18n['cite']['archive-url']] = refs['P1065']citeParams[i18n['cite']['archive-date']] = refs['P2960']citeParams[i18n['cite']['quote']] = refs['P1683']refparts = mw.getCurrentFrame():expandTemplate{title=template_web, args=citeParams}elseif refs['P1433'] and (refs['P1476'] or refs['P248']) and template_journal then-- if both "published in" and "title" (or "stated in") are present, then use cite journal templateciteParams[i18n['cite']['work']] = refs['P1433']citeParams[i18n['cite']['title']] = refs['P1476'] or refs['P248']citeParams[i18n['cite']['author']] = refs['P50']citeParams[i18n['cite']['date']] = refs['P577']citeParams[i18n['cite']['issue']] = refs['P433']citeParams[i18n['cite']['pages']] = refs['P304']citeParams[i18n['cite']['language']] = refs['P407']citeParams[i18n['cite']['issn']] = refs['P236']citeParams[i18n['cite']['doi']] = refs['P356']refparts = mw.getCurrentFrame():expandTemplate{title=template_journal, args=citeParams}elseif validref then-- raw ouputlocal snaksorder = claim.references[ref]["snaks-order"]local function indexed(a)for _, b in ipairs(snaksorder) doif b == a then return true endendreturn falseendfor k, _ in pairs(refs or {}) doif not indexed(k) thentable.insert(snaksorder, k)endendlocal italics = "''"for _, k in ipairs(snaksorder) doif refs[k] thenrefparts = refparts and refparts .. " " or ""refparts = refparts .. mw.ustring.gsub(getLabelByLangs(k, lang), "^%l", mw.ustring.upper) .. ": "refparts = refparts .. italics .. refs[k] .. italics .. "."italics = ""endendendif refparts thenlocal ref_name = claim.references[ref].hashresult[#result + 1] = mw.getCurrentFrame():extensionTag("ref", refparts, {name=ref_name})if maxrefs and maxrefs == #result then break endendendif #result > 0 thenif parameters.references thenif isSet(i18n.categoryref) thenresult[#result + 1] = "[[" ..i18n.categoryref .. "]]"endreturn table.concat(result), trueelsereturn '', trueendendreturn '', falseend-- Set whitelist or blacklist valueslocal function setWhiteOrBlackList(num_qual, args)local lists = {['whitelist']={}, ['blacklist']={}, ['ignorevalue']={}, ['selectvalue']={}}for i = 0, num_qual dofor k, _ in pairs(lists) doif isSet(args[k .. i]) thenlists[k][tostring(i)] = {}local pattern = 'Q%d+'if string.sub(args[k .. i], 1, 1) ~= 'Q' thenpattern = '[^%p%s]+'endfor q in string.gmatch(args[k .. i], pattern) dolists[k][tostring(i)][q] = trueendendendendreturn lists['whitelist'], lists['blacklist'], lists['ignorevalue'], lists['selectvalue']endlocal function tableParameters(args, parameters, column)local column_params = mw.clone(parameters)column_params.formatting = args["colformat"..column]; if column_params.formatting == "" then column_params.formatting = nil endcolumn_params.convert = args["convert" .. column]if args["case" .. column] thencolumn_params.case = args["case" .. column]endreturn column_paramsendlocal function getEntityId(args, pargs, unnamed)pargs = pargs or {}local id = args.item or args.from or (unnamed and mw.text.trim(args[1] or '') or nil)if not isSet(id) thenid = pargs.item or pargs.from or (unnamed and mw.text.trim(pargs[1] or '') or nil)endif isSet(id) thenif string.find(id, ":") then -- remove prefix as Property:Pidid = mw.text.split(id, ":")[2]endelseid = mw.wikibase.getEntityIdForCurrentPage()endreturn idendlocal function getArg(value, default, aliases)if type(value) == 'boolean' then return valueelseif value == "false" or value == "no" then return falseelseif value == "true" or value == "yes" then return trueelseif value and aliases and aliases[value] then return aliases[value]elseif isSet(value) then return valueelseif default then return defaultelse return nilendend-- Main function claim ----------------------------------------------- on debug console use: =p.claim{item="Q...", property="P...", ...}function p.claim(frame)local args = frame.args or frame -- via invoke or requirelocal pargs = frame.args and frame:getParent().args or {}local is_sandbox = isSet(pargs.sandbox)if not required and is_sandbox thenreturn require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).claim(frame)end--If a value is already set, use itif isSet(args.value) thenif args.value == 'NONE' thenreturnelsereturn args.valueendend-- argumentslocal parameters = {}parameters.id = getEntityId(args, pargs)if parameters.id == nil then return endparameters.property = string.upper(args.property or "")local qualifierId = {}qualifierId[1] = getArg(string.upper(args.qualifier or args.qualifier1 or ""))local i = 2while isSet(args["qualifier" .. i]) doqualifierId[i] = string.upper(args["qualifier" .. i])i = i + 1endparameters.formatting = getArg(args.formatting)parameters.convert = getArg(args.convert)parameters.numformat = getArg(args.numformat)parameters.case = args.caseparameters.list = getArg(args.list, true, {firstrank='bestrank'})parameters.listmax = args.listmaxparameters.listrank = getArg(args.listrank)if type(parameters.list) == "number" then -- backwards compatibilityparameters.listmax = parameters.listmax or parameters.listparameters.list = trueelseif parameters.list == "bestrank" thenparameters.listrank = parameters.listrank or "bestrank"parameters.list = trueendparameters.shownovalue = getArg(args.shownovalue, true)parameters.showsomevalue = getArg(args.showsomevalue, true)parameters.separator = getArg(args.separator)parameters.conjunction = getArg(args.conjunction, parameters.separator)parameters.qseparator = getArg(args.qseparator, parameters.separator)parameters.qconjunction = getArg(args.qconjunction, parameters.conjunction)local sorting_col = args.tablesortlocal sorting_up = (args.sorting or "") ~= "-1"local rowformat = args.rowformatparameters.references = getArg(args.references, false)parameters.onlysourced = getArg(args.onlysourced, false)local showerrors = args.showerrorslocal default = args.defaultif default then showerrors = nil endparameters.lang = findLang(args.lang)if parameters.formatting == "raw" thenparameters.editicon, parameters.labelicon = false, falseelseparameters.editicon, parameters.labelicon = setIcons(args.editicon, pargs.editicon) -- needs loadI18n by findLandend-- fetch propertylocal claims = {}local bestrank = parameters.listrank == 'bestrank' and parameters.list ~= 'lang'for p in string.gmatch(parameters.property, 'P%d+') doclaims = getStatements(parameters.id, p, bestrank)if #claims > 0 thenparameters.property = pbreakendendif #claims == 0 thenlocal ret = showerrors and printError("property-not-found") or defaultreturn ret, args.query == 'num' and 0 or ''end-- defaults for tablelocal preformat, postformat = "", ""local whitelisted = falselocal whitelist, blacklist, ignorevalue, selectvalue = {}, {}, {}, {}if parameters.formatting == "table" thenparameters.separator = parameters.separator or "<br />"parameters.conjunction = parameters.conjunction or "<br />"parameters.qseparator = getArg(args.qseparator, mw.message.new('Comma-separator'):inLanguage(parameters.lang[1]):plain())parameters.qconjunction = getArg(args.qconjunction, parameters.qseparator)if not rowformat thenrowformat = "$0 ($1"i = 2while qualifierId[i] dorowformat = rowformat .. ", $" .. ii = i + 1endrowformat = rowformat .. ")"elseif mw.ustring.find(rowformat, "^[*#]") thenparameters.separator = "</li><li>"parameters.conjunction = "</li><li>"if mw.ustring.match(rowformat, "^[*#]") == "*" thenpreformat = "<ul><li>"postformat = "</li></ul>"elsepreformat = "<ol><li>"postformat = "</li></ol>"endrowformat = mw.ustring.gsub(rowformat, "^[*#] ?", "")end-- set whitelist and blacklist valueswhitelist, blacklist, ignorevalue, selectvalue = setWhiteOrBlackList(#qualifierId, args)local next = nextif next(whitelist) ~= nil then whitelisted = true endend-- set feminine case if gender is requestedlocal itemgender = args.itemgenderlocal idgenderif itemgender thenif string.match(itemgender, "^P%d+$") thenlocal snak_id = getSnak(mw.wikibase.getBestStatements(parameters.id, itemgender), {1, "mainsnak", "datavalue", "value", "id"})if snak_id thenidgender = snak_idendelseif string.match(itemgender, "^Q%d+$") thenidgender = itemgenderendendlocal gender_requested = falseif parameters.case == "gender" or idgender thengender_requested = trueelseif parameters.formatting == "table" thenfor i=0, #qualifierId doif args["case" .. i] and args["case" .. i] == "gender" thengender_requested = truebreakendendendif gender_requested thenif feminineGender(idgender or parameters.id) thenparameters.gender = "feminineform"endend-- get initial sort indiceslocal sortindices = {}for idx in pairs(claims) dosortindices[#sortindices + 1] = idxend-- sort by claim ranklocal comparator = function(a, b)local rankmap = { deprecated = 2, normal = 1, preferred = 0 }local ranka = rankmap[claims[a].rank or "normal"] .. string.format("%08d", a)local rankb = rankmap[claims[b].rank or "normal"] .. string.format("%08d", b)return ranka < rankbendtable.sort(sortindices, comparator)local result, result2, result_querylocal errorif parameters.list or parameters.formatting == "table" then-- convert LF to line feed, <br /> may not work on some casesparameters.separator = parameters.separator == "LF" and "\010" or parameters.separatorparameters.conjunction = parameters.conjunction == "LF" and "\010" or parameters.conjunction-- i18n separatorsparameters.separator = parameters.separator or mw.message.new('Comma-separator'):inLanguage(parameters.lang[1]):plain()parameters.conjunction = parameters.conjunction or (mw.message.new('And'):inLanguage(parameters.lang[1]):plain() .. mw.message.new('Word-separator'):inLanguage(parameters.lang[1]):plain())-- iterate over all elements and return their value (if existing)local value, valueqlocal sortkey, sortkeyqlocal values = {}local sortkeys = {}local refs = {}local rowlist = {} -- rows to list with whitelist or blacklistfor idx in pairs(claims) dolocal claim = claims[sortindices[idx]]local reference = {}if not whitelisted then rowlist[idx] = true endif parameters.formatting == "table" thenlocal params = tableParameters(args, parameters, "0")value, sortkey, error = getValueOfClaim(claim, nil, params)if value thenvalues[#values + 1] = {}sortkeys[#sortkeys + 1] = {}refs[#refs + 1] = {}if whitelist["0"] or blacklist["0"] thenlocal valueraw, _, _ = getValueOfClaim(claim, nil, {["formatting"]="raw", ["lang"]=params.lang})if whitelist["0"] and whitelist["0"][valueraw or ""] thenrowlist[#values] = trueelseif blacklist["0"] and blacklist["0"][valueraw or ""] thenrowlist[#values] = falseendendfor i, qual in ipairs(qualifierId) dolocal j = tostring(i)params = tableParameters(args, parameters, j)local valueq, sortkeyq, valuerawif qual == parameters.property then -- hack for getting the property with another formatting, i.e. colformat1=rawvalueq, sortkeyq, _ = getValueOfClaim(claim, nil, params)elsefor q in mw.text.gsplit(qual, '%s*OR%s*') doif string.find(q, ".+/.+") thenvalueq, sortkeyq, valueraw = getValueOfParentClaim(claim, q, params)elseif string.find(q, "^/.+") thenlocal claim2 = getStatements(parameters.id, string.sub(q, 2), bestrank)if #claim2 > 0 then-- only first value of a property as alternative to a qualifier-- multiple values may not be related to a given raw of the tablevalueq, sortkeyq, _ = getValueOfClaim(claim2[1], nil, params)endelsevalueq, sortkeyq, _ = getValueOfClaim(claim, q, params)endif valueq thenqual = qbreakendendendvalues[#values]["col" .. j] = valueqsortkeys[#sortkeys]["col" .. j] = sortkeyq or valueqif whitelist[j] or blacklist[j] or ignorevalue[j] or selectvalue[j] thenvalueq = valueraw or getValueOfClaim(claim, qual, {["formatting"]="raw", ["lang"]=params.lang})if whitelist[j] and whitelist[j][valueq or ""] thenrowlist[#values] = trueelseif blacklist[j] and blacklist[j][valueq or ""] thenrowlist[#values] = falseelseif ignorevalue[j] and ignorevalue[j][valueq or ""] thenvalues[#values]["col" .. j] = nilelseif selectvalue[j] and not selectvalue[j][valueq or ""] thenvalues[#values]["col" .. j] = nilendendendendelsevalue, sortkey, error = getValueOfClaim(claim, qualifierId[1], parameters)values[#values + 1] = {}sortkeys[#sortkeys + 1] = {}refs[#refs + 1] = {}endif not value and showerrors then value = error endif value thenif (parameters.references or parameters.onlysourced) and claim.references thenreference = claim.referencesendrefs[#refs]["col0"] = referencevalues[#values]["col0"] = valuesortkeys[#sortkeys]["col0"] = sortkey or valueendend-- sort and format resultssortindices = {}for idx in pairs(values) dosortindices[#sortindices + 1] = idxendif sorting_col thenlocal sorting_table = mw.text.split(sorting_col, '%D+')local comparator = function(a, b)local valuea, valueblocal i = 1while valuea == valueb and i <= #sorting_table dovaluea = sortkeys[a]["col" .. sorting_table[i]] or ''valueb = sortkeys[b]["col" .. sorting_table[i]] or ''i = i + 1endif sorting_up thenreturn valueb > valueaendreturn valueb < valueaendtable.sort(sortindices, comparator)endlocal maxvals = tonumber(parameters.listmax)result = {}for idx in pairs(values) dolocal valuerow = values[sortindices[idx]]local reference, valid_ref = getReferences({["references"] = refs[sortindices[idx]]["col0"]}, parameters)value = valuerow["col0"]if parameters.formatting == "table" thenif not rowlist[sortindices[idx]] thenvalue = nilelselocal rowformatting = rowformat .. "$" -- fake end character added for easy gsubvalue = mw.ustring.gsub(rowformatting, "$0", {["$0"] = value})value = mw.ustring.gsub(value, "$R0", reference) -- add referencefor i, _ in ipairs(qualifierId) dolocal valueq = valuerow["col" .. i]if args["rowsubformat" .. i] and isSet(valueq) then-- add fake end character $-- gsub $i not followed by a number so $1 doesn't match $10, $11...-- remove fake end charactervalueq = captureEscapes(valueq)valueq = mw.ustring.gsub(args["rowsubformat" .. i] .. "$", "$" .. i .. "(%D)", valueq .. "%1")valueq = string.sub(valueq, 1, -2)rowformatting = mw.ustring.gsub(rowformatting, "$" .. i .. "(%D)", args["rowsubformat" .. i] .. "%1")endvalueq = valueq and captureEscapes(valueq) or ''value = mw.ustring.gsub(value, "$" .. i .. "(%D)", valueq .. "%1")endvalue = string.sub(value, 1, -2) -- remove fake end charactervalue = expandBraces(value, rowformatting)endelseif value thenvalue = expandBraces(value, parameters.formatting)value = value .. referenceendif isSet(value) and (not parameters.onlysourced or (parameters.onlysourced and valid_ref)) thenresult[#result + 1] = valueif not parameters.list or (maxvals and maxvals == #result) thenbreakendendendif args.query == 'num' thenresult_query = #resultendif #result > 0 thenif parameters.formatting == 'table' thenresult = addEditIconTable(result, parameters) -- in a table, add edit icon on last elementendresult = preformat .. mw.text.listToText(result, parameters.separator, parameters.conjunction) .. postformatelseresult = ''endelse-- return first elementlocal claim = claims[sortindices[1]]result, result2, error = getValueOfClaim(claim, qualifierId[1], parameters)if result thenlocal ref, valid_ref = getReferences(claim, parameters)if parameters.onlysourced and valid_ref == false thenresult = nilelseresult = result .. refendendif args.query == 'num' then result_query = result and 1 or 0 endendif isSet(result) thenif not (parameters.formatting == 'table' or (result2 and result2 == 'no-icon')) then-- add edit icon, except table added previously and except explicit no-icon internal flagresult = result .. addEditIcon(parameters)endelseif showerrors then result = error else result = default endendif args.query == 'untranslated' and required and not is_sandbox thenresult_query = untranslatedendreturn result, result_query or ''end-- Local functions for getParentValues -----------------------local function uc_first(word)if word == nil then return endreturn mw.ustring.upper(mw.ustring.sub(word, 1, 1)) .. mw.ustring.sub(word, 2)endlocal function getPropertyValue(id, property, parameter, langs, labelicon, case)local snaks = mw.wikibase.getBestStatements(id, property)local mysnak = getSnak(snaks, {1, "mainsnak"})if mysnak == nil thenreturnendlocal entity_idlocal result = '-' -- default for 'no value'if mysnak.datavalue thenentity_id = "Q" .. tostring(mysnak.datavalue.value['numeric-id'])result, _ = getSnakValue(mysnak, {formatting=parameter, lang=langs, labelicon=labelicon, case=case})endreturn entity_id, resultendlocal function getParentObjects(id,prop_format,label_format,languages, propertySupString, propertyLabel,propertyLink,label_show,labelicon0,labelicon1,upto_number,upto_label,upto_value,last_only,grammatical_case,include_self)local propertySups = mw.text.split(propertySupString, '[^P%d]')local maxloop = 10if upto_number thenmaxloop = tonumber(upto_number)elseif next(upto_label) or next(upto_value) thenmaxloop = 50endlocal labels_filter = next(label_show)local result = {}local id_value = idfor iter = 1, maxloop dolocal link, label, labelwicon, linktext, id_labelfor _, propertySup in pairs(propertySups) do local _id_value, _link = getPropertyValue(id_value, propertySup, prop_format, languages, labelicon1, grammatical_case)if _id_value and _link then id_value = _id_value; link = _link break endendif not id_value or not link then break endif propertyLink then_, linktext = getPropertyValue(id_value, propertyLink, "label", languages)if linktext thenlink = mw.ustring.gsub(link, "%[%[(.*)%|.+%]%]", "[[%1|" .. linktext .. "]]")endendid_label, label = getPropertyValue(id_value, propertyLabel, label_format, languages, false, "infoboxlabel")if labelicon0 then_, labelwicon = getPropertyValue(id_value, propertyLabel, label_format, languages, labelicon0, "infoboxlabel")elselabelwicon = labelendif labels_filter == nil or (label_show[id_label] or label_show[label]) thenresult[#result + 1] = {labelwicon, link}label_show[id_label or 'none'], label_show[label or 'none'] = nil, nil -- only first label foundendif upto_label[id_label] or upto_label[label] or upto_value[id_value] thenbreakendendif last_only thenresult = {result[#result]}endif include_self thenlocal label_self, link_self_, label_self = getPropertyValue(id, propertyLabel, label_format, languages, labelicon0, "infoboxlabel")link_self, _ = getLabelByLangs(id, languages)table.insert(result, 1, {label_self, link_self})endreturn resultendlocal function parentObjectsToString(result,rowformat,cascade,sorting)local ret = {}local first = 1local last = #resultlocal iter = 1if sorting == "-1" then first = #result; last = 1; iter = -1 endfor i = first, last, iter dolocal rowtext = mw.ustring.gsub(rowformat, "$[01]", {["$0"] = result[i][1], ["$1"] = result[i][2]})ret[#ret + 1] = expandBraces(rowtext, rowformat)endif cascade thenlocal direction = mw.language.new(wiki.langcode):isRTL() and "right" or "left"local suffix = ""for i = 1, #ret doret[i] = '<ul style="line-height:100%; margin-' .. direction .. ':0.45em; padding-' .. direction .. ':0;"><li>' .. ret[i]suffix = suffix .. '</li></ul>'endret[#ret] = ret[#ret] .. suffixendreturn retend-- Returns pairs of parent label and property value fetching a recursive treefunction p.getParentValues(frame)local args = frame.args or frame -- via invoke or requirelocal pargs = frame.args and frame:getParent().args or {}if not required and isSet(pargs.sandbox) thenreturn require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).getParentValues(frame)endlocal id = getEntityId(args, pargs)if id == nil then return endlocal languages = findLang(args.lang)local propertySup = getArg(args.property, "P131") --administrative entitylocal propertyLabel = getArg(args.label, "P31") --instancelocal propertyLink = getArg(args.valuetext)local property_format = getArg(args.formatting)local label_format = getArg(args.labelformat, "label")local upto_number = getArg(args.upto)local last_only = getArg(args.last_only, false)local editicon, labelicon = setIcons(args.editicon, pargs.editicon)local include_self = getArg(args.include_self, false)local case = getArg(args.case)local upto_label = {}for q in string.gmatch(args.uptolabelid or '', 'Q%d+') doupto_label[q] = trueendif type(upto_number) == 'string' thenupto_label[uc_first(upto_number)] = trueupto_number = nilrequire(wiki.module_title .. '/debug').track('upto') -- replace upto by uptolabelidendlocal upto_value = {}for q in string.gmatch(args.uptovalueid or args.uptolinkid or '', 'Q%d+') doupto_value[q] = trueendlocal label_show = {}for q in string.gmatch(args.showlabelid or '', 'Q%d+') dolabel_show[q] = trueendfor _, v in ipairs(mw.text.split(args.labelshow or '', "/")) doif v ~= '' thenlabel_show[uc_first(v)] = truerequire(wiki.module_title .. '/debug').track('labelshow') -- replace labelshow by showlabelidendendlocal rowformat = args.rowformat; if not isSet(rowformat) then rowformat = "$0 = $1" endlocal labelicon0, labelicon1 = labelicon, labeliconif string.find(label_format, '{{.*$0.*}}') or (string.find(rowformat, '{{.*$0.*}}') and label_format ~= 'raw') thenlabelicon0 = falseendlocal result = getParentObjects(id,property_format,label_format,languages, propertySup, propertyLabel,propertyLink,label_show,labelicon0,labelicon1,upto_number,upto_label,upto_value,last_only,case,include_self)if #result == 0 then return endlocal separator = args.separator; if not isSet(separator) then separator = "<br />" endlocal sorting = args.sorting; if sorting == "" then sorting = nil endlocal cascade = (args.cascade == "true" or args.cascade == "yes")local ret = parentObjectsToString(result,rowformat,cascade,sorting)ret = addEditIconTable(ret, {property=propertySup, editicon=editicon, id=id, lang=languages})return mw.text.listToText(ret, separator, separator)end-- Link with a parent label --------------------function p.linkWithParentLabel(frame)local pargs = frame.args and frame:getParent().args or {}if not required and isSet(pargs.sandbox) thenreturn require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).linkWithParentLabel(frame)endlocal args = {}if frame.args thenfor k, v in pairs(frame.args) do -- metatableargs[k] = vendelseargs = frame -- via requireendif isSet(args.value) thenreturn args.valueend-- get id value of property/qualifierlocal largs = mw.clone(args)largs.list = tonumber(args.list) and args.list or truelargs.formatting = "raw"largs.separator = "/·/"largs.editicon = falselocal items_list, _ = p.claim(largs)if not isSet(items_list) then return endlocal items_table = mw.text.split(items_list, "/·/", true)-- get internal link of property/qualifierlargs.formatting = "internallink"local link_list, _ = p.claim(largs)local link_table = mw.text.split(link_list, "/·/", true)-- get label of parent propertylocal parent_claim = getSnak(getStatements(items_table[1], args.parent, true), {1, "mainsnak", "datatype"})if parent_claim == 'monolingualtext' thenlargs.formatting = nillargs.list = 'lang'elselargs.formatting = "label"largs.list = falseendlargs.property = args.parentlargs.qualifier = nilfor i, v in ipairs(items_table) dolargs.item = vlocal link_label, _ = p.claim(largs)if isSet(link_label) thenlink_table[i] = mw.ustring.gsub(link_table[i] or '', "%[%[(.*)%|.+%]%]", "[[%1|" .. link_label .. "]]")endendargs.editicon, _ = setIcons(args.editicon, pargs.editicon)args.id = getEntityId(args, pargs)args.lang = findLang(args.lang)return mw.text.listToText(link_table) .. addEditIcon(args)end-- Calculate number of years old ----------------------------function p.yearsOld(frame)if not required and frame.args and isSet(frame:getParent().args.sandbox) thenreturn require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).yearsOld(frame)endlocal args = frame.args or frame -- via invoke or requirelocal pargs = frame.args and frame:getParent().args or {}local id = getEntityId(args, pargs)if id == nil then return endlocal lang = mw.language.new('en')local function getBestValue(id, prop)return getSnak(mw.wikibase.getBestStatements(id, prop), {1, "mainsnak", "datavalue", "value"})endlocal birth = getBestValue(id, 'P569')if type(birth) ~= 'table' or birth.time == nil or birth.precision == nil or birth.precision < 8 thenreturnendlocal death = getBestValue(id, 'P570')if type(death) ~= 'table' or death.time == nil or death.precision == nil thendeath = {['time'] = lang:formatDate('c'), ['precision'] = 11} -- current dateelseif death.precision < 8 thenreturnendlocal dates = {}dates[1] = {['min'] = {}, ['max'] = {}, ['precision'] = birth.precision}dates[1].min.year = tonumber(mw.ustring.match(birth.time, "^[+-]?%d+"))dates[1].min.month = tonumber(mw.ustring.match(birth.time, "-(%d%d)-"))dates[1].min.day = tonumber(mw.ustring.match(birth.time, "-(%d%d)T"))dates[1].max = mw.clone(dates[1].min)dates[2] = {['min'] = {}, ['max'] = {}, ['precision'] = death.precision}dates[2].min.year = tonumber(mw.ustring.match(death.time, "^[+-]?%d+"))dates[2].min.month = tonumber(mw.ustring.match(death.time, "-(%d%d)-"))dates[2].min.day = tonumber(mw.ustring.match(death.time, "-(%d%d)T"))dates[2].max = mw.clone(dates[2].min)for i, d in ipairs(dates) doif d.precision == 10 then -- monthd.min.day = 1local timestamp = string.format("%04d", tostring(math.abs(d.max.year))).. string.format("%02d", tostring(d.max.month)).. "01"d.max.day = tonumber(lang:formatDate("j", timestamp .. " + 1 month - 1 day"))elseif d.precision < 10 then -- year or decaded.min.day = 1d.min.month = 1d.max.day = 31d.max.month = 12if d.precision == 8 then -- decaded.max.year = d.max.year + 9endendendlocal function age(d1, d2)local years = d2.year - d1.yearif d2.month < d1.month or (d2.month == d1.month and d2.day < d1.day) thenyears = years - 1endif d2.year > 0 and d1.year < 0 thenyears = years - 1 -- no year 0endreturn yearsendlocal old_min = age(dates[1].max, dates[2].min)local old_max = age(dates[1].min, dates[2].max)local old, old_exprif old_min == 0 and old_max == 0 thenold = "< 1"old_max = 1 -- expression in singularelseif old_min == old_max thenold = old_minelseold = old_min .. "/" .. old_maxendif args.formatting == 'unit' thenlocal langs = findLang(args.lang)local yolocal yo_pl = {}if langs[1] == wiki.langcode thenyo_pl = i18n["years-old"]endif not isSet(yo_pl[2]) thenlocal yo_label, _ = getLabelByLangs('Q24564698', langs)yo_pl = {yo_label, yo_label}endyo = mw.language.new(langs[1]):plural(old_max, yo_pl)if mw.ustring.find(yo, '$1', 1, true) thenold_expr = mw.ustring.gsub(yo, "$1", old)elseold_expr = old .. ' ' .. yoendelseif args.formatting thenold_expr = expandBraces(mw.ustring.gsub(args.formatting, '$1', old), args.formatting)elseold_expr = oldendreturn old_exprend-- Gets a label in a given language (content language by default) or its fallbacks, optionnally linked.function p.getLabel(frame)local args = frame.args or frame -- via invoke or requirelocal pargs = frame.args and frame:getParent().args or {}if not required and isSet(pargs.sandbox) thenreturn require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).getLabel(frame)endlocal id = getEntityId(args, pargs, 1)if id == nil then return endlocal languages = findLang(args.lang)local labelicon = falseif mw.wikibase.isValidEntityId(id) then_, labelicon = setIcons(args.editicon, pargs.editicon)endlocal label_icon = ''local label, langif args.label thenlabel = args.labelelse-- exceptions or labels fixedlocal exist, labels = pcall(require, wiki.module_title .. "/labels" .. (languages[1] == wiki.langcode and '' or '/' .. languages[1]))if exist and labels.infoboxLabelsFromId and next(labels.infoboxLabelsFromId) ~= nil thenlabel = labels.infoboxLabelsFromId[id]endif label == nil thenlabel, lang = getLabelByLangs(id, languages)if label thenif isSet(args.itemgender) and feminineGender(args.itemgender) thenlabel = feminineForm(id, lang) or labelendlabel = mw.language.new(lang):ucfirst(mw.text.nowiki(label)) -- sanitizeif args.case thenlabel = case(args.case, label, lang)endendlabel_icon = addLabelIcon(id, lang, languages[1], labelicon)endendlocal linked = args.linkedlocal ret2 = required and untranslated or ''if isSet(linked) and linked ~= "no" thenlocal article = mw.wikibase.getSitelink(id) or ("d:Special:EntityPage/" .. id)return "[[" .. article .. "|" .. (label or id) .. "]]" .. label_icon, ret2elsereturn (label or id) .. label_icon, ret2endend-- Utilities ------------------------------- See also module ../debug.-- Copied from Module:Wikibasefunction p.getSiteLink(frame)local args = frame.args or frame -- via invoke or requirelocal pargs = frame.args and frame:getParent().args or {}local id = getEntityId(args, pargs, 1)if id == nil then return endreturn mw.wikibase.getSitelink(id, mw.text.trim(args[2] or ''))end-- Helper function for the default language code usedfunction p.lang(frame)local lang = frame and frame.args[1] -- nil via requirereturn findLang(lang)[1]end-- Number of statementsfunction p.numStatements(frame)local args = frame.args or frame -- via invoke or requirelocal pargs = frame.args and frame:getParent().args or {}local id = getEntityId(args, pargs)if id == nil then return 0 endlocal prop = mw.text.trim(args[1] or '')local num = {}if not isSet(prop) thenlocal largs = {}for k, v in pairs(pargs) dolargs[k] = vendfor k, v in pairs(args) dolargs[k] = vendlargs.query = 'num'_, num = p.claim(largs)return numelseif args[2] then -- qualifierlocal qual = mw.text.trim(args[2])local values = p.claim{item=id, property=prop, qualifier=qual, formatting='raw', separator='/·/'}if values thennum = mw.text.split(values, '/·/')endelsenum = mw.wikibase.getBestStatements(id, prop)endreturn #numend-- Returns true if property datavalue is found excluding novalue/somevaluefunction p.validProperty(frame)local args = frame.args or frame -- via invoke or requirelocal pargs = frame.args and frame:getParent().args or {}local item = getEntityId(args, pargs)if item == nil then return endlocal property = mw.text.trim(args[1])local prop_data = getSnak(mw.wikibase.getBestStatements(item, property), {1, "mainsnak", "datavalue"})return prop_data and true or nilendfunction p.editAtWikidata(frame)local args = frame.args or frame -- via invoke or requirelocal pargs = frame.args and frame:getParent().args or {}local value = isSet(args[1])if value then return endlocal param = {}param.id = getEntityId(args, pargs)param.property = args.propertyparam.lang = findLang(args.lang)param.editicon, _ = setIcons(args.editicon)return addEditIcon(param)endfunction p.formatNum(frame)local num = tonumber(mw.text.trim(frame.args[1]))local lang = findLang(mw.text.trim(frame.args[2]))return mw.language.new(lang[1]):formatNum(num)endreturn p
🔥 Top keywords: Laman UtamaDua Darjat (drama)Khas:CariKhilaf Yang TertulisHari Raya AidiladhaCinta Untuk Sekali LagiAniq DurarHari TasyrikMonogamiTempoh haram puasaBunga SaljuSenarai peribahasa (A–M)Abang AdikJamrahDharma Harun Al RashidKhas:Perubahan terkiniZim Zim Ala KazimUEFA Euro 2024NafarKobe Jae ChongBRICSErysha EmyraAku Bukan UstazahIbadah korbanAzahari HusinSharifah RoseKata adjektifInna lillahi wa inna ilaihi raji'unNabi Muhammad SAWSolatThe Hardest Singing ShowPlat pendaftaran kenderaan MalaysiaMandi wajibRiena DianaZainalabidinAnwar IbrahimPasukan bola sepak kebangsaan PortugalKesultanan Melayu MelakaProjek: Anchor SPM