Diferencia entre revisiones de «Wikidata»

De musiki
Sin resumen de edición
Sin resumen de edición
Línea 1: Línea 1:
--script that retrieves basic data stored in Wikidata, for the datamodel, see https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua
--[[*********************************************************************************
 
    * Nombre: Módulo:Wikidata
    *
    * Descripción: Este módulo devuelve el valor o valores con o sin formato específico
    *            a una propiedad de Wikidata.  
    *
    * Fecha última revisión: 6 de septiembre de 2014.
    *
    * Estado: En uso.
    *
    *********************************************************************************`-- ]]
local p = {}
local p = {}
local datequalifiers = {'P585', 'P571', 'P580', 'P582'}
local es = mw.language.new('es')
local primera = true
--local marco Ojo. marco no debe definirse como local pues si se hace así puede fallar.
--[[ =========================================================================
            Mensajes de error
      ========================================================================= `-- ]]
local avisos = {
    ["errores"] = {
        ["property-param-not-provided"] = "Parámetro de la propiedad no proporcionado.",
        ["entity-not-found"] = "Entrada no encontrada.",
        ["unknown-claim-type"] = "Tipo de notificación desconocida.",
        ["unknown-snak-type"] = "Tipo de dato desconocido.",
        ["unknown-datavalue-type"] = "Formato de dato desconocido.",
        ["unknown-entity-type"] = "Tipo de entrada desconocido.",
        ["unknown-value-module"] = "Debe ajustar ambos parámetros de valor y el valor del módulo de funciones.",
        ["value-module-not-found"] = "No se ha encontrado el módulo apuntado por valor-módulo.",
        ["value-function-not-found"] = "No se ha encontrado la función apuntada por valor-función.",
        ["other entity"] = "Enlaces a elementos diferentes desactivado."
    },
    ["somevalue"] = "''valor desconocido''",
    ["novalue"] = ""
}


local linguistic = require('Module:Linguistic')
-- Módulos y funciones utilizadas
--local formatDate = require('Module:Complex date') only loaded when needed to save memory in large pages like Wikidata:List of properties/all
local elementoTabla = require('Módulo:Tablas').elemento
local fb = require('Module:Fallback')
--
local i18nmessages = mw.loadData('Module:i18n/wikidata')
-- Módulos en los que están definidos los tipos de datos más habituales si son
 
-- diferentes de Wikidata/Formatos
-- Wiki-specific parameters
--
local defaultlang = mw.getCurrentFrame():preprocess("{{int:lang}}")
local modulosTipos =  {
local defaultlink = 'wikidata'
['altura']      = 'Módulo:Wikidata/Formato magnitud',
 
['área']        = 'Módulo:Wikidata/Formato magnitud',
local function i18n(str)
['educado en']  = 'Módulo:Wikidata/Formatos educación',
local message = i18nmessages[str]
['imagen']      = 'Módulo:Wikidata/Formato imagen',
if type(message) == 'string' then
['lugar']        = 'Módulo:Wikidata/Formato lugar',
return message
['formatoLugar'] = 'Módulo:Wikidata/Formato lugar',
end
['magnitud']    = 'Módulo:Wikidata/Formato magnitud',
return fb._langSwitch(message, defaultlang) .. ''
['movimiento']  = 'Módulo:Wikidata/Formato movimiento',
end
['periodicidad'] = 'Módulo:Wikidata/Formato magnitud',
 
['premio'] = 'Módulo:Wikidata/Formato premio',
local function formatError( key, text )
}
return error(i18n(key) .. (text or ''))
end
 
--[[ =========================================================================
local function addTrackingCat(prop, cat)
      Función para pasar el frame cuando se usa en otros módulos.     
if not prop and not cat then
    ========================================================================= `-- ]]
return error("no property provided")
function p:setFrame(frame)
end
marco = frame
if not cat then
cat = i18nmessages.trackingcat .. '/' .. string.upper(prop)
end
return '[[Category:' .. cat .. ']]'
end
 
local function removeBlanks(args)
for i, j in pairs(args) do -- does not work ??
if (j == '') or (j == '-') then args[i] = nil end
end
return args
end
 
local function formatTheUnknown() -- voir si on peut accorder/adapter l'usage de "inconnu"
return i18n('somevalue')
end
 
local function isSpecial(snak)
return snak.snaktype ~= 'value'
end
 
local function sameValue(snak, target)
return not isSpecial(snak) and p.getRawvalue(snak) == target
end
end
--[[ =========================================================================
      Función para identificar el ítem correspondiente a la página o otro dado.
              Esto último aún no funciona.     
    ========================================================================= `-- ]]


local function showLang(statement, str) -- TODO (not yet in proper format)
--adds a lang indication at the start of the string, based on data in statement
local mainsnak = statement.mainsnak
if isSpecial(mainsnak) then
return str
end


local langlist = {}
function SelecionEntidadPorId( id )
if mainsnak.datavalue.type == 'monolingualtext' then
langlist = {mainsnak.datavalue.value.language}
        if id and id ~= '' then
elseif statement.qualifiers and statement.qualifiers.P407 then
            return mw.wikibase.getEntityObject( id )
local convertlangcode = mw.loadData('Module:Dictionary/lang codes')
        else
for i, j in pairs( statement.qualifiers.P407 ) do
            return mw.wikibase.getEntityObject()
if not isSpecial(j) then
        end
local val = convertlangcode[j.datavalue.value['numeric-id']]
table.insert(langlist, val)
end
end
end
end
--[[ =========================================================================
if #langlist == 0 then
      Función que identifica si el valor devuelto es un ítem o una propiedad
return str
      y en función de eso añade el prefijo correspondiente   
else
    ========================================================================= `-- ]]
return '(' .. table.concat(langlist) .. ')' .. str
end
function SelecionEntidadPorValor( valor )
    local prefijo = ''
    if valor['entity-type'] == 'item' then
        prefijo = 'q' -- Prefijo de ítem
    elseif valor['entity-type'] == 'property' then
        prefijo = 'p' -- Prefijo de propiedad
    else
        return formatoError( 'unknown-entity-type' )
    end
    return prefijo .. valor['numeric-id'] -- Se concatena el prefijo y el código numérico
end
end
 
function p.getEntity( val )
--[[ =========================================================================
if type(val) == 'table' then
      Función auxiliar para dar formato a los mensajes de error     
return val
    ========================================================================= `-- ]]
end
return mw.wikibase.getEntityObject(val)
function formatoError( clave )
    return '<span class="error">' .. avisos.errores[clave] .. '</span>'
end
end
 
--[[ =========================================================================
-- DATE FUNCTIONS
      Función para determinar el rango   
local function splitTimestamp(timestamp, calendar)
    ========================================================================= `-- ]]
local pattern = "(%W)(%d+)%-(%d+)%-(%d+)"
function getRango(tablaDeclaraciones)
local era, year, month, day = timestamp:match(pattern)
 
local rank = 'deprecated'
if calendar == 'julian' then
--todo  year, month, day = formatdate.gregorianToJulian( era .. year, month, day )
    for indice, declaracion in pairs(tablaDeclaraciones) do
end
        if declaracion.rank == 'preferred' then
 
            return 'preferred'
return {day = day, month = month, year = year, era = era, timestamp = timestamp, type = 'dateobject'}
        elseif declaracion.rank == 'normal' then
            rank = 'normal'
        end
    end
    return rank
end
end
 
local function rangeObject(begin, ending)
--[[ =========================================================================
local timestamp
      Función para determinar la declaracion o declaraciones de mayor rango   
if begin then
    ========================================================================= `-- ]]
timestamp = begin.timestamp
function filtrarDeclaracionPorRango(tablaDeclaraciones)
elseif ending then
    local rango = getRango(tablaDeclaraciones)
timestamp = ending.timestamp
    local tablaAuxiliar = tablaDeclaraciones
end
    tablaDeclaraciones = {}
return {begin = begin, ending = ending, timestamp = timestamp, type = 'rangeobject'}
    for indice, declaracion in pairs(tablaAuxiliar) do
        if declaracion.rank == rango then
            table.insert(tablaDeclaraciones, declaracion)
        end  
    end
    return tablaDeclaraciones
end
end
 
local function dateObject(orig, params) -- transforme un snak en un nouvel objet utilisable par Module:Date complexe
--[[ =========================================================================
if not params then
      Función para seleccionar el tipo de declaración: Referencia, valor principal
params = {}
      o calificador     
end
    ========================================================================= `-- ]]
 
local newobj = splitTimestamp(orig.time, orig.calendar) -- initalise l'object en mettant la valeur des dates
function seleccionDeclaracion(declaracion, opciones)
 
    local fuente = {}
newobj.precision = params.precision or orig.precision
    local propiedadFuente = {}
newobj.type = 'dateobject'
    local calificador = opciones.formatoCalificador ~= '()' and opciones.calificador
return newobj
    if calificador ~= '' and calificador  and declaracion['qualifiers'] then
    if declaracion['qualifiers'][mw.ustring.upper(calificador)] then
            return declaracion.qualifiers[mw.ustring.upper(calificador)][1] -- devuelve el calificador (solo devolverá el primer valor)
        else
        return "" --Para que no lance excepción si no existe el calificador
        end
    elseif opciones.dato == 'fuente' and declaracion['references'] then
    fuente = declaracion.references[1]['snaks']
        for k,v in pairs(fuente) do
            propiedadFuente = k
        end
        return declaracion.references[1]['snaks'][propiedadFuente][1]  -- devuelve la fuente (queda que se itinere la tabla)
    elseif (calificador == '' or not calificador) and (opciones.dato ~= 'fuente') then
        return declaracion.mainsnak -- devuelve el valor principal
    else
    return ''   
    end
end
--[[ =========================================================================
      Función para recopilar las declaraciones     
    ========================================================================= `-- ]]
function p.getDeclaraciones(entityId)
    -- == Comprobamos que existe un ítem enlazado a la página en Wikidata ==
    if not pcall (SelecionEntidadPorId, entityId ) then
    return false
    end
    local entidad  = SelecionEntidadPorId(entityId)
    if not entidad then
        return  '' -- Si la página no está enlazada a un ítem no devuelve nada
    end
    -- == Comprobamos que el ítem tiene declaraciones (claims) ==
    if not entidad.claims then
        return '' -- Si el ítem no tiene declaraciones no devuelve nada
    end
    -- == Declaración de formato y concatenado limpio ==
    return entidad.claims
end
end
 
