Modulis:Vikidati

Vikipēdijas lapa
Jump to navigation Jump to search
Dokumentācijas ikona Moduļa dokumentācija[skatīt] [labot] [hronoloģija] [pārlādēt]

Oriģinālais kods: fr:Module:Wikidata

--script that retrieves basic data stored in Wikidata, for the datamodel, see https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua

wd = wd or {}
reference = reference or require "Module:Wikidata/fr/Atsauces"

local linguistic = require "Module:Valodas rīki"
local formatDate = require "Module:Komplekss datums"
local formatNum = require 'Module:Conversion'
local langmodule = require'Module:Valodas'
local cite = require "Module:Biblio"
local langcodes = mw.loadData "Module:Wikidata/fr/Valodu kodi"
local getData = require 'Module:Wikidata/fr/Récup'
local entities = require 'Module:Wikidata/fr/Formatēšana'
local tools = require 'Module:Wikidata/fr/Rīki'
local defaultlang = mw.getContentLanguage():getCode()

local translate = tools.translate

function wd.addtrackingcat(prop, cat) -- doit parfois être appelé par d'autres modules
	if not prop and not cat then
		return error("no property provided")
	end
	if not cat then
		cat = translate('trackingcat', prop or 'P??')
	end
	return tools.addcat(cat )
end

local function removeblanks(args)
	for i, j in pairs(args) do
		if j == '' then args[i] = nil end
	end
	return args
end

local function unknownvalue(displayformat) -- à améliorer
	if not displayformat then
		return translate('somevalue')
	end
	if type(displayformat) == 'string' then
		return displayformat
	end
	return tools.formatError()
end

local function novalue(displayformat)
	if not displayformat then
		return translate('novalue')
	end
	if type(displayformat) == 'string' then
		return displayformat
	end
	return tools.formatError()
end

local function getlangcode(entityid)
	return 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 = tools.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 langmodule.indicationMultilingue(langlist)
	end
end

local function formattable(statements, params) -- transform a table of claims into a table of formatted values
    for i, j in pairs(statements) do
        j = wd.formatStatement(j, params)
    end
    return statements
end

function wd.tableToText(values, params) -- takes a list of already formatted values and make them a text
    if not values then
        return nil
    end
    return linguistic.quickconj( values, params.conjtype)--linguistic.conj( values, params.lang, params.conjtype )
end


function wd.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

function wd.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 = formatDate.splitDate(orig.time, orig.calendar)
	
	newobj.precision = params.precision or orig.precision
	newobj.type = 'dateobject'
	return newobj
end

function wd.objecttotext(obj, params)
	if obj.type == 'dateobject' then
		return formatDate.simplestring(obj, params)
	elseif obj.type == 'rangeobject' then
		return formatDate.daterange(obj.begin, obj.ending, params)
	end
end


function wd.getDate(statement)
--[[
returns an object containing a timestamp for easy sorting, and other data
	2 types of object
		dateobject
			{timestamp = string, year = number, month = number, day = number, calendar = string}
		rangeobject
			{timestamp = string, begin = dateobject, ending = dateobject}
]]--
	local q = statement.qualifiers
	if not q or not (q.P585 or q.P580 or q.P582) then
		return nil
	end
	local begin, ending
	-- si p585 : dateobject
	if q.P585 and q.P585[1].snaktype == 'value' then -- P585: punctual date
		return wd.dateobject(q.P585[1].datavalue.value)
	end

	-- si p580 ou P582 : rangeobject avec une date de début et/ou une date de fin
	if q.P582 and q.P582[1].snaktype == 'value' then
		ending = wd.dateobject(q.P582[1].datavalue.value)
	end
	if (q.P580 and q.P580[1].snaktype == 'value') then
		begin = wd.dateobject(q.P580[1].datavalue.value)
	end
	if begin or ending then -- sinon ce sont des 'specialvalues', il faudrait aussi les prendre en charge
		return wd.rangeobject(begin, ending)
	end
end

