"Module:Wikidata" के अवतरणों में अंतर
नेविगेशन पर जाएँ
खोज पर जाएँ
https://hiwiki.iiit.ac.in/index.php?title=>Uzume (missed one) |
https://hiwiki.iiit.ac.in/index.php/>Pols12 (fixes getEquivalentWPArticle (workaround for T14974 (output can’t start with a colon); fixes targetLang param forwarding)) |
||
पंक्ति १: | पंक्ति १: | ||
-- | --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 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 | local function i18n(str) | ||
local message = i18nmessages[str] | |||
if type(message) == 'string' then | |||
return message | |||
end | |||
return fb._langSwitch(message, defaultlang) .. '' | |||
end | |||
local function formatError( key, text ) | |||
return error(i18n(key) .. (text or '')) | |||
end | |||
if | 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 | end | ||
return '[[Category:' .. cat .. ']]' | |||
end | 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 | end | ||
-- | return args | ||
end | |||
local function formatTheUnknown() -- voir si on peut accorder/adapter l'usage de "inconnu" | |||
return i18n('somevalue') | |||
return | end | ||
local function isSpecial(snak) | |||
return snak.snaktype ~= 'value' | |||
end | end | ||
local function | local function sameValue(snak, target) | ||
return | return not isSpecial(snak) and p.getRawvalue(snak) == target | ||
end | end | ||
local function | |||
local function showLang(statement, str) -- TODO (not yet in proper format) | |||
local | --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 | ||
end | end | ||
if | if #langlist == 0 then | ||
return str | |||
return | |||
else | else | ||
return | return '(' .. table.concat(langlist) .. ')' .. str | ||
end | end | ||
end | end | ||
function p.getEntity( val ) | |||
if | if type(val) == 'table' then | ||
return val | |||
return | |||
end | end | ||
return mw.wikibase.getEntityObject(val) | |||
end | end | ||
-- | -- DATE FUNCTIONS | ||
local function splitTimestamp(timestamp, calendar) | |||
local function | local pattern = "(%W)(%d+)%-(%d+)%-(%d+)" | ||
local | local era, year, month, day = timestamp:match(pattern) | ||
local | |||
if calendar == 'julian' then | |||
if | --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 | |||
if | local function rangeObject(begin, ending) | ||
local timestamp | |||
if begin then | |||
timestamp = begin.timestamp | |||
elseif ending then | |||
timestamp = ending.timestamp | |||
end | 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 | 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 | end | ||
if precision == | 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 | |||
local function formatDaterange(obj, params) --TODO | |||
local begin = formatDatepoint(obj.begin, params) or '' | |||
local ending = formatDatepoint(obj.ending, params) or '' | |||
return begin .. '-' .. ending | |||
end | |||
return | local function objectToText(obj, params) | ||
if obj.type == 'dateobject' then | |||
return formatDatepoint(obj, params) | |||
elseif obj.type == 'rangeobject' then | |||
return formatDaterange(obj, params) | |||
end | 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 | |||
return | |||
end | 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 | ||
possible types of object: | |||
if not | 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) | |||
end | end | ||
-- | -- else preload relevant data | ||
local | 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 | |||
local | 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 | |||
local | 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 | end | ||
return | return nil | ||
end | end | ||
for i, prop in pairs(pointprop) do | |||
local val = getval(prop) | |||
if val then return val end | |||
if | |||
end | end | ||
--if no date has not been found, look for startdate or enddate | |||
-- | local begin, ending | ||
if | for i, prop in pairs(beginprop) do | ||
begin = getval(prop) | |||
if begin then | |||
break | |||
end | |||
end | end | ||
for i, prop in pairs(endingprop) do | |||
ending = getval(prop) | |||
if ending then | |||
break | |||
end | end | ||
end | end | ||
if begin or ending then | |||
return rangeObject(begin, ending) | |||
end | |||
return nil | |||
end | end | ||
function p.getFormattedDate(statement, params) | |||
local datetable = p.getDate(statement) | |||
local | if not datetable then | ||
return nil | |||
end | end | ||
return objectToText(datetable, params) | |||
end | |||
local function hasTargetValue(claim, target) | |||
if target == nil then | |||
return true | |||
end | end | ||
return sameValue(claim.mainsnak, target) | |||
end | end | ||
local function | local function hasRank(claim, target) | ||
if target == 'valid' then | |||
return hasRank(claim, 'preferred') or hasRank(claim, 'normal') | |||
if | |||
else | else | ||
return | return claim.rank == target | ||
end | end | ||
end | end | ||
local function | local function bestRanked(claims) | ||
if not claims then | |||
if | return nil | ||
return | end | ||
local preferred, normal = {}, {} | |||
for _, j in ipairs(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 | else | ||
return normal | |||
return | |||
end | end | ||
end | end | ||
local function | local function hasQualifier(claim, qualifier, qualifiervalues) | ||
if not | 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 | end | ||
if (not qualifiervalues) or (qualifiervalues == {}) then | |||
if | return true -- si aucune valeur spécifique n'est exigée | ||
end | end | ||
for _, j in ipairs(claim.qualifiers[qualifier]) do | |||
for _, l in ipairs(qualifiervalues) do | |||
if p.sameValue(j, l) then | |||
return true | |||
end | |||
end | end | ||
end | end | ||
end | return false | ||
end | |||
local function | local function hasSource(statement, source, sourceproperty) | ||
if not statement.references then | |||
return false | |||
if | |||
return | |||
end | end | ||
sourceproperty = string.upper(sourceproperty or 'P248') | |||
local sourcevalue = string.upper(source or '') | |||
for _, ref in ipairs(statement.references) do | |||
local | for prop, content in pairs(ref.snaks) do | ||
if prop == sourceproperty then | |||
for ref in | if sourcevalue == '' then | ||
return true | |||
else | |||
for | for _, k in ipairs(content) do | ||
if | if sameValue(k, source) then | ||
return true | |||
end | |||
end | |||
end | |||
end | end | ||
end | end | ||
end | end | ||
return | return false | ||
end | end | ||
local function | local function hasDate(statement) | ||
if not statement.qualifiers then | |||
if | return false | ||
return false | |||
end | end | ||
local | local dateprops = {'P580', 'P585', 'P582'} | ||
for i, prop in pairs(dateprops) do | |||
if statement.qualifiers[prop] then | |||
return true | |||
return | |||
end | end | ||
end | end | ||
return | return false | ||
end | end | ||
local function | |||
return | 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 | end | ||
local function | |||
if | local function numval(claims, numval) -- retourn les numval premières valeurs de la table claims | ||
local numval = tonumber(numval) or 0 -- raise an error if numval is not a positive integer ? | |||
if #claims <= numval then | |||
end | return claims | ||
end | |||
local newclaims = {} | |||
while #newclaims < numval do | |||
table.insert(newclaims, claims[#newclaims + 1]) | |||
end | |||
return newclaims | |||
end | |||
local function wikipediaLink(entity, lang) | |||
local link | |||
local lg = string.gsub(lang, '-', '_') | |||
if (lg == 'be_tarask') then lg = 'be_x_old' end | |||
if (lg == 'nb') then lg = 'no' end | |||
if type(entity) == 'table' then | |||
link = entity:getSitelink(lg .. 'wiki') | |||
else | |||
link = mw.wikibase.getSitelink(entity, lg .. 'wiki') | |||
end | |||
if link then | |||
return ':' .. lang .. ':' .. link | |||
end | end | ||
return nil | |||
end | |||
local function getLink(entity, typelink, lang) | |||
if typelink == 'wikidata' then | |||
if type(entity) == 'table' then | |||
if entity.type == 'property' then | |||
return 'd:P:' .. entity.id | |||
elseif entity.type == 'lexeme' then | |||
return 'd:L:' .. entity.id | |||
else | else | ||
return 'd:' .. entity.id | |||
end | |||
else | |||
if string.sub(entity, 1, 1) == 'P' then | |||
return 'd:P:' .. entity | |||
elseif string.sub(entity, 1, 1) == 'L' then | |||
return 'd:L:' .. entity | |||
else | |||
return 'd:' .. entity | |||
end | |||
end | |||
elseif typelink == 'wikipedia' then | |||
return wikipediaLink(entity, lang or defaultlang) | |||
elseif typelink == 'anywikipedia' then | |||
for _, lg in ipairs(fb.fblist(lang or defaultlang, true)) do | |||
local link = wikipediaLink(entity, lg) | |||
if link then | |||
return link | |||
end | end | ||
end | end | ||
end | end | ||
return nil | |||
end | 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) | |||
function p. | table.sort(objs, function(a, b) | ||
local | 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 | ||
end) | |||
return objs | |||
end | end | ||
function p. | 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 | end | ||
function p. | function p.getRawvalue(snak) | ||
return p.getDatavalue(snak, { displayformat = 'raw' }) | |||
return | |||
end | end | ||
function p.showentity(entity, lang) | |||
p. | if not entity then | ||
return nil | |||
if | |||
end | end | ||
local | local label, link, id = p._getLabel(entity, lang), getLink(entity, 'wikidata') | ||
if | if type(entity) == 'table' then | ||
id = entity.id | |||
else | |||
id = entity | |||
end | end | ||
return | return '[[' .. link .. '|' .. label .. ']] <small>(' .. id .. ')</small>' | ||
end | end | ||
function p.getDatavalue(snak, params) | |||
p. | if isSpecial(snak) then | ||
return nil | |||
return | |||
end | end | ||
local | |||
if not params then | |||
params = {} | |||
local | end | ||
if | local displayformat = params.displayformat | ||
if | 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 id = snak.datavalue.value.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) | |||
else | |||
if params.urlpattern then | |||
showntext = mw.text.nowiki(showntext or value) | |||
value = mw.ustring.gsub(value, '%%', '%%%%') -- escape '%' | |||
value = '[' .. mw.ustring.gsub(mw.ustring.gsub(params.urlpattern, '$1', value), ' ', '%%20') .. ' ' .. showntext .. ']' | |||
elseif params.pattern then | |||
local pattern = mw.ustring.gsub(params.pattern, '%%', '%%%%') | |||
value = mw.ustring.gsub(value, '%%', '%%%%') | |||
value = mw.ustring.gsub(pattern, '$1', value) | |||
else | |||
if displayformat ~= 'raw' then | |||
value = mw.text.nowiki(value) | |||
end | end | ||
end | end | ||
end | 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 | end | ||
if | |||
return | 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 = mw.loadData('Module:Wikidata/Globes')[value.globe] | |||
value.precision = nil | |||
return coord._coord(value) | |||
else | else | ||
return | value.globe = mw.loadData('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 | end | ||
return | 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, params.lang) | |||
local unit = mw.ustring.match(value.unit, '(Q%d+)') | |||
if unit then | |||
number = number .. ' ' .. p.formatEntity(unit, params) | |||
end | end | ||
return | return number | ||
end | end | ||
elseif datatype == 'monolingualtext' then | |||
return '<span lang="' .. value.language .. '">' .. value.text .. '</span>' | |||
else | else | ||
return | return formatError( 'unknown-datavalue-type', datatype ) | ||
end | end | ||
end | end | ||
local | local function getMultipleClaims(args) | ||
local | local newargs = args | ||
if ( | 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 | ||
end | end | ||
return | return claims | ||
end | 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 | |||
if | 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 | end | ||
local | local property = string.upper(args.property) | ||
local | local allClaims | ||
local entity = args.entity | |||
if type(entity) == 'table' then | |||
allClaims = (entity and entity.claims and entity.claims[property]) or {} | |||
else | |||
allClaims = mw.wikibase.getAllStatements(entity, property) | |||
end | |||
if #allClaims == 0 then | |||
return nil | |||
end | end | ||
if not args.rank then | |||
args.rank = 'best' | |||
end | |||
local claims = {} | |||
for _, statement in ipairs(allClaims) 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 | end | ||
if #claims == 0 then | |||
return nil | |||
end | end | ||
return | 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 | end | ||
function p.formatClaimList(claims, args) | |||
p. | if not claims then | ||
return nil | |||
if not | |||
return | |||
end | end | ||
for i, j in pairs(claims) do | |||
claims[i] = p.formatStatement(j, args) | |||
end | end | ||
return | return claims | ||
end | end | ||
p. | function p.stringTable(args) -- like getClaims, but get a list of string rather than a list of snaks, for easier manipulation | ||
local | local claims = p.getClaims(args) | ||
if | 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 ipairs(fb.fblist(params.lang or defaultlang, true)) do | |||
for _, snak in ipairs(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 #vals == 0 then | |||
return nil | |||
end | end | ||
return | return vals | ||
end | 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 | |||
local | |||
if not | |||
return | |||
end | end | ||
for i, j in pairs(qualiftable) do | |||
local params = params | |||
for | if j.datatype == 'globe-coordinate' then | ||
if | params.displayformat = 'qualifier' | ||
end | end | ||
qualiftable[i] = p.formatSnak(j, params) | |||
end | end | ||
return | return linguistic.conj(qualiftable, params.lang or defaultlang) | ||
end | end | ||
p. | |||
function p.formatStatement( statement, args ) | |||
local | 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 | 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 | end | ||
if | 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 | ||
end | end | ||
if args.showsource and statement.references then | |||
local cite = require 'Module:Cite' | |||
local frame = mw.getCurrentFrame() | |||
local sourcestring = '' | |||
for _, ref in ipairs(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(source.datavalue.value.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 | ||
end | end | ||
str = str .. sourcestring | |||
end | end | ||
return str | |||
if | end | ||
function p.getmainid(claim) | |||
if claim and not isSpecial(claim.mainsnak) then | |||
return claim.mainsnak.datavalue.value.id | |||
end | end | ||
return | return nil | ||
end | 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, displayformat) -- label when no label is available | |||
if displayformat == 'id' then | |||
if type(entity) ~= 'table' then | |||
return entity | |||
else | |||
return entity.id | |||
end | |||
end | |||
return i18n('no-label') | |||
end | |||
function p._getLabel(entity, lang, default, fallback) | |||
if not entity then | |||
return nil | |||
p. | |||
if | |||
end | end | ||
if not lang then | |||
lang = defaultlang | |||
lang = | |||
end | end | ||
if type(entity) ~= 'table' and lang == defaultlang then | |||
local label, lg = mw.wikibase.getLabelWithLang(entity) | |||
if label and (fallback ~= '-' or lg == lang) then | |||
return label | |||
local | |||
if | |||
end | end | ||
else | |||
if | entity = p.getEntity(entity) | ||
- | if entity and entity.labels then | ||
if fallback ~= '-' then | |||
for _, lg in ipairs(fb.fblist(lang, true)) do | |||
if entity.labels[lg] then | |||
return entity.labels[lg].value | |||
end | end | ||
end | end | ||
else | |||
if entity.labels[lang] then | |||
return entity.labels[lang].value | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
return defaultLabel(entity, default) | |||
end | end | ||
function p._getDescription(entity, lang, fallback) | |||
if not entity then | |||
return i18n('no description') | |||
end | |||
p. | if not lang then | ||
lang = defaultlang | |||
if not | |||
end | end | ||
if type(entity) ~= 'table' and lang == defaultlang then | |||
local description, lg = mw.wikibase.getDescriptionWithLang(entity) | |||
if description and (fallback ~= '-' or lg == lang) then | |||
local | return description | ||
end | end | ||
else | else | ||
- | entity = p.getEntity(entity) | ||
if entity and entity.descriptions then | |||
if fallback ~= '-' then | |||
for _, lg in ipairs(fb.fblist(lang, true)) do | |||
if entity.descriptions[lg] then | |||
return entity.descriptions[lg].value | |||
end | |||
end | |||
else | |||
if entity.descriptions[lang] then | |||
return entity.descriptions[lang].value | |||
end | |||
end | |||
end | |||
end | end | ||
return i18n('no description') | |||
end | end | ||
local function formattedLabel(label, entity, args) | |||
local link = getLink(entity, args.link, args.lang) | |||
return | if not link then | ||
link = getLink(entity, defaultlink, args.lang) | |||
end | |||
if not link then | |||
return label | |||
else | |||
return '[[' .. link .. '|' .. label .. ']]' | |||
end | |||
end | end | ||
function p. | function p.formatEntity( entity, args ) | ||
if not entity then | if not entity then | ||
return nil | |||
end | end | ||
if not args then | |||
args = {} | |||
if not | |||
end | end | ||
local label = p._getLabel(entity, args.lang, 'id', args.fallback) | |||
return formattedLabel(label, entity, args) | |||
end | |||
function p.getLabel(frame) -- simple for simple templates like {{Q|}}} | |||
local | local args = frame.args | ||
local entity = args.entity | |||
local lang = args.lang | |||
if not entity then | |||
return i18n('invalid-id') | |||
end | end | ||
if string.sub(entity, 1, 10) == 'Property:P' then | |||
entity = string.sub(entity, 10) | |||
elseif string.sub(entity, 1, 8) == 'Lexeme:L' then | |||
entity = string.sub(entity, 8) | |||
return | elseif not ({L = 1, P = 1, Q = 1})[string.sub(entity, 1, 1)] or not tonumber(string.sub(entity, 2)) then | ||
return i18n('invalid-id') | |||
end | end | ||
if not args.link or args.link == '' or args.link == '-' then -- by default: no link | |||
if lang == '' then | |||
if | lang = defaultlang | ||
end | end | ||
return p._getLabel(entity, lang, args.default, args.fallback) | |||
else | else | ||
return p.formatEntity(entity, args) | |||
end | end | ||
end | |||
if | function p._formatStatements( args )--Format statements and concat them cleanly | ||
if args.value == '-' then | |||
return nil | |||
end | 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 | end | ||
function p.showQualifier( args ) | |||
function p. | local qualifs = args.qualifiers or args.qualifier | ||
local | if type(qualifs) == 'string' then | ||
qualifs = mw.text.split(qualifs, ',') | |||
if | end | ||
if not qualifs then | |||
return formatError( 'property-param-not-provided' ) | |||
end | end | ||
local | local claims = p.getClaims(args) | ||
if not | if not claims then | ||
return nil | return nil | ||
end | end | ||
local str = '' | |||
local new | |||
for _, cl in ipairs(claims) do | |||
new = p.getFormattedQualifiers(cl, qualifs, args) or '' | |||
str = str .. new | |||
end | |||
return str | |||
end | |||
local | function p._formatAndCat(args) | ||
local val = p._formatStatements(args) | |||
local | if val then | ||
if not | 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 _, cl in ipairs(claims) do | |||
table.insert(formattedvalues, p.getFormattedDate(cl)) | |||
end | |||
local val = linguistic.conj(formattedvalues) | |||
if val and args.addcat == true then | |||
return val .. addTrackingCat(args.property) | |||
else | |||
return val | |||
end | |||
end | |||
--[[ | |||
Returns a Wikipedia page name (with interwiki prefix) which is equivalent page | |||
to given page in given language. | |||
Args: | |||
* sourceTitle: wiki page title which exists on sourceLang Wikipedia. | |||
* sourceLang: language code of Wikipedia where `sourceTitle` is an | |||
article. Defaults to `en`. | |||
* targetLang: language code of Wikipedia from which you want to get | |||
equivalent article to `sourceTitle`. Defaults to `defaultlang`. | |||
Bug: return value should not start with a colon because of T14974 | |||
]] | |||
function p._getEquivalentWPArticle(sourceTitle, sourceLang, targetLang) | |||
if not sourceLang or sourceLang == '' then | |||
sourceLang = 'en' | |||
end | |||
if not targetLang or targetLang == '' then | |||
targetLang = defaultlang | |||
end | |||
local sourceLink = ' :' .. sourceLang .. ':' .. sourceTitle | |||
if sourceLang == targetLang then | |||
return sourceLink | |||
end | |||
local sourceWiki = sourceLang .. 'wiki' -- e.g. "enwiki" is global site id for English Wikipedia | |||
local id = mw.wikibase.getEntityIdForTitle( sourceTitle, sourceWiki ) | |||
if not id then | |||
return sourceLink --source page has no linked Wikidata element, let’s keep it | |||
end | |||
local fallbackLangs = mw.language.getFallbacksFor(targetLang) | |||
table.insert(fallbackLangs, 1, targetLang) --keeps targetLang as first lang to try | |||
for _, fallbackLang in ipairs(fallbackLangs) do | |||
local existingEquivalent = getLink(id, 'anywikipedia', fallbackLang) | |||
if existingEquivalent then | |||
return ' ' .. existingEquivalent | |||
end | end | ||
end | |||
return sourceLink --source page has no interwiki, let’s keep it | |||
end | |||
function p.formatStatements( args ) | |||
return p._formatStatements( args ) | |||
end | |||
function p.getEntityFromId(id) | |||
return p.getEntity(id) | |||
end | |||
---------------------------------------- | |||
-- Functions callable from a template -- | |||
---------------------------------------- | |||
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 | |||
if not entity then | |||
return i18n('invalid-id') | |||
end | |||
local lang = frame.args.lang | |||
local fallback = frame.args.fallback | |||
return p._getDescription(entity, lang, fallback) | |||
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 | 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 | end | ||
return p._formatAndCat( args ) | |||
end | end | ||
function p.labelOf(frame) | |||
local id = frame.args[1] | |||
function p. | -- returns the label of the given entity/property id | ||
local | -- if no id is given, the one from the entity associated with the calling Wikipedia article is used | ||
if | if not id then | ||
local entity = mw.wikibase.getEntity() | |||
if not entity then return printError("entity-not-found") end | |||
id = entity.id | |||
end | end | ||
return | return mw.wikibase.label(id) | ||
end | end | ||
function p. | function p.getLink(frame) | ||
local | local entity = frame.args.entity | ||
if not entity then | |||
if not | return i18n('invalid-id') | ||
return i18n | |||
end | end | ||
local | local fallback = frame.args.fallback | ||
local lang = frame.args.lang | |||
local label = frame.args.label | |||
local typelink = 'anywikipedia' | |||
if (fallback == '') or (fallback == '-') then typelink = 'wikipedia' end | |||
if (label == '') or (label == '-') then | |||
label = p._getLabel(entity, lang, 'id', fallback) | |||
end | end | ||
return '[[' .. getLink(entity, typelink, lang) .. '|' .. label .. ']]' | |||
end | |||
--[[ | |||
Returns a Wikipedia page name with interwiki prefix which is equivalent page | |||
to given page in given language. | |||
Args: | |||
* sourceTitle: wiki page title which exists on sourceLang Wikipedia. | |||
* sourceLang: language code of Wikipedia where `sourceTitle` is an | |||
article. Defaults to `en`. | |||
* targetLang: language code of Wikipedia from which you want to get | |||
equivalent article to `sourceTitle`. Defaults to `defaultlang`. | |||
]] | |||
function p.getEquivalentWPArticle(frame) | |||
return p._getEquivalentWPArticle( | |||
frame.args.sourceTitle, | |||
frame.args.sourceLang, | |||
frame.args.targetLang | |||
) | |||
end | end | ||
return p | return p |
०२:०९, ६ जनवरी २०२२ का अवतरण
"इस मॉड्यूल हेतु प्रलेख Module:Wikidata/doc पर बनाया जा सकता है"
--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)
local message = i18nmessages[str]
if type(message) == 'string' then
return message
end
return fb._langSwitch(message, 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)
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 _, j in ipairs(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 _, j in ipairs(claim.qualifiers[qualifier]) do
for _, l in ipairs(qualifiervalues) do
if p.sameValue(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 _, ref in ipairs(statement.references) do
for prop, content in pairs(ref.snaks) do
if prop == sourceproperty then
if sourcevalue == '' then
return true
else
for _, k in ipairs(content) do
if sameValue(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 an 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
local function wikipediaLink(entity, lang)
local link
local lg = string.gsub(lang, '-', '_')
if (lg == 'be_tarask') then lg = 'be_x_old' end
if (lg == 'nb') then lg = 'no' end
if type(entity) == 'table' then
link = entity:getSitelink(lg .. 'wiki')
else
link = mw.wikibase.getSitelink(entity, lg .. 'wiki')
end
if link then
return ':' .. lang .. ':' .. link
end
return nil
end
local function getLink(entity, typelink, lang)
if typelink == 'wikidata' then
if type(entity) == 'table' then
if entity.type == 'property' then
return 'd:P:' .. entity.id
elseif entity.type == 'lexeme' then
return 'd:L:' .. entity.id
else
return 'd:' .. entity.id
end
else
if string.sub(entity, 1, 1) == 'P' then
return 'd:P:' .. entity
elseif string.sub(entity, 1, 1) == 'L' then
return 'd:L:' .. entity
else
return 'd:' .. entity
end
end
elseif typelink == 'wikipedia' then
return wikipediaLink(entity, lang or defaultlang)
elseif typelink == 'anywikipedia' then
for _, lg in ipairs(fb.fblist(lang or defaultlang, true)) do
local link = wikipediaLink(entity, lg)
if link then
return link
end
end
end
return nil
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
local label, link, id = p._getLabel(entity, lang), getLink(entity, 'wikidata')
if type(entity) == 'table' then
id = entity.id
else
id = entity
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 id = snak.datavalue.value.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)
else
if params.urlpattern then
showntext = mw.text.nowiki(showntext or value)
value = mw.ustring.gsub(value, '%%', '%%%%') -- escape '%'
value = '[' .. mw.ustring.gsub(mw.ustring.gsub(params.urlpattern, '$1', value), ' ', '%%20') .. ' ' .. showntext .. ']'
elseif params.pattern then
local pattern = mw.ustring.gsub(params.pattern, '%%', '%%%%')
value = mw.ustring.gsub(value, '%%', '%%%%')
value = mw.ustring.gsub(pattern, '$1', value)
else
if displayformat ~= 'raw' then
value = mw.text.nowiki(value)
end
end
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 = mw.loadData('Module:Wikidata/Globes')[value.globe]
value.precision = nil
return coord._coord(value)
else
value.globe = mw.loadData('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, params.lang)
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 property = string.upper(args.property)
local allClaims
local entity = args.entity
if type(entity) == 'table' then
allClaims = (entity and entity.claims and entity.claims[property]) or {}
else
allClaims = mw.wikibase.getAllStatements(entity, property)
end
if #allClaims == 0 then
return nil
end
if not args.rank then
args.rank = 'best'
end
local claims = {}
for _, statement in ipairs(allClaims) 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 ipairs(fb.fblist(params.lang or defaultlang, true)) do
for _, snak in ipairs(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 _, ref in ipairs(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(source.datavalue.value.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.getmainid(claim)
if claim and not isSpecial(claim.mainsnak) then
return claim.mainsnak.datavalue.value.id
end
return nil
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, displayformat) -- label when no label is available
if displayformat == 'id' then
if type(entity) ~= 'table' then
return entity
else
return entity.id
end
end
return i18n('no-label')
end
function p._getLabel(entity, lang, default, fallback)
if not entity then
return nil
end
if not lang then
lang = defaultlang
end
if type(entity) ~= 'table' and lang == defaultlang then
local label, lg = mw.wikibase.getLabelWithLang(entity)
if label and (fallback ~= '-' or lg == lang) then
return label
end
else
entity = p.getEntity(entity)
if entity and entity.labels then
if fallback ~= '-' then
for _, lg in ipairs(fb.fblist(lang, true)) do
if entity.labels[lg] then
return entity.labels[lg].value
end
end
else
if entity.labels[lang] then
return entity.labels[lang].value
end
end
end
end
return defaultLabel(entity, default)
end
function p._getDescription(entity, lang, fallback)
if not entity then
return i18n('no description')
end
if not lang then
lang = defaultlang
end
if type(entity) ~= 'table' and lang == defaultlang then
local description, lg = mw.wikibase.getDescriptionWithLang(entity)
if description and (fallback ~= '-' or lg == lang) then
return description
end
else
entity = p.getEntity(entity)
if entity and entity.descriptions then
if fallback ~= '-' then
for _, lg in ipairs(fb.fblist(lang, true)) do
if entity.descriptions[lg] then
return entity.descriptions[lg].value
end
end
else
if entity.descriptions[lang] then
return entity.descriptions[lang].value
end
end
end
end
return i18n('no description')
end
local function formattedLabel(label, entity, args)
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.formatEntity( entity, args )
if not entity then
return nil
end
if not args then
args = {}
end
local label = p._getLabel(entity, args.lang, 'id', args.fallback)
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 not entity then
return i18n('invalid-id')
end
if string.sub(entity, 1, 10) == 'Property:P' then
entity = string.sub(entity, 10)
elseif string.sub(entity, 1, 8) == 'Lexeme:L' then
entity = string.sub(entity, 8)
elseif not ({L = 1, P = 1, Q = 1})[string.sub(entity, 1, 1)] or not tonumber(string.sub(entity, 2)) then
return i18n('invalid-id')
end
if not args.link or args.link == '' or args.link == '-' then -- by default: no link
if lang == '' then
lang = defaultlang
end
return p._getLabel(entity, lang, args.default, args.fallback)
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 = ''
local new
for _, cl in ipairs(claims) do
new = p.getFormattedQualifiers(cl, 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 _, cl in ipairs(claims) do
table.insert(formattedvalues, p.getFormattedDate(cl))
end
local val = linguistic.conj(formattedvalues)
if val and args.addcat == true then
return val .. addTrackingCat(args.property)
else
return val
end
end
--[[
Returns a Wikipedia page name (with interwiki prefix) which is equivalent page
to given page in given language.
Args:
* sourceTitle: wiki page title which exists on sourceLang Wikipedia.
* sourceLang: language code of Wikipedia where `sourceTitle` is an
article. Defaults to `en`.
* targetLang: language code of Wikipedia from which you want to get
equivalent article to `sourceTitle`. Defaults to `defaultlang`.
Bug: return value should not start with a colon because of T14974
]]
function p._getEquivalentWPArticle(sourceTitle, sourceLang, targetLang)
if not sourceLang or sourceLang == '' then
sourceLang = 'en'
end
if not targetLang or targetLang == '' then
targetLang = defaultlang
end
local sourceLink = ' :' .. sourceLang .. ':' .. sourceTitle
if sourceLang == targetLang then
return sourceLink
end
local sourceWiki = sourceLang .. 'wiki' -- e.g. "enwiki" is global site id for English Wikipedia
local id = mw.wikibase.getEntityIdForTitle( sourceTitle, sourceWiki )
if not id then
return sourceLink --source page has no linked Wikidata element, let’s keep it
end
local fallbackLangs = mw.language.getFallbacksFor(targetLang)
table.insert(fallbackLangs, 1, targetLang) --keeps targetLang as first lang to try
for _, fallbackLang in ipairs(fallbackLangs) do
local existingEquivalent = getLink(id, 'anywikipedia', fallbackLang)
if existingEquivalent then
return ' ' .. existingEquivalent
end
end
return sourceLink --source page has no interwiki, let’s keep it
end
function p.formatStatements( args )
return p._formatStatements( args )
end
function p.getEntityFromId(id)
return p.getEntity(id)
end
----------------------------------------
-- Functions callable from a template --
----------------------------------------
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
if not entity then
return i18n('invalid-id')
end
local lang = frame.args.lang
local fallback = frame.args.fallback
return p._getDescription(entity, lang, fallback)
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.labelOf(frame)
local id = frame.args[1]
-- returns the label of the given entity/property id
-- if no id is given, the one from the entity associated with the calling Wikipedia article is used
if not id then
local entity = mw.wikibase.getEntity()
if not entity then return printError("entity-not-found") end
id = entity.id
end
return mw.wikibase.label(id)
end
function p.getLink(frame)
local entity = frame.args.entity
if not entity then
return i18n('invalid-id')
end
local fallback = frame.args.fallback
local lang = frame.args.lang
local label = frame.args.label
local typelink = 'anywikipedia'
if (fallback == '') or (fallback == '-') then typelink = 'wikipedia' end
if (label == '') or (label == '-') then
label = p._getLabel(entity, lang, 'id', fallback)
end
return '[[' .. getLink(entity, typelink, lang) .. '|' .. label .. ']]'
end
--[[
Returns a Wikipedia page name with interwiki prefix which is equivalent page
to given page in given language.
Args:
* sourceTitle: wiki page title which exists on sourceLang Wikipedia.
* sourceLang: language code of Wikipedia where `sourceTitle` is an
article. Defaults to `en`.
* targetLang: language code of Wikipedia from which you want to get
equivalent article to `sourceTitle`. Defaults to `defaultlang`.
]]
function p.getEquivalentWPArticle(frame)
return p._getEquivalentWPArticle(
frame.args.sourceTitle,
frame.args.sourceLang,
frame.args.targetLang
)
end
return p