local function formatDatepoint(obj, params) -- TO IMPROVE
--[[ =========================================================================
if not obj then
      Función para  crear la cadena que devolverá la declaración   
    ========================================================================= `-- ]]
   
local function valinQualif(claim, qualifs)
local claimqualifs = claim.qualifiers
local i,qualif
local vals, vals1, datavalue, value
if not claimqualifs then
return nil
return nil
end
end
local formatDate = require('Module:Complex date')
for i, qualif in pairs(qualifs) do
local lang = params.lang or defaultlang
vals = claimqualifs[qualif]
local precision = math.min(obj.precision, params.precision or 15) -- if we don't want to show the value to its full detail
if vals then
if precision >= 11 then
vals1 = vals[1]
return formatDate.complex_date{args={date1 = obj.year .. '-' .. obj.month .. '-' .. obj.day, lang= lang}}
if vals1 then
elseif precision == 10 then
datavalue=vals1.datavalue
return formatDate.complex_date{args={date1 = obj.year .. '-' .. obj.month, lang= lang}}
elseif precision == 9 then
if datavalue then
return formatDate.complex_date{args={date1 = tostring(obj.year), lang= lang}}
value = datavalue.value
elseif precision == 8 then
return formatDate.complex_date{args={date1 = string.sub(tostring(obj.year), 1, 3) .. '0', lang = lang, precision = 'decade'}}
if value then
elseif precision == 7 then
return value.time
return formatDate.complex_date{args={date1 = string.sub(tostring(obj.year + 100), 1, 2), lang = lang, precision = 'century'}}
end
return nil
end
 
local function formatDaterange(obj, params) --TODO
local begin = formatDatepoint(obj.begin, params) or ''
local ending = formatDatepoint(obj.ending, params) or ''
return begin .. '-' .. ending
end
 
local function objectToText(obj, params)
if obj.type == 'dateobject' then
return formatDatepoint(obj, params)
elseif obj.type == 'rangeobject' then
return formatDaterange(obj, params)
end
return nil
end
 
local function tableToText(values, params) -- takes a list of already formatted values and make them a text
if not values or #values == 0 then
return nil
end
return linguistic.conj(values, params.lang or defaultlang, params.conjtype)--linguistic.conj( values, params.lang, params.conjtype )
end
 
function p.getDate(obj)
--[[
returns an object containing a timestamp for easy sorting, and other data
possible types of object:
dateobject
{timestamp = string, year = number, month = number, day = number, calendar = string}
rangeobject
{timestamp = string, begin = dateobject, ending = dateobject}
]]--
if not obj then
return nil
end
if type(obj) == 'string' then
obj = p.getEntity(obj)
end
 
-- if obj is a statement with date, get it
if obj.mainsnak and not isSpecial(obj.mainsnak) and obj.mainsnak.datatype == 'time' then
return dateObject(obj.mainsnak.datavalue.value)
end
 
-- else preload relevant data
local qualifs = obj.qualifiers -- when obj is a statement, look in qualifiers
local claims = obj.claims -- when obj is an item, look in claims
 
local pointprop = {'P585', 'P571'} -- dates corresponding to a punctual fact
local beginprop = {'P580', 'P569'} -- start date, birth date == start of a date range
local endingprop = {'P582', 'P570'}
 
local function getval(prop)
local val
if claims and claims[prop] and not isSpecial(claims[prop][1].mainsnak) then
val = claims[prop][1].mainsnak.datavalue.value
elseif qualifs and qualifs[prop] and not isSpecial(qualifs[prop][1]) then
val = qualifs[prop][1].datavalue.value
end
if val then
return dateObject(val)
end
return nil
end
 
for i, prop in pairs(pointprop) do
local val = getval(prop)
if val then return val end
end
--if no date has not been found, look for startdate or enddate
local begin, ending
for i, prop in pairs(beginprop) do
begin = getval(prop)
if begin then
break
end
end
for i, prop in pairs(endingprop) do
ending = getval(prop)
if ending then
break
end
end
if begin or ending then
return rangeObject(begin, ending)
end
return nil
end
 
function p.getFormattedDate(statement, params)
local datetable = p.getDate(statement)
if not datetable then
return nil
end
return objectToText(datetable, params)
end
 
local function hasTargetValue(claim, target)
if target == nil then
return true
end
return sameValue(claim.mainsnak, target)
end
 
local function hasRank(claim, target)
if target == 'valid' then
return hasRank(claim, 'preferred') or hasRank(claim, 'normal')
else
return claim.rank == target
end
end
 
local function bestRanked(claims)
if not claims then
return nil
end
local preferred, normal = {}, {}
for _, j in ipairs(claims) do
if j.rank == 'preferred' then
table.insert(preferred, j)
elseif j.rank == 'normal' then
table.insert(normal, j)
end
end
if #preferred > 0 then
return preferred
else
return normal
end
end
 
local function hasQualifier(claim, qualifier, qualifiervalues)
if not qualifier then -- si aucun qualificatif est demandé, ça passe
return true
end
 
qualifier = string.upper(qualifier)
if not claim.qualifiers or not claim.qualifiers[qualifier] then
return false
end
 
if type(qualifiervalues) == 'string' then
qualifiervalues = mw.text.split(qualifiervalues, ',')
end
 
if (not qualifiervalues) or (qualifiervalues == {}) then
return true -- si aucune valeur spécifique n'est exigée
end
 
for _, j in ipairs(claim.qualifiers[qualifier]) do
for _, l in ipairs(qualifiervalues) do
if p.sameValue(j, l) then
return true
end
end
end
return false
end
 
local function hasSource(statement, source, sourceproperty)
if not statement.references then
return false
end
sourceproperty = string.upper(sourceproperty or 'P248')
local sourcevalue = string.upper(source or '')
for _, ref in ipairs(statement.references) do
for prop, content in pairs(ref.snaks) do
if prop == sourceproperty then
if sourcevalue == '' then
return true
else
for _, k in ipairs(content) do
if sameValue(k, source) then
return true
end
end
end
end
end
Línea 320: Línea 223:
end
end
end
end
return false
end    
end
 
function p.getPropiedad(opciones, declaracion)
local function hasDate(statement)
    local propiedad    = {}
if not statement.qualifiers then
    local tablaOrdenada = {}
return false
end
local dateprops = {'P580', 'P585', 'P582'}
for i, prop in pairs(dateprops) do
if statement.qualifiers[prop] then
return true
end
end
return false
end


local function isInLanguage(snak, lang) -- ne fonctionne que pour les monolingualtext / étendre aux autres types en utilisant les qualifiers ?
    if opciones.propiedad == 'precisión' or opciones.propiedad == 'latitud' or opciones.propiedad == 'longitud'  then
return not isSpecial(snak) and snak.datavalue.type == 'monolingualtext' and snak.datavalue.value.language == lang
        propiedad = 'P625' -- Si damos el valor latitud, longitud o precisión equivaldrá a dar p625
end
    else
        propiedad = opciones.propiedad -- En el resto de casos se lee lo dado
    end


local function numval(claims, numval) -- retourn les numval premières valeurs de la table claims
    if not propiedad then -- Comprobamos si existe la propiedad dada y en caso contrario se devuelve un error
local numval = tonumber(numval) or 0 -- raise an error if numval is not a positive integer ?
        return formatoError( 'property-param-not-provided' )
if #claims <= numval then
    end
return claims
end
    if declaracion then
local newclaims = {}
        tablaOrdenada = declaracion
while #newclaims < numval do
    elseif not p.getDeclaraciones(opciones.entityId) then
table.insert(newclaims, claims[#newclaims + 1])
    return formatoError( 'other entity' )
end
    elseif p.getDeclaraciones(opciones.entityId)[mw.ustring.upper(propiedad)] then
return newclaims
    tablaOrdenada = p.getDeclaraciones(opciones.entityId)[mw.ustring.upper(propiedad)]
end
    else
    return ''
    end


local function wikipediaLink(entity, lang)
-- Evitar que pete cuando se haga el find en opciones['formatoTexto'] si vale nil
local link
    if not opciones['formatoTexto'] then
if type(entity) == 'table' then
    opciones['formatoTexto'] = ''
link = entity:getSitelink(lang .. 'wiki')
    end
else
link = mw.wikibase.getSitelink(entity, lang .. 'wiki')
end
if link then
return ':' .. lang .. ':' .. link
end
return nil
end


local function getLink(entity, typelink, lang)
    --Dejar en su caso los valores de mayor rango
if typelink == 'wikidata' then
    if (opciones.rangoMayor == '') then
if type(entity) == 'table' then
        tablaOrdenada = filtrarDeclaracionPorRango(tablaOrdenada)
if entity.type == 'property' then
    end
return 'd:P:' .. entity.id
elseif entity.type == 'lexeme' then
return 'd:L:' .. entity.id
else
return 'd:' .. entity.id
end
else
if string.sub(entity, 1, 1) == 'P' then
return 'd:P:' .. entity
elseif string.sub(entity, 1, 1) == 'L' then
return 'd:L:' .. entity
else
return 'd:' .. entity
end
end


elseif typelink == 'wikipedia' then
    --Ordenar en su caso por fecha. Ver la función chronosort de :fr:Module:Wikidata/Récup
return wikipediaLink(entity, lang or defaultlang)
    if opciones.ordenar == 'por fecha' then
    require('Módulo:Tablas').ordenar(tablaOrdenada,
    function(elemento1,elemento2)
    local fecha1 = valinQualif(elemento1, datequalifiers) or '' -- elemento1.qualifiers.P580[1].datavalue.value.time or ''
    local fecha2 = valinQualif(elemento2, datequalifiers) or '' -- elemento2.qualifiers.P580[1].datavalue.value.time or ''
   
        return fecha1 < fecha2
        end
    )
    end
   
    if not tablaOrdenada[1] then
    return
    end


elseif typelink == 'anywikipedia' then
    -- == Si solo se desea que devuelva un valor ==
for _, lg in ipairs(fb.fblist(lang or defaultlang, true)) do
    -- Pendiente eliminar el parámetro y sustituirlo por un nuevo valor del parámetro lista=no que haría lo mismo que opciones.uno =
local link = wikipediaLink(entity, lg)
    if opciones.uno == 'sí' then -- Para que devuelva el valor de índice 1
if link then
        tablaOrdenada = {tablaOrdenada[1]}
return link
    elseif opciones.uno == 'último' then -- Para que devuelva la última entrada de la tabla
end
        tablaOrdenada = {tablaOrdenada[#tablaOrdenada]}
end
    end
end
return nil
end


function p.comparedate(a, b) -- returns true if a is earlier than B or if a has a date but not b
-- == Creamos una tabla con los valores que devolverá ==
if a and b then
return a.timestamp < b.timestamp
    local formatoDeclaraciones = {}
elseif a then
    local hayDeclaraciones
return true
   
end
for indice, declaracion in pairs(tablaOrdenada) do
return false
  declaracionFormateada = p.formatoDeclaracion(declaracion, opciones)
end
  if declaracionFormateada and declaracionFormateada ~= '' then
          table.insert(formatoDeclaraciones, declaracionFormateada)
          hayDeclaraciones = true
      end   
  end
 
    primera = true
   
    if not hayDeclaraciones then
        return
    end


function p.chronosort(objs, inverted)
    -- Aplicar el formato a la lista de valores según el tipo de lista de las
table.sort(objs, function(a, b)
    -- opciones
local timeA = p.getDate(a)
    if opciones['lista'] == 'no ordenada' then
local timeB = p.getDate(b)
    -- Añadir en su caso un lápiz
if inverted then
    if opciones.linkback == 'sí' then
return p.comparedate(timeB, timeA)
    return '<ul><li>' .. p.addLinkback(mw.text.listToText( formatoDeclaraciones, '</li><li>','</li><li>' ), opciones.entityId, opciones.propiedad) .. '</li></ul>'
    else
        return '<ul><li>' .. mw.text.listToText( formatoDeclaraciones, '</li><li>','</li><li>' ) .. '</li></ul>'
        end
    elseif opciones['lista'] == 'ordenada' then
    -- Añadir en su caso un lápiz
if opciones.linkback == 'sí' then
        return '<ol><li>' .. p.addLinkback(mw.text.listToText( formatoDeclaraciones, '</li><li>','</li><li>' ), opciones.entityId, opciones.propiedad) .. '</li></ol>'           
else
else
return p.comparedate(timeA, timeB)
        return '<ol><li>' .. mw.text.listToText( formatoDeclaraciones, '</li><li>','</li><li>' ) .. '</li></ol>'           
end
        end
end)
    else
 
    -- valores separados por coma o por el separador y la
return objs
      -- conjunción de las opciones
      local separador, conjuncion
       
        if opciones['conjunción'] == 'null' then
            conjuncion = nil
        else
            conjuncion = opciones['conjunción']
        end
   
        if opciones['separador'] == 'null' then
            separador = nil
        else
            separador = opciones['separador']
        end
       
        if table.getn(formatoDeclaraciones) > 1 then
        if not conjuncion then
        conjuncion = 'y'
        end
        if marco and conjuncion == 'y' then
        conjuncion = ' ' .. string.sub(marco:preprocess('{{y-e|{{Desvincular|' .. formatoDeclaraciones[#formatoDeclaraciones] .. '}}}}'), 1, 1) .. ' '
        elseif conjuncion == 'y' or conjuncion == 'o' then
        conjuncion = ' ' .. conjuncion .. ' '
        end
        end
       
        -- Añadir en su caso un lápiz
    if opciones.linkback == 'sí' then
return p.addLinkback(mw.text.listToText( formatoDeclaraciones, separador,conjuncion ), opciones.entityId, opciones.propiedad) 
    else
        return mw.text.listToText( formatoDeclaraciones, separador,conjuncion )
        end
    end
end
end


function p.sortclaims(claims, sorttype)
-- Función que sirve para comprobar si una entidad tiene una propiedad con un
if type(sorttype) == 'function' then
-- valor específico
table.sort(claims, sorttype)
-- Parámetros:
elseif sorttype == 'chronological' then
--  · entidad: tabla de la entidad de Wikidata
return p.chronosort(claims)
--  · propiedad: identificador de Wikidata para la propiedad
elseif sorttype == 'inverted' then
--  · valor: valor de la propiedad en Wikidata
return p.chronosort(claims, true)
function p.tieneValorPropiedad(entidad, propiedad, valor)
end
return claims
if entidad and entidad.claims and entidad.claims[propiedad] then
end
 
local mainsnak
function p.getRawvalue(snak)
return p.getDatavalue(snak, { displayformat = 'raw' })
for key,value in ipairs(entidad.claims[propiedad]) do
end
if value and value.mainsnak then
 
mainsnak = value.mainsnak
function p.showentity(entity, lang)
if mainsnak.datatype == 'wikibase-item' and  
if not entity then
mainsnak.snaktype == 'value' and
return nil
mainsnak.datavalue.value.id == valor then
end
return true
local label, link, id = p._getLabel(entity, lang), getLink(entity, 'wikidata')
if type(entity) == 'table' then
id = entity.id
else
id = entity
end
return '[[' .. link .. '|' .. label .. ']] <small>(' .. id .. ')</small>'
end
 
function p.getDatavalue(snak, params)
if isSpecial(snak) then
return nil
end
 
if not params then
params = {}
end
 
local displayformat = params.displayformat
local datatype = snak.datavalue.type
local value = snak.datavalue.value
 
if datatype == 'wikibase-entityid' then
if type(displayformat) == 'function' then
return displayformat(snak, params)
end
local id = snak.datavalue.value.id
if displayformat == 'raw' then
return id
elseif displayformat == 'wikidatastyle' then
return p.showentity(id, params.lang)
else
return p.formatEntity(id, params)
end
 
elseif datatype == 'string' then
local showntext = params.showntext
if displayformat == 'weblink' then
if showntext then
return '[' .. value .. ' ' .. showntext .. ']'
else
return value
end
end
if snak.datatype == 'math' and displayformat ~= 'raw' then
value = mw.getCurrentFrame():extensionTag('math', value)
else
if params.urlpattern then
showntext = mw.text.nowiki(showntext or value)
value = mw.ustring.gsub(value, '%%', '%%%%') -- escape '%'
value = '[' .. mw.ustring.gsub(mw.ustring.gsub(params.urlpattern, '$1', value), ' ', '%%20') .. ' ' .. showntext .. ']'
elseif params.pattern then
local pattern = mw.ustring.gsub(params.pattern, '%%', '%%%%')
value = mw.ustring.gsub(value, '%%', '%%%%')
value = mw.ustring.gsub(pattern, '$1', value)
else
if displayformat ~= 'raw' then
value = mw.text.nowiki(value)
end
end
end
end
end
end
return value
elseif datatype == 'time' then -- format example: +00000001809-02-12T00:00:00Z
if displayformat == 'raw' then
return value.time
else
return objectToText(dateObject(value), params)
end
elseif datatype == 'globecoordinate' then
-- retourne une table avec clés latitude, longitude, précision et globe à formater par un autre module (à changer ?)
if displayformat == 'latitude' then
return value.latitude
elseif displayformat == 'longitude' then
return value.longitude
elseif displayformat == 'qualifier' then
local coord = require 'Module:Coordinates'
value.globe = mw.loadData('Module:Wikidata/Globes')[value.globe]
value.precision = nil
return coord._coord(value)
else
value.globe = mw.loadData('Module:Wikidata/Globes')[value.globe] -- transforme l'ID du globe en nom anglais utilisable par geohack
return value -- note : les coordonnées Wikidata peuvent être utilisée depuis Module:Coordinates. Faut-il aussi autoriser à appeler Module:Coordiantes ici ?
end
elseif datatype == 'quantity' then -- todo : gérer les paramètre précision
if displayformat == 'raw' then
return tonumber(value.amount)
else
local formatNum = require 'Module:Formatnum'
local number = formatNum.formatNum(value.amount, params.lang)
local unit = mw.ustring.match(value.unit, '(Q%d+)')
if unit then
number = number .. '&nbsp;' .. p.formatEntity(unit, params)
end
return number
end
elseif datatype == 'monolingualtext' then
return '<span lang="' .. value.language .. '">' .. value.text .. '</span>'
else
return formatError( 'unknown-datavalue-type', datatype )
end
end
return false
end
end


local function getMultipleClaims(args)
-- Función que sirve para devolver la leyenda (P2096) de una imagen (P18) en Wikidata en un determinado idioma
local newargs = args
-- La función se llama así: {{#invoke:Wikidata |getLeyendaImagen | <PARÁMETRO> | lang=<ISO-639code> |id=<QID>}}
local claims = {}
-- Devuelve PARÁMETRO, a menos que sea igual a "FETCH_WIKIDATA", del objeto QID (llamada que consume recursos)
for i, j in pairs(args.property) do
-- Si se omite QID o está vacio, se utiliza el artículo actual (llamada que NO consume recursos)
newargs.property = j
-- Si se omite lang se utiliza por defecto el idioma local de la wiki, en caso contrario el idioma del código ISO-639
local newclaims = p.getClaims(args)
-- ISO-639 está documentado aquí: https://docs.oracle.com/cd/E13214_01/wli/docs92/xref/xqisocodes.html#wp1252447
if newclaims then
-- El ranking es: 'preferred' > 'normal' y devuelve la etiqueta de la primera imágen con ranking 'preferred'
for k, l in pairs(newclaims) do
-- O la etiqueta de la primera imagen with ranking 'normal' si no hay ningún 'preferred'
table.insert(claims, l)
-- Ranks: https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua
end
 
end
p.getLeyendaImagen = function(frame)
-- busca un un elemento concreto en Wikidata (QID), en caso contrario que sea nil
local id = frame.args.id
if id and (#id == 0) then
id = nil
end
end
return claims
end


function p.getClaims( args ) -- returns a table of the claims matching some conditions given in args
-- busca el parámetro del idioma que debería contender un código ISO-639 de dos dígitos
args = removeBlanks(args)
-- si no se declara, toma por defecto el idioma local de la wiki (es)
if not args.property then
local lang = frame.args.lang
return formatError( 'property-param-not-provided' )
if (not lang) or (#lang < 2) then
end
lang = mw.language.getContentLanguage().code
if type(args.property) == 'table' then
return getMultipleClaims(args)
end
--Get entity
if args.item then -- synonyms
args.entity = args.item
end
local property = string.upper(args.property)
local allClaims
local entity = args.entity
if type(entity) == 'table' then
allClaims = (entity and entity.claims and entity.claims[property]) or {}
else
allClaims = mw.wikibase.getAllStatements(entity, property)
end
if #allClaims == 0 then
return nil
end
end


if not args.rank then
-- el primer parámetro sin nombrar es el parámetro local, si se declara
args.rank = 'best'
local input_parm = mw.text.trim(frame.args[1] or "")
end
if input_parm == "FETCH_WIKIDATA" or input_parm == "" or input_parm == nil then
local claims = {}
local ent = mw.wikibase.getEntityObject(id)
for _, statement in ipairs(allClaims) do
local imgs
if
if ent and ent.claims then
(
imgs = ent.claims.P18
not args.excludespecial
or
not (isSpecial(statement.mainsnak))
)
and
(
not args.targetvalue
or
hasTargetValue(statement, args.targetvalue)
)
and
(
not args.qualifier
or
hasQualifier(statement, args.qualifier, args.qualifiervalues or args.qualifiervalue)
)
and
(
not args.withsource or args.withsource == '-'
or
hasSource(statement, args.withsource, args.sourceproperty)
)
and
(
not args.isinlanguage
or
isInLanguage(statement.mainsnak, args.isinlanguage)
)
and
(
args.rank == 'best' -- rank == best est traité à a fin
or
hasRank(statement, args.rank)
)
then
table.insert(claims, statement)
end
end
end
local imglbl
if #claims == 0 then
if imgs then
return nil
-- busca una imagen con ranking 'preferred'  
end
for k1, v1 in pairs(imgs) do
if args.rank == 'best' then
if v1.rank == "preferred" and v1.qualifiers and v1.qualifiers.P2096 then
claims = bestRanked(claims)
local imglbls = v1.qualifiers.P2096
end
for k2, v2 in pairs(imglbls) do
if args.sorttype then
if v2.datavalue.value.language == lang then
claims = p.sortclaims(claims, args.sorttype)
imglbl = v2.datavalue.value.text
end
 
if args.numval then
return numval(claims, args.numval)
end
return claims
end
 
function p.formatClaimList(claims, args)
if not claims then
return nil
end
for i, j in pairs(claims) do
claims[i] = p.formatStatement(j, args)
end
return claims
end
 
function p.stringTable(args) -- like getClaims, but get a list of string rather than a list of snaks, for easier manipulation
local claims = p.getClaims(args)
return p.formatClaimList(claims, args)
end
 
local function getQualifiers(statement, qualifs, params)
if not statement.qualifiers then
return nil
end
local vals = {}
for i, j in pairs(qualifs) do
j = string.upper(j)
if statement.qualifiers[j] then
local inserted = false
if statement.qualifiers[j][1].datatype == 'monolingualtext' then
local in_preferred_lang
for _, language in ipairs(fb.fblist(params.lang or defaultlang, true)) do
for _, snak in ipairs(statement.qualifiers[j]) do
if isInLanguage(snak, language) then
in_preferred_lang = snak
break
break
end
end
end
end
if in_preferred_lang then
break
end
end
if in_preferred_lang then
table.insert(vals, in_preferred_lang)
inserted = true
end
end
if not inserted then
for _, snak in pairs(statement.qualifiers[j]) do
table.insert(vals, snak)
end
end
end
end
end
-- si no hay ninguna, busca una con ranking 'normal'
end
if (not imglbl) then
if #vals == 0 then
for k1, v1 in pairs(imgs) do
return nil
if v1.rank == "normal" and v1.qualifiers and v1.qualifiers.P2096 then
end
local imglbls = v1.qualifiers.P2096
return vals
for k2, v2 in pairs(imglbls) do
end
if v2.datavalue.value.language == lang then
 
imglbl = v2.datavalue.value.text
function p.getFormattedQualifiers(statement, qualifs, params)
break
if not params then params = {} end
end
local qualiftable = getQualifiers(statement, qualifs, params)
if not qualiftable then
return nil
end
for i, j in pairs(qualiftable) do
local params = params
if j.datatype == 'globe-coordinate' then
params.displayformat = 'qualifier'
end
qualiftable[i] = p.formatSnak(j, params)
end
return linguistic.conj(qualiftable, params.lang or defaultlang)
end
 
function p.formatStatement( statement, args )
if not statement.type or statement.type ~= 'statement' then
return formatError( 'unknown-claim-type', statement.type )
end
if not args then args = {} end
local lang = args.lang or defaultlang
local str = p.formatSnak( statement.mainsnak, args )
if args.showlang == true then
str = showLang(statement, str)
end
 
local qualifs = args.showqualifiers
if qualifs then
if type(qualifs) == 'string' then
qualifs = mw.text.split(qualifs, ',')
end
local foundvalues = p.getFormattedQualifiers(statement, qualifs, args)
if foundvalues then
if args.delimiter then
str = str .. args.delimiter .. foundvalues
else
str = str .. linguistic.inparentheses(foundvalues, lang)
end
end
end
 
if args.showdate then -- when "showdate and p.chronosort are both set, date retrieval is performed twice
local timedata = p.getDate(statement)
if timedata then
local formatteddate = objectToText(timedata, args)
formatteddate = linguistic.inparentheses(formatteddate, lang)
str = str .. '<small>' .. formatteddate ..'</small>'
end
end
 
if args.showsource and statement.references then
local cite = require 'Module:Cite'
local frame = mw.getCurrentFrame()
local sourcestring = ''
for _, ref in ipairs(statement.references) do
if ref.snaks.P248 then
for j, source in pairs(ref.snaks.P248) do
if not isSpecial(source) then
local page
if ref.snaks.P304 and not isSpecial(ref.snaks.P304[1]) then
page = ref.snaks.P304[1].datavalue.value
end
end
local s = cite.citeitem(source.datavalue.value.id, lang, page)
s = frame:extensionTag( 'ref', s )
sourcestring = sourcestring .. s
end
end
end
end
elseif ref.snaks.P854 and not isSpecial(ref.snaks.P854[1]) then
s = frame:extensionTag( 'ref', p.getDatavalue(ref.snaks.P854[1]) )
sourcestring = sourcestring .. s
end
end
end
end
str = str .. sourcestring
return imglbl
end
return str
end
 
function p.getmainid(claim)
if claim and not isSpecial(claim.mainsnak) then
return claim.mainsnak.datavalue.value.id
end
return nil
end
 
function p.formatSnak(snak, params)
--local params = params or {} pour faciliter l'appel depuis d'autres modules
if snak.snaktype == 'value' then
return p.getDatavalue(snak, params)
elseif snak.snaktype == 'somevalue' then
return formatTheUnknown()
elseif snak.snaktype == 'novalue' then
return i18n('novalue') --todo
else
else
return formatError( 'unknown-snak-type', snak.snaktype )
return input_parm
end
end
end
end


local function defaultLabel(entity, displayformat) -- label when no label is available
-- Función que devuelve el valor de entidad.claims[idPropiedad][ocurrencia].mainsnak.datavalue.value.text
if displayformat == 'id' then
-- con entidad.claims[idPropiedad][ocurrencia].mainsnak.datavalue.value.language = 'es'
if type(entity) ~= 'table' then
return entity
else
return entity.id
end
end
return i18n('no-label')
end


function p._getLabel(entity, lang, default, fallback)
-- Útil para obtener valores de propiedades de tipo monolingualtext
if not entity then
return nil
end
if not lang then
lang = defaultlang
end
if type(entity) ~= 'table' and lang == defaultlang then
local label, lg = mw.wikibase.getLabelWithLang(entity)
if label and (fallback ~= '-' or lg == lang) then
return label
end
else
entity = p.getEntity(entity)
if entity and entity.labels then
if fallback ~= '-' then
for _, lg in ipairs(fb.fblist(lang, true)) do
if entity.labels[lg] then
return entity.labels[lg].value
end
end
else
if entity.labels[lang] then
return entity.labels[lang].value
end
end
end
end
return defaultLabel(entity, default)
end


function p._getDescription(entity, lang, fallback)
function p.getPropiedadEnEspanyol(idEntidad, idPropiedad)
if not entity then
-- Ver cs:Modul:Wikidata/item formatEntityWithGender
return i18n('no description')
--
local entidad =  mw.wikibase.getEntityObject(idEntidad)
if not entidad then
return
end
end
if not lang then
lang = defaultlang
local declaracion  = elementoTabla(entidad,'claims', idPropiedad)
if not declaracion then
return
end
end
if type(entity) ~= 'table' and lang == defaultlang then
local description, lg = mw.wikibase.getDescriptionWithLang(entity)
local valor
if description and (fallback ~= '-' or lg == lang) then
return description
for k,v in pairs(declaracion) do
end
valor = elementoTabla(v,'mainsnak', 'datavalue', 'value')
else
entity = p.getEntity(entity)
if valor.language == 'es' then
if entity and entity.descriptions then
return valor.text
if fallback ~= '-' then
for _, lg in ipairs(fb.fblist(lang, true)) do
if entity.descriptions[lg] then
return entity.descriptions[lg].value
end
end
else
if entity.descriptions[lang] then
return entity.descriptions[lang].value
end
end
end
end
end
return i18n('no description')
end
local function formattedLabel(label, entity, args)
local link = getLink(entity, args.link, args.lang)
if not link then
link = getLink(entity, defaultlink, args.lang)
end
if not link then
return label
else
return '[[' .. link .. '|' .. label .. ']]'
end
end
end
end


function p.formatEntity( entity, args )
-- devuelve el ID de la página en Wikidata (Q...), o nada si la página no está conectada a Wikidata
if not entity then
function p.pageId(frame)
return nil
local entity = mw.wikibase.getEntityObject()
end
if not entity then return nil else return entity.id end
if not args then
args = {}
end
local label = p._getLabel(entity, args.lang, 'id', args.fallback)
return formattedLabel(label, entity, args)
end
end


function p.getLabel(frame) -- simple for simple templates like {{Q|}}}
function p.categorizar(opciones, declaracion)
local args = frame.args
-- Evitar que pete cuando se haga el find en opciones['formatoTexto'] si vale nil
local entity = args.entity
    if not opciones['formatoTexto'] then
local lang = args.lang
    opciones['formatoTexto'] = ''
if not entity then
    end
return i18n('invalid-id')
local categoriaOpciones=opciones['categoría']
if not categoriaOpciones then
return ''
end
end


if string.sub(entity, 1, 10) == 'Property:P' then
opciones['enlace'] = 'no'
entity = string.sub(entity, 10)
elseif string.sub(entity, 1, 8) == 'Lexeme:L' then
entity = string.sub(entity, 8)
elseif not ({L = 1, P = 1, Q = 1})[string.sub(entity, 1, 1)] or not tonumber(string.sub(entity, 2)) then
return i18n('invalid-id')
end


if not args.link or args.link == '' or args.link == '-' then -- by default: no link
    -- Crear una tabla con los valores de la propiedad.
if lang == '' then
local valoresDeclaracion = {}
lang = defaultlang
end
    if declaracion then
return p._getLabel(entity, lang, args.default, args.fallback)
        valoresDeclaracion = declaracion
else
    elseif opciones.propiedad then
return p.formatEntity(entity, args)
        local propiedad = {}
end
        if opciones.propiedad == 'precisión' or opciones.propiedad == 'latitud' or opciones.propiedad == 'longitud'  then
            propiedad = 'P625' -- Si damos el valor latitud, longitud o precisión equivaldrá a dar p625
        else
            propiedad = opciones.propiedad -- En el resto de casos se lee lo dado
        end
       
        if not p.getDeclaraciones(opciones.entityId) then
        return formatoError( 'other entity' )
        elseif p.getDeclaraciones(opciones.entityId)[mw.ustring.upper(propiedad)] then  
        valoresDeclaracion = p.getDeclaraciones(opciones.entityId)[mw.ustring.upper(propiedad)]
        else
        return ''
        end   
    else
    return ''
    end
-- Creamos una tabla con cada categoría a partir de cada valor de la declaración
    local categorias    = {}
    local hayCategorias
   
    if type(categoriaOpciones) == 'string' then
        local ModuloPaginas = require('Módulo:Páginas')
     
        for indice, valor in pairs(valoresDeclaracion) do
            valorFormateado = p.formatoDeclaracion(valor, opciones)
        if valorFormateado ~= '' then
        categoria = ModuloPaginas.existeCategoria(categoriaOpciones:gsub('$1',valorFormateado))
   
                if categoria then
                    table.insert(categorias, categoria)
                    hayCategorias = true
                end
            end   
        end
    elseif type(categoriaOpciones) == 'table' then
        for indice, valor in pairs(valoresDeclaracion) do
            categoria = categoriaOpciones[elementoTabla(valor, 'mainsnak', 'datavalue', 'value', 'numeric-id')]
           
            if categoria then
                table.insert(categorias, 'Categoría:' .. categoria)
                hayCategorias = true
            end
        end
    end
   
    if hayCategorias then
        return '[[' .. mw.text.listToText( categorias, ']][[',']][[') .. ']]'
    end
   
    return ''
end
end
 
function p._formatStatements( args )--Format statements and concat them cleanly
--[[ =========================================================================
if args.value == '-' then
        Función que comprueba si la página está enlazada a  Wikidata
return nil
        en caso de estarlo pasa el valor como a argumento a la función formatSnak() 
end
    ========================================================================= `-- ]]