function wd.getFormattedDate(statement, params)
	local datetable = wd.getDate(statement)
	if not datetable then
		return nil
	end
	return wd.objecttotext(datetable, params)
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.datavalue.type
	local value = snak.datavalue.value
	
	local displayformat = params.displayformat
	if type(displayformat) == 'function' then
        return displayformat(snak, params)
 	end

	if (datatype == 'wikibase-entityid') then
		return entities.formatEntity(tools.getId(snak), params)
	end

	if datatype == ('string') then
		if params.displayformat == 'weblink' then
			return require('Module:Weblink').makelink(value, params.text)
		end
		if type(params.displayformat) == 'function' then
			value = params.displayformat(value)
		end
		if params.urlpattern then
			local urlpattern = params.urlpattern
			if type(urlpattern) == 'function' then
				urlpattern = urlpattern(value)
			end
			value = '[' .. mw.ustring.gsub(urlpattern, '$1', value) .. ' ' .. (params.text or value) .. ']'
		end
		return value
	end
	
	if datatype == 'time' then -- format example: +00000001809-02-12T00:00:00Z
		local precision = params.precision -- degré de précision à afficher ('day', 'month', 'year'), inférieur ou égal à value.precision
		if displayformat == 'raw' then
			return value.time
		else
			return wd.objecttotext(wd.dateobject(value, {precision = precision}), {linktopic = params.linktopic})
		end
	end

	if datatype == 'globecoordinate' then
		-- retourne une table avec clés latitude, longitude, précision et globe à formater par un autre module (à changer ?)
		value.globe = require('Module:Wikidata/Globes')[value.globe] -- transforme l'ID du globe en nom anglais utilisable par geohack
		if formatting == 'latitude' then
			return value.latitude
		elseif formatting == 'longitude' then
			return value.longitude
		else
			return value -- 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ètre précision
		local amount, unit = value.amount, value.unit
 		if displayformat == 'raw' then
			return amount
		end
		if unit then
			unit = unit:match('Q%d+')
		end
			
		local showunit = params.showunit or true		
		if showunit == '-' then
			showunit = false
		end
		local targetunit = params.targetunit

		return formatNum.displayvalue(amount, unit,
			{targetunit = params.targetunit, displayformat = params.displayformat, rounding = params.rounding, showunit = showunit}
			)
	end
	if datatype == 'monolingualtext' then
		return langmodule.langue({value.language, value.text})
	end
	
	return tools.formatError('unknown-datavalue-type' )
    
end

function wd.getClaims( args ) -- returns a table of the claims matching some conditions given in args
	return getData.getClaims(args)
end

function wd.formatClaimList(claims, args)
    if not claims then
        return nil
    end
	for i, j in pairs(claims) do
        claims[i] = wd.formatStatement(j, args)
    end
    if args.removedupes and (args.removedupes ~= '-') then
		claims = tools.addnewvalues({}, claims)
	end
    return claims
end

function wd.stringTable(args) -- like getClaims, but get a list of string rather than a list of snaks, for easier manipulation
	local claims = wd.getClaims(args)
	return wd.formatClaimList(claims, args)
end


local function getQualifiers(statement, qualifs, params)
	if not statement.qualifiers then
		return nil
	end
	local vals = {}
	for i, j in pairs(qualifs) do
		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 = getQualifiers(statement, qualifs)
	if not qualiftable then
		return nil
	end
	for i, j in pairs(qualiftable) do
		qualiftable[i] = wd.formatSnak(j, params)
	end
	return linguistic.conj(qualiftable)
end

function wd.formatStatement( statement, args )
	if not args then
		args = {}
	end
    if not statement.type or statement.type ~= 'statement' then
        return tools.formatError( 'unknown-claim-type' )
    end
    local str = wd.formatSnak( statement.mainsnak, args )
    if args.showlang == true then
    	str = (showlang(statement) or '') .. ' ' .. str
    end
    if args.showqualifiers then
    	local qualifs =  args.showqualifiers
    	if type(qualifs) == 'string' then
    		qualifs = mw.text.split(qualifs, ',')
    	end
    	local qualifargs = {}
 		-- formatage des qualificateur = 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
    	
    	local formattedqualifs = wd.getFormattedQualifiers(statement, qualifs, qualifargs)
    	if formattedqualifs then
    		str = str .. linguistic.inparentheses(formattedqualifs, lang)
		end
	end

    if args.showdate then -- when "showdate and chronosort are both set, date retrieval is performed twice
    	local timedata = wd.getDate(statement)
    	if timedata then
    		local formatteddate = wd.objecttotext(timedata, args)
    		formatteddate = linguistic.inparentheses(formatteddate, lang)
    		str = str .. '<small>' .. formatteddate ..'</small>'
    	end
    end

	if args.showsource and statement.references then
		local sourcestring = ''
		for i, ref in pairs(statement.references) 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
			local function firstsnak(prop)
				return wd.formatSnak(prop[1])
			end
			if ref.snaks.P248 then
				for j, source in pairs(ref.snaks.P248) do
					if source.snaktype == 'value' then
						local page, accessdate
						if hasValue('P304') then
							page = wd.formatSnak(ref.snaks.P304[1])
						end
						if hasValue('P813') then
							accessdate = wd.formatSnak(ref.snaks.P813[1])
						end
						s = reference.citeitem(tools.getId(source), {['page'] = page, ['accessdate'] = accessdate})
						s = mw.getCurrentFrame():extensionTag( 'ref', s )
						sourcestring = sourcestring .. s
					end
				end
			elseif hasValue('P854') and hasValue('P1476') then
				local url, title, accessdate, publishdate, publishlang
				url, title = wd.formatSnak(ref.snaks.P854[1]), wd.formatSnak(ref.snaks.P1476[1])
				if hasValue('P813') then
					accessdate = wd.formatSnak(ref.snaks.P813[1])
				end
				-- publishdate avec P577 ? (ne semble pas vraiment correspondre) 
				if hasValue('P407') then
					local id = tools.getId(ref.snaks.P407[1])
					publishlang = getlangcode(id)
				end
				s = cite.lienWeb{titre = title, url = url, langue = publishlang, ['en ligne le'] = publishdate, ['consulté le'] = accessdate}
				s = mw.getCurrentFrame():extensionTag( 'ref', s)
				sourcestring = sourcestring .. s
			elseif ref.snaks.P854 and ref.snaks.P854[1].snaktype == 'value' then
				s = mw.getCurrentFrame():extensionTag( 'ref', wd.formatSnak(ref.snaks.P854[1]))
				sourcestring = sourcestring .. s
			end
			end
			str = str .. sourcestring
		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(params.unknownlabel)
    elseif snak.snaktype == 'novalue' then
        return novalue(params.novaluelabel)
    elseif snak.snaktype == 'value' then
        return wd.getDatavalue( snak, params)
    else
        return tools.formatError( 'unknown-snak-type' )
    end
