Wikipedia diqwiki https://diq.wikipedia.org/wiki/Pela_Seri MediaWiki 1.47.0-wmf.7 first-letter Medya Xısusi Werênayış Karber Werênayışê karberi Wikipediya Werênayışê Wikipediya Dosya Werênayışê dosya MedyaWiki Werênayışê MedyaWikiyi Şablon Werênayışê şabloni Peşti Werênayışê peşti Kategoriye Werênayışê kategoriye Portal Werênayışê portali TimedText TimedText talk Modul Werênayışê moduli Event Event talk Abdul Aziz 0 19926 549196 406346 2026-06-22T07:40:48Z Mirzali 16 549196 wikitext text/x-wiki {{Infobox kraliyet}} '''Abdul Aziz''' (be [[Zazaki]]: ''Ebduleziz'', be [[Usmanıcki|Tırkiyê Usmanıcan]]: ''`Abdü´l-Âzīz-i evvel'' عبد العزيز) padişahê Usmanıcano 32ın û xelifeyê İslamiyo 111ın biyo. Lacê [[Mahmud II]] biyo. Serra 1830ıne de ameyo ra riyê dınya. Mergê Sultan [[Abdul Mecid|Ebdulmecid]]i ra dıme 25ê Heziraniyê serra 1861ıne de veciyo ro text. {{İmperatorê Usmanıcan}} {{Xelifey}} [[Kategoriye:Sultanê Usmanıcan]] [[Kategoriye:Şarê Estanboli]] [[Kategoriye:Merdumê ke 1830 de biyê]] [[Kategoriye:Merdumê ke 1876 de merdê]] 21xjh8r7ddj4sfh2usqycfsjsj056u1 Şablon:Navbar 10 21712 549186 546587 2026-06-22T06:47:33Z Mirzali 16 549186 wikitext text/x-wiki {{#if:{{{1|}}}|<span class="nowrap">[[File:OOjs UI icon article-ltr.svg|16px|link={{{1}}}]]-[[File:OOjs UI icon edit-ltr.svg|16px|link={{fullurl:{{FULLPAGENAMEE:{{{1}}}}}|action=edit}}|Şabloni bıvurnê]]</span>|}}<noinclude>{{documentation}} [[Kategoriye:Şablonê Wikipediya]]</noinclude> fndqjgivc58l7q4xqrpt6clnkqdzb1l Adele 0 40621 549197 526212 2026-06-22T07:44:02Z Mirzali 16 549197 wikitext text/x-wiki {{Merdumi}} '''Adele Laurie Blue Adkins''' (b. 5 Gulane 1988)<ref>{{Cite web |title=Adele: New Record is ‘Quite Different’ |url=http://www.spin.com/articles/adele-new-record-quite-different |access-date=2013-04-07 |archivedate=2015-05-11 |archiveurl=https://web.archive.org/web/20150511211143/http://www.spin.com/articles/adele-new-record-quite-different }}</ref>, yew bestekar, senatkar û muzisyena İngılıza. Serra 1988ıne de mıntıqaya [[Tottenham]]i de biya.<ref>[http://www.guardian.co.uk/music Pop and rock, britawards 2008]</ref> Serra 2008ıne de BBC ra xelata ''Vengê 2008''i grewta. Bahdo 28ê Çeleyê 2008ıne de albumê xoyo verên ''[[19]]'' çap kerdo. Ebe nê albumi ra hem [[Qraliya Yewbiyayiye]] de hem zi cihan de zaf biya namdare. Serra 2009ıne de Xelata Grammy ra dı xelati gırewtê. Serra 2011ıne de albumê xoyo dıyıne [[21]] çap kerdo. Ebe nê albumi ra dınya de zaf biya namdare û zafê kesi no albume gırewto û Adele ebe nê albumi Xelata Grammy ra şeş xêlati gırewtê û rekorê [[Beyoncé]]ye egale kerdo. == Diskografiya Adele == * [[2008]] : [[19]] * [[2011]] : [[21]] * [[2015]] : [[25]] * [[2021]] : [[30]] == Referansi == <references/> [[Kategoriye:Senatkarê Qraliya Yewbiyayiye]] [[Kategoriye:Şarê Londra]] [[Kategoriye:Merdumê ke 1988 de biyê]] 82sm1mtp1ddcuuiyyzjuvsimfya6a7d Modul:Wikidata 828 42723 549192 520153 2026-06-22T07:19:29Z Mirzali 16 549192 Scribunto text/plain --script that retrieves basic data stored in Wikidata, for the datamodel, see https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua local wd = {} -- creation of a subobject to store comparison funtions, used for sorting claims -- to be able to build more complex sorts like topological sorts wd.compare = {} local databases = { } local modules = { } local databasesNames = { -- modules de données statiques pouvant être appelés avec mw.loadData(), ne nécessitant pas require() i18n = 'Module:Wikidata/I18n', globes = 'Module:Wikidata/Globes', langhierarchy = 'Module:Wikidata/Hiérarchie des langues', langcodes = 'Module:Dictionnaire Wikidata/Codes langue', -- big, infrequently useda invertedlangcodes = 'Module:Dictionnaire Wikidata/Codes langue/inversé' } local modulesNames = { reference = 'Module:Wikidata/Références', linguistic = 'Module:Linguistique', datemodule = 'Module:Date', formatDate = 'Module:Date complexe', formatNum = 'Module:Conversion', langmodule = 'Module:Langue', cite = 'Module:Biblio', weblink = 'Module:Weblink' } local function loadDatabase( t, key ) if databasesNames[key] then local m = mw.loadData( databasesNames[key] ) t[key] = m return m end end local function loadModule( t, key ) if modulesNames[key] then local m = require( modulesNames[key] ) t[key] = m return m end end setmetatable( databases, { __index = loadDatabase } ) setmetatable( modules, { __index = loadModule } ) -- ainsi le require() sera opéré seulement si nécessaire par modules.(nom du module) local datequalifiers = {'P585', 'P571', 'P580', 'P582', 'P1319', 'P1326'} -- === I18n === local defaultlang = mw.getContentLanguage():getCode() function wd.translate(str, rep1, rep2) str = databases.i18n[str] or str if rep1 and (type (rep1) == 'string') then str = str:gsub('$1', rep1) end if rep2 and (type (rep2) == 'string')then str = str:gsub('$2', rep2) end return str end local function addCat(cat, sortkey) if sortkey then return '[[Category:' .. cat .. '|' .. sortkey .. ']]' end return '[[Category:' .. cat .. ']]' end local function formatError( key , category, debug) if debug then return error(databases.i18n[key] or key) end if category then return addCat(category, key) else return addCat('cat-unsorted-issue', key) end end -- function wd.isSpecial(snak) return (snak.snaktype ~= 'value') end function wd.getId(snak) if (snak.snaktype == 'value') then return 'Q' .. snak.datavalue.value['numeric-id'] end end function wd.getNumericId(snak) if (snak.snaktype == 'value') then return snak.datavalue.value['numeric-id'] end end function wd.getMainId(claim) return wd.getId(claim.mainsnak) end function wd.entityId(entity) if type(entity) == 'string' then return entity elseif type(entity) == 'table' then return entity.id end end function wd.getEntityIdForCurrentPage() return mw.wikibase.getEntityIdForCurrentPage() end -- function that returns true if the "qid" parameter is the qid -- of the item that is linked to the calling page function wd.isPageOfQId(qid) local self_id = mw.wikibase.getEntityIdForCurrentPage() return self_id ~= nil and qid == self_id end function wd.getEntity( val ) if type(val) == 'table' then return val end if val == '-' then return nil end if val == '' then val = nil end return mw.wikibase.getEntity(val) end function wd.splitStr(val) -- transforme en table les chaînes venant du Wikitexte qui utilisent des virgules de séparation if type(val) == 'string' then val = mw.text.split(val, ",") end return val end function wd.isHere(searchset, val) for i, j in pairs(searchset) do if val == j then return true end end return false end local function wikidataLink(entity) local name =':d:' if type(entity) == 'string' then if entity:match("P[0-9+]") then entity = "Property:" .. entity end return name .. entity elseif type(entity) == 'table' then if entity["type"] == "property" then name = ":d:Property:" end return name .. entity.id elseif type(entity) == nil then return formatError('entity-not-found') end end function wd.siteLink(entity, project, lang) -- returns 3 values: a sitelink (with the relevant prefix) a project name and a language lang = lang or defaultlang if (type(project) ~= 'string') then project = 'wiki' end project = project:lower() if project == 'wikipedia' then project = 'wiki' end if type(entity) == 'string' and (project == 'wiki') and ( (not lang or lang == defaultlang) ) then -- évite de charger l'élément entier return mw.wikibase.sitelink(entity), 'wiki', defaultlang end if project == 'wikidata' then return wikidataLink(entity), 'wikidata' end local projects = { -- nom = {préfixe sur Wikidata, préfix pour les liens sur Wikipédia, ajouter préfixe de langue} wiki = {'wiki', nil, true}, -- wikipedia commons = {'commonswiki', 'commons', false}, commonswiki = {'commonswiki', 'commons', false}, wikiquote = {'wikiquote', 'q', true}, wikivoyage = {'wikivoyage', 'voy', true}, wikibooks = {'wikibooks', 'b', true}, wikinews = {'wikinews', 'n', true}, wikiversity = {'wikiversity', 'v', true}, wikisource = {'wikisource', 's', true}, wiktionary = {'wiktionary', 'wikt', true}, specieswiki = {'specieswiki', 'species', false}, metawiki = {'metawiki', 'm', false}, incubator = {'incubator', 'incubator', false}, outreach = {'outreach', 'outreach', false}, mediawiki = {'mediawiki', 'mw', false} } local entityid = entity.id or entity local projectdata = projects[project:lower()] if not projectdata then -- defaultlink might be in the form "dewiki" rather than "project: 'wiki', lang: 'de' " for k, v in pairs(projects) do if project:match( k .. '$' ) and mw.language.isKnownLanguageTag(project:sub(1, #project-#k)) then lang = project:sub(1, #project-#k) project = project:sub(#lang + 1, #project) projectdata = projects[project] break end end if not mw.language.isKnownLanguageTag(lang) then return --formatError('invalid-project-code', projet or 'nil') end end if not projectdata then return -- formatError('invalid-project-code', projet or 'nil') end local linkcode = projectdata[1] local prefix = projectdata[2] local multiversion = projectdata[3] if multiversion then linkcode = lang .. linkcode end local link = mw.wikibase.getSitelink(entityid, linkcode) if not link then return nil end if prefix then link = prefix .. ':' .. link end if multiversion then link = ':' .. lang .. ':' .. link end return link, project, lang end -- add new values to a list, avoiding duplicates function wd.addNewValues(olditems, newitems, maxnum, stopval) if not newitems then return olditems end for _, qid in pairs(newitems) do if stopval and (qid == stopval) then table.insert(olditems, qid) return olditems end if maxnum and (#olditems >= maxnum) then return olditems end if not wd.isHere(olditems, qid) then table.insert(olditems, qid) end end return olditems end --=== FILTER CLAIMS ACCORDING TO VARIOUS CRITERIA : FUNCTION GETCLAIMS et alii === local function notSpecial(claim) local type if claim.mainsnak ~= nil then type = claim.mainsnak.snaktype else -- condition respectée quand showonlyqualifier est un paramètre renseigné -- dans ce cas, claim n'est pas une déclaration entière, mais UNE snak qualifiée du main snak type = claim.snaktype end return type == 'value' end local function hasTargetValue(claim, targets) -- retourne true si la valeur est dans la liste des target, ou si c'est une valeur spéciale filtrée séparément par excludespecial local id = wd.getMainId(claim) local targets = wd.splitStr(targets) return wd.isHere(targets, id) or wd.isSpecial(claim.mainsnak) end local function excludeValues(claim, values) -- true si la valeur n'est pas dans la liste, ou si c'est une valeur spéciale (filtrée à part par excludespecial) return wd.isSpecial(claim.mainsnak) or not ( hasTargetValue(claim, values) ) 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 withRank(claims, target) if target == 'best' then return bestRanked(claims) end local newclaims = {} for pos, claim in pairs(claims) do if target == 'valid' then if claim.rank ~= 'deprecated' then table.insert(newclaims, claim) end elseif claim.rank == target then table.insert(newclaims, claim) end end return newclaims end function wd.hasQualifier(claim, acceptedqualifs, acceptedvals, excludequalifiervalues) local claimqualifs = claim.qualifiers if (not claimqualifs) then return false end acceptedqualifs = wd.splitStr(acceptedqualifs) acceptedvals = wd.splitStr( acceptedvals) local function ok(qualif) -- vérification pour un qualificatif individuel if not claimqualifs[qualif] then return false end if not (acceptedvals) then -- si aucune valeur spécifique n'est demandée, OK return true end for i, wanted in pairs(acceptedvals) do for j, actual in pairs(claimqualifs[qualif]) do if wd.getId(actual) == wanted then return true end end end end for i, qualif in pairs(acceptedqualifs) do if ok(qualif) then return true end end return false end function wd.hasQualifierNumber(claim, acceptedqualifs, acceptedvals, excludequalifiervalues) local claimqualifs = claim.qualifiers if (not claimqualifs) then return false end acceptedqualifs = wd.splitStr(acceptedqualifs) acceptedvals = wd.splitStr( acceptedvals) local function ok(qualif) -- vérification pour un qualificatif individuel if not claimqualifs[qualif] then return false end if not (acceptedvals) then -- si aucune valeur spécifique n'est demandée, OK return true end for i, wanted in pairs(acceptedvals) do for j, actual in pairs(claimqualifs[qualif]) do if mw.wikibase.renderSnak(actual) == wanted then return true end end end end for i, qualif in pairs(acceptedqualifs) do if ok(qualif) then return true end end return false end local function hasSource(claim, targetsource, sourceproperty) sourceproperty = sourceproperty or 'P248' if targetsource == "-" then return true end if (not claim.references) then return false end local candidates = claim.references[1].snaks[sourceproperty] -- les snaks utilisant la propriété demandée if (not candidates) then return false end if (targetsource == "any") then -- si n'importe quelle valeur est acceptée tant qu'elle utilise en ref la propriété demandée return true end targetsource = wd.splitStr(targetsource) for _, source in pairs(candidates) do local s = wd.getId(source) for i, target in pairs(targetsource) do if s == target then return true end end end return false end local function excludeQualifier(claim, qualifier, qualifiervalues) return not wd.hasQualifier(claim, qualifier, qualifiervalues) end function wd.hasDate(claim) if not claim then return false --error() ? end if wd.getDateFromQualif(claim, 'P585') or wd.getDateFromQualif(claim, 'P580') or wd.getDateFromQualif(claim, 'P582') then return true end return false end local function hasLink(claim, site, lang) if (claim.mainsnak.snaktype ~= 'value') then -- ne pas supprimer les valeurs spéciales, il y a une fonction dédiée pour ça return true end local id = wd.getMainId(claim) local link = wd.siteLink(id, site, lang) if link then return true end end local function isInLanguage(claim, lang) -- ne fonctionne que pour les monolingualtext / étendre aux autres types en utilisant les qualifiers ? if type(lang) == 'table' then -- si c'est une table de language séparées par des virgules, on les accepte toutes for i, l in pairs(lang) do local v = isInLanguage(claim, l) if v then return true end end end if type(lang) ~= ('string') then return --? end if (lang == '-') then return true end if (lang == 'locallang') then lang = mw.getContentLanguage():getCode() end -- pour les monolingual text local snak = claim.mainsnak or claim if snak.snaktype == 'value' and snak.datavalue.type == 'monolingualtext' then if snak.datavalue.value.language == lang then return true end return false end -- pour les autres types de données : recherche dans les qualificatifs if (lang == 'diq') then lang = 'Q150' elseif (lang == 'en') then lang = 'Q1860' else lang = databases.invertedlangcodes[lang] end if claim.qualifiers and claim.qualifiers.P407 then if wd.hasQualifier(claim, {'P407'}, {lang}) then return true else return false end end return true -- si on ne ne sait pas la langue, on condière que c'est bon end local function firstVals(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 not claims then return nil end while (#claims > numval) do table.remove(claims) end return claims end local function lastVals(claims, numval2) -- retourn les valeurs de la table claims à partir de numval2 local numval2 = tonumber(numval2) or 0 -- raise a error if numval is not a positive integer ? if not claims then return nil end for i=1,numval2 do table.remove(claims, 1) end return claims end -- retourne les valeurs de la table claims à partir de removedupesdate, -- sans les dates en doublons avec conversion entre les calendrier julien et grégorien, -- ou uniquement en catégorisant si le paramètre removedupesdate est égale à 'cat' local function removeDupesDate(claims, removedupesdate) if not claims or #claims < 2 then return claims, '' end local cat = '' local newClaims = {} local newIsos = {} local function findIndex(searchset, val) -- similaire à wd.isHere mais retourne l'index de la valeur trouvée for i, j in pairs(searchset) do if val == j then return i end end return -1 end for _, claim in ipairs( claims ) do local snak = claim.mainsnak or claim if (snak.snaktype == 'value') and (snak.datatype == 'time') and snak.datavalue.value.precision >= 11 then -- s'il s'agit d'un time et que la précision est au moins l'année local iso = snak.datavalue.value.time _, _, iso = string.find(iso, "(+%d+-%d+-%d+T)") local deleteIfDuplicate = false if snak.datavalue.value.calendarmodel == 'http://www.wikidata.org/entity/Q1985727' then -- si la date est grégorienne if modules.formatDate.before('+1582', iso) then -- si avant 1582 on calcule la date julienne _, _, y, m, d = string.find(iso, "+(%d+)-(%d+)-(%d+)T") y, m , d = modules.datemodule.gregorianToJulian(y, m , d) if m < 10 then m = '0' .. m end if d < 10 then d = '0' .. d end iso = '+' .. y .. '-' .. m .. '-' .. d .. 'T' deleteIfDuplicate = true end local index = findIndex(newIsos, iso) if index >= 0 then -- si la date est déjà présente cat = cat .. '[[Catégorie:Article avec des dates identiques venant de wikidata dans le code de l\'infobox]]' if removedupesdate == "cat" then -- ne faire que catégoriser table.insert(newIsos, iso) table.insert(newClaims, claim) elseif not deleteIfDuplicate then -- supprimer l'autre date si la date courante n'a pas été convertie newClaims[index] = claim end -- sinon supprimer la date courante else -- pas de doublon table.insert(newIsos, iso) table.insert(newClaims, claim) end elseif snak.datavalue.value.calendarmodel == 'http://www.wikidata.org/entity/Q1985786' then -- si date julienne if not modules.formatDate.before('+1582', iso) then -- si après 1582 on calcule la date grégorienne _, _, y, m, d = string.find(iso, "+(%d+)-(%d+)-(%d+)T") y, m , d = modules.datemodule.julianToGregorian(y, m , d) if m < 10 then m = '0' .. m end if d < 10 then d = '0' .. d end iso = '+' .. y .. '-' .. m .. '-' .. d .. 'T' deleteIfDuplicate = true end local index = findIndex(newIsos, iso) if index >= 0 then -- si date déjà présente cat = cat .. '[[Catégorie:Article avec des dates identiques venant de wikidata dans le code de l\'infobox]]' if removedupesdate == "cat" then -- ne faire que catégoriser table.insert(newIsos, iso) table.insert(newClaims, claim) elseif not deleteIfDuplicate then -- supprimer l'autre date si la date courante n'a pas été convertie newClaims[index] = claim end -- sinon supprimer la date courante else -- pas de doublon table.insert(newIsos, iso) table.insert(newClaims, claim) end else -- autre calendrier table.insert(newIsos, iso) table.insert(newClaims, claim) end else -- précision insuffisante table.insert(newIsos, iso) table.insert(newClaims, claim) end end return newClaims, cat end local function timeFromQualifs(claim, qualifs) local claimqualifs = claim.qualifiers if not claimqualifs then return nil end for i, qualif in ipairs(qualifs or datequalifiers) do local vals = claimqualifs[qualif] if vals and (vals[1].snaktype == 'value') then return vals[1].datavalue.value.time, vals[1].datavalue.value.precision end end end local function atDate(claim, mydate) if mydate == "today" then mydate = os.date("!%Y-%m-%dT%TZ") end -- determines required precision depending on the atdate format local d = mw.text.split(mydate, "-") local myprecision if d[3] then myprecision = 11 -- day elseif d[2] then myprecision = 10 -- month else myprecision = 9 -- year end -- with point in time local d, storedprecision = timeFromQualifs(claim, {'P585'}) if d then return modules.formatDate.equal(mydate, d, math.min(myprecision, storedprecision)) end -- with start or end date -- TODO: precision local mindate = timeFromQualifs(claim, {'P580'}) local maxdate = timeFromQualifs(claim, {'P582'}) if modules.formatDate.before(mydate, mindate) and modules.formatDate.before(maxdate, mydate) then return true end return false end local function check(claim, condition) if type(condition) == 'function' then -- cas standard return condition(claim) end return formatError('invalid type', 'function', type(condition)) end local function minPrecision(claim, minprecision) local snak if claim.qualifiers then -- si une date est donnée en qualificatif, c'est elle qu'on utilise de préférence au mainsnak for i, j in ipairs(datequalifiers) do if claim.qualifiers[j] then snak = claim.qualifiers[j][1] break end end end if not snak then snak = claim.mainsnak or claim end if (snak.snaktype == 'value') and (snak.datatype == 'time') and (snak.datavalue.value.precision < minprecision) then return false end return true end function wd.sortClaims(claims, sorttype) if not claims then return nil end if wd.isHere({'chronological', 'order', 'inverted', 'age', 'ageinverted'}, sorttype) then return wd.chronoSort(claims, sorttype) elseif sorttype == 'ascending' then return wd.quantitySort(claims) elseif sorttype == 'descending' then return wd.quantitySort(claims, true) elseif type(sorttype) == 'function' then table.sort(claims, sorttype) return claims elseif type(sorttype) == 'string' and sorttype:sub(1, 1) == 'P' then return wd.numericPropertySort(claims, sorttype) end return claims end function wd.filterClaims(claims, args) --retire de la tables de claims celles qui sont éliminés par un des filters de la table des filters local function filter(condition, filterfunction, funargs) if not args[condition] then return end for i = #claims, 1, -1 do if not( filterfunction(claims[i], args[funargs[1]], args[funargs[2]], args[funargs[3]]) ) then table.remove(claims, i) end end end filter('isinlang', isInLanguage, {'isinlang'} ) filter('excludespecial', notSpecial, {} ) filter('condition', check, {'condition'} ) if claims[1] and claims[1].mainsnak then filter('targetvalue', hasTargetValue, {'targetvalue'} ) filter('atdate', atDate, {'atdate'} ) filter('qualifier', wd.hasQualifier, {'qualifier', 'qualifiervalue'} ) filter('qualifiernumber', wd.hasQualifierNumber, {'qualifiernumber', 'qualifiernumbervalue'} ) filter('excludequalifier', excludeQualifier, {'excludequalifier', 'excludequalifiervalue'} ) filter('withsource', hasSource, {'withsource', 'sourceproperty'} ) filter('withdate', wd.hasDate, {} ) filter('excludevalues', excludeValues, {'excludevalues'}) filter('withlink', hasLink, {'withlink', 'linklang'} ) filter('minprecision', minPrecision, {'minprecision'} ) claims = withRank(claims, args.rank or 'best') end if #claims == 0 then return nil end if args.sorttype then claims = wd.sortClaims(claims, args.sorttype) end if args.numval2 then claims = lastVals(claims, args.numval2) end if args.numval then claims = firstVals(claims, args.numval) end return claims end function wd.loadEntity(entity, cache) if type(entity) ~= 'table' then if cache then if not cache[entity] then cache[entity] = mw.wikibase.getEntity(entity) mw.log("cached") end return cache[entity] else if entity == '' or (entity == '-') then entity = nil end return mw.wikibase.getEntity(entity) end else return entity end end function wd.getClaims( args ) -- returns a table of the claims matching some conditions given in args if args.claims then -- if claims have already been set, return them return args.claims end local properties = args.property if type(properties) == 'string' then properties = wd.splitStr(string.upper(args.property)) end if not properties then return formatError( 'property-param-not-provided' ) end --Get entity local entity = args.entity if type(entity) == 'string' then if entity == '' then entity = nil end elseif type(entity) == 'table' then entity = entity.id end if (not entity) then entity = mw.wikibase.getEntityIdForCurrentPage() end if (not entity) or (entity == '-') or (entity == wd.translate('somevalue')) or (entity == modules.linguistic.ucfirst(wd.translate('somevalue'))) then return nil end if args.labelformat and args.labelformat == 'gendered' then local longgender = {m = 'male', f = 'female'} args.labelformat = longgender[wd.getgender(entity)] end local claims = {} if #properties == 1 then claims = mw.wikibase.getAllStatements(entity, properties[1]) -- do not use mw.wikibase.getBestStatements at this stage, as it may remove the best ranked values that match other criteria in the query else for i, prop in ipairs(properties) do local newclaims = mw.wikibase.getAllStatements(entity, prop) if newclaims and #newclaims > 0 then for j, claim in ipairs(newclaims) do table.insert(claims, claim) end end end end if (not claims) or (#claims == 0) then return nil end return wd.filterClaims(claims, args) end --=== ENTITY FORMATTING === function wd.getLabel(entity, lang1, lang2) if (not entity) then return nil -- ou option de gestion des erreurs ? end entity = entity.id or ( type(entity) == "string" and entity) if not(type(entity) == 'string') then return nil end lang1 = lang1 or defaultlang local str, lang --str : texte rendu, lang : langue de celui-ci if lang1 == defaultlang then -- le plus économique str, lang = mw.wikibase.getLabelWithLang(entity) -- le libellé peut être en français ou en anglais else str = mw.wikibase.getLabelByLang(entity, lang1) if str then lang = lang1 end end if str and (lang == lang1) then --pas de catégorie "à traduire" si on a obtenu un texte dans la langue désirée (normalement fr) return str end if lang2 then -- langue secondaire, avec catégorie "à traduire" str2 = mw.wikibase.getLabelByLang(entity, lang2) if str2 then lang = lang2 str = str2 end end if not str then --si ni lang1, ni lang2 ni l'anglais ne sont présents, parcours de la hiérarchie des langues for _, trylang in ipairs(databases.langhierarchy.codes) do str = mw.wikibase.getLabelByLang(entity, trylang) if str then lang = trylang break end end end if str then local translationCat = databases.i18n['to translate'] translationCat = translationCat .. (databases.langhierarchy.cattext[lang] or '') translationCat = addCat(translationCat) return str, translationCat end end function wd.formatEntity( entity, params ) if (not entity) then return nil --formatError('entity-not-found') end local id = entity if type(id) == 'table' then id = id.id end params = params or {} local lang = params.lang or defaultlang local speciallabels = params.speciallabels local displayformat = params.displayformat local labelformat = params.labelformat local labelformat2 = params.labelformat2 local defaultlabel = params.defaultlabel or id local linktype = params.link local defaultlink = params.defaultlink local defaultlinkquery = params.defaultlinkquery if speciallabels and speciallabels[id] then --speciallabels override the standard label + link combination return speciallabels[id] end if params.displayformat == 'raw' then return id end if params.labelformat == 'male' then labelformat = function(objectid) return wd.genderedlabel(objectid, 'm') end end if params.labelformat == 'female' then labelformat = function(objectid) return wd.genderedlabel(objectid, 'f') end end local link, label, translationCat if type(labelformat) == 'function' then -- sert à des cas particuliers label, translationCat = labelformat(entity) end if not label then label, translationCat = wd.getLabel(entity, lang, params.wikidatalang) end translationCat = translationCat or "" -- sera toujours ajoutée au résultat mais sera vide si la catégorie de maintenance n'est pas nécessaire if type(labelformat2) == 'function' then -- sert à des cas particuliers label = labelformat2(label) end -- détermination du fait qu'on soit ou non en train de rendre l'élément sur la page de son article local rendering_entity_on_its_page = wd.isPageOfQId(id) if not label then if (defaultlabel == '-') then return nil end link = wd.siteLink(id, 'wikidata') return '[[' .. link .. '|' .. id .. ']]' .. translationCat -- si pas de libellé, on met un lien vers Wikidata pour qu'on comprenne à quoi ça fait référence end if (linktype == '-') or rendering_entity_on_its_page then return label .. translationCat end local link = wd.siteLink(entity, linktype, lang) -- defaultlinkquery will try to link to another page on this Wiki if (not link) and defaultlinkquery then if type(defaultlinkquery) == 'string' then defaultlinkquery = {property = defaultlinkquery} end defaultlinkquery.excludespecial = true defaultlinkquery.entity = entity local claims = wd.getClaims(defaultlinkquery) if claims then for i, j in pairs(claims) do local id = wd.getMainId(j) link = wd.siteLink(id, linktype, lang) if link then break end end end end if link then if mw.ustring.sub(link, 1, 9) == "Category:" or mw.ustring.sub(link, 1, 10) == "Catégorie:" then link = ":" .. link --lier vers une catégorie au lieu de catégoriser end return '[[' .. link .. '|' .. label .. ']]' .. translationCat end -- if not link, you can use defaultlink: a sidelink to another Wikimedia project if (not defaultlink) then defaultlink = {'enwiki'} end if defaultlink and (defaultlink ~= '-') then local linktype local sidelink, site, langcode if type(defaultlink) == 'string' then defaultlink = {defaultlink} end for i, j in ipairs(defaultlink) do sidelink, site, langcode = wd.siteLink(entity, j, lang) if sidelink then break end end if not sidelink then sidelink, site = wd.siteLink(entity, 'wikidata') end local icon, class, title = site, nil, nil -- le texte affiché du lien if site == 'wiki' then icon, class, title = langcode, "indicateur-langue", wd.translate('see-another-language', mw.language.fetchLanguageName(langcode, defaultlang)) elseif site == 'wikidata' then icon, class, title = 'd', "indicateur-langue", wd.translate('see-wikidata') else title = wd.translate('see-another-project', site) end local val = '[[' .. sidelink .. '|' .. '<span class = "' .. (class or '').. '" title = "' .. (title or '') .. '">' .. icon .. '</span>]]' return label .. ' <small>(' .. val .. ')</small>' .. translationCat end return label .. translationCat end function wd.addTrackingCat(prop, cat) -- doit parfois être appelé par d'autres modules if type(prop) == 'table' then prop = prop[1] -- devrait logiquement toutes les ajouter end if not prop and not cat then return formatError("property-param-not-provided") end if not cat then cat = wd.translate('trackingcat', prop or 'P??') end return addCat(cat ) end local function unknownValue(snak, label) local str = label if type(str) == "function" then str = str(snak) end if (not str) then if snak.datatype == 'time' then str = wd.translate('sometime') else str = wd.translate('somevalue') end end if type(str) ~= "string" then return formatError(snak.datatype) end return str end local function noValue(displayformat) if not displayformat then return wd.translate('novalue') end if type(displayformat) == 'string' then return displayformat end return formatError() end local function getLangCode(entityid) return databases.langcodes[tonumber(entityid:sub(2))] end local function showLang(statement, maxLang) -- retourne le code langue entre paranthèse avant la valeur (par exemple pour les biblios et liens externes) local mainsnak = statement.mainsnak if mainsnak.snaktype ~= 'value' then return nil end local langlist = {} if mainsnak.datavalue.type == 'monolingualtext' then langlist = {mainsnak.datavalue.value.language} elseif (not statement.qualifiers) or (not statement.qualifiers.P407) then return else for i, j in pairs( statement.qualifiers.P407 ) do if j.snaktype == 'value' then local langentity = wd.getId(j) local langcode = getLangCode(langentity) table.insert(langlist, langcode) end end end if (#langlist > 1) or (#langlist == 1 and langlist[1] ~= defaultlang) then -- si c'est en français, pas besoin de le dire langlist.maxLang = maxLang return modules.langmodule.indicationMultilingue(langlist) end end -- === DATE HANDLING === local function fuzzydate(str, precision) -- ajoute le qualificatif "vers" à une date if not str then return nil end if (precision >= 11) or (precision == 7) or (precision == 6) then --dates avec jour, siècles, millénaires return "vers le " .. str end if (precision == 8) then --décennies ("années ...") return "vers les " .. str end return "vers " .. str end function wd.addStandardQualifs(str, statement) if (not statement) or (not statement.qualifiers) then return str end if not str then return error()-- what's that ? end if statement.qualifiers.P1480 then for i, j in pairs(statement.qualifiers.P1480) do local v = wd.getId(j) if (v == "Q21818619") then str = wd.translate('approximate-place', str) elseif (v == "Q18122778") or (v == "Q18912752") or (v == "Q56644435") or (v == "Q30230067") then str = wd.translate('uncertain-information', str) elseif (v == "Q5727902") then if (statement.mainsnak.datatype == 'time') then local datevalue = statement.mainsnak.datavalue if datevalue then str = fuzzydate(str, datevalue.value.precision) end else str = wd.translate('approximate-value', str) end end end end return str end local function rangeObject(begin, ending, params) --[[ objet comportant un timestamp pour le classement chronologique et deux dateobject (begin et ending) ]]-- local timestamp if begin then timestamp = begin.timestamp else 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 {type = 'dateobject', timestamp = str, era = '+' ou '-', year = number, month = number, day = number, calendar = calendar} ]]-- if not params then params = {} end local newobj = modules.formatDate.splitDate(orig.time, orig.calendarmodel) newobj.precision = params.precision or orig.precision newobj.type = 'dateobject' return newobj end local function objectToText(obj, params) if obj.type == 'dateobject' then return modules.formatDate.simplestring(obj, params) elseif obj.type == 'rangeobject' then return modules.formatDate.daterange(obj.begin, obj.ending, params) end end function wd.getDateFromQualif(statement, qualif) if (not statement) or (not statement.qualifiers) or not (statement.qualifiers[qualif]) then return nil end local v = statement.qualifiers[qualif][1] if v.snaktype ~= 'value' then -- que faire dans ce cas ? return nil end return dateObject(v.datavalue.value) end function wd.getDate(statement) local period = wd.getDateFromQualif(statement, 'P585') -- retourne un dateobject if period then return period end local begin, ending = wd.getDateFromQualif(statement, 'P580'), wd.getDateFromQualif(statement, 'P582') if begin or ending then return rangeObject(begin, ending) -- retourne un rangeobject fait de deux dateobject end return nil end function wd.getFormattedDate(statement, params) if not statement then return nil end local str --cherche la date avec les qualifs P580/P582 local datetable = wd.getDate(statement) if datetable then str = objectToText(datetable, params) end -- puis limite intérieur / supérieur if not str then local start, ending = wd.getDateFromQualif(statement, 'P1319'), wd.getDateFromQualif(statement, 'P1326') str = modules.formatDate.between(start, ending, params) end -- sinon, le mainsnak, pour les données de type time if (not str) and (statement.mainsnak.datatype == 'time') then local mainsnak = statement.mainsnak if (mainsnak.snaktype == 'value') or (mainsnak.snaktype == 'somevalue') then str = wd.formatSnak(mainsnak, params) end end if str and params and (params.addstandardqualifs ~= '-') then str = wd.addStandardQualifs(str, statement) end return str end wd.compare.by_quantity = function(c1, c2) local v1 = wd.getDataValue(c1.mainsnak) local v2 = wd.getDataValue(c2.mainsnak) if not (v1 and v2) then return true end return v1 < v2 end --[[ tri chronologique générique : retourne une fonction de tri de liste de déclaration en fonction d’une fonction qui calcule la clé de tri et d’une fonction qui compare les clés de tri paramètres nommés: (appel type wikidata.compare.chrono_key_sort{sortKey="nom clé"}) sortKey (optionnel) : chaine, le nom de la clé utilisée pour un tri (pour éviter de rentrer en collision avec "dateSortKey" utilisé par chronoSort au besoin) snak_key_get_function : fonction qui calcule la valeur de la clé à partir d’un snak ou d’une déclaration, (obligatoire) le résultat n’est calculé qu’une fois et est stocké en cache dans claim[sortKey] key_compare_function : fonction de comparaison des clés calculées par snak_key_get_function (optionnel) --]] function wd.chrono_key_sort(arg) local snak_key_get_function = arg.snak_key_get_function local sortKey = arg.sortKey or "dateSortKey" local key_compare_function = arg.key_compare_function or function(c1, c2) return c1 < c2 end return function(claims) for _, claim in ipairs( claims ) do if not claim[sortKey] then local key = snak_key_get_function(claim) if key then claim[sortKey] = wd.compare.get_claim_date(key) else claim[sortKey] = 0 end end end table.sort( claims, function(c1, c2) return key_compare_function(c1[sortKey], c2[sortKey]) end ) return claims end end function wd.quantitySort(claims, inverted) local function sort(c1, c2) local v1 = wd.getDataValue(c1.mainsnak) local v2 = wd.getDataValue(c2.mainsnak) if not (v1 and v2) then return true end if inverted then return v2 < v1 end return v1 < v2 end table.sort(claims, sort ) return claims end function wd.compare.get_claim_date(claim, datetype) -- rend une date au format numérique pour faire des comparaisons local snak = claim.mainsnak or claim if datetype and datetype == 'personbirthdate' then -- fonctionne avec un claim dont la valeur est une personne dont on va rendre la date de naissance if (snak.snaktype == 'value') and (snak.datatype == 'wikibase-item') then local personid = wd.getId(snak) local birthclaims = wd.getClaims({ entity = personid, property = 'P569', numval = 1}) if birthclaims then return wd.compare.get_claim_date(birthclaims[1] or birthclaims) else return math.huge end else return math.huge end -- en cas de donnée manquante, valeur infinie qui entraîne le classement en fin de liste end local iso, datequalif, isonumber if (snak.snaktype == 'value') and (snak.datatype == 'time') then iso = snak.datavalue.value.time else for i, dqualif in ipairs(datequalifiers) do iso = timeFromQualifs(claim, {dqualif}) if iso then datequalif = dqualif break end end if not iso then return math.huge end end -- transformation en nombre (indication de la base car gsub retourne deux valeurs) isonumber = tonumber( iso:gsub( '(%d)%D', '%1' ), 10 ) -- ajustement de la date tenant compte du qualificatif dont elle est issue : un fait se terminant à une date est antérieur à un autre commençant à cette date if datequalif == 'P582' then --date de fin isonumber = isonumber - 2 elseif datequalif == 'P1326' then -- date au plus tard isonumber = isonumber - 1 elseif datequalif == 'P1319' then -- date au plus tôt isonumber = isonumber + 1 elseif datequalif == 'P571' or datequalif == 'P580' then -- date de début et date de création isonumber = isonumber + 2 end return isonumber end function wd.compare.chronoCompare(c1, c2) return wd.compare.get_claim_date(c1) < wd.compare.get_claim_date(c2) end -- fonction pour renverser l’ordre d’une autre fonction function wd.compare.rev(comp_criteria) return function(c1, c2) -- attention les tris en lua attendent des fonctions de comparaison strictement inférieur, on doit -- vérifier la non égalité quand on inverse l’ordre d’un critère, d’ou "and comp_criteria(c2,c1)" return not(comp_criteria(c1,c2)) and comp_criteria(c2,c1) end end -- Fonction qui trie des Claims de type time selon l'ordre chronologique -- Une clé de tri nomée « dateSortKey » est ajouté à chaque claim. -- Si des clés de tri de ce nom existent déjà, elles sont utilisées sans modification. function wd.chronoSort( claims, sorttype ) for _, claim in ipairs( claims ) do if not claim.dateSortKey then if sorttype and (sorttype == 'age' or sorttype == 'ageinverted') then claim.dateSortKey = wd.compare.get_claim_date(claim, 'personbirthdate') else claim.dateSortKey = wd.compare.get_claim_date(claim) end if sorttype and (sorttype == 'inverted' or sorttype == 'ageinverted') and claim.dateSortKey == math.huge then claim.dateSortKey = -math.huge -- quand la donnée est manquante on lui assigne la valeur qui entraîne le classement en fin de liste end end end table.sort( claims, function ( c1, c2 ) if sorttype and (sorttype == 'inverted' or sorttype == 'ageinverted') then return c2.dateSortKey < c1.dateSortKey end return c1.dateSortKey < c2.dateSortKey end ) return claims end local function get_numeric_claim_value(claim, propertySort) local val local claimqualifs = claim.qualifiers if claimqualifs then local vals = claimqualifs[propertySort] if vals and vals[1].snaktype == 'value' then val = vals[1].datavalue.value end end return tonumber(val or 0) end function wd.compare.numeric(propertySort) return function(c1, c2) return get_numeric_claim_value(c1, propertySort) < get_numeric_claim_value(c2, propertySort) end end -- Fonction qui trie des Claims de type value selon l'ordre de la propriété fournit -- Une clé de tri nomée « dateSortKey » est ajouté à chaque claim. -- Si des clés de tri de ce nom existent déjà, elles sont utilisées sans modification. function wd.numericPropertySort( claims, propertySort ) for _, claim in ipairs( claims ) do if not claim.dateSortKey then local val = get_numeric_claim_value(claim, propertySort) claim.dateSortKey = tonumber(val or 0) end end table.sort( claims, function ( c1, c2 ) return c1.dateSortKey < c2.dateSortKey end ) return claims end --[[ test possible en console pour la fonction précédente : = p.formatStatements{entity = "Q375946", property = 'P50', sorttype = 'P1545', linkback = "true"} --]] -- =================== function wd.getReferences(statement) local refdata = statement.references if not refdata then return nil end local refs = {} local hashes = {} for i, ref in pairs(refdata) do local s local function hasValue(prop) -- checks that the prop is here with valid value if ref.snaks[prop] and ref.snaks[prop][1].snaktype == 'value' then return true end return false end if ref.snaks.P248 then -- cas lorsque P248 (affirmé dans) est utilisé for j, source in pairs(ref.snaks.P248) do if source.snaktype == 'value' then local page, accessdate, quotation if hasValue('P304') then -- page page = wd.formatSnak(ref.snaks.P304[1]) end if hasValue('P813') then -- date de consultation accessdate = wd.formatSnak(ref.snaks.P813[1]) end if hasValue('P1683') then -- citation quotation = wd.formatSnak(ref.snaks.P1683[1]) end local sourceId = wd.getId(source) s = modules.reference.citeitem(sourceId, {['page'] = page, ['accessdate'] = accessdate, ['citation'] = quotation}) table.insert(refs, s) table.insert(hashes, ref.hash .. sourceId) end end elseif hasValue('P8091') or hasValue('P854') then -- cas lorsque P8091 (Archival Resource Key) ou P854 (URL de la référence)est utilisé local arkKey, url, title, author, publisher, accessdate, publishdate, publishlang, quotation, description if hasValue('P8091') then arkKey = wd.formatSnak(ref.snaks.P8091[1], {text = "-"}) url = 'https://n2t.net/' .. arkKey if hasValue('P1476') then title = wd.formatSnak(ref.snaks.P1476[1]) else title = arkKey end elseif hasValue('P854') then url = wd.formatSnak(ref.snaks.P854[1], {text = "-"}) if hasValue('P1476') then title = wd.formatSnak(ref.snaks.P1476[1]) else title = mw.ustring.gsub(url, '^[Hh][Tt][Tt][Pp]([Ss]?):(/?)([^/])', 'http%1://%3') end end --todo : handle multiple values for author, etc. if hasValue('P1810') then -- sous le nom description = 'sous le nom ' .. wd.formatSnak(ref.snaks.P1810[1]) end if hasValue('P813') then -- date de consultation accessdate = wd.formatSnak(ref.snaks.P813[1]) end if hasValue('P50') then -- author (item type) author = wd.formatSnak(ref.snaks.P50[1]) elseif hasValue('P2093') then -- author (string type) author = wd.formatSnak(ref.snaks.P2093[1]) end if hasValue('P123') then -- éditeur publisher = wd.formatSnak(ref.snaks.P123[1]) end if hasValue('P1683') then -- citation quotation = wd.formatSnak(ref.snaks.P1683[1]) end if hasValue('P577') then -- date de publication publishdate = wd.formatSnak(ref.snaks.P577[1]) end if hasValue('P407') then -- langue de l'œuvre local id = wd.getId(ref.snaks.P407[1]) publishlang = getLangCode(id) end s = modules.cite.lienWeb{titre = title, url = url, auteur = author, editeur = publisher, langue = publishlang, ['en ligne le'] = publishdate, ['consulté le'] = accessdate, ['citation'] = quotation, ['description'] = description} table.insert(hashes, ref.hash) table.insert(refs, s) elseif ref.snaks.P854 and ref.snaks.P854[1].snaktype == 'value' then s = wd.formatSnak(ref.snaks.P854[1], {text = "-"}) table.insert(hashes, ref.snaks.P854[1].hash) table.insert(refs, s) end end if #refs > 0 then if #hashes == #refs then return refs, hashes end return refs end end function wd.sourceStr(sources, hashes) if not sources or (#sources == 0) then return nil end local useHashes = hashes and #hashes == #sources for i, j in ipairs(sources) do local refArgs = {name = 'ref', content = j} if useHashes and hashes[i] ~= '-' then refArgs.args = {name = 'wikidata-' .. hashes[i]} end sources[i] = mw.getCurrentFrame():extensionTag(refArgs) end return table.concat(sources, '<sup class="reference cite_virgule">,</sup>') end function wd.getDataValue(snak, params) if not params then params = {} end local speciallabels = params.speciallabels -- parfois on a besoin de faire une liste d'éléments pour lequel le libellé doit être changé, pas très pratique d'utiliser une fonction pour ça if snak.snaktype ~= 'value' then return nil end local datatype = snak.datatype local value = snak.datavalue.value local displayformat = params.displayformat if type(displayformat) == 'function' then return displayformat(snak, params) end if datatype == 'wikibase-item' then return wd.formatEntity(wd.getId(snak), params) end if datatype == 'url' then if params.displayformat == 'raw' then return value else return modules.weblink.makelink(value, params.text) end end if datatype == 'math' then return mw.getCurrentFrame():extensionTag( "math", value) end if datatype == 'tabular-data' then return mw.ustring.sub(value, 6, 100) -- returns the name of the file, without the "Data:" prefix end if (datatype == 'string') or (datatype == 'external-id') or (datatype == 'commonsMedia') then -- toutes les données de type string sauf "math" if params.urlpattern then local urlpattern = params.urlpattern if type(urlpattern) == 'function' then urlpattern = urlpattern(value) end -- encodage de l'identifiant qui se retrouve dans le path de l'URL, à l'exception des slashes parfois rencontrés, qui sont des séparateurs à ne pas encoder local encodedValue = mw.uri.encode(value, 'PATH'):gsub('%%2F', '/') -- les parenthèses autour du encodedValue:gsub() sont nécessaires, sinon sa 2e valeur de retour est aussi passée en argument au mw.ustring.gsub() parent local url = mw.ustring.gsub(urlpattern, '$1', (encodedValue:gsub('%%', '%%%%'))) value = '[' .. url .. ' ' .. (params.text or value) .. ']' end return value end if datatype == 'time' then -- format example: +00000001809-02-12T00:00:00Z if displayformat == 'raw' then return value.time else local dateobject = dateObject(value, {precision = params.precision}) return objectToText(dateobject, params) end end if datatype == 'globe-coordinate' 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 else local coordvalue = mw.clone( value ) coordvalue.globe = databases.globes[value.globe] -- transforme l'ID du globe en nom anglais utilisable par geohack return coordvalue -- note : les coordonnées Wikidata peuvent être utilisée depuis Module:Coordinates. Faut-il aussi autoriser à appeler Module:Coordiantes ici ? end end if datatype == 'quantity' then -- todo : gérer les paramètres précision local amount, unit = value.amount, value.unit if unit then unit = unit:match('Q%d+') end if not unit then unit = 'hebi' end local raw if displayformat == "raw" then raw = true end return modules.formatNum.displayvalue(amount, unit, {targetunit = params.targetunit, raw = raw, rounding = params.rounding, showunit = params.showunit or 'short', showlink = params.showlink} ) end if datatype == 'monolingualtext' then if value.language == defaultlang then return value.text else return modules.langmodule.langue({value.language, value.text, nocat=true}) end end return formatError('unknown-datavalue-type' ) end function wd.stringTable(args) -- like getClaims, but get a list of string rather than a list of snaks, for easier manipulation local claims = args.claims local cat = '' if not claims then claims = wd.getClaims(args) end if not claims or claims == {} then return {}, {}, cat end if args.removedupesdate and (args.removedupesdate ~= '-') then claims, cat = removeDupesDate(claims, args.removedupesdate) end local props = {} -- liste des propriétés associété à chaque string pour catégorisation et linkback for i, j in pairs(claims) do claims[i] = wd.formatStatement(j, args) table.insert(props, j.mainsnak.property) end if args.removedupes and (args.removedupes ~= '-') then claims = wd.addNewValues({}, claims) -- devrait aussi supprimer de props celles qui ne sont pas utilisées end return claims, props, cat end function wd.getQualifiers(statement, qualifs, params) if not statement.qualifiers then return nil end local vals = {} if type(qualifs) == 'string' then qualifs = wd.splitStr(qualifs) end for i, j in pairs(qualifs) do if statement.qualifiers[j] then for k, l in pairs(statement.qualifiers[j]) do table.insert(vals, l) end end end if #vals == 0 then return nil end return vals end function wd.getFormattedQualifiers(statement, qualifs, params) if not params then params = {} end local qualiftable = wd.getQualifiers(statement, qualifs) if not qualiftable then return nil end qualiftable = wd.filterClaims(qualiftable, params) or {} for i, j in pairs(qualiftable) do qualiftable[i] = wd.formatSnak(j, params) end return modules.linguistic.conj(qualiftable, params.conjtype) end function wd.showQualifiers(str, statement, args) local qualifs = args.showqualifiers if not qualifs then return str -- or error ? end if type(qualifs) == 'string' then qualifs = wd.splitStr(qualifs) end local qualifargs = args.qualifargs or {} -- formatage des qualificatifs = args commençant par "qualif", ou à défaut, les mêmes que pour la valeur principale qualifargs.displayformat = args.qualifdisplayformat or args.displayformat qualifargs.labelformat = args.qualiflabelformat or args.labelformat qualifargs.labelformat2 = args.qualiflabelformat2 or args.labelformat2 qualifargs.link = args.qualiflink or args.link qualifargs.linktopic = args.qualiflinktopic or args.linktopic qualifargs.conjtype = args.qualifconjtype qualifargs.precision = args.qualifprecision qualifargs.targetunit = args.qualiftargetunit qualifargs.defaultlink = args.qualifdefaultlink or args.defaultlink qualifargs.defaultlinkquery = args.qualifdefaultlinkquery or args.defaultlinkquery local formattedqualifs if args.qualifformat and type (args.qualifformat) == 'function' then formattedqualifs = args.qualifformat(statement, qualifs, qualifargs) else formattedqualifs = wd.getFormattedQualifiers(statement, qualifs, qualifargs) end if formattedqualifs and formattedqualifs ~= "" then str = str .. " (" .. formattedqualifs .. ")" end return str end function wd.formatSnak( snak, params ) if not params then params = {} end -- pour faciliter l'appel depuis d'autres modules if snak.snaktype == 'somevalue' then return unknownValue(snak, params.unknownlabel) elseif snak.snaktype == 'novalue' then return noValue(params.novaluelabel) elseif snak.snaktype == 'value' then return wd.getDataValue( snak, params) else return formatError( 'unknown-snak-type' ) end end function wd.formatStatement( statement, args ) -- FONCTION A REORGANISER (pas très lisible) if not args then args = {} end if not statement.type or statement.type ~= 'statement' then return formatError( 'unknown-claim-type' ) end local prop = statement.mainsnak.property local str -- special displayformat f if args.statementformat and (type(args.statementformat) == 'function') then str = args.statementformat(statement, args) elseif (statement.mainsnak.datatype == 'time') and (statement.mainsnak.dateformat ~= '-') then if args.displayformat == 'raw' and statement.mainsnak.snaktype == 'value' then str = statement.mainsnak.datavalue.value.time else str = wd.getFormattedDate(statement, args) end elseif args.showonlyqualifier and (args.showonlyqualifier ~= '') then str = wd.getFormattedQualifiers(statement, args.showonlyqualifier, args) if not str then return nil end if args.addstandardqualifs ~= '-' then str = wd.addStandardQualifs(str, statement) end else str = wd.formatSnak( statement.mainsnak, args ) if (args.addstandardqualifs ~= '-') and (args.displayformat ~= 'raw') then str = wd.addStandardQualifs(str, statement) end end -- ajouts divers if args.showlang == true then local indicateur = showLang(statement, args.maxLang) if indicateur then str = indicateur .. '&nbsp;' .. str end end if args.showqualifiers then str = wd.showQualifiers(str, statement, args) end if args.showdate then -- when "showdate and chronosort are both set, date retrieval is performed twice local period = wd.getFormattedDate(statement, args, "-") -- 3 arguments indicate the we should not use additional qualifiers, alrady added by wd.formatStatement if period then str = str .. " <small>(" .. period .. ")</small>" end end if args.showsource and args.showsource ~= '-' then local sources, hashes = wd.getReferences(statement) if sources then local source = wd.sourceStr(sources, hashes) if source then str = str .. source end end end return str end function wd.addLinkBack(str, id, property) if not id or id == '' then id = wd.getEntityIdForCurrentPage() end if not id then return str end if type(property) == 'table' then property = property[1] end id = wd.entityId(id) local class = '' if property then class = 'wd_' .. string.lower(property) end local icon = '[[File:Blue pencil.svg|%s|10px|baseline|class=noviewer|link=%s]]' local title = wd.translate('see-wikidata-value') local url = mw.uri.fullUrl('d:' .. id, 'uselang=fr') url.fragment = property -- ajoute une #ancre si paramètre "property" défini url = tostring(url) local v = mw.html.create('span') :addClass(class) :wikitext(str) :tag('span') :addClass('noprint wikidata-linkback') :wikitext(icon:format(title, url)) :allDone() return tostring(v) end function wd.addRefAnchor(str, id) --[[ Insère une ancre pour une référence générée à partir d'un élément wd. L'id Wikidata sert d'identifiant à l'ancre, à utiliser dans les modèles type "harvsp" --]] return tostring( mw.html.create('span') :attr('id', id) :attr('class', "ouvrage") :wikitext(str) ) end --=== FUNCTIONS USING AN ENTITY AS ARGUMENT === local function formatStatementsGrouped(args, type) -- regroupe les affirmations ayant la même valeur en mainsnak, mais des qualificatifs différents -- (seulement pour les propriétés de type élément) local claims = wd.getClaims(args) if not claims then return nil end local groupedClaims = {} -- regroupe les affirmations par valeur de mainsnak local function addClaim(claim) local id = wd.getMainId(claim) for i, j in pairs(groupedClaims) do if (j.id == id) then table.insert(groupedClaims[i].claims, claim) return end end table.insert(groupedClaims, {id = id, claims = {claim}}) end for i, claim in pairs(claims) do addClaim(claim) end local stringTable = {} -- instructions ad hoc pour les paramètres concernant la mise en forme d'une déclaration individuelle local funs = { {param = "showqualifiers", fun = function(str, claims) local qualifs = {} for i, claim in pairs(claims) do local news = wd.getFormattedQualifiers(claim, args.showqualifiers, args) if news then table.insert(qualifs, news) end end local qualifstr = modules.linguistic.conj(qualifs, wd.translate("qualif-separator")) if qualifstr and qualifstr ~= "" then str = str .. " (" .. qualifstr .. ")" end return str end }, {param = "showdate", fun = function(str, claims) -- toutes les dates sont regroupées à l'intérieur des mêmes parenthèses ex "médaille d'or (1922, 1924)" local dates = {} for i, statement in pairs(claims) do local s = wd.getFormattedDate(statement, args, true) if statement then table.insert(dates, s) end end local datestr = modules.linguistic.conj(dates) if datestr and datestr ~= "" then str = str .. " <small>(" .. datestr .. ")</small>" end return str end }, {param = "showsource", fun = function(str, claims) -- les sources sont toutes affichées au même endroit, à la fin -- si deux affirmations ont la même source, on ne l'affiche qu'une fois local sources = {} local hashes = {} local function dupeRef(old, new) for i, j in pairs(old) do if j == new then return true end end end for i, claim in pairs(claims) do local refs, refHashes = wd.getReferences(claim) if refs then for i, j in pairs(refs) do if not dupeRef(sources, j) then table.insert(sources, j) local hash = (refHashes and refHashes[i]) or '-' table.insert(hashes, hash) end end end end return str .. (wd.sourceStr(sources, hashes) or "") end } } for i, group in pairs(groupedClaims) do -- bricolage pour utiliser les arguments de formatStatements local str = wd.formatEntity(group.id, args) if not str then str = '???' -- pour éviter erreur Lua si formatEntity a retourné nil end for i, fun in pairs(funs) do if args[fun.param] then str = fun.fun(str, group.claims, args) end end table.insert(stringTable, str) end args.valuetable = stringTable return wd.formatStatements(args) end function wd.formatStatements( args )--Format statement and concat them cleanly if args.value == '-' then return nil end -- If a value is already set: use it, except if it's the special value {{WD}} (use wikidata) if args.value and args.value ~= '' then local valueexpl = wd.translate("activate-query") if args.value ~= valueexpl then return args.value end -- There is no value set, and args.expl disables wikidata on empty values elseif args.expl then return nil end if args.grouped and args.grouped ~= '' then args.grouped = false return formatStatementsGrouped(args) end local valuetable = args.valuetable -- dans le cas où les valeurs sont déjà formatées local props -- les prorpriétés réellement utilisées (dans certains cas, ce ne sont pas toutes celles de args.property local cat = '' if not valuetable then -- cas le plus courant valuetable, props, cat = wd.stringTable(args) end if args.ucfirst == '-' and args.conjtype == 'new line' then args.conjtype = 'lowercase new line' end local str = modules.linguistic.conj(valuetable, args.conjtype) if not str then return args.default end if not props then props = wd.splitStr(args.property)[1] end if args.ucfirst ~= '-' then str = modules.linguistic.ucfirst(str) end if args.addcat and (args.addcat ~= '-') then str = str .. wd.addTrackingCat(props) .. cat end if args.linkback and (args.linkback ~= '-') then str = wd.addLinkBack(str, args.entity, props) end if args.returnnumberofvalues then return str, #valuetable end return str end function wd.formatAndCat(args) if not args then return nil end args.linkback = args.linkback or true args.addcat = true if args.value then -- do not ignore linkback and addcat, as formatStatements do if args.value == '' then return nil end local val = args.value .. wd.addTrackingCat(args.property) val = wd.addLinkBack(val, args.entity, args.property) return val end return wd.formatStatements( args ) end function wd.getTheDate(args) local claims = wd.getClaims(args) if not claims then return nil end local formattedvalues = {} for i, j in pairs(claims) do local v = wd.getFormattedDate(j, args) if v then table.insert(formattedvalues, v ) end end local val = modules.linguistic.conj(formattedvalues) if not val then return nil end if args.addcat == true then val = val .. wd.addTrackingCat(args.property) end val = wd.addLinkBack(val, args.entity, args.property) return val end function wd.keyDate (event, item, params) params = params or {} params.entity = item if type(event) == 'table' then for i, j in pairs(event) do params.targetvalue = nil -- réinitialisation barbare des paramètres modifiés local s = wd.keyDate(j, item, params) if s then return s end end elseif type(event) ~= 'string' then return formatError('invalid-datatype', type(event), 'string') elseif string.sub(event, 1, 1) == 'Q' then -- on demande un élément utilisé dans P:P793 (événement clé) params.property = 'P793' params.targetvalue = event params.addcat = params.addcat or true return wd.getTheDate(params) elseif string.sub(event, 1, 1) == 'P' then -- on demande une propriété params.property = event return wd.formatAndCat(params) else return formatError('invalid-entity-id', event) end end function wd.mainDate(entity) -- essaye P580/P582 local args = {entity = entity, addcat = true} args.property = 'P580' local startpoint = wd.formatStatements(args) args.property = 'P582' local endpoint = wd.formatStatements(args) local str if (startpoint or endpoint) then str = modules.formatDate.daterange(startpoint, endpoint, params) str = wd.addLinkBack(str, entity, 'P582') return str end -- défaut : P585 args.property = {'P585', 'P571'} args.linkback = true return wd.formatStatements(args) end -- ==== Fonctions sur le genre ==== function wd.getgender(id) local vals = { ['Q6581072'] = 'f', -- féminin ['Q6581097'] = 'm', -- masculin ['Q1052281'] = 'f', -- femme transgenre ['Q2449503'] = 'm', -- homme transgenre ['Q17148251'] = 'f', -- en:Travesti (gender identity) ['Q43445'] = 'f', -- femelle ['Q44148'] = 'm', -- mâle default = '?' } local gender = wd.formatStatements{entity = id, property = 'P21', displayformat = 'raw', numval = 1} return vals[gender] or vals.default end -- catégories de genre/nombre function wd.getgendernum(claims) local personid, gender local anym = false local anyf = false local anyunknown = false for i, claim in pairs(claims) do local snak = claim.mainsnak or claim if(snak.snaktype == 'value') and (snak.datatype == 'wikibase-item') then personid = wd.getId(snak) gender = wd.getgender(personid) anym = anym or (gender == 'm') anyf = anyf or (gender == 'f') anyunknown = anyunknown or (gender == '?') else anyunknown = true end end local gendernum if #claims > 1 then if anyunknown then gendernum = 'p' else if anym and not anyf then gendernum = 'mp' end if anyf and not anym then gendernum = 'fp' end if anym and anyf then gendernum = 'mixtep' end end else gendernum = 's' if anym then gendernum = 'ms' end if anyf then gendernum = 'fs' end end return gendernum end -- récupération des libellés genrés de Wikidata function wd.genderedlabel(id, labelgender) local label if not labelgender then return nil end if labelgender == 'f' then -- femme : chercher le libellé dans P2521 (libellé féminin) label = wd.formatStatements{entity = id, property = 'P2521', isinlang = 'diq', numval = 1, ucfirst = '-'} elseif labelgender == 'm' then -- homme : chercher le libellé dans P3321 (libellé masculin) label = wd.formatStatements{entity = id, property = 'P3321', isinlang = 'diq', numval = 1, ucfirst = '-'} end if not label then label = wd.getLabel(id) end return label end -- === FUNCTIONS FOR TRANSITIVE PROPERTIES === function wd.getIds(item, query) query.excludespecial = true query.displayformat = 'raw' query.entity = item query.addstandardqualifs = '-' return wd.stringTable(query) end -- recursively adds a list of qid to an existing list, based on the results of a query function wd.addVals(list, query, maxdepth, maxnodes, stopval) maxdepth = tonumber(maxdepth) or 10 maxnodes = tonumber(maxnodes) or 100 if (maxdepth < 0) then return list end if stopval and wd.isHere(list, stopval) then return list end local origsize = #list for i = 1, origsize do -- tried a "checkpos" param instead of starting to 1 each time, but no impact on performance local candidates = wd.getIds(list[i], query) list = wd.addNewValues(list, candidates, maxnodes, stopval) if list[#list] == stopval then return list end if #list >= maxnodes then return list end end if (#list == origsize) then return list end return wd.addVals(list, query, maxdepth - 1, maxnodes, stopval, origsize + 1) end -- returns a list of items transitively matching a query (orig item is not included in the list) function wd.transitiveVals(item, query, maxdepth, maxnodes, stopval) maxdepth = tonumber(maxdepth) or 5 if type(query) == "string" then query = {property = query} end -- récupération des valeurs local vals = wd.getIds(item, query) if not vals then return nil end local v = wd.addVals(vals, query, maxdepth - 1, maxnodes, stopval) if not v then return nil end -- réarrangement des valeurs if query.valorder == "inverted" then local a = {} for i = #v, 1, -1 do a[#a+1] = v[i] end v = a end return v end -- returns true if an item is the value of a query, transitively function wd.inTransitiveVals(searchedval, sourceval, query, maxdepth, maxnodes ) local vals = wd.transitiveVals(sourceval, query, maxdepth, maxnodes, searchedval ) if (not vals) then return false end for _, val in ipairs(vals) do if (val == searchedval) then return true end end return false end -- returns true if an item is a superclass of another, based on P279 function wd.isSubclass(class, item, maxdepth) local query = {property = 'P279'} if class == item then -- item is a subclass of itself iff it is a class if wd.getIds(item, query) then return true end return false end return wd.inTransitiveVals(class, item, query, maxdepth ) end -- returns true if one of the best ranked P31 values of an item is the target or a subclass of the target -- rank = 'valid' would seem to make sense, but it would need to check for date qualifiers as some P31 values have begin or end date function wd.isInstance(targetclass, item, maxdepth) maxdepth = maxdepth or 10 local directclasses = wd.transitiveVals(item, {property = 'P31'}, 1) if not directclasses then return false end for i, class in pairs(directclasses) do if wd.isSubclass(targetclass, class, maxdepth - 1) then return true end end return false end -- return the first value in a transitive query that belongs to a particular class. For instance find a value of P131 that is a province of Canada function wd.findVal(sourceitem, targetclass, query, recursion, instancedepth) if type(query) == "string" then query = {property = query} end local candidates = wd.getIds(sourceitem, query) if candidates then for i, j in pairs(candidates) do if wd.isInstance(targetclass, j, instancedepth) then return j end end if not recursion then recursion = 3 else recursion = recursion - 1 end if recursion < 0 then return nil end for i, candidate in pairs(candidates) do return wd.findVal(candidate, targetclass, query, recursion, instancedepth) end end end -- === VARIA === function wd.getDescription(entity, lang) lang = lang or defaultlang local description if lang == defaultlang then return mw.wikibase.description(qid) end if not entity.descriptions then return wd.translate('no description') end local descriptions = entity.descriptions if not descriptions then return nil end if descriptions[lang] then return descriptions[delang].value end return entity.id end function wd.Dump(entity) entity = wd.getEntity(entity) if not entity then return formatError("entity-param-not-provided") end return "<pre>"..mw.dumpObject(entity).."</pre>" end function wd.frameFun(frame) local args = frame.args local funname = args[1] table.remove(args, 1) return wd[funname](args) end return wd 9skrfjlt6xfp3u49khjzmos7vcq4orj 549193 549192 2026-06-22T07:23:27Z Mirzali 16 Vurnayışê hesabê 549192 ke terefê [[Karber:Mirzali|Mirzali]] ra peyser gêriyayo. 549193 Scribunto text/plain --script that retrieves basic data stored in Wikidata, for the datamodel, see https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua local wd = {} local modules = { } local modulesNames = { reference = 'Module:Wikidata/Références', i18n = 'Module:Wikidata/I18n', globes = 'Module:Wikidata/Globes', langcodes = 'Module:Dictionnaire Wikidata/Codes langue', -- big, infrequently useda invertedlangcodes = 'Module:Dictionnaire Wikidata/Codes langue/inversé', linguistic = 'Module:Linguistique', formatDate = 'Module:Date complexe', formatNum = 'Module:Conversion', langmodule = 'Module:Langue', cite = 'Module:Biblio', weblink = 'Module:Weblink' } local function loadModule( t, key ) if modulesNames[key] then local m = require( modulesNames[key] ) t[key] = m return m end end setmetatable( modules, { __index = loadModule } ) local datequalifiers = {'P585', 'P571', 'P580', 'P582', 'P1319', 'P1326'} -- === I18n === local defaultlang = mw.getContentLanguage():getCode() function wd.translate(str, rep1, rep2) str = modules.i18n[str] or str if rep1 and (type (rep1) == 'string') then str = str:gsub('$1', rep1) end if rep2 and (type (rep2) == 'string')then str = str:gsub('$2', rep2) end return str end local function addCat(cat, sortkey) if sortkey then return '[[Category:' .. cat .. '|' .. sortkey .. ']]' end return '[[Category:' .. cat .. ']]' end local function formatError( key , category, debug) if debug then return error(modules.i18n[key] or key) end if category then return addCat(category, key) else return addCat('cat-unsorted-issue', key) end end -- function wd.isSpecial(snak) return (snak.snaktype ~= 'value') end function wd.getId(snak) if (snak.snaktype == 'value') then return 'Q' .. snak.datavalue.value['numeric-id'] end end function wd.getNumericId(snak) if (snak.snaktype == 'value') then return snak.datavalue.value['numeric-id'] end end function wd.getMainId(claim) return wd.getId(claim.mainsnak) end function wd.entityId(entity) if type(entity) == 'string' then return entity elseif type(entity) == 'table' then return entity.id end end function wd.getEntityIdForCurrentPage() return mw.wikibase.getEntityIdForCurrentPage() end -- function that returns true if the "qid" parameter is the qid -- of the item that is linked to the calling page function wd.isPageOfQId(qid) local self_id = mw.wikibase.getEntityIdForCurrentPage() return self_id ~= nil and qid == self_id end function wd.getEntity( val ) if type(val) == 'table' then return val end if val == '-' then return nil end if val == '' then val = nil end return mw.wikibase.getEntity(val) end function wd.splitStr(val) -- transforme en table les chaînes venant du Wikitexte qui utilisent des virgules de séparation if type(val) == 'string' then val = mw.text.split(val, ",") end return val end function wd.isHere(searchset, val) for i, j in pairs(searchset) do if val == j then return true end end return false end local function wikidataLink(entity) local name =':d:' if type(entity) == 'string' then if entity:match("P[0-9+]") then entity = "Property:" .. entity end return name .. entity elseif type(entity) == 'table' then if entity["type"] == "property" then name = ":d:Property:" end return name .. entity.id elseif type(entity) == nil then return formatError('entity-not-found') end end function wd.siteLink(entity, project, lang) -- returns 3 values: a sitelink (with the relevant prefix) a project name and a language lang = lang or defaultlang if (type(project) ~= 'string') then project = 'wiki' end project = project:lower() if project == 'wikipedia' then project = 'wiki' end if type(entity) == 'string' and (project == 'wiki') and ( (not lang or lang == defaultlang) ) then -- évite de charger l'élément entier return mw.wikibase.sitelink(entity), 'wiki', defaultlang end if project == 'wikidata' then return wikidataLink(entity), 'wikidata' end local projects = { -- nom = {préfixe sur Wikidata, préfix pour les liens sur Wikipédia, ajouter préfixe de langue} wiki = {'wiki', nil, true}, -- wikipedia commons = {'commonswiki', 'commons', false}, commonswiki = {'commonswiki', 'commons', false}, wikiquote = {'wikiquote', 'q', true}, wikivoyage = {'wikivoyage', 'voy', true}, wikibooks = {'wikibooks', 'b', true}, wikinews = {'wikinews', 'n', true}, wikiversity = {'wikiversity', 'v', true}, wikisource = {'wikisource', 's', true}, wiktionary = {'wiktionary', 'wikt', true}, specieswiki = {'specieswiki', 'species', false}, metawiki = {'metawiki', 'm', false}, incubator = {'incubator', 'incubator', false}, outreach = {'outreach', 'outreach', false}, mediawiki = {'mediawiki', 'mw', false} } local entityid = entity.id or entity local projectdata = projects[project:lower()] if not projectdata then -- defaultlink might be in the form "enwiki" rather than "project: 'wiki', lang: 'en' " for k, v in pairs(projects) do if project:match( k .. '$' ) and mw.language.isKnownLanguageTag(project:sub(1, #project-#k)) then lang = project:sub(1, #project-#k) project = project:sub(#lang + 1, #project) projectdata = projects[project] break end end if not mw.language.isKnownLanguageTag(lang) then return --formatError('invalid-project-code', projet or 'nil') end end if not projectdata then return -- formatError('invalid-project-code', projet or 'nil') end local linkcode = projectdata[1] local prefix = projectdata[2] local multiversion = projectdata[3] if multiversion then linkcode = lang .. linkcode end local link = mw.wikibase.getSitelink(entityid, linkcode) if not link then return nil end if prefix then link = prefix .. ':' .. link end if multiversion then link = ':' .. lang .. ':' .. link end return link, project, lang end -- add new values to a list, avoiding duplicates function wd.addNewValues(olditems, newitems, maxnum, stopval) if not newitems then return olditems end for _, qid in pairs(newitems) do if stopval and (qid == stopval) then table.insert(olditems, qid) return olditems end if maxnum and (#olditems >= maxnum) then return olditems end if not wd.isHere(olditems, qid) then table.insert(olditems, qid) end end return olditems end --=== FILTER CLAIMS ACCORDING TO VARIOUS CRITERIA : FUNCTION GETCLAIMS et alii === local function notSpecial(claim) local type if claim.mainsnak ~= nil then type = claim.mainsnak.snaktype else -- condition respectée quand showonlyqualifier est un paramètre renseigné -- dans ce cas, claim n'est pas une déclaration entière, mais UNE snak qualifiée du main snak type = claim.snaktype end return type == 'value' end local function hasTargetValue(claim, targets) -- retourne true si la valeur est dans la liste des target, ou si c'est une valeur spéciale filtrée séparément par excludespecial local id = wd.getMainId(claim) local targets = wd.splitStr(targets) return wd.isHere(targets, id) or wd.isSpecial(claim.mainsnak) end local function excludeValues(claim, values) -- true si la valeur n'est pas dans la liste, ou si c'est une valeur spéciale (filtrée à part par excludespecial) return wd.isSpecial(claim.mainsnak) or not ( hasTargetValue(claim, values) ) 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 withRank(claims, target) if target == 'best' then return bestRanked(claims) end local newclaims = {} for pos, claim in pairs(claims) do if target == 'valid' then if claim.rank ~= 'deprecated' then table.insert(newclaims, claim) end elseif claim.rank == target then table.insert(newclaims, claim) end end return newclaims end function wd.hasQualifier(claim, acceptedqualifs, acceptedvals, excludequalifiervalues) local claimqualifs = claim.qualifiers if (not claimqualifs) then return false end acceptedqualifs = wd.splitStr(acceptedqualifs) acceptedvals = wd.splitStr( acceptedvals) local function ok(qualif) -- vérification pour un qualificatif individuel if not claimqualifs[qualif] then return false end if not (acceptedvals) then -- si aucune valeur spécifique n'est demandée, OK return true end for i, wanted in pairs(acceptedvals) do for j, actual in pairs(claimqualifs[qualif]) do if wd.getId(actual) == wanted then return true end end end end for i, qualif in pairs(acceptedqualifs) do if ok(qualif) then return true end end return false end function wd.hasQualifierNumber(claim, acceptedqualifs, acceptedvals, excludequalifiervalues) local claimqualifs = claim.qualifiers if (not claimqualifs) then return false end acceptedqualifs = wd.splitStr(acceptedqualifs) acceptedvals = wd.splitStr( acceptedvals) local function ok(qualif) -- vérification pour un qualificatif individuel if not claimqualifs[qualif] then return false end if not (acceptedvals) then -- si aucune valeur spécifique n'est demandée, OK return true end for i, wanted in pairs(acceptedvals) do for j, actual in pairs(claimqualifs[qualif]) do if mw.wikibase.renderSnak(actual) == wanted then return true end end end end for i, qualif in pairs(acceptedqualifs) do if ok(qualif) then return true end end return false end local function hasSource(claim, targetsource, sourceproperty) sourceproperty = sourceproperty or 'P248' if targetsource == "-" then return true end if (not claim.references) then return false end local candidates = claim.references[1].snaks[sourceproperty] -- les snaks utilisant la propriété demandée if (not candidates) then return false end if (targetsource == "any") then -- si n'importe quelle valeur est acceptée tant qu'elle utilise en ref la propriété demandée return true end targetsource = wd.splitStr(targetsource) for _, source in pairs(candidates) do local s = wd.getId(source) for i, target in pairs(targetsource) do if s == target then return true end end end return false end local function excludeQualifier(claim, qualifier, qualifiervalues) return not wd.hasQualifier(claim, qualifier, qualifiervalues) end function wd.hasDate(claim) if not claim then return false --error() ? end if wd.getDateFromQualif(claim, 'P585') or wd.getDateFromQualif(claim, 'P580') or wd.getDateFromQualif(claim, 'P582') then return true end return false end local function hasLink(claim, site, lang) if (claim.mainsnak.snaktype ~= 'value') then -- ne pas supprimer les valeurs spéciales, il y a une fonction dédiée pour ça return true end local id = wd.getMainId(claim) local link = wd.siteLink(id, site, lang) if link then return true end end local function isInLanguage(claim, lang) -- ne fonctionne que pour les monolingualtext / étendre aux autres types en utilisant les qualifiers ? if type(lang) == 'table' then -- si c'est une table de language séparées par des virgules, on les accepte toutes for i, l in pairs(lang) do local v = isInLanguage(claim, l) if v then return true end end end if type(lang) ~= ('string') then return --? end if (lang == '-') then return true end if (lang == 'locallang') then lang = mw.getContentLanguage():getCode() end -- pour les monolingual text local snak = claim.mainsnak or claim if snak.snaktype == 'value' and snak.datavalue.type == 'monolingualtext' then if snak.datavalue.value.language == lang then return true end return false end -- pour les autres types de données : recherche dans les qualificatifs if (lang == 'diq') then lang = 'Q150' elseif (lang == 'en') then lang = 'Q1860' else lang = invertedlangcodes[lang] end if claim.qualifiers and claim.qualifiers.P407 then if wd.hasQualifier(claim, {'P407'}, {lang}) then return true else return false end end return true -- si on ne ne sait pas la langue, on condière que c'est bon end local function firstVals(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 not claims then return nil end while (#claims > numval) do table.remove(claims) end return claims end local function lastVals(claims, numval2) -- retourn les valeurs de la table claims à partir de numval2 local numval2 = tonumber(numval2) or 0 -- raise a error if numval is not a positive integer ? if not claims then return nil end for i=1,numval2 do table.remove(claims, 1) end return claims end local function timeFromQualifs(claim, qualifs) local claimqualifs = claim.qualifiers if not claimqualifs then return nil end for i, qualif in pairs(qualifs or timequalifiers) do local vals = claimqualifs[qualif] if vals and (vals[1].snaktype == 'value') then return vals[1].datavalue.value.time end end end local function atDate(claim, mydate, precision) if mydate == "today" then mydate = os.date("!%Y-%m-%dT%TZ") end -- with point in time local d = timeFromQualifs(claim, {'P585'}) if d then return modules.formatDate.equal(mydate, d, precision) end -- with start or end date local mindate = timeFromQualifs(claim, {'P580'}) local maxdate = timeFromQualifs(claim, {'P582'}) if modules.formatDate.before(mydate, mindate) and modules.formatDate.before(maxdate, mydate) then return true end return false end local function check(claim, condition) if type(condition) == 'function' then -- cas standard return condition(claim) end return formatError('invalid type', 'function', type(condition)) end local function minPrecision(claim, minprecision) local snack if claim.qualifiers then -- si une date est donnée en qualificatif, c'est elle qu'on utilise de préférence au mainsnak for i, j in ipairs(datequalifiers) do if claim.qualifiers[j] then snack = claim.qualifiers[j][1] break end end end if not snack then snack = claim.mainsnak or claim end if (snack.snaktype == 'value') and (snack.datatype == 'time') and (snack.datavalue.value.precision < minprecision) then return false end return true end function wd.sortClaims(claims, sorttype) if not claims then return nil end if sorttype == 'chronological' then return wd.chronoSort(claims) elseif sorttype == 'inverted' then return wd.chronoSort(claims, true) elseif sorttype == 'order' then return wd.chronoSort(claims) elseif type(sorttype) == 'function' then table.sort(claims, sorttype) return claims elseif type(sorttype) == 'string' and sorttype:sub(1, 1) == 'P' then return wd.numericPropertySort(claims, sorttype) end return claims end local alreadyFiltered = false function wd.filterClaims(claims, args) --retire de la tables de claims celles qui sont éliminés par un des filters de la table des filters local function filter(condition, filterfunction, funargs) if not args[condition] then return end for i = #claims, 1, -1 do if not( filterfunction(claims[i], args[funargs[1]], args[funargs[2]], args[funargs[3]]) ) then table.remove(claims, i) end end end filter('isinlang', isInLanguage, {'isinlang'} ) filter('excludespecial', notSpecial, {} ) filter('condition', check, {'condition'} ) if claims[1] and claims[1].mainsnak then filter('targetvalue', hasTargetValue, {'targetvalue'} ) filter('atdate', atDate, {'atdate'} ) filter('qualifier', wd.hasQualifier, {'qualifier', 'qualifiervalue'} ) filter('qualifiernumber', wd.hasQualifierNumber, {'qualifiernumber', 'qualifiernumbervalue'} ) filter('excludequalifier', excludeQualifier, {'excludequalifier', 'excludequalifiervalue'} ) filter('withsource', hasSource, {'withsource', 'sourceproperty'} ) filter('withdate', wd.hasDate, {} ) filter('excludevalues', excludeValues, {'excludevalues'}) filter('withlink', hasLink, {'withlink', 'linklang'} ) filter('minprecision', minPrecision, {'minprecision'} ) claims = withRank(claims, args.rank or 'best') end if args.sorttype then claims = wd.sortClaims(claims, args.sorttype) end if #claims == 0 then return nil end if args.numval2 then claims = lastVals(claims, args.numval2) end if args.numval then claims = firstVals(claims, args.numval) end return claims end function wd.loadEntity(entity, cache) if type(entity) ~= 'table' then if cache then if not cache[entity] then cache[entity] = mw.wikibase.getEntity(entity) mw.log("cached") end return cache[entity] else if entity == '' or (entity == '-') then entity = nil end return mw.wikibase.getEntity(entity) end else return entity end end function wd.getClaims( args ) -- returns a table of the claims matching some conditions given in args if args.claims then -- if claims have already been set, return them return args.claims end local properties = args.property if type(properties) == 'string' then properties = wd.splitStr(string.upper(args.property)) end if not properties then return formatError( 'property-param-not-provided' ) end --Get entity local entity = args.entity if type(entity) == 'string' then if entity == '' then entity = nil end elseif type(entity) == 'table' then entity = entity.id end if (not entity) then entity = mw.wikibase.getEntityIdForCurrentPage() end if (not entity) or (entity == '-') then return nil end local claims = {} if #properties == 1 then claims = mw.wikibase.getAllStatements(entity, properties[1]) -- do not use mw.wikibase.getBestStatements at this stage, as it may remove the best ranked values that match other criteria in the query else for i, prop in ipairs(properties) do local newclaims = mw.wikibase.getAllStatements(entity, prop) if newclaims and #newclaims > 0 then for j, claim in ipairs(newclaims) do table.insert(claims, claim) end end end end if (not claims) or (#claims == 0) then return nil end return wd.filterClaims(claims, args) end --=== ENTITY FORMATTING === function wd.getLabel(entity, lang, labelformat) if (not entity) then return nil -- ou option de gestion des erreurs ? end lang = lang or defaultlang if type(labelformat) == 'function' then return labelformat(entity) end entity = entity.id or ( type(entity) == "string" and entity) if (type(entity) == 'string') and (lang == defaultlang) then -- le plus économique local str = mw.wikibase.label(entity) if str then -- mw.wikibase.label() ne fonctionne pas avec les redirect https://phabricator.wikimedia.org/T157868 return str end end return mw.wikibase.getLabelByLang(entity, lang) end function wd.formatEntity( entity, params ) if (not entity) then return nil --formatError('entity-not-found') end local id = entity if type(id) == 'table' then id = id.id end params = params or {} local lang = params.lang or defaultlang local speciallabels = params.speciallabels local displayformat = params.displayformat local labelformat = params.labelformat local defaultlabel = params.defaultlabel or id local linktype = params.link local defaultlink = params.defaultlink local defaultlinkquery = params.defaultlinkquery if speciallabels and speciallabels[id] then --speciallabels override the standard label + link combination return speciallabels[id] end if params.displayformat == 'raw' then return id end local link, label label = wd.getLabel(entity, lang, labelformat) -- détermination du fait qu'on soit ou non en train de rendre l'élément sur la page de son article local rendering_entity_on_its_page = wd.isPageOfQId(id) if not label then if (defaultlabel == '-') then return nil end link = wd.siteLink(id, 'wikidata') return '[[' .. link .. '|' .. id .. ']]' .. addCat(modules.i18n['to translate']) -- si pas de libellé, on met un lien vers Wikidata pour qu'on comprenne à quoi ça fait référence end if (linktype == '-') or rendering_entity_on_its_page then return label end local link = wd.siteLink(entity, linktype, lang) -- defaultlinkquery will try to link to another page on this Wiki if (not link) and defaultlinkquery then if type(defaultlinkquery) == 'string' then defaultlinkquery = {property = defaultlinkquery} end defaultlinkquery.excludespecial = true defaultlinkquery.entity = entity local claims = wd.getClaims(defaultlinkquery) if claims then for i, j in pairs(claims) do local id = wd.getMainId(j) link = wd.siteLink(id, linktype, lang) if link then break end end end end if link then return '[[' .. link .. '|' .. label .. ']]' end -- if not link, you can use defaultlink: a sidelink to another Wikimedia project if (not defaultlink) then defaultlink = {'enwiki'} end if defaultlink and (defaultlink ~= '-') then local linktype local sidelink, site, langcode if type(defaultlink) == 'string' then defaultlink = {defaultlink} end for i, j in ipairs(defaultlink) do sidelink, site, langcode = wd.siteLink(entity, j, lang) if sidelink then break end end if not sidelink then sidelink, site = wd.siteLink(entity, 'wikidata') end local icon, class, title = site, nil, nil -- le texte affiché du lien if site == 'wiki' then icon, class, title = langcode, "indicateur-langue", wd.translate('see-another-language', mw.language.fetchLanguageName(langcode, defaultlang)) elseif site == 'wikidata' then icon, class, title = 'd', "indicateur-langue", wd.translate('see-wikidata') else title = wd.translate('see-another-project', site) end local val = '[[' .. sidelink .. '|' .. ']]' return label .. '' end return label end function wd.addTrackingCat(prop, cat) -- doit parfois être appelé par d'autres modules if type(prop) == 'table' then prop = prop[1] -- devrait logiquement toutes les ajouter end if not prop and not cat then return formatError("property-param-not-provided") end if not cat then cat = wd.translate('trackingcat', prop or 'P??') end return addCat(cat ) end local function unknownValue(snak, label) local str = label if type(str) == "function" then str = str(snak) end if (not str) then if snak.datatype == 'time' then str = wd.translate('sometime') else str = wd.translate('somevalue') end end if type(str) ~= "string" then return formatError(snak.datatype) end return str end local function noValue(displayformat) if not displayformat then return wd.translate('novalue') end if type(displayformat) == 'string' then return displayformat end return formatError() end local function getLangCode(entityid) return modules.langcodes[tonumber(entityid:sub(2))] end local function showLang(statement) -- retourne le code langue entre paranthèse avant la valeur (par exemple pour les biblios et liens externes) local mainsnak = statement.mainsnak if mainsnak.snaktype ~= 'value' then return nil end local langlist = {} if mainsnak.datavalue.type == 'monolingualtext' then langlist = {mainsnak.datavalue.value.language} elseif (not statement.qualifiers) or (not statement.qualifiers.P407) then return else for i, j in pairs( statement.qualifiers.P407 ) do if j.snaktype == 'value' then local langentity = wd.getId(j) local langcode = getLangCode(langentity) table.insert(langlist, langcode) end end end if (#langlist > 1) or (#langlist == 1 and langlist[1] ~= defaultlang) then -- si c'est en français, pas besoin de le dire return modules.langmodule.indicationMultilingue(langlist) end end -- === DATE HANDLING === function wd.addStandardQualifs(str, statement) if (not statement) or (not statement.qualifiers) then return str end if not str then return error()-- what's that ? end if statement.qualifiers.P1480 then for i, j in pairs(statement.qualifiers.P1480) do local v = wd.getId(j) if (v == "Q21818619") then str = wd.translate('approximate-place', str) elseif (v == "Q18122778") or (v == "Q18912752") then str = wd.translate('uncertain-information', str) elseif (v == "Q5727902") then if (statement.mainsnak.datatype == 'time') then str = modules.formatDate.fuzzydate(str) else str = wd.translate('approximate-value', str) end end end end return str end local function rangeObject(begin, ending, params) --[[ objet comportant un timestamp pour le classement chronologique et deux dateobject (begin et ending) ]]-- local timestamp if begin then timestamp = begin.timestamp else 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 {type = 'dateobject', timestamp = str, era = '+' ou '-', year = number, month = number, day = number, calendar = calendar} ]]-- if not params then params = {} end local newobj = modules.formatDate.splitDate(orig.time, orig.calendarmodel) newobj.precision = params.precision or orig.precision newobj.type = 'dateobject' return newobj end local function objectToText(obj, params) if obj.type == 'dateobject' then return modules.formatDate.simplestring(obj, params) elseif obj.type == 'rangeobject' then return modules.formatDate.daterange(obj.begin, obj.ending, params) end end function wd.getDateFromQualif(statement, qualif) if (not statement) or (not statement.qualifiers) or not (statement.qualifiers[qualif]) then return nil end local v = statement.qualifiers[qualif][1] if v.snaktype ~= 'value' then -- que faire dans ce cas ? return nil end return dateObject(v.datavalue.value) end function wd.getDate(statement) local period = wd.getDateFromQualif(statement, 'P585') -- retourne un dateobject if period then return period end local begin, ending = wd.getDateFromQualif(statement, 'P580'), wd.getDateFromQualif(statement, 'P582') if begin or ending then return rangeObject(begin, ending) -- retourne un rangeobject fait de deux dateobject end return nil end function wd.getFormattedDate(statement, params) if not statement then return nil end local str --cherche la date avec les qualifs P580/P582 local datetable = wd.getDate(statement) if datetable then str = objectToText(datetable, params) end -- puis limite intérieur / supérieur if not str then local start, ending = wd.getDateFromQualif(statement, 'P1319'), wd.getDateFromQualif(statement, 'P1326') str = modules.formatDate.between(start, ending, params) end -- sinon, le mainsnak, pour les données de type time if (not str) and (statement.mainsnak.datatype == 'time') then local mainsnak = statement.mainsnak if (mainsnak.snaktype == 'value') or (mainsnak.snaktype == 'somevalue') then str = wd.formatSnak(mainsnak, params) end end if str and params and (params.addstandardqualifs ~= '-') then str = wd.addStandardQualifs(str, statement) end return str end -- Fonction qui trie des Claims de type time selon l'ordre chronologique -- Une clé de tri nomée « dateSortKey » est ajouté à chaque claim. -- Si des clés de tri de ce nom existent déjà, elles sont utilisées sans modification. function wd.chronoSort( claims, inverted ) for _, claim in ipairs( claims ) do if not claim.dateSortKey then local snack = claim.mainsnak or claim local iso if (snack.snaktype == 'value') and (snack.datatype == 'time') then iso = snack.datavalue.value.time else iso = timeFromQualifs(claim, datequalifiers) or '0' end -- transformation en nombre (indication de la base car gsub retourne deux valeurs) iso = tonumber( iso:gsub( '(%d)%D', '%1' ), 10 ) claim.dateSortKey = iso end end table.sort( claims, function ( c1, c2 ) if inverted then return c2.dateSortKey < c1.dateSortKey end return c1.dateSortKey < c2.dateSortKey end ) return claims end -- Fonction qui trie des Claims de type value selon l'ordre de la propriété fournit -- Une clé de tri nomée « dateSortKey » est ajouté à chaque claim. -- Si des clés de tri de ce nom existent déjà, elles sont utilisées sans modification. function wd.numericPropertySort( claims, propertySort ) for _, claim in ipairs( claims ) do if not claim.dateSortKey then local val local claimqualifs = claim.qualifiers if claimqualifs then local vals = claimqualifs[propertySort] if vals and vals[1].snaktype == 'value' then val = vals[1].datavalue.value end end claim.dateSortKey = tonumber(val or 0) end end table.sort( claims, function ( c1, c2 ) return c1.dateSortKey < c2.dateSortKey end ) return claims end -- =================== function wd.getReferences(statement) local refdata = statement.references if not refdata then return nil end local refs = {} local hashes = {} for i, ref in pairs(refdata) do local s local function hasValue(prop) -- checks that the prop is here with valid value if ref.snaks[prop] and ref.snaks[prop][1].snaktype == 'value' then return true end return false end if ref.snaks.P248 then -- cas lorsque P248 (affirmé dans) est utilisé for j, source in pairs(ref.snaks.P248) do if source.snaktype == 'value' then local page, accessdate, quotation if hasValue('P304') then -- page page = wd.formatSnak(ref.snaks.P304[1]) end if hasValue('P813') then -- date de consultation accessdate = wd.formatSnak(ref.snaks.P813[1]) end if hasValue('P1683') then -- citation quotation = wd.formatSnak(ref.snaks.P1683[1]) end local sourceId = wd.getId(source) s = modules.reference.citeitem(sourceId, {['page'] = page, ['accessdate'] = accessdate, ['citation'] = quotation}) table.insert(refs, s) table.insert(hashes, ref.hash .. sourceId) end end elseif hasValue('P854') then -- cas lorsque P854 (URL de la référence) est utilisé local url, title, author, publisher, accessdate, publishdate, publishlang, quotation url = wd.formatSnak(ref.snaks.P854[1], {text = "-"}) if hasValue('P1476') then title = wd.formatSnak(ref.snaks.P1476[1]) else title = mw.ustring.gsub(url, '^[Hh][Tt][Tt][Pp]([Ss]?):(/?)([^/])', 'http%1://%3') end --todo : handle multiple values for author, etc. if hasValue('P813') then -- date de consultation accessdate = wd.formatSnak(ref.snaks.P813[1]) end if hasValue('P50') then -- author (item type) author = wd.formatSnak(ref.snaks.P50[1]) elseif hasValue('P2093') then -- author (string type) author = wd.formatSnak(ref.snaks.P2093[1]) end if hasValue('P123') then -- éditeur publisher = wd.formatSnak(ref.snaks.P123[1]) end if hasValue('P1683') then -- citation quotation = wd.formatSnak(ref.snaks.P1683[1]) end if hasValue('P577') then -- date de publication publishdate = wd.formatSnak(ref.snaks.P577[1]) end if hasValue('P407') then -- langue de l'œuvre local id = wd.getId(ref.snaks.P407[1]) publishlang = getLangCode(id) end s = modules.cite.lienWeb{titre = title, url = url, auteur = author, editeur = publisher, langue = publishlang, ['en ligne le'] = publishdate, ['consulté le'] = accessdate, ['citation'] = quotation} table.insert(hashes, ref.hash) table.insert(refs, s) elseif ref.snaks.P854 and ref.snaks.P854[1].snaktype == 'value' then s = wd.formatSnak(ref.snaks.P854[1], {text = "-"}) table.insert(hashes, ref.snaks.P854[1].hash) table.insert(refs, s) end end if #refs > 0 then if #hashes == #refs then return refs, hashes end return refs end end function wd.sourceStr(sources, hashes) if not sources or (#sources == 0) then return nil end local useHashes = hashes and #hashes == #sources for i, j in ipairs(sources) do local refArgs = {name = 'ref', content = j} if useHashes and hashes[i] ~= '-' then refArgs.args = {name = 'wikidata-' .. hashes[i]} end sources[i] = mw.getCurrentFrame():extensionTag(refArgs) end return table.concat(sources) end function wd.getDataValue(snak, params) if not params then params = {} end local speciallabels = params.speciallabels -- parfois on a besoin de faire une liste d'éléments pour lequel le libellé doit être changé, pas très pratique d'utiliser une fonction pour ça if snak.snaktype ~= 'value' then return nil end local datatype = snak.datatype local value = snak.datavalue.value local displayformat = params.displayformat if type(displayformat) == 'function' then return displayformat(snak, params) end if datatype == 'wikibase-item' then return wd.formatEntity(wd.getId(snak), params) end if datatype == 'url' then return modules.weblink.makelink(value, params.text) end if datatype == 'math' then return mw.getCurrentFrame():extensionTag( "math", value) end if (datatype == 'string') or (datatype == 'external-id') or (datatype == 'commonsMedia') then -- toutes les données de type string sauf "math" if params.urlpattern then local urlpattern = params.urlpattern if type(urlpattern) == 'function' then urlpattern = urlpattern(value) end local url = mw.ustring.gsub(urlpattern, '$1', (value:gsub('%%', '%%%%'))):gsub(' ', '%%20') value = '[' .. url .. ' ' .. (params.text or value) .. ']' end return value end if datatype == 'time' then -- format example: +00000001809-02-12T00:00:00Z if displayformat == 'raw' then return value.time else local dateobject = dateObject(value, {precision = params.precision}) return objectToText(dateobject, params) end end if datatype == 'globe-coordinate' 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 else local coordvalue = mw.clone( value ) coordvalue.globe = modules.globes[value.globe] -- transforme l'ID du globe en nom anglais utilisable par geohack return coordvalue -- note : les coordonnées Wikidata peuvent être utilisée depuis Module:Coordinates. Faut-il aussi autoriser à appeler Module:Coordiantes ici ? end end if datatype == 'quantity' then -- todo : gérer les paramètres précision local amount, unit = value.amount, value.unit if unit then unit = unit:match('Q%d+') end local raw if displayformat == "raw" then raw = true end return modules.formatNum.displayvalue(amount, unit, {targetunit = params.targetunit, raw = raw, rounding = params.rounding, showunit = params.showunit or 'short', showlink = params.showlink} ) end if datatype == 'monolingualtext' then if value.language == defaultlang then return value.text else return modules.langmodule.langue({value.language, value.text}) end end return formatError('unknown-datavalue-type' ) end function wd.stringTable(args) -- like getClaims, but get a list of string rather than a list of snaks, for easier manipulation local claims = args.claims if not claims then claims = wd.getClaims(args) end if not claims or claims == {} then return {}, {} end local props = {} -- liste des propriétés associété à chaque string pour catégorisation et linkback for i, j in pairs(claims) do claims[i] = wd.formatStatement(j, args) table.insert(props, j.mainsnak.property) end if args.removedupes and (args.removedupes ~= '-') then claims = wd.addNewValues({}, claims) -- devrait aussi supprimer de props celles qui ne sont pas utilisées end return claims, props end function wd.getQualifiers(statement, qualifs, params) if not statement.qualifiers then return nil end local vals = {} if type(qualifs) == 'string' then qualifs = wd.splitStr(qualifs) end for i, j in pairs(qualifs) do if statement.qualifiers[j] then for k, l in pairs(statement.qualifiers[j]) do table.insert(vals, l) end end end if #vals == 0 then return nil end return vals end function wd.getFormattedQualifiers(statement, qualifs, params) if not params then params = {} end local qualiftable = wd.getQualifiers(statement, qualifs) if not qualiftable then return nil end qualiftable = wd.filterClaims(qualiftable, params) or {} for i, j in pairs(qualiftable) do qualiftable[i] = wd.formatSnak(j, params) end return modules.linguistic.conj(qualiftable, params.conjtype) end function wd.showQualifiers(str, statement, args) local qualifs = args.showqualifiers if not qualifs then return str -- or error ? end if type(qualifs) == 'string' then qualifs = wd.splitStr(qualifs) end local qualifargs = args.qualifargs or {} -- formatage des qualificatifs = args commençant par "qualif", ou à défaut, les mêmes que pour la valeur principale qualifargs.displayformat = args.qualifdisplayformat or args.displayformat qualifargs.labelformat = args.qualiflabelformat or args.labelformat qualifargs.link = args.qualiflink or args.link qualifargs.linktopic = args.qualiflinktopic or args.linktopic qualifargs.conjtype = args.qualifconjtype qualifargs.defaultlink = args.qualifdefaultlink or args.defaultlink qualifargs.defaultlinkquery = args.qualifdefaultlinkquery or args.defaultlinkquery local formattedqualifs = wd.getFormattedQualifiers(statement, qualifs, qualifargs) if formattedqualifs and formattedqualifs ~= "" then str = str .. " (" .. formattedqualifs .. ")" end return str end function wd.formatSnak( snak, params ) if not params then params = {} end -- pour faciliter l'appel depuis d'autres modules if snak.snaktype == 'somevalue' then return unknownValue(snak, params.unknownlabel) elseif snak.snaktype == 'novalue' then return noValue(params.novaluelabel) elseif snak.snaktype == 'value' then return wd.getDataValue( snak, params) else return formatError( 'unknown-snak-type' ) end end function wd.formatStatement( statement, args ) if not args then args = {} end if not statement.type or statement.type ~= 'statement' then return formatError( 'unknown-claim-type' ) end local prop = statement.mainsnak.property local str -- special displayformat f if args.statementformat and (type(args.statementformat) == 'function') then str = args.statementformat(statement, args) elseif (statement.mainsnak.datatype == 'time') and (statement.mainsnak.dateformat ~= '-') then if args.displayformat == 'raw' and statement.mainsnak.snaktype == 'value' then str = statement.mainsnak.datavalue.value.time else str = wd.getFormattedDate(statement, args) end elseif args.showonlyqualifier and (args.showonlyqualifier ~= '') then str = wd.getFormattedQualifiers(statement, args.showonlyqualifier, args) if not str then return nil end if args.addstandardqualifs ~= '-' then str = wd.addStandardQualifs(str, statement) end else str = wd.formatSnak( statement.mainsnak, args ) if args.addstandardqualifs ~= '-' then str = wd.addStandardQualifs(str, statement) end end -- ajouts divers if args.showlang == true then local indicateur = showLang(statement) if indicateur then str = indicateur .. '&nbsp;' .. str end end if args.showqualifiers then str = wd.showQualifiers(str, statement, args) end if args.showdate then -- when "showdate and chronosort are both set, date retrieval is performed twice local period = wd.getFormattedDate(statement, args, "-") -- 3 arguments indicate the we should not use additional qualifiers, alrady added by wd.formatStatement if period then str = str .. " <small>(" .. period .. ")</small>" end end if args.showsource then local sources, hashes = wd.getReferences(statement) if sources then local source = wd.sourceStr(sources, hashes) if source then str = str .. source end end end return str end function wd.addLinkBack(str, id, property) if not id then id = wd.getEntityIdForCurrentPage() end if not id then return str end if type(property) == 'table' then property = property[1] end id = wd.entityId(id) local class = '' if property then class = 'wd_' .. string.lower(property) end local icon = '[[File:Blue pencil.svg|%s|10px|baseline|class=noviewer|link=%s]]' local title = wd.translate('see-wikidata-value') local url = mw.uri.fullUrl('d:' .. id, 'uselang=diq') url.fragment = property -- ajoute une #ancre si paramètre "property" défini url = tostring(url) local v = mw.html.create('span') :addClass(class) :wikitext(str) :tag('span') :addClass('noprint wikidata-linkback') :wikitext(icon:format(title, url)) :allDone() return tostring(v) end function wd.addRefAnchor(str, id) --[[ Insère une ancre pour une référence générée à partir d'un élément wd. L'id Wikidata sert d'identifiant à l'ancre, à utiliser dans les modèles type "harvsp" --]] return tostring( mw.html.create('span') :attr('id', id) :attr('class', "ouvrage") :wikitext(str) ) end --=== FUNCTIONS USING AN ENTITY AS ARGUMENT === local function formatStatementsGrouped(args, type) -- regroupe les affirmations ayant la même valeur en mainsnak, mais des qualificatifs différents -- (seulement pour les propriétés de type élément) local claims = wd.getClaims(args) if not claims then return nil end local groupedClaims = {} -- regroupe les affirmations par valeur de mainsnak local function addClaim(claim) local id = wd.getMainId(claim) for i, j in pairs(groupedClaims) do if (j.id == id) then table.insert(groupedClaims[i].claims, claim) return end end table.insert(groupedClaims, {id = id, claims = {claim}}) end for i, claim in pairs(claims) do addClaim(claim) end local stringTable = {} -- instructions ad hoc pour les paramètres concernant la mise en forme d'une déclaration individuelle local funs = { {param = "showqualifiers", fun = function(str, claims) local qualifs = {} for i, claim in pairs(claims) do local news = wd.getFormattedQualifiers(claim, args.showqualifiers, args) if news then table.insert(qualifs, news) end end local qualifstr = modules.linguistic.conj(qualifs, "qualif-separator") if qualifstr and qualifstr ~= "" then str = str .. " (" .. qualifstr .. ")" end return str end }, {param = "showdate", fun = function(str, claims) -- toutes les dates sont regroupées à l'intérieur des mêmes parenthèses ex "médaille d'or (1922, 1924)" local dates = {} for i, statement in pairs(claims) do local s = wd.getFormattedDate(statement, args, true) if statement then table.insert(dates, s) end end local datestr = modules.linguistic.conj(dates) if datestr and datestr ~= "" then str = str .. " <small>(" .. datestr .. ")</small>" end return str end }, {param = "showsource", fun = function(str, claims) -- les sources sont toutes affichées au même endroit, à la fin -- si deux affirmations ont la même source, on ne l'affiche qu'une fois local sources = {} local hashes = {} local function dupeRef(old, new) for i, j in pairs(old) do if j == new then return true end end end for i, claim in pairs(claims) do local refs, refHashes = wd.getReferences(claim) if refs then for i, j in pairs(refs) do if not dupeRef(sources, j) then table.insert(sources, j) local hash = (refHashes and refHashes[i]) or '-' table.insert(hashes, hash) end end end end return str .. (wd.sourceStr(sources, hashes) or "") end } } for i, group in pairs(groupedClaims) do -- bricolage pour utiliser les arguments de formatStatements local str = wd.formatEntity(group.id, args) for i, fun in pairs(funs) do if args[fun.param] then str = fun.fun(str, group.claims, args) end end table.insert(stringTable, str) end args.valuetable = stringTable return wd.formatStatements(args) end function wd.formatStatements( args )--Format statement and concat them cleanly if args.value == '-' then return nil end -- If a value is already set: use it, except if it's the special value {{WD}} (use wikidata) if args.value and args.value ~= '' then local valueexpl = wd.translate("activate-query") if args.value ~= valueexpl then return args.value end -- There is no value set, and args.expl disables wikidata on empty values elseif args.expl then return nil end if args.grouped and args.grouped ~= '' then args.grouped = false return formatStatementsGrouped(args) end local valuetable = args.valuetable -- dans le cas où les valeurs sont déjà formtées local props -- les prorpriétés réellement utilisées (dans certainse cas, ce ne sont pas toutes celles de ags.property if not valuetable then -- cas le plus courant valuetable, props = wd.stringTable(args) end local str = modules.linguistic.conj(valuetable, args.conjtype) if not str then return args.default end if not props then props = wd.splitStr(args.property)[1] end if args.ucfirst ~= '-' then str = modules.linguistic.ucfirst(str) end if args.addcat and (args.addcat ~= '-') then str = str .. wd.addTrackingCat(props) end if args.linkback and (args.linkback ~= '-') then str = wd.addLinkBack(str, args.entity, props) end if args.returnnumberofvalues then return str, #valuetable end return str end function wd.formatAndCat(args) if not args then return nil end args.linkback = args.linkback or true args.addcat = true if args.value then -- do not ignore linkback and addcat, as formatStatements do if args.value == '-' then return nil end local val = args.value .. wd.addTrackingCat(args.property) val = wd.addLinkBack(val, args.entity, args.property) return val end return wd.formatStatements( args ) end function wd.getTheDate(args) local claims = wd.getClaims(args) if not claims then return nil end local formattedvalues = {} for i, j in pairs(claims) do local v = wd.getFormattedDate(j, args) if v then table.insert(formattedvalues, v ) end end local val = modules.linguistic.conj(formattedvalues) if not val then return nil end if args.addcat == true then val = val .. wd.addTrackingCat(args.property) end val = wd.addLinkBack(val, args.entity, args.property) return val end function wd.keyDate (event, item, params) params = params or {} params.entity = item if type(event) == 'table' then for i, j in pairs(event) do params.targetvalue = nil -- réinitialisation barbare des paramètres modifiés local s = wd.keyDate(j, item, params) if s then return s end end elseif type(event) ~= 'string' then return formatError('invalid-datatype', type(event), 'string') elseif string.sub(event, 1, 1) == 'Q' then -- on demande un élément utilisé dans P:P793 (événement clé) params.property = 'P793' params.targetvalue = event params.addcat = params.addcat or true return wd.getTheDate(params) elseif string.sub(event, 1, 1) == 'P' then -- on demande une propriété params.property = event return wd.formatAndCat(params) else return formatError('invalid-entity-id', event) end end function wd.mainDate(entity) -- essaye P580/P582 local args = {entity = entity, addcat = true} args.property = 'P580' local startpoint = wd.formatStatements(args) args.property = 'P582' local endpoint = wd.formatStatements(args) local str if (startpoint or endpoint) then str = modules.formatDate.daterange(startpoint, endpoint, params) str = wd.addLinkBack(str, entity, 'P582') return str end -- défaut : P585 args.property = {'P585', 'P571'} args.linkback = true return wd.formatStatements(args) end -- === FUNCTIONS FOR TRANSITIVE PROPERTIES === function wd.getIds(item, query) query.excludespecial = true query.displayformat = 'raw' query.entity = item query.addstandardqualifs = '-' return wd.stringTable(query) end -- recursively adds a list of qid to an existing list, based on the results of a query function wd.addVals(list, query, maxdepth, maxnodes, stopval) maxdepth = tonumber(maxdepth) or 10 maxnodes = tonumber(maxnodes) or 100 if (maxdepth < 0) then return list end if stopval and wd.isHere(list, stopval) then return list end local origsize = #list for i = 1, origsize do -- tried a "checkpos" param instead of starting to 1 each time, but no impact on performance local candidates = wd.getIds(list[i], query) list = wd.addNewValues(list, candidates, maxnodes, stopval) if list[#list] == stopval then return list end if #list >= maxnodes then return list end end if (#list == origsize) then return list end return wd.addVals(list, query, maxdepth - 1, maxnodes, stopval, origsize + 1) end -- returns a list of items transitively matching a query (orig item is not included in the list) function wd.transitiveVals(item, query, maxdepth, maxnodes, stopval) maxdepth = tonumber(maxdepth) or 5 if type(query) == "string" then query = {property = query} end -- récupération des valeurs local vals = wd.getIds(item, query) if not vals then return nil end local v = wd.addVals(vals, query, maxdepth - 1, maxnodes, stopval) if not v then return nil end -- réarrangement des valeurs if query.valorder == "inverted" then local a = {} for i, j in pairs(v) do table.insert(a, 1, j) end v = a end return v end -- returns true if an item is the value of a query, transitively function wd.inTransitiveVals(searchedval, sourceval, query, maxdepth, maxnodes ) local vals = wd.transitiveVals(sourceval, query, maxdepth, maxnodes, searchedval ) if (not vals) then return false end for _, val in ipairs(vals) do if (val == searchedval) then return true end end return false end -- returns true if an item is a superclass of another, based on P279 function wd.isSubclass(class, item, maxdepth) local query = {property = 'P279'} if class == item then -- item is a subclass of itself iff it is a class if wd.getIds(item, query) then return true end return false end return wd.inTransitiveVals(class, item, query, maxdepth ) end -- returns true if one of the best ranked P31 values of an item is the target or a subclass of the target -- rank = 'valid' would seem to make sense, but it would need to check for date qualifiers as some P31 values have begin or end date function wd.isInstance(targetclass, item, maxdepth) maxdepth = maxdepth or 10 local directclasses = wd.transitiveVals(item, {property = 'P31'}, 1) if not directclasses then return false end for i, class in pairs(directclasses) do if wd.isSubclass(targetclass, class, maxdepth - 1) then return true end end return false end -- return the first value in a transitive query that belongs to a particular class. For instance find a value of P131 that is a province of Canada function wd.findVal(sourceitem, targetclass, query, recursion, instancedepth) if type(query) == "string" then query = {property = query} end local candidates = wd.getIds(sourceitem, query) if candidates then for i, j in pairs(candidates) do if wd.isInstance(targetclass, j, instancedepth) then return j end end if not recursion then recursion = 3 else recursion = recursion - 1 end if recursion < 0 then return nil end for i, candidate in pairs(candidates) do return wd.findVal(candidate, targetclass, query, recursion, instancedepth) end end end -- === VARIA === function wd.getDescription(entity, lang) lang = lang or defaultlang local description if lang == defaultlang then return mw.wikibase.descriptionl(qid) end if not entity.descriptions then return wd.translate('no description') end local descriptions = entity.descriptions if not descriptions then return nil end if descriptions[lang] then return descriptions[delang].value end return entity.id end function wd.Dump(entity) entity = wd.getEntity(entity) if not entity then return formatError("entity-param-not-provided") end return "<pre>"..mw.dumpObject(entity).."</pre>" end function wd.frameFun(frame) local args = frame.args local funname = args[1] table.remove(args, 1) return wd[funname](args) end return wd dpvnumy5zupnmafj3h7h8nxf2so54d7 549194 549193 2026-06-22T07:30:53Z Mirzali 16 549194 Scribunto text/plain -- vim: set noexpandtab ft=lua ts=4 sw=4: require('strict') local p = {} local debug = false ------------------------------------------------------------------------------ -- module local variables and functions local wiki = { langcode = mw.language.getContentLanguage().code } -- internationalisation local i18n = { ["errors"] = { ["property-not-found"] = "Property not found.", ["entity-not-found"] = "Wikidata entity not found.", ["unknown-claim-type"] = "Unknown claim type.", ["unknown-entity-type"] = "Unknown entity type.", ["qualifier-not-found"] = "Qualifier not found.", ["site-not-found"] = "Wikimedia project not found.", ["unknown-datetime-format"] = "Unknown datetime format.", ["local-article-not-found"] = "Article is not yet available in this wiki." }, ["datetime"] = { -- $1 is a placeholder for the actual number [0] = "$1 billion years", -- precision: billion years [1] = "$100 million years", -- precision: hundred million years [2] = "$10 million years", -- precision: ten million years [3] = "$1 million years", -- precision: million years [4] = "$100,000 years", -- precision: hundred thousand years [5] = "$10,000 years", -- precision: ten thousand years [6] = "$1 millennium", -- precision: millennium [7] = "$1 century", -- precision: century [8] = "$1s", -- precision: decade -- the following use the format of #time parser function [9] = "Y", -- precision: year, [10] = "F Y", -- precision: month [11] = "F j, Y", -- precision: day [12] = "F j, Y ga", -- precision: hour [13] = "F j, Y g:ia", -- precision: minute [14] = "F j, Y g:i:sa", -- precision: second ["beforenow"] = "$1 BCE", -- how to format negative numbers for precisions 0 to 5 ["afternow"] = "$1 CE", -- how to format positive numbers for precisions 0 to 5 ["bc"] = '$1 "BCE"', -- how print negative years ["ad"] = "$1", -- how print positive years -- the following are for function getDateValue() and getQualifierDateValue() ["default-format"] = "dmy", -- default value of the #3 (getDateValue) or -- #4 (getQualifierDateValue) argument ["default-addon"] = "BC", -- default value of the #4 (getDateValue) or -- #5 (getQualifierDateValue) argument ["prefix-addon"] = false, -- set to true for languages put "BC" in front of the -- datetime string; or the addon will be suffixed ["addon-sep"] = " ", -- separator between datetime string and addon (or inverse) ["format"] = -- options of the 3rd argument { ["mdy"] = "F j, Y", ["my"] = "F Y", ["y"] = "Y", ["dmy"] = "j F Y", ["ymd"] = "Y-m-d", ["ym"] = "Y-m" } }, ["monolingualtext"] = '<span lang="%language">%text</span>', ["warnDump"] = "[[Category:Called function 'Dump' from module Wikidata]]", ["ordinal"] = { [1] = "st", [2] = "nd", [3] = "rd", ["default"] = "th" } } if wiki.langcode ~= "en" then --require("Module:i18n").loadI18n("Module:Wikidata/i18n", i18n) -- got idea from [[:w:Module:Wd]] local module_title; if ... == nil then module_title = mw.getCurrentFrame():getTitle() else module_title = ... end require('Module:i18n').loadI18n(module_title..'/i18n', i18n) end -- this function needs to be internationalised along with the above: -- takes cardinal numer as a numeric and returns the ordinal as a string -- we need three exceptions in English for 1st, 2nd, 3rd, 21st, .. 31st, etc. local function makeOrdinal (cardinal) local ordsuffix = i18n.ordinal.default if cardinal % 10 == 1 then ordsuffix = i18n.ordinal[1] elseif cardinal % 10 == 2 then ordsuffix = i18n.ordinal[2] elseif cardinal % 10 == 3 then ordsuffix = i18n.ordinal[3] end -- In English, 1, 21, 31, etc. use 'st', but 11, 111, etc. use 'th' -- similarly for 12 and 13, etc. if (cardinal % 100 == 11) or (cardinal % 100 == 12) or (cardinal % 100 == 13) then ordsuffix = i18n.ordinal.default end return tostring(cardinal) .. ordsuffix end local function printError(code) return '<span class="error">' .. (i18n.errors[code] or code) .. '</span>' end local function parseDateFormat(f, timestamp, addon, prefix_addon, addon_sep) local year_suffix local tstr = "" local lang_obj = mw.language.new(wiki.langcode) local f_parts = mw.text.split(f, 'Y', true) for idx, f_part in pairs(f_parts) do year_suffix = '' if string.match(f_part, "x[mijkot]$") then -- for non-Gregorian year f_part = f_part .. 'Y' elseif idx < #f_parts then -- supress leading zeros in year year_suffix = lang_obj:formatDate('Y', timestamp) year_suffix = string.gsub(year_suffix, '^0+', '', 1) end tstr = tstr .. lang_obj:formatDate(f_part, timestamp) .. year_suffix end if addon ~= "" and prefix_addon then return addon .. addon_sep .. tstr elseif addon ~= "" then return tstr .. addon_sep .. addon else return tstr end end local function parseDateValue(timestamp, date_format, date_addon) local prefix_addon = i18n["datetime"]["prefix-addon"] local addon_sep = i18n["datetime"]["addon-sep"] local addon = "" -- check for negative date if string.sub(timestamp, 1, 1) == '-' then timestamp = '+' .. string.sub(timestamp, 2) addon = date_addon end local _date_format = i18n["datetime"]["format"][date_format] if _date_format ~= nil then return parseDateFormat(_date_format, timestamp, addon, prefix_addon, addon_sep) else return printError("unknown-datetime-format") end end -- This local function combines the year/month/day/BC/BCE handling of parseDateValue{} -- with the millennium/century/decade handling of formatDate() local function parseDateFull(timestamp, precision, date_format, date_addon) local prefix_addon = i18n["datetime"]["prefix-addon"] local addon_sep = i18n["datetime"]["addon-sep"] local addon = "" -- check for negative date if string.sub(timestamp, 1, 1) == '-' then timestamp = '+' .. string.sub(timestamp, 2) addon = date_addon end -- get the next four characters after the + (should be the year now in all cases) -- ok, so this is dirty, but let's get it working first local intyear = tonumber(string.sub(timestamp, 2, 5)) if intyear == 0 and precision <= 9 then return "" end -- precision is 10000 years or more if precision <= 5 then local factor = 10 ^ ((5 - precision) + 4) local y2 = math.ceil(math.abs(intyear) / factor) local relative = mw.ustring.gsub(i18n.datetime[precision], "$1", tostring(y2)) if addon ~= "" then -- negative date relative = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative) else relative = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative) end return relative end -- precision is decades (8), centuries (7) and millennia (6) local era, card if precision == 6 then card = math.floor((intyear - 1) / 1000) + 1 era = mw.ustring.gsub(i18n.datetime[6], "$1", makeOrdinal(card)) end if precision == 7 then card = math.floor((intyear - 1) / 100) + 1 era = mw.ustring.gsub(i18n.datetime[7], "$1", makeOrdinal(card)) end if precision == 8 then era = mw.ustring.gsub(i18n.datetime[8], "$1", tostring(math.floor(math.abs(intyear) / 10) * 10)) end if era then if addon ~= "" then era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.bc, '"', ""), "$1", era) else era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.ad, '"', ""), "$1", era) end return era end local _date_format = i18n["datetime"]["format"][date_format] if _date_format ~= nil then -- check for precision is year and override supplied date_format if precision == 9 then _date_format = i18n["datetime"][9] end return parseDateFormat(_date_format, timestamp, addon, prefix_addon, addon_sep) else return printError("unknown-datetime-format") end end -- the "qualifiers" and "snaks" field have a respective "qualifiers-order" and "snaks-order" field -- use these as the second parameter and this function instead of the built-in "pairs" function -- to iterate over all qualifiers and snaks in the intended order. local function orderedpairs(array, order) if not order then return pairs(array) end -- return iterator function local i = 0 return function() i = i + 1 if order[i] then return order[i], array[order[i]] end end end -- precision: 0 - billion years, 1 - hundred million years, ..., 6 - millennia, 7 - century, 8 - decade, 9 - year, 10 - month, 11 - day, 12 - hour, 13 - minute, 14 - second local function normalizeDate(date) date = mw.text.trim(date, "+") -- extract year local yearstr = mw.ustring.match(date, "^\-?%d+") local year = tonumber(yearstr) -- remove leading zeros of year return year .. mw.ustring.sub(date, #yearstr + 1), year end local function formatDate(date, precision, timezone) precision = precision or 11 local date, year = normalizeDate(date) if year == 0 and precision <= 9 then return "" end -- precision is 10000 years or more if precision <= 5 then local factor = 10 ^ ((5 - precision) + 4) local y2 = math.ceil(math.abs(year) / factor) local relative = mw.ustring.gsub(i18n.datetime[precision], "$1", tostring(y2)) if year < 0 then relative = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative) else relative = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative) end return relative end -- precision is decades, centuries and millennia local era if precision == 6 then era = mw.ustring.gsub(i18n.datetime[6], "$1", tostring(math.floor((math.abs(year) - 1) / 1000) + 1)) end if precision == 7 then era = mw.ustring.gsub(i18n.datetime[7], "$1", tostring(math.floor((math.abs(year) - 1) / 100) + 1)) end if precision == 8 then era = mw.ustring.gsub(i18n.datetime[8], "$1", tostring(math.floor(math.abs(year) / 10) * 10)) end if era then if year < 0 then era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.bc, '"', ""), "$1", era) elseif year > 0 then era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.ad, '"', ""), "$1", era) end return era end -- precision is year if precision == 9 then return year end -- precision is less than years if precision > 9 then --[[ the following code replaces the UTC suffix with the given negated timezone to convert the global time to the given local time timezone = tonumber(timezone) if timezone and timezone ~= 0 then timezone = -timezone timezone = string.format("%.2d%.2d", timezone / 60, timezone % 60) if timezone[1] ~= '-' then timezone = "+" .. timezone end date = mw.text.trim(date, "Z") .. " " .. timezone end ]]-- local formatstr = i18n.datetime[precision] if year == 0 then formatstr = mw.ustring.gsub(formatstr, i18n.datetime[9], "") elseif year < 0 then -- Mediawiki formatDate doesn't support negative years date = mw.ustring.sub(date, 2) formatstr = mw.ustring.gsub(formatstr, i18n.datetime[9], mw.ustring.gsub(i18n.datetime.bc, "$1", i18n.datetime[9])) elseif year > 0 and i18n.datetime.ad ~= "$1" then formatstr = mw.ustring.gsub(formatstr, i18n.datetime[9], mw.ustring.gsub(i18n.datetime.ad, "$1", i18n.datetime[9])) end return mw.language.new(wiki.langcode):formatDate(formatstr, date) end end local function printDatavalueEntity(data, parameter) -- data fields: entity-type [string], numeric-id [int, Wikidata id] local id if data["entity-type"] == "item" then id = "Q" .. data["numeric-id"] elseif data["entity-type"] == "property" then id = "P" .. data["numeric-id"] else return printError("unknown-entity-type") end if parameter then if parameter == "link" then local linkTarget = mw.wikibase.getSitelink(id) local linkName = mw.wikibase.getLabel(id) if linkTarget then -- if there is a local Wikipedia article link to it using the label or the article title return "[[" .. linkTarget .. "|" .. (linkName or linkTarget) .. "]]" else -- if there is no local Wikipedia article output the label or link to the Wikidata object to let the user input a proper label if linkName then return linkName else return "[[:d:" .. id .. "|" .. id .. "]]" end end else return data[parameter] end else return mw.wikibase.getLabel(id) or id end end local function printDatavalueTime(data, parameter) -- data fields: time [ISO 8601 time], timezone [int in minutes], before [int], after [int], precision [int], calendarmodel [wikidata URI] -- precision: 0 - billion years, 1 - hundred million years, ..., 6 - millennia, 7 - century, 8 - decade, 9 - year, 10 - month, 11 - day, 12 - hour, 13 - minute, 14 - second -- calendarmodel: e.g. http://www.wikidata.org/entity/Q1985727 for the proleptic Gregorian calendar or http://www.wikidata.org/wiki/Q11184 for the Julian calendar] if parameter then if parameter == "calendarmodel" then data.calendarmodel = mw.ustring.match(data.calendarmodel, "Q%d+") -- extract entity id from the calendar model URI elseif parameter == "time" then data.time = normalizeDate(data.time) end return data[parameter] else return formatDate(data.time, data.precision, data.timezone) end end local function printDatavalueMonolingualText(data, parameter) -- data fields: language [string], text [string] if parameter then return data[parameter] else local result = mw.ustring.gsub(mw.ustring.gsub(i18n.monolingualtext, "%%language", data["language"]), "%%text", data["text"]) return result end end local function findClaims(entity, property) if not property or not entity or not entity.claims then return end if mw.ustring.match(property, "^P%d+$") then -- if the property is given by an id (P..) access the claim list by this id return entity.claims[property] else property = mw.wikibase.resolvePropertyId(property) if not property then return end return entity.claims[property] end end local function getSnakValue(snak, parameter) if snak.snaktype == "value" then -- call the respective snak parser if snak.datavalue.type == "string" then return snak.datavalue.value elseif snak.datavalue.type == "globecoordinate" then return printDatavalueCoordinate(snak.datavalue.value, parameter) elseif snak.datavalue.type == "quantity" then return printDatavalueQuantity(snak.datavalue.value, parameter) elseif snak.datavalue.type == "time" then return printDatavalueTime(snak.datavalue.value, parameter) elseif snak.datavalue.type == "wikibase-entityid" then return printDatavalueEntity(snak.datavalue.value, parameter) elseif snak.datavalue.type == "monolingualtext" then return printDatavalueMonolingualText(snak.datavalue.value, parameter) end end return mw.wikibase.renderSnak(snak) end local function getQualifierSnak(claim, qualifierId) -- a "snak" is Wikidata terminology for a typed key/value pair -- a claim consists of a main snak holding the main information of this claim, -- as well as a list of attribute snaks and a list of references snaks if qualifierId then -- search the attribute snak with the given qualifier as key if claim.qualifiers then local qualifier = claim.qualifiers[qualifierId] if qualifier then return qualifier[1] end end return nil, printError("qualifier-not-found") else -- otherwise return the main snak return claim.mainsnak end end local function getValueOfClaim(claim, qualifierId, parameter) local error local snak snak, error = getQualifierSnak(claim, qualifierId) if snak then return getSnakValue(snak, parameter) else return nil, error end end local function getReferences(frame, claim) local result = "" -- traverse through all references for ref in pairs(claim.references or {}) do local refparts -- traverse through all parts of the current reference for snakkey, snakval in orderedpairs(claim.references[ref].snaks or {}, claim.references[ref]["snaks-order"]) do if refparts then refparts = refparts .. ", " else refparts = "" end -- output the label of the property of the reference part, e.g. "imported from" for P143 refparts = refparts .. tostring(mw.wikibase.getLabel(snakkey)) .. ": " -- output all values of this reference part, e.g. "German Wikipedia" and "English Wikipedia" if the referenced claim was imported from both sites for snakidx = 1, #snakval do if snakidx > 1 then refparts = refparts .. ", " end refparts = refparts .. getSnakValue(snakval[snakidx]) end end if refparts then result = result .. frame:extensionTag("ref", refparts) end end return result end local function parseInput(frame) local qid = frame.args.qid if qid and (#qid == 0) then qid = nil end local propertyID = mw.text.trim(frame.args[1] or "") local input_parm = mw.text.trim(frame.args[2] or "") if input_parm ~= "FETCH_WIKIDATA" then return false, input_parm, nil, nil end local entity = mw.wikibase.getEntity(qid) local claims if entity and entity.claims then claims = entity.claims[propertyID] if not claims then return false, "", nil, nil end else return false, "", nil, nil end return true, entity, claims, propertyID end local function isType(claims, type) return claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == type end local function getValue(entity, claims, propertyID, delim, labelHook) if labelHook == nil then labelHook = function (qnumber) return nil; end end if isType(claims, "wikibase-entityid") then local out = {} for k, v in pairs(claims) do local qnumber = "Q" .. v.mainsnak.datavalue.value["numeric-id"] local sitelink = mw.wikibase.getSitelink(qnumber) local label = labelHook(qnumber) or mw.wikibase.getLabel(qnumber) or qnumber if sitelink then out[#out + 1] = "[[" .. sitelink .. "|" .. label .. "]]" else out[#out + 1] = "[[:d:" .. qnumber .. "|" .. label .. "]]<abbr title='" .. i18n["errors"]["local-article-not-found"] .. "'>[*]</abbr>" end end return table.concat(out, delim) else -- just return best values return entity:formatPropertyValues(propertyID).value end end ------------------------------------------------------------------------------ -- module global functions if debug then function p.inspectI18n(frame) local val = i18n for _, key in pairs(frame.args) do key = mw.text.trim(key) val = val[key] end return val end end function p.descriptionIn(frame) local langcode = frame.args[1] local id = frame.args[2] -- return description of a Wikidata entity in the given language or the default language of this Wikipedia site return mw.wikibase.getEntity(id):getDescription(langcode or wiki.langcode) end function p.labelIn(frame) local langcode = frame.args[1] local id = frame.args[2] -- return label of a Wikidata entity in the given language or the default language of this Wikipedia site return mw.wikibase.getEntity(id):getLabel(langcode or wiki.langcode) end -- This is used to get a value, or a comma separated list of them if multiple values exist p.getValue = function(frame) local delimdefault = ", " -- **internationalise later** local delim = frame.args.delimiter or "" delim = string.gsub(delim, '"', '') if #delim == 0 then delim = delimdefault end local go, errorOrentity, claims, propertyID = parseInput(frame) if not go then return errorOrentity end return getValue(errorOrentity, claims, propertyID, delim) end -- Same as above, but uses the short name property for label if available. p.getValueShortName = function(frame) local go, errorOrentity, claims, propertyID = parseInput(frame) if not go then return errorOrentity end local entity = errorOrentity -- if wiki-linked value output as link if possible local function labelHook (qnumber) local label local claimEntity = mw.wikibase.getEntity(qnumber) if claimEntity ~= nil then if claimEntity.claims.P1813 then for k2, v2 in pairs(claimEntity.claims.P1813) do if v2.mainsnak.datavalue.value.language == "en" then label = v2.mainsnak.datavalue.value.text end end end end if label == nil or label == "" then return nil end return label end return getValue(errorOrentity, claims, propertyID, ", ", labelHook); end -- This is used to get a value, or a comma separated list of them if multiple values exist -- from an arbitrary entry by using its QID. -- Use : {{#invoke:Wikidata|getValueFromID|<ID>|<Property>|FETCH_WIKIDATA}} -- E.g.: {{#invoke:Wikidata|getValueFromID|Q151973|P26|FETCH_WIKIDATA}} - to fetch value of 'spouse' (P26) from 'Richard Burton' (Q151973) -- Please use sparingly - this is an *expensive call*. p.getValueFromID = function(frame) local itemID = mw.text.trim(frame.args[1] or "") local propertyID = mw.text.trim(frame.args[2] or "") local input_parm = mw.text.trim(frame.args[3] or "") if input_parm == "FETCH_WIKIDATA" then local entity = mw.wikibase.getEntity(itemID) local claims if entity and entity.claims then claims = entity.claims[propertyID] end if claims then return getValue(entity, claims, propertyID, ", ") else return "" end else return input_parm end end local function getQualifier(frame, outputHook) local propertyID = mw.text.trim(frame.args[1] or "") local qualifierID = mw.text.trim(frame.args[2] or "") local input_parm = mw.text.trim(frame.args[3] or "") if input_parm == "FETCH_WIKIDATA" then local entity = mw.wikibase.getEntity() if entity.claims[propertyID] ~= nil then local out = {} for k, v in pairs(entity.claims[propertyID]) do for k2, v2 in pairs(v.qualifiers[qualifierID]) do if v2.snaktype == 'value' then out[#out + 1] = outputHook(v2); end end end return table.concat(out, ", "), true else return "", false end else return input_parm, false end end p.getQualifierValue = function(frame) local function outputValue(value) local qnumber = "Q" .. value.datavalue.value["numeric-id"] if (mw.wikibase.getSitelink(qnumber)) then return "[[" .. mw.wikibase.getSitelink(qnumber) .. "]]" else return "[[:d:" .. qnumber .. "|" ..qnumber .. "]]<abbr title='" .. i18n["errors"]["local-article-not-found"] .. "'>[*]</abbr>" end end return (getQualifier(frame, outputValue)) end -- This is used to get a value like 'male' (for property p21) which won't be linked and numbers without the thousand separators p.getRawValue = function(frame) local go, errorOrentity, claims, propertyID = parseInput(frame) if not go then return errorOrentity end local entity = errorOrentity local result = entity:formatPropertyValues(propertyID, mw.wikibase.entity.claimRanks).value -- if number type: remove thousand separators, bounds and units if isType(claims, "quantity") then result = mw.ustring.gsub(result, "(%d),(%d)", "%1%2") result = mw.ustring.gsub(result, "(%d)±.*", "%1") end return result end -- This is used to get the unit name for the numeric value returned by getRawValue p.getUnits = function(frame) local go, errorOrentity, claims, propertyID = parseInput(frame) if not go then return errorOrentity end local entity = errorOrentity local result = entity:formatPropertyValues(propertyID, mw.wikibase.entity.claimRanks).value if isType(claims, "quantity") then result = mw.ustring.sub(result, mw.ustring.find(result, " ")+1, -1) end return result end -- This is used to get the unit's QID to use with the numeric value returned by getRawValue p.getUnitID = function(frame) local go, errorOrentity, claims = parseInput(frame) if not go then return errorOrentity end local entity = errorOrentity local result if isType(claims, "quantity") then -- get the url for the unit entry on Wikidata: result = claims[1].mainsnak.datavalue.value.unit -- and just reurn the last bit from "Q" to the end (which is the QID): result = mw.ustring.sub(result, mw.ustring.find(result, "Q"), -1) end return result end p.getRawQualifierValue = function(frame) local function outputHook(value) if value.datavalue.value["numeric-id"] then return mw.wikibase.getLabel("Q" .. value.datavalue.value["numeric-id"]) else return value.datavalue.value end end local ret, gotData = getQualifier(frame, outputHook) if gotData then ret = string.upper(string.sub(ret, 1, 1)) .. string.sub(ret, 2) end return ret end -- This is used to get a date value for date_of_birth (P569), etc. which won't be linked -- Dates and times are stored in ISO 8601 format (sort of). -- At present the local formatDate(date, precision, timezone) function doesn't handle timezone -- So I'll just supply "Z" in the call to formatDate below: p.getDateValue = function(frame) local date_format = mw.text.trim(frame.args[3] or i18n["datetime"]["default-format"]) local date_addon = mw.text.trim(frame.args[4] or i18n["datetime"]["default-addon"]) local go, errorOrentity, claims = parseInput(frame) if not go then return errorOrentity end local entity = errorOrentity local out = {} for k, v in pairs(claims) do if v.mainsnak.datavalue.type == 'time' then local timestamp = v.mainsnak.datavalue.value.time local dateprecision = v.mainsnak.datavalue.value.precision -- A year can be stored like this: "+1872-00-00T00:00:00Z", -- which is processed here as if it were the day before "+1872-01-01T00:00:00Z", -- and that's the last day of 1871, so the year is wrong. -- So fix the month 0, day 0 timestamp to become 1 January instead: timestamp = timestamp:gsub("%-00%-00T", "-01-01T") out[#out + 1] = parseDateFull(timestamp, dateprecision, date_format, date_addon) end end return table.concat(out, ", ") end p.getQualifierDateValue = function(frame) local date_format = mw.text.trim(frame.args[4] or i18n["datetime"]["default-format"]) local date_addon = mw.text.trim(frame.args[5] or i18n["datetime"]["default-addon"]) local function outputHook(value) local timestamp = value.datavalue.value.time return parseDateValue(timestamp, date_format, date_addon) end return (getQualifier(frame, outputHook)) end -- This is used to fetch all of the images with a particular property, e.g. image (P18), Gene Atlas Image (P692), etc. -- Parameters are | propertyID | value / FETCH_WIKIDATA / nil | separator (default=space) | size (default=frameless) -- It will return a standard wiki-markup [[File:Filename | size]] for each image with a selectable size and separator (which may be html) -- e.g. {{#invoke:Wikidata|getImages|P18|FETCH_WIKIDATA}} -- e.g. {{#invoke:Wikidata|getImages|P18|FETCH_WIKIDATA|<br>|250px}} -- If a property is chosen that is not of type "commonsMedia", it will return empty text. p.getImages = function(frame) local sep = mw.text.trim(frame.args[3] or " ") local imgsize = mw.text.trim(frame.args[4] or "frameless") local go, errorOrentity, claims = parseInput(frame) if not go then return errorOrentity end local entity = errorOrentity if (claims[1] and claims[1].mainsnak.datatype == "commonsMedia") then local out = {} for k, v in pairs(claims) do local filename = v.mainsnak.datavalue.value out[#out + 1] = "[[File:" .. filename .. "|" .. imgsize .. "]]" end return table.concat(out, sep) else return "" end end -- This is used to get the TA98 (Terminologia Anatomica first edition 1998) values like 'A01.1.00.005' (property P1323) -- which are then linked to https://ifaa.unifr.ch/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/01.1.00.005%20Entity%20TA98%20EN.htm -- uses the newer mw.wikibase calls instead of directly using the snaks -- formatPropertyValues returns a table with the P1323 values concatenated with ", " so we have to split them out into a table in order to construct the return string p.getTAValue = function(frame) local ent = mw.wikibase.getEntity() local props = ent:formatPropertyValues('P1323') local out = {} local t = {} for k, v in pairs(props) do if k == 'value' then t = mw.text.split( v, ", ") for k2, v2 in pairs(t) do out[#out + 1] = "[https://ifaa.unifr.ch/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/" .. string.sub(v2, 2) .. "%20Entity%20TA98%20EN.htm " .. v2 .. "]" end end end local ret = table.concat(out, "<br> ") if #ret == 0 then ret = "Invalid TA" end return ret end --[[ This is used to return an image legend from Wikidata image is property P18 image legend is property P2096 Call as {{#invoke:Wikidata |getImageLegend | <PARAMETER> | lang=<ISO-639code> |id=<QID>}} Returns PARAMETER, unless it is equal to "FETCH_WIKIDATA", from Item QID (expensive call) If QID is omitted or blank, the current article is used (not an expensive call) If lang is omitted, it uses the local wiki language, otherwise it uses the provided ISO-639 language code ISO-639: https://docs.oracle.com/cd/E13214_01/wli/docs92/xref/xqisocodes.html#wp1252447 Ranks are: 'preferred' > 'normal' This returns the label from the first image with 'preferred' rank Or the label from the first image with 'normal' rank if preferred returns nothing Ranks: https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua ]] p.getImageLegend = function(frame) -- look for named parameter id; if it's blank make it nil local id = frame.args.id if id and (#id == 0) then id = nil end -- look for named parameter lang -- it should contain a two-character ISO-639 language code -- if it's blank fetch the language of the local wiki local lang = frame.args.lang if (not lang) or (#lang < 2) then lang = mw.language.getContentLanguage().code end -- first unnamed parameter is the local parameter, if supplied local input_parm = mw.text.trim(frame.args[1] or "") if input_parm == "FETCH_WIKIDATA" then local ent = mw.wikibase.getEntity(id) local imgs if ent and ent.claims then imgs = ent.claims.P18 end local imglbl if imgs then -- look for an image with 'preferred' rank for k1, v1 in pairs(imgs) do if v1.rank == "preferred" and v1.qualifiers and v1.qualifiers.P2096 then local imglbls = v1.qualifiers.P2096 for k2, v2 in pairs(imglbls) do if v2.datavalue.value.language == lang then imglbl = v2.datavalue.value.text break end end end end -- if we don't find one, look for an image with 'normal' rank if (not imglbl) then for k1, v1 in pairs(imgs) do if v1.rank == "normal" and v1.qualifiers and v1.qualifiers.P2096 then local imglbls = v1.qualifiers.P2096 for k2, v2 in pairs(imglbls) do if v2.datavalue.value.language == lang then imglbl = v2.datavalue.value.text break end end end end end end return imglbl else return input_parm end end -- This is used to get the QIDs of all of the values of a property, as a comma separated list if multiple values exist -- Usage: {{#invoke:Wikidata |getPropertyIDs |<PropertyID> |FETCH_WIKIDATA}} -- Usage: {{#invoke:Wikidata |getPropertyIDs |<PropertyID> |<InputParameter> |qid=<QID>}} p.getPropertyIDs = function(frame) local go, errorOrentity, propclaims = parseInput(frame) if not go then return errorOrentity end local entity = errorOrentity -- if wiki-linked value collect the QID in a table if (propclaims[1] and propclaims[1].mainsnak.snaktype == "value" and propclaims[1].mainsnak.datavalue.type == "wikibase-entityid") then local out = {} for k, v in pairs(propclaims) do out[#out + 1] = "Q" .. v.mainsnak.datavalue.value["numeric-id"] end return table.concat(out, ", ") else -- not a wikibase-entityid, so return empty return "" end end -- returns the page id (Q...) of the current page or nothing of the page is not connected to Wikidata function p.pageId(frame) return mw.wikibase.getEntityIdForCurrentPage() end function p.claim(frame) local property = frame.args[1] or "" local id = frame.args["id"] local qualifierId = frame.args["qualifier"] local parameter = frame.args["parameter"] local list = frame.args["list"] local references = frame.args["references"] local showerrors = frame.args["showerrors"] local default = frame.args["default"] if default then showerrors = nil end -- get wikidata entity local entity = mw.wikibase.getEntity(id) if not entity then if showerrors then return printError("entity-not-found") else return default end end -- fetch the first claim of satisfying the given property local claims = findClaims(entity, property) if not claims or not claims[1] then if showerrors then return printError("property-not-found") else return default end end -- get initial sort indices local sortindices = {} for idx in pairs(claims) do sortindices[#sortindices + 1] = idx end -- sort by claim rank local comparator = function(a, b) local rankmap = { deprecated = 2, normal = 1, preferred = 0 } local ranka = rankmap[claims[a].rank or "normal"] .. string.format("%08d", a) local rankb = rankmap[claims[b].rank or "normal"] .. string.format("%08d", b) return ranka < rankb end table.sort(sortindices, comparator) local result local error if list then local value -- iterate over all elements and return their value (if existing) result = {} for idx in pairs(claims) do local claim = claims[sortindices[idx]] value, error = getValueOfClaim(claim, qualifierId, parameter) if not value and showerrors then value = error end if value and references then value = value .. getReferences(frame, claim) end result[#result + 1] = value end result = table.concat(result, list) else -- return first element local claim = claims[sortindices[1]] result, error = getValueOfClaim(claim, qualifierId, parameter) if result and references then result = result .. getReferences(frame, claim) end end if result then return result else if showerrors then return error else return default end end end -- look into entity object function p.ViewSomething(frame) local f = (frame.args[1] or frame.args.id) and frame or frame:getParent() local id = f.args.id if id and (#id == 0) then id = nil end local data = mw.wikibase.getEntity(id) if not data then return nil end local i = 1 while true do local index = f.args[i] if not index then if type(data) == "table" then return mw.text.jsonEncode(data, mw.text.JSON_PRESERVE_KEYS + mw.text.JSON_PRETTY) else return tostring(data) end end data = data[index] or data[tonumber(index)] if not data then return end i = i + 1 end end -- getting sitelink of a given wiki -- get sitelink of current item if qid not supplied function p.getSiteLink(frame) local qid = frame.args.qid if qid == "" then qid = nil end local f = mw.text.trim( frame.args[1] or "") local entity = mw.wikibase.getEntity(qid) if not entity then return end local link = entity:getSitelink( f ) if not link then return end return link end function p.Dump(frame) local f = (frame.args[1] or frame.args.id) and frame or frame:getParent() local data = mw.wikibase.getEntity(f.args.id) if not data then return i18n.warnDump end local i = 1 while true do local index = f.args[i] if not index then return "<pre>"..mw.dumpObject(data).."</pre>".. i18n.warnDump end data = data[index] or data[tonumber(index)] if not data then return i18n.warnDump end i = i + 1 end end return p 0ut9ea611aebtqxr1j5hmyqvjdhhyh8 549195 549194 2026-06-22T07:35:53Z Mirzali 16 549195 Scribunto text/plain --script that retrieves basic data stored in Wikidata, for the datamodel, see https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua local wd = {} local modules = { } local modulesNames = { reference = 'Module:Wikidata/Références', i18n = 'Module:Wikidata/I18n', globes = 'Module:Wikidata/Globes', langcodes = 'Module:Dictionnaire Wikidata/Codes langue', -- big, infrequently useda invertedlangcodes = 'Module:Dictionnaire Wikidata/Codes langue/inversé', linguistic = 'Module:Linguistique', formatDate = 'Module:Date complexe', formatNum = 'Module:Conversion', langmodule = 'Module:Langue', cite = 'Module:Biblio', weblink = 'Module:Weblink' } local function loadModule( t, key ) if modulesNames[key] then local m = require( modulesNames[key] ) t[key] = m return m end end setmetatable( modules, { __index = loadModule } ) local datequalifiers = {'P585', 'P571', 'P580', 'P582', 'P1319', 'P1326'} -- === I18n === local defaultlang = mw.getContentLanguage():getCode() function wd.translate(str, rep1, rep2) str = modules.i18n[str] or str if rep1 and (type (rep1) == 'string') then str = str:gsub('$1', rep1) end if rep2 and (type (rep2) == 'string')then str = str:gsub('$2', rep2) end return str end local function addCat(cat, sortkey) if sortkey then return '[[Category:' .. cat .. '|' .. sortkey .. ']]' end return '[[Category:' .. cat .. ']]' end local function formatError( key , category, debug) if debug then return error(modules.i18n[key] or key) end if category then return addCat(category, key) else return addCat('cat-unsorted-issue', key) end end -- function wd.isSpecial(snak) return (snak.snaktype ~= 'value') end function wd.getId(snak) if (snak.snaktype == 'value') then return 'Q' .. snak.datavalue.value['numeric-id'] end end function wd.getNumericId(snak) if (snak.snaktype == 'value') then return snak.datavalue.value['numeric-id'] end end function wd.getMainId(claim) return wd.getId(claim.mainsnak) end function wd.entityId(entity) if type(entity) == 'string' then return entity elseif type(entity) == 'table' then return entity.id end end function wd.getEntityIdForCurrentPage() return mw.wikibase.getEntityIdForCurrentPage() end -- function that returns true if the "qid" parameter is the qid -- of the item that is linked to the calling page function wd.isPageOfQId(qid) local self_id = mw.wikibase.getEntityIdForCurrentPage() return self_id ~= nil and qid == self_id end function wd.getEntity( val ) if type(val) == 'table' then return val end if val == '-' then return nil end if val == '' then val = nil end return mw.wikibase.getEntity(val) end function wd.splitStr(val) -- transforme en table les chaînes venant du Wikitexte qui utilisent des virgules de séparation if type(val) == 'string' then val = mw.text.split(val, ",") end return val end function wd.isHere(searchset, val) for i, j in pairs(searchset) do if val == j then return true end end return false end local function wikidataLink(entity) local name =':d:' if type(entity) == 'string' then if entity:match("P[0-9+]") then entity = "Property:" .. entity end return name .. entity elseif type(entity) == 'table' then if entity["type"] == "property" then name = ":d:Property:" end return name .. entity.id elseif type(entity) == nil then return formatError('entity-not-found') end end function wd.siteLink(entity, project, lang) -- returns 3 values: a sitelink (with the relevant prefix) a project name and a language lang = lang or defaultlang if (type(project) ~= 'string') then project = 'wiki' end project = project:lower() if project == 'wikipedia' then project = 'wiki' end if type(entity) == 'string' and (project == 'wiki') and ( (not lang or lang == defaultlang) ) then -- évite de charger l'élément entier return mw.wikibase.sitelink(entity), 'wiki', defaultlang end if project == 'wikidata' then return wikidataLink(entity), 'wikidata' end local projects = { -- nom = {préfixe sur Wikidata, préfix pour les liens sur Wikipédia, ajouter préfixe de langue} wiki = {'wiki', nil, true}, -- wikipedia commons = {'commonswiki', 'commons', false}, commonswiki = {'commonswiki', 'commons', false}, wikiquote = {'wikiquote', 'q', true}, wikivoyage = {'wikivoyage', 'voy', true}, wikibooks = {'wikibooks', 'b', true}, wikinews = {'wikinews', 'n', true}, wikiversity = {'wikiversity', 'v', true}, wikisource = {'wikisource', 's', true}, wiktionary = {'wiktionary', 'wikt', true}, specieswiki = {'specieswiki', 'species', false}, metawiki = {'metawiki', 'm', false}, incubator = {'incubator', 'incubator', false}, outreach = {'outreach', 'outreach', false}, mediawiki = {'mediawiki', 'mw', false} } local entityid = entity.id or entity local projectdata = projects[project:lower()] if not projectdata then -- defaultlink might be in the form "enwiki" rather than "project: 'wiki', lang: 'en' " for k, v in pairs(projects) do if project:match( k .. '$' ) and mw.language.isKnownLanguageTag(project:sub(1, #project-#k)) then lang = project:sub(1, #project-#k) project = project:sub(#lang + 1, #project) projectdata = projects[project] break end end if not mw.language.isKnownLanguageTag(lang) then return --formatError('invalid-project-code', projet or 'nil') end end if not projectdata then return -- formatError('invalid-project-code', projet or 'nil') end local linkcode = projectdata[1] local prefix = projectdata[2] local multiversion = projectdata[3] if multiversion then linkcode = lang .. linkcode end local link = mw.wikibase.getSitelink(entityid, linkcode) if not link then return nil end if prefix then link = prefix .. ':' .. link end if multiversion then link = ':' .. lang .. ':' .. link end return link, project, lang end -- add new values to a list, avoiding duplicates function wd.addNewValues(olditems, newitems, maxnum, stopval) if not newitems then return olditems end for _, qid in pairs(newitems) do if stopval and (qid == stopval) then table.insert(olditems, qid) return olditems end if maxnum and (#olditems >= maxnum) then return olditems end if not wd.isHere(olditems, qid) then table.insert(olditems, qid) end end return olditems end --=== FILTER CLAIMS ACCORDING TO VARIOUS CRITERIA : FUNCTION GETCLAIMS et alii === local function notSpecial(claim) local type if claim.mainsnak ~= nil then type = claim.mainsnak.snaktype else -- condition respectée quand showonlyqualifier est un paramètre renseigné -- dans ce cas, claim n'est pas une déclaration entière, mais UNE snak qualifiée du main snak type = claim.snaktype end return type == 'value' end local function hasTargetValue(claim, targets) -- retourne true si la valeur est dans la liste des target, ou si c'est une valeur spéciale filtrée séparément par excludespecial local id = wd.getMainId(claim) local targets = wd.splitStr(targets) return wd.isHere(targets, id) or wd.isSpecial(claim.mainsnak) end local function excludeValues(claim, values) -- true si la valeur n'est pas dans la liste, ou si c'est une valeur spéciale (filtrée à part par excludespecial) return wd.isSpecial(claim.mainsnak) or not ( hasTargetValue(claim, values) ) 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 withRank(claims, target) if target == 'best' then return bestRanked(claims) end local newclaims = {} for pos, claim in pairs(claims) do if target == 'valid' then if claim.rank ~= 'deprecated' then table.insert(newclaims, claim) end elseif claim.rank == target then table.insert(newclaims, claim) end end return newclaims end function wd.hasQualifier(claim, acceptedqualifs, acceptedvals, excludequalifiervalues) local claimqualifs = claim.qualifiers if (not claimqualifs) then return false end acceptedqualifs = wd.splitStr(acceptedqualifs) acceptedvals = wd.splitStr( acceptedvals) local function ok(qualif) -- vérification pour un qualificatif individuel if not claimqualifs[qualif] then return false end if not (acceptedvals) then -- si aucune valeur spécifique n'est demandée, OK return true end for i, wanted in pairs(acceptedvals) do for j, actual in pairs(claimqualifs[qualif]) do if wd.getId(actual) == wanted then return true end end end end for i, qualif in pairs(acceptedqualifs) do if ok(qualif) then return true end end return false end function wd.hasQualifierNumber(claim, acceptedqualifs, acceptedvals, excludequalifiervalues) local claimqualifs = claim.qualifiers if (not claimqualifs) then return false end acceptedqualifs = wd.splitStr(acceptedqualifs) acceptedvals = wd.splitStr( acceptedvals) local function ok(qualif) -- vérification pour un qualificatif individuel if not claimqualifs[qualif] then return false end if not (acceptedvals) then -- si aucune valeur spécifique n'est demandée, OK return true end for i, wanted in pairs(acceptedvals) do for j, actual in pairs(claimqualifs[qualif]) do if mw.wikibase.renderSnak(actual) == wanted then return true end end end end for i, qualif in pairs(acceptedqualifs) do if ok(qualif) then return true end end return false end local function hasSource(claim, targetsource, sourceproperty) sourceproperty = sourceproperty or 'P248' if targetsource == "-" then return true end if (not claim.references) then return false end local candidates = claim.references[1].snaks[sourceproperty] -- les snaks utilisant la propriété demandée if (not candidates) then return false end if (targetsource == "any") then -- si n'importe quelle valeur est acceptée tant qu'elle utilise en ref la propriété demandée return true end targetsource = wd.splitStr(targetsource) for _, source in pairs(candidates) do local s = wd.getId(source) for i, target in pairs(targetsource) do if s == target then return true end end end return false end local function excludeQualifier(claim, qualifier, qualifiervalues) return not wd.hasQualifier(claim, qualifier, qualifiervalues) end function wd.hasDate(claim) if not claim then return false --error() ? end if wd.getDateFromQualif(claim, 'P585') or wd.getDateFromQualif(claim, 'P580') or wd.getDateFromQualif(claim, 'P582') then return true end return false end local function hasLink(claim, site, lang) if (claim.mainsnak.snaktype ~= 'value') then -- ne pas supprimer les valeurs spéciales, il y a une fonction dédiée pour ça return true end local id = wd.getMainId(claim) local link = wd.siteLink(id, site, lang) if link then return true end end local function isInLanguage(claim, lang) -- ne fonctionne que pour les monolingualtext / étendre aux autres types en utilisant les qualifiers ? if type(lang) == 'table' then -- si c'est une table de language séparées par des virgules, on les accepte toutes for i, l in pairs(lang) do local v = isInLanguage(claim, l) if v then return true end end end if type(lang) ~= ('string') then return --? end if (lang == '-') then return true end if (lang == 'locallang') then lang = mw.getContentLanguage():getCode() end -- pour les monolingual text local snak = claim.mainsnak or claim if snak.snaktype == 'value' and snak.datavalue.type == 'monolingualtext' then if snak.datavalue.value.language == lang then return true end return false end -- pour les autres types de données : recherche dans les qualificatifs if (lang == 'diq') then lang = 'Q150' elseif (lang == 'en') then lang = 'Q1860' else lang = invertedlangcodes[lang] end if claim.qualifiers and claim.qualifiers.P407 then if wd.hasQualifier(claim, {'P407'}, {lang}) then return true else return false end end return true -- si on ne ne sait pas la langue, on condière que c'est bon end local function firstVals(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 not claims then return nil end while (#claims > numval) do table.remove(claims) end return claims end local function lastVals(claims, numval2) -- retourn les valeurs de la table claims à partir de numval2 local numval2 = tonumber(numval2) or 0 -- raise a error if numval is not a positive integer ? if not claims then return nil end for i=1,numval2 do table.remove(claims, 1) end return claims end local function timeFromQualifs(claim, qualifs) local claimqualifs = claim.qualifiers if not claimqualifs then return nil end for i, qualif in pairs(qualifs or timequalifiers) do local vals = claimqualifs[qualif] if vals and (vals[1].snaktype == 'value') then return vals[1].datavalue.value.time end end end local function atDate(claim, mydate, precision) if mydate == "today" then mydate = os.date("!%Y-%m-%dT%TZ") end -- with point in time local d = timeFromQualifs(claim, {'P585'}) if d then return modules.formatDate.equal(mydate, d, precision) end -- with start or end date local mindate = timeFromQualifs(claim, {'P580'}) local maxdate = timeFromQualifs(claim, {'P582'}) if modules.formatDate.before(mydate, mindate) and modules.formatDate.before(maxdate, mydate) then return true end return false end local function check(claim, condition) if type(condition) == 'function' then -- cas standard return condition(claim) end return formatError('invalid type', 'function', type(condition)) end local function minPrecision(claim, minprecision) local snack if claim.qualifiers then -- si une date est donnée en qualificatif, c'est elle qu'on utilise de préférence au mainsnak for i, j in ipairs(datequalifiers) do if claim.qualifiers[j] then snack = claim.qualifiers[j][1] break end end end if not snack then snack = claim.mainsnak or claim end if (snack.snaktype == 'value') and (snack.datatype == 'time') and (snack.datavalue.value.precision < minprecision) then return false end return true end function wd.sortClaims(claims, sorttype) if not claims then return nil end if sorttype == 'chronological' then return wd.chronoSort(claims) elseif sorttype == 'inverted' then return wd.chronoSort(claims, true) elseif sorttype == 'order' then return wd.chronoSort(claims) elseif type(sorttype) == 'function' then table.sort(claims, sorttype) return claims elseif type(sorttype) == 'string' and sorttype:sub(1, 1) == 'P' then return wd.numericPropertySort(claims, sorttype) end return claims end local alreadyFiltered = false function wd.filterClaims(claims, args) --retire de la tables de claims celles qui sont éliminés par un des filters de la table des filters local function filter(condition, filterfunction, funargs) if not args[condition] then return end for i = #claims, 1, -1 do if not( filterfunction(claims[i], args[funargs[1]], args[funargs[2]], args[funargs[3]]) ) then table.remove(claims, i) end end end filter('isinlang', isInLanguage, {'isinlang'} ) filter('excludespecial', notSpecial, {} ) filter('condition', check, {'condition'} ) if claims[1] and claims[1].mainsnak then filter('targetvalue', hasTargetValue, {'targetvalue'} ) filter('atdate', atDate, {'atdate'} ) filter('qualifier', wd.hasQualifier, {'qualifier', 'qualifiervalue'} ) filter('qualifiernumber', wd.hasQualifierNumber, {'qualifiernumber', 'qualifiernumbervalue'} ) filter('excludequalifier', excludeQualifier, {'excludequalifier', 'excludequalifiervalue'} ) filter('withsource', hasSource, {'withsource', 'sourceproperty'} ) filter('withdate', wd.hasDate, {} ) filter('excludevalues', excludeValues, {'excludevalues'}) filter('withlink', hasLink, {'withlink', 'linklang'} ) filter('minprecision', minPrecision, {'minprecision'} ) claims = withRank(claims, args.rank or 'best') end if args.sorttype then claims = wd.sortClaims(claims, args.sorttype) end if #claims == 0 then return nil end if args.numval2 then claims = lastVals(claims, args.numval2) end if args.numval then claims = firstVals(claims, args.numval) end return claims end function wd.loadEntity(entity, cache) if type(entity) ~= 'table' then if cache then if not cache[entity] then cache[entity] = mw.wikibase.getEntity(entity) mw.log("cached") end return cache[entity] else if entity == '' or (entity == '-') then entity = nil end return mw.wikibase.getEntity(entity) end else return entity end end function wd.getClaims( args ) -- returns a table of the claims matching some conditions given in args if args.claims then -- if claims have already been set, return them return args.claims end local properties = args.property if type(properties) == 'string' then properties = wd.splitStr(string.upper(args.property)) end if not properties then return formatError( 'property-param-not-provided' ) end --Get entity local entity = args.entity if type(entity) == 'string' then if entity == '' then entity = nil end elseif type(entity) == 'table' then entity = entity.id end if (not entity) then entity = mw.wikibase.getEntityIdForCurrentPage() end if (not entity) or (entity == '-') then return nil end local claims = {} if #properties == 1 then claims = mw.wikibase.getAllStatements(entity, properties[1]) -- do not use mw.wikibase.getBestStatements at this stage, as it may remove the best ranked values that match other criteria in the query else for i, prop in ipairs(properties) do local newclaims = mw.wikibase.getAllStatements(entity, prop) if newclaims and #newclaims > 0 then for j, claim in ipairs(newclaims) do table.insert(claims, claim) end end end end if (not claims) or (#claims == 0) then return nil end return wd.filterClaims(claims, args) end --=== ENTITY FORMATTING === function wd.getLabel(entity, lang, labelformat) if (not entity) then return nil -- ou option de gestion des erreurs ? end lang = lang or defaultlang if type(labelformat) == 'function' then return labelformat(entity) end entity = entity.id or ( type(entity) == "string" and entity) if (type(entity) == 'string') and (lang == defaultlang) then -- le plus économique local str = mw.wikibase.label(entity) if str then -- mw.wikibase.label() ne fonctionne pas avec les redirect https://phabricator.wikimedia.org/T157868 return str end end return mw.wikibase.getLabelByLang(entity, lang) end function wd.formatEntity( entity, params ) if (not entity) then return nil --formatError('entity-not-found') end local id = entity if type(id) == 'table' then id = id.id end params = params or {} local lang = params.lang or defaultlang local speciallabels = params.speciallabels local displayformat = params.displayformat local labelformat = params.labelformat local defaultlabel = params.defaultlabel or id local linktype = params.link local defaultlink = params.defaultlink local defaultlinkquery = params.defaultlinkquery if speciallabels and speciallabels[id] then --speciallabels override the standard label + link combination return speciallabels[id] end if params.displayformat == 'raw' then return id end local link, label label = wd.getLabel(entity, lang, labelformat) -- détermination du fait qu'on soit ou non en train de rendre l'élément sur la page de son article local rendering_entity_on_its_page = wd.isPageOfQId(id) if not label then if (defaultlabel == '-') then return nil end link = wd.siteLink(id, 'wikidata') return '[[' .. link .. '|' .. id .. ']]' .. addCat(modules.i18n['to translate']) -- si pas de libellé, on met un lien vers Wikidata pour qu'on comprenne à quoi ça fait référence end if (linktype == '-') or rendering_entity_on_its_page then return label end local link = wd.siteLink(entity, linktype, lang) -- defaultlinkquery will try to link to another page on this Wiki if (not link) and defaultlinkquery then if type(defaultlinkquery) == 'string' then defaultlinkquery = {property = defaultlinkquery} end defaultlinkquery.excludespecial = true defaultlinkquery.entity = entity local claims = wd.getClaims(defaultlinkquery) if claims then for i, j in pairs(claims) do local id = wd.getMainId(j) link = wd.siteLink(id, linktype, lang) if link then break end end end end if link then return '[[' .. link .. '|' .. label .. ']]' end -- if not link, you can use defaultlink: a sidelink to another Wikimedia project if (not defaultlink) then defaultlink = {'enwiki'} end if defaultlink and (defaultlink ~= '-') then local linktype local sidelink, site, langcode if type(defaultlink) == 'string' then defaultlink = {defaultlink} end for i, j in ipairs(defaultlink) do sidelink, site, langcode = wd.siteLink(entity, j, lang) if sidelink then break end end if not sidelink then sidelink, site = wd.siteLink(entity, 'wikidata') end local icon, class, title = site, nil, nil -- le texte affiché du lien if site == 'wiki' then icon, class, title = langcode, "indicateur-langue", wd.translate('see-another-language', mw.language.fetchLanguageName(langcode, defaultlang)) elseif site == 'wikidata' then icon, class, title = 'd', "indicateur-langue", wd.translate('see-wikidata') else title = wd.translate('see-another-project', site) end local val = '[[' .. sidelink .. '|' .. ']]' return label .. '' end return label end function wd.addTrackingCat(prop, cat) -- doit parfois être appelé par d'autres modules if type(prop) == 'table' then prop = prop[1] -- devrait logiquement toutes les ajouter end if not prop and not cat then return formatError("property-param-not-provided") end if not cat then cat = wd.translate('trackingcat', prop or 'P??') end return addCat(cat ) end local function unknownValue(snak, label) local str = label if type(str) == "function" then str = str(snak) end if (not str) then if snak.datatype == 'time' then str = wd.translate('sometime') else str = wd.translate('somevalue') end end if type(str) ~= "string" then return formatError(snak.datatype) end return str end local function noValue(displayformat) if not displayformat then return wd.translate('novalue') end if type(displayformat) == 'string' then return displayformat end return formatError() end local function getLangCode(entityid) return modules.langcodes[tonumber(entityid:sub(2))] end local function showLang(statement) -- retourne le code langue entre paranthèse avant la valeur (par exemple pour les biblios et liens externes) local mainsnak = statement.mainsnak if mainsnak.snaktype ~= 'value' then return nil end local langlist = {} if mainsnak.datavalue.type == 'monolingualtext' then langlist = {mainsnak.datavalue.value.language} elseif (not statement.qualifiers) or (not statement.qualifiers.P407) then return else for i, j in pairs( statement.qualifiers.P407 ) do if j.snaktype == 'value' then local langentity = wd.getId(j) local langcode = getLangCode(langentity) table.insert(langlist, langcode) end end end if (#langlist > 1) or (#langlist == 1 and langlist[1] ~= defaultlang) then -- si c'est en français, pas besoin de le dire return modules.langmodule.indicationMultilingue(langlist) end end -- === DATE HANDLING === function wd.addStandardQualifs(str, statement) if (not statement) or (not statement.qualifiers) then return str end if not str then return error()-- what's that ? end if statement.qualifiers.P1480 then for i, j in pairs(statement.qualifiers.P1480) do local v = wd.getId(j) if (v == "Q21818619") then str = wd.translate('approximate-place', str) elseif (v == "Q18122778") or (v == "Q18912752") then str = wd.translate('uncertain-information', str) elseif (v == "Q5727902") then if (statement.mainsnak.datatype == 'time') then str = modules.formatDate.fuzzydate(str) else str = wd.translate('approximate-value', str) end end end end return str end local function rangeObject(begin, ending, params) --[[ objet comportant un timestamp pour le classement chronologique et deux dateobject (begin et ending) ]]-- local timestamp if begin then timestamp = begin.timestamp else 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 {type = 'dateobject', timestamp = str, era = '+' ou '-', year = number, month = number, day = number, calendar = calendar} ]]-- if not params then params = {} end local newobj = modules.formatDate.splitDate(orig.time, orig.calendarmodel) newobj.precision = params.precision or orig.precision newobj.type = 'dateobject' return newobj end local function objectToText(obj, params) if obj.type == 'dateobject' then return modules.formatDate.simplestring(obj, params) elseif obj.type == 'rangeobject' then return modules.formatDate.daterange(obj.begin, obj.ending, params) end end function wd.getDateFromQualif(statement, qualif) if (not statement) or (not statement.qualifiers) or not (statement.qualifiers[qualif]) then return nil end local v = statement.qualifiers[qualif][1] if v.snaktype ~= 'value' then -- que faire dans ce cas ? return nil end return dateObject(v.datavalue.value) end function wd.getDate(statement) local period = wd.getDateFromQualif(statement, 'P585') -- retourne un dateobject if period then return period end local begin, ending = wd.getDateFromQualif(statement, 'P580'), wd.getDateFromQualif(statement, 'P582') if begin or ending then return rangeObject(begin, ending) -- retourne un rangeobject fait de deux dateobject end return nil end function wd.getFormattedDate(statement, params) if not statement then return nil end local str --cherche la date avec les qualifs P580/P582 local datetable = wd.getDate(statement) if datetable then str = objectToText(datetable, params) end -- puis limite intérieur / supérieur if not str then local start, ending = wd.getDateFromQualif(statement, 'P1319'), wd.getDateFromQualif(statement, 'P1326') str = modules.formatDate.between(start, ending, params) end -- sinon, le mainsnak, pour les données de type time if (not str) and (statement.mainsnak.datatype == 'time') then local mainsnak = statement.mainsnak if (mainsnak.snaktype == 'value') or (mainsnak.snaktype == 'somevalue') then str = wd.formatSnak(mainsnak, params) end end if str and params and (params.addstandardqualifs ~= '-') then str = wd.addStandardQualifs(str, statement) end return str end -- Fonction qui trie des Claims de type time selon l'ordre chronologique -- Une clé de tri nomée « dateSortKey » est ajouté à chaque claim. -- Si des clés de tri de ce nom existent déjà, elles sont utilisées sans modification. function wd.chronoSort( claims, inverted ) for _, claim in ipairs( claims ) do if not claim.dateSortKey then local snack = claim.mainsnak or claim local iso if (snack.snaktype == 'value') and (snack.datatype == 'time') then iso = snack.datavalue.value.time else iso = timeFromQualifs(claim, datequalifiers) or '0' end -- transformation en nombre (indication de la base car gsub retourne deux valeurs) iso = tonumber( iso:gsub( '(%d)%D', '%1' ), 10 ) claim.dateSortKey = iso end end table.sort( claims, function ( c1, c2 ) if inverted then return c2.dateSortKey < c1.dateSortKey end return c1.dateSortKey < c2.dateSortKey end ) return claims end -- Fonction qui trie des Claims de type value selon l'ordre de la propriété fournit -- Une clé de tri nomée « dateSortKey » est ajouté à chaque claim. -- Si des clés de tri de ce nom existent déjà, elles sont utilisées sans modification. function wd.numericPropertySort( claims, propertySort ) for _, claim in ipairs( claims ) do if not claim.dateSortKey then local val local claimqualifs = claim.qualifiers if claimqualifs then local vals = claimqualifs[propertySort] if vals and vals[1].snaktype == 'value' then val = vals[1].datavalue.value end end claim.dateSortKey = tonumber(val or 0) end end table.sort( claims, function ( c1, c2 ) return c1.dateSortKey < c2.dateSortKey end ) return claims end -- =================== function wd.getReferences(statement) local refdata = statement.references if not refdata then return nil end local refs = {} local hashes = {} for i, ref in pairs(refdata) do local s local function hasValue(prop) -- checks that the prop is here with valid value if ref.snaks[prop] and ref.snaks[prop][1].snaktype == 'value' then return true end return false end if ref.snaks.P248 then -- cas lorsque P248 (affirmé dans) est utilisé for j, source in pairs(ref.snaks.P248) do if source.snaktype == 'value' then local page, accessdate, quotation if hasValue('P304') then -- page page = wd.formatSnak(ref.snaks.P304[1]) end if hasValue('P813') then -- date de consultation accessdate = wd.formatSnak(ref.snaks.P813[1]) end if hasValue('P1683') then -- citation quotation = wd.formatSnak(ref.snaks.P1683[1]) end local sourceId = wd.getId(source) s = modules.reference.citeitem(sourceId, {['page'] = page, ['accessdate'] = accessdate, ['citation'] = quotation}) table.insert(refs, s) table.insert(hashes, ref.hash .. sourceId) end end elseif hasValue('P854') then -- cas lorsque P854 (URL de la référence) est utilisé local url, title, author, publisher, accessdate, publishdate, publishlang, quotation url = wd.formatSnak(ref.snaks.P854[1], {text = "-"}) if hasValue('P1476') then title = wd.formatSnak(ref.snaks.P1476[1]) else title = mw.ustring.gsub(url, '^[Hh][Tt][Tt][Pp]([Ss]?):(/?)([^/])', 'http%1://%3') end --todo : handle multiple values for author, etc. if hasValue('P813') then -- date de consultation accessdate = wd.formatSnak(ref.snaks.P813[1]) end if hasValue('P50') then -- author (item type) author = wd.formatSnak(ref.snaks.P50[1]) elseif hasValue('P2093') then -- author (string type) author = wd.formatSnak(ref.snaks.P2093[1]) end if hasValue('P123') then -- éditeur publisher = wd.formatSnak(ref.snaks.P123[1]) end if hasValue('P1683') then -- citation quotation = wd.formatSnak(ref.snaks.P1683[1]) end if hasValue('P577') then -- date de publication publishdate = wd.formatSnak(ref.snaks.P577[1]) end if hasValue('P407') then -- langue de l'œuvre local id = wd.getId(ref.snaks.P407[1]) publishlang = getLangCode(id) end s = modules.cite.lienWeb{titre = title, url = url, auteur = author, editeur = publisher, langue = publishlang, ['en ligne le'] = publishdate, ['consulté le'] = accessdate, ['citation'] = quotation} table.insert(hashes, ref.hash) table.insert(refs, s) elseif ref.snaks.P854 and ref.snaks.P854[1].snaktype == 'value' then s = wd.formatSnak(ref.snaks.P854[1], {text = "-"}) table.insert(hashes, ref.snaks.P854[1].hash) table.insert(refs, s) end end if #refs > 0 then if #hashes == #refs then return refs, hashes end return refs end end function wd.sourceStr(sources, hashes) if not sources or (#sources == 0) then return nil end local useHashes = hashes and #hashes == #sources for i, j in ipairs(sources) do local refArgs = {name = 'ref', content = j} if useHashes and hashes[i] ~= '-' then refArgs.args = {name = 'wikidata-' .. hashes[i]} end sources[i] = mw.getCurrentFrame():extensionTag(refArgs) end return table.concat(sources) end function wd.getDataValue(snak, params) if not params then params = {} end local speciallabels = params.speciallabels -- parfois on a besoin de faire une liste d'éléments pour lequel le libellé doit être changé, pas très pratique d'utiliser une fonction pour ça if snak.snaktype ~= 'value' then return nil end local datatype = snak.datatype local value = snak.datavalue.value local displayformat = params.displayformat if type(displayformat) == 'function' then return displayformat(snak, params) end if datatype == 'wikibase-item' then return wd.formatEntity(wd.getId(snak), params) end if datatype == 'url' then return modules.weblink.makelink(value, params.text) end if datatype == 'math' then return mw.getCurrentFrame():extensionTag( "math", value) end if (datatype == 'string') or (datatype == 'external-id') or (datatype == 'commonsMedia') then -- toutes les données de type string sauf "math" if params.urlpattern then local urlpattern = params.urlpattern if type(urlpattern) == 'function' then urlpattern = urlpattern(value) end local url = mw.ustring.gsub(urlpattern, '$1', (value:gsub('%%', '%%%%'))):gsub(' ', '%%20') value = '[' .. url .. ' ' .. (params.text or value) .. ']' end return value end if datatype == 'time' then -- format example: +00000001809-02-12T00:00:00Z if displayformat == 'raw' then return value.time else local dateobject = dateObject(value, {precision = params.precision}) return objectToText(dateobject, params) end end if datatype == 'globe-coordinate' 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 else local coordvalue = mw.clone( value ) coordvalue.globe = modules.globes[value.globe] -- transforme l'ID du globe en nom anglais utilisable par geohack return coordvalue -- note : les coordonnées Wikidata peuvent être utilisée depuis Module:Coordinates. Faut-il aussi autoriser à appeler Module:Coordiantes ici ? end end if datatype == 'quantity' then -- todo : gérer les paramètres précision local amount, unit = value.amount, value.unit if unit then unit = unit:match('Q%d+') end local raw if displayformat == "raw" then raw = true end return modules.formatNum.displayvalue(amount, unit, {targetunit = params.targetunit, raw = raw, rounding = params.rounding, showunit = params.showunit or 'short', showlink = params.showlink} ) end if datatype == 'monolingualtext' then if value.language == defaultlang then return value.text else return modules.langmodule.langue({value.language, value.text}) end end return formatError('unknown-datavalue-type' ) end function wd.stringTable(args) -- like getClaims, but get a list of string rather than a list of snaks, for easier manipulation local claims = args.claims if not claims then claims = wd.getClaims(args) end if not claims or claims == {} then return {}, {} end local props = {} -- liste des propriétés associété à chaque string pour catégorisation et linkback for i, j in pairs(claims) do claims[i] = wd.formatStatement(j, args) table.insert(props, j.mainsnak.property) end if args.removedupes and (args.removedupes ~= '-') then claims = wd.addNewValues({}, claims) -- devrait aussi supprimer de props celles qui ne sont pas utilisées end return claims, props end function wd.getQualifiers(statement, qualifs, params) if not statement.qualifiers then return nil end local vals = {} if type(qualifs) == 'string' then qualifs = wd.splitStr(qualifs) end for i, j in pairs(qualifs) do if statement.qualifiers[j] then for k, l in pairs(statement.qualifiers[j]) do table.insert(vals, l) end end end if #vals == 0 then return nil end return vals end function wd.getFormattedQualifiers(statement, qualifs, params) if not params then params = {} end local qualiftable = wd.getQualifiers(statement, qualifs) if not qualiftable then return nil end qualiftable = wd.filterClaims(qualiftable, params) or {} for i, j in pairs(qualiftable) do qualiftable[i] = wd.formatSnak(j, params) end return modules.linguistic.conj(qualiftable, params.conjtype) end function wd.showQualifiers(str, statement, args) local qualifs = args.showqualifiers if not qualifs then return str -- or error ? end if type(qualifs) == 'string' then qualifs = wd.splitStr(qualifs) end local qualifargs = args.qualifargs or {} -- formatage des qualificatifs = args commençant par "qualif", ou à défaut, les mêmes que pour la valeur principale qualifargs.displayformat = args.qualifdisplayformat or args.displayformat qualifargs.labelformat = args.qualiflabelformat or args.labelformat qualifargs.link = args.qualiflink or args.link qualifargs.linktopic = args.qualiflinktopic or args.linktopic qualifargs.conjtype = args.qualifconjtype qualifargs.defaultlink = args.qualifdefaultlink or args.defaultlink qualifargs.defaultlinkquery = args.qualifdefaultlinkquery or args.defaultlinkquery local formattedqualifs = wd.getFormattedQualifiers(statement, qualifs, qualifargs) if formattedqualifs and formattedqualifs ~= "" then str = str .. " (" .. formattedqualifs .. ")" end return str end function wd.formatSnak( snak, params ) if not params then params = {} end -- pour faciliter l'appel depuis d'autres modules if snak.snaktype == 'somevalue' then return unknownValue(snak, params.unknownlabel) elseif snak.snaktype == 'novalue' then return noValue(params.novaluelabel) elseif snak.snaktype == 'value' then return wd.getDataValue( snak, params) else return formatError( 'unknown-snak-type' ) end end function wd.formatStatement( statement, args ) if not args then args = {} end if not statement.type or statement.type ~= 'statement' then return formatError( 'unknown-claim-type' ) end local prop = statement.mainsnak.property local str -- special displayformat f if args.statementformat and (type(args.statementformat) == 'function') then str = args.statementformat(statement, args) elseif (statement.mainsnak.datatype == 'time') and (statement.mainsnak.dateformat ~= '-') then if args.displayformat == 'raw' and statement.mainsnak.snaktype == 'value' then str = statement.mainsnak.datavalue.value.time else str = wd.getFormattedDate(statement, args) end elseif args.showonlyqualifier and (args.showonlyqualifier ~= '') then str = wd.getFormattedQualifiers(statement, args.showonlyqualifier, args) if not str then return nil end if args.addstandardqualifs ~= '-' then str = wd.addStandardQualifs(str, statement) end else str = wd.formatSnak( statement.mainsnak, args ) if args.addstandardqualifs ~= '-' then str = wd.addStandardQualifs(str, statement) end end -- ajouts divers if args.showlang == true then local indicateur = showLang(statement) if indicateur then str = indicateur .. '&nbsp;' .. str end end if args.showqualifiers then str = wd.showQualifiers(str, statement, args) end if args.showdate then -- when "showdate and chronosort are both set, date retrieval is performed twice local period = wd.getFormattedDate(statement, args, "-") -- 3 arguments indicate the we should not use additional qualifiers, alrady added by wd.formatStatement if period then str = str .. " <small>(" .. period .. ")</small>" end end if args.showsource then local sources, hashes = wd.getReferences(statement) if sources then local source = wd.sourceStr(sources, hashes) if source then str = str .. source end end end return str end function wd.addLinkBack(str, id, property) if not id then id = wd.getEntityIdForCurrentPage() end if not id then return str end if type(property) == 'table' then property = property[1] end id = wd.entityId(id) local class = '' if property then class = 'wd_' .. string.lower(property) end local icon = '[[File:Blue pencil.svg|%s|10px|baseline|class=noviewer|link=%s]]' local title = wd.translate('see-wikidata-value') local url = mw.uri.fullUrl('d:' .. id, 'uselang=diq') url.fragment = property -- ajoute une #ancre si paramètre "property" défini url = tostring(url) local v = mw.html.create('span') :addClass(class) :wikitext(str) :tag('span') :addClass('noprint wikidata-linkback') :wikitext(icon:format(title, url)) :allDone() return tostring(v) end function wd.addRefAnchor(str, id) --[[ Insère une ancre pour une référence générée à partir d'un élément wd. L'id Wikidata sert d'identifiant à l'ancre, à utiliser dans les modèles type "harvsp" --]] return tostring( mw.html.create('span') :attr('id', id) :attr('class', "ouvrage") :wikitext(str) ) end --=== FUNCTIONS USING AN ENTITY AS ARGUMENT === local function formatStatementsGrouped(args, type) -- regroupe les affirmations ayant la même valeur en mainsnak, mais des qualificatifs différents -- (seulement pour les propriétés de type élément) local claims = wd.getClaims(args) if not claims then return nil end local groupedClaims = {} -- regroupe les affirmations par valeur de mainsnak local function addClaim(claim) local id = wd.getMainId(claim) for i, j in pairs(groupedClaims) do if (j.id == id) then table.insert(groupedClaims[i].claims, claim) return end end table.insert(groupedClaims, {id = id, claims = {claim}}) end for i, claim in pairs(claims) do addClaim(claim) end local stringTable = {} -- instructions ad hoc pour les paramètres concernant la mise en forme d'une déclaration individuelle local funs = { {param = "showqualifiers", fun = function(str, claims) local qualifs = {} for i, claim in pairs(claims) do local news = wd.getFormattedQualifiers(claim, args.showqualifiers, args) if news then table.insert(qualifs, news) end end local qualifstr = modules.linguistic.conj(qualifs, "qualif-separator") if qualifstr and qualifstr ~= "" then str = str .. " (" .. qualifstr .. ")" end return str end }, {param = "showdate", fun = function(str, claims) -- toutes les dates sont regroupées à l'intérieur des mêmes parenthèses ex "médaille d'or (1922, 1924)" local dates = {} for i, statement in pairs(claims) do local s = wd.getFormattedDate(statement, args, true) if statement then table.insert(dates, s) end end local datestr = modules.linguistic.conj(dates) if datestr and datestr ~= "" then str = str .. " <small>(" .. datestr .. ")</small>" end return str end }, {param = "showsource", fun = function(str, claims) -- les sources sont toutes affichées au même endroit, à la fin -- si deux affirmations ont la même source, on ne l'affiche qu'une fois local sources = {} local hashes = {} local function dupeRef(old, new) for i, j in pairs(old) do if j == new then return true end end end for i, claim in pairs(claims) do local refs, refHashes = wd.getReferences(claim) if refs then for i, j in pairs(refs) do if not dupeRef(sources, j) then table.insert(sources, j) local hash = (refHashes and refHashes[i]) or '-' table.insert(hashes, hash) end end end end return str .. (wd.sourceStr(sources, hashes) or "") end } } for i, group in pairs(groupedClaims) do -- bricolage pour utiliser les arguments de formatStatements local str = wd.formatEntity(group.id, args) for i, fun in pairs(funs) do if args[fun.param] then str = fun.fun(str, group.claims, args) end end table.insert(stringTable, str) end args.valuetable = stringTable return wd.formatStatements(args) end function wd.formatStatements( args )--Format statement and concat them cleanly if args.value == '-' then return nil end -- If a value is already set: use it, except if it's the special value {{WD}} (use wikidata) if args.value and args.value ~= '' then local valueexpl = wd.translate("activate-query") if args.value ~= valueexpl then return args.value end -- There is no value set, and args.expl disables wikidata on empty values elseif args.expl then return nil end if args.grouped and args.grouped ~= '' then args.grouped = false return formatStatementsGrouped(args) end local valuetable = args.valuetable -- dans le cas où les valeurs sont déjà formtées local props -- les prorpriétés réellement utilisées (dans certainse cas, ce ne sont pas toutes celles de ags.property if not valuetable then -- cas le plus courant valuetable, props = wd.stringTable(args) end local str = modules.linguistic.conj(valuetable, args.conjtype) if not str then return args.default end if not props then props = wd.splitStr(args.property)[1] end if args.ucfirst ~= '-' then str = modules.linguistic.ucfirst(str) end if args.addcat and (args.addcat ~= '-') then str = str .. wd.addTrackingCat(props) end if args.linkback and (args.linkback ~= '-') then str = wd.addLinkBack(str, args.entity, props) end if args.returnnumberofvalues then return str, #valuetable end return str end function wd.formatAndCat(args) if not args then return nil end args.linkback = args.linkback or true args.addcat = true if args.value then -- do not ignore linkback and addcat, as formatStatements do if args.value == '-' then return nil end local val = args.value .. wd.addTrackingCat(args.property) val = wd.addLinkBack(val, args.entity, args.property) return val end return wd.formatStatements( args ) end function wd.getTheDate(args) local claims = wd.getClaims(args) if not claims then return nil end local formattedvalues = {} for i, j in pairs(claims) do local v = wd.getFormattedDate(j, args) if v then table.insert(formattedvalues, v ) end end local val = modules.linguistic.conj(formattedvalues) if not val then return nil end if args.addcat == true then val = val .. wd.addTrackingCat(args.property) end val = wd.addLinkBack(val, args.entity, args.property) return val end function wd.keyDate (event, item, params) params = params or {} params.entity = item if type(event) == 'table' then for i, j in pairs(event) do params.targetvalue = nil -- réinitialisation barbare des paramètres modifiés local s = wd.keyDate(j, item, params) if s then return s end end elseif type(event) ~= 'string' then return formatError('invalid-datatype', type(event), 'string') elseif string.sub(event, 1, 1) == 'Q' then -- on demande un élément utilisé dans P:P793 (événement clé) params.property = 'P793' params.targetvalue = event params.addcat = params.addcat or true return wd.getTheDate(params) elseif string.sub(event, 1, 1) == 'P' then -- on demande une propriété params.property = event return wd.formatAndCat(params) else return formatError('invalid-entity-id', event) end end function wd.mainDate(entity) -- essaye P580/P582 local args = {entity = entity, addcat = true} args.property = 'P580' local startpoint = wd.formatStatements(args) args.property = 'P582' local endpoint = wd.formatStatements(args) local str if (startpoint or endpoint) then str = modules.formatDate.daterange(startpoint, endpoint, params) str = wd.addLinkBack(str, entity, 'P582') return str end -- défaut : P585 args.property = {'P585', 'P571'} args.linkback = true return wd.formatStatements(args) end -- === FUNCTIONS FOR TRANSITIVE PROPERTIES === function wd.getIds(item, query) query.excludespecial = true query.displayformat = 'raw' query.entity = item query.addstandardqualifs = '-' return wd.stringTable(query) end -- recursively adds a list of qid to an existing list, based on the results of a query function wd.addVals(list, query, maxdepth, maxnodes, stopval) maxdepth = tonumber(maxdepth) or 10 maxnodes = tonumber(maxnodes) or 100 if (maxdepth < 0) then return list end if stopval and wd.isHere(list, stopval) then return list end local origsize = #list for i = 1, origsize do -- tried a "checkpos" param instead of starting to 1 each time, but no impact on performance local candidates = wd.getIds(list[i], query) list = wd.addNewValues(list, candidates, maxnodes, stopval) if list[#list] == stopval then return list end if #list >= maxnodes then return list end end if (#list == origsize) then return list end return wd.addVals(list, query, maxdepth - 1, maxnodes, stopval, origsize + 1) end -- returns a list of items transitively matching a query (orig item is not included in the list) function wd.transitiveVals(item, query, maxdepth, maxnodes, stopval) maxdepth = tonumber(maxdepth) or 5 if type(query) == "string" then query = {property = query} end -- récupération des valeurs local vals = wd.getIds(item, query) if not vals then return nil end local v = wd.addVals(vals, query, maxdepth - 1, maxnodes, stopval) if not v then return nil end -- réarrangement des valeurs if query.valorder == "inverted" then local a = {} for i, j in pairs(v) do table.insert(a, 1, j) end v = a end return v end -- returns true if an item is the value of a query, transitively function wd.inTransitiveVals(searchedval, sourceval, query, maxdepth, maxnodes ) local vals = wd.transitiveVals(sourceval, query, maxdepth, maxnodes, searchedval ) if (not vals) then return false end for _, val in ipairs(vals) do if (val == searchedval) then return true end end return false end -- returns true if an item is a superclass of another, based on P279 function wd.isSubclass(class, item, maxdepth) local query = {property = 'P279'} if class == item then -- item is a subclass of itself iff it is a class if wd.getIds(item, query) then return true end return false end return wd.inTransitiveVals(class, item, query, maxdepth ) end -- returns true if one of the best ranked P31 values of an item is the target or a subclass of the target -- rank = 'valid' would seem to make sense, but it would need to check for date qualifiers as some P31 values have begin or end date function wd.isInstance(targetclass, item, maxdepth) maxdepth = maxdepth or 10 local directclasses = wd.transitiveVals(item, {property = 'P31'}, 1) if not directclasses then return false end for i, class in pairs(directclasses) do if wd.isSubclass(targetclass, class, maxdepth - 1) then return true end end return false end -- return the first value in a transitive query that belongs to a particular class. For instance find a value of P131 that is a province of Canada function wd.findVal(sourceitem, targetclass, query, recursion, instancedepth) if type(query) == "string" then query = {property = query} end local candidates = wd.getIds(sourceitem, query) if candidates then for i, j in pairs(candidates) do if wd.isInstance(targetclass, j, instancedepth) then return j end end if not recursion then recursion = 3 else recursion = recursion - 1 end if recursion < 0 then return nil end for i, candidate in pairs(candidates) do return wd.findVal(candidate, targetclass, query, recursion, instancedepth) end end end -- === VARIA === function wd.getDescription(entity, lang) lang = lang or defaultlang local description if lang == defaultlang then return mw.wikibase.descriptionl(qid) end if not entity.descriptions then return wd.translate('no description') end local descriptions = entity.descriptions if not descriptions then return nil end if descriptions[lang] then return descriptions[delang].value end return entity.id end function wd.Dump(entity) entity = wd.getEntity(entity) if not entity then return formatError("entity-param-not-provided") end return "<pre>"..mw.dumpObject(entity).."</pre>" end function wd.frameFun(frame) local args = frame.args local funname = args[1] table.remove(args, 1) return wd[funname](args) end return wd dpvnumy5zupnmafj3h7h8nxf2so54d7 Modul:Navbar 828 42728 549190 546492 2026-06-22T07:06:51Z Mirzali 16 Vurnayışê hesabê 546492 ke terefê [[Karber:Kosotorx|Kosotorx]] ra peyser gêriyayo. 549190 Scribunto text/plain local p = {} local getArgs function p._navbar(args) local titleArg = 1 if args.collapsible then titleArg = 2 if not args.plain then args.mini = 1 end if args.fontcolor then args.fontstyle = 'color:' .. args.fontcolor .. ';' end args.style = 'float:left; text-align:left; width:6em;' end local titleText = args[titleArg] or (':' .. mw.getCurrentFrame():getParent():getTitle()) local title = mw.title.new(mw.text.trim(titleText), 'Template'); if not title then error(' ' .. 'name') end local talkpage = title.talkPageTitle and title.talkPageTitle.fullText or ''; local div = mw.html.create():tag('div') div :addClass('plainlinks') :addClass('hlist') :addClass('navbar') :cssText(args.style) if args.mini then div:addClass('mini') end if not (args.mini or args.plain) then div :tag('span') :css('word-spacing', 0) :cssText(args.fontstyle) :wikitext(args.text or 'This box:') :wikitext(' ') end if args.brackets then div :tag('span') :css('margin-right', '-0.125em') :cssText(args.fontstyle) :wikitext('&#91;') :newline(); end if not args.noedit then ul :tag('li') :addClass('nv-edit') :wikitext('[' .. title:fullUrl('action=edit') .. ' ') :tag(args.mini and 'abbr' or 'span') :attr('title', 'Edit this template') :cssText(args.fontstyle) :wikitext(args.mini and 'e' or 'edit') :done() :wikitext(']'); end if args.brackets then div :tag('span') :css('margin-left', '-0.125em') :cssText(args.fontstyle) :wikitext('&#93;') :newline(); end if args.collapsible then div :done() :tag('span') :css('font-size', '110%') :cssText(args.fontstyle) :wikitext(args[1]) end return tostring(div:done()) end function p.navbar(frame) if not getArgs then getArgs = require('Module:Arguments').getArgs end return p._navbar(getArgs(frame)) end return p ih95soqt0dww8di3zm2y7sqlv8xfa9q Modul:Interface Wikidata 828 60928 549189 548546 2026-06-22T07:04:28Z Mirzali 16 Vurnayışê hesabê 548546 ke terefê [[Karber:Ghostwer|Ghostwer]] ra peyser gêriyayo. 549189 Scribunto text/plain local p = {} local d = require 'Module:Wikidata' -- fonctions ne pouvant être appelées que depuis un autre module p.fromLua = { -- manipulation d'une liste d'affirmations getClaims = d.getClaims, stringTable = d.stringTable, tableToText = d.tableToText, formatStatements = d.formatStatements, formatQualifiers = d.showQualifier, formatAndCat = d.formatAndCat, wikidataDate = d.wikidataDate, addLinkback = d.addLinkBack, addtrackingcat = d.addTrackingCat, -- manipulation d'une affirmation individelle getmainid = d.getMainId, formatStatement = d.formatStatement, statementDate = d.getFormattedDate, -- récupère la date des qualificatifs getFormattedQualifiers = d.getFormattedQualifiers, getQualifiers = d.getQualifiers, getReferences = d.getReferences, -- manipulation de snaks getid = d.getId, formatSnak = d.formatSnak, -- utilisation de qids getEntity = d.getEntity, formatEntity = d.formatEntity, getLink = d.siteLink, getLabel = d.getLabel, --getLabel est plus simple que formatEntity -- utilisation des propriétés transitives isInstance = d.isInstance, isSubclass = d.isSubclass, addVals = d.addVals, transitiveVals = d.transitiveVals, inTransitiveVals = d.inTransitiveVals, findVal = d.findVal, -- gestion des dates mainDate = d.mainDate, getDate = d.getTheDate, keyDate = d.keyDate, -- Fonctions diverses citeItem = d.citeitem, translate = d.translate, Dump = d.Dump, } -- Fonctions frame pour usage depuis le Wikitexte (avec parfois des options pour gérer des données moins propres local function cleanargs(args) local newargs = {} for i, j in pairs(args) do if j ~= '' then newargs[i] = j end end return newargs end function p.formatStatements( frame ) -- pour [[Modèle:Wikidata]] 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.fromLua.formatStatements( args ) end function p.addLinkBack( frame ) local args = cleanargs(frame.args) if args[1] and args[1]:match"%S" then return d.addLinkBack( '', args.entity, mw.text.trim( args[1] ) ) end end function p.formatEntity(frame) local args = cleanargs(frame.args) local entity = args.entity or args[1] if (not entity) or (entity == '') then entity = mw.wikibase.getEntityObject() end return d.formatEntity(entity, args) end function p.formatAndCat(frame) local args = cleanargs(frame.args) return d.formatAndCat(args) end function p.citeItem(frame) local args = cleanargs(frame.args) local item, page = args[1], args['page'] return p.fromLua.citeItem(item, page) end function p.getLabel(frame) local args = cleanargs(frame.args) local item = args[1] local lang = args[2] or "diq" return d.getLabel(item, lang) end function p.mainDate(frame) return d.mainDate(frame.args['entity']) end function p.Dump(frame) return d.Dump(frame.args[1]) end function p.formatQualifiers(frame) local args = frame.args return d.formatQualifiers(args) end function p.getDescription(frame) -- fonction simpliste, mais bon, les descriptions Wikidata, c'est pas non plus super utile return mw.wikibase.description(frame.args[1]) end function p.getLink(frame) local args = frame.args local link, proj, lang = p.fromLua.getLink(args[1], args[2], args[3]) return link end function p.translate(frame) return d.translate(frame.args[1]) end function p.findVal(frame) local args = frame.args return d.findVal(args.source, args.target, args.property, args.recursion, args.instancedepth) end function p.transitiveVals(frame) local args = frame.args return d.transitiveVals(args.item, args, args.maxdepth, args.maxnodes, args.stopval, true) end return p jqlhtisqyy0vys9obingsf4luhprrwb Modul:Date complexe 828 60929 549188 548300 2026-06-22T07:01:39Z Mirzali 16 Vurnayışê hesabê 548300 ke terefê [[Karber:~2026-18379-86|~2026-18379-86]] ra peyser gêriyayo. 549188 Scribunto text/plain -- TODO: améliorer les synergies avec Module:Date (gestion par module:Date de dates sans lien et de "XIe siècle en astronautique" local datemodule = require 'Module:Date' local linguistic -- = require 'Module:Linguistique' -- chargé uniquement si nécessaire local roman -- = require 'Module:Romain' -- chargé uniquement si nécessaire local p = {} local numericprecision = { -- convertir les précisions en valeurs numériques = à celles utilisées par Wikidata gigayear = 0, megayear = 3, millenium = 6, century = 7, decade = 8, year = 9, month = 10, day = 11, hour = 12, minute = 13, second = 14, } local function vowelfirst(str) linguistic = require 'Module:Linguistique' return linguistic.vowelfirst(str) end local function setprecision(obj, maxprecision) local precision if type(obj) == "string" then precision = tonumber(obj) elseif type(obj) == "number" then precision = obj elseif type(obj) == "table" then precision = tonumber(obj.precision) or numericprecision[obj.precision] end if not precision then precision = 0 end -- maxprecision, surtout pour données Wikidata quand on veut afficher avec moins de précision que l'input (par exemple afficher seulement l'année) if maxprecision then maxprecision = tonumber(maxprecision) or numericprecision[maxprecision] end if maxprecision then return math.min(precision, maxprecision) end return precision end local function bigDate(year, precision) -- TODO : gestion de la précision local format = require "Module:Format" local val, unit = 0, "" if year > 999999999 then unit = " [[giga|G]][[Année julienne|a]]" val = year / 1000000000 elseif year > 999999 then unit = " [[méga|M]][[Année julienne|a]]" val = year / 1000000 end val = format.do_formatnum({val}) return val .. unit end local function milleniumString(millenium, era, hideera) roman = roman or require 'Module:Romain' local str = roman.toRoman(millenium) .. 'hezar' if era == '-' and (not hideera) then str = str .. 'İR ' end return str end local function centuryString(century, era, hideera) roman = roman or require 'Module:Romain' local str = 'Seserra' .. roman.toRoman(century) if era == '-' and (not hideera) then str = str .. 'İR' end return str end local function decadeString(decade, era, hideera) local str = ' ' .. decade .. '0' if era == '-' and (not hideera) then str = str .. ' İR ' end return '[[' .. str .. ']]' end function p.simplestring(dateobject, displayformat) -- transforme un object date ponctuel en texte -- les dates de type ISO devraient passer par Module:Date, mais il faut pouvoir désactiver les liens if type(dateobject) == 'string' or type(dateobject) == 'nil' then return dateobject end if (not dateobject.year) and (not dateobject.month) and dateobject.day then -- si seul le jour est passé, par exemple à cause de removeclutter, le format n'est pas pris en charge par module:Date if displayformat.precision and numericprecision[displayformat.precision] < 11 then return '' else return tostring(dateobject.day) end end local era = dateobject.era if not displayformat then displayformat = {} end local linktopic = displayformat.linktopic local nolinks if linktopic == '-' then nolinks = true end local str local precision = setprecision(dateobject, displayformat.precision) -- formats gérés par ce module local year = tonumber( dateobject.year) or 0 if year > 999999 then -- grosses dates pour l'astronomie, la paléontologie return bigDate(year, precision) end local hideera = displayformat.hideera if precision == 6 then local millenium = math.floor((year - 1)/1000) + 1 str = milleniumString(millenium, era, hideera) elseif precision == 7 then local century = math.floor((year - 1)/100) + 1 str = centuryString(century, era, hideera) elseif precision == 8 then local decade = tostring(math.floor(year/10)) str = decadeString(decade, era, hideera) end if str then return str end -- formats gérés par Module:Date local year = dateobject.year if year and (era == '-') then year = 0 - year end local month, day if precision > 9 then month = dateobject.month if precision > 10 then day = dateobject.day end end local avJC -- équivalent de hideera pour modeleDate if displayformat.hideera then avJC = 'non' end str = datemodule.modeleDate{jour = day, mois = month, annee = year, qualificatif = linktopic, nolinks = nolinks, avJC = avJC} return str or '' end local function fromToNow(d, datestr, precision) -- retourne "depuis" plutôt que "à partir de" quand c'est pas terminé if (precision >= 11) or (precision == 7) or (precision == 6) then -- ont dit "à partir du pour les dates avec jour, les siècles, les millénaires if vowelfirst(datestr) then -- suppose l'absence de lien interne return "depuis l'" .. datestr else return "depuis le " .. datestr end end return "depuis " .. datestr end local function fromdate(d, displayformat) -- retourne "à partir de date" en langage naturel displayformat = displayformat or {} local precision = setprecision(d, displayformat.precision) local datestr = p.simplestring(d, displayformat) if displayformat and displayformat.textformat == 'minimum' then return datestr -- par exemple pour les classements MH, juste afficher la date de début end if displayformat and displayformat.textformat == 'short' then return datestr .. '&nbsp;&ndash;&nbsp;' -- pour certaines infobox (footballeur par exemple), afficher date de début et un tiret end if p.before ( os.date("!%Y-%m-%dT%TZ"), d) then return fromToNow(d, datestr, precision) end if (precision >= 11) or (precision == 7) or (precision == 6) then -- ont dit "à partir du pour les dates avec jour, les siècles, les millénaires return 'à partir du ' .. datestr end if (precision == 10) and (vowelfirst(datemodule.determinationMois(d.month))) then return "à partir d'" .. datestr end return 'à partir de ' .. datestr end local function upto(d, displayformat) -- retourne "jusqu'à date' en langage naturel displayformat = displayformat or {} local datestring = p.simplestring(d, displayformat) local precision = setprecision(d, displayformat.precision) if displayformat and displayformat.textformat == 'infobox' then return '&nbsp;&ndash;&nbsp;'.. datestring-- pour certaines infobox (footballeur par exemple), afficher date de début et un tiret end if displayformat and displayformat.textformat == 'short' then return'&nbsp;&ndash;&nbsp;' .. datestring -- pour certaines infobox (footballeur par exemple), afficher date de début et un tiret end if (precision >= 11) or (precision == 7) or (precision == 6) then --on dit "jusqu'au" pour les dates avec jour, et pour les siècles return "jusqu'au " .. datestring elseif (precision > 9) then return "jusqu'à " .. datestring else return "jusqu'en " .. datestring end end local function fromuntillong(startstr, endstr, era, precision) -- on dit "du 3 au 14 janvier" mais "de septembe à octobre if precision >= 11 then -- >= day return "du " .. startstr .. " au " .. endstr .. era else if vowelfirst(startstr) then return "d'" .. startstr .. " à ".. endstr .. era else return "de " .. startstr .. " à " .. endstr .. era end end end local function removeclutter(startpoint, endpoint, precision, displayformat) -- prépare à rendre la date plus jolie : "juin 445 av-JC-juillet 445 av-JC -> juin-juillet 445-av-JC" if (type(startpoint) ~= 'table') or (type(endpoint) ~= 'table') then return startpoint, endpoint, precision, displayformat end local era = endpoint.era local sameera if startpoint.era == endpoint.era then sameera = true end if sameera and (endpoint.year == startpoint.year) then startpoint.year = nil if (startpoint.month == endpoint.month) then startpoint.month = nil if (startpoint.day == endpoint.day) then startpoint.day = nil end end end return startpoint, endpoint, era, displayformat, sameera end function p.between(startpoint, endpoint, displayformat) displayformat = displayformat or {} local precision = setprecision(endpoint, displayformat.precision) or 9 local startpoint = p.simplestring(startpoint, displayformat) local endpoint = p.simplestring(endpoint, displayformat) if not (startpoint or endpoint) then return nil end if not endpoint then if precision <= 10 then return "après " .. startpoint else return "après le " .. startpoint end end if not startpoint then if precision <= 10 then return "avant " .. endpoint else return "avant le " .. endpoint end end -- analyse les paramètres pour éviter les redondances local startpoint, endpoint, era, displayformat, sameera = removeclutter(startpoint, endpoint, precision, displayformat) local startstr, endstr = p.simplestring(startpoint, displayformat), p.simplestring(endpoint, displayformat) displayformat.hideera = true if (startstr == '') or (startstr == endstr) then if (not sameera) then displayformat.hideera = false --sinon c'est incompréhensible return p.simplestring(endpoint, displayformat) end return endstr end -- pour éviter les tournures répétitives comme "du 13 septembre 2006 au 18 september 2006" if era == "-" then era = " av J-C" else era = "" end if precision <= 10 then return "mabênê " .. startstr .. " ya zi " .. endstr .. " " .. era else return "entre le " .. startstr .. " et le " .. endstr .. " " .. era end end local function fromuntil(startpoint, endpoint, displayformat) displayformat = displayformat or {} local precision = setprecision(endpoint, displayformat.precision) -- analyse les paramètres pour éviter les redondances local startpoint, endpoint, era, displayformat, sameera = removeclutter(startpoint, endpoint, precision, displayformat) local hideera= displayformat.hideera displayformat.hideera = true -- pour les chaînes intermédiaires local startstr, endstr = p.simplestring(startpoint, displayformat), p.simplestring(endpoint, displayformat) if (startstr == '') or (startstr == endstr) then displayformat.hideera = hideera -- on va faire une chaîne simple, on reprend donc le format initialement demandé if (not sameera) then displayformat.hideera = false --sinon c'est incompréhensible end return p.simplestring(endpoint, displayformat) end -- pour éviter les tournures répétitives comme "du 13 septembre 2006 au 18 september 2006" if era == '-' then era = ' İR' else era = '' end if displayformat.textformat == 'long' then return fromuntillong(startstr, endstr, era, precision) elseif (type(precision) == "number") and (precision > 9) then -- si les date contiennent des mois ou jours, il vaut mieux un espace return startstr .. ' -<wbr> ' .. endstr .. era else return startstr .. '-<wbr>' .. endstr .. era end end function p.fuzzydate(dateobject, displayformat) local str = p.simplestring(dateobject, displayformat) if not str then return nil end return "verê " .. str end function p.daterange(startpoint, endpoint, displayformat) if startpoint and endpoint then return fromuntil(startpoint, endpoint, displayformat) elseif startpoint then return fromdate(startpoint, displayformat) elseif endpoint then return upto(endpoint, displayformat) else return nil end end function p.duration(start, ending) if (not start) or (not ending) then return nil -- ? end return datemodule.age(start.year, start.month, start.day, ending.year, ending.month, ending.day) end local function splitWDdate(str) -- depuis datavalue.value.time de Wikidata, fonctionnerait aussi en utilisant simplement splitISO local pattern = "(%W)(%d+)%-(%d+)%-(%d+)" local era, year, month, day = str:match(pattern) return era, year, month, day end local function splitISO(str) local era, year, month, day era = string.sub(str, 1, 1) if tonumber(era) then era = '+' end local f = string.gmatch(str, '%d+') year, month, day = f(), f(), f() return era, year, month, day end function p.splitDate(orig, calendar) if not orig then return nil end if type(orig) == 'table' then return orig end if type(orig) ~= 'string' then return error("bad datatype for date, string expected, got " .. type(orig)) end local era, y, m, d = splitWDdate(orig) if not era then era, y, m, d = splitISO(orig) end y, m, d = tonumber(y or 1), tonumber(m or 1), tonumber(d or 1) return {day = d, month = m, year = y, era = era, type = 'dateobject', calendar = calendar} end function p.before(a, b) -- return true if b is before a or if at least one of a or b is missing a = p.splitDate(a) b = p.splitDate(b) if (not a) or (not b) then return true end local order = {'era', 'year', 'month', 'day'} for i, j in pairs(order) do if b[j] < a[j] then return true elseif b[j] > a[j] then return false end end return true end return p td175s5n84uloefhesobgbdefhml4b3 549191 549188 2026-06-22T07:12:50Z Mirzali 16 549191 Scribunto text/plain require('strict') local yesno = require('Module:Yesno') local getArgs = require ('Module:Arguments').getArgs local data = mw.loadData ('Module:Time/data' .. (mw.getCurrentFrame():getTitle():match ('/sandbox') or '')); -- load the data module local cfg = data.cfg; -- for internationalization local tz = {}; -- holds local copy of the specified timezone table from tz_data{} --[[--------------------------< I S _ S E T >------------------------------------------------------------------ Whether variable is set or not. A variable is set when it is not nil and not empty. ]] local function is_set( var ) return not (nil == var or '' == var); end --[[--------------------------< S U B S T I T U T E >---------------------------------------------------------- Populates numbered arguments in a message string using an argument table. ]] local function substitute (msg, args_t) return args_t and mw.message.newRawMessage (msg, args_t):plain() or msg; end --[[--------------------------< E R R O R _ M S G >------------------------------------------------------------ create an error message <args_t> is a sequence where [1] is template name and [2] is substituted error message ]] local function error_msg (args_t) return substitute (cfg.err_msg, args_t); end --[[--------------------------< D E C O D E _ D S T _ E V E N T >---------------------------------------------- extract ordinal, day-name, and month from daylight saving start/end definition string as digits: Second Sunday in March returns 2 0 3 Casing doesn't matter but the form of the string does: <ordinal> <day> <any single word> <month> – all are separated by spaces ]] local function decode_dst_event (dst_event_string) local ord, day, month; dst_event_string = dst_event_string:lower(); -- force the string to lower case because that is how the tables above are indexed ord, day, month = dst_event_string:match ('([%a%d]+)%s+(%a+)%s+%a+%s+(%a+)'); if not (is_set (ord) and is_set (day) and is_set (month)) then -- if one or more of these not set, then pattern didn't match return nil; end return cfg.ordinals[ord], cfg.days[day], cfg.months[month]; end --[[--------------------------< G E T _ D A Y S _ I N _ M O N T H >-------------------------------------------- Returns the number of days in the month where month is a number 1–12 and year is four-digit Gregorian calendar. Accounts for leap year. ]] local function get_days_in_month (year, month) local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; year = tonumber (year); -- force these to be numbers just in case month = tonumber (month); if (2 == month) then -- if February if (0 == (year%4) and (0 ~= (year%100) or 0 == (year%400))) then -- is year a leap year? return 29; -- if leap year then 29 days in February end end return days_in_month [month]; end --[[--------------------------< G E T _ D S T _ M O N T H _ D A Y >-------------------------------------------- Return the date (month and day of the month) for the day that is the ordinal (nth) day-name in month (second Friday in June) of the current year timestamp is today's date-time number from os.time(); used to supply year timezone is the timezone parameter value from the template call Equations used in this function taken from Template:Weekday_in_month ]] local function get_dst_month_day (timestamp, start) local ord, weekday_num, month; local first_day_of_dst_month_num; local last_day_of_dst_month_num; local days_in_month; local year; if true == start then ord, weekday_num, month = decode_dst_event (tz.dst_begins); -- get start string and convert to digits else ord, weekday_num, month = decode_dst_event (tz.dst_ends); -- get end string and convert to digits end if not (is_set (ord) and is_set (weekday_num) and is_set (month)) then return nil; -- could not decode event string end year = os.date ('%Y', timestamp); if -1 == ord then -- j = t + 7×(n + 1) - (wt - w) mod 7 -- if event occurs on the last day-name of the month ('last Sunday of October') days_in_month = get_days_in_month (year, month); last_day_of_dst_month_num = os.date ('%w', os.time ({['year']=year, ['month']=month, ['day']=days_in_month})); return month, days_in_month + 7*(ord + 1) - ((last_day_of_dst_month_num - weekday_num) % 7); else -- j = 7×n - 6 + (w - w1) mod 7 first_day_of_dst_month_num = os.date ('%w', os.time ({['year']=year, ['month']=month, ['day']=1})) return month, 7 * ord - 6 + (weekday_num - first_day_of_dst_month_num) % 7; -- return month and calculated date end end --[[--------------------------< G E T _ U T C _ O F F S E T >-------------------------------------------------- Get utc offset in hours and minutes, convert to seconds. If the offset can't be converted return nil. TODO: return error message? TODO: limit check this? +/-n hours? ]] local function get_utc_offset () local sign; local hours; local minutes; sign, hours, minutes = mw.ustring.match (tz.utc_offset, '([%+%-±−]?)(%d%d):(%d%d)'); if '-' == sign then sign = -1; else sign = 1; end if is_set (hours) and is_set (minutes) then return sign * ((hours * 3600) + (minutes * 60)); else return nil; -- we require that all timezone tables have what appears to be a valid offset end end --[[--------------------------< M A K E _ D S T _ T I M E S T A M P S >---------------------------------------- Return UTC timestamps for the date/time of daylight saving time events (beginning and ending). These timestamps will be compared to current UTC time. A dst timestamp is the date/time in seconds UTC for the timezone at the hour of the dst event. For dst rules that specify local event times, the timestamp is the sum of: timestamp = current year + dst_month + dst_day + dst_time (all in seconds) local time Adjust local time to UTC by subtracting utc_offset: timestamp = timestamp - utc_offset (in seconds) For dst_end timestamp, subtract an hour for DST timestamp = timestamp - 3600 (in seconds) For dst rules that specify utc event time the process is the same except that utc offset is not subtracted. ]] local function make_dst_timestamps (timestamp) local dst_begin, dst_end; -- dst begin and end time stamps local year; -- current year local dst_b_month, dst_e_month, dst_day; -- month and date of dst event local dst_hour, dst_minute; -- hour and minute of dst event on year-dst_month-dst_day local invert = false; -- flag to pass on when dst_begin month is numerically larger than dst_end month (southern hemisphere) local utc_offset; local utc_flag; year = os.date ('%Y', timestamp); -- current year utc_offset = get_utc_offset (); -- in seconds if not is_set (utc_offset) then -- utc offset is a required timezone property return nil; end dst_b_month, dst_day = get_dst_month_day (timestamp, true); -- month and day that dst begins if not is_set (dst_b_month) then return nil; end dst_hour, dst_minute = tz.dst_time:match ('(%d%d):(%d%d)'); -- get dst time utc_flag = tz.dst_time:find ('[Uu][Tt][Cc]%s*$'); -- set flag when dst events occur at a specified utc time dst_begin = os.time ({['year'] = year, ['month'] = dst_b_month, ['day'] = dst_day, ['hour'] = dst_hour, ['min'] = dst_minute}); -- form start timestamp if not is_set (utc_flag) then -- if dst events are specified to occur at local time dst_begin = dst_begin - utc_offset; -- adjust local time to utc by subtracting utc offset end dst_e_month, dst_day = get_dst_month_day (timestamp, false); -- month and day that dst ends if not is_set (dst_e_month) then return nil; end if is_set (tz.dst_e_time) then dst_hour, dst_minute = tz.dst_e_time:match ('(%d%d):(%d%d)'); -- get ending dst time; this one for those locales that use different start and end times utc_flag = tz.dst_e_time:find ('[Uu][Tt][Cc]%s*$'); -- set flag if dst is pegged to utc time end dst_end = os.time ({['year'] = year, ['month'] = dst_e_month, ['day'] = dst_day, ['hour'] = dst_hour, ['min'] = dst_minute}); -- form end timestamp if not is_set (utc_flag) then -- if dst events are specified to occur at local time dst_end = dst_end - 3600; -- assume that local end time is DST so adjust to local ST dst_end = dst_end - utc_offset; -- adjust local time to utc by subtracting utc offset end if dst_b_month > dst_e_month then invert = true; -- true for southern hemisphere eg: start September YYYY end April YYYY+1 end return dst_begin, dst_end, invert; end --[[--------------------------< G E T _ T E S T _ T I M E >---------------------------------------------------- decode ISO formatted date/time into a table suitable for os.time(). Fallback to {{Timestamp}} format. For testing, this time is UTC just as is returned by the os.time() function. ]] local function get_test_time (iso_date) local year, month, day, hour, minute, second; year, month, day, hour, minute, second = iso_date:match ('(%d%d%d%d)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)'); if not year then year, month, day, hour, minute, second = iso_date:match ('^(%d%d%d%d)(%d%d)(%d%d)(%d%d)(%d%d)(%d%d)$'); if not year then return nil; -- test time did not match the specified patterns end end return {['year'] = year, ['month'] = month, ['day'] = day, ['hour'] = hour, ['min'] = minute, ['sec'] = second}; end --[[----------------------< G E T _ F U L L _ U T C _ O F F S E T >----------------------------------------------- Creates a standard UTC offset from numerical inputs, for function time to convert to a table. Expected inputs shall have the form: <sign><hour><separator><portion> where: <sign> – optional; one of the characters: '+', '-' (hyphen), '±', '−' (minus); defaults to '+' <hour> - one or two digits <separator> - one of the characters '.' or ':'; required when <portion> is included; ignored else <portion> - optional; one or two digits when <separator> is '.'; two digits else returns correct utc offset string when input has a correct form; else returns the unmodified input ]] local function get_full_utc_offset (utc_offset) local h, m, sep, sign; local patterns = { '^([%+%-±−]?)(%d%d?)(%.)(%d%d?)$', -- one or two fractional hour digits '^([%+%-±−]?)(%d%d?)(:)(%d%d)$', -- two minute digits '^([%+%-±−]?)(%d%d?)[%.:]?$', -- hours only; ignore trailing separator } for _, pattern in ipairs(patterns) do -- loop through the patterns sign, h, sep, m = mw.ustring.match (utc_offset, pattern); if h then break; -- if h is set then pattern matched end end if not h then return utc_offset; -- did not match a pattern end sign = ('' == sign) and '+' or sign; -- sign character is required; set to '+' if not specified m = ('.' == sep) and ((sep .. m) * 60) or m or 0; -- fractional h to m return string.format ('utc%s%02d:%02d', sign, h, m); end --[[--------------------------< T A B L E _ L E N >------------------------------------------------------------ return number of elements in table ]] local function table_len (tbl) local count = 0; for _ in pairs (tbl) do count = count + 1; end return count; end --[[--------------------------< F I R S T _ S E T >------------------------------------------------------------ scans through a list of parameter names that are aliases of each other and returns the value assigned to the first args[alias] that has a set value; nil else. scan direction is right-to-left (top-to-bottom) ]] local function first_set (list, args) local i = 1; local count = table_len (list); -- get count of items in list while i <= count do -- loop through all items in list if is_set( args[list[i]] ) then -- if parameter name in list is set in args return args[list[i]]; -- return the value assigned to the args parameter end i = i + 1; -- point to next end end --[=[-------------------------< T I M E >---------------------------------------------------------------------- This template takes several parameters (some positonal, some not); none are required: 1. the time zone abbreviation/UTC offset (positional, always the first unnamed parameter) 2. a date format flag; second positional parameter or |df=; can have one of several values 3. |dst= when set to 'no' disables dst calculations for locations that do not observe dst – Arizona in MST 4. |timeonly= when set to 'yes' only display the time 5. |dateonly= when set to 'yes' only display the date 6. |hide-refresh = when set to 'yes' removes the refresh link 7. |hide-tz = when set to 'yes' removes the timezone name 8. |unlink-tz = when set to 'yes' unlinks the timzone name 9. |_TEST_TIME_= a specific utc time in ISO date time format used for testing this code TODO: convert _TEST_TIME_ to |time=? Timezone abbreviations can be found here: [[List_of_time_zone_abbreviations]] For custom date format parameters |df-cust=, |df-cust-a=, |df-cust-p= use codes described here: [[:mw:Help:Extension:ParserFunctions##time]] ]=] local function time (frame) local args = getArgs (frame); local utc_timestamp, timestamp; -- current or _TEST_TIME_ timestamps; timestamp is local ST or DST time used in output local dst_begin_ts, dst_end_ts; -- DST begin and end timestamps in UTC local tz_abbr; -- select ST or DST timezone abbreviaion used in output local time_string; -- holds output time/date in |df= format local utc_offset; local invert; -- true when southern hemisphere local DF; -- date format flag; the |df= parameter local is_dst_tz; local tz_aliases = data.tz_aliases; -- get the aliases table local tz_data = data.tz_data; -- get the tz data table local Timeonly = yesno(first_set (cfg.aliases['timeonly'], args)); -- boolean local Dateonly = yesno(first_set (cfg.aliases['dateonly'], args)); -- boolean if Timeonly and Dateonly then -- invalid condition when both are set Timeonly, Dateonly = false; end local Hide_refresh = yesno(first_set (cfg.aliases['hide-refresh'], args)); -- boolean local Hide_tz = yesno(first_set (cfg.aliases['hide-tz'], args)); -- boolean local Unlink_tz = yesno(first_set (cfg.aliases['unlink-tz'], args)); -- boolean local DST = first_set (cfg.aliases['dst'], args) or true; -- string 'always' or boolean local Lang = first_set (cfg.aliases['lang'], args); -- to render in a language other than the local wiki's language local DF_cust = first_set (cfg.aliases['df-cust'], args); -- custom date/time formats local DF_cust_a = first_set (cfg.aliases['df-cust-a'], args); -- for am/pm sensitive formats local DF_cust_p = first_set (cfg.aliases['df-cust-p'], args); if not ((DF_cust_a and DF_cust_p) or -- DF_cust_a xor DF_cust_p (not DF_cust_a and not DF_cust_p))then return error_msg ({'Time', cfg.err_text['bad_df_pair']}); -- both are required end if args[1] then args[1] = get_full_utc_offset (args[1]):lower(); -- make lower case because tz table member indexes are lower case else args[1] = 'utc'; -- default to utc end if mw.ustring.match (args[1], 'utc[%+%-±−]%d%d:%d%d') then -- if rendering time for a UTC offset timezone tz.abbr = args[1]:upper():gsub('%-', '−'); -- set the link label to upper case and replace hyphen with a minus character (U+2212) tz.article = tz.abbr; -- article title same as abbreviation tz.utc_offset = mw.ustring.match (args[1], 'utc([%+%-±−]?%d%d:%d%d)'):gsub('−', '%-'); -- extract the offset value; replace minus character with hyphen local s, t = mw.ustring.match (tz.utc_offset, '(±)(%d%d:%d%d)'); -- ± only valid for offset 00:00 if s and '00:00' ~= t then return error_msg ({'Time', cfg.err_text['bad_sign']}); end tz.df = 'iso'; args[1] = 'utc_offsets'; -- spoof to show that we recognize this timezone else tz = tz_aliases[args[1]] and tz_data[tz_aliases[args[1]]] or tz_data[args[1]]; -- make a local copy of the timezone table from tz_data{} if not tz then return error_msg ({'Time', substitute (cfg.err_text['unknown_tz'], args[1])}); -- if the timezone given isn't in module:time/data(/sandbox) end end DF = first_set (cfg.aliases['df'], args) or args[2] or tz.df or cfg.default_df; -- template |df= overrides typical df from tz properties DF = DF:lower(); -- normalize to lower case if not cfg.df_vals[DF] then return error_msg ({'Time', substitute (cfg.err_text['bad_format'], DF)}); end if is_set (args._TEST_TIME_) then -- typically used to test the code at a specific utc time local test_time = get_test_time (args._TEST_TIME_); if not test_time then return error_msg ({'Time', cfg.err_text['test_time']}); end utc_timestamp = os.time(test_time); else utc_timestamp = os.time (); -- get current server time (UTC) end utc_offset = get_utc_offset (); -- utc offset for specified timezone in seconds timestamp = utc_timestamp + utc_offset; -- make local time timestamp if 'always' == DST and is_set (tz.dst_abbr) then -- if needed to always display dst time timestamp = timestamp + 3600; -- add a hour for dst tz_abbr = tz.dst_abbr; -- dst abbreviation elseif not yesno(DST) and is_set (tz.dst_abbr) then -- for timezones that DO observe dst but for this location ... tz_abbr = tz.abbr; -- ... dst is not observed (|dst=no) show time as standard time else if is_set (tz.dst_begins) and is_set (tz.dst_ends) and is_set (tz.dst_time) then -- make sure we have all of the parts dst_begin_ts, dst_end_ts, invert = make_dst_timestamps (timestamp); -- get begin and end dst timestamps and invert flag if nil == dst_begin_ts or nil == dst_end_ts then return error_msg ({'Time', cfg.err_text['bad_dst']}); end if invert then -- southern hemisphere; use beginning and ending of standard time in the comparison if utc_timestamp >= dst_end_ts and utc_timestamp < dst_begin_ts then -- is current date time standard time? tz_abbr = tz.abbr; -- standard time abbreviation else timestamp = timestamp + 3600; -- add an hour tz_abbr = tz.dst_abbr; -- dst abbreviation end else -- northern hemisphere if utc_timestamp >= dst_begin_ts and utc_timestamp < dst_end_ts then -- all timestamps are UTC timestamp = timestamp + 3600; -- add an hour tz_abbr = tz.dst_abbr; else tz_abbr = tz.abbr; end end elseif is_set (tz.dst_begins) or is_set (tz.dst_ends) or is_set (tz.dst_time) then -- if some but not all not all parts then emit error message return error_msg ({'Time', substitute (cfg.err_text['bad_def'], args_t[1]:upper())}); else tz_abbr = tz.abbr; -- dst not observed for this timezone end end if Dateonly then if 'iso' == DF then -- |df=iso DF = 'iso_date'; elseif DF:find ('^dmy') or 'y' == DF then -- |df=dmy, |df=dmy12, |df=dmy24, |df=y DF = 'dmy_date'; else DF = 'mdy_date'; -- default end elseif Timeonly or DF:match ('^%d+$') then -- time only of |df= is just digits DF = table.concat ({'t', DF:match ('%l*(12)') or '24'}); -- |df=12, |df=24, |df=dmy12, |df=dmy24, |df=mdy12, |df=mdy24; default to t24 elseif 'y' == DF or 'dmy24' == DF then DF = 'dmy'; elseif 'mdy24' == DF then DF = 'mdy'; end local dformat; if is_set (DF_cust) then dformat=DF_cust; elseif is_set (DF_cust_a) then -- custom format is am/pm sensitive? if 'am' == os.date ('%P', timestamp) then -- if current time is am dformat = DF_cust_a; -- use custom am format else dformat = DF_cust_p; -- use custom pm format end else dformat = cfg.format[DF]; -- use format from tables or from |df= end time_string = frame:callParserFunction ({name='#time', args={dformat, '@'..timestamp, Lang}}); if Lang then time_string = table.concat ({ -- bidirectional isolation of non-local language; yeah, rather brute force but simple '<bdi lang="', -- start of opening bdi tag Lang, -- insert rendered language code '">', -- end of opening tag time_string, -- insert the time string '</bdi>' -- and close the tag }); end if not is_set (tz.article) then -- if some but not all not all parts then emit error message return error_msg ({'Time', substitute (cfg.err_text['bad_def'], args_t[1]:upper())}); end local refresh_link = (Hide_refresh and '') or table.concat ({ ' <span class="plainlinks" style="font-size:85%;">[[', -- open span mw.title.getCurrentTitle():fullUrl({action = 'purge'}), -- add the a refresh link url ' ', cfg['refresh-label'], -- add the label ']]</span>', -- close the span }); local tz_tag = (Hide_tz and '') or ((Unlink_tz and table.concat ({' ', tz_abbr})) or -- unlinked table.concat ({' [[', tz.article, '|', tz_abbr, ']]'})); -- linked return table.concat ({time_string, tz_tag, refresh_link}); end --[[--------------------------< U T C _ O F F S E T >---------------------------------------------------------- implements {{UTC offset}} mimics templates {{Time/GMT offset}}, {{Time/EST offset}}, etc. {{#invoke:Time|utc_offset|<tz>}} – for a stand-alone invoke {{#invoke:Time|utc_offset}} – for an invoke in a template (<tz> is first positional parameter in the template call) where <tz> is a timezone abbreviation known to Module:Time/data returns a UTC offset string suitable for use with the {{#time:}} parser function: {{#time:H:i | {{#invoke:Time|utc_offset|MST}} }} {{#time:H:i | {{UTC_offset|MST}} }} ]] local function utc_offset (frame) local function apply_dst_ajdust (offset) -- local function to adjust standard time to daylight time; called when adjustment is needed local hours, minutes = offset:match ('^(%-?%d%d):(%d%d)'); -- extract signed hours and minutes from specified offset return string.format ('%s:%s', tonumber (hours) + 1, minutes); -- return optional sign hh:mm string end local args_t = getArgs (frame); -- fetch arguments; only {{{1}}}, timesone specifier is used if not args_t[1] then -- no timezone specifier return error_msg ({'UTC offset', cfg.err_text['missing_tz']}); -- abandon with error message end local timezone = args_t[1]:lower(); -- lowercase for indexing into tz data tables timezone = data.tz_aliases[timezone] or timezone; -- if <timezone> is an alias, map to its canonical value if not data.tz_data[timezone] then -- timezone specifier not known return error_msg ({'UTC offset', substitute (cfg.err_text['unknown_tz'], {timezone})}); -- abandon with error message end tz = data.tz_aliases[timezone] and data.tz_data[data.tz_aliases[timezone]] or data.tz_data[timezone]; -- fetch a copy of this timezone's data; <tz> is a page-global table used by functions called from this function local utc_timestamp = os.time (); -- get current server time (UTC) in seconds; used to determine when dst adjustment should be applied local timestamp = utc_timestamp + get_utc_offset (); -- make local time timestamp (in seconds) local utc_offset; local DST = first_set (cfg.aliases['dst'], args_t) or true; -- string 'always' or boolean if 'always' == DST then -- if needed to always display dst time utc_offset = apply_dst_ajdust (tz.utc_offset); -- return dst-adjusted timezone-offset from utc elseif not yesno (DST) then -- for timezones that DO observe dst but for this location ... utc_offset = tz.utc_offset; -- ... dst is not observed (|dst=no) show time as standard time else if is_set (tz.dst_begins) and is_set (tz.dst_ends) and is_set (tz.dst_time) then -- make sure we have all of the parts local dst_begin_ts, dst_end_ts, invert = make_dst_timestamps (timestamp); -- get begin and end dst timestamps and <invert> flag if nil == dst_begin_ts or nil == dst_end_ts then -- if either of these are nil return error_msg ({'UTC offset', cfg.err_text['bad_dst']}); -- abandon with error message end if invert then -- southern hemisphere; use beginning and ending of standard time in the comparison if utc_timestamp >= dst_end_ts and utc_timestamp < dst_begin_ts then -- is current date time standard time? utc_offset = tz.utc_offset; -- return timezone-offset from utc else utc_offset = apply_dst_ajdust (tz.utc_offset); -- return dst-adjusted timezone-offset from utc end else -- northern hemisphere if utc_timestamp >= dst_begin_ts and utc_timestamp < dst_end_ts then -- is current date time daylight time? utc_offset = apply_dst_ajdust (tz.utc_offset); -- return dst-adjusted timezone-offset from utc else utc_offset = tz.utc_offset; -- return timezone-offset from utc end end elseif is_set (tz.dst_begins) or is_set (tz.dst_ends) or is_set (tz.dst_time) then -- if some but not all not all parts then emit error message return error_msg ({'UTC offset', substitute (cfg.err_text['bad_def'], args_t[1]:upper())}); else -- timezone does not use dst utc_offset = tz.utc_offset; -- return timezone-offset from utc end end local sign, hours, minutes = utc_offset:match ('^([%-%+]?)(%d%d?):(%d%d)') if '' == sign then sign = '+'; end if 0 ~= tonumber (minutes) then return string.format ('%s%s %s %s%s minutes', sign, tonumber(hours), ('1' == hours) and 'hour' or 'hours', sign, tonumber(minutes)); else return string.format ('%s%s %s', sign, tonumber(hours), ('1' == hours) and 'hour' or 'hours'); end end --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ ]] return { time = time, utc_offset = utc_offset, } ee8ma965y3vn1tv2yag76hcdhegz1qn .observer 0 69966 549184 504176 2026-06-22T06:41:41Z Mirzali 16 549184 wikitext text/x-wiki '''.observer''', [[İnternet|internet]] de nameyê bandıra jeneriko (be zıwanê [[İngılızki]]: ''[[Bandıra sewiyaya serêna jenerike|Generic top-level domains]]'') ke yew kodê interneti rê bırriyayo a. == Bıvênên == * [[Domain]] * [[Komputer]] * [[Website]] {{Generic top-level domain}} {{ccTLD}} [[Kategoriye:Bandıra sewiyaya serêna jenerike]] 18jewtxaic8php32n0gewidzbj2azsx NGC 7802 0 73947 549185 490357 2026-06-22T06:42:46Z Mirzali 16 549185 wikitext text/x-wiki {{Galaksiye}} '''NGC 7802''', yew cısmê [[Asmên|asmên]]io. No cısım [[Katalogo Pêroyiyo Newe|Katalogê Pêroyiyê Neweyi]] de komê estareyanê {{Wikidata|P59}} miyan de ca gêno. {{Wikidata|P575}} de terefê {{Wikidata|P61}}i ra keşıf biyo. == Bıvênên == * [[Asmên]] * [[Galaksiye]] * [[Estare]] * [[Pulsar]] * [[Nebula]] * [[Lista cısmanê NGC]] == Gıreyê teberi == * {{NASANED}} * {{Simbad}} * {{Leda}} * {{Seds}} * {{WikiSky}} {{NGC|7802}} [[Kategoriye:Asmênşınasiye]] d1v8wpebx3v3fmboewl44djxt41kuxu Kategoriye:Şablonê Wikipediya 14 100220 549187 2026-06-22T06:48:48Z Mirzali 16 Ebe zerrekê '[[Kategoriye:Şabloni]]' ra pela newiye vıraziye 549187 wikitext text/x-wiki [[Kategoriye:Şabloni]] q5jnl44vy0m5dg4uo50robiubpob2bi