wikidata

Documentation for this module may be created at Module:Wikidata/doc

-- version 20200118 from master @cawiki  local p = {}  -- Initialization of variables --------------------  local i18n = {-- internationalisation at [[Module:Wikidata/i18n]] ["errors"] = { ["property-not-found"] = "Property not found.", ["entity-not-found"] = "Wikidata entity 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 },  ["years-old"] = { ["singular"] = "",-- year old, as in {{PLURAL:$1|singular|plural}} ["plural"] = "",-- years old ["paucal"] = "",-- for languages with 3 plural forms as in {{PLURAL:$1|singular|paucal|plural}} },  ["cite"] = {-- Cite web parameters ["url"]= "url", ["title"]= "title", ["website"]= "website", ["access-date"]= "access-date", ["archive-url"]= "archive-url", ["archive-date"]= "archive-date", ["author"]= "author", ["publisher"]= "publisher", ["quote"]= "quote", ["language"]= "language", ["date"]= "date", ["pages"]= "pages" } }  local cases = {} -- functions for local grammatical cases defined at [[Module:Wikidata/i18n]]  local required = ... -- variadic arguments from require function local wiki =  { langcode = mw.language.getContentLanguage().code, module_title = required or mw.getCurrentFrame():getTitle() }  -- Module local functions --------------------------------------------  -- Credit to http://stackoverflow.com/a/1283608/2644759, cc-by-sa 3.0 local function tableMerge(t1, t2) for k,v in pairs(t2) do if type(v) == "table" then if type(t1[k] or false) == "table" then tableMerge(t1[k] or {}, t2[k] or {}) else t1[k] = v end else t1[k] = v end end return t1 end  local function loadI18n() local exist, res = pcall(require, wiki.module_title .. "/i18n") if exist and next(res) ~= nil then tableMerge(i18n, res.i18n) cases = res.cases end end  loadI18n()  -- 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 var == '') end  -- Set local case to a label local function case(localcase, label, ...) if not isSet(label) then return label end  if localcase == "smallcaps" then return '' .. label .. '' elseif cases[localcase] then return cases[localcase](label, ...) end  return label end  -- Table of language codes: requested or default and its fallbacks local function findLang(langcode) if mw.language.isKnownLanguageTag(langcode or '') == false then local cframe = mw.getCurrentFrame() local pframe = cframe:getParent() langcode = pframe and pframe.args.lang if mw.language.isKnownLanguageTag(langcode or '') == false then if not mw.title.getCurrentTitle().isContentPage then langcode = cframe:preprocess('{{int:lang}}') end if mw.language.isKnownLanguageTag(langcode or '') == false then langcode = wiki.langcode end end end local languages = mw.language.getFallbacksFor(langcode) table.insert(languages, 1, langcode) return languages end  -- mw.wikibase.getLabelWithLang or getLabelByLang with a table of languages local function getLabelByLangs(id, languages) local label local lang = languages[1] if lang == wiki.langcode then -- using getLabelWithLang when possible instead of getLabelByLang label, lang = mw.wikibase.getLabelWithLang(id) else lang = nil for _, l in ipairs(languages) do label = mw.wikibase.getLabelByLang(id, l) if label then lang = l break end end end  return label, lang end  -- Is gender femenine? true or false local function feminineGender(id) local claims = mw.wikibase.getBestStatements(id or mw.wikibase.getEntityIdForCurrentPage(),'P21') if #claims == 0 then return false elseif claims[1].mainsnak.datavalue == nil then -- novalue or somevalue return false else local genderId = claims[1].mainsnak.datavalue.value.id if genderId == "Q6581072" or genderId == "Q1052281" or genderId == "Q43445" then -- female, transgender female, female organism return true end end return false end  -- Fetch female form of label local function feminineForm(id, lang) local feminine_claims = mw.wikibase.getBestStatements(id, 'P2521') -- female form of label for _, feminine_claim in ipairs(feminine_claims) do if feminine_claim.mainsnak.datavalue.value.language == lang then return feminine_claim.mainsnak.datavalue.value.text end end end  -- Fetch unit symbol local function unitSymbol(id, lang) local claims = findClaims(id, 'P5061') local langclaims = {} if claims then for _, snak in ipairs(claims) do if snak.mainsnak and snak.mainsnak.datavalue and snak.mainsnak.datavalue.value and not langclaims[snak.mainsnak.datavalue.value.language] -- just the first one by language then langclaims[snak.mainsnak.datavalue.value.language] = snak.mainsnak.datavalue.value.text end end for _, l in ipairs(lang) do if langclaims[l] then return langclaims[l] end end end return langclaims["mul"] -- last try end  -- Add an icon for no label in requested language local function addLabelIcon(label_id, lang, uselang, icon) local ret_lang, ret_icon = '', '' if icon then if lang and lang ~= uselang then ret_lang = " (" .. lang .. ")" end if label_id and (lang == nil or lang ~= uselang) then ret_icon = " [[File:Noun Project label icon 1116097 cc mirror.svg|12px|" .. mw.message.new('Translate-taction-translate'):inLanguage(uselang):plain() .. "|link=https://www.wikidata.org/wiki/Special:EntityPage/" .. label_id .. "?uselang=" .. uselang .. "]]" end end return ret_lang .. ret_icon end  -- Escape URL escapes to avoid Lua captures local function urlEscapes(text) return mw.ustring.gsub(text, "(%%%d)", "%%%1") end  -- expandTemplate or callParserFunction local 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 Q1164668 if mw.ustring.find(formatting, '{{', 1, true) == nil then return text end if type(text) ~= "string" then text = tostring(text) end  for braces in mw.ustring.gmatch(text, "{{(.-)}}") do local parts = mw.text.split(braces, "|") local title_part = parts[1] local parameters = {} for i = 2, #parts do local subparts = mw.ustring.find(parts[i], "=") if subparts then parameters[mw.ustring.sub(parts[i], 1, subparts-1)] = mw.ustring.sub(parts[i], subparts+1, -1) else table.insert(parameters, parts[i]) end end  local braces_expanded if mw.ustring.find(title_part, ":") and mw.text.split(title_part, ":")[1] ~= mw.site.namespaces[10].name -- not a prefix Template: then braces_expanded = mw.getCurrentFrame():callParserFunction{name=title_part, args=parameters} else braces_expanded = mw.getCurrentFrame():expandTemplate{title=title_part, args=parameters} end braces = mw.ustring.gsub(braces, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1") -- escape magic characters braces_expanded = urlEscapes(braces_expanded) text = mw.ustring.gsub(text, "{{" .. braces .. "}}", braces_expanded) end  return text end  -- Resolve Wikidata redirects, pending phab:T157868 local function resolveEntityId(id) if not id or not mw.wikibase.isValidEntityId(id) then return id end -- if no label in local language nor its fallbacks, maybe it is a redirect -- not using mw.title.new(id).isRedirect as it is expensive if mw.wikibase.getLabel(id) == nil then local entity = mw.wikibase.getEntity(id) -- expensive function if not entity then return nil end if id ~= entity.id then -- Qid redirected to be fixed -- see [[Special:WhatLinksHere/Template:Track/wikidata/redirect]] require(wiki.module_title .. '/debug').track('redirect') require(wiki.module_title .. '/debug').track('redirect/' .. id) else -- no redirect and no label, fix it to avoid expensive functions require(wiki.module_title .. '/debug').track('label') require(wiki.module_title .. '/debug').track('label/' .. id) end return entity.id end return id end  -- format data type math local function printDatatypeMath(data) return mw.getCurrentFrame():callParserFunction('#tag:math', data) end  -- format data type musical-notation local function printDatatypeMusical(data, formatting) local attr = {} if formatting == 'sound' then attr.sound = 1 end return mw.getCurrentFrame():extensionTag('score', data, attr) end  -- format data value string local function printDatavalueString(data, parameters) if parameters.formatting == 'weblink' then  return '[' .. data .. ' ' .. mw.text.split(data, '//' )[2] .. ']' elseif mw.ustring.find((parameters.formatting or ''), '$1', 1, true) then -- formatting = a pattern return expandBraces(mw.ustring.gsub(parameters.formatting, '$1', {['$1']=data}), parameters.formatting) elseif parameters.case then return case(parameters.case, data, parameters.lang[1]) else return data end end  -- format data type url local function printDatatypeUrl(data, parameters) return printDatavalueString(urlEscapes(data), parameters) end  -- format data value globecoordinate local function printDatavalueCoordinate(data, parameter) 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'} if parameter and string.find(parameter, '$lat', 1, true) and string.find(parameter, '$lon', 1, true) then local ret = mw.ustring.gsub(parameter, '$l[ao][tn]', {['$lat'] = data.latitude, ['$lon'] = data.longitude}) if string.find(parameter, '$globe', 1, true) then local myglobe = 'earth' if isSet(data.globe) then local globenum = mw.text.split(data.globe, 'entity/')[2] -- http://www.wikidata.org/wiki/Q2 myglobe = globes[globenum] or 'earth' end ret = mw.ustring.gsub(ret, '$globe', myglobe) end return expandBraces(ret, parameter) elseif parameter == 'latitude' then return data.latitude elseif parameter == 'longitude' then return data.longitude elseif parameter == 'dimension' then return data.dimension else --default formatting='globe' if data.globe == '' or data.globe == nil or data.globe == 'http://www.wikidata.org/entity/Q2' then return 'earth' else local globenum = mw.text.split(data.globe, 'entity/')[2] return globes[globenum] or globenum end end end  local function roundPrecision(in_num, out_num) -- rounds out_num with significant figures of in_num (default precision) -- first, count digits after decimal mark, handling cases like '12.345e6' local exponent, prec local integer, dot, decimals, expstr = in_num:match('^(%d*)(%.?)(%d*)(.*)') local e = expstr:sub(1, 1) if e == 'e' or e == 'E' then exponent = tonumber(expstr:sub(2)) end if dot == '' then prec = -integer:match('0*$'):len() else prec = #decimals end if exponent then -- So '1230' and '1.23e3' both give prec = -1, and '0.00123' and '1.23e-3' give 5. prec = prec - exponent end -- significant figures local in_bracket = 10^-prec -- -1 -> 10, 5 -> 0.00001 local out_bracket = in_bracket * out_num / in_num out_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_bracket end  -- format data value quantity local function printDatavalueQuantity(data, parameters) local amount = data.amount amount = mw.ustring.gsub(amount, "%+", "") local sortkey = string.format("%09d", amount) local suffix = "" if string.sub(parameters.formatting or '', 1, 4) == "unit" or parameters.convert then -- example "unit": "http://www.wikidata.org/entity/Q174728" local unit_id = data.unit unit_id = mw.ustring.sub(unit_id, mw.ustring.find(unit_id, "Q"), -1) if string.sub(unit_id, 1, 1) == "Q" then local convert_to = parameters.convert if convert_to and convert_to ~= unit_id then -- convert units local 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] then local amount_f = mw.getCurrentFrame():callParserFunction('#expr', mw.ustring.gsub(conv_temp[unit_id][convert_to], "$1", amount)) amount = math.floor(tonumber(amount_f) + 0.5) unit_id = convert_to else local conversions = mw.wikibase.getAllStatements(unit_id, 'P2442') -- conversion to standard unit table.insert(conversions, mw.wikibase.getBestStatements(unit_id, 'P2370')[1]) -- conversion to SI unit for _, conv in ipairs(conversions) do if conv.mainsnak.snaktype == 'value' then -- no somevalue nor novalue if conv.mainsnak.datavalue.value.unit == "http://www.wikidata.org/entity/" .. convert_to then amount = roundPrecision(amount, amount * tonumber(conv.mainsnak.datavalue.value.amount)) unit_id = convert_to break end end end end end if parameters.formatting == "unitcode" then -- get unit symbol local unit_symbol = '' if parameters.lang[1] == wiki.langcode and pcall(require, wiki.module_title .. "/Units") then unit_symbol = require(wiki.module_title .. "/Units").getUnit(amount, '', unit_id, true, '') end if unit_symbol == '' then unit_symbol = unitSymbol(unit_id, parameters.lang) end if unit_symbol then suffix = " " .. unit_symbol end end if suffix == '' then -- get unit name local unit_label, lang = getLabelByLangs(unit_id, parameters.lang) if lang == wiki.langcode and pcall(require, wiki.module_title .. "/Units") then suffix = " " .. require(wiki.module_title .. "/Units").getUnit(amount, unit_label, unit_id, false, '') else suffix = " " .. (unit_label or unit_id) .. addLabelIcon(unit_id, lang, parameters.lang[1], parameters.editicon) end end end end amount = mw.language.new(parameters.lang[1]):formatNum(tonumber(amount)) return amount .. suffix, sortkey end  -- format data value time local function printDatavalueTime(data, parameters) -- Dates and times are stored in ISO 8601 format local timestamp = data.time local post_format local calendar_add = ""  if string.sub(timestamp, 1, 1) == '-' then post_format = i18n.datetime["bc"] elseif string.sub(timestamp, 2, 3) == '00' then post_format = i18n.datetime["ad"] else -- calendar model local 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") then calendar_add = " (" .. mw.message.new('Wikibase-time-calendar-' .. calendar_model[calendar_id]):inLanguage(parameters.lang[1]):plain() .. ")" end end  local function d(f, t) local ts = t or timestamp local form = type(f) == "function" and f(ts) or f -- function in i18n.datetime[precision] if string.sub(ts, 1, 1) == '-' then ts = '+' .. string.sub(ts, 2) end -- formatDate() only supports years from 0 return mw.language.new(parameters.lang[1]):formatDate(form, ts) end  local function postFormat(t) if post_format and mw.ustring.find(post_format, "$1") then return mw.ustring.gsub(post_format, "$1", t) end return t end  local precision = data.precision or 11 local intyear = tonumber(string.match(timestamp, "[+-](%d+)")) local ret = ""  if precision <= 5 then -- precision is 10000 years or more local factor = 10 ^ ((5 - precision) + 4) local y2 = math.ceil(math.abs(intyear) / factor) local relative = mw.ustring.gsub(i18n.datetime[precision], "$1", tostring(y2)) if post_format == i18n.datetime["bc"] then ret = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative) else ret = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative) end local ret_number = string.match(ret, "%d+") if ret_number ~= nil then ret = mw.ustring.gsub(ret, ret_number, mw.language.new(parameters.lang[1]):formatNum(tonumber(ret_number))) end elseif precision == 6 then -- millennia local card = math.floor((intyear - 1) / 1000) + 1 if mw.ustring.find(i18n.datetime[6], "$1") then ret = mw.ustring.gsub(i18n.datetime[6], "$1", tostring(card)) else ret = d(i18n.datetime[6], string.format("%04d", tostring(card))) end ret = postFormat(ret) elseif precision == 7 then -- centuries local card = math.floor((math.abs(intyear) - 1) / 100) + 1 if mw.ustring.find(i18n.datetime[7], "$1") then ret = mw.ustring.gsub(i18n.datetime[7], "$1", tostring(card)) else ret = d(i18n.datetime[7], string.format("%04d", tostring(card))) end ret = postFormat(ret) .. calendar_add elseif precision == 8 then -- decades local card = math.floor(math.abs(intyear) / 10) * 10 ret = postFormat(mw.ustring.gsub(i18n.datetime[8], "$1", tostring(card))) .. calendar_add elseif precision == 9 or parameters.formatting == 'Y' then -- precision is year ret = postFormat(tostring(intyear)) .. calendar_add elseif precision == 10 then -- month timestamp = timestamp .. " + 1 day" -- formatDate yyyy-mm-00 returns the previous month ret = d(i18n.datetime[10]) ret = postFormat(ret) .. calendar_add ret, _ = string.gsub(ret, "([ %[])0+", "%1") -- supress leading zeros in year, optionally linked else -- precision 11, day ret = d(parameters.formatting or i18n.datetime[11]) ret = postFormat(ret) .. calendar_add ret, _ = string.gsub(ret, "([ %[])0+", "%1") end return ret, timestamp end  -- format data value entity local function printDatavalueEntity(data, parameters) local entity_id = data['id'] local entity_page = 'Special:EntityPage/' .. entity_id if parameters.formatting == 'raw' then if data['entity-type'] == 'item' then entity_id = resolveEntityId(entity_id) end return entity_id, entity_id end local label, lang = getLabelByLangs(entity_id, parameters.lang) local sitelink = mw.wikibase.getSitelink(entity_id) local parameter = parameters.formatting local labelcase = label or sitelink if parameters.gender == 'feminineform' then labelcase = feminineForm(entity_id, lang) or labelcase end if parameters.case ~= 'gender' then labelcase = case(parameters.case, labelcase, lang, entity_id, parameters.id) end local ret1, ret2 if parameter == 'label' then ret1 = labelcase or entity_id ret2 = labelcase or entity_id elseif parameter == 'sitelink' then ret1 = (sitelink or 'wikidata:' .. entity_page) ret2 = sitelink or entity_id elseif mw.ustring.find((parameter or ''), '$1', 1, true) then -- formatting = a pattern ret1 = mw.ustring.gsub(parameter, '$1', labelcase or entity_id) ret1 = expandBraces(ret1, parameter) ret2 = labelcase or entity_id else if parameter == "ucfirst" or parameter == "ucinternallink" then if labelcase and lang then labelcase = mw.language.new(lang):ucfirst(labelcase) end -- only first of a list, reset formatting for next ones if parameter == "ucinterlanllink" then parameters.formatting = 'internallink' else parameters.formatting = nil -- default format end end  if sitelink then ret1 = '[[' .. sitelink .. '|' .. labelcase .. ']]' ret2 = labelcase elseif label and (parameter == 'internallink' or parameter == 'ucinternallink') then ret1 = '[[' .. label .. '|' .. labelcase .. ']]' ret2 = labelcase else ret1 = '[[wikidata:' .. entity_page .. '|' .. (labelcase or entity_id) .. ']]' ret2 = labelcase or entity_id end end  return ret1 .. addLabelIcon(entity_id, lang, parameters.lang[1], parameters.editicon), ret2 end  -- format data value monolingualtext local function printDatavalueMonolingualText(data, parameters) -- data fields: language [string], text [string]  if parameters.list == "lang" and data["language"] ~= parameters.lang[1] then return elseif parameters.formatting == "language" or parameters.formatting == "text" then return data[parameters.formatting] end local result = data["text"] if data["language"] ~= wiki.langcode then result = mw.ustring.gsub('$2', '$[12]', {["$1"]=data["language"], ["$2"]=data["text"]}) end if mw.ustring.find((parameters.formatting or ''), '$', 1, true) then -- output format defined with $text, $language result = mw.ustring.gsub(parameters.formatting, '$text', result) result = mw.ustring.gsub(result, '$language', data["language"]) end return result end  local function printError(key) return ' .. i18n.errors[key] .. '' end  -- the "qualifiers" and "snaks" field have a respective "qualifiers-order" and "snaks-order" field -- use these as the second parameter and this function instead of the built-in "pairs" function -- to iterate over all qualifiers and snaks in the intended order. local function orderedpairs(array, order) if not order then return pairs(array) end  -- return iterator function local i = 0 return function() i = i + 1 if order[i] then return order[i], array[order[i]] end end end  function findClaims(entityId, property) if not property or not entityId then return end  if not mw.ustring.match(property, "^P%d+$") then -- get property id for the given label property = mw.wikibase.resolvePropertyId(property) if not property then return end end local claims = mw.wikibase.getAllStatements(entityId, property) if #claims == 0 then claims = nil end return claims end  local function getSnakValue(snak, parameters) if snak.snaktype == 'value' then -- call the respective snak parser if snak.datatype == 'math' then return printDatatypeMath(snak.datavalue.value) elseif snak.datatype == 'musical-notation' then return printDatatypeMusical(snak.datavalue.value, parameters.formatting) elseif snak.datatype == "url" then return printDatatypeUrl(snak.datavalue.value, parameters) elseif snak.datavalue.type == "string" then return printDatavalueString(snak.datavalue.value, parameters) elseif snak.datavalue.type == "globecoordinate" then return printDatavalueCoordinate(snak.datavalue.value, parameters.formatting) elseif snak.datavalue.type == "quantity" then return printDatavalueQuantity(snak.datavalue.value, parameters) elseif snak.datavalue.type == "time" then return printDatavalueTime(snak.datavalue.value, parameters) elseif snak.datavalue.type == 'wikibase-entityid' then return printDatavalueEntity(snak.datavalue.value, parameters) elseif snak.datavalue.type == 'monolingualtext' then return printDatavalueMonolingualText(snak.datavalue.value, parameters) end elseif snak.snaktype == 'novalue' then if parameters.formatting == 'raw' then return end return mw.message.new('Wikibase-snakview-snaktypeselector-novalue'):inLanguage(parameters.lang[1]):plain() elseif snak.snaktype == 'somevalue' then if parameters.formatting == 'raw' then return end return mw.message.new('Wikibase-snakview-snaktypeselector-somevalue'):inLanguage(parameters.lang[1]):plain() end return mw.wikibase.renderSnak(snak) end  local 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 snaks if qualifierId then -- search the attribute snak with the given qualifier as key if claim.qualifiers then local qualifier = claim.qualifiers[qualifierId] if qualifier then if qualifier[1].datatype == "monolingualtext" then -- iterate over monolingualtext qualifiers to get local language for idx in pairs(qualifier) do if qualifier[idx].datavalue.value and qualifier[idx].datavalue.value.language == parameters.lang[1] then return qualifier[idx] end end elseif parameters.list then return qualifier else return qualifier[1] end end end return nil, printError("qualifier-not-found") else -- otherwise return the main snak return claim.mainsnak end end  function getValueOfClaim(claim, qualifierId, parameters) local error local snak snak, error = getQualifierSnak(claim, qualifierId, parameters) if not snak then return nil, nil, error elseif snak[1] then -- a multi qualifier local result = {} local sortkey = {} for idx in pairs(snak) do result[#result + 1], sortkey[#sortkey + 1] = getSnakValue(snak[idx], parameters) end return mw.text.listToText(result, parameters.qseparator, parameters.qconjunction), sortkey[1] else -- a property or a qualifier return getSnakValue(snak, parameters) end end  local function getValueOfParentClaim(claim, qualifierId, parameters) local qids = mw.text.split(qualifierId, '/', true) local valueraw, parent_claims, value, sortkey if qids[1] == parameters.property then valueraw, _, _ = getValueOfClaim(claim, nil, {["formatting"]="raw", ["lang"]=parameters.lang}) else valueraw, _, _ = getValueOfClaim(claim, qids[1], {["formatting"]="raw", ["lang"]=parameters.lang}) end if string.sub(valueraw or '', 1, 1) == "Q" then -- protection for 'no value' parent_claims = mw.wikibase.getBestStatements(valueraw, qids[2]) if parent_claims[1] ~= nil then value, sortkey, _ = getValueOfClaim(parent_claims[1], nil, parameters) -- raw parent value needed for while/black lists, lang for avoiding an error on types other than entity valueraw, _, _ = getValueOfClaim(parent_claims[1], nil, {["formatting"]="raw", ["lang"]=parameters.lang}) end end return value, sortkey, valueraw end  local function getReferences(claim) local refaliases = { citeWeb= "Q5637226", author= "P50", publisher= "P123", importedFrom= "P143", statedIn= "P248", pages= "P304", publicationDate= "P577", startTime= "P580", endTime= "P582", chapter= "P792", retrieved= "P813", referenceURL= "P854", archiveURL= "P1065", title= "P1476", quote= "P1683", shortName= "P1813", language= "P2439", archiveDate= "P2960" } local result = "" -- traverse through all references for ref in pairs(claim.references or {}) do local refparts local refs = {} -- traverse through all parts of the current reference for snakkey, snakval in pairs(claim.references[ref].snaks or {}) do if snakkey ~= refaliases.importedFrom then -- "imported from" is not a proper reference for snakidx = 1, #snakval do if snakidx > 1 then refparts = refparts .. ", " end refparts = refparts or '' .. getSnakValue(snakval[snakidx], {lang={wiki.langcode}}) end refs[snakkey] = refparts refparts = nil end end  -- get title of general template for citing web references local template = mw.wikibase.getSitelink(refaliases.citeWeb) or "" template = mw.text.split(template, ":")[2] -- split off namespace from front  -- (1) if both "reference URL" and "title" are present, then use the general template for citing web references if refs[refaliases.referenceURL] and (refs[refaliases.title] or refs[refaliases.statedIn]) and template then local citeParams = {} citeParams[i18n['cite']['url']] = refs[refaliases.referenceURL] citeParams[i18n['cite']['title']] = refs[refaliases.title] or refs[refaliases.statedIn]:match("^%[%[.-|(.-)%]%]") citeParams[i18n['cite']['website']] = refs[refaliases.statedIn] citeParams[i18n['cite']['language']] = refs[refaliases.language] citeParams[i18n['cite']['date']] = refs[refaliases.publicationDate] citeParams[i18n['cite']['access-date']] = refs[refaliases.retrieved] citeParams[i18n['cite']['archive-url']] = refs[refaliases.archiveURL] citeParams[i18n['cite']['archive-date']] = refs[refaliases.archiveDate] citeParams[i18n['cite']['publisher']] = refs[refaliases.publisher] citeParams[i18n['cite']['quote']] = refs[refaliases.quote] citeParams[i18n['cite']['pages']] = refs[refaliases.pages] citeParams[i18n['cite']['author']] = refs[refaliases.author] refparts = mw.getCurrentFrame():expandTemplate{title=template, args=citeParams} else -- raw ouput for k, v in orderedpairs(refs or {}, claim.references[ref]["snaks-order"]) do if k and v then if refparts then refparts = refparts .. ", " else refparts = "" end refparts = refparts .. tostring(mw.wikibase.getLabel(k)) .. ": " refparts = refparts .. v end end end if refparts then result = result .. mw.getCurrentFrame():extensionTag("ref", refparts) end end return result end  -- Set whitelist or blacklist values local function setWhiteOrBlackList(type_list, num_qual, args) local listed = false local list = {} for i = 0, num_qual do if isSet(args[type_list .. i]) then listed = true list[tostring(i)] = {} local values = mw.text.split(args[type_list .. i], "/", true) for _, v in ipairs(values) do list[tostring(i)][v] = true list[tostring(i)][resolveEntityId(v)] = true end end end return list, listed end  local 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 end column_params.convert = args["convert" .. column] if args["case" .. column] then column_params.case = args["case" .. column] end return column_params end  -- 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 require --If a value is already set, use it if isSet(args.value) then if args.value == 'NONE' then return else return args.value end end  -- arguments local pargs = frame.args and frame:getParent().args local id = args.item or (pargs and pargs.item) if not isSet(id) then id = mw.wikibase.getEntityIdForCurrentPage() if id == nil then return end end local property = string.upper(args.property or "") local qualifierId = {} qualifierId[1] = isSet(args.qualifier) and string.upper(args.qualifier) or nil local i = 2 while isSet(args["qualifier" .. i]) do qualifierId[i] = string.upper(args["qualifier" .. i]) i = i + 1 end local formatting = args.formatting; if formatting == "" then formatting = nil end local convert = args.convert; if convert == "" then convert = nil end if convert and string.sub(convert, 1, 1) ~= "Q" then convert = nil end local case = args.case local list = args.list or true; if (list == "false" or list == "no") then list = false end local sorting_col = args.tablesort local sorting_up = (args.sorting or "") ~= "-1" local separator = args.separator local conjunction = args.conjunction or args.separator local rowformat = args.rowformat local references = args.references local showerrors = args.showerrors local default = args.default if default then showerrors = nil end local editicon = not (args.editicon == "false" or args.editicon == "no")  local parameters = {["id"] = id, ["property"] = property, ["formatting"] = formatting, ["convert"] = convert, ["list"] = list, ["case"] = case, ["editicon"] = editicon, ["separator"] = separator, ["conjunction"] = conjunction, ["qseparator"] = separator, ["qconjunction"] = conjunction}  -- defaults for table local preformat, postformat = "", "" local whitelisted, blacklisted = false, false local whitelist, blacklist = {}, {} if parameters.formatting == "table" then parameters.separator = parameters.separator or "
"
parameters.conjunction = parameters.conjunction or "
"
parameters.qseparator = ", " parameters.qconjunction = ", " if not rowformat then rowformat = "$0 ($1" i = 2 while qualifierId[i] do rowformat = rowformat .. ", $" .. i i = i + 1 end rowformat = rowformat .. ")" elseif mw.ustring.find(rowformat, "^[*#]") then parameters.separator = "
  • " parameters.conjunction = "
  • " if mw.ustring.match(rowformat, "^[*#]") == "*" then preformat = "
    • " postformat = "
    "
    else preformat = "
    1. " postformat = "
    "
    end rowformat = mw.ustring.gsub(rowformat, "^[*#] ?", "") end -- set whitelist and blacklist values whitelist, whitelisted = setWhiteOrBlackList("whitelist", #qualifierId, args) blacklist, blacklisted = setWhiteOrBlackList("blacklist", #qualifierId, args) end -- fetch property local claims for p in string.gmatch(property, 'P%d+') do claims = findClaims(id, p) if claims and claims[1] then break end end if not claims or not claims[1] then if showerrors then return printError("property-not-found") else return default end end -- find language and defaults parameters.lang = findLang(args.lang) -- set feminine case if gender is requested local itemgender = args["itemgender"] local idgender if itemgender then if string.match(itemgender, "^P%d+$") then local snak = mw.wikibase.getBestStatements(id, itemgender)[1] if snak and snak.mainsnak and snak.mainsnak.datavalue and snak.mainsnak.datavalue.value then idgender = snak.mainsnak.datavalue.value.id end elseif string.match(itemgender, "^Q%d+$") then idgender = itemgender end end local gender_requested = false if parameters.case == "gender" or idgender then gender_requested = true elseif parameters.formatting == "table" then for i=0, #qualifierId do if args["case" .. i] and args["case" .. i] == "gender" then gender_requested = true break end end end if gender_requested then if feminineGender(idgender or id) then parameters.gender = "feminineform" end end -- get initial sort indices local sortindices = {} for idx in pairs(claims) do sortindices[#sortindices + 1] = idx end -- sort by claim rank local 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 < rankb end table.sort(sortindices, comparator) local result local error if parameters.list or parameters.formatting == "table" then -- convert LF to line feed,
    may not work on some cases
    parameters.separator = parameters.separator == "LF" and "\010" or parameters.separator parameters.conjunction = parameters.conjunction == "LF" and "\010" or parameters.conjunction -- i18n separators parameters.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, valueq local sortkey, sortkeyq local values = {} local sortkeys = {} local refs = {} local firstrank = parameters.list == "firstrank" and claims[sortindices[1]].rank or '' local rowlist = {} -- rows to list with whitelist or blacklist for idx in pairs(claims) do local claim = claims[sortindices[idx]] local reference = {} if not whitelisted then rowlist[idx] = true end if firstrank ~= '' and firstrank ~= claim.rank then break end if parameters.formatting == "table" then local params = tableParameters(args, parameters, "0") value, sortkey, error = getValueOfClaim(claim, nil, params) if value then values[#values + 1] = {} sortkeys[#sortkeys + 1] = {} refs[#refs + 1] = {} if whitelist["0"] or blacklist["0"] then local valueraw, _, _ = getValueOfClaim(claim, nil, {["formatting"]="raw", ["lang"]=params.lang}) if whitelist["0"] and whitelist["0"][valueraw or ""] then rowlist[#values] = true elseif blacklist["0"] and blacklist["0"][valueraw or ""] then rowlist[#values] = false end end for i, qual in ipairs(qualifierId) do local j = tostring(i) params = tableParameters(args, parameters, j) local valueq, sortkeyq, valueraw if qual == property then -- hack for getting the property with another formatting, i.e. colformat1=raw valueq, sortkeyq, _ = getValueOfClaim(claim, nil, params) else for q in mw.text.gsplit(qual, '%s*OR%s*') do if string.find(q, ".+/.+") then valueq, sortkeyq, valueraw = getValueOfParentClaim(claim, q, params) elseif string.find(q, "^/.+") then local claim2 = findClaims(id, string.sub(q, 2)) if claim2 then valueq, sortkeyq, _ = getValueOfClaim(claim2[1], nil, params) end else valueq, sortkeyq, _ = getValueOfClaim(claim, q, params) end if valueq then break end end end values[#values]["col" .. j] = valueq sortkeys[#sortkeys]["col" .. j] = sortkeyq or valueq if whitelist[j] or blacklist[j] then valueq = valueraw or getValueOfClaim(claim, qual, {["formatting"]="raw", ["lang"]=params.lang}) if whitelist[j] and whitelist[j][valueq or ""] then rowlist[#values] = true elseif blacklist[j] and blacklist[j][valueq or ""] then rowlist[#values] = false end end end end else value, sortkey, error = getValueOfClaim(claim, qualifierId[1], parameters) values[#values + 1] = {} sortkeys[#sortkeys + 1] = {} refs[#refs + 1] = {} end if not value and showerrors then value = error end if value then if references and claim.references then reference = claim.references end refs[#refs]["col0"] = reference values[#values]["col0"] = value sortkeys[#sortkeys]["col0"] = sortkey or value end end -- sort and format results sortindices = {} for idx in pairs(values) do sortindices[#sortindices + 1] = idx end if sorting_col then local sorting_table = mw.text.split(sorting_col, '/', true) local comparator = function(a, b) local valuea, valueb local i = 1 while valuea == valueb and i <= #sorting_table do valuea = sortkeys[a]["col" .. sorting_table[i]] or '' valueb = sortkeys[b]["col" .. sorting_table[i]] or '' i = i + 1 end if sorting_up then return valueb > valuea end return valueb < valuea end table.sort(sortindices, comparator) end result = {} for idx in pairs(values) do local valuerow = values[sortindices[idx]] local reference = getReferences({["references"] = refs[sortindices[idx]]["col0"]}) value = valuerow["col0"] if parameters.formatting == "table" then if not rowlist[sortindices[idx]] then value = nil else value = mw.ustring.gsub(rowformat .. "$", "$0", value) -- fake end character added for easy gsub value = mw.ustring.gsub(value, "$R0", reference) -- add reference local rowformatting = rowformat .. "$" for i, _ in ipairs(qualifierId) do local valueq = valuerow["col" .. i] if args["rowsubformat" .. i] and valueq then -- add fake end character $ -- gsub $i not followed by a number so $1 doesn't match $10, $11... -- remove fake end character 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") end valueq = valueq and urlEscapes(valueq) or '' value = mw.ustring.gsub(value, "$" .. i .. "(%D)", valueq .. "%1") end value = string.sub(value, 1, -2) -- remove fake end character value = expandBraces(value, rowformatting) end elseif value then value = expandBraces(value, parameters.formatting) value = value .. reference if isSet(value) then result[#result + 1] = value end end if not parameters.list then break end end result = preformat .. mw.text.listToText(result, parameters.separator, parameters.conjunction) .. postformat else -- return first element local claim = claims[sortindices[1]] result, _, error = getValueOfClaim(claim, qualifierId[1], parameters) if result and references then result = result .. getReferences(claim) end end if isSet(result) then return result else if showerrors then return error else return default end end end -- This is used to get the TA98 (Terminologia Anatomica first edition 1998) values like 'A01.1.00.005' (property P1323) -- which are then linked to http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/01.1.00.005%20Entity%20TA98%20EN.htm -- uses the newer mw.wikibase calls instead of directly using the snaks -- formatPropertyValues returns a table with the P1323 values concatenated with ", " so we have to split them out into a table in order to construct the return string p.getTAValue = function(frame) local ent = mw.wikibase.getEntity() local props = ent:formatPropertyValues('P1323') local out = {} local t = {} for k, v in pairs(props) do if k == 'value' then t = mw.text.split( v, ", ") for k2, v2 in pairs(t) do out[#out + 1] = "[http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/" .. string.sub(v2, 2) .. "%20Entity%20TA98%20EN.htm " .. v2 .. "]" end end end local ret = table.concat(out, "
    "
    ) if #ret == 0 then ret = "Invalid TA" end return ret end -- Local functions for getParentValues ----------------------- local function uc_first(word) return mw.ustring.upper(mw.ustring.sub(word, 1, 1)) .. mw.ustring.sub(word, 2) end local function getPropertyValue(id, property, parameter, langs, editicon, case) local snaks = mw.wikibase.getBestStatements(id, property) local mysnak if snaks and snaks[1] and snaks[1].mainsnak then mysnak = snaks[1].mainsnak else return end local entity_id local result = '-' -- default for 'no value' if mysnak.datavalue then entity_id = "Q" .. tostring(mysnak.datavalue.value['numeric-id']) result, _ = getSnakValue(mysnak, {formatting=parameter, lang=langs, editicon=editicon, case=case}) end return entity_id, result end local function contains(tab, val) for index, value in ipairs(tab) do if value == val then return true end end return false end local function getParentObjects(id, formatting, languages, propertySupString, propertyLabel, propertyLink, labelShow, editicon, upto, upto_linkId, last_only, grammatical_case, include_self) if (upto_linkId == nil) then upto_linkId = "" end local upto_link_ids = mw.text.split(upto_linkId, '[/%s]+') local propertySups = mw.text.split(propertySupString, '[/%s]+') local lastlabel = uc_first(upto or '') local maxloop = tonumber(upto) or (lastlabel == '' and 10 or 50) local labelFilter = {} if labelShow then for i, v in ipairs(mw.text.split(labelShow, "/")) do labelFilter[uc_first(v)] = true end end local label_self _, label_self = getPropertyValue(id, propertyLabel, "label", languages) local result = {} local label, link, linktext for iter = 1, maxloop do local label, link for _, propertySup in pairs(propertySups) do _id, _link = getPropertyValue(id, propertySup, formatting, languages, editicon, grammatical_case) if _id and _link then id = _id link = _link break end end if not id or not link then break end if propertyLink then _, linktext = getPropertyValue(id, propertyLink, "label", languages) if linktext then link = mw.ustring.gsub(link, "%[%[(.*)%|.+%]%]", "[[%1|" .. linktext .. "]]") end end --_, label = getPropertyValue(id, propertyLabel, "label", languages, editicon, "infoboxlabel") _, label = getPropertyValue(id, propertyLabel, "label", languages, false, "infoboxlabel") -- check Template:Automatic taxobox if labelShow == nil or labelFilter[label] then result[#result + 1] = {label, link} if label then labelFilter[label] = nil -- only first label found end end if not tonumber(upto) and label == lastlabel then break end if contains(upto_link_ids, id) then break end end if last_only then result = {result[#result]} end if include_self then table.insert(result, 1, {label_self, mw.title.getCurrentTitle().text}) end return result end local function parentObjectsToString(result, rowformat, separator, cascade, sorting) local ret = {} local first = 1 local last = #result local iter = 1 if sorting == "-1" then first = #result; last = 1; iter = -1 end for i = first, last, iter do local rowtext = mw.ustring.gsub(rowformat, "$[01]", {["$0"] = result[i][1], ["$1"] = result[i][2]}) ret[#ret +1] = expandBraces(rowtext, rowformat) end if cascade then local prefix = "" for i = 1, #ret do ret[i] = prefix .. "• " .. ret[i] prefix = prefix .. " " end end return mw.text.listToText(ret, separator, separator) end -- Returns pairs of instance label and property value fetching a recursive tree function p.getParentValues(frame) local args = frame.args or frame -- via invoke or require local pargs = frame.args and frame:getParent().args local id = args.item or (pargs and pargs.item) if not isSet(id) then id = mw.wikibase.getEntityIdForCurrentPage() if id == nil then return end end local languages = findLang(args.lang) local propertySup = args["property"]; if not isSet(propertySup) then propertySup = "P131" end --administrative entity local propertyLabel = args["label"]; if not isSet(propertyLabel) then propertyLabel = "P31" end --instance local propertyLink = args["valuetext"]; if propertyLink == "" then propertyLink = nil end --internallink local upto = args["upto"]; if upto == "" then upto = nil end local last_only = (args.last_only == "true" or args.last_only == "yes") local labelShow = args["labelshow"]; if labelShow == "" then labelShow = nil end local editicon = not (args.editicon == "false" or args.editicon == "no") local include_self = (args.include_self == "true" or args.include_self == "yes") local case = args["case"]; if case == "" then case = nil end if isSet(args.uptolabelid) then upto = mw.wikibase.getLabel(args.uptolabelid) end if isSet(args.showlabelid) then local showLabelList = {} for substring in mw.text.gsplit(args.showlabelid, '[/%s]+') do table.insert(showLabelList, mw.wikibase.getLabel(substring)) end if #showLabelList > 0 then labelShow = table.concat(showLabelList,"/") end end local result = getParentObjects(id, args.formatting, languages, propertySup, propertyLabel, propertyLink, labelShow, editicon, upto, args.uptolinkid, last_only, case, include_self) local rowformat = args["rowformat"]; if not isSet(rowformat) then rowformat = "$0 = $1" end local separator = args["separator"]; if not isSet(separator) then separator = "
    "
    end local sorting = args["sorting"]; if sorting == "" then sorting = nil end local cascade = (args.cascade == "true" or args.cascade == "yes") return parentObjectsToString(result, rowformat, separator, cascade, sorting) end -- Link with a parent label -------------------- function p.linkWithParentLabel(frame) local args = {} if frame.args then for k, v in pairs(frame.args) do -- metatable args[k] = v end else args = frame -- via require end if isSet(args.value) then return args.value end -- get internal link of property/qualifier local largs = mw.clone(args) largs.list = "true" largs.formatting = "internallink" largs.separator = "/·/" largs.editicon = "false" local link_list = p.claim(largs) if not isSet(link_list) then return end local link_table = mw.text.split(link_list, "/·/", true) -- get id value of property/qualifier largs.formatting = "raw" local items_list = p.claim(largs) local items_table = mw.text.split(items_list, "/·/", true) -- get label of parent property local parent_claims = findClaims(items_table[1], args.parent) if parent_claims and parent_claims[1].mainsnak.datatype == 'monolingualtext' then largs.formatting = nil largs.list = 'lang' else largs.formatting = "label" largs.list = "false" end largs.property = args.parent largs.qualifier = nil for i, v in ipairs(items_table) do largs.item = v local link_label = p.claim(largs) if isSet(link_label) then link_table[i] = mw.ustring.gsub(link_table[i] or '', "%[%[(.*)%|.+%]%]", "[[%1|" .. link_label .. "]]") end end args.editicon = not (args.editicon == "false" or args.editicon == "no") args.id = args.item or mw.wikibase.getEntityIdForCurrentPage() args.lang = findLang(args.lang) return mw.text.listToText(link_table) end -- Calculate number of years old ---------------------------- function p.yearsOld(frame) local args = frame.args or frame -- via invoke or require local id = args.item if not isSet(id) then id = mw.wikibase.getEntityIdForCurrentPage() end local lang = mw.language.new('en') local function getBestValue(id, prop) local snak = mw.wikibase.getBestStatements(id, prop)[1] if snak and snak.mainsnak and snak.mainsnak.datavalue and snak.mainsnak.datavalue.value then return snak.mainsnak.datavalue.value end end local birth = getBestValue(id, 'P569') if type(birth) ~= 'table' or birth.time == nil or birth.precision == nil or birth.precision < 8 then return end local death = getBestValue(id, 'P570') if type(death) ~= 'table' or death.time == nil or death.precision == nil then death = {['time'] = lang:formatDate('c'), ['precision'] = 11} -- current date elseif death.precision < 8 then return end local 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) do if d.precision == 10 then -- month d.min.day = 1 local 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 decade d.min.day = 1 d.min.month = 1 d.max.day = 31 d.max.month = 12 if d.precision == 8 then -- decade d.max.year = d.max.year + 9 end end end local function age(d1, d2) local years = d2.year - d1.year if d2.month < d1.month or (d2.month == d1.month and d2.day < d1.day) then years = years - 1 end if d2.year > 0 and d1.year < 0 then years = years - 1 -- no year 0 end return years end local old_min = age(dates[1].max, dates[2].min) local old_max = age(dates[1].min, dates[2].max) local old, old_expr if old_min == 0 and old_max == 0 then old = "< 1" old_max = 1 -- expression in singular elseif old_min == old_max then old = old_min else old = old_min .. "/" .. old_max end if args.formatting == 'unit' then local langs = findLang(args.lang) local yo, yo_sg, yo_pl, yo_pau if langs[1] == wiki.langcode then yo_sg = i18n["years-old"].singular yo_pl = i18n["years-old"].plural yo_pau = i18n["years-old"].paucal end if not isSet(yo_pl) then yo_pl = getLabelByLangs('Q24564698', langs) yo_sg = yo_pl end if not isSet(yo_pau) then yo_pau = yo_pl end yo = mw.language.new(langs[1]):plural(old_max, {yo_sg, yo_pau, yo_pl}) if mw.ustring.find(yo, '$1', 1, true) then old_expr = mw.ustring.gsub(yo, "$1", old) else old_expr = old .. ' ' .. yo end elseif args.formatting then old_expr = expandBraces(mw.ustring.gsub(args.formatting, '$1', old), args.formatting) else old_expr = old end return old_expr end -- 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 require local id = mw.text.trim(args[1] or "") if not isSet(id) then return end local editicon = not (args.editicon == "false" or args.editicon == "no") and mw.wikibase.isValidEntityId(id) local label_icon = '' local label, lang if args.label then label = args.label else local languages = findLang(args.lang) -- exceptions or labels fixed local exist, labels = pcall(require, wiki.module_title .. "/labels" .. (languages[1] == wiki.langcode and '' or '/' .. languages[1])) if exist and next(labels.infoboxLabelsFromId) ~= nil then label = labels.infoboxLabelsFromId[id] end if label == nil then local new_id = resolveEntityId(id) if new_id then label, lang = getLabelByLangs(new_id, languages) if label then if args.itemgender and feminineGender(args.itemgender) then label = feminineForm(new_id, lang) or label end label = mw.language.new(lang):ucfirst(mw.text.nowiki(label)) -- sanitize end label_icon = addLabelIcon(new_id or id, lang, languages[1], editicon) end end end local linked = args.linked if isSet(linked) and linked ~= "no" then local article = mw.wikibase.getSitelink(id) or ("d:" .. id) return "[[" .. article .. "|" .. (label or id) .. "]]" .. label_icon else return (label or id) .. label_icon end end -- Utilities ----------------------------- -- debugging functions, see module ../debug. function p.ViewSomething(frame) return require(wiki.module_title .. "/debug").ViewSomething(frame) end function p.Dump(frame) return require(wiki.module_title .. "/debug").Dump(frame) end function p.getEntityFromTree(frame) return require(wiki.module_title .. "/debug").getEntityFromTree(frame) end -- Copied from Module:Wikibase function p.getSiteLink(frame) local id = frame.args[1] if not isSet(id) then id = mw.wikibase.getEntityIdForCurrentPage() if id == nil then return end end return mw.wikibase.getSitelink(id, frame.args[2]) end -- Helper function for the default language code used function p.lang(frame) local lang = frame and frame.args[1] -- nil via require return findLang(lang)[1] end -- Number of statements function p.numStatements(frame) local args = frame.args local id = args.item if id == '' or id == nil then id = mw.wikibase.getEntityIdForCurrentPage() if id == nil then return 0 end end local prop = mw.text.trim(args[1]) local num = mw.wikibase.getBestStatements(id, prop) return #num end -- Returns the first id or value of given property or nil if not found, not isValidEntityId or novalue/somevalue -- See Module:Wikibase function p.validProperty(frame) local property = mw.text.trim(frame.args[1]) local item = frame.args.item or frame.args.from; if item == '' then item = nil end local type = frame.args.type or "id" local entity = mw.wikibase.getEntity(item) if not entity then return end if not entity.claims then return end local hasProp = entity.claims[property] if not hasProp then return end if not hasProp[1].mainsnak.datavalue then return end if type == "value" then return hasProp[1].mainsnak.datavalue.value end if not hasProp[1].mainsnak.datavalue.value.id then return end if not mw.wikibase.isValidEntityId(hasProp[1].mainsnak.datavalue.value.id) then return end return hasProp[1].mainsnak.datavalue.value.id end function p.labelOf(frame) local id = frame.args[1] -- returns the label of the given entity/property id -- if no id is given, the one from the entity associated with the calling Wikipedia article is used if not id then local entity = mw.wikibase.getEntity() if not entity then return printError("entity-not-found") end id = entity.id end return mw.wikibase.getLabel(id) end local function bestranked(claims) if not claims then return nil end local preferred, normal = {}, {} for i, j in pairs(claims) do if j.rank == 'preferred' then table.insert(preferred, j) elseif j.rank == 'normal' then table.insert(normal, j) end end if #preferred > 0 then return preferred else return normal end end function p.labelIn(frame) local langcode = frame.args[1] or wiki.langcode local id = frame.args[2] local property_id = frame.args["p"] local entity = mw.wikibase.getEntity(id) if property_id ~= nil then local claims = findClaims(entity.id, property_id) if not claims or not claims[1] then return nil end claims = bestranked(claims) local claim_id = getValueOfClaim(claims[1], nil, {["formatting"]="raw"}) entity = mw.wikibase.getEntity(claim_id) end -- return label of a Wikidata entity in the given language or the default language of this Wikipedia site return entity.labels[langcode].value end function p.internalLinkOf(frame) local id = frame.args[1] if id == nil then return nil end local entity = mw.wikibase.getEntity(id) if entity == nil then return nil end local res = printDatavalueEntity(entity, { formatting ="ucinternallink", lang = findLang()}) return res end function p.claimsCount(frame) local property = frame.args["property"] local id = frame.args["id"] -- get wikidata entity local entity = mw.wikibase.getEntity(id) if not entity then if showerrors then return printError("entity-not-found") else return default end end -- fetch the first claim of satisfying the given property local claims = findClaims(id, property) if not claims or not claims[1] then if showerrors then return printError("property-not-found") else return default end end return #claims end function p.processMarkup(frame) local f = (frame.args[1] or frame.args.item) and frame or frame:getParent() return f:preprocess(f.args[1]) end return p
  • Tags:

    🔥 Trending searches on Wiki Ìgbò:

    NairalandSenegalEniola AjaoThe Game of Love and ChanceLondonBotswanaOnye omekome nke GorPinky WebbEducationJamilah TangazaEgwu AgbachaekurunwaCoordinated Universal TimeJa'afar Mahmud AdamIkụbiga azu okeGetenesh UrgeOtu abalị LagosSol PicóOgbunabaliAsụsụ PalorEriggaIgboNNdị otu egwuregwu bọọlụ ụmụ nwanyị nke mba NaịjirịaAsụsụ WareAfrịkaIcelandRichard Wright (author)LAminu AlaList of Nigerian states by date of statehoodSwahili languageÁbuGimsIfesinachi Comedy Nwanyanwu2019 na mgbanwe ihu igwe4 DisembaPornhubWikiSão Tomé and PríncipeWikiquoteBiodiversityHausaTekno (musician)Fave (onye na-abụ abụ)JoyBanana Island, LagosAkList of minimum driving agesChineze NwagboÀlàApple Inc.FootbọlVictonyLiezel HuberYasmine SabriTobiloba AjayiPublic domainNigeriaCorbin BleuIce PrinceBrenda MsangiHillsong Music (label)TimayaStockholmXXXTentacion19 DisembaDivine NdhlukulaỌkara OgunodeKanoShallipopi🡆 More