Ir al contenido

Módulo:Biocitas

De Wikisource, la biblioteca libre.
Documentación del módulo


Uso

Utilizado por la plantilla {{Biocitas}}.
Esta documentación está transcluida desde Módulo:Biocitas/doc.
Los editores pueden experimentar en la zona de pruebas
Por favor, añade las categorías a la subpágina de documentación.
(subpáginas - enlaces)

local p = {}
local Wikidata = require('Módulo:Wikidata')
local Enlaces = require('Módulo:Enlaces')
local Str = require('Módulo:String')
local Entidad  = mw.wikibase.getEntityObject() or ''     -- Tabla con los datos en Wikidata de la persona.
--parámetros reconocidos. 1 = vigente, 0 = obsoleto
local params ={['texto']=1,['obras']=1,['documentos']=1,['foto']=1,['wikipedia']=0,['wikiquote']=0,['wikinoticias']=0,['commons']=0,['wikispecies']=0,['wikidata']=1,['añomuerte']=1,['siglomuerte']=1,['añonacimiento']=1,['siglonacimiento']=1,['ordenar']=1,['inicial']=1,['añosmuerte']=0,['vivo']=1,['país']=1}
local categorias = ''
local withoutEpoque = true

function errorMessage(text)
	-- Función que entrega un mensaje de error formateado como tal
	local html = mw.html.create('div')
	html:addClass('error')
		:wikitext(text)
	categorias=categorias..'[[Categoría:Wikisource:Artículos con errores en la plantilla Biocitas]]'
	return tostring(html)
end

-- Función para eliminar contenido entre paréntesis
function remove_parentheses(text)
    -- Sustituye todo lo que está entre paréntesis (incluyendo los paréntesis) por una cadena vacía
    if text==nil then return "" end
    local texto = text
    texto = text:gsub("%b()", "")
    if texto ~= nil then 
    	return texto
    else
    	return text
    end
end

function computeCenturyFromYear(year)
	-- Dado un año entrega el siglo
	if year >= 0 then
		return math.ceil(year / 100)
	else
		return -math.ceil(-year / 100)
	end