end

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 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.addLinkback(str, id, property)
	if not id then
		id = tools.getEntity()
	end
	if not id then
		return str
	end
	if type(id) == 'table' then
		id = id.id
	end
	
	local class = ''
	if property then
		class = 'wd_' .. string.lower(property)
	end
	local title = translate('see-wikidata-value')
	local icon = '[%s [[File:Blue pencil.svg|%s|10px|baseline|link=]] ]'
	local url = mw.uri.fullUrl('d:' .. id, 'uselang=fr')
	url.fragment = property
	url = tostring(url)
	local v = mw.html.create('span')
		:addClass(class)
		:wikitext(str)
		:tag('span')
			:addClass('noprint plainlinks wikidata-linkback')
			:css('padding-left', '.5em')
			:wikitext(icon:format(url, title))
		: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 Wikidata.
    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

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
	if args.value and args.value ~= '' then
		return args.value
	end
	args.entity = tools.getEntity(args.entity)
	local valuetable = wd.stringTable(args)
	
	local str = wd.tableToText(valuetable, args)
	
	if not str then
		return nil
	end
	if args.addcat and (args.addcat ~= '-') then
		str = str .. wd.addtrackingcat(args.property)
	end
	if args.linkback and (args.linkback ~= '-') then
		str = wd.addLinkback(str, args.entity, args.property)
	end
	return str
end

function wd.showQualifier( args )
	local qualifs = args.qualifiers or args.qualifier
	if type(qualifs) == 'string' then
		qualifs = mw.text.split(qualifs, ',')
	end
	if not qualifs then
		return tools.formatError( 'property-param-not-provided' )
	end
	local claims = wd.getClaims(args)
	if not claims then
		return nil
	end
	local str = ''
	for i, j in pairs(claims) do
		local new = wd.getFormattedQualifiers(j, qualifs, args) or ''
		str = str .. new
	end
	return str
end

function wd.formatAndCat(args)
	if not args then
		return nil
	end
	args.linkback = true
	args.addcat = true
	if args.value then -- do not ignore linkback and addcat, as formatStatements do
		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
		table.insert(formattedvalues, wd.getFormattedDate(j))
	end
	local val = 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


-- Complex functions using several items
local function getids(query)
	query.excludespecial = true
	query.displayformat = 'raw'
	return wd.stringTable(query)
end


function wd.Dump(entity)
	entity = tools.getEntity(entity)
	if not entity then
		return tools.formatError("entity-param-not-provided")
	end
	return "<pre>"..mw.dumpObject(entity).."</pre>"
end

wd.getid = tools.getId
wd.getmainid = tools.getMainId

-- fonctions obsolètes
function wd.getLabel(entity, args)
	entities.getLabel(entity)
end

function wd.formatEntity(entity, args)
	return entities.formatEntity(entity, args)
end

function wd._getLabel(entity, args)
	return wd.getLabel(entity, args)
end

function wd._formatAndCat(args)
	return wd.formatAndCat(args)
end
function wd._formatStatements(args)
	return wd.formatStatements(args)
end
return wd