--If a value is already set, use it
if args.value and args.value ~= '' then
function p.formatoDeclaracion( declaracion, opciones)
return args.value
    if not declaracion.type or declaracion.type ~= 'statement' then -- Se comprueba que tiene valor de tipo y que este sea statement (declaración) lo cual pasa siempre que existe la propiedad
end
        return formatoError( 'unknown-claim-type' ) -- Si no se cumple devuelve error
local valuetable = p.stringTable(args)
    end
return tableToText(valuetable, args)
   
    -- En el caso de que haya calificador se devuelve a la derecha del valor de la
    -- declaración entre paréntesis.
   
    local calificativo = opciones.calificativo or opciones.calificador
    if calificativo and declaracion.qualifiers then
    -- De momento los calificativos, normalmente años, no se enlazan
      local opcionesCalificativo = {['formatoTexto']='', enlace='no', ['formatoFecha']='año'} -- Pendiente
     
      local wValorCalificativo
      local wValorCalificativoFormateado
     
      local funcionCalificativo, mensajeError = obtenerFuncion(calificativo, opciones['módulo calificativo'])
     
if mensajeError then
return mensajeError
elseif funcionCalificativo then
        -- Utilizar la función recibida sobre todos los calificativos
        wValorCalificativo          = declaracion.qualifiers
          wValorCalificativoFormateado = funcionCalificativo(wValorCalificativo, opcionesCalificativo)
      elseif opciones.formatoCalificador and opciones.formatoCalificador == '()' then