end
function getTextForCentury(century)
	-- Dado un siglo en número, entrega un texto preformateado con 
	-- números romanos y un indicador de antes de Cristo.
	local romanNumbers1 = {'', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X'}
	local romanNumbers2 = {'', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'}

	local text = romanNumbers2[math.floor(math.abs(century) / 10) + 1] .. romanNumbers1[math.floor(math.abs(century) % 10) + 1]

	if century > 0 then
		return 'Siglo '..text
	else
		return 'Siglo '.. text .. ' a. C.'
	end
end
function getTextForYear(year)
	-- transforma un año de formato -45 a 45 a. C.
	local text = math.abs(year)
	if year < 0 then
		text = text .. ' a. C.'
	end
	return text
end
function getDateFromArgs(args, field)
	-- Obtiene datos (fecha de nacimiento, fallecimiento) de parámetros determinados en la plantilla {{Biocitas}}
	-- con el formato AñoNacimiento, AñoMuerte, SigloNacimiento o SigloMuerte. TextoNacimiento o InciertoNacimiento también funciona
	local struct = {
		year = nil,
		century = nil,
		text = nil,
		precision = 0
	}

	--extract year or century
	local date = args['año' .. field]
	if date == nil then
		date = args[field]
	end
	if tonumber(date) ~= nil then
		struct.year = tonumber(date)
		if struct.year == 0 then
			struct.text = errorMessage("¡El calendario gregoriano no tiene año 0!")
			return struct
		end
		struct.century = computeCenturyFromYear(struct.year)
		struct.precision = 9
	elseif args['siglo' .. field] ~= nil then
		struct.century = tonumber(args['siglo' .. field])
		struct.precision = 7
	end

	--build text
	if struct.year ~= nil then
		struct.text = getTextForYear(struct.year)
	elseif struct.century ~= nil then
		struct.text = getTextForCentury(struct.century, true)
	else
		struct.text = date
	end
	if args['texto' .. field] ~= nil then
		struct.precision = 0 --we don't know anything
		struct.text = args['texto' .. field] .. ' ' .. struct.text
	end
	if args['incierto' .. field] ~= nil and struct.text ~= nil then
		struct.precision = 0 --we don't know anything
		struct.text = args['incierto' .. field] .. ' ' .. struct.text
	end

	return struct
end


function getDateFromTimeStatements(statements, field,html)
	-- Función que obtiene las fechas desde Wikidata (copiada literal sin adaptaciones desde la frWS)
	if #statements == 0 then
		return {
			precision = 0
		}
	end

	local time = nil
	for _, statement in pairs(statements) do
		local newTime = getDateFromTimeStatement(statement, field)
		if time == nil then
			time = newTime
		elseif time.year ~= newTime.year then --si hay años contradictorios
			time.precision = 8
			--html:wikitext(errorMessage('Hay varios años de ' .. field .. ' posibles en Wikidata. Una manera de resolver este error es fijar una de las dos fechas como "preferida".'))
			--return {
				--text = errorMessage('Hay varios años de ' .. field .. ' posibles en Wikidata. Una manera de resolver este error es fijar una de las dos fechas como "preferida".'),
			--	precision = 0
			--}
		end
	end

	if time == nil then
		return {
			precision = 0
		}
	end

	return time
end

function parseWbTime(value)
	local _,_, year = string.find(value.time, '([%+%-]%d%d%d+)%-')
	year = tonumber(year)
	
	return {
		year = year,
		century = computeCenturyFromYear(year),
		text = nil,
		precision = value.precision
	}
end

function getDateFromTimeStatement(statement, field)
	local struct = {
		year = nil,
		century = nil,
		text = nil,
		precision = 0
	}
	local prefix = ''
	local snak = statement.mainsnak
	if snak.snaktype == 'novalue' then
		return struct
	end
		if statement.qualifiers ~= nil then
			if statement.qualifiers.P1480 ~= nil then
				for _,qualifier in pairs(statement.qualifiers.P1480) do
					if qualifier.datavalue.value['numeric-id'] == 5727902 then
						struct = parseWbTime(snak.datavalue.value)
						prefix = 'circa '
						struct.precision = 8 --TODO: hacky
					end
				end
			end
			if statement.qualifiers.P1319 ~= nil then
				for _,qualifier in pairs(statement.qualifiers.P1319) do
					struct = parseWbTime(qualifier.datavalue.value)
					prefix = 'después de'
					struct.precision = 8 --TODO: hacky
				end
			elseif statement.qualifiers.P1326 ~= nil then
				for _,qualifier in pairs(statement.qualifiers.P1326) do

					struct = parseWbTime(qualifier.datavalue.value)
					prefix = 'antes de '
					struct.precision = 8 --TODO: hacky
				end
			elseif statement.qualifiers.P1317 ~= nil then
				for _,qualifier in pairs(statement.qualifiers.P1317) do
					struct = parseWbTime(qualifier.datavalue.value)
					prefix = 'floruit '
					struct.precision = 8 --TODO: hacky
				end
			else
				struct = parseWbTime(snak.datavalue.value)
			end
		elseif snak.snaktype == 'value' then
			struct = parseWbTime(snak.datavalue.value)
		else
			return struct
		end

	--Create text
	if struct.precision >= 9 then
		struct.text = prefix .. getTextForYear(struct.year)
	elseif struct.precision == 8 then
		struct.text = prefix .. getTextForYear(struct.year)
	elseif struct.precision == 7 then
		struct.text = prefix .. getTextForCentury(struct.century, true)
	else
		struct.text = errorMessage('La fecha de ' .. field .. ' tiene muy poca precisión en Wikidata')
	end
	
	return struct
end
function resolverFecha(arg, wd)
	local fecha = arg
	if arg.text == nil and wd ~= nil then
		fecha = wd
	elseif arg.text ~= nil then
		categorias = categorias..'[[Categoría:Wikisource:Artículos con datos locales]]'
		if wd and wd.text == nil then
			categorias = categorias..'[[Categoría:Wikisource:Artículos con datos por trasladar a Wikidata]]'
		end
	end
	return fecha
end
function categoriaEpica(fecha, tol)
	local categoria = ''
	if fecha.century ~= nil and (fecha.year == nil or fecha.year <= fecha.century * 100 + tol or fecha.precision <=8 ) then
		if 14 <= fecha.century then
			categoria='[[Categoría:Autores del ' .. getTextForCentury(fecha.century, false) .. ']]'
		end
		if 6 <= fecha.century and fecha.century <= 14 then
			categoria=categoria..'[[Categoría:Autores de la Edad Media]]'
		end
		if fecha.century < 6 then
			categoria='[[Categoría:Autores de la Antigüedad]]'
		end
		withoutEpoque = false
	end
	return categoria
end
function p.biocitas( frame ) -- función principal para llamar desde {{biocitas}}
	if mw.title.getCurrentTitle().namespace ~= 106 then
		return errorMessage('La plantilla Biocitas se utiliza solo en espacios de nombres Autor, por ejemplo Autor:Miguel de Cervantes')
	end
    local argus = {}
	for k,v in pairs(frame:getParent().args) do -- crea una tabla con los parámetros incluídos en la plantilla, y elimina parámetros vacíos
		if v ~= '' and type(k) ~= 'number' then
			argus[mw.ustring.lower(k)] = v -- todos los parámetros en minúsculas por defecto: 
		end
	end
	
	
    local html = mw.html.create() -- cuerpo principal de la plantilla
    
    local tabla = html:tag('table'):addClass('divgrande')
    
    local divgrande = tabla:tag('tr')--:addClass('divgrande')  -- div principal que contiene al resto 
    
    -- WIKIDATA! --
    if Entidad == '' and argus['wikidata'] then
    	Entidad = mw.wikibase.getEntityObject(argus['wikidata'])
    end
    
	if Entidad == '' then
		categorias=categorias..'[[Categoría:Wikisource:Artículos de autores no conectados a Wikidata]]'
		html:wikitext(errorMessage('<small>Error: Los artículos de autores deben estar enlazados en Wikidata. '..
			'Agrega un enlace a otro proyecto usando el link en la columna izquierda, '..
			'o '..frame:preprocess('[https://www.wikidata.org/wiki/Special:NewItem?site=eswikisource&page={{FULLPAGENAMEE}} crea un nuevo elemento en Wikidata]')..'</small>'))
	end
	---- variables para manejar fechas de muerte y nacimiento	
	local nacimientoArg = getDateFromArgs(argus, 'nacimiento')
	local muerteArg = getDateFromArgs(argus, 'muerte')
	local floruitArg = getDateFromArgs(argus, 'floruit')

	local nacimientoWikidata = nil
	local muerteWikidata = nil
	local floruitWikidata = nil
	
	if Entidad ~= nil and Entidad ~= '' then --si existe la entidad en Wikidata, obtiene las fechas desde ahí.
		nacimientoWikidata = getDateFromTimeStatements(Entidad:getBestStatements('P569'), 'nacimiento')
		muerteWikidata = getDateFromTimeStatements(Entidad:getBestStatements('P570'), 'muerte')
		floruitWikidata = getDateFromTimeStatements(Entidad:getBestStatements('P1317'), 'floruit')
		floruitWikidata.precision = 8
	end
	
	nacimiento = resolverFecha(nacimientoArg, nacimientoWikidata)
	muerte = resolverFecha(muerteArg, muerteWikidata)
	floruit = resolverFecha(floruitArg, floruitWikidata)
	
	if nacimiento.precision >= 9 and nacimiento.year > 1300 then
		categorias=categorias..'[[Categoría:N' .. nacimiento.year .. ']]'
	
	end
	if muerte.precision >= 9 and muerte.year > 1300 then
		categorias=categorias..'[[Categoría:F' .. muerte.year .. ']]'
	end

	categorias=categorias..categoriaEpica(nacimiento, -20)
	categorias=categorias..categoriaEpica(muerte, 5)
	categorias=categorias..categoriaEpica(floruit, 0)
	
	if withoutEpoque then
		categorias=categorias..'[[Categoría:Época desconocida]]'
	end
	--año de la muerte, para las plantillas
	local anomuerte 
	local anosmuerte = argus['añosmuerte']
	
	if muerte.year then
		anomuerte = getTextForYear(muerte.year)
	elseif muerte.century then
		anomuerte = muerte.century*100
	elseif argus['añomuerte'] ~= '' and argus['añomuerte'] ~= nil  then
		anomuerte = argus['añomuerte']
	elseif argus['siglomuerte'] ~= '' and argus['siglomuerte'] ~= nil then
		anomuerte = (tonumber(argus['siglomuerte']))*100
	elseif floruit.year then
		--muerte presunta 70 años después de florecer
		anomuerte = getTextForYear(floruit.year + 70) 
	elseif floruit.century then
		--si sólo se conoce el siglo, murió a mediados de siglo
		anomuerte = floruit.century*100 - 50
	end
	--artículos sin información de año de muerte
	if (argus['vivo']==nil or argus['vivo']=='') and (anomuerte == '' or anomuerte ==nil) and (muerte.century == '' or muerte.century ==nil) then
		categorias = categorias..'[[Categoría:Wikisource:Artículos de autores sin información de año de muerte]]'
	end
	
	-- texto fechas
	local textofechas = ''
	if nacimiento.text or muerte.text then
		textofechas = (nacimiento.text or '')..' - '..(muerte.text or '')
	elseif floruit.text then
		textofechas = 'fl. '..floruit.text	
	end
	
	-- esqueleto y CSS de los divs internos 
	local foto = divgrande:tag('td'):addClass('bc-foto')
	local medio = divgrande:tag('td'):addClass('bc-medio')
	--local divtitulo = medio:tag('div'):addClass('bc-titulo')
	local enlaces = divgrande:tag('td'):addClass('bc-enlaces')
	local derechos = html:tag('div'):addClass('bc-derechos')
	
	--variables locales
	local sep = "<span style='display:inline-block; width:.5em;'>&nbsp;</span>"
	local nombre = frame:preprocess("{{PAGENAME}}")

	--Contenido de los divs secundarios
	--divtitulo:wikitext("Ficha de ".. nombre:gsub(' %(.*%)','')) --en el título nombres sin paréntesis
	
	-- Lista de enlaces
		if (not argus['wikidata'] or argus['wikidata'] == '') and Entidad~=nil then
			argus['wikidata']=Entidad.id --enlazar a elemento wikidata
		end

	---- Enlaces uno por uno ---
	listaenlaces = Enlaces.all(argus)
	if argus['obras'] ~= 'none' then  --Obras (aparece siempre por defecto a menos que se defina como none)
		listaenlaces["obras"] = { ['name']   = 'Categoría de obras',
					['image']  = 'Wikisource-logo.svg',
					['text']   = 'Obras',
					['prefix'] = ':Categoría:Obras de ',
					['title']  = '',
		}
		
		if argus['obras'] ~= '' and argus['obras'] ~= nil  then
			listaenlaces["obras"]["title"] = argus['obras']
		else
			listaenlaces["obras"]["title"] = nombre
		end
	end
	
	-- crea elementos para el resto de los enlaces
	listaenlaces["documentos"] = { ['name']   = 'Categoría de documentos',
					['image']  = 'Wikisource-logo.svg',
					['text']   = 'Documentos	',
					['prefix'] = ':Categoría:Documentos de ',
					['title']  = argus['documentos'] or '',
		}
	-- texto propio de biocitas
	listaenlaces["eswiki"]["text"] = "Biografía"
	listaenlaces["eswikiquote"]["text"] = "Citas"
	listaenlaces["eswikinews"]["text"] = "Noticias"
	listaenlaces["commonswiki"]["text"] = "Multimedia"
	listaenlaces["specieswiki"]["text"] = "Especies descritas"
	listaenlaces["wikidata"]["text"] = "Metadatos"
	
	orden = {'obras', 'documentos', 'eswiki', 'eswikiquote', 'eswikinews', 'commonswiki', 'specieswiki', 'wikidata'}
	
	textoenlaces = Enlaces.formattedbiocitas(listaenlaces, orden)

	enlaces:wikitext(textoenlaces)
	
	--llave automágica
	local apellidos = mw.text.trim((propiedad('p734',{['uno']='sí'}) or '')..' '..(propiedad('p1950',{['uno']='sí'}) ))
	local nombres = (propiedad('P735',{['conjunción']=' '}) or '')
    if apellidos == '' or apellidos == nil then	--p.ej. Alonso de Villegas, Autor:Jerónimo Bécker, etc.
    	apellidos = nombres	--Mejor que "Autores-," cuando no existe apellido
    end
    if string.sub(apellidos,1,3) == 'de ' then
    	apellidos = string.sub(apellidos,4)
    end
	local llave=(apellidos..', '..nombres) ~= ', ' and (apellidos..', '..nombres)
	mw.log(llave)

	-- Ordenar e Iniciales--
	if argus['ordenar']==nil and llave then
		argus['ordenar'] = llave
	end
	if argus['ordenar'] ~= nil then
		if argus['inicial'] == nil then
			argus['inicial'] = Str.CaracterParaOrdenar(argus['ordenar']) --Si no está especificada la inicial, la saca de la primera letra de la llave de ordenado.
		end
		html:wikitext(frame:preprocess('{{DEFAULTSORT:' .. argus['ordenar'] .. '}}'))
		categorias=categorias..'[[Categoría:Autores-'..argus['inicial']..']]'  --categoría Autores-X
	else
		html:wikitext(errorMessage("El parámetro «|Ordenar=» es obligatorio"))
		categorias=categorias..'[[Categoría:Wikisource:Artículos de autores sin llave de ordenamiento]]'  --categoría Autores-X
	end
	if argus['ordenar'] ~= nil then
			veasetambien = enlaces:tag('div')
			veasetambien
				:addClass('bc-enlace')
				:wikitext("◄"..sep.."[[:Categoría:Autores-"..argus['inicial'].."|Autores-"..argus['inicial'].."]]") --enlace a Autores-X
	end
		
	--- Índice de autores ---
	--indice = enlaces:tag('div')
	--indice
	--	:addClass('bc-enlace')
	--	:wikitext("[[:Categoría:Autores|Índice de autores]]")



-- Texto de al medio
	if argus['texto'] ~= '' and argus['texto'] ~= nil  then
		medio:wikitext(argus['texto'])
	else
		local description = remove_parentheses(mw.wikibase.getDescription())
		medio:wikitext("'''"..nombre.."'''<br/>("..textofechas..')<br/>'..(description or ''))
		categorias = categorias..'[[Categoría:Wikisource:Autores con texto automático]]'
	end
	-- Firma  ( aun no se puede conectar con otras Q de wikidata :(  )
	--if argus['wikidata']== '' then 
		if propiedad ('p109') ~= '' then
			medio:wikitext("<br><br> [[File:"..propiedad('p109',{['uno']='sí'}).."|frameless|99999x50px|center|Firma]]")
		end
	--else
--		if propiedad ('p109',{['entidad']=argus['wikidata']}) ~= '' then
--			medio:wikitext("<br><br> [[File:"..propiedad('p109',{['uno']='sí',['entidad']=argus['wikidata']}).."|frameless|center|Firma]]")
--		end
--	end

-- Retrato autor --
        local sexo = propiedad('p21')  
        
		if argus['foto'] ~= '' and argus['foto'] ~= nil  then
		foto:wikitext("[[File:"..argus['foto'].."|frameless|99999x150px|center]]")
		
		elseif propiedad('p18') ~= '' then
			foto:wikitext("[[File:"..propiedad('p18',{['uno']='sí'}).."|frameless|99999x150px|"..propiedad('p18',{['calificador']='P2096',['idioma']='es'}).."|center]]")
		else
			local faltaFoto
			local fotos = {'Silver - replace this image male.svg', 'Silver - replace this image female.svg','Falta foto.jpg'}
			if sexo == "masculino" then
				faltaFoto = fotos[1]
			elseif sexo == "femenino" then
				faltaFoto = fotos[2]
			else
				faltaFoto = fotos[3]
			end
			foto:wikitext("[[File:"..faltaFoto.."|frameless|99999x150px|center]]")
		end


	
	
	--Plantilla de derechos
	if anomuerte ~='' and anomuerte ~= nil then
		derechos
			:wikitext(frame:preprocess("{{DP-Autor|"..anomuerte.."}}"))
	elseif anosmuerte ~='' and anosmuerte ~= nil then
		derechos
			:wikitext(frame:preprocess("{{DP-AUTOR-"..anosmuerte.."}}"))
	else
		derechos
			:wikitext(frame:preprocess("{{DP-AUTOR-none}}"))
	end

	-- categorías--
	categorias=categorias.."[[Categoría:Autores]]"
	if argus['vivo'] and mw.ustring.lower(argus['vivo']) ~= 'no' then
		categorias=categorias.."[[Categoría:Personas vivas]]"
	end
	-- categorizar por país: primera prioridad la tienen
	if argus['país'] ~= nil and argus['país'] ~='' then
		categorias=categorias.."[[Categoría:Autores "..frame:preprocess("{{gentilicio|"..argus['país'].."|mp}}").."]]"
	else
		argus['país'] = propiedad('P27',{['conjunción']=',',['enlace']='no'})
		if argus['país'] ~= nil and argus['país'] ~='' then
		for _,v in ipairs(mw.text.split(argus['país'], '[,]')) do  --el módulo Wikidata entrega la información en palabras separadas por coma y por "y". Esto convierte esa información en una tabla y itera en sus ítems (para autores con más de una nacionalidad)
			--categoría Autores por país: usa plantilla {{gentilicio}}
			categorias=categorias.."[[Categoría:Autores "..frame:preprocess("{{gentilicio|"..v.."|mp}}").."]]"
		end
		else
			categorias=categorias.."[[Categoría:Wikisource:Artículos de autores sin país]]"
		end
	end
	
	for k,v in pairs(argus) do
		if params[k] then
			if params[k] == 0 then
				categorias = categorias..'[[Categoría:Wikisource:Artículos que usan parámetros obsoletos en la plantilla Biocitas]]' --añade categoría de seguimiento a parámetros obsoletos (declarados arriba)
			end
		else
			html:wikitext(errorMessage('Error: parámetro '..k..' no reconocido'))
			categorias=categorias..'[[Categoría:Wikisource:Artículos que usan parámetros no reconocidos en la plantilla Biocitas]]'
		end
	end
	
		
	if mw.title.getCurrentTitle().namespace ~= 106 then --solo categorías en el espacio principal
		categorias = ''	
	end
	html:wikitext(categorias)
    return tostring(html) .. '\n__NOTOC__'
end 

-- Función que devuelve la lista de los valores de una propiedad en Wikidata formateados
function propiedad(idPropiedad,opciones)
	
    if Entidad and Entidad.claims   then --and Entidad.claims[idPropiedad] then
    	if not opciones then
    		opciones = {}
    	end
    	idPropiedad = string.upper(idPropiedad)
    	opciones['propiedad'] = idPropiedad
        valorPropiedad = Wikidata.getPropiedad(opciones,Entidad.claims[idPropiedad])
        if not valorPropiedad or valorPropiedad == '' then
        	return ''
        end
        return valorPropiedad
    else return ''
    end
end


return p