Ver la documentación del módulu en ca:Mòdul:Wikidades.


-- version 20231204 from master @cawiki-- changes from previous version: whitelist, blacklist, ignorevalue and selectvalue work with multivalue qualifierslocal p = {}-- Initialization of variables --------------------local i18n = {-- internationalisation at [[Module:Wikidata/i18n]]["errors"] = {["property-not-found"] = "Property not found.",["qualifier-not-found"] = "Qualifier not found.",},["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 billion years",-- precision: billion years[1] = "$100 million years",-- precision: hundred million years[2] = "$10 million years",-- precision: ten million years[3] = "$1 million years",-- precision: million years[4] = "$100000 years",-- precision: hundred thousand years; thousand separators added afterwards[5] = "$10000 years",-- precision: ten thousand years; thousand separators added afterwards[6] = "$1 millennium",-- precision: millennium[7] = "$1 century",-- precision: century[8] = "$1s",-- 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"] = {["hours"] = "h", ["minutes"] = "m", ["seconds"] = "s"},-- duration: xh xm xs},["years-old"] = {"", ""},-- 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 = " [[File: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=" .. uselang .. "]]"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 .. '>'.. "[[File:Arbcom ru editing.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, ["list"]=params.list})if valueq thenif whitelist[j] thenfor k, v in pairs(whitelist[j]) doif v and string.find(valueq, k, 1, true) thenrowlist[#values] = trueendendelseif blacklist[j] thenfor k, v in pairs(blacklist[j]) doif v and string.find(valueq, k, 1, true) thenrowlist[#values] = falseendendelseif ignorevalue[j] thenfor k, v in pairs(ignorevalue[j]) doif v and string.find(valueq, k, 1, true) thenvalues[#values]["col" .. j] = nilendendelseif selectvalue[j] thenlocal selectedfor k, v in pairs(selectvalue[j]) doif v and string.find(valueq, k, 1, true) thenselected = trueendendif selected == nil thenvalues[#values]["col" .. j] = nilendendendendendendelsevalue, 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 .. '&nbsp;' .. 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