wValorCalificativo = declaracion.qualifiers[mw.ustring.upper(calificativo)]
    if wValorCalificativo and wValorCalificativo[1] then
    wValorCalificativoFormateado = p.formatoDato(wValorCalificativo[1], opcionesCalificativo)
    end
    elseif opciones.formatoCalificador and table.getn(mw.text.split(opciones.formatoCalificador, '%.')) == 2 then
    moduloFormatoCalificador = mw.text.split(opciones.formatoCalificador, '%.')
    formateado = require ('Módulo:' .. moduloFormatoCalificador[1])
        if not formateado then
            return formatoError( 'value-module-not-found' )
        end
        fun = formateado[moduloFormatoCalificador[2]]
        if not fun then
            return formatoError( 'value-function-not-found' )
        end
       
        if mw.ustring.find(opciones['formatoTexto'],'mayúscula', plain ) and
      (primera or (opciones['separador'] and opciones['separador'] ~= 'null') or
      (opciones['lista'] and opciones['lista'] ~= '')) then
      opciones['mayúscula'] = 'sí'
              primera = false
    end
   
    if mw.ustring.find(opciones['formatoTexto'],'cursivas', plain ) then
    opcionesEntidad.cursivas = 'sí'
    end
       
        wValorCalificativoFormateado = fun( declaracion.qualifiers, opciones, marco)
        --return require('Módulo:Tablas').tostring(declaracion)
    else
        -- Utilizar el primer valor del calificativo de la propiedad recibida
        wValorCalificativo = declaracion.qualifiers[mw.ustring.upper(calificativo)]
       
        if wValorCalificativo and wValorCalificativo[1] then
            wValorCalificativoFormateado = p.formatoDato(wValorCalificativo[1], opcionesCalificativo)
      end
    end
if opciones.separadorcalificador then separador = opciones.separadorcalificador else separador = ' ' end
    if wValorCalificativoFormateado then
    datoFormateado = p.formatoDato(declaracion.mainsnak, opciones)
    return (datoFormateado and datoFormateado .. '&nbsp;<small>(' .. wValorCalificativoFormateado .. ')</small>') or nil
    end    
    end
    -- Si no hay calificativo.
    return p.formatoDato(seleccionDeclaracion(declaracion, opciones), opciones, declaracion.qualifiers)
end
end
 
