-- vim: set noexpandtab ft=lua ts=4 sw=4:require('strict')
local p = local debug = false
-- module local variableslocal wiki =
-- internationalisationlocal i18n =
-- Credit to http://stackoverflow.com/a/1283608/2644759-- cc-by-sa 3.0local function tableMerge(t1, t2) for k,v in pairs(t2) do if type(v)
"table" then tableMerge(t1[k] or, t2[k] or) else t1[k] = v end else t1[k] = v end end return t1end
local function loadI18n local exist, res = pcall(require, "Module:Wikidata-i18n") if exist then tableMerge(i18n, res.i18n) endend
loadI18n
local function printError(code) return '
' .. (i18n.errors[code] or code) .. ''endif debug then function p.inspectI18n(frame) local val = i18n for _, key in pairs(frame.args) do key = mw.text.trim(key) val = val[key] end return val endend
local function parseDateFull(timestamp, precision, date_format, date_addon) local prefix_addon = i18n["datetime"]["prefix-addon"] local addon_sep = i18n["datetime"]["addon-sep"] local addon = ""
-- check for negative date if string.sub(timestamp, 1, 1)
0 and precision <= 9 then return "" end -- precision is 10000 years or more if precision <= 5 then 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 addon ~= "" then -- negative date relative = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative) else relative = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative) end return relative end
-- precision is decades, centuries and millennia local era if precision
7 then era = mw.ustring.gsub(i18n.datetime[7], "$1", tostring(math.floor((math.abs(intyear) - 1) / 100) + 1)) end if precision
9 then _date_format = i18n["datetime"][9] end local year_suffix local tstr = "" local lang_obj = mw.language.new(wiki.langcode) local f_parts = mw.text.split(_date_format, 'Y', true) for idx, f_part in pairs(f_parts) do year_suffix = if string.match(f_part, "x[mijkot]$") then -- for non-Gregorian year f_part = f_part .. 'Y' elseif idx < #f_parts then -- supress leading zeros in year year_suffix = lang_obj:formatDate('Y', timestamp) year_suffix = string.gsub(year_suffix, '^0+', , 1) end tstr = tstr .. lang_obj:formatDate(f_part, timestamp) .. year_suffix end local fdate if addon ~= "" and prefix_addon then fdate = addon .. addon_sep .. tstr elseif addon ~= "" then fdate = tstr .. addon_sep .. addon else fdate = tstr end return fdate else return printError("unknown-datetime-format") endend
-- 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
-- precision: 0 - billion years, 1 - hundred million years, ..., 6 - millennia, 7 - century, 8 - decade, 9 - year, 10 - month, 11 - day, 12 - hour, 13 - minute, 14 - secondlocal function normalizeDate(date) date = mw.text.trim(date, "+") -- extract year local yearstr = mw.ustring.match(date, "^\-?%d+") local year = tonumber(yearstr) -- remove leading zeros of year return year .. mw.ustring.sub(date, #yearstr + 1), yearend
local function formatDate(date, precision, timezone) precision = precision or 11 local date, year = normalizeDate(date) if year
6 then era = mw.ustring.gsub(i18n.datetime[6], "$1", tostring(math.floor((math.abs(year) - 1) / 1000) + 1)) end if precision
8 then era = mw.ustring.gsub(i18n.datetime[8], "$1", tostring(math.floor(math.abs(year) / 10) * 10)) end if era then if year < 0 then era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.bc, '"', ""), "$1", era) elseif year > 0 then era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.ad, '"', ""), "$1", era) end return era end -- precision is year if precision
0 then formatstr = mw.ustring.gsub(formatstr, i18n.datetime[9], "") elseif year < 0 then -- Mediawiki formatDate doesn't support negative years date = mw.ustring.sub(date, 2) formatstr = mw.ustring.gsub(formatstr, i18n.datetime[9], mw.ustring.gsub(i18n.datetime.bc, "$1", i18n.datetime[9])) elseif year > 0 and i18n.datetime.ad ~= "$1" then formatstr = mw.ustring.gsub(formatstr, i18n.datetime[9], mw.ustring.gsub(i18n.datetime.ad, "$1", i18n.datetime[9])) end return mw.language.new(wiki.langcode):formatDate(formatstr, date) endend
local function printDatavalueEntity(data, parameter) -- data fields: entity-type [string], numeric-id [int, Wikidata id] local id if data["entity-type"]
"property" then id = "P" .. data["numeric-id"] else return printError("unknown-entity-type") end if parameter then if parameter
local function printDatavalueTime(data, parameter) -- data fields: time [ISO 8601 time], timezone [int in minutes], before [int], after [int], precision [int], calendarmodel [wikidata URI] -- precision: 0 - billion years, 1 - hundred million years, ..., 6 - millennia, 7 - century, 8 - decade, 9 - year, 10 - month, 11 - day, 12 - hour, 13 - minute, 14 - second -- calendarmodel: e.g. http://www.wikidata.org/entity/Q1985727 for the proleptic Gregorian calendar or http://www.wikidata.org/wiki/Q11184 for the Julian calendar] if parameter then if parameter
"time" then data.time = normalizeDate(data.time) end return data[parameter] else return formatDate(data.time, data.precision, data.timezone) endend
local function printDatavalueMonolingualText(data, parameter) -- data fields: language [string], text [string] if parameter then return data[parameter] else local result = mw.ustring.gsub(mw.ustring.gsub(i18n.monolingualtext, "%%language", data["language"]), "%%text", data["text"]) return result endend
local function findClaims(entity, property) if not property or not entity or not entity.claims then return end if mw.ustring.match(property, "^P%d+$") then -- if the property is given by an id (P..) access the claim list by this id return entity.claims[property] else property = mw.wikibase.resolvePropertyId(property) if not property then return end
return entity.claims[property] endend
local function getSnakValue(snak, parameter) if snak.snaktype
"string" then return snak.datavalue.value elseif snak.datavalue.type
"quantity" then return printDatavalueQuantity(snak.datavalue.value, parameter) elseif snak.datavalue.type
"wikibase-entityid" then return printDatavalueEntity(snak.datavalue.value, parameter) elseif snak.datavalue.type
local function getReferences(frame, claim) local result = "" -- traverse through all references for ref in pairs(claim.references or) do local refparts -- traverse through all parts of the current reference for snakkey, snakval in orderedpairs(claim.references[ref].snaks or, claim.references[ref]["snaks-order"]) do if refparts then refparts = refparts .. ", " else refparts = "" end -- output the label of the property of the reference part, e.g. "imported from" for P143 refparts = refparts .. tostring(mw.wikibase.label(snakkey)) .. ": " -- output all values of this reference part, e.g. "German Wikipedia" and "English Wikipedia" if the referenced claim was imported from both sites for snakidx = 1, #snakval do if snakidx > 1 then refparts = refparts .. ", " end refparts = refparts .. getSnakValue(snakval[snakidx]) end end if refparts then result = result .. frame:extensionTag("ref", refparts) end end return resultend
function p.claim(frame) local property = frame.args[1] or "" local id = frame.args["id"] -- "id" must be nil, as access to other Wikidata objects is disabled in Mediawiki configuration local qualifierId = frame.args["qualifier"] local parameter = frame.args["parameter"] local list = frame.args["list"] local references = frame.args["references"] local showerrors = frame.args["showerrors"] local default = frame.args["default"] if default then showerrors = nil end -- get wikidata entity local entity = mw.wikibase.getEntityObject(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(entity, property) if not claims or not claims[1] then if showerrors then return printError("property-not-found") else return default 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 = 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 list then local value -- iterate over all elements and return their value (if existing) result = for idx in pairs(claims) do local claim = claims[sortindices[idx]] value, error = getValueOfClaim(claim, qualifierId, parameter) if not value and showerrors then value = error end if value and references then value = value .. getReferences(frame, claim) end result[#result + 1] = value end result = table.concat(result, list) else -- return first element local claim = claims[sortindices[1]] result, error = getValueOfClaim(claim, qualifierId, parameter) if result and references then result = result .. getReferences(frame, claim) end end if result then return result else if showerrors then return error else return default end endend
-- look into entity objectfunction p.ViewSomething(frame) local f = (frame.args[1] or frame.args.id) and frame or frame:getParent local id = f.args.id if id and (#id
local i = 1 while true do local index = f.args[i] if not index then if type(data)
-- getting sitelink of a given wikifunction p.getSiteLink(frame) local f = frame.args[1] local entity = mw.wikibase.getEntity if not entity then return end local link = entity:getSitelink(f) if not link then return end return linkend
function p.Dump(frame) local f = (frame.args[1] or frame.args.id) and frame or frame:getParent local data = mw.wikibase.getEntityObject(f.args.id) if not data then return i18n.warnDump end
local i = 1 while true do local index = f.args[i] if not index then return "
"..mw.dumpObject(data).."".. i18n.warnDump end
data = data[index] or data[tonumber(index)] if not data then return i18n.warnDump end
i = i + 1 endend
-- This is used to get a date value for date_of_birth (P569), etc. which won't be linked-- Dates and times are stored in ISO 8601 format (sort of).-- At present the local formatDate(date, precision, timezone) function doesn't handle timezone-- So I'll just supply "Z" in the call to formatDate below:p.getDateValue = function(frame) local propertyID = mw.text.trim(frame.args[1] or "") local input_parm = mw.text.trim(frame.args[2] or "") local date_format = mw.text.trim(frame.args[3] or i18n["datetime"]["default-format"]) local date_addon = mw.text.trim(frame.args[4] or i18n["datetime"]["default-addon"]) if input_parm
'time' then local timestamp = v.mainsnak.datavalue.value.time local dateprecision = v.mainsnak.datavalue.value.precision out[#out + 1] = parseDateFull(timestamp, dateprecision, date_format, date_addon) end end return table.concat(out, ", ") else return "" end else return input_parm endend
return p