Module:Wikidata: Difference between revisions
Jump to navigation
Jump to search
Content deleted Content added
essentially a copy of d:Module:Wikidata |
synch with current version of d:Module:Wikidata |
||
Line 1: | Line 1: | ||
--script that retrieves basic data stored in Wikidata, for the datamodel, see https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua |
--script that retrieves basic data stored in Wikidata, for the datamodel, see https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua |
||
local p = {} |
local p = {} |
||
local fb = require('Module:Fallback') |
|||
local linguistic = require('Module:Linguistic') |
local linguistic = require('Module:Linguistic') |
||
--local formatDate = require('Module:Complex date') only loaded when needed to save memory in large pages like Wikidata:List of properties/all |
|||
local i18n = { |
|||
local fb = require('Module:Fallback') |
|||
["errors"] = { |
|||
local i18nmessages = mw.loadData('Module:i18n/wikidata') |
|||
["property-param-not-provided"] = "property parameter missing", |
|||
["qualifier-param-not-provided"] = "qualifier parameter missing", |
|||
["entity-not-found"] = "entity not found", |
|||
["unknown-claim-type"] = "unknown claim type", |
|||
["unknown-snak-type"] = "unknown snak type", |
|||
["unknown-datavalue-type"] = "unknown datavalue type.", |
|||
["unknown-entity-type"] = "unknown entity type", |
|||
["invalid-id"] = "invalid ID" |
|||
}, |
|||
["no-label"] = "no label", |
|||
['no description'] = "no description", |
|||
["novalue"] = "not applicable" |
|||
} |
|||
-- Wiki-specific parameters |
|||
local function wikibasedate(datedata, lang, case, class, trim_year) |
|||
local defaultlang = mw.getCurrentFrame():preprocess("{{int:lang}}") |
|||
-- convert Wikibase date string into year month day minute seconds |
|||
local defaultlink = 'wikidata' |
|||
if not datedata then |
|||
return nil |
|||
local function i18n(str, lang) |
|||
local message = i18nmessages[str] |
|||
if type(message) == 'string' then |
|||
return message |
|||
end |
end |
||
return fb._langSwitch(message, lang or defaultlang) |
|||
if not lang then |
|||
end |
|||
return error("language not provided") |
|||
local function formatError( key, text ) |
|||
return error(i18n(key) .. (text or '')) |
|||
end |
|||
local function addTrackingCat(prop, cat) |
|||
if not prop and not cat then |
|||
return error("no property provided") |
|||
end |
end |
||
if |
if not cat then |
||
cat = i18nmessages.trackingcat .. '/' .. string.upper(prop) |
|||
return error("invalid date structure, should be a Wikibase time-type snak") |
|||
end |
end |
||
return '[[Category:' .. cat .. ']]' |
|||
local datestring = datedata.time |
|||
end |
|||
local precision = tonumber(datedata.precision) |
|||
local calendar = 'gregorian' |
|||
local function removeBlanks(args) |
|||
local datetable, era = p.parsedatestring(datestring) |
|||
for i, j in pairs(args) do -- does not work ?? |
|||
if datedata.calendarmodel == 'http://www.wikidata.org/entity/Q1985786' then --todo here: convert calendards |
|||
if (j == '') or (j == '-') then args[i] = nil end |
|||
calendar = 'julian' |
|||
end |
end |
||
return args |
|||
end |
|||
local function formatTheUnknown() -- voir si on peut accorder/adapter l'usage de "inconnu" |
|||
-- adapt value to precision (should be done after the conversion of the string so that we can later have finer treatment like around 1957 rather than "1950s" |
|||
return i18n('somevalue') |
|||
if precision < 10 then |
|||
end |
|||
datetable[2] = '' |
|||
local function isSpecial(snak) |
|||
return snak.snaktype ~= 'value' |
|||
end |
|||
local function sameValue(snak, target) |
|||
return not isSpecial(snak) and p.getRawvalue(snak) == target |
|||
end |
|||
local function showLang(statement, str) -- TODO (not yet in proper format) |
|||
--adds a lang indication at the start of the string, based on data in statement |
|||
local mainsnak = statement.mainsnak |
|||
if isSpecial(mainsnak) then |
|||
return str |
|||
end |
end |
||
if precision < 11 then |
|||
local langlist = {} |
|||
datetable[3] = '' |
|||
if mainsnak.datavalue.type == 'monolingualtext' then |
|||
langlist = {mainsnak.datavalue.value.language} |
|||
elseif statement.qualifiers and statement.qualifiers.P407 then |
|||
local convertlangcode = mw.loadData('Module:Dictionary/lang codes') |
|||
for i, j in pairs( statement.qualifiers.P407 ) do |
|||
if not isSpecial(j) then |
|||
local val = convertlangcode[j.datavalue.value['numeric-id']] |
|||
table.insert(langlist, val) |
|||
end |
|||
end |
|||
end |
end |
||
if |
if #langlist == 0 then |
||
return str |
|||
datetable[4] = '' |
|||
else |
|||
return '('.. table.concat(langlist) .. ')' .. str |
|||
end |
end |
||
end |
|||
if precision < 13 then |
|||
datetable[5] = '' |
|||
function p.getEntity( val ) |
|||
if type(val) == 'table' then |
|||
return val |
|||
end |
end |
||
return mw.wikibase.getEntityObject(val) |
|||
if precision < 14 then |
|||
end |
|||
datetable[6] = '' |
|||
end |
|||
-- DATE FUNCTIONS |
|||
local datestr = p._Date(datetable, lang, case, (class or 'dtstart'), trim_year) |
|||
local function splitTimestamp(timestamp, calendar) |
|||
if era == '-' then |
|||
local pattern = "(%W)(%d+)%-(%d+)%-(%d+)" |
|||
return p.BC(datestr, lang) |
|||
local era, year, month, day = timestamp:match(pattern) |
|||
else |
|||
return datestr |
|||
if calendar == 'julian' then |
|||
--todo year, month, day = formatdate.gregorianToJulian( era .. year, month, day ) |
|||
end |
end |
||
return {day = day, month = month, year = year, era = era, timestamp = timestamp, type = 'dateobject'} |
|||
end |
end |
||
local function |
local function rangeObject(begin, ending) |
||
local timestamp |
|||
return '<span class="error">' .. i18n.errors[key] .. '</span>' |
|||
if begin then |
|||
timestamp = begin.timestamp |
|||
elseif ending then |
|||
timestamp = ending.timestamp |
|||
end |
|||
return {begin = begin, ending = ending, timestamp = timestamp, type = 'rangeobject'} |
|||
end |
end |
||
local function dateObject(orig, params) -- transforme un snak en un nouvel objet utilisable par Module:Date complexe |
|||
local function formatLink(value) |
|||
if not params then |
|||
local link = value |
|||
params = {} |
|||
local showntext = value |
|||
end |
|||
if string.sub(showntext, 1, 7) == "http://" then |
|||
showntext = string.sub(showntext,8 ) |
|||
local newobj = splitTimestamp(orig.time, orig.calendar) -- initalise l'object en mettant la valeur des dates |
|||
end |
|||
if string.sub(showntext, -1) == '/' then -- when last char is a char, should possibly be fixed directly in the item instead ? |
|||
newobj.precision = params.precision or orig.precision |
|||
showntext = string.sub(showntext, 1, #showntext - 1) |
|||
newobj.type = 'dateobject' |
|||
end |
|||
return newobj |
|||
return '[' .. link .. ' ' .. showntext .. ']' |
|||
end |
end |
||
local function |
local function formatDatepoint(obj, params) -- TO IMPROVE |
||
if not obj then |
|||
if snak.snaktype == 'value' and p.getRawvalue(snak) == target then |
|||
return |
return nil |
||
end |
|||
local formatDate = require('Module:Complex date') |
|||
local lang = params.lang or defaultlang |
|||
local precision = math.min(obj.precision, params.precision or 15) -- if we don't want to show the value to its full detail |
|||
if precision >= 11 then |
|||
return formatDate.complex_date{args={date1 = obj.year .. '-' .. obj.month .. '-' .. obj.day, lang= lang}} |
|||
elseif precision == 10 then |
|||
return formatDate.complex_date{args={date1 = obj.year .. '-' .. obj.month, lang= lang}} |
|||
elseif precision == 9 then |
|||
return formatDate.complex_date{args={date1 = tostring(obj.year), lang= lang}} |
|||
elseif precision == 8 then |
|||
return formatDate.complex_date{args={date1 = string.sub(tostring(obj.year), 1, 3) .. '0', lang = lang, precision = 'decade'}} |
|||
elseif precision == 7 then |
|||
return formatDate.complex_date{args={date1 = string.sub(tostring(obj.year + 100), 1, 2), lang = lang, precision = 'century'}} |
|||
end |
end |
||
return nil |
|||
end |
end |
||
local function |
local function formatDaterange(obj, params) --TODO |
||
local begin = formatDatepoint(obj.begin, params) or '' |
|||
return mw.wikibase.getEntityObject(id) |
|||
local ending = formatDatepoint(obj.ending, params) or '' |
|||
return begin .. '-' .. ending |
|||
end |
end |
||
local function |
local function objectToText(obj, params) |
||
if obj.type == 'dateobject' then |
|||
for i, j in pairs(statements) do |
|||
return formatDatepoint(obj, params) |
|||
elseif obj.type == 'rangeobject' then |
|||
end |
|||
return formatDaterange(obj, params) |
|||
return statements |
|||
end |
|||
return nil |
|||
end |
end |
||
local function tableToText(values, params) -- takes a list of already formatted values and make them a text |
local function tableToText(values, params) -- takes a list of already formatted values and make them a text |
||
if not values then |
|||
return nil |
|||
end |
|||
return linguistic.conj(values, params.lang or defaultlang, params.conjtype)--linguistic.conj( values, params.lang, params.conjtype ) |
|||
end |
end |
||
function p.getDate(obj) |
|||
--[[ |
--[[ |
||
returns an object containing a timestamp for easy sorting, and other data |
|||
return a "timedata" object as used by the date modules with the date of an item from the p580, p582 and p585 qualifiers |
|||
possible types of object: |
|||
object format: |
|||
dateobject |
|||
* timestamp 28 char string value for the timepoint, or if non the beginning or if none, the end (for easy sorting) |
|||
{timestamp = string, year = number, month = number, day = number, calendar = string} |
|||
* timepoint: snak |
|||
rangeobject |
|||
* begin: snak |
|||
{timestamp = string, begin = dateobject, ending = dateobject} |
|||
]]-- |
]]-- |
||
if not obj then |
|||
local timedata = {} |
|||
local q = statement.qualifiers |
|||
if not q or not (q.P585 or q.P580 or q.P582) then |
|||
return nil |
return nil |
||
end |
end |
||
if |
if type(obj) == 'string' then |
||
obj = p.getEntity(obj) |
|||
timedata.endpoint = q.P582[1].datavalue.value |
|||
timedata.timestamp = q.P582[1].datavalue.value.time |
|||
end |
end |
||
if q.P580 and q.P580[1].snaktype == 'value' then |
|||
-- if obj is a statement with date, get it |
|||
timedata.startpoint = q.P580[1].datavalue.value |
|||
if obj.mainsnak and not isSpecial(obj.mainsnak) and obj.mainsnak.datatype == 'time' then |
|||
timedata.timestamp = q.P580[1].datavalue.value.time |
|||
return dateObject(obj.mainsnak.datavalue.value.time) |
|||
end |
end |
||
if q.P585 and q.P585[1].snaktype == 'value' then |
|||
-- else preload relevant data |
|||
timedata.timepoint = q.P585[1].datavalue.value |
|||
local qualifs = obj.qualifiers -- when obj is a statement, look in qualifiers |
|||
timedata.timestamp = q.P585[1].datavalue.value.time |
|||
local claims = obj.claims -- when obj is an item, look in claims |
|||
local pointprop = {'P585', 'P571'} -- dates corresponding to a punctual fact |
|||
local beginprop = {'P580', 'P569'} -- start date, birth date == start of a date range |
|||
local endingprop = {'P582', 'P570'} |
|||
local function getval(prop) |
|||
local val |
|||
if claims and claims[prop] and not isSpecial(claims[prop][1].mainsnak) then |
|||
val = claims[prop][1].mainsnak.datavalue.value |
|||
elseif qualifs and qualifs[prop] and not isSpecial(qualifs[prop][1]) then |
|||
val = qualifs[prop][1].datavalue.value |
|||
end |
|||
if val then |
|||
return dateObject(val) |
|||
end |
|||
return nil |
|||
end |
|||
for i, prop in pairs(pointprop) do |
|||
local val = getval(prop) |
|||
if val then return val end |
|||
end |
|||
--if no date has not been found, look for startdate or enddate |
|||
local begin, ending |
|||
for i, prop in pairs(beginprop) do |
|||
begin = getval(prop) |
|||
if begin then |
|||
break |
|||
end |
|||
end |
|||
for i, prop in pairs(endingprop) do |
|||
ending = getval(prop) |
|||
if ending then |
|||
break |
|||
end |
|||
end |
|||
if begin or ending then |
|||
return rangeObject(begin, ending) |
|||
end |
end |
||
return |
return nil |
||
end |
end |
||
function p.getFormattedDate(statement, params) |
|||
local datetable = p.getDate(statement) |
|||
targetvalue = string.upper(targetvalue) |
|||
if not datetable then |
|||
local oldclaims = claims |
|||
return nil |
|||
local claims = {} |
|||
end |
|||
for i, statement in pairs(oldclaims) do |
|||
return objectToText(datetable, params) |
|||
if samevalue(statement.mainsnak, targetvalue) then |
|||
table.insert(claims, statement) |
|||
end |
|||
end |
|||
return claims |
|||
end |
end |
||
local function |
local function hasTargetValue(claim, target) |
||
if target == nil then |
|||
local oldclaims = claims |
|||
return true |
|||
local claims = {} |
|||
end |
|||
for i, statement in pairs(oldclaims) do |
|||
return sameValue(claim.mainsnak, target) |
|||
if statement.rank == 'preferred' or statement.rank == 'normal' then |
|||
table.insert(claims, statement) |
|||
end |
|||
end |
|||
return claims |
|||
end |
end |
||
local function |
local function hasRank(claim, target) |
||
if target == 'valid' then |
|||
return hasRank(claim, 'preferred') or hasRank(claim, 'normal') |
|||
else |
|||
if #preferred > 0 then |
|||
return claim.rank == target |
|||
return preferred |
|||
end |
|||
else |
|||
return withrank(claims, 'normal') |
|||
end |
|||
end |
|||
if rank == 'valid' then |
|||
return validclaims(claims) |
|||
end |
|||
local oldclaims = claims |
|||
local claims = {} |
|||
for i, statement in pairs(oldclaims) do |
|||
if statement.rank == rank then |
|||
table.insert(claims, statement) |
|||
end |
|||
end |
|||
return claims |
|||
end |
end |
||
local function |
local function bestRanked(claims) |
||
if not claims then |
|||
qualifier, qualifiervalue = string.upper(qualifier), string.upper(qualifiervalue or '') |
|||
return nil |
|||
end |
|||
local oldclaims = claims |
|||
local preferred, normal = {}, {} |
|||
local claims = {} |
|||
for i, j in pairs(claims) do |
|||
if j.rank == 'preferred' then |
|||
if statement.qualifiers and statement.qualifiers then |
|||
table.insert(preferred, j) |
|||
if qualifiervalue ~= '' then |
|||
elseif j.rank == 'normal' then |
|||
for j, qualif in pairs(statement.qualifiers[qualifier]) do |
|||
table.insert(normal, j) |
|||
if p.getRawvalue(qualif) == qualifiervalue then |
|||
end |
|||
table.insert(claims, statement) |
|||
end |
|||
end |
|||
if #preferred > 0 then |
|||
end |
|||
return preferred |
|||
else |
|||
else |
|||
table.insert(claims, statement) |
|||
return normal |
|||
end |
|||
end |
|||
end |
|||
return claims |
|||
end |
end |
||
local function withsource(claims, source, sourceproperty) |
|||
local function hasQualifier(claim, qualifier, qualifiervalues) |
|||
local oldclaims = claims |
|||
if not qualifier then -- si aucun qualificatif est demandé, ça passe |
|||
local claims = {} |
|||
return true |
|||
sourceproperty = string.upper(sourceproperty or 'P248') |
|||
end |
|||
local sourcevalue = string.upper(source or '') |
|||
for i, statement in pairs(oldclaims) do |
|||
qualifier = string.upper(qualifier) |
|||
local success |
|||
if not claim.qualifiers or not claim.qualifiers[qualifier] then |
|||
if statement.references then |
|||
return false |
|||
for j, reference in pairs(statement.references) do |
|||
end |
|||
if success then break end -- sp that it does not return twice the same reference when the property is used twice |
|||
for prop, content in pairs(reference.snaks) do |
|||
if type(qualifiervalues) == 'string' then |
|||
if prop == sourceproperty then |
|||
qualifiervalues = mw.text.split(qualifiervalues, ',') |
|||
if sourcevalue == '' then |
|||
end |
|||
table.insert(claims, statement) |
|||
success = true |
|||
if (not qualifiervalues) or (qualifiervalues == {}) then |
|||
else |
|||
return true -- si aucune valeur spécifique n'est exigée |
|||
for l, m in pairs(content) do |
|||
end |
|||
if p.getRawvalue(m) == source then |
|||
table.insert(claims, statement) |
|||
for i, j in pairs(claim.qualifiers[qualifier]) do |
|||
success = true |
|||
for k, l in pairs(qualifiervalues) do |
|||
end |
|||
if p.getRawvalue(j) == l then |
|||
end |
|||
return true |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
return false |
|||
end |
|||
end |
|||
return claims |
|||
local function hasSource(statement, source, sourceproperty) |
|||
if not statement.references then |
|||
return false |
|||
end |
|||
sourceproperty = string.upper(sourceproperty or 'P248') |
|||
local sourcevalue = string.upper(source or '') |
|||
for i, ref in pairs(statement.references) do |
|||
for prop, content in pairs(ref.snaks) do |
|||
if prop == sourceproperty then |
|||
if sourcevalue == '' then |
|||
return true |
|||
else |
|||
for j, k in pairs(content) do |
|||
if p.getRawvalue(k) == source then |
|||
return true |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
return false |
|||
end |
end |
||
local function |
local function hasDate(statement) |
||
if not statement.qualifiers then |
|||
local oldclaims = claims |
|||
return false |
|||
local claims = {} |
|||
end |
|||
for i, statement in pairs(oldclaims) do |
|||
local dateprops = {'P580', 'P585', 'P582'} |
|||
if statement.mainsnak.snaktype == 'value' then |
|||
for i, prop in pairs(dateprops) do |
|||
table.insert(claims, statement) |
|||
if statement.qualifiers[prop] then |
|||
end |
|||
return true |
|||
end |
|||
end |
|||
return claims |
|||
end |
|||
return false |
|||
end |
end |
||
local function |
local function isInLanguage(snak, lang) -- ne fonctionne que pour les monolingualtext / étendre aux autres types en utilisant les qualifiers ? |
||
return not isSpecial(snak) and snak.datavalue.type == 'monolingualtext' and snak.datavalue.value.language == lang |
|||
end |
|||
local function numval(claims, numval) -- retourn les numval premières valeurs de la table claims |
|||
local numval = tonumber(numval) or 0 -- raise a error if numval is not a positive integer ? |
|||
if #claims <= numval then |
|||
return claims |
|||
end |
|||
local newclaims = {} |
|||
while #newclaims < numval do |
|||
table.insert(newclaims, claims[#newclaims + 1]) |
|||
end |
|||
return newclaims |
|||
end |
|||
function p.comparedate(a, b) -- returns true if a is earlier than B or if a has a date but not b |
|||
if a and b then |
if a and b then |
||
return a.timestamp < b.timestamp |
return a.timestamp < b.timestamp |
||
Line 247: | Line 358: | ||
return true |
return true |
||
end |
end |
||
return false |
|||
end |
end |
||
function p.chronosort(objs, inverted) |
|||
table.sort( |
table.sort(objs, function(a, b) |
||
local timeA = getDate(a) |
local timeA = p.getDate(a) |
||
local timeB = getDate(b) |
local timeB = p.getDate(b) |
||
if inverted then |
if inverted then |
||
return comparedate(timeB, timeA) |
return p.comparedate(timeB, timeA) |
||
else |
else |
||
return comparedate(timeA, timeB) |
return p.comparedate(timeA, timeB) |
||
end |
end |
||
end) |
|||
) |
|||
return |
return objs |
||
end |
end |
||
function p.sortclaims(claims, sorttype) |
function p.sortclaims(claims, sorttype) |
||
if sorttype == ' |
if type(sorttype) == 'function' then |
||
return chronosort(claims) |
|||
elseif sorttype == 'inverted' then |
|||
return chronosort(claims, true) |
|||
elseif type(sorttype) == 'function' then |
|||
table.sort(claims, sorttype) |
table.sort(claims, sorttype) |
||
elseif sorttype == 'chronological' then |
|||
return claims |
|||
return p.chronosort(claims) |
|||
elseif sorttype == 'inverted' then |
|||
return p.chronosort(claims, true) |
|||
end |
end |
||
return claims |
return claims |
||
end |
end |
||
function p.getRawvalue(snak) |
|||
return p.getDatavalue(snak, {displayformat = 'raw'}) |
|||
local numval = tonumber(numval) or 0 -- raise a error if numval is not a positive integer ? |
|||
local newclaims = {} |
|||
for i, j in pairs(claims) do |
|||
if #newclaims == numval then |
|||
return newclaims |
|||
end |
|||
table.insert(newclaims,j) |
|||
end |
|||
return newclaims |
|||
end |
end |
||
function p. |
function p.showentity(entity, lang) |
||
if not entity then |
|||
return p.getDatavalue(snak, {format = 'raw'}) |
|||
return nil |
|||
end |
|||
if type(entity) == 'string' then |
|||
entity = p.getEntity(entity) |
|||
end |
|||
if not entity or not entity.type then |
|||
return formatError('entity-not-found') |
|||
end |
|||
local label = p._getLabel(entity, lang) |
|||
local id = entity.id |
|||
local link = id |
|||
if entity.type == 'property' then |
|||
link = 'Property:' .. link |
|||
end |
|||
return '[[' .. link .. '|' .. label .. ']] <small>(' .. id .. ')</small>' |
|||
end |
end |
||
function p.getDatavalue(snak, params) |
function p.getDatavalue(snak, params) |
||
if isSpecial(snak) then |
|||
return nil |
|||
end |
|||
local datatype = snak.datavalue.type |
|||
local value = snak.datavalue.value |
|||
local displayformat = params.format |
|||
if datatype == 'wikibase-entityid' then |
|||
if displayformat == 'raw' then |
|||
return "Q" .. tostring(value['numeric-id']) |
|||
else |
|||
return p.formatEntityId("Q" .. tostring(value['numeric-id']), params) |
|||
end |
|||
elseif datatype == 'string' then |
|||
if displayformat == 'weblink' then |
|||
return formatLink(value) |
|||
end |
|||
return value |
|||
if not params then |
|||
params = {} |
|||
elseif datatype == 'time' then -- format example: +00000001809-02-12T00:00:00Z |
|||
end |
|||
if displayformat == 'raw' then |
|||
return value.time |
|||
else |
|||
return require('Module:Date').Wikibasedate(value, params.lang) |
|||
end |
|||
local displayformat = params.displayformat |
|||
elseif datatype == 'globecoordinate' then |
|||
local datatype = snak.datavalue.type |
|||
local latitude, longitude = value.latitude, value.longitude |
|||
local value = snak.datavalue.value |
|||
local globe = require('Module:Wikidata/Globes')[value.globe] -- transforme l'ID du globe en nom anglais utilisable par geohack |
|||
local precision = value.precision |
|||
if datatype == 'wikibase-entityid' then |
|||
if type(displayformat) == 'function' then |
|||
precision = 'dmsand2' |
|||
return displayformat(snak, params) |
|||
elseif precision < 0.016 then |
|||
end |
|||
precision = 'dms' |
|||
local prefix = 'Q' |
|||
elseif precision < 1 then |
|||
if snak.datavalue.value["entity-type"] == 'property' then |
|||
precision = 'dm' |
|||
prefix = 'P' |
|||
end |
|||
local id = prefix .. tostring(value['numeric-id']) |
|||
if displayformat == 'raw' then |
|||
return id |
|||
elseif displayformat == 'wikidatastyle' then |
|||
return p.showentity(id, params.lang) |
|||
else |
else |
||
return p.formatEntity(id, params) |
|||
precision = 'd' |
|||
end |
end |
||
return require('Module:Coordinates')._coord{latitude = latitude, longitude = longitude, globe = globe, precision = precision} |
|||
elseif datatype == 'string' then |
|||
local showntext = params.showntext |
|||
if displayformat == 'weblink' then |
|||
if showntext then |
|||
return '[' .. value .. ' ' .. showntext .. ']' |
|||
else |
|||
return value |
|||
end |
|||
end |
|||
if snak.datatype == 'math' and displayformat ~= 'raw' then |
|||
value = mw.getCurrentFrame():extensionTag('math', value) |
|||
end |
|||
if params.urlpattern then |
|||
value = '[' .. mw.ustring.gsub(mw.ustring.gsub(params.urlpattern, '$1', value), ' ', '%%20') .. ' ' .. (showntext or value) .. ']' |
|||
end |
|||
return value |
|||
elseif datatype == 'time' then -- format example: +00000001809-02-12T00:00:00Z |
|||
if displayformat == 'raw' then |
|||
return value.time |
|||
else |
|||
return objectToText(dateObject(value), params) |
|||
local str = string.sub(value.amount,2) |
|||
end |
|||
return require('Module:Formatnum').formatnum(str, {lang= params.lang}) |
|||
end |
|||
elseif datatype == 'globecoordinate' then |
|||
else |
|||
-- retourne une table avec clés latitude, longitude, précision et globe à formater par un autre module (à changer ?) |
|||
return formatError( 'unknown-datavalue-type' ) |
|||
if displayformat == 'latitude' then |
|||
end |
|||
return value.latitude |
|||
elseif displayformat == 'longitude' then |
|||
return value.longitude |
|||
elseif displayformat == 'qualifier' then |
|||
local coord = require 'Module:Coordinates' |
|||
value.globe = require('Module:Wikidata/Globes')[value.globe] |
|||
value.precision = nil |
|||
return coord._coord(value) |
|||
else |
|||
value.globe = require('Module:Wikidata/Globes')[value.globe] -- transforme l'ID du globe en nom anglais utilisable par geohack |
|||
return value -- note : les coordonnées Wikidata peuvent être utilisée depuis Module:Coordinates. Faut-il aussi autoriser à appeler Module:Coordiantes ici ? |
|||
end |
|||
elseif datatype == 'quantity' then -- todo : gérer les paramètre précision |
|||
if displayformat == 'raw' then |
|||
return tonumber(value.amount) |
|||
else |
|||
local formatNum = require 'Module:Formatnum' |
|||
local number = formatNum.formatNum(value.amount) |
|||
local unit = mw.ustring.match(value.unit, '(Q%d+)') |
|||
if unit then |
|||
number = number .. ' ' .. p.formatEntity(unit, params) |
|||
end |
|||
return number |
|||
end |
|||
elseif datatype == 'monolingualtext' then |
|||
return '<span lang="' .. value.language .. '">' .. value.text .. '</span>' |
|||
else |
|||
return formatError( 'unknown-datavalue-type', datatype ) |
|||
end |
|||
end |
end |
||
Line 354: | Line 506: | ||
newargs.property = j |
newargs.property = j |
||
local newclaims = p.getClaims(args) |
local newclaims = p.getClaims(args) |
||
for k, l in pairs(newclaims) do |
if newclaims then |
||
for k, l in pairs(newclaims) do |
|||
table.insert(claims, l) |
table.insert(claims, l) |
||
end |
|||
end |
end |
||
end |
end |
||
return claims |
return claims |
||
end |
end |
||
function p.getClaims( args ) -- returns a table of the claims matching some conditions given in args |
function p.getClaims( args ) -- returns a table of the claims matching some conditions given in args |
||
args = removeBlanks(args) |
|||
if not args.property then |
|||
if not args.property then |
|||
return formatError( 'property-param-not-provided' ) |
|||
end |
|||
if type(args.property) == 'table' then |
|||
return getMultipleClaims(args) |
|||
end |
|||
--Get entity |
|||
if args.item then -- synonyms |
|||
local entity = nil |
|||
local property = string.upper(args.property) |
|||
if args.item then -- item used as a synonym for entity |
|||
args.entity = args.item |
args.entity = args.item |
||
end |
end |
||
local entity = args.entity |
|||
if type(entity) ~= 'table' then |
|||
entity = p.getEntity(entity) |
|||
end |
|||
local property = string.upper(args.property) |
|||
if not entity or not entity.claims or not entity.claims[property] then |
|||
return nil |
return nil |
||
end |
end |
||
if type( args.entity ) == "table" then |
|||
entity = args.entity |
|||
else |
|||
entity = getEntityFromId( args.entity ) |
|||
end |
|||
if not args.rank then |
|||
if not entity or not entity.claims or not entity.claims[property] then |
|||
args.rank = 'best' |
|||
return nil |
|||
end |
|||
local claims = {} |
|||
-- ~= '' lorsque le paramètre est écrit mais laissé blanc dans une fonction frame |
|||
for i, statement in pairs(entity.claims[property]) do |
|||
if |
|||
if args.targetvalue and args.targetvalue ~= '' then |
|||
( |
|||
claims = withtargetvalue(claims, args.targetvalue) |
|||
not args.excludespecial |
|||
end |
|||
or |
|||
not (isSpecial(statement.mainsnak)) |
|||
) |
|||
and |
|||
( |
|||
not args.targetvalue |
|||
or |
|||
hasTargetValue(statement, args.targetvalue) |
|||
) |
|||
and |
|||
( |
|||
not args.qualifier |
|||
or |
|||
hasQualifier(statement, args.qualifier, args.qualifiervalues or args.qualifiervalue) |
|||
) |
|||
and |
|||
( |
|||
not args.withsource or args.withsource == '-' |
|||
or |
|||
hasSource(statement, args.withsource, args.sourceproperty) |
|||
) |
|||
and |
|||
( |
|||
not args.isinlanguage |
|||
or |
|||
isInLanguage(statement.mainsnak, args.isinlanguage) |
|||
) |
|||
and |
|||
( |
|||
args.rank == 'best' -- rank == best est traité à a fin |
|||
or |
|||
hasRank(statement, args.rank) |
|||
) |
|||
then |
|||
table.insert(claims, statement) |
|||
end |
|||
end |
|||
if #claims == 0 then |
|||
return nil |
|||
end |
|||
if args.rank == 'best' then |
|||
claims = bestRanked(claims) |
|||
end |
|||
if args.sorttype then |
|||
claims = p.sortclaims(claims, args.sorttype) |
|||
end |
|||
if args.numval then |
|||
return numval(claims, args.numval) |
|||
claims = withqualifier(claims, args.qualifier, args.qualifiervalue) |
|||
end |
|||
return claims |
|||
if (args.source and args.source) or (args.sourceproperty and args.sourceproperty ~= '') then |
|||
end |
|||
claims = withsource(claims, args.source, args.sourceproperty) |
|||
end |
|||
if args.excludespecial and args.excludespecial ~= '' then |
|||
claims = excludespecial(claims) |
|||
end |
|||
function p.formatClaimList(claims, args) |
|||
if args.rank ~= 'all' then |
|||
if not claims then |
|||
return nil |
|||
args.rank = 'best' |
|||
end |
|||
claims = withrank(claims, args.rank) |
|||
end |
|||
if args.sorttype then |
|||
claims = p.sortclaims(claims, args.sorttype) |
|||
end |
|||
if args.numval and args.numval ~= '' then --keep at the end, after other filters have been implmented |
|||
claims = numval(claims, args.numval) |
|||
end |
|||
if #claims > 0 then |
|||
return claims |
|||
end |
end |
||
for i, j in pairs(claims) do |
|||
claims[i] = p.formatStatement(j, args) |
|||
end |
|||
return claims |
|||
end |
end |
||
function p.stringTable(args) -- like getClaims, but get a list of string rather than a list of snaks, for easier manipulation |
|||
function p.getQualifiers(args) |
|||
local claims = p.getClaims(args) |
local claims = p.getClaims(args) |
||
return p.formatClaimList(claims, args) |
|||
end |
|||
local function getQualifiers(statement, qualifs, params) |
|||
if not statement.qualifiers then |
|||
return nil |
return nil |
||
end |
end |
||
local |
local vals = {} |
||
for i, j in pairs(qualifs) do |
|||
local found = {} |
|||
j = string.upper(j) |
|||
for i, j in pairs(claims) do |
|||
if |
if statement.qualifiers[j] then |
||
local inserted = false |
|||
break |
|||
if statement.qualifiers[j][1].datatype == 'monolingualtext' then |
|||
end |
|||
local in_preferred_lang |
|||
for k, l in pairs(j.qualifiers[targetqualif]) do |
|||
for _, language in pairs(fb.fblist(params.lang or defaultlang)) do |
|||
table.insert(found, l) |
|||
for _, snak in pairs(statement.qualifiers[j]) do |
|||
if isInLanguage(snak, language) then |
|||
in_preferred_lang = snak |
|||
break |
|||
end |
|||
end |
|||
if in_preferred_lang then |
|||
break |
|||
end |
|||
end |
|||
if in_preferred_lang then |
|||
table.insert(vals, in_preferred_lang) |
|||
inserted = true |
|||
end |
|||
end |
|||
if not inserted then |
|||
for _, snak in pairs(statement.qualifiers[j]) do |
|||
table.insert(vals, snak) |
|||
end |
|||
end |
|||
end |
end |
||
end |
end |
||
if # |
if #vals == 0 then |
||
return |
return nil |
||
end |
end |
||
return vals |
|||
end |
end |
||
function p.getFormattedQualifiers( |
function p.getFormattedQualifiers(statement, qualifs, params) |
||
if not params then params = {} end |
|||
local qualifs = p.getQualifiers(args) |
|||
local qualiftable = getQualifiers(statement, qualifs, params) |
|||
if not qualifs then |
|||
if not qualiftable then |
|||
return nil |
return nil |
||
end |
end |
||
for i, j in pairs( |
for i, j in pairs(qualiftable) do |
||
local params = params |
|||
qualifs[i] = p.formatSnak(j, args) |
|||
if j.datatype == 'globe-coordinate' then |
|||
params.displayformat = 'qualifier' |
|||
end |
|||
qualiftable[i] = p.formatSnak(j, params) |
|||
end |
end |
||
return linguistic.conj(qualiftable, params.lang or defaultlang) |
|||
return tableToText(qualifs, args) |
|||
end |
end |
||
function p.formatStatement( statement, args ) |
|||
if not statement.type or statement.type ~= 'statement' then |
|||
return formatError( 'unknown-claim-type', statement.type ) |
|||
end |
|||
if not args then args = {} end |
|||
local lang = args.lang or defaultlang |
|||
local str = p.formatSnak( statement.mainsnak, args ) |
|||
if args.showlang == true then |
|||
str = showLang(statement, str) |
|||
end |
|||
local qualifs = args.showqualifiers |
|||
function p.formatQualifier( frame ) |
|||
if qualifs then |
|||
return p.getFormattedQualifiers(frame.args) |
|||
if type(qualifs) == 'string' then |
|||
end |
|||
qualifs = mw.text.split(qualifs, ',') |
|||
end |
|||
local foundvalues = p.getFormattedQualifiers(statement, qualifs, args) |
|||
if foundvalues then |
|||
if args.delimiter then |
|||
str = str .. args.delimiter .. foundvalues |
|||
else |
|||
str = str .. linguistic.inparentheses(foundvalues, lang) |
|||
end |
|||
end |
|||
end |
|||
if args.showdate then -- when "showdate and p.chronosort are both set, date retrieval is performed twice |
|||
function p.formatClaimList(claims, args) |
|||
local timedata = p.getDate(statement) |
|||
if not claims then |
|||
if timedata then |
|||
return nil |
|||
local formatteddate = objectToText(timedata, args) |
|||
end |
|||
formatteddate = linguistic.inparentheses(formatteddate, lang) |
|||
for i, j in pairs(claims) do |
|||
str = str .. '<small>' .. formatteddate ..'</small>' |
|||
claims[i] = p.formatStatement(j, args) |
|||
end |
|||
end |
|||
return claims |
|||
end |
|||
if args.showsource and statement.references then |
|||
function p.stringTable(args) -- like getClaims, but get a list of string rather than a list of snaks, for easier manipulation |
|||
local cite = require 'Module:Cite' |
|||
local frame = mw.getCurrentFrame() |
|||
return p.formatClaimList(claims, args) |
|||
local sourcestring = '' |
|||
for i, ref in pairs(statement.references) do |
|||
if ref.snaks.P248 then |
|||
for j, source in pairs(ref.snaks.P248) do |
|||
if not isSpecial(source) then |
|||
local page |
|||
if ref.snaks.P304 and not isSpecial(ref.snaks.P304[1]) then |
|||
page = ref.snaks.P304[1].datavalue.value |
|||
end |
|||
local s = cite.citeitem('Q' .. source.datavalue.value['numeric-id'], lang, page) |
|||
s = frame:extensionTag( 'ref', s ) |
|||
sourcestring = sourcestring .. s |
|||
end |
|||
end |
|||
elseif ref.snaks.P854 and not isSpecial(ref.snaks.P854[1]) then |
|||
s = frame:extensionTag( 'ref', p.getDatavalue(ref.snaks.P854[1]) ) |
|||
sourcestring = sourcestring .. s |
|||
end |
|||
end |
|||
str = str .. sourcestring |
|||
end |
|||
return str |
|||
end |
end |
||
function p.formatSnak(snak, params) |
|||
function p.formatStatements( args )--Format statement and concat them cleanly |
|||
--local params = params or {} pour faciliter l'appel depuis d'autres modules |
|||
local valuetable = p.stringTable(args) |
|||
if snak.snaktype == 'value' then |
|||
return tableToText(valuetable, args) |
|||
return p.getDatavalue(snak, params) |
|||
elseif snak.snaktype == 'somevalue' then |
|||
return formatTheUnknown() |
|||
elseif snak.snaktype == 'novalue' then |
|||
return i18n('novalue') --todo |
|||
else |
|||
return formatError( 'unknown-snak-type', snak.snaktype ) |
|||
end |
|||
end |
end |
||
local function defaultLabel(entity, lang, displayformat) -- label when no label is available |
|||
function p.formatStatement( statement, args ) |
|||
if entity and displayformat == 'id' then |
|||
if not statement.type or statement.type ~= 'statement' then |
|||
return entity.id |
|||
return formatError( 'unknown-claim-type' ) |
|||
end |
|||
return i18n('no-label', lang) |
|||
end |
|||
local str = p.formatSnak( statement.mainsnak, args ) |
|||
if args.showqualifiers then -- very ugly |
|||
local targetqualif = string.upper(args.showqualifiers) |
|||
local foundvalues = {} |
|||
if statement.qualifiers and statement.qualifiers[targetqualif] then |
|||
for i, j in pairs(statement.qualifiers[targetqualif]) do |
|||
table.insert(foundvalues, p.getDatavalue(j, {lang=args.lang, link=args.link})) |
|||
end |
|||
str = str .. linguistic.inparentheses(mw.text.listToText(foundvalues), lang) |
|||
end |
|||
end |
|||
if args.withdate then -- when "withdate and chronosorty are borth set, date retrieval is performed twice |
|||
local timedata = getDate(statement) |
|||
if timedata then |
|||
local dat = require('Module:Daterange').wikibasedaterange(timedata, args.lang) |
|||
local formattteddate = linguistic.inparentheses(dat, args.lang) |
|||
str = str .. formattteddate |
|||
end |
|||
end |
|||
function p._getLabel(entity, lang, default) |
|||
if args.showsource and statement.references then -- not great |
|||
if not entity then |
|||
local sourcestring = '' |
|||
return nil |
|||
for i, ref in pairs(statement.references) do |
|||
end |
|||
if ref.snaks.P248 then |
|||
if type(entity) ~= 'table' then |
|||
for j, source in pairs(ref.snaks.P248) do |
|||
entity = p.getEntity(entity) |
|||
if source.snaktype == 'value' then |
|||
end |
|||
local page |
|||
if entity and entity.labels then |
|||
if ref.snaks.P304 and ref.snaks.P304[1].snaktype == 'value' then |
|||
for i, lg in pairs(fb.fblist(lang or defaultlang)) do |
|||
page = ref.snaks.P304[1].datavalue.value |
|||
if entity.labels[lg] then |
|||
end |
|||
return entity.labels[lg].value |
|||
local s = require('Module:Cite/sandbox').citeitem('Q' .. source.datavalue.value['numeric-id'], args.lang, page) |
|||
end |
|||
s = mw.getCurrentFrame():extensionTag( 'ref', s ) |
|||
end |
|||
sourcestring = sourcestring .. s |
|||
end |
|||
end |
|||
return defaultLabel(entity, lang, default) |
|||
end |
|||
elseif ref.snaks.P854 and ref.snaks.P854[1].snaktype == 'value' then |
|||
s = mw.getCurrentFrame():extensionTag( 'ref', formatLink(ref.snaks.P854[1].datavalue.value)) |
|||
sourcestring = sourcestring .. s |
|||
end |
|||
end |
|||
str = str .. sourcestring |
|||
end |
|||
return str |
|||
end |
end |
||
function p. |
function p._getDescription(entity, lang) |
||
if not entity then |
|||
if not args then args = {} end -- pour faciliter l'appel depuis d'autres modules |
|||
return i18n('no description') |
|||
if snak.snaktype == 'somevalue' then |
|||
end |
|||
return fb._langSwitch(require('Module:I18n/unknown'), args.lang) |
|||
if type(entity) ~= 'table' then |
|||
elseif snak.snaktype == 'novalue' then |
|||
entity = p.getEntity(entity) |
|||
return i18n['novalue'] --todo |
|||
end |
|||
elseif snak.snaktype == 'value' then |
|||
local descriptions = entity.descriptions |
|||
return p.getDatavalue( snak, args) |
|||
if not descriptions then |
|||
else |
|||
return i18n('no description') |
|||
return formatError( 'unknown-snak-type' ) |
|||
end |
|||
if descriptions[lang] then |
|||
return descriptions[lang].value |
|||
end |
|||
local langlist = fb.fblist(lang or defaultlang) -- list of fallback languages if no label in the desired language |
|||
for i, lg in pairs(langlist) do |
|||
if descriptions[lg] then |
|||
return descriptions[lg].value |
|||
end |
|||
end |
|||
return i18n('no description') |
|||
end |
end |
||
function |
local function wikipediaLink(entity, lang) |
||
local link = entity:getSitelink(lang .. 'wiki') |
|||
if type(entity) == 'string' then |
|||
if link then |
|||
entity = mw.wikibase.getEntityObject(entity) |
|||
return ':' .. lang .. ':' .. link |
|||
end |
end |
||
return nil |
|||
local label = entity:getLabel(lang) |
|||
if label then |
|||
return label |
|||
end |
|||
for i, j in pairs (mw.language.getFallbacksFor(lang)) do |
|||
label = entity:getLabel(j) |
|||
if label then |
|||
return label |
|||
end |
|||
end |
|||
if default == 'nolabel' then |
|||
return i18n['no-label'] |
|||
end |
|||
return entity.id |
|||
end |
end |
||
function |
local function getLink(entity, typelink, lang) |
||
if |
if not typelink or typelink == '-' then |
||
return nil |
|||
entity = mw.wikibase.getEntityObject(entity) |
|||
end |
end |
||
if not lang then |
|||
lang = defaultlang |
|||
if not entity.descriptions then |
|||
end |
|||
return i18n['no description'] |
|||
end |
|||
if typelink == 'wikidata' then |
|||
local descriptions = entity.descriptions |
|||
if entity.type == 'property' then |
|||
if not descriptions then |
|||
return 'd:P:' .. entity.id |
|||
else |
|||
end |
|||
return 'd:' .. entity.id |
|||
if descriptions[lang] then |
|||
end |
|||
return descriptions[lang].value |
|||
end |
|||
elseif typelink == 'wikipedia' then |
|||
local fblist = require('Module:Fallback').fblist(lang) -- list of fallback languages in no label in the desired language |
|||
return wikipediaLink(entity, lang) |
|||
for i, j in pairs (mw.language.getFallbacksFor(lang)) do |
|||
if descriptions.lang then |
|||
elseif typelink == 'anywikipedia' then |
|||
return descriptions[lang].value |
|||
local fallbacklist = fb.fblist(lang) |
|||
end |
|||
for i, lg in pairs(fallbacklist) do |
|||
end |
|||
link = wikipediaLink(entity, lg) |
|||
if default == 'nolabel' then |
|||
if link then return link end |
|||
return i18n['no-label'] |
|||
end |
|||
end |
|||
return entity.id |
|||
return nil |
|||
end |
end |
||
local function formattedLabel(label, entity, args) |
local function formattedLabel(label, entity, args) |
||
if not args then args = {} end |
|||
local link = getLink(entity, args.link, args.lang) |
|||
return label |
|||
if not link then |
|||
end |
|||
link = getLink(entity, defaultlink, args.lang) |
|||
local link |
|||
if args.link == 'wikipedia' then |
|||
link = entity:getSitelink(lang .. 'wiki') |
|||
if link then |
|||
link = ':' .. lang .. ':' .. link |
|||
end |
|||
elseif args.link == 'anywikipedia' then -- if Wikipeia links does not exist in the user's language, goes through the fallbackchain |
|||
local sitelinks = entity.sitelinks |
|||
if sitelinks then |
|||
local hack = {} |
|||
for i, j in pairs(sitelinks) do |
|||
if string.sub(i, #i-4, #i) then |
|||
hack[string.sub(i, 1, #i - 4)] = j.title |
|||
end |
|||
end |
|||
if not hack['en'] then hack['en'] = '~' end |
|||
local linklang |
|||
link, linklang = require('Module:Fallback')._langSwitch(hack, lang) |
|||
if link then |
|||
link = ':' .. linklang .. ':' .. link |
|||
end |
|||
end |
|||
end |
end |
||
if not link then |
if not link then |
||
return label |
|||
link = 'd:' .. entity.id |
|||
else |
|||
return '[[' .. link .. '|' .. label .. ']]' |
|||
end |
end |
||
return '[[' .. link .. '|' .. label .. ']]' |
|||
end |
end |
||
function p.formatEntityId( entity, args ) |
|||
local entity = getEntityFromId(entity) |
|||
local label = p._getLabel(entity, args.lang) |
|||
return formattedLabel(label, entity, args) |
|||
end |
|||
function p.getmainid(claim) |
function p.getmainid(claim) |
||
if claim and claim.mainsnak |
if claim and not isSpecial(claim.mainsnak) then |
||
return 'Q' .. claim.mainsnak.datavalue.value['numeric-id'] |
return 'Q' .. claim.mainsnak.datavalue.value['numeric-id'] |
||
end |
end |
||
return nil |
|||
end |
end |
||
function p.formatEntity( entity, args ) |
function p.formatEntity( entity, args ) |
||
if not entity then |
|||
return nil |
|||
end |
|||
if not args then args = {} end |
|||
if type(entity) == 'string' then |
if type(entity) == 'string' then |
||
entity = |
entity = p.getEntity(entity) |
||
end |
end |
||
local label = p._getLabel(entity, args.lang) |
|||
if not label then |
|||
return formattedLabel(label, entity, args) |
|||
label = entity.id |
|||
end |
|||
return formattedLabel(label, entity, args) |
|||
end |
end |
||
function p.getLabel(frame) -- simple for simple templates like {{Q|}}} |
function p.getLabel(frame) -- simple for simple templates like {{Q|}}} |
||
local args = frame.args |
local args = frame.args |
||
local entity = args.entity |
|||
local lang = args.lang |
|||
if lang == '' then |
|||
lang = defaultlang |
|||
lang = frame:preprocess('{{int:lang}}') |
|||
end |
|||
if string.sub(entity, 1, 10) == 'Property:P' then |
|||
if string.sub(entity, 1, 10) == 'Property:P' then |
|||
entity = string.sub(entity, 10) |
|||
elseif (string.sub(entity, 1, 1) ~= 'P' and string.sub(entity, 1, 1) ~= 'Q') or (not tonumber(string.sub(entity, 2))) then |
|||
return i18n('invalid-id') |
|||
end |
|||
if not args.link or args.link == '' then -- by default: no link |
|||
if not args.link or args.link == '' then -- by default: no link |
|||
args.link = '-' |
|||
end |
|||
end |
|||
if args.link == '-' then |
|||
if args.link == '-' then |
|||
return p._getLabel(entity, lang) or i18n.errors['invalid-id'] |
|||
return p._getLabel(entity, lang) or i18n('invalid-id') |
|||
else |
|||
else |
|||
args.lang = lang |
|||
return p.formatEntity(entity, args) |
|||
end |
|||
end |
end |
||
function p. |
function p._formatStatements( args )--Format statements and concat them cleanly |
||
if args.value == '-' then |
|||
local entity = frame.args.entity |
|||
return nil |
|||
local lang = frame.args.lang |
|||
end |
|||
if not lang or lang == '' then |
|||
--If a value is already set, use it |
|||
lang = frame:preprocess('{{int:lang}}') |
|||
if args.value and args.value ~= '' then |
|||
end |
|||
return args.value |
|||
if (string.sub(entity, 1, 1) ~= 'P' and string.sub(entity, 1, 1) ~= 'Q') or (not tonumber(string.sub(entity, 2))) then |
|||
end |
|||
return i18n.errors['invalid-id'] |
|||
local valuetable = p.stringTable(args) |
|||
end |
|||
return tableToText(valuetable, args) |
|||
return p._getDescription(entity, lang) or i18n.errors['invalid-id'] |
|||
end |
end |
||
function p. |
function p.showQualifier( args ) |
||
local qualifs = args.qualifiers or args.qualifier |
|||
return p.formatStatements(args) |
|||
if type(qualifs) == 'string' then |
|||
qualifs = mw.text.split(qualifs, ',') |
|||
end |
|||
if not qualifs then |
|||
return formatError( 'property-param-not-provided' ) |
|||
end |
|||
local claims = p.getClaims(args) |
|||
if not claims then |
|||
return nil |
|||
end |
|||
local str = '' |
|||
for i, j in pairs(claims) do |
|||
local new = p.getFormattedQualifiers(j, qualifs, args) or '' |
|||
str = str .. new |
|||
end |
|||
return str |
|||
end |
end |
||
function p. |
function p._formatAndCat(args) |
||
local val = p._formatStatements(args) |
|||
local args = frame.args -- parameters not provided directly in the calling template, to avoid update issues |
|||
if val then |
|||
return val .. addTrackingCat(args.property) |
|||
args = frame:getParent().args |
|||
end |
|||
return nil |
|||
end |
|||
function p.getTheDate(args) |
|||
if (not args.item) or (args.item == '') then |
|||
local claims = p.getClaims(args) |
|||
return "no item given" |
|||
if not claims then |
|||
return nil |
|||
end |
end |
||
local formattedvalues = {} |
|||
if (not args.property) or (args.property == '') then |
|||
for i, j in pairs(claims) do |
|||
return "no property given" |
|||
table.insert(formattedvalues, p.getFormattedDate(j)) |
|||
end |
end |
||
local val = linguistic.conj(formattedvalues) |
|||
if not args.lang then |
|||
if val and args.addcat == true then |
|||
args.lang = frame:preprocess('{{int:lang}}') |
|||
return val .. addTrackingCat(args.property) |
|||
end |
|||
else |
|||
return p.formatStatements( args ) |
|||
return val |
|||
end |
|||
end |
|||
---FONCTIONS depuis le FRAME |
|||
function p.getaDate(frame) |
|||
return p.getTheDate(frame.args) |
|||
end |
|||
function p.getQualifier(frame) |
|||
return p.showQualifier(frame.args) |
|||
end |
|||
function p.getDescription(frame) -- simple for simple templates like {{Q|}}} |
|||
local entity = frame.args.entity |
|||
local lang = frame.args.lang |
|||
return p._getDescription(entity, lang) or i18n('invalid-id') |
|||
end |
|||
function p.formatStatements( args ) |
|||
return p._formatStatements( args ) |
|||
end |
|||
function p.formatStatementsE(frame) |
|||
local args = {} |
|||
if frame == mw.getCurrentFrame() then |
|||
args = frame:getParent().args -- paramètres du modèle appelant (est-ce vraiment une bonne idée ?) |
|||
for k, v in pairs(frame.args) do |
|||
args[k] = v |
|||
end |
|||
else |
|||
args = frame |
|||
end |
|||
return p._formatStatements( args ) |
|||
end |
|||
function p.formatAndCat(frame) |
|||
local args = {} |
|||
if frame == mw.getCurrentFrame() then |
|||
args = frame:getParent().args -- paramètres du modèle appelant (est-ce vraiment une bonne idée ?) |
|||
for k, v in pairs(frame.args) do |
|||
args[k] = v |
|||
end |
|||
else |
|||
args = frame |
|||
end |
|||
return p._formatAndCat( args ) |
|||
end |
|||
function p.getEntityFromId(id) |
|||
return p.getEntity(id) |
|||
end |
end |
||
Revision as of 14:23, 27 April 2016
Lua
CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules
Module permitting basic data retrieval from Wikidata items, based on mw:Extension:Wikibase Client/Lua
Functions callable from Lua
p.getClaims returns claims in a particular item that match a particular query
- item (required): its Qid
- property (required) property that the claims should have
- qualifier = qualifiers that the statement should have
- withrank = rank of the statement ; 'preferred', 'normal', 'deprecated' or 'valid' (ie. normal and preferred). By default = preferred.
- sourceproperty = this property should be used in the source
- withsource = the source that should be provided in the statement (if sourceproperty is not provided, the property used is stated in (P248))
- excludespecial = set to true if you do not want to get "novalue" and "somevalue".
- numval = if you want to set a maximum number of values to be returned
- sorttype = set to "chronological" to get the statements in chronological order using the start time (P580), end time (P582) and point in time (P585) qualifiers. Set to "inverted" for chronological order. From a Lua module, you can also define your own sorting criteria.
- showsource = set to "true" if you want the source of the statement to be displayed.
p.formatStatements(args): returns a string containing the statements given in the table args. Same keys as getClaims, plus formatting arguments:
- lang (required) for the desired language
- displayformat = the format in which the args should be returned. For example, for a string-type property displayformat = "weblink" returns a formatted weblink.
- conjtype = the conjunction separating the statements. For example, conj = '<br />' will make a new line between each statement.
- showqualifiers = the qualifiers that should be shown along with the mainsnak value
p.getLabel get the label of an entity
- entity = entity ID with its Q or P
- lang
Functions callable from wikitext
- p.formatStatementsE same as p.formatStatements, except that "lang" is not required. It is most conveniently used from {{Data}} that takes exactly the same arguments.
Examples
Code | Render | Comment |
---|---|---|
{{#invoke:Wikidata|pageId}} | Script error: The function "pageId" does not exist. | return wikidata q-code for pages connected to wikidata |
{{#invoke:Wikidata|getLabel|entity=Q42|link=wikipedia}} | Douglas Adams | link to wikipedia |
{{#invoke:Wikidata|getLabel|entity=Q42|link=wikipedia|format=lc}} | Douglas Adams | link to wikipedia but shown with lower case |
{{#invoke:Wikidata|getLabel|entity=Q42|link=-}} | Douglas Adams | no links |
{{#invoke:Wikidata|getLabel|entity=Q42|link=wikipedia|lang=ja}} | ダグラス・アダムズ | |
{{#invoke:Wikidata|getLabel|entity=Q42|link=wikidata}} | Douglas Adams | link to wikidata |
{{#invoke:Wikidata|getLabel|entity=Q42|link=wikidata|lang=ja}} | ダグラス・アダムズ | |
{{#invoke:Wikidata|getDescription|entity=Q42|link=wikidata|lang=fr}} | écrivain de science-fiction et humoriste anglais (1952–2001) | |
{{#invoke:Wikidata|formatStatementsE|item=Q42|property=p31}} | human | |
{{#invoke:Wikidata|formatStatementsE|item=Q42|property=p31|link=-}} | human | |
{{#invoke:Wikidata|formatStatementsE|item=Q42|property=p31|lang=ja}} | ヒト | |
{{#invoke:Wikidata|formatStatementsE|item=Q42|property=p569}} | ||
{{#invoke:Wikidata|formatStatementsE|item=Q42|property=p569|lang=ja}} | ||
{{#invoke:Wikidata|formatStatementsE|item=Q12418|property=p186}} | oil paint and poplar panel | |
{{#invoke:Wikidata|formatStatementsE|item=Q12418|property=p186|link=-}} | oil paint and poplar panel | |
{{#invoke:Wikidata|formatStatementsE|item=Q12418|property=p186|displayformat=raw}} | Q296955 and Q106857865 | |
{{#invoke:Wikidata|formatStatementsE|item=Q12418|property=p186|lang=ja}} | 油絵具およびポプラ板 | |
{{#invoke:Wikidata|formatStatementsE|item=Q12418|property=p186|rank=valid}} | oil paint, poplar panel and wood | rank = "valid" accepts both "preferred" and "normal" values |
{{#invoke:Wikidata|formatStatementsE|item=Q12418|property=p186|showqualifiers=p518}} | Lua error in Module:Linguistic at line 111: variable 'lang' is not declared. | shows the value of the p518 qualifier (if any) in addition to the main value |
{{#invoke:Wikidata|formatStatementsE|item=Q83259|property=p669|showqualifiers=p670|delimiter= }} | shows the value of the P670 qualifier (if any) in addition to the main value separated by a space | |
{{#invoke:Wikidata|formatStatementsE|item=Q12418|property=p186|qualifier=p518}} | poplar panel | should only display values that have a p518 qualifier |
{{#invoke:Wikidata|formatStatementsE|item=Q12418|property=p186|numval=1}} | oil paint | returns the number of values numval (priority to those with "rank= preferred", if there are not enough of them, also accepts "rank = normal") |
{{#invoke:Wikidata|formatStatementsE|item=Q12418|property=P276|sourceproperty=P854}} | Salle des États, Louvre | |
{{#invoke:Wikidata|formatStatementsE|item=Q11879536|property=P460|withsource=Q1645493}} | Lisa del Giocondo | |
{{#invoke:Wikidata|formatStatementsE|item=Q153|property=P231|showsource=true}} | Lua error in Module:Fallback at line 62: attempt to call method 'lower' (a nil value). | |
{{#invoke:Wikidata|formatStatementsE|item=Q205309|property=P793|sorttype=inverted}} | closure, demolition, renovation, renovation, first match and construction | |
{{#invoke:Wikidata|formatStatementsE|property=P625|item=Q90|displayformat=latitude}} | 48.856666666667 | Latitude of Paris |
{{#invoke:Wikidata|formatStatementsE|property=P19|item=Q1441042}} | Lua error at line 19: attempt to call field '_langSwitch' (a nil value). | unknown value |
{{#invoke:Wikidata|formatStatementsE|property=P19|item=Q43650835}} | Lua error at line 19: attempt to call field '_langSwitch' (a nil value). | no value |
Code
--script that retrieves basic data stored in Wikidata, for the datamodel, see https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua
local p = {}
local linguistic = require('Module:Linguistic')
--local formatDate = require('Module:Complex date') only loaded when needed to save memory in large pages like Wikidata:List of properties/all
local fb = require('Module:Fallback')
local i18nmessages = mw.loadData('Module:i18n/wikidata')
-- Wiki-specific parameters
local defaultlang = mw.getCurrentFrame():preprocess("{{int:lang}}")
local defaultlink = 'wikidata'
local function i18n(str, lang)
local message = i18nmessages[str]
if type(message) == 'string' then
return message
end
return fb._langSwitch(message, lang or defaultlang)
end
local function formatError( key, text )
return error(i18n(key) .. (text or ''))
end
local function addTrackingCat(prop, cat)
if not prop and not cat then
return error("no property provided")
end
if not cat then
cat = i18nmessages.trackingcat .. '/' .. string.upper(prop)
end
return '[[Category:' .. cat .. ']]'
end
local function removeBlanks(args)
for i, j in pairs(args) do -- does not work ??
if (j == '') or (j == '-') then args[i] = nil end
end
return args
end
local function formatTheUnknown() -- voir si on peut accorder/adapter l'usage de "inconnu"
return i18n('somevalue')
end
local function isSpecial(snak)
return snak.snaktype ~= 'value'
end
local function sameValue(snak, target)
return not isSpecial(snak) and p.getRawvalue(snak) == target
end
local function showLang(statement, str) -- TODO (not yet in proper format)
--adds a lang indication at the start of the string, based on data in statement
local mainsnak = statement.mainsnak
if isSpecial(mainsnak) then
return str
end
local langlist = {}
if mainsnak.datavalue.type == 'monolingualtext' then
langlist = {mainsnak.datavalue.value.language}
elseif statement.qualifiers and statement.qualifiers.P407 then
local convertlangcode = mw.loadData('Module:Dictionary/lang codes')
for i, j in pairs( statement.qualifiers.P407 ) do
if not isSpecial(j) then
local val = convertlangcode[j.datavalue.value['numeric-id']]
table.insert(langlist, val)
end
end
end
if #langlist == 0 then
return str
else
return '('.. table.concat(langlist) .. ')' .. str
end
end
function p.getEntity( val )
if type(val) == 'table' then
return val
end
return mw.wikibase.getEntityObject(val)
end
-- DATE FUNCTIONS
local function splitTimestamp(timestamp, calendar)
local pattern = "(%W)(%d+)%-(%d+)%-(%d+)"
local era, year, month, day = timestamp:match(pattern)
if calendar == 'julian' then
--todo year, month, day = formatdate.gregorianToJulian( era .. year, month, day )
end
return {day = day, month = month, year = year, era = era, timestamp = timestamp, type = 'dateobject'}
end
local function rangeObject(begin, ending)
local timestamp
if begin then
timestamp = begin.timestamp
elseif ending then
timestamp = ending.timestamp
end
return {begin = begin, ending = ending, timestamp = timestamp, type = 'rangeobject'}
end
local function dateObject(orig, params) -- transforme un snak en un nouvel objet utilisable par Module:Date complexe
if not params then
params = {}
end
local newobj = splitTimestamp(orig.time, orig.calendar) -- initalise l'object en mettant la valeur des dates
newobj.precision = params.precision or orig.precision
newobj.type = 'dateobject'
return newobj
end
local function formatDatepoint(obj, params) -- TO IMPROVE
if not obj then
return nil
end
local formatDate = require('Module:Complex date')
local lang = params.lang or defaultlang
local precision = math.min(obj.precision, params.precision or 15) -- if we don't want to show the value to its full detail
if precision >= 11 then
return formatDate.complex_date{args={date1 = obj.year .. '-' .. obj.month .. '-' .. obj.day, lang= lang}}
elseif precision == 10 then
return formatDate.complex_date{args={date1 = obj.year .. '-' .. obj.month, lang= lang}}
elseif precision == 9 then
return formatDate.complex_date{args={date1 = tostring(obj.year), lang= lang}}
elseif precision == 8 then
return formatDate.complex_date{args={date1 = string.sub(tostring(obj.year), 1, 3) .. '0', lang = lang, precision = 'decade'}}
elseif precision == 7 then
return formatDate.complex_date{args={date1 = string.sub(tostring(obj.year + 100), 1, 2), lang = lang, precision = 'century'}}
end
return nil
end
local function formatDaterange(obj, params) --TODO
local begin = formatDatepoint(obj.begin, params) or ''
local ending = formatDatepoint(obj.ending, params) or ''
return begin .. '-' .. ending
end
local function objectToText(obj, params)
if obj.type == 'dateobject' then
return formatDatepoint(obj, params)
elseif obj.type == 'rangeobject' then
return formatDaterange(obj, params)
end
return nil
end
local function tableToText(values, params) -- takes a list of already formatted values and make them a text
if not values then
return nil
end
return linguistic.conj(values, params.lang or defaultlang, params.conjtype)--linguistic.conj( values, params.lang, params.conjtype )
end
function p.getDate(obj)
--[[
returns an object containing a timestamp for easy sorting, and other data
possible types of object:
dateobject
{timestamp = string, year = number, month = number, day = number, calendar = string}
rangeobject
{timestamp = string, begin = dateobject, ending = dateobject}
]]--
if not obj then
return nil
end
if type(obj) == 'string' then
obj = p.getEntity(obj)
end
-- if obj is a statement with date, get it
if obj.mainsnak and not isSpecial(obj.mainsnak) and obj.mainsnak.datatype == 'time' then
return dateObject(obj.mainsnak.datavalue.value.time)
end
-- else preload relevant data
local qualifs = obj.qualifiers -- when obj is a statement, look in qualifiers
local claims = obj.claims -- when obj is an item, look in claims
local pointprop = {'P585', 'P571'} -- dates corresponding to a punctual fact
local beginprop = {'P580', 'P569'} -- start date, birth date == start of a date range
local endingprop = {'P582', 'P570'}
local function getval(prop)
local val
if claims and claims[prop] and not isSpecial(claims[prop][1].mainsnak) then
val = claims[prop][1].mainsnak.datavalue.value
elseif qualifs and qualifs[prop] and not isSpecial(qualifs[prop][1]) then
val = qualifs[prop][1].datavalue.value
end
if val then
return dateObject(val)
end
return nil
end
for i, prop in pairs(pointprop) do
local val = getval(prop)
if val then return val end
end
--if no date has not been found, look for startdate or enddate
local begin, ending
for i, prop in pairs(beginprop) do
begin = getval(prop)
if begin then
break
end
end
for i, prop in pairs(endingprop) do
ending = getval(prop)
if ending then
break
end
end
if begin or ending then
return rangeObject(begin, ending)
end
return nil
end
function p.getFormattedDate(statement, params)
local datetable = p.getDate(statement)
if not datetable then
return nil
end
return objectToText(datetable, params)
end
local function hasTargetValue(claim, target)
if target == nil then
return true
end
return sameValue(claim.mainsnak, target)
end
local function hasRank(claim, target)
if target == 'valid' then
return hasRank(claim, 'preferred') or hasRank(claim, 'normal')
else
return claim.rank == target
end
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
local function hasQualifier(claim, qualifier, qualifiervalues)
if not qualifier then -- si aucun qualificatif est demandé, ça passe
return true
end
qualifier = string.upper(qualifier)
if not claim.qualifiers or not claim.qualifiers[qualifier] then
return false
end
if type(qualifiervalues) == 'string' then
qualifiervalues = mw.text.split(qualifiervalues, ',')
end
if (not qualifiervalues) or (qualifiervalues == {}) then
return true -- si aucune valeur spécifique n'est exigée
end
for i, j in pairs(claim.qualifiers[qualifier]) do
for k, l in pairs(qualifiervalues) do
if p.getRawvalue(j) == l then
return true
end
end
end
return false
end
local function hasSource(statement, source, sourceproperty)
if not statement.references then
return false
end
sourceproperty = string.upper(sourceproperty or 'P248')
local sourcevalue = string.upper(source or '')
for i, ref in pairs(statement.references) do
for prop, content in pairs(ref.snaks) do
if prop == sourceproperty then
if sourcevalue == '' then
return true
else
for j, k in pairs(content) do
if p.getRawvalue(k) == source then
return true
end
end
end
end
end
end
return false
end
local function hasDate(statement)
if not statement.qualifiers then
return false
end
local dateprops = {'P580', 'P585', 'P582'}
for i, prop in pairs(dateprops) do
if statement.qualifiers[prop] then
return true
end
end
return false
end
local function isInLanguage(snak, lang) -- ne fonctionne que pour les monolingualtext / étendre aux autres types en utilisant les qualifiers ?
return not isSpecial(snak) and snak.datavalue.type == 'monolingualtext' and snak.datavalue.value.language == lang
end
local function numval(claims, numval) -- retourn les numval premières valeurs de la table claims
local numval = tonumber(numval) or 0 -- raise a error if numval is not a positive integer ?
if #claims <= numval then
return claims
end
local newclaims = {}
while #newclaims < numval do
table.insert(newclaims, claims[#newclaims + 1])
end
return newclaims
end
function p.comparedate(a, b) -- returns true if a is earlier than B or if a has a date but not b
if a and b then
return a.timestamp < b.timestamp
elseif a then
return true
end
return false
end
function p.chronosort(objs, inverted)
table.sort(objs, function(a, b)
local timeA = p.getDate(a)
local timeB = p.getDate(b)
if inverted then
return p.comparedate(timeB, timeA)
else
return p.comparedate(timeA, timeB)
end
end)
return objs
end
function p.sortclaims(claims, sorttype)
if type(sorttype) == 'function' then
table.sort(claims, sorttype)
elseif sorttype == 'chronological' then
return p.chronosort(claims)
elseif sorttype == 'inverted' then
return p.chronosort(claims, true)
end
return claims
end
function p.getRawvalue(snak)
return p.getDatavalue(snak, {displayformat = 'raw'})
end
function p.showentity(entity, lang)
if not entity then
return nil
end
if type(entity) == 'string' then
entity = p.getEntity(entity)
end
if not entity or not entity.type then
return formatError('entity-not-found')
end
local label = p._getLabel(entity, lang)
local id = entity.id
local link = id
if entity.type == 'property' then
link = 'Property:' .. link
end
return '[[' .. link .. '|' .. label .. ']] <small>(' .. id .. ')</small>'
end
function p.getDatavalue(snak, params)
if isSpecial(snak) then
return nil
end
if not params then
params = {}
end
local displayformat = params.displayformat
local datatype = snak.datavalue.type
local value = snak.datavalue.value
if datatype == 'wikibase-entityid' then
if type(displayformat) == 'function' then
return displayformat(snak, params)
end
local prefix = 'Q'
if snak.datavalue.value["entity-type"] == 'property' then
prefix = 'P'
end
local id = prefix .. tostring(value['numeric-id'])
if displayformat == 'raw' then
return id
elseif displayformat == 'wikidatastyle' then
return p.showentity(id, params.lang)
else
return p.formatEntity(id, params)
end
elseif datatype == 'string' then
local showntext = params.showntext
if displayformat == 'weblink' then
if showntext then
return '[' .. value .. ' ' .. showntext .. ']'
else
return value
end
end
if snak.datatype == 'math' and displayformat ~= 'raw' then
value = mw.getCurrentFrame():extensionTag('math', value)
end
if params.urlpattern then
value = '[' .. mw.ustring.gsub(mw.ustring.gsub(params.urlpattern, '$1', value), ' ', '%%20') .. ' ' .. (showntext or value) .. ']'
end
return value
elseif datatype == 'time' then -- format example: +00000001809-02-12T00:00:00Z
if displayformat == 'raw' then
return value.time
else
return objectToText(dateObject(value), params)
end
elseif datatype == 'globecoordinate' then
-- retourne une table avec clés latitude, longitude, précision et globe à formater par un autre module (à changer ?)
if displayformat == 'latitude' then
return value.latitude
elseif displayformat == 'longitude' then
return value.longitude
elseif displayformat == 'qualifier' then
local coord = require 'Module:Coordinates'
value.globe = require('Module:Wikidata/Globes')[value.globe]
value.precision = nil
return coord._coord(value)
else
value.globe = require('Module:Wikidata/Globes')[value.globe] -- transforme l'ID du globe en nom anglais utilisable par geohack
return value -- note : les coordonnées Wikidata peuvent être utilisée depuis Module:Coordinates. Faut-il aussi autoriser à appeler Module:Coordiantes ici ?
end
elseif datatype == 'quantity' then -- todo : gérer les paramètre précision
if displayformat == 'raw' then
return tonumber(value.amount)
else
local formatNum = require 'Module:Formatnum'
local number = formatNum.formatNum(value.amount)
local unit = mw.ustring.match(value.unit, '(Q%d+)')
if unit then
number = number .. ' ' .. p.formatEntity(unit, params)
end
return number
end
elseif datatype == 'monolingualtext' then
return '<span lang="' .. value.language .. '">' .. value.text .. '</span>'
else
return formatError( 'unknown-datavalue-type', datatype )
end
end
local function getMultipleClaims(args)
local newargs = args
local claims = {}
for i, j in pairs(args.property) do
newargs.property = j
local newclaims = p.getClaims(args)
if newclaims then
for k, l in pairs(newclaims) do
table.insert(claims, l)
end
end
end
return claims
end
function p.getClaims( args ) -- returns a table of the claims matching some conditions given in args
args = removeBlanks(args)
if not args.property then
return formatError( 'property-param-not-provided' )
end
if type(args.property) == 'table' then
return getMultipleClaims(args)
end
--Get entity
if args.item then -- synonyms
args.entity = args.item
end
local entity = args.entity
if type(entity) ~= 'table' then
entity = p.getEntity(entity)
end
local property = string.upper(args.property)
if not entity or not entity.claims or not entity.claims[property] then
return nil
end
if not args.rank then
args.rank = 'best'
end
local claims = {}
-- ~= '' lorsque le paramètre est écrit mais laissé blanc dans une fonction frame
for i, statement in pairs(entity.claims[property]) do
if
(
not args.excludespecial
or
not (isSpecial(statement.mainsnak))
)
and
(
not args.targetvalue
or
hasTargetValue(statement, args.targetvalue)
)
and
(
not args.qualifier
or
hasQualifier(statement, args.qualifier, args.qualifiervalues or args.qualifiervalue)
)
and
(
not args.withsource or args.withsource == '-'
or
hasSource(statement, args.withsource, args.sourceproperty)
)
and
(
not args.isinlanguage
or
isInLanguage(statement.mainsnak, args.isinlanguage)
)
and
(
args.rank == 'best' -- rank == best est traité à a fin
or
hasRank(statement, args.rank)
)
then
table.insert(claims, statement)
end
end
if #claims == 0 then
return nil
end
if args.rank == 'best' then
claims = bestRanked(claims)
end
if args.sorttype then
claims = p.sortclaims(claims, args.sorttype)
end
if args.numval then
return numval(claims, args.numval)
end
return claims
end
function p.formatClaimList(claims, args)
if not claims then
return nil
end
for i, j in pairs(claims) do
claims[i] = p.formatStatement(j, args)
end
return claims
end
function p.stringTable(args) -- like getClaims, but get a list of string rather than a list of snaks, for easier manipulation
local claims = p.getClaims(args)
return p.formatClaimList(claims, args)
end
local function getQualifiers(statement, qualifs, params)
if not statement.qualifiers then
return nil
end
local vals = {}
for i, j in pairs(qualifs) do
j = string.upper(j)
if statement.qualifiers[j] then
local inserted = false
if statement.qualifiers[j][1].datatype == 'monolingualtext' then
local in_preferred_lang
for _, language in pairs(fb.fblist(params.lang or defaultlang)) do
for _, snak in pairs(statement.qualifiers[j]) do
if isInLanguage(snak, language) then
in_preferred_lang = snak
break
end
end
if in_preferred_lang then
break
end
end
if in_preferred_lang then
table.insert(vals, in_preferred_lang)
inserted = true
end
end
if not inserted then
for _, snak in pairs(statement.qualifiers[j]) do
table.insert(vals, snak)
end
end
end
end
if #vals == 0 then
return nil
end
return vals
end
function p.getFormattedQualifiers(statement, qualifs, params)
if not params then params = {} end
local qualiftable = getQualifiers(statement, qualifs, params)
if not qualiftable then
return nil
end
for i, j in pairs(qualiftable) do
local params = params
if j.datatype == 'globe-coordinate' then
params.displayformat = 'qualifier'
end
qualiftable[i] = p.formatSnak(j, params)
end
return linguistic.conj(qualiftable, params.lang or defaultlang)
end
function p.formatStatement( statement, args )
if not statement.type or statement.type ~= 'statement' then
return formatError( 'unknown-claim-type', statement.type )
end
if not args then args = {} end
local lang = args.lang or defaultlang
local str = p.formatSnak( statement.mainsnak, args )
if args.showlang == true then
str = showLang(statement, str)
end
local qualifs = args.showqualifiers
if qualifs then
if type(qualifs) == 'string' then
qualifs = mw.text.split(qualifs, ',')
end
local foundvalues = p.getFormattedQualifiers(statement, qualifs, args)
if foundvalues then
if args.delimiter then
str = str .. args.delimiter .. foundvalues
else
str = str .. linguistic.inparentheses(foundvalues, lang)
end
end
end
if args.showdate then -- when "showdate and p.chronosort are both set, date retrieval is performed twice
local timedata = p.getDate(statement)
if timedata then
local formatteddate = objectToText(timedata, args)
formatteddate = linguistic.inparentheses(formatteddate, lang)
str = str .. '<small>' .. formatteddate ..'</small>'
end
end
if args.showsource and statement.references then
local cite = require 'Module:Cite'
local frame = mw.getCurrentFrame()
local sourcestring = ''
for i, ref in pairs(statement.references) do
if ref.snaks.P248 then
for j, source in pairs(ref.snaks.P248) do
if not isSpecial(source) then
local page
if ref.snaks.P304 and not isSpecial(ref.snaks.P304[1]) then
page = ref.snaks.P304[1].datavalue.value
end
local s = cite.citeitem('Q' .. source.datavalue.value['numeric-id'], lang, page)
s = frame:extensionTag( 'ref', s )
sourcestring = sourcestring .. s
end
end
elseif ref.snaks.P854 and not isSpecial(ref.snaks.P854[1]) then
s = frame:extensionTag( 'ref', p.getDatavalue(ref.snaks.P854[1]) )
sourcestring = sourcestring .. s
end
end
str = str .. sourcestring
end
return str
end
function p.formatSnak(snak, params)
--local params = params or {} pour faciliter l'appel depuis d'autres modules
if snak.snaktype == 'value' then
return p.getDatavalue(snak, params)
elseif snak.snaktype == 'somevalue' then
return formatTheUnknown()
elseif snak.snaktype == 'novalue' then
return i18n('novalue') --todo
else
return formatError( 'unknown-snak-type', snak.snaktype )
end
end
local function defaultLabel(entity, lang, displayformat) -- label when no label is available
if entity and displayformat == 'id' then
return entity.id
end
return i18n('no-label', lang)
end
function p._getLabel(entity, lang, default)
if not entity then
return nil
end
if type(entity) ~= 'table' then
entity = p.getEntity(entity)
end
if entity and entity.labels then
for i, lg in pairs(fb.fblist(lang or defaultlang)) do
if entity.labels[lg] then
return entity.labels[lg].value
end
end
end
return defaultLabel(entity, lang, default)
end
function p._getDescription(entity, lang)
if not entity then
return i18n('no description')
end
if type(entity) ~= 'table' then
entity = p.getEntity(entity)
end
local descriptions = entity.descriptions
if not descriptions then
return i18n('no description')
end
if descriptions[lang] then
return descriptions[lang].value
end
local langlist = fb.fblist(lang or defaultlang) -- list of fallback languages if no label in the desired language
for i, lg in pairs(langlist) do
if descriptions[lg] then
return descriptions[lg].value
end
end
return i18n('no description')
end
local function wikipediaLink(entity, lang)
local link = entity:getSitelink(lang .. 'wiki')
if link then
return ':' .. lang .. ':' .. link
end
return nil
end
local function getLink(entity, typelink, lang)
if not typelink or typelink == '-' then
return nil
end
if not lang then
lang = defaultlang
end
if typelink == 'wikidata' then
if entity.type == 'property' then
return 'd:P:' .. entity.id
else
return 'd:' .. entity.id
end
elseif typelink == 'wikipedia' then
return wikipediaLink(entity, lang)
elseif typelink == 'anywikipedia' then
local fallbacklist = fb.fblist(lang)
for i, lg in pairs(fallbacklist) do
link = wikipediaLink(entity, lg)
if link then return link end
end
end
return nil
end
local function formattedLabel(label, entity, args)
if not args then args = {} end
local link = getLink(entity, args.link, args.lang)
if not link then
link = getLink(entity, defaultlink, args.lang)
end
if not link then
return label
else
return '[[' .. link .. '|' .. label .. ']]'
end
end
function p.getmainid(claim)
if claim and not isSpecial(claim.mainsnak) then
return 'Q' .. claim.mainsnak.datavalue.value['numeric-id']
end
return nil
end
function p.formatEntity( entity, args )
if not entity then
return nil
end
if not args then args = {} end
if type(entity) == 'string' then
entity = p.getEntity(entity)
end
local label = p._getLabel(entity, args.lang)
if not label then
label = entity.id
end
return formattedLabel(label, entity, args)
end
function p.getLabel(frame) -- simple for simple templates like {{Q|}}}
local args = frame.args
local entity = args.entity
local lang = args.lang
if lang == '' then
lang = defaultlang
end
if string.sub(entity, 1, 10) == 'Property:P' then
entity = string.sub(entity, 10)
elseif (string.sub(entity, 1, 1) ~= 'P' and string.sub(entity, 1, 1) ~= 'Q') or (not tonumber(string.sub(entity, 2))) then
return i18n('invalid-id')
end
if not args.link or args.link == '' then -- by default: no link
args.link = '-'
end
if args.link == '-' then
return p._getLabel(entity, lang) or i18n('invalid-id')
else
return p.formatEntity(entity, args)
end
end
function p._formatStatements( args )--Format statements and concat them cleanly
if args.value == '-' then
return nil
end
--If a value is already set, use it
if args.value and args.value ~= '' then
return args.value
end
local valuetable = p.stringTable(args)
return tableToText(valuetable, args)
end
function p.showQualifier( args )
local qualifs = args.qualifiers or args.qualifier
if type(qualifs) == 'string' then
qualifs = mw.text.split(qualifs, ',')
end
if not qualifs then
return formatError( 'property-param-not-provided' )
end
local claims = p.getClaims(args)
if not claims then
return nil
end
local str = ''
for i, j in pairs(claims) do
local new = p.getFormattedQualifiers(j, qualifs, args) or ''
str = str .. new
end
return str
end
function p._formatAndCat(args)
local val = p._formatStatements(args)
if val then
return val .. addTrackingCat(args.property)
end
return nil
end
function p.getTheDate(args)
local claims = p.getClaims(args)
if not claims then
return nil
end
local formattedvalues = {}
for i, j in pairs(claims) do
table.insert(formattedvalues, p.getFormattedDate(j))
end
local val = linguistic.conj(formattedvalues)
if val and args.addcat == true then
return val .. addTrackingCat(args.property)
else
return val
end
end
---FONCTIONS depuis le FRAME
function p.getaDate(frame)
return p.getTheDate(frame.args)
end
function p.getQualifier(frame)
return p.showQualifier(frame.args)
end
function p.getDescription(frame) -- simple for simple templates like {{Q|}}}
local entity = frame.args.entity
local lang = frame.args.lang
return p._getDescription(entity, lang) or i18n('invalid-id')
end
function p.formatStatements( args )
return p._formatStatements( args )
end
function p.formatStatementsE(frame)
local args = {}
if frame == mw.getCurrentFrame() then
args = frame:getParent().args -- paramètres du modèle appelant (est-ce vraiment une bonne idée ?)
for k, v in pairs(frame.args) do
args[k] = v
end
else
args = frame
end
return p._formatStatements( args )
end
function p.formatAndCat(frame)
local args = {}
if frame == mw.getCurrentFrame() then
args = frame:getParent().args -- paramètres du modèle appelant (est-ce vraiment une bonne idée ?)
for k, v in pairs(frame.args) do
args[k] = v
end
else
args = frame
end
return p._formatAndCat( args )
end
function p.getEntityFromId(id)
return p.getEntity(id)
end
return p