function p.showQualifier( args )
--[[ =========================================================================
local qualifs = args.qualifiers or args.qualifier
        Función que comprueba el tipo de dato (snaktype)
if type(qualifs) == 'string' then
        si es value pasa el valor como argumento a la función formatoValorDato()  
qualifs = mw.text.split(qualifs, ',')
    ========================================================================= `-- ]]
end
if not qualifs then
function p.formatoDato( dato, opciones, calificativos)
return formatError( 'property-param-not-provided' )
   
end
    if not dato or dato == '' then
local claims = p.getClaims(args)
        return ''
if not claims then
    end
return nil
    if dato.snaktype == 'somevalue' then
end
    -- Fecha más temprana
local str = ''
    if calificativos then
local new
    if calificativos['P1319'] and calificativos['P1319'][1] and
for _, cl in ipairs(claims) do
          calificativos['P1319'][1].datavalue and
new = p.getFormattedQualifiers(cl, qualifs, args) or ''
          calificativos['P1319'][1].datavalue.type=='time' then
str = str .. new
         
end
                local opcionesFecha={['formatoFecha']=opciones['formatoFecha'],enlace=opciones.enlace}
return str
       
                return 'post. ' .. require('Módulo:Wikidata/Fecha').FormateaFechaHora(calificativos['P1319'][1].datavalue.value, opcionesFecha)
            end
    end
   
    -- Si no tiene un calificativo válido
        return avisos['somevalue'] -- Valor desconocido
    elseif dato.snaktype == 'novalue' then
        return avisos['novalue'] -- Sin valor
    elseif dato.snaktype == 'value' then
        return formatoValorDato( dato.datavalue, opciones, calificativos) -- Si tiene el tipo de dato se pasa el valor a la función formatDatavalue()
    else
        return formatoError( 'unknown-snak-type' ) -- Tipo de dato desconocido
    end
end
end
 
function p._formatAndCat(args)
--[[ =========================================================================
local val = p._formatStatements(args)
      Función que establece el tipo de formato en función del tipo de valor
if val then
      (valorDato.type) y en caso de solicitarse un formato complemetario asocia
return val .. addTrackingCat(args.property)
      el módulo donde se establece el formato y la función de este que lo establece   
    ========================================================================= `-- ]]
function formatoValorDato( valorDato, opciones, calificativos)
local funcion, mensajeError = obtenerFuncion(opciones['valor-función'] or opciones['value-function'], opciones['valor-módulo'])
if mensajeError then
return mensajeError
elseif funcion then
local opcionesEntidad = {}
for k, v in pairs(opciones) do
opcionesEntidad[k] = v
end
   
    if mw.ustring.find(opciones['formatoTexto'],'mayúscula', plain ) and
      (primera or (opciones['separador'] and opciones['separador'] ~= 'null') or
      (opciones['lista'] and opciones['lista'] ~= '')) then
      opcionesEntidad['mayúscula'] = 'sí'
              primera = false
    end
   
    if mw.ustring.find(opciones['formatoTexto'],'cursivas', plain ) then
    opcionesEntidad.cursivas = 'sí'
    end
   
return funcion(valorDato.value, opcionesEntidad, marco, calificativos)
end
end
return nil
    -- == Formatos por defecto en función del tipo de valor ==
--          * Para tipo coordenadas cuando se da como valor de propiedad: latitud, longitud o precisión
    if opciones.propiedad == 'latitud' then
        return valorDato.value['latitude']
    elseif opciones.propiedad == 'longitud' then
        return valorDato.value['longitude']
    elseif opciones.propiedad == 'precisión' then
        return valorDato.value['precision']
--          * Con el resto de valores en propiedad
    elseif valorDato.type == 'wikibase-entityid' then    -- Tipo: Número de entidad que puede ser un ítem o propiedad
    local opcionesEntidad = {}
    if mw.ustring.find(opciones['formatoTexto'],'mayúscula', plain ) and
      (primera or (opciones['separador'] and opciones['separador'] ~= 'null') or
      (opciones['lista'] and opciones['lista'] ~= '')) then
      opcionesEntidad['mayúscula'] = 'sí'
              primera = false
    end
    opcionesEntidad.enlace        = opciones.enlace
    opcionesEntidad.etiqueta      = opciones.etiqueta
    opcionesEntidad['debeExistir'] = opciones['debeExistir']
   
    if mw.ustring.find(opciones['formatoTexto'],'cursivas', plain ) then
    opcionesEntidad.cursivas = 'sí'
    end
        return p.formatoIdEntidad( SelecionEntidadPorValor( valorDato.value ), opcionesEntidad)
    elseif valorDato.type == 'string' then              -- Tipo: Cadena de texto (string)
        return valorDato.value
    elseif valorDato.type == 'url' then    --Tipo URL (dirección web)
    return value.url
    elseif valorDato.type == 'time' then                -- Tipo: Fecha/hora
        local opcionesFecha={['formatoFecha']=opciones['formatoFecha'],enlace=opciones.enlace}
     
        if mw.ustring.find(opciones['formatoTexto'] or '','mayúscula', plain ) and primera then
        opcionesFecha['mayúscula']='sí'
        end
       
        return require('Módulo:Wikidata/Fecha').FormateaFechaHora(valorDato.value, opcionesFecha, calificativos)
    elseif valorDato.type == 'monolingualtext' then      -- Tipo: monoligüe
    if valorDato.value then
            return valorDato.value.text
        else
            return ''
        end
    elseif valorDato.type ==  'quantity' then            -- Tipo: Cantidad
    return require('Módulo:Wikidata/Formatos').formatoUnidad(valorDato, opciones)
    elseif  valorDato.value['latitude']  and valorDato.value['longitude'] then -- Tipo: Coordenadas
    local globo = require('Módulo:Wikidata/Globos')[valorDato.value.globe]
--Concatenamos los valores de latitud y longitud dentro de la plantilla Coord
        if globo ~= 'earth' then
            return  marco:preprocess('{{coord|' .. valorDato.value['latitude'] .. '|' ..
                  valorDato.value['longitude'] .. '|globe:' .. globo .. '_type:' .. opciones.tipo .. '|display=' ..
                  opciones.display ..'|formato=' .. opciones.formato..'}}')
        else
        return  marco:preprocess('{{coord|' .. valorDato.value['latitude'] .. '|' ..
                  valorDato.value['longitude'] .. '|type:' .. opciones.tipo .. '|display=' ..
                  opciones.display ..'|formato=' .. opciones.formato..'}}')
        end
    else
        return formatoError( 'unknown-datavalue-type' ) -- Si no es de ninguno de estos tipos devolverá error valor desconocido
    end
end
end
  --[[ =========================================================================
          Damos formato a los enlaces internos   
      ========================================================================= `-- ]]


function p.getTheDate(args)
-- Opciones:
local claims = p.getClaims(args)
--    - enlace: Valores posibles 'sí' o 'no'
if not claims then
--    - mayúscula: Valores posibles 'sí' o 'no'
return nil
--     - cursivas: Valores posibles 'sí' o 'no'
end
local formattedvalues = {}
for _, cl in ipairs(claims) do
table.insert(formattedvalues, p.getFormattedDate(cl))
end
local val = linguistic.conj(formattedvalues)
if val and args.addcat == true then
return val .. addTrackingCat(args.property)
else
return val
end
end
---FONCTIONS depuis le FRAME
function p.getaDate(frame)
return p.getTheDate(frame.args)
end


function p.getQualifier(frame)
function p.formatoIdEntidad(idEntidad, opciones)
return p.showQualifier(frame.args)
    local enlace  = mw.wikibase.sitelink(idEntidad)
    local etiqueta = mw.wikibase.label(idEntidad)
return require('Módulo:Wikidata/Formatos').enlazar(enlace, etiqueta, idEntidad, opciones)
end
end
--[[ =========================================================================
        Función principal   
    ========================================================================= `-- ]]
function p.Wikidata( frame )
    marco = frame
    local args = frame.args
   
    if args.valor == 'no' then
    return
    end


function p.getDescription(frame) -- simple for simple templates like {{Q|}}}
    local parentArgs = frame:getParent().args
local entity = frame.args.entity
   
if not entity then
    -- Copiar los argumentos
return i18n('invalid-id')
    local argumentos = {}
   
    for k, v in pairs(args) do
    argumentos[k] = v
    end
   
    for k, v in pairs(parentArgs) do
    if not argumentos[k] then
    argumentos[k] = v
    end
    end
   
    --if true then return require('Módulo:Tablas').tostring(argumentos) end
   
    -- No generar el valor de Wikidata si se ha facilitado un valor local y
    -- el valor local es prioritario.
    local valorWikidata;
    if (args.prioridad ~= 'sí' or (args.importar and args.importar == 'no')) and args.valor and args.valor ~= '' then
    valorWikidata = '';
    else
    valorWikidata = p.getPropiedad(argumentos, nil);
    end
   
local categorias = '';
local namespace = frame:preprocess('{{NAMESPACENUMBER}}');
if (namespace == '0' and (not args.categorias or args.categorias ~= 'no') and
args.propiedad and string.upper(args.propiedad) ~= 'P18' -- P18: imagen de Commons
and string.upper(args.propiedad) ~= 'P41' -- P41: imagen de la bandera
and string.upper(args.propiedad) ~= 'P94' -- P94: imagen del escudo de armas
and string.upper(args.propiedad) ~= 'P109' -- P109: firma de persona
and string.upper(args.propiedad) ~= 'P154') then -- P154: logotipo
if valorWikidata ~= '' and args.valor and args.valor ~= '' then
categorias = '[[Categoría:Wikipedia:Artículos con datos locales]]'
elseif valorWikidata and valorWikidata == '' and args.valor and args.valor ~= '' and
(not args.calificador or args.calificador == '') and
(not args.dato or args.dato == '' or args.dato ~= 'fuente')then
categorias = '[[Categoría:Wikipedia:Artículos con datos por trasladar a Wikidata]]'
end
end
end
local lang = frame.args.lang
local fallback = frame.args.fallback
    if args.prioridad == 'sí' and valorWikidata  ~= '' then -- Si se da el valor sí a prioridad tendrá preferencia el valor de Wikidata
 
    if args.importar and args.importar == 'no' and args.valor and args.valor ~= '' then
return p._getDescription(entity, lang, fallback)
    return args.valor .. categorias
    elseif valorWikidata then
        return valorWikidata .. categorias -- valor que sustituye al valor de Wikidata parámetro 2
        else
        return categorias
        end
    elseif args.valor and args.valor ~= '' then
        return args.valor .. categorias
    elseif args.importar and args.importar == 'no' then
        return ''
    elseif valorWikidata then -- Si el valor es nil salta una excepcion al concatenar
        return valorWikidata .. categorias
    else
    return ''
  end 
end
end


function p.formatStatements( args )
function obtenerFuncion(funcion, nombreModulo)
return p._formatStatements( args )
if not funcion then
end
return
 
elseif type(funcion) == 'function' then -- Uso desde LUA
function p.formatStatementsE(frame)
return funcion
local args = {}
elseif funcion == '' or not nombreModulo or nombreModulo == '' then
if frame == mw.getCurrentFrame() then
return
args = frame:getParent().args -- paramètres du modèle appelant (est-ce vraiment une bonne idée ?)
else -- Uso desde una plantilla
for k, v in pairs(frame.args) do
local modulo
args[k] = v
if not nombreModulo or nombreModulo == '' or nombreModulo == 'Wikidata/Formatos' then
modulo = require(modulosTipos[funcion] or 'Módulo:Wikidata/Formatos')
else
modulo = require ('Módulo:' .. nombreModulo)
end
end
else
args = frame
      if not modulo then
          return nil, formatoError( 'value-module-not-found' )
        elseif not modulo[funcion] then
          return nil, formatoError( 'value-function-not-found' )
        else
          return modulo[funcion]
      end
end
end
return p._formatStatements( args )
end
end


