Module:Wikidata: Difference between revisions
Jump to navigation
Jump to search
Content deleted Content added
return date as a year or Isodate |
fix rendering for snaktype 'somevalue' and 'novalue' |
||
(29 intermediate revisions by 8 users not shown) | |||
Line 4: | Line 4: | ||
local linguistic = require('Module:Linguistic') |
local linguistic = require('Module:Linguistic') |
||
local selectClaims = require('Module:Wikidata/GetClaims') |
|||
--local formatDate = require('Module:Complex date') only loaded when needed to save memory in large pages like Wikidata:List of properties/all |
|||
local tools = require('Module:Wikidata/Tools') |
|||
local entities = require('Module:Wikidata/FormatEntity') |
|||
local dates = require('Module:Wikidata/Dates') |
|||
local weblink = require('Module:Weblink') |
|||
local langSwitch = require('Module:LangSwitch')._langSwitch |
|||
local fb = require('Module:Fallback') |
local fb = require('Module:Fallback') |
||
local i18nmessages = mw.loadData('Module:i18n/wikidata') |
local i18nmessages = mw.loadData('Module:i18n/wikidata') |
||
-- Wiki-specific parameters |
-- Wiki-specific parameters |
||
local defaultlang = mw.getCurrentFrame(): |
local defaultlang = mw.getCurrentFrame():callParserFunction('Int', 'Lang') |
||
local defaultlink = 'wikidata' |
local defaultlink = 'wikidata' |
||
Line 17: | Line 23: | ||
return message |
return message |
||
end |
end |
||
return |
return langSwitch(message, lang or defaultlang) |
||
end |
end |
||
local function formatError( |
local function formatError(key, text) |
||
return error(i18n(key) .. (text or '')) |
return error(i18n(key) .. ' ' .. (text or ''), 2) |
||
end |
end |
||
p.getClaims = selectClaims.getClaims |
|||
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) |
local function removeBlanks(args) |
||
for i |
for i = #args, 1, -1 do |
||
if ( |
if (args[i] == '') or (args[i] == '-') then |
||
table.remove(args, i) |
|||
end |
|||
end |
end |
||
return args |
return args |
||
end |
end |
||
local function getQualifiers(statement, qualifs, params) |
|||
local function formatTheUnknown() -- voir si on peut accorder/adapter l'usage de "inconnu" |
|||
if not statement.qualifiers then |
|||
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 |
return nil |
||
end |
end |
||
if type(qualifs) == 'string' then |
|||
local formatDate = require('Module:Complex date') |
|||
qualifs = mw.text.split(qualifs, ',') |
|||
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 |
||
local vals = {} |
|||
return nil |
|||
for i, j in pairs(qualifs) do |
|||
end |
|||
j = string.upper(j) |
|||
if statement.qualifiers[j] then |
|||
local function formatDaterange(obj, params) --TODO |
|||
local inserted = false |
|||
local begin = formatDatepoint(obj.begin, params) or '' |
|||
if statement.qualifiers[j][1].datatype == 'monolingualtext' then |
|||
local ending = formatDatepoint(obj.ending, params) or '' |
|||
local in_preferred_lang |
|||
return begin .. '-' .. ending |
|||
for _, language in pairs(fb.fblist(params.lang or defaultlang)) do |
|||
end |
|||
for _, snak in pairs(statement.qualifiers[j]) do |
|||
if isInLanguage(snak, language) then |
|||
local function objectToText(obj, params) |
|||
in_preferred_lang = snak |
|||
if obj.type == 'dateobject' then |
|||
break |
|||
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 |
||
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 |
||
end |
end |
||
if #vals == 0 then |
|||
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 |
return nil |
||
end |
end |
||
return vals |
|||
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. |
function p.formatSnak(snak, params) |
||
-- special values: 'novalue' and 'somevalue' |
|||
if isSpecial(snak) then |
|||
local datatype = snak.datatype |
|||
return nil |
|||
if snak.snaktype == 'somevalue' then |
|||
return i18n('somevalue') |
|||
elseif snak.snaktype == 'novalue' then |
|||
return i18n('novalue') |
|||
end |
end |
||
local value = snak.datavalue.value |
|||
-- user-defined displayformat |
|||
if not params then |
|||
params = {} |
|||
end |
|||
local displayformat = params.displayformat |
local displayformat = params.displayformat |
||
if type(displayformat) == 'function' then |
|||
local datatype = snak.datavalue.type |
|||
return displayformat(snak, params) |
|||
local value = snak.datavalue.value |
|||
end |
|||
if datatype == 'wikibase- |
if datatype == 'wikibase-item' or datatype == 'wikibase-property' then |
||
return entities.formatEntity(tools.getId(snak), params) |
|||
if type(displayformat) == 'function' then |
|||
elseif datatype == 'url' then |
|||
return displayformat(snak, params) |
|||
return weblink.makelink(value, params.text, params.displayformat) |
|||
end |
|||
elseif datatype == 'math' then |
|||
local prefix = 'Q' |
|||
return mw.getCurrentFrame():extensionTag('math', value) |
|||
if snak.datavalue.value["entity-type"] == 'property' then |
|||
elseif datatype == 'string' or datatype == 'external-id' or datatype == 'commonsMedia' then |
|||
prefix = 'P' |
|||
if params.urlpattern then |
|||
end |
|||
local urlpattern = params.urlpattern |
|||
local id = prefix .. tostring(value['numeric-id']) |
|||
if |
if type(urlpattern) == 'function' then |
||
urlpattern = urlpattern(value) |
|||
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 |
||
value = '[' .. mw.ustring.gsub(urlpattern, '$1', value) .. ' ' .. (params.text or value) .. ']' |
|||
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 |
end |
||
return value |
return value |
||
elseif datatype == 'time' then -- format example: +00000001809-02-12T00:00:00Z |
|||
return dates.formatTimeSnak(snak, params) |
|||
elseif datatype == 'time' then -- format example: +1809-02-12T00:00:00Z |
|||
elseif datatype == 'globe-coordinate' then |
|||
-- default return a table with latitude, longitude, precision and globe that can be used by another module |
|||
return value.time |
|||
elseif displayformat == 'year' then |
|||
obj = dateObject(value); |
|||
return obj.year |
|||
elseif displayformat == 'isodate' then |
|||
obj = dateObject(value); |
|||
return obj.year .. '-' .. obj.month .. '-' .. obj.day |
|||
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 |
if displayformat == 'latitude' then |
||
return value.latitude |
return value.latitude |
||
Line 478: | Line 122: | ||
return value.longitude |
return value.longitude |
||
elseif displayformat == 'qualifier' then |
elseif displayformat == 'qualifier' then |
||
local coord = require |
local coord = require('Module:Coordinates') |
||
value.globe = require('Module:Wikidata/Globes')[value.globe] |
value.globe = require('Module:Wikidata/Globes')[value.globe] |
||
value.precision = nil |
value.precision = nil |
||
return coord._coord(value) |
return coord._coord(value) |
||
else |
else |
||
value.globe = require('Module:Wikidata/Globes')[value.globe] -- |
value.globe = require('Module:Wikidata/Globes')[value.globe] -- get English name for geohack |
||
return value |
|||
return value -- note : les coordonnées Wikidata peuvent être utilisée depuis Module:Coordinates. Faut-il aussi autoriser à appeler Module:Coordiantes ici ? |
|||
end |
end |
||
elseif datatype == 'quantity' then |
|||
-- TODO: handle precision parameters |
|||
elseif datatype == 'quantity' then -- todo : gérer les paramètre précision |
|||
if displayformat == 'raw' then |
if displayformat == 'raw' then |
||
return tonumber(value.amount) |
return tonumber(value.amount) |
||
else |
else |
||
local formatNum = require |
local formatNum = require('Module:Formatnum') |
||
local number = formatNum.formatNum(value.amount) |
local number = formatNum.formatNum(value.amount) |
||
local unit = mw.ustring.match(value.unit, '(Q%d+)') |
local unit = mw.ustring.match(value.unit, '(Q%d+)') |
||
if unit then |
if unit then |
||
number = number .. ' ' .. |
number = number .. ' ' .. entities.formatEntity(unit, params) |
||
end |
end |
||
return number |
return number |
||
end |
end |
||
elseif datatype == 'monolingualtext' then |
elseif datatype == 'monolingualtext' then |
||
if displayformat == 'raw' then |
|||
return '<span lang="' .. value.language .. '">' .. value.text .. '</span>' |
|||
-- Don't use HTML |
|||
else |
|||
local byte, char = string.byte, mw.ustring.char |
|||
return formatError( 'unknown-datavalue-type', datatype ) |
|||
local lang = value.language:lower() |
|||
end |
|||
local tag = {} |
|||
end |
|||
table.insert(tag, char(0x2068)) -- U+2068: First Strong Isolate (FSI) |
|||
table.insert(tag, char(0xE0001)) -- U+E0001: Language tag |
|||
local function getMultipleClaims(args) |
|||
for i = 1, #lang do |
|||
local newargs = args |
|||
local b = byte(lang, i) |
|||
if b >= 0x61 and b <= 0x7A or b == 0x2D or b == 0x5F then -- 'a'..'z', '-', '_' |
|||
for i, j in pairs(args.property) do |
|||
table.insert(tag, char(0xE0000 + b)) -- U+E0020..U+E007E: Tag characters (remaps ASCII only) |
|||
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 |
||
table.insert(tag, value.text) |
|||
table.insert(tag, char(0xE007F)) -- U+E007F: Cancel Tag |
|||
table.insert(tag, char(0x2069)) -- U+2069: Pop Directional Isolate (PDI) |
|||
return table.concat(tag) |
|||
else |
|||
return '<bdi lang="' .. value.language .. '">' .. value.text .. '</bdi>' |
|||
end |
end |
||
else |
|||
return formatError('unknown-datavalue-type', datatype ) |
|||
end |
end |
||
if #vals == 0 then |
|||
return nil |
|||
end |
|||
return vals |
|||
end |
end |
||
function p. |
function p.formatStatementQualifiers(statement, qualifs, params) |
||
if not params then params = {} end |
if not params then params = {} end |
||
local qualiftable = getQualifiers(statement, qualifs, params) |
local qualiftable = getQualifiers(statement, qualifs, params) |
||
Line 675: | Line 185: | ||
end |
end |
||
function p.formatStatement( |
function p.formatStatement(statement, args) |
||
if not statement.type or statement.type ~= 'statement' then |
if not statement.type or statement.type ~= 'statement' then |
||
return formatError( |
return formatError('unknown-claim-type', statement.type) |
||
end |
end |
||
if not args then args = {} end |
if not args then args = {} end |
||
local lang = args.lang or defaultlang |
local lang = args.lang or defaultlang |
||
local str = p.formatSnak( |
local str = p.formatSnak(statement.mainsnak, args) |
||
if args.showlang == true then |
|||
str = showLang(statement, str) |
|||
end |
|||
local qualifs = args.showqualifiers |
local qualifs = args.showqualifiers |
||
if qualifs then |
if qualifs then |
||
local qualifStr = p.formatStatementQualifiers(statement, qualifs, args) |
|||
if type(qualifs) == 'string' then |
|||
if qualifStr then |
|||
qualifs = mw.text.split(qualifs, ',') |
|||
end |
|||
local foundvalues = p.getFormattedQualifiers(statement, qualifs, args) |
|||
if foundvalues then |
|||
if args.delimiter then |
if args.delimiter then |
||
str = str .. args.delimiter .. |
str = str .. args.delimiter .. qualifStr |
||
else |
else |
||
str = str .. linguistic.inparentheses( |
-- str = str .. linguistic.inparentheses(qualifStr, lang) |
||
str = str .. ' (' .. qualifStr .. ')' |
|||
end |
end |
||
end |
end |
||
end |
end |
||
if args.showdate then -- when |
if args.showdate then -- when `showdate` and `p.chronosort` are both set, date retrieval is performed twice |
||
local |
local params |
||
local date = dates.getFormattedDate(statement, params) |
|||
if timedata then |
|||
if date then |
|||
local formatteddate = objectToText(timedata, args) |
|||
-- str = str .. ' <small>' .. linguistic.inparentheses(date, lang) .. '</small>' |
|||
str = str .. '<small>' .. |
str = str .. ' <small>(' .. date ..')</small>' |
||
end |
end |
||
end |
end |
||
if args.showsource and statement.references then |
if args.showsource and statement.references then |
||
local cite = require |
local cite = require('Module:Cite') |
||
local frame = mw.getCurrentFrame() |
local frame = mw.getCurrentFrame() |
||
local sourcestring = '' |
local sourcestring = '' |
||
Line 717: | Line 222: | ||
if ref.snaks.P248 then |
if ref.snaks.P248 then |
||
for j, source in pairs(ref.snaks.P248) do |
for j, source in pairs(ref.snaks.P248) do |
||
if not isSpecial(source) then |
if not tools.isSpecial(source) then |
||
local page |
local page |
||
if ref.snaks.P304 and not isSpecial(ref.snaks.P304[1]) then |
if ref.snaks.P304 and not tools.isSpecial(ref.snaks.P304[1]) then |
||
page = ref.snaks.P304[1].datavalue.value |
page = ref.snaks.P304[1].datavalue.value |
||
end |
end |
||
local s = cite.citeitem('Q' .. source.datavalue.value['numeric-id'], lang, page) |
local s = cite.citeitem('Q' .. source.datavalue.value['numeric-id'], lang, page) |
||
s = frame:extensionTag( |
s = frame:extensionTag('ref', s) |
||
sourcestring = sourcestring .. s |
sourcestring = sourcestring .. s |
||
end |
end |
||
end |
end |
||
elseif ref.snaks.P854 and not isSpecial(ref.snaks.P854[1]) then |
elseif ref.snaks.P854 and not tools.isSpecial(ref.snaks.P854[1]) then |
||
s = frame:extensionTag( |
s = frame:extensionTag('ref', p.getDatavalue(ref.snaks.P854[1])) |
||
sourcestring = sourcestring .. s |
sourcestring = sourcestring .. s |
||
end |
end |
||
Line 735: | Line 240: | ||
end |
end |
||
return str |
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 ( (not lang) or (lang == defaultlang) ) and (type(entity) == "string") then |
|||
return mw.wikibase.label(entity) |
|||
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 |
end |
||
Line 781: | Line 246: | ||
return i18n('no description') |
return i18n('no description') |
||
end |
end |
||
if type(entity) |
if type(entity) == 'string' and (not lang or lang == defaultlang) then |
||
return mw.wikibase.description(entity) |
|||
end |
end |
||
entity = mw.wikibase.getEntity(entity) |
|||
local descriptions = entity.descriptions |
local descriptions = entity.descriptions |
||
if not descriptions then |
if not descriptions then |
||
return i18n('no description') |
return i18n('no description') |
||
end |
|||
if descriptions[lang] then |
|||
return descriptions[lang].value |
|||
end |
end |
||
local langlist = fb.fblist(lang or defaultlang) -- list of fallback languages if no label in the desired language |
local langlist = fb.fblist(lang or defaultlang) -- list of fallback languages if no label in the desired language |
||
Line 800: | Line 263: | ||
end |
end |
||
-- == FUNCTIONS HANDLING SEVERAL STATEMENTS === |
|||
local function wikipediaLink(entity, lang) |
|||
local link = entity:getSitelink(lang .. 'wiki') |
|||
if link then |
|||
return ':' .. lang .. ':' .. link |
|||
end |
|||
return nil |
|||
end |
|||
function p.stringTable(args) -- find the relevant claims, and formats them as a list of strings |
|||
local function getLink(entity, typelink, lang) |
|||
-- Get claims |
|||
if not typelink or typelink == '-' then |
|||
local claims = p.getClaims(args) |
|||
if not claims then |
|||
return nil |
return nil |
||
end |
end |
||
-- Define the formatter function |
|||
if not lang then |
|||
local formatterFun = p.formatStatement |
|||
lang = defaultlang |
|||
if args.type == 'date' then |
|||
formatterFun = dates.getFormattedDate |
|||
elseif args.type == 'qualifiers' then |
|||
formatterFun = formatStatementQualifiers |
|||
end |
end |
||
-- Format claims |
|||
for i = #claims, 1, -1 do |
|||
if typelink == 'wikidata' then |
|||
claims[i] = formatterFun(claims[i], args) |
|||
if entity.type == 'property' then |
|||
if not claims[i] then |
|||
return 'd:P:' .. entity.id |
|||
table.remove(claims, i) |
|||
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 |
||
end |
end |
||
return |
return claims |
||
end |
end |
||
function p.formatStatements(args)--Format statements and concat them cleanly |
|||
local function formattedLabel(label, entity, args) |
|||
-- If a value is already set, use it |
|||
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 |
if args.value == '-' then |
||
return nil |
return nil |
||
end |
end |
||
if args.value then |
|||
--If a value is already set, use it |
|||
if args.value and args.value ~= '' then |
|||
return args.value |
return args.value |
||
end |
end |
||
-- Obsolete parameters |
|||
local valuetable = p.stringTable(args) |
|||
if args.item then |
|||
return tableToText(valuetable, args) |
|||
args.entity = args.item |
|||
end |
|||
function p.showQualifier( args ) |
|||
local qualifs = args.qualifiers or args.qualifier |
|||
if type(qualifs) == 'string' then |
|||
qualifs = mw.text.split(qualifs, ',') |
|||
end |
end |
||
local values = p.stringTable(args) -- gets statements, and format each of them |
|||
if not qualifs then |
|||
if not values then |
|||
return formatError( 'property-param-not-provided' ) |
|||
end |
|||
local claims = p.getClaims(args) |
|||
if not claims then |
|||
return nil |
return nil |
||
end |
end |
||
return linguistic.conj(values, args.lang or defaultlang, args.conjtype) -- concatenate them |
|||
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 |
||
-- == FRAME FUNCTIONS == |
|||
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|}}} |
function p.getDescription(frame) -- simple for simple templates like {{Q|}}} |
||
local entity = frame.args.entity |
local entity = frame.args.entity |
||
local lang = frame.args.lang |
local lang = frame.args.lang |
||
return p._getDescription(entity, lang) |
|||
return p._getDescription(entity, lang) or i18n('invalid-id') |
|||
end |
|||
function p.formatStatements( args ) |
|||
return p._formatStatements( args ) |
|||
end |
end |
||
Line 982: | Line 325: | ||
args = frame |
args = frame |
||
end |
end |
||
args = removeBlanks(args) |
|||
return p._formatStatements( args ) |
|||
return p.formatStatements(args) |
|||
end |
end |
||
function p. |
function p._getLabel(entity, args) |
||
return entities.formatEntity(entity, args) |
|||
local args = {} |
|||
end |
|||
if frame == mw.getCurrentFrame() then |
|||
function p.getLabel(frame) -- simple for simple templates like {{Q|}}} |
|||
args = frame:getParent().args -- paramètres du modèle appelant (est-ce vraiment une bonne idée ?) |
|||
local args = removeBlanks(frame.args) |
|||
local entity = args.entity or args[1] |
|||
args[k] = v |
|||
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 |
|||
return entities.formatEntity(entity, args) |
|||
end |
|||
function p._wikidataDate(prop, item, params) |
|||
local claims = p.getClaims{entity = item, property = prop} |
|||
if not claims then |
|||
return nil |
|||
end |
|||
params = params or {} |
|||
local vals = {} |
|||
for i, j in pairs(claims) do |
|||
local v = dates.getFormattedDate(j, params) |
|||
if v then |
|||
table.insert(vals, v) |
|||
end |
end |
||
else |
|||
args = frame |
|||
end |
end |
||
return |
return linguistic.conj(vals, params.conjtype or 'or') |
||
end |
|||
function p.wikidataDate(frame) |
|||
p._wikidataDate(frame.args[property], frame.args[params], frame.args) |
|||
end |
|||
function p._main_date(entity) |
|||
-- First try with P580/P582 |
|||
local startpoint = p._wikidataDate('P580', entity) |
|||
local endpoint = p._wikidataDate('P582', entity) |
|||
if startpoint or endpoint then |
|||
return (startpoint or '') .. ' – ' .. (endpoint or '') |
|||
end |
|||
-- Else use P585 |
|||
return p._wikidataDate('P585', entity) |
|||
end |
|||
function p.main_date(frame) |
|||
return p._main_date(frame.args[1]) |
|||
end |
end |
||
-- returns the page id (Q...) of the current page or nothing of the page is not connected to Wikidata |
|||
function p.getEntityFromId(id) |
|||
function p.pageId(frame) |
|||
return p.getEntity(id) |
|||
local entity = mw.wikibase.getEntityObject() |
|||
return entity and entity.id |
|||
end |
end |
||
Latest revision as of 11:07, 3 May 2021
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}} | Q12069631 | 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}} | oil paint and poplar panel (painting support) | 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}} | 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}} | 64-17-5[1][2][3] | |
{{#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}} | unknown | unknown value |
{{#invoke:Wikidata|formatStatementsE|property=P19|item=Q43650835}} | not applicable | no value |
Code
- ↑ ChEBI (title not provided in Wikidata), European Bioinformatics Institute, Creative Commons Attribution 3.0 Unported
- ↑ Global Substance Registration System (title not provided in Wikidata)
- ↑ CAS Common Chemistry
--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 selectClaims = require('Module:Wikidata/GetClaims')
local tools = require('Module:Wikidata/Tools')
local entities = require('Module:Wikidata/FormatEntity')
local dates = require('Module:Wikidata/Dates')
local weblink = require('Module:Weblink')
local langSwitch = require('Module:LangSwitch')._langSwitch
local fb = require('Module:Fallback')
local i18nmessages = mw.loadData('Module:i18n/wikidata')
-- Wiki-specific parameters
local defaultlang = mw.getCurrentFrame():callParserFunction('Int', 'Lang')
local defaultlink = 'wikidata'
local function i18n(str, lang)
local message = i18nmessages[str]
if type(message) == 'string' then
return message
end
return langSwitch(message, lang or defaultlang)
end
local function formatError(key, text)
return error(i18n(key) .. ' ' .. (text or ''), 2)
end
p.getClaims = selectClaims.getClaims
local function removeBlanks(args)
for i = #args, 1, -1 do
if (args[i] == '') or (args[i] == '-') then
table.remove(args, i)
end
end
return args
end
local function getQualifiers(statement, qualifs, params)
if not statement.qualifiers then
return nil
end
if type(qualifs) == 'string' then
qualifs = mw.text.split(qualifs, ',')
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.formatSnak(snak, params)
-- special values: 'novalue' and 'somevalue'
local datatype = snak.datatype
if snak.snaktype == 'somevalue' then
return i18n('somevalue')
elseif snak.snaktype == 'novalue' then
return i18n('novalue')
end
local value = snak.datavalue.value
-- user-defined displayformat
local displayformat = params.displayformat
if type(displayformat) == 'function' then
return displayformat(snak, params)
end
if datatype == 'wikibase-item' or datatype == 'wikibase-property' then
return entities.formatEntity(tools.getId(snak), params)
elseif datatype == 'url' then
return weblink.makelink(value, params.text, params.displayformat)
elseif datatype == 'math' then
return mw.getCurrentFrame():extensionTag('math', value)
elseif datatype == 'string' or datatype == 'external-id' or datatype == 'commonsMedia' then
if params.urlpattern then
local urlpattern = params.urlpattern
if type(urlpattern) == 'function' then
urlpattern = urlpattern(value)
end
value = '[' .. mw.ustring.gsub(urlpattern, '$1', value) .. ' ' .. (params.text or value) .. ']'
end
return value
elseif datatype == 'time' then -- format example: +00000001809-02-12T00:00:00Z
return dates.formatTimeSnak(snak, params)
elseif datatype == 'globe-coordinate' then
-- default return a table with latitude, longitude, precision and globe that can be used by another module
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] -- get English name for geohack
return value
end
elseif datatype == 'quantity' then
-- TODO: handle precision parameters
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 .. ' ' .. entities.formatEntity(unit, params)
end
return number
end
elseif datatype == 'monolingualtext' then
if displayformat == 'raw' then
-- Don't use HTML
local byte, char = string.byte, mw.ustring.char
local lang = value.language:lower()
local tag = {}
table.insert(tag, char(0x2068)) -- U+2068: First Strong Isolate (FSI)
table.insert(tag, char(0xE0001)) -- U+E0001: Language tag
for i = 1, #lang do
local b = byte(lang, i)
if b >= 0x61 and b <= 0x7A or b == 0x2D or b == 0x5F then -- 'a'..'z', '-', '_'
table.insert(tag, char(0xE0000 + b)) -- U+E0020..U+E007E: Tag characters (remaps ASCII only)
end
end
table.insert(tag, value.text)
table.insert(tag, char(0xE007F)) -- U+E007F: Cancel Tag
table.insert(tag, char(0x2069)) -- U+2069: Pop Directional Isolate (PDI)
return table.concat(tag)
else
return '<bdi lang="' .. value.language .. '">' .. value.text .. '</bdi>'
end
else
return formatError('unknown-datavalue-type', datatype )
end
end
function p.formatStatementQualifiers(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)
local qualifs = args.showqualifiers
if qualifs then
local qualifStr = p.formatStatementQualifiers(statement, qualifs, args)
if qualifStr then
if args.delimiter then
str = str .. args.delimiter .. qualifStr
else
-- str = str .. linguistic.inparentheses(qualifStr, lang)
str = str .. ' (' .. qualifStr .. ')'
end
end
end
if args.showdate then -- when `showdate` and `p.chronosort` are both set, date retrieval is performed twice
local params
local date = dates.getFormattedDate(statement, params)
if date then
-- str = str .. ' <small>' .. linguistic.inparentheses(date, lang) .. '</small>'
str = str .. ' <small>(' .. date ..')</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 tools.isSpecial(source) then
local page
if ref.snaks.P304 and not tools.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 tools.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._getDescription(entity, lang)
if not entity then
return i18n('no description')
end
if type(entity) == 'string' and (not lang or lang == defaultlang) then
return mw.wikibase.description(entity)
end
entity = mw.wikibase.getEntity(entity)
local descriptions = entity.descriptions
if not descriptions then
return i18n('no description')
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
-- == FUNCTIONS HANDLING SEVERAL STATEMENTS ===
function p.stringTable(args) -- find the relevant claims, and formats them as a list of strings
-- Get claims
local claims = p.getClaims(args)
if not claims then
return nil
end
-- Define the formatter function
local formatterFun = p.formatStatement
if args.type == 'date' then
formatterFun = dates.getFormattedDate
elseif args.type == 'qualifiers' then
formatterFun = formatStatementQualifiers
end
-- Format claims
for i = #claims, 1, -1 do
claims[i] = formatterFun(claims[i], args)
if not claims[i] then
table.remove(claims, i)
end
end
return claims
end
function p.formatStatements(args)--Format statements and concat them cleanly
-- If a value is already set, use it
if args.value == '-' then
return nil
end
if args.value then
return args.value
end
-- Obsolete parameters
if args.item then
args.entity = args.item
end
local values = p.stringTable(args) -- gets statements, and format each of them
if not values then
return nil
end
return linguistic.conj(values, args.lang or defaultlang, args.conjtype) -- concatenate them
end
-- == FRAME FUNCTIONS ==
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)
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
args = removeBlanks(args)
return p.formatStatements(args)
end
function p._getLabel(entity, args)
return entities.formatEntity(entity, args)
end
function p.getLabel(frame) -- simple for simple templates like {{Q|}}}
local args = removeBlanks(frame.args)
local entity = args.entity or args[1]
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
return entities.formatEntity(entity, args)
end
function p._wikidataDate(prop, item, params)
local claims = p.getClaims{entity = item, property = prop}
if not claims then
return nil
end
params = params or {}
local vals = {}
for i, j in pairs(claims) do
local v = dates.getFormattedDate(j, params)
if v then
table.insert(vals, v)
end
end
return linguistic.conj(vals, params.conjtype or 'or')
end
function p.wikidataDate(frame)
p._wikidataDate(frame.args[property], frame.args[params], frame.args)
end
function p._main_date(entity)
-- First try with P580/P582
local startpoint = p._wikidataDate('P580', entity)
local endpoint = p._wikidataDate('P582', entity)
if startpoint or endpoint then
return (startpoint or '') .. ' – ' .. (endpoint or '')
end
-- Else use P585
return p._wikidataDate('P585', entity)
end
function p.main_date(frame)
return p._main_date(frame.args[1])
end
-- returns the page id (Q...) of the current page or nothing of the page is not connected to Wikidata
function p.pageId(frame)
local entity = mw.wikibase.getEntityObject()
return entity and entity.id
end
return p