function p.formatAndCat(frame)
function p.addLinkback(valorPropiedad, idEntidad, idPropiedad)
local args = {}
local lidEntidad
if frame == mw.getCurrentFrame() then
args = frame:getParent().args -- paramètres du modèle appelant (est-ce vraiment une bonne idée ?)
if valorPropiedad and idPropiedad then
for k, v in pairs(frame.args) do
lidEntidad= (idEntidad ~='' and idEntidad) or mw.wikibase.getEntityIdForCurrentPage()
args[k] = v
end
else
args = frame
end
end
return p._formatAndCat( args )
end


function p.getEntityFromId(id)
if lidEntidad then
return p.getEntity(id)
return valorPropiedad .. '<span class=\"wikidata-link noprint\"> [[Archivo:Blue_pencil.svg|Ver y modificar los datos en Wikidata|10px|baseline|alt=Ver y modificar los datos en Wikidata|enlace=https://www.wikidata.org/wiki/' .. lidEntidad .. '?uselang=es#' .. idPropiedad ..
    ']]</span>'
    else
    return valorPropiedad
    end
end
end
 
return p
return p

Revisión del 07:42 28 feb 2019

La documentación para este módulo puede ser creada en Módulo:Wikidata/doc

Error de secuencia de órdenes: Error de Lua: Error interno: El intérprete ha finalizado con el estado 127.

--[[*********************************************************************************
    * Nombre: Módulo:Wikidata
    *
    * Descripción: Este módulo devuelve el valor o valores con o sin formato específico 
    *             a una propiedad de Wikidata. 
    *
    * Fecha última revisión: 6 de septiembre de 2014.
    *
    * Estado: En uso. 
    *
    *********************************************************************************`-- ]]
 
local p = {}
local datequalifiers = {'P585', 'P571', 'P580', 'P582'}
local es = mw.language.new('es')
local primera = true
--local marco Ojo. marco no debe definirse como local pues si se hace así puede fallar.
 --[[ =========================================================================
            Mensajes de error
      ========================================================================= `-- ]]
 
local avisos = {
    ["errores"] = {
        ["property-param-not-provided"] = "Parámetro de la propiedad no proporcionado.",
        ["entity-not-found"] = "Entrada no encontrada.",
        ["unknown-claim-type"] = "Tipo de notificación desconocida.",
        ["unknown-snak-type"] = "Tipo de dato desconocido.",
        ["unknown-datavalue-type"] = "Formato de dato desconocido.",
        ["unknown-entity-type"] = "Tipo de entrada desconocido.",
        ["unknown-value-module"] = "Debe ajustar ambos parámetros de valor y el valor del módulo de funciones.",
        ["value-module-not-found"] = "No se ha encontrado el módulo apuntado por valor-módulo.",
        ["value-function-not-found"] = "No se ha encontrado la función apuntada por valor-función.",
        ["other entity"] = "Enlaces a elementos diferentes desactivado."
    },
    ["somevalue"] = "''valor desconocido''",
    ["novalue"] = ""
}

-- Módulos y funciones utilizadas
local elementoTabla = require('Módulo:Tablas').elemento
--
-- Módulos en los que están definidos los tipos de datos más habituales si son
-- diferentes de Wikidata/Formatos
--
local modulosTipos =  {
	['altura']       = 'Módulo:Wikidata/Formato magnitud',
	['área']         = 'Módulo:Wikidata/Formato magnitud',
	['educado en']   = 'Módulo:Wikidata/Formatos educación',
	['imagen']       = 'Módulo:Wikidata/Formato imagen',
	['lugar']        = 'Módulo:Wikidata/Formato lugar',
	['formatoLugar'] = 'Módulo:Wikidata/Formato lugar',
	['magnitud']     = 'Módulo:Wikidata/Formato magnitud',
	['movimiento']   = 'Módulo:Wikidata/Formato movimiento',	
	['periodicidad'] = 'Módulo:Wikidata/Formato magnitud',
	['premio']		 = 'Módulo:Wikidata/Formato premio',
}
	
	
 --[[ =========================================================================
      Función para pasar el frame cuando se usa en otros módulos.      
     ========================================================================= `-- ]]
function p:setFrame(frame)
	marco = frame
end
 --[[ =========================================================================
      Función para identificar el ítem correspondiente a la página o otro dado.
              Esto último aún no funciona.      
     ========================================================================= `-- ]]


function SelecionEntidadPorId( id )
 
        if id and id ~= ''  then
            return mw.wikibase.getEntityObject( id )
        else 
            return mw.wikibase.getEntityObject()
        end 
 
end 
 
 
 --[[ =========================================================================
      Función que identifica si el valor devuelto es un ítem o una propiedad 
      y en función de eso añade el prefijo correspondiente     
     ========================================================================= `-- ]]
 
function SelecionEntidadPorValor( valor )
    local prefijo = ''
    if valor['entity-type'] == 'item' then
        prefijo = 'q' -- Prefijo de ítem
    elseif valor['entity-type'] == 'property' then
        prefijo = 'p' -- Prefijo de propiedad
    else
        return formatoError( 'unknown-entity-type' )
    end
    return prefijo .. valor['numeric-id'] -- Se concatena el prefijo y el código numérico
end
 
 --[[ =========================================================================
      Función auxiliar para dar formato a los mensajes de error      
     ========================================================================= `-- ]] 
 
function formatoError( clave )
    return '<span class="error">' .. avisos.errores[clave] .. '</span>'
end
 --[[ =========================================================================
      Función para determinar el rango     
     ========================================================================= `-- ]]
function getRango(tablaDeclaraciones)
 
	local rank = 'deprecated'
 
    for indice, declaracion in pairs(tablaDeclaraciones) do
        if declaracion.rank == 'preferred' then
            return 'preferred'
        elseif declaracion.rank == 'normal' then
            rank = 'normal'
        end 
    end
 
    return rank
end
 
 --[[ =========================================================================
      Función para determinar la declaracion o declaraciones de mayor rango    
     ========================================================================= `-- ]]
function filtrarDeclaracionPorRango(tablaDeclaraciones)
    local rango = getRango(tablaDeclaraciones)
    local tablaAuxiliar = tablaDeclaraciones
    tablaDeclaraciones = {}
 
    for indice, declaracion in pairs(tablaAuxiliar) do
        if declaracion.rank == rango then
            table.insert(tablaDeclaraciones, declaracion)
        end 
    end 
    return tablaDeclaraciones
end
 
 --[[ =========================================================================
      Función para seleccionar el tipo de declaración: Referencia, valor principal 
      o calificador      
     ========================================================================= `-- ]]
 
function seleccionDeclaracion(declaracion, opciones)
    local fuente = {}
    local propiedadFuente = {}
    local calificador = opciones.formatoCalificador ~= '()' and opciones.calificador
 
    if calificador ~= '' and calificador  and declaracion['qualifiers'] then
    	if declaracion['qualifiers'][mw.ustring.upper(calificador)] then
            return declaracion.qualifiers[mw.ustring.upper(calificador)][1] -- devuelve el calificador (solo devolverá el primer valor)
        else
        	return "" --Para que no lance excepción si no existe el calificador
        end
    elseif opciones.dato == 'fuente' and declaracion['references'] then
    	fuente = declaracion.references[1]['snaks']
        for k,v in pairs(fuente) do
            propiedadFuente = k
        end
        return declaracion.references[1]['snaks'][propiedadFuente][1]  -- devuelve la fuente (queda que se itinere la tabla)
    elseif (calificador == '' or not calificador) and (opciones.dato ~= 'fuente') then
        return declaracion.mainsnak -- devuelve el valor principal
    else 
    	return ''    
    end
end 
 
 --[[ =========================================================================
      Función para recopilar las declaraciones      
     ========================================================================= `-- ]] 
 
function p.getDeclaraciones(entityId)
 
 
    -- == Comprobamos que existe un ítem enlazado a la página en Wikidata ==
    if not pcall (SelecionEntidadPorId, entityId ) then 
    	return false
    end
    local entidad  = SelecionEntidadPorId(entityId) 
 
    if not entidad then
        return  '' -- Si la página no está enlazada a un ítem no devuelve nada
    end
 
    -- == Comprobamos que el ítem tiene declaraciones (claims) == 
 
    if not entidad.claims then
        return '' -- Si el ítem no tiene declaraciones no devuelve nada
    end
    -- == Declaración de formato y concatenado limpio ==
 
    return entidad.claims
end
 
 --[[ =========================================================================
      Función para  crear la cadena que devolverá la declaración     
     ========================================================================= `-- ]] 
     
local function valinQualif(claim, qualifs)
	local claimqualifs = claim.qualifiers
	local i,qualif
	local vals, vals1, datavalue, value
	
	if not claimqualifs then
		return nil
	end
	for i, qualif in pairs(qualifs) do
		vals = claimqualifs[qualif]
		if vals then
			vals1 = vals[1]
			if vals1 then
				datavalue=vals1.datavalue
				
				if datavalue then
					value = datavalue.value
					
					if value then
						return value.time
					end
				end
			end
		end
	end
end     
 
function p.getPropiedad(opciones, declaracion)
    local propiedad     = {}
    local tablaOrdenada = {}

    if opciones.propiedad == 'precisión' or opciones.propiedad == 'latitud' or opciones.propiedad == 'longitud'  then
        propiedad = 'P625' -- Si damos el valor latitud, longitud o precisión equivaldrá a dar p625
    else
        propiedad = opciones.propiedad -- En el resto de casos se lee lo dado
    end

    if not propiedad then -- Comprobamos si existe la propiedad dada y en caso contrario se devuelve un error
        return formatoError( 'property-param-not-provided' )
    end
 
    if declaracion then
        tablaOrdenada = declaracion
    elseif not p.getDeclaraciones(opciones.entityId) then
    	return formatoError( 'other entity' )
    elseif p.getDeclaraciones(opciones.entityId)[mw.ustring.upper(propiedad)] then 
    	tablaOrdenada = p.getDeclaraciones(opciones.entityId)[mw.ustring.upper(propiedad)]
    else
    	return ''
    end

	-- Evitar que pete cuando se haga el find en opciones['formatoTexto'] si vale nil
    if not opciones['formatoTexto'] then
    	opciones['formatoTexto'] = ''
    end

    --Dejar en su caso los valores de mayor rango
    if (opciones.rangoMayor == 'sí') then
        tablaOrdenada = filtrarDeclaracionPorRango(tablaOrdenada)
    end

    --Ordenar en su caso por fecha. Ver la función chronosort de :fr:Module:Wikidata/Récup
    if opciones.ordenar == 'por fecha' then
    	require('Módulo:Tablas').ordenar(tablaOrdenada, 
    		function(elemento1,elemento2) 
    			local fecha1 = valinQualif(elemento1, datequalifiers) or '' -- elemento1.qualifiers.P580[1].datavalue.value.time or ''
    			local fecha2 = valinQualif(elemento2, datequalifiers) or '' -- elemento2.qualifiers.P580[1].datavalue.value.time or ''
    			
    		    return fecha1 < fecha2
    	    end
    	 )
    end
    
    if not tablaOrdenada[1] then
    	return
    end

    -- == Si solo se desea que devuelva un valor ==
    -- Pendiente eliminar el parámetro y sustituirlo por un nuevo valor del parámetro lista=no que haría lo mismo que opciones.uno = sí
    if opciones.uno == 'sí' then -- Para que devuelva el valor de índice 1
        tablaOrdenada = {tablaOrdenada[1]}
    elseif opciones.uno == 'último' then -- Para que devuelva la última entrada de la tabla
        tablaOrdenada = {tablaOrdenada[#tablaOrdenada]}
    end

-- == Creamos una tabla con los valores que devolverá ==
 
    local formatoDeclaraciones = {}
    local hayDeclaraciones
    
	for indice, declaracion in pairs(tablaOrdenada) do
   		declaracionFormateada = p.formatoDeclaracion(declaracion, opciones)
   		if declaracionFormateada and declaracionFormateada ~= '' then
           	table.insert(formatoDeclaraciones, declaracionFormateada)
           	hayDeclaraciones = true
       	end    
   	end
   	
    primera = true
    
    if not hayDeclaraciones then
        return
    end

    -- Aplicar el formato a la lista de valores según el tipo de lista de las
    -- opciones
    if opciones['lista'] == 'no ordenada' then
    	-- Añadir en su caso un lápiz
    	if opciones.linkback == 'sí' then
    		return '<ul><li>' .. p.addLinkback(mw.text.listToText( formatoDeclaraciones, '</li><li>','</li><li>' ), opciones.entityId, opciones.propiedad) .. '</li></ul>'
    	else
        	return '<ul><li>' .. mw.text.listToText( formatoDeclaraciones, '</li><li>','</li><li>' ) .. '</li></ul>'
        end
    elseif opciones['lista'] == 'ordenada' then
    	-- Añadir en su caso un lápiz
		if opciones.linkback == 'sí' then
        	return '<ol><li>' .. p.addLinkback(mw.text.listToText( formatoDeclaraciones, '</li><li>','</li><li>' ), opciones.entityId, opciones.propiedad) .. '</li></ol>'            			
		else
        	return '<ol><li>' .. mw.text.listToText( formatoDeclaraciones, '</li><li>','</li><li>' ) .. '</li></ol>'            
        end
    else
     	-- valores separados por coma o por el separador y la
      	-- conjunción de las opciones
       	local separador, conjuncion
        	
        if opciones['conjunción'] == 'null' then
            conjuncion = nil
        else
            conjuncion = opciones['conjunción'] 
        end
    
        if opciones['separador'] == 'null' then
            separador	= nil
        else
            separador = opciones['separador']
        end
        
        if table.getn(formatoDeclaraciones) > 1 then
        	if not conjuncion then
        		conjuncion = 'y'
        	end
        	if marco and conjuncion == 'y' then
        		conjuncion = ' ' .. string.sub(marco:preprocess('{{y-e|{{Desvincular|' .. formatoDeclaraciones[#formatoDeclaraciones] .. '}}}}'), 1, 1) .. ' '
        	elseif conjuncion == 'y' or conjuncion == 'o' then
        		conjuncion = ' ' .. conjuncion .. ' '
        	end
        end
        
        -- Añadir en su caso un lápiz
    	if opciones.linkback == 'sí' then
			return p.addLinkback(mw.text.listToText( formatoDeclaraciones, separador,conjuncion ), opciones.entityId, opciones.propiedad)  		
    	else
        	return mw.text.listToText( formatoDeclaraciones, separador,conjuncion )
        end
    end
end

-- Función que sirve para comprobar si una entidad tiene una propiedad con un
-- valor específico
-- Parámetros:
--   · entidad: tabla de la entidad de Wikidata
--   · propiedad: identificador de Wikidata para la propiedad
--   · valor: valor de la propiedad en Wikidata
function p.tieneValorPropiedad(entidad, propiedad, valor)
	
	if entidad and entidad.claims and entidad.claims[propiedad] then
		
		local mainsnak
		
		for key,value in ipairs(entidad.claims[propiedad]) do
			if value and value.mainsnak then
				mainsnak = value.mainsnak
				if mainsnak.datatype == 'wikibase-item' and 
						mainsnak.snaktype == 'value' and 
						mainsnak.datavalue.value.id == valor then
					return true
				end
			end
		end
	end
	
	return false
end

-- Función que sirve para devolver la leyenda (P2096) de una imagen (P18) en Wikidata en un determinado idioma
-- La función se llama así: {{#invoke:Wikidata |getLeyendaImagen | <PARÁMETRO> | lang=<ISO-639code> |id=<QID>}}
-- Devuelve PARÁMETRO, a menos que sea igual a "FETCH_WIKIDATA", del objeto QID (llamada que consume recursos)
-- Si se omite QID o está vacio, se utiliza el artículo actual (llamada que NO consume recursos)
-- Si se omite lang se utiliza por defecto el idioma local de la wiki, en caso contrario el idioma del código ISO-639
-- ISO-639 está documentado aquí: https://docs.oracle.com/cd/E13214_01/wli/docs92/xref/xqisocodes.html#wp1252447
-- El ranking es: 'preferred' > 'normal' y devuelve la etiqueta de la primera imágen con ranking 'preferred'
-- O la etiqueta de la primera imagen with ranking 'normal' si no hay ningún 'preferred'
-- Ranks: https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua

p.getLeyendaImagen = function(frame)
	-- busca un un elemento concreto en Wikidata (QID), en caso contrario que sea nil
	local id = frame.args.id
	if id and (#id == 0) then
		id = nil
	end

	-- busca el parámetro del idioma que debería contender un código ISO-639 de dos dígitos
	-- si no se declara, toma por defecto el idioma local de la wiki (es)
	local lang = frame.args.lang
	if (not lang) or (#lang < 2) then
		lang = mw.language.getContentLanguage().code
	end

	-- el primer parámetro sin nombrar es el parámetro local, si se declara
	local input_parm = mw.text.trim(frame.args[1] or "")
	if input_parm == "FETCH_WIKIDATA" or input_parm == "" or input_parm == nil then
		local ent = mw.wikibase.getEntityObject(id)
		local imgs
		if ent and ent.claims then
			imgs = ent.claims.P18
		end
		local imglbl
		if imgs then
			-- busca una imagen con ranking 'preferred' 
			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
			-- si no hay ninguna, busca una con ranking 'normal'
			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

-- Función que devuelve el valor de entidad.claims[idPropiedad][ocurrencia].mainsnak.datavalue.value.text
-- con entidad.claims[idPropiedad][ocurrencia].mainsnak.datavalue.value.language = 'es'

-- Útil para obtener valores de propiedades de tipo monolingualtext

function p.getPropiedadEnEspanyol(idEntidad, idPropiedad)
	-- Ver cs:Modul:Wikidata/item	formatEntityWithGender
	
	-- 
	local entidad =  mw.wikibase.getEntityObject(idEntidad)
	
	if not entidad then
		return
	end
	
	local declaracion   = elementoTabla(entidad,'claims', idPropiedad)
	
	if not declaracion then
		return
	end
	
	local valor
	
	for k,v in pairs(declaracion) do
		valor = elementoTabla(v,'mainsnak', 'datavalue', 'value')
		
		if valor.language == 'es' then
			return valor.text
		end
	end
end

-- devuelve el ID de la página en Wikidata (Q...), o nada si la página no está conectada a Wikidata
function p.pageId(frame)
	local entity = mw.wikibase.getEntityObject()
	if not entity then return nil else return entity.id end
end

function p.categorizar(opciones, declaracion)
	-- Evitar que pete cuando se haga el find en opciones['formatoTexto'] si vale nil
    if not opciones['formatoTexto'] then
    	opciones['formatoTexto'] = ''
    end	
	
	local categoriaOpciones=opciones['categoría']	
	
	if not categoriaOpciones then
		return ''
	end

	opciones['enlace'] = 'no'

    -- Crear una tabla con los valores de la propiedad.	
	local valoresDeclaracion = {}
 
    if declaracion then
        valoresDeclaracion = declaracion
    elseif opciones.propiedad then
        local propiedad = {}
        if opciones.propiedad == 'precisión' or opciones.propiedad == 'latitud' or opciones.propiedad == 'longitud'  then
            propiedad = 'P625' -- Si damos el valor latitud, longitud o precisión equivaldrá a dar p625
        else
            propiedad = opciones.propiedad -- En el resto de casos se lee lo dado
        end
        
        if not p.getDeclaraciones(opciones.entityId) then
    	    return formatoError( 'other entity' )
        elseif p.getDeclaraciones(opciones.entityId)[mw.ustring.upper(propiedad)] then 
    	    valoresDeclaracion = p.getDeclaraciones(opciones.entityId)[mw.ustring.upper(propiedad)]
        else
    	    return ''
        end    	
    else
    	return ''
    end 
 
--  Creamos una tabla con cada categoría a partir de cada valor de la declaración
    local categorias    = {}
    local hayCategorias
    
    if type(categoriaOpciones) == 'string' then
        local ModuloPaginas = require('Módulo:Páginas')
      
        for indice, valor in pairs(valoresDeclaracion) do
            valorFormateado = p.formatoDeclaracion(valor, opciones)
    	    if valorFormateado ~= '' then
    		    categoria = ModuloPaginas.existeCategoria(categoriaOpciones:gsub('$1',valorFormateado))
    		
                if categoria then
                    table.insert(categorias, categoria)
                    hayCategorias = true
                end
            end    
        end
    elseif type(categoriaOpciones) == 'table' then
        for indice, valor in pairs(valoresDeclaracion) do
            categoria = categoriaOpciones[elementoTabla(valor, 'mainsnak', 'datavalue', 'value', 'numeric-id')]
            
            if categoria then
                table.insert(categorias, 'Categoría:' .. categoria)
                hayCategorias = true
            end
        end
    end
    
    if hayCategorias then
        return '[[' .. mw.text.listToText( categorias, ']][[',']][[') .. ']]'
    end
    
    return ''
end
 
 --[[ =========================================================================
        Función que comprueba si la página está enlazada a  Wikidata
        en caso de estarlo pasa el valor como a argumento a la función formatSnak()   
     ========================================================================= `-- ]]
 
function p.formatoDeclaracion( declaracion, opciones)
    if not declaracion.type or declaracion.type ~= 'statement' then -- Se comprueba que tiene valor de tipo y que este sea statement (declaración) lo cual pasa siempre que existe la propiedad
        return formatoError( 'unknown-claim-type' ) -- Si no se cumple devuelve error 
    end
    
    -- En el caso de que haya calificador se devuelve a la derecha del valor de la 
    -- declaración entre paréntesis.
    
    local calificativo = opciones.calificativo or opciones.calificador
 
    if calificativo and declaracion.qualifiers then
    	-- De momento los calificativos, normalmente años, no se enlazan
       local opcionesCalificativo = {['formatoTexto']='', enlace='no', ['formatoFecha']='año'} -- Pendiente
       
       local wValorCalificativo
       local wValorCalificativoFormateado
       
       local funcionCalificativo, mensajeError = obtenerFuncion(calificativo, opciones['módulo calificativo'])
       
		if mensajeError then
			return mensajeError
		elseif funcionCalificativo then
       	  -- Utilizar la función recibida sobre todos los calificativos
       	  wValorCalificativo           = declaracion.qualifiers
          wValorCalificativoFormateado = funcionCalificativo(wValorCalificativo, opcionesCalificativo)
       	elseif opciones.formatoCalificador and opciones.formatoCalificador == '()' then
			wValorCalificativo = declaracion.qualifiers[mw.ustring.upper(calificativo)]
	    	if wValorCalificativo and wValorCalificativo[1] then
	    		wValorCalificativoFormateado = p.formatoDato(wValorCalificativo[1], opcionesCalificativo)
	    	end
    	elseif opciones.formatoCalificador and table.getn(mw.text.split(opciones.formatoCalificador, '%.')) == 2 then
    		moduloFormatoCalificador = mw.text.split(opciones.formatoCalificador, '%.')
    		formateado = require ('Módulo:' .. moduloFormatoCalificador[1])
	        if not formateado then
	            return formatoError( 'value-module-not-found' )
	        end
	        fun = formateado[moduloFormatoCalificador[2]]
	        if not fun then
	            return formatoError( 'value-function-not-found' )
	        end
	        
	        if mw.ustring.find(opciones['formatoTexto'],'mayúscula', plain ) and 
		       (primera or (opciones['separador'] and opciones['separador'] ~= 'null') or 
		       	(opciones['lista'] and opciones['lista'] ~= '')) then
		      opciones['mayúscula'] = 'sí'
	              primera = false
		    end
		    
		    if mw.ustring.find(opciones['formatoTexto'],'cursivas', plain ) then
		    	opcionesEntidad.cursivas = 'sí'
		    end
	        
	        wValorCalificativoFormateado = fun( declaracion.qualifiers, opciones, marco)
	        --return require('Módulo:Tablas').tostring(declaracion)
	    else
       	  -- Utilizar el primer valor del calificativo de la propiedad recibida
       	  wValorCalificativo = declaracion.qualifiers[mw.ustring.upper(calificativo)]
       	  
       	  if wValorCalificativo and wValorCalificativo[1] then
            wValorCalificativoFormateado = p.formatoDato(wValorCalificativo[1], opcionesCalificativo)
	      end
	    end
		if opciones.separadorcalificador then separador = opciones.separadorcalificador else separador = ' ' end
    	if wValorCalificativoFormateado then
    		datoFormateado = p.formatoDato(declaracion.mainsnak, opciones)
    		return (datoFormateado and datoFormateado .. '&nbsp;<small>(' .. wValorCalificativoFormateado .. ')</small>') or nil
    	end	    
    end
 
    -- Si no hay calificativo.
    return p.formatoDato(seleccionDeclaracion(declaracion, opciones), opciones, declaracion.qualifiers)
end
 
 --[[ =========================================================================
        Función que comprueba el tipo de dato (snaktype)
        si es value pasa el valor como argumento a la función formatoValorDato()    
     ========================================================================= `-- ]] 
 
function p.formatoDato( dato, opciones, calificativos)
    
    if not dato or dato == '' then
        return ''
    end
    if dato.snaktype == 'somevalue' then
    	-- Fecha más temprana
    	if calificativos then
    		if calificativos['P1319'] and calificativos['P1319'][1] and
    	       calificativos['P1319'][1].datavalue and
    	       calificativos['P1319'][1].datavalue.type=='time' then
    	       	
                local opcionesFecha={['formatoFecha']=opciones['formatoFecha'],enlace=opciones.enlace}
        
                return 'post. ' .. require('Módulo:Wikidata/Fecha').FormateaFechaHora(calificativos['P1319'][1].datavalue.value, opcionesFecha)
            end
    	end
    	
    	-- Si no tiene un calificativo válido
        return avisos['somevalue'] -- Valor desconocido
    elseif dato.snaktype == 'novalue' then
        return avisos['novalue'] -- Sin valor
    elseif dato.snaktype == 'value' then
        return formatoValorDato( dato.datavalue, opciones, calificativos) -- Si tiene el tipo de dato se pasa el valor a la función formatDatavalue()
    else
        return formatoError( 'unknown-snak-type' ) -- Tipo de dato desconocido
    end
end
 
 --[[ =========================================================================
       Función que establece el tipo de formato en función del tipo de valor 
       (valorDato.type) y en caso de solicitarse un formato complemetario asocia
       el módulo donde se establece el formato y la función de este que lo establece    
     ========================================================================= `-- ]] 
 
function formatoValorDato( valorDato, opciones, calificativos)
	local funcion, mensajeError = obtenerFuncion(opciones['valor-función'] or opciones['value-function'], opciones['valor-módulo'])
	
	if mensajeError then
		return mensajeError
	elseif funcion then
		local opcionesEntidad = {}
		
		for k, v in pairs(opciones) do
			opcionesEntidad[k] = v
		end
	    
	    if mw.ustring.find(opciones['formatoTexto'],'mayúscula', plain ) and 
	       (primera or (opciones['separador'] and opciones['separador'] ~= 'null') or 
	       	(opciones['lista'] and opciones['lista'] ~= '')) then
	      opcionesEntidad['mayúscula'] = 'sí'
              primera = false
	    end	
	    
	    if mw.ustring.find(opciones['formatoTexto'],'cursivas', plain ) then
	    	opcionesEntidad.cursivas = 'sí'
	    end
	    
		return funcion(valorDato.value, opcionesEntidad, marco, calificativos)		
	end
 
    -- == Formatos por defecto en función del tipo de valor ==
 
--          * Para tipo coordenadas cuando se da como valor de propiedad: latitud, longitud o precisión
 
    if opciones.propiedad == 'latitud' then 
        return valorDato.value['latitude']
    elseif opciones.propiedad == 'longitud' then
        return valorDato.value['longitude']
    elseif opciones.propiedad == 'precisión' then
        return valorDato.value['precision']
 
--           * Con el resto de valores en propiedad
 
    elseif valorDato.type == 'wikibase-entityid' then    -- Tipo: Número de entidad que puede ser un ítem o propiedad
	    local opcionesEntidad = {}
	    if mw.ustring.find(opciones['formatoTexto'],'mayúscula', plain ) and 
	       (primera or (opciones['separador'] and opciones['separador'] ~= 'null') or 
	       	(opciones['lista'] and opciones['lista'] ~= '')) then
	      opcionesEntidad['mayúscula'] = 'sí'
              primera = false
	    end
	    opcionesEntidad.enlace         = opciones.enlace
	    opcionesEntidad.etiqueta       = opciones.etiqueta
	    opcionesEntidad['debeExistir'] = opciones['debeExistir']
	    
	    if mw.ustring.find(opciones['formatoTexto'],'cursivas', plain ) then
	    	opcionesEntidad.cursivas = 'sí'
	    end
        return p.formatoIdEntidad( SelecionEntidadPorValor( valorDato.value ), opcionesEntidad)
    elseif valorDato.type == 'string' then               -- Tipo: Cadena de texto (string)
        return valorDato.value 
    elseif valorDato.type == 'url' then     --Tipo URL (dirección web)
	    return value.url
    elseif valorDato.type == 'time' then                 -- Tipo: Fecha/hora
        local opcionesFecha={['formatoFecha']=opciones['formatoFecha'],enlace=opciones.enlace}
       
        if mw.ustring.find(opciones['formatoTexto'] or '','mayúscula', plain ) and primera then
	        opcionesFecha['mayúscula']='sí'
        end
        
        return require('Módulo:Wikidata/Fecha').FormateaFechaHora(valorDato.value, opcionesFecha, calificativos)
    elseif valorDato.type == 'monolingualtext' then       -- Tipo: monoligüe
    	if valorDato.value then
            return valorDato.value.text
        else 
            return ''
        end
    elseif valorDato.type ==  'quantity' then            -- Tipo: Cantidad 
    	return require('Módulo:Wikidata/Formatos').formatoUnidad(valorDato, opciones)
    elseif  valorDato.value['latitude']  and valorDato.value['longitude'] then -- Tipo: Coordenadas
    	local globo = require('Módulo:Wikidata/Globos')[valorDato.value.globe]
 
--Concatenamos los valores de latitud y longitud dentro de la plantilla Coord
 
        if globo ~= 'earth' then
            return  marco:preprocess('{{coord|' .. valorDato.value['latitude'] .. '|' .. 
                   valorDato.value['longitude'] .. '|globe:' .. globo .. '_type:' .. opciones.tipo .. '|display=' .. 
                   opciones.display ..'|formato=' .. opciones.formato..'}}')
        else
        	return  marco:preprocess('{{coord|' .. valorDato.value['latitude'] .. '|' .. 
                   valorDato.value['longitude'] .. '|type:' .. opciones.tipo .. '|display=' .. 
                   opciones.display ..'|formato=' .. opciones.formato..'}}')
        end
 
    else
        return formatoError( 'unknown-datavalue-type' ) -- Si no es de ninguno de estos tipos devolverá error valor desconocido
    end
end
 
  --[[ =========================================================================
          Damos formato a los enlaces internos    
       ========================================================================= `-- ]]

-- Opciones:
--     - enlace:		Valores posibles 'sí' o 'no'
--     - mayúscula:		Valores posibles 'sí' o 'no'
--     - cursivas:		Valores posibles 'sí' o 'no'

function p.formatoIdEntidad(idEntidad, opciones)
    local enlace   = mw.wikibase.sitelink(idEntidad)
    local etiqueta = mw.wikibase.label(idEntidad)
	return require('Módulo:Wikidata/Formatos').enlazar(enlace, etiqueta, idEntidad, opciones)
end
 
 --[[ =========================================================================
        Función principal     
     ========================================================================= `-- ]]
 
function p.Wikidata( frame )
    marco = frame
    local args = frame.args
    
    if args.valor == 'no' then
    	return
    end

    local parentArgs = frame:getParent().args
    
    -- Copiar los argumentos
    local argumentos = {}
    
    for k, v in pairs(args) do
    	argumentos[k] = v
    end
    
    for k, v in pairs(parentArgs) do
    	if not argumentos[k] then
    		argumentos[k] = v
    	end
    end
    
    --if true then return require('Módulo:Tablas').tostring(argumentos) end
    
    -- No generar el valor de Wikidata si se ha facilitado un valor local y
    -- el valor local es prioritario.
    local valorWikidata;
    if (args.prioridad ~= 'sí' or (args.importar and args.importar == 'no')) and args.valor and args.valor ~= '' then
    	valorWikidata = '';
    else
    	valorWikidata = p.getPropiedad(argumentos, nil);
    end
    
 	local categorias = '';
 	local namespace = frame:preprocess('{{NAMESPACENUMBER}}');
 	
 	if (namespace == '0' and (not args.categorias or args.categorias ~= 'no') and 
 			args.propiedad and string.upper(args.propiedad) ~= 'P18' -- P18: imagen de Commons
 			and string.upper(args.propiedad) ~= 'P41' -- P41: imagen de la bandera
 			and string.upper(args.propiedad) ~= 'P94' -- P94: imagen del escudo de armas
 			and string.upper(args.propiedad) ~= 'P109' -- P109: firma de persona
 			and string.upper(args.propiedad) ~= 'P154') then -- P154: logotipo
	 	if valorWikidata ~= '' and args.valor and args.valor ~= '' then
	 		categorias = '[[Categoría:Wikipedia:Artículos con datos locales]]'
	 	elseif valorWikidata and valorWikidata == '' and args.valor and args.valor ~= '' and 
	 		(not args.calificador or args.calificador == '') and 
	 		(not args.dato or args.dato == '' or args.dato ~= 'fuente')then
	 		categorias = '[[Categoría:Wikipedia:Artículos con datos por trasladar a Wikidata]]'
	 	end
	end
 
    if args.prioridad == 'sí' and valorWikidata  ~= '' then -- Si se da el valor sí a prioridad tendrá preferencia el valor de Wikidata 
    	if args.importar and args.importar == 'no' and args.valor and args.valor ~= '' then 
    		return args.valor .. categorias
    	elseif valorWikidata then
        	return valorWikidata .. categorias -- valor que sustituye al valor de Wikidata parámetro 2
        else
        	return categorias
        end
    elseif args.valor and args.valor ~= '' then 
         return args.valor .. categorias
    elseif args.importar and args.importar == 'no' then 
         return ''
    elseif valorWikidata then -- Si el valor es nil salta una excepcion al concatenar
        return valorWikidata .. categorias
    else
    	return ''
  end  
end

function obtenerFuncion(funcion, nombreModulo)
	if not funcion then
		return
	elseif type(funcion) == 'function' then -- Uso desde LUA
		return funcion
	elseif funcion == '' or not nombreModulo or nombreModulo == '' then
		return
	else -- Uso desde una plantilla
		local modulo
		
		if not nombreModulo or nombreModulo == '' or nombreModulo == 'Wikidata/Formatos' then
			modulo = require(modulosTipos[funcion] or 'Módulo:Wikidata/Formatos')
		else
			modulo = require ('Módulo:' .. nombreModulo)
		end
		
       	if not modulo then
           	return nil, formatoError( 'value-module-not-found' )
        elseif not modulo[funcion] then
           	return nil, formatoError( 'value-function-not-found' )
        else
           	return modulo[funcion]
       	end
	end
end

function p.addLinkback(valorPropiedad, idEntidad, idPropiedad)
	local lidEntidad
	
	if valorPropiedad and idPropiedad then
		lidEntidad= (idEntidad ~='' and idEntidad) or mw.wikibase.getEntityIdForCurrentPage()
	end

	if lidEntidad then
		return valorPropiedad .. '<span class=\"wikidata-link noprint\"> [[Archivo:Blue_pencil.svg|Ver y modificar los datos en Wikidata|10px|baseline|alt=Ver y modificar los datos en Wikidata|enlace=https://www.wikidata.org/wiki/' .. lidEntidad .. '?uselang=es#' .. idPropiedad ..
    	 ']]</span>'
    else
    	return valorPropiedad
    end
end
 
return p