Mòdul:Wikidata

De Viquipèdia
Jump to navigation Jump to search
Icona de documentació de mòdul Documentació del mòdul [ mostra ] [ modifica el codi ] [ mostra l'historial ] [ refresca ]

Mòdul Wikidata (codi · ús · discussió · tests · casos prova | subpàgines · enllaços)

A continuació es mostra la documentació transclosa de la subpàgina /ús. [salta a la caixa de codi]


Wikidata Stamp Rec Light.svg

Aquest mòdul extrau dades formatades de Wikidata.

Funcions

Funció bàsica:

  • claim: Retorna amb un format determinat el valor (o els valors) d'una declaració o del qualificador d'una declaració. Per defecte està referit a l'item (Qnnnn) de l'article actiu.

Altres funcions:

  • getLabel: retorna una etiqueta en la llengua especificada, o la llengua per defecte.
  • getParentValues: retorna etiquetes i valors superiors d'una propietat de forma recursiva.
  • linkWithParentLabel: crea un enllaç amb l'etiqueta d'una propietat superior. Per exemple per enllaçar Autor taxonòmic (P405) amb l'etiqueta Abreviatura d'autor en zoologia (P835) definida en el corresponent ítem superior.
  • getTAValue: retorna els valors de TA98 (Terminologia Anatomica primera edició 1998) de la propietat P1323. No pren paràmetres i retorna una llista amb cada valor enllaçat a la font externa.
  • ViewSomething: retorna qualsevol cosa de les dades estructurades, incloent etiquetes, descripcions, referències i enllaços interwiki.
  • years_old: retorna l'edat d'una persona: diferència entre Data de naixement (p569) i Data de defunció (p570), quan estan les dues propietats; o diferència entre Data de naixement (p569) i la data d'avui, si no hi ha P570. Retorna una (nn) o dues xifres (nn/mm) segons la precisió de les dates. No retorna res quan alguna de les dues està expressada en segles.

Funció claim

Sintaxi completa:

{{#invoke:Wikidata|claim|property= |qualifier= |value= |list= |tablesort= |formatting= |separator= |conjunction= |item= |lang= |editicon= |showerrors= |default= }}

Sintaxi addicional pel format de taula:

{{#invoke:Wikidata|claim|property= |qualifier= |qualifier2= |...|qualifierx= |formatting=table |tablesort= |tablesortalt= |sorting= |rowformat= |rowsubformat1= |...|rowsubformatx= |colformat0= |...|colformatx= |case0= |...|casex= |separator= |conjunction= |item= |lang= |editicon= |showerrors= |default= }}

Paràmetres:

  • property= (obligatori) Propietat de la declaració, amb format "P" seguit d'un número. Es pot veure enllaçat en l'element de Wikidata i una llista completa a Llista de propietats. Accepta també una p minúscula, però no és recomanat. Igualment accepta l'etiqueta de la propietat, per exemple property=estat equival a property=P17 per la propietat Estat (P17).
  • qualifier= (opcional) Propietat del qualificador, amb format "P" seguit d'un número. Es pot veure enllaçat en l'element de Wikidata. Accepta també una p minúscula, però no és recomanat.
  • value= (opcional) Valor preferent al de Wikidata. Pot ser un paràmetre opcional en una plantilla amb el format {{{paràmetre|}}}, així si existeix pren el valor del paràmetre i sinó el valor de Wikidata.
  • list= (opcional). Per defecte assumeix list=true traient una llista dels valors de totes les declaracions o els qualificadors (vegeu separator i conjuction).
    • list=false o list=no Treu només un valor, el de rang més alt segons l'ordre preferent/normal/obsolet, o el més antic dels que tenen el rang més alt.
    • list=firstrank Treu la llista dels valors amb el primer rang més alt. És equivalent a list=true si tots tenen el mateix rang.
    • tablesort=0 (opcional) ordenació ascendent de la llista. Per defecte l'ordenació és pel rang (preferent, normal, obsolet) i per l'antiguitat de definició a Wikidata.
    • list=lang En cas de valors multilingües només treu els corresponents a la llengua del paràmetre lang. Vegeu el paràmetre lang i formatting per format multilingüe (monolingualtext).
  • formatting= (opcional) Format desitjat. Valors possibles, per a cada tipus:
    • Format d'element (entity):
      • formatting=raw Número identificador de l'element.
      • formatting=label Etiqueta de l'element.
      • formatting=sitelink Títol de la pàgina de la Viquipèdia de l'element, sense enllaç. Si no existeix retorna el format raw amb el prefix wikidata:.
      • formatting=internallink Enllaç intern sempre que sigui possible, bé a la pàgina de la Viquipèdia (sitelink) o bé a l'etiqueta. Si no existeix l'enllaç a la Viquipèdia de l'element, i existeix una etiqueta, evita l'enllaç per defecte a Wikidata, encara que resulti un enllaç vermell.
      • formatting=pattern Format segons un patró usant $1 com a paràmetre a substituir.
      Pot incloure plantilles o funcions parser amb el format: {{((}}plantilla{{!}}paràmetre{{!}}nom{{=}}paràmetre{{))}}
    El format per defecte és un enllaç conduït, bé a sitelink o bé a wikitada:raw, usant label com a etiqueta de l'enllaç.
    • formatting=ucfirst Variant del format per defecte amb majúscula inicial en l'etiqueta. En una llista només posa majúscula en el primer element.
    • formatting=ucinternallink Variant del format "ucfirst" combinat amb "internallink".
    • Format de text (string):
      • formatting=weblink Format d'enllaç extern [http://example.com example.com]
      • formatting=pattern Format segons un patró usant $1 com a paràmetre a substituir. Exemple:formatting=[http://whc.unesco.org/en/list/$1 $1]. Per a propietats que ja hi tenen un enllaç autogenerat per WD, el patró es troba a la pàgina de discussió de la propietat.
    • Format numèric (quantity):
    • Format multilingüe (monolingualtext):
      • formatting=language Codi de llengua en que està escrit el valor del paràmetre, en el cas de paràmetres amb format monolingual text, com ara el Nom oficial (P1448).
      • formatting=text Recupera el text en brut, sense la marca de llengua. Per defecte s'inclou la marca de llengua quan és diferent a la llengua local del wiki: <span lang="en">United...</span>.
      • formatting=pattern Format segons un patró usant $language i $text com a variables a substituir. Per exemple, "formatting=($language) $text" per treure el text amb el codi de llengua al davant entre parèntesis.
      • list=lang Sols treu els valors corresponents a la llengua definida o la llengua per defecte. Vegeu el paràmetre lang.
      • formatting=ca (obsolet) equival a list=lang quan lang=ca. En procés de substitució.
    • Format coordenades (globecoordinate):
      • formatting=latitude Valor de latitud en una declaració de coordenades, en format decimal
      • formatting=longitude Valor de longitud en una declaració de coordenades, en format decimal
      • formatting=dimension Valor de dimensió en una declaració de coordenades, en metres, equivalent al paràmetre dim de GeoHack.
      • formatting=globe (per defecte) Valor del paràmetre globe de la plantilla:coord, necessari per coordenades fora de la Terra. Les dades estan definides al Mòdul:Mapa cos celeste/dades.
    • Format de dates (time):
      • formatting= format #time Accepta qualsevol format vàlid de la funció d'analitzador #time. Per exemple: formatting=d-m-Y (19-10-2018), formatting=[[j xg]] (19 d'octubre), formatting=Y (2018). Per defecte usa el format "j F Y" (19 octubre 2018)
    • Format de taula de propietat i qualificadors:
      • formatting=table Taula de valors de llista de propietats amb els seus qualificadors. Es poden indicar fins a 9 qualificadors i el format de cada línia. Els separadors són per defecte salts de línia (vegeu separator i conjunction). Paràmetres específics per a aquest format:
        • qualifier2 ... qualifierx= Qualificadors addicionals al primer qualifier, amb nombre il·limitat consecutius.
        • rowformat= Format de la fila de propietat més qualificadors. La propietat s'indica amb $0 i els qualificadors $1 a $x. Per defecte és rowformat=$0 ($1, ... $x). Pot incloure marques de llistes * o # i també plantilles o funcions parser amb el format: {{((}}plantilla{{!}}paràmetre{{!}}nom{{=}}paràmetre{{))}}
        • rowsubformat1 ... rowsubformatx= Subformat opcional a aplicar a $1-$x definits en rowformat. Pot ser útil per no trencar el format en cas d'un qualificador buit. Per exemple, "rowformat=$0 $1" i "rowsubformat1=per $1" resulta "$0 per $1" o bé "$0" sense qualificador.
        • colformat0 ... colformatx= Format opcional a aplicar a les columnes, 0 per la propietat i 1-x pels qualificadors. Accepta la mateixa sintaxi que formatting per a cada tipus de valor.
        • case0 ... casex= Cas gramatical a aplicar a cada columna. Vegeu més avall. El paràmetre case, sense numeració, s'aplica a tots els valors.
        • whitelist0 ... whitelistx= Llista, separada per una barra vertical (/), dels ítems a mostrar per a una columna.
        • blacklist0 ... blacklistx= Llista, separada per una barra vertical (/), dels ítems que no es mostraran per a una columna. En cas d'usar whitelist per a una columna i blacklist per a una altra els resultats poden ser inesperats (vegeu un comentari al respecte)
        • tablesort= amb valors de 0 a x, permet ordenar la taula per la propietat (0) o els qualificadors (1 a x). Per defecte l'ordenació és pel rang de la propietat (preferent, normal, obsolet) i per l'antiguitat de definició a Wikidata.
        • tablesortalt= per a una ordenació alternativa quan el valor corresponent a tablesort està buit. Pot ser útil en casos en que es combinen qualificadors en una mateixa columna, per exemple Data (P585) o Data d'inici (P580).
        • sorting=-1 inverteix l'ordenació fent-la descendent. Amb qualsevol altre valor, o en el seu defecte, l'ordenació és ascendent.
        • list=false (vegeu més amunt) treu només la primera fila de la taula, segons l'ordre indicat o per defecte.
  • separator= (opcional) Separador a usar en llistes o taules. En cas de llistes, per defecte és MediaWiki:Comma-separator, en català una coma i un espai en blanc ', '. En cas de taules per defecte és un salt de línia <br />. En algun cas, si s'inclou en etiquetes que usen strip markers, pot ser que un <br /> no funcioni. L'alternativa és usar separator=LF per a un caràcter de control line feed.
  • conjunction= (opcional) Conjunció a usar com a separador diferent entre els dos últims elements de la llista. Per defecte és igual a separator si està definit i si no és MediaWiki:And més MediaWiki:Word-separator, en català ' i '. En el cas de taules per defecte és un salt de línia <br />
  • case= (opcional) Cas gramatical a generar. Casos definits:
    • case=gender, treu la forma femenina segons Sexe (P21) de l'element (pàgina actual, item o itemgender). La forma femenina en català es generada automàticament amb les excepcions de Mòdul:ca-flexió/femení.
    • case=infoboxlabel, treu l'etiqueta sense complement amb preposicions i altres correccions definides a Mòdul:Wikidata/labels en la taula infoboxlabels. Es pot combinar amb itemgender per afegir-hi a més el case=gender.
    • case=infoboxdata, per a canvis en l'etiqueta de l'enllaç en valors d'una infotaula, per exemple per usar un àlies més simple o les sigles de forma més apropiada per a una infotaula. Els canvis es defineixen a la taula infoboxdata del Mòdul:Wikidata/labels. Cal considerar abans si caldria modificar l'etiqueta a Wikidata.
    • case=smallcaps, treu l'etiqueta en versaleta.
  • item= (opcional) Permet indicar un item (Qnnnnn) diferent a l'article actiu. Cal fer-lo servir amb moderació pel seu alt consum de recursos. Es pot usar també com a paràmetre global en la plantilla o la invocació superior.
  • itemgender= (opcional) Element on es comprova la forma femenina segons Sexe (P21), per defecte item. S'usa en combinació amb case=gender o case=infoboxlabel.
  • lang= (opcional) Permet indicar el codi d'una llengua determinada. Es pot usar també com a paràmetre global en la plantilla o la invocació superior. Per defecte usa la llengua local del wiki per a l'espai principal d'articles o la llengua d'usuari definida en les preferències per a altres espais de noms. Si no troba el valor en aquesta llengua ho intenta en les llengües alternatives definides en el MediaWiki. Per exemple per català les llengües alternatives són occità i anglès. En cas que el valor no s'hagi trobat en la llengua demanada, hi afegeix un petit llapis com a icona per a traduir-ho a Wikidata. Aquesta icona es pot eliminar amb el paràmetre editicon.
  • editicon= (opcional) Defineix si es posa un petit llapis Tradueix com a icona per editar a Wikitada en cas que el valor no s'hagi trobat en la llengua demanada. Per defecte és true. Amb valors editicon=false o editicon=no és false.
  • showerrors= (opcional) Amb qualsevol valor mostra el missatge d'error, si n'hi ha cap. Si no està definit mostrarà el paràmetre default en cas d'error.
  • default= (opcional) Text a mostrar en cas d'error. No té cap efecte si està definit el paràmetre showerrors. Si no està definit, i tampoc el paràmetre showerrors, retornarà un valor buit en cas d'error.

Funció getLabel

  • 1= (primer paràmetre posicional, requerit) Identificador de l'ítem de Wikidata (Qxxx o Pxxx).
  • lang= (opcional) Codi de llengua. Per defecte és la llengua del wiki en l'espai principal d'articles o la llengua de les preferències de l'usuari en altres espais. Si no troba l'etiqueta llavors la cerca en les llengües alternatives definides per MediaWiki. Per exemple per català les alternatives són primer occità i finalment anglès. Si tampoc la troba en les llengües alternatives retornarà l'ID de Wikidata (el primer paràmetre).
  • itemgender= (opcional) Identificador de l'ítem que determina el gènere a usar. En cas que sigui gènere femení retornarà l'etiqueta definida a Forma femenina de l'etiqueta (P2521), si existeix en la llengua corresponent.
  • fixed= (opcional) Amb qualsevol valor, i en cas que lang sigui la llengua local del wiki, obté l'etiqueta fixada a Mòdul:Wikidata/labels en la taula infoboxLabelsFromId.
  • linked= (opcional) Amb qualsevol valor definit retornarà l'etiqueta enllaçada a l'article local.
  • label= (opcional) Treu l'etiqueta indicada. Només té sentit amb linked= per generar un enllaç amb l'etiqueta de label=.
  • editicon= (opcional) Defineix si es posa un petit llapis Tradueix com a icona per editar a Wikitada en cas que l'etiqueta no s'hagi trobat en la llengua demanada. Per defecte és true. Amb valors editicon=false o editicon=no és false.

Funció getParentValues

  • item= (opcional) Permet indicar un item (Qnnnnn) diferent a l'article actiu. Aquest accés arbitrari a Wikidata està limitat pel seu alt consum de recursos.
  • property= (opcional) Propietat de la declaració, amb format "P" seguit d'un número. Per defecte és Situat a la unitat administrativa (P131).
  • label= (opcional) Propietat de l'etiqueta. Per defecte és Instància de (P31).
  • valuetext= (opcional) Propietat del text de l'enllaç del valor. Per defecte és un enllaç intern (vegeu formatting=internallink més amunt).
  • upto= (opcional) Fins on volem profunditzar en l'arbre de consultes, abans no trobi cap més propietat. Tipus de valors:
    • upto=etiqueta: última etiqueta a consultar, per exemple "upto=estat".
    • upto=valor numèric: nombre de nivells màxim a extreure. Per defecte és 10 com a protecció, normalment un valor més alt del que serà necessari.
  • labelshow= (opcional) Filtre d'etiquetes a mostrar, separades per una barra / si són més d'una. Per exemple "labelshow=municipi/comarca". Mostra el primer valor trobat per a cada etiqueta, sense repeticions posteriors de la mateixa etiqueta.
  • sorting= (opcional) Ordenació de la llista. Només té un valor possible "sorting=-1" per ordenar de forma inversa.
  • rowformat= (opcional) Format de sortida per a cada parell de valors obtingut, indicant $0 per l'etiqueta i $1 pel valor. Per defecte és "rowformat=$0 = $1" mostrant per exemple "comarca = [[Maresme]]"
  • separator= (opcional) Separador per a cada parell de valors obtingut, per defecte és <br />. A notar que no s'utilitza l'opció conjunction pel darrer separador.

Nota: les etiquetes de les instàncies es modifiquen amb un format més adequat a les necessitats d'una infotaula. Per exemple, "municipi del Brasil" es presenta com a "Municipi". A Mòdul:Wikidata/labels es poden definir les correccions necessàries.

Funció linkWithParentLabel

Accepta la majoria de paràmetres de la funció claim, excepte "formatting" que usa el valor per defecte "internallink". Addicionalment:

  • parent= és la propietat a usar en l'etiqueta corresponent a l'ítem superior del valor obtingut per "property/qualifier".

Funció years_old

La seva sintaxi és: {{#invoke:Wikidata|years_old|formatting=''tipus pattern'' |item= }}. item i formatting són opcionals. Un exemple típic de formatting és ($1 anys)

Exemples

Els exemples a continuació són mostres provades en les pàgines corresponents. Es poden fer proves a Viquipèdia:Proves de Wikidata, comprovacions en previsualització d'una pàgina o usar el paràmetre item per un element de Wikidata diferent de la pàgina actual.

  • Ús simple:
{{#invoke:Wikidata | claim |property=P20}} a l'article Jean-François Champollion dóna: París
és la propietat Lloc de defunció (P20), per defecte amb el valor enllaçat.
  • Sense enllaç:
{{#invoke:Wikidata | claim | property=P20 | formatting=label}} dóna: París
  • Valor preferent:
{{#invoke:Wikidata | claim | property=P20 | value={{{lloc_mort|}}} }} en la infotaula de l'article donarà
el valor de {{{lloc_mort|}}} si està definit en l'article, en cas contrari París
  • Valor tipus data:
{{#invoke:Wikidata | claim | property=P569}} dóna la data de naixement amb el format per defecte:
23 desembre 1790 i 22 desembre 1790
  • Formatat amb un patró:
{{#invoke:Wikidata | claim | property=P214 | formatting=[http://viaf.org/viaf/$1 $1]}} dóna:
34454460
  • Un únic valor:
Imatge de mostra
{{#invoke:Wikidata | claim | property=P18 | list=false | formatting=[[File:$1|thumb|upright=.5|Imatge de mostra]]}}
Treu només la primera de les imatges definides.
  • Format d'enllaç extern:
{{#invoke:Wikidata | claim | property=P856 | formatting=weblink}} a Berlín dóna:
www.berlin.de/
  • Llista de valors:
{{#invoke:Wikidata | claim | property=P47}} a Alcoià dóna:
l'Alacantí, l'Alt Vinalopó, Comtat, Marina Baixa, La Vall d'Albaida i Vinalopó Mitjà
Cal notar l'enllaç conduït [[Comtat (País Valencià)|Comtat]]
  • Llista formatada:
{{#invoke:Wikidata | claim | property=P150 | separator=<br /> | conjunction=<br />}} dóna
Alcoi
Banyeres de Mariola
Benifallim
Castalla
Ibi
Onil
Penàguila
Tibi
  • Coordenades:
{{#invoke:Wikidata | claim | property=P625 | formatting=latitude}} dóna: 38.701944444444
{{#invoke:Wikidata | claim | property=P625 | formatting=longitude}} dóna: -0.47722222222222

Dependències

  • ../i18n (opcional): traduccions de missatges i formats locals. Si no existeix, surt en anglès.
  • ../Units (opcional): tractament d'unitats, en plural o amb codi. Si no existeix, treu el nom complet de la unitat en singular.
    • Mòdul:Ca-flexió: generació de plurals estàndard d'unitats no inclosos a Mòdul:Wikidata/Units.
  • ../labels (opcional): excepcions i correccions d'etiquetes per a una infotaula.
  • Mòdul:Mapa cos celeste/dades (opcional): configuració per a coordenades de cossos celestes. Si no existeix retorna l'ID del cos en lloc de les coordenades.
  • Mòdul:Utilitats: pot aparèixer ocasionalment per a rastreig de determinats usos. Només usat provisionalment per a manteniment.

Les subpàgines "Mòdul:Wikidata/i18n", "Mòdul:Wikidata/Units" i "Mòdul:Wikidata/labels" són relatives al mòdul principal. Si en una instal·lació es canvia el títol de "Mòdul:Wikidata" les crides a les subpàgines funcionaran amb el nou títol.

Vegeu també

-- version 20181003 from master @cawiki

local p = {}

-----------------------------------------------------------------------------
-- internationalisation at [[Module:Wikidata/i18n]]
local i18n = {
	["errors"] = {
		["property-not-found"] = "Property not found.",
		["entity-not-found"] = "Wikidata entity not found.",
		["unknown-claim-type"] = "Unknown claim type.",
		["unknown-entity-type"] = "Unknown entity type.",
		["qualifier-not-found"] = "Qualifier not found.",
		["site-not-found"] = "Wikimedia project not found.",
		["unknown-datetime-format"] = "Unknown datetime format.",
		["local-article-not-found"] = "Article is not yet available in this wiki.",
		['not-from-content-page'] = "Do not invoke from content page. Use a template or use a module subpage like /sandbox for testing ."
	},
	["datetime"] =
	{
		-- $1 is a placeholder for the actual number
		[0] = "$1 billion years",	-- precision: billion years
		[1] = "$100 million years",	-- precision: hundred million years
		[2] = "$10 million years",	-- precision: ten million years
		[3] = "$1 million years",	-- precision: million years
		[4] = "$100,000 years",		-- precision: hundred thousand years
		[5] = "$10,000 years",		-- precision: ten thousand years
		[6] = "$1 millennium",		-- precision: millennium
		[7] = "$1 century",			-- precision: century
		[8] = "$1s",				-- precision: decade
		-- the following use the format of #time parser function
		[9]  = "Y",					-- precision: year, 
		[10] = "F Y",				-- precision: month
		[11] = "F j, Y",			-- precision: day
		[12] = "F j, Y ga",			-- precision: hour
		[13] = "F j, Y g:ia",		-- precision: minute
		[14] = "F j, Y g:i:sa",		-- precision: second
		
		["beforenow"] = "$1 BCE",	-- how to format negative numbers for precisions 0 to 5
		["afternow"] = "$1 CE",		-- how to format positive numbers for precisions 0 to 5
		["bc"] = '$1 "BCE"',		-- how print negative years
		["ad"] = "$1",				-- how print positive years
		["bc-addon"] = " BC",		-- suffix for negative dates
		["ad-addon"] = ""			-- suffix for 1st century AD dates
	},
	["monolingualtext"] = '<span lang="%language">%text</span>',
	["warnDump"] = "[[Category:Called function 'Dump' from module Wikidata]]",
	
	["cite"] = {					-- Cite web parameters
		["url"]          = "url",
		["title"]        = "title",
		["website"]      = "website",
		["access-date"]  = "access-date",
		["archive-url"]  = "archive-url",
		["archive-date"] = "archive-date",
		["author"]       = "author",
		["publisher"]    = "publisher",
		["quote"]        = "quote",
		["language"]     = "language",
		["date"]         = "date",
		["pages"]        = "pages"
	}
}

local cases = {} -- functions for local grammatical cases defined at [[Module:Wikidata/i18n]]

local wiki = 
{
	langcode = mw.language.getContentLanguage().code,
	module_title = "Module:Wikidata"
}

----------------------------------------------------------------------------
-- module local functions

-- Credit to http://stackoverflow.com/a/1283608/2644759
-- cc-by-sa 3.0
local function tableMerge(t1, t2)
	for k,v in pairs(t2) do
		if type(v) == "table" then
			if type(t1[k] or false) == "table" then
				tableMerge(t1[k] or {}, t2[k] or {})
			else
				t1[k] = v
			end
		else
			t1[k] = v
		end
	end
	return t1
end

local function loadI18n()
	local exist, res = pcall(require, wiki.module_title .. "/i18n")
	if exist and next(res) ~= nil then
		tableMerge(i18n, res.i18n)
		cases = res.cases
	end
end

loadI18n()

local function case(word, localcase, lang)
	if word == nil or word == '' or cases[localcase] == nil then
		return word
	end
	
	return cases[localcase](word, lang)
end

local function findLang(langcode)
	if langcode == nil or langcode == "" or mw.language.isKnownLanguageTag(langcode) == false then
		local myframe = mw.getCurrentFrame()
		langcode = myframe.args.lang
		if langcode == nil or langcode == "" or mw.language.isKnownLanguageTag(langcode) == false then
			langcode = myframe:getParent().args.lang
			if langcode == nil or langcode == "" or mw.language.isKnownLanguageTag(langcode) == false then
				if not mw.title.getCurrentTitle().isContentPage then
					langcode = myframe:preprocess( '{{int:lang}}' )
				end
				if langcode == nil or langcode == "" or mw.language.isKnownLanguageTag(langcode) == false then
					langcode = wiki.langcode
				end
			end
		end
	end
	local languages = mw.language.getFallbacksFor(langcode)
	table.insert(languages, 1, langcode)
	return languages
end

-- mw.wikibase.getLabelWithLang or getLabelByLang with a table of languages
local function getLabelByLangs(id, languages)
	local label
	local lang = languages[1]
	if lang == wiki.langcode then
		-- using getLabelWithLang when possible instead of getLabelByLang
		label, lang = mw.wikibase.getLabelWithLang(id)
	else
		for _, l in ipairs(languages) do
			label = mw.wikibase.getLabelByLang(id, l)
			lang = l
			if label then
				break
			end
		end
	end
	return label, lang
end

-- Is gender femenine? true or false
local function feminineGender(id)
	local entity = mw.wikibase.getEntity(id)
	local genderClaims = entity.claims["P21"] -- sex or gender
	if genderClaims then
		local genderId = getValueOfClaim(genderClaims[1], nil, {["formatting"]="raw"})
		if genderId == "Q6581072" or genderId == "Q1052281" or genderId == "Q43445" then -- female, transgender female, female organism
			return true
		end
	end
	return false
end

-- Fetch female form of label
local function feminineForm(id, lang)
	local feminine_claims = findClaims(mw.wikibase.getEntity(id), 'P2521') -- female form of label
	if feminine_claims then
		for _, feminine_claim in ipairs(feminine_claims) do
			local feminine_value = getValueOfClaim(feminine_claim, nil, {["list"]="lang", ["lang"]={lang}})
			if feminine_value then
				return feminine_value
			end
		end
	end
end

-- Fetch unit symbol
local function unitSymbol(id, lang)
	local claims = findClaims(mw.wikibase.getEntity(id), 'P5061')
	local langclaims = {}
	if claims then
		for _, snak in ipairs(claims) do
			if snak.mainsnak and snak.mainsnak.datavalue and snak.mainsnak.datavalue.value and
				not langclaims[snak.mainsnak.datavalue.value.language] -- just the first one by language
				then
					langclaims[snak.mainsnak.datavalue.value.language] = snak.mainsnak.datavalue.value.text
			end
		end
		for _, l in ipairs(lang) do
			if langclaims[l] then
				return langclaims[l]
			end
		end
	end
	return langclaims["mul"] -- last try
end

-- Add a small pencil as icon for edit on Wikidata
local function addEditIcon(id, lang, uselang, icon)
	if icon and lang ~= uselang then
		return " [[File:Arbcom ru editing.svg|12px|" .. mw.message.new('Translate-taction-translate'):inLanguage(uselang):plain() .. "|link=d:" .. id .. "]]"
	end
	return ''
end

local function expandBraces(text, formatting)
	if text == nil or formatting == nil then return text end
	-- only expand braces if provided in argument, not included in value as in Q1164668
	if mw.ustring.find(formatting, '{{', 1, true) == nil then return text end
	if type(text) ~= "string" then
		text = tostring(text)
	end
	
	for braces in mw.ustring.gmatch(text, "{{(.-)}}") do
		local parts = mw.text.split(braces, "|")
		local title_part = parts[1]
		local parameters = {}
		for i = 2, #parts do
			if mw.ustring.find(parts[i], "=") then
				local subparts = mw.text.split(parts[i], "=")
				parameters[subparts[1]] = subparts[2]
			else
				table.insert(parameters, parts[i])
			end
		end
		
		local braces_expanded
		if mw.ustring.find(title_part, ":")
			and mw.text.split(title_part, ":")[1] ~= mw.site.namespaces[10].name -- not a prefix Template:
			then
			braces_expanded = mw.getCurrentFrame():callParserFunction{name=title_part, args=parameters}
		else
			braces_expanded = mw.getCurrentFrame():expandTemplate{title=title_part, args=parameters}
		end
		braces = mw.ustring.gsub(braces, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1") -- escape magic characters
		braces_expanded = mw.ustring.gsub(braces_expanded, "(%%[0-9])", "%%%1") -- no captures in replacement string, i.e. url %-coded
		text = mw.ustring.gsub(text, "{{" .. braces .. "}}", braces_expanded)
	end
	
	return text
end

local function printDatavalueString(data, parameters)
	if parameters.formatting == 'weblink' then 
		return '[' .. data ..  ' ' ..  mw.text.split(data, '//' )[2] .. ']'
	elseif mw.ustring.find((parameters.formatting or ''), '$1', 1, true) then -- formatting = a pattern
		local escaped_data = mw.ustring.gsub(data, "%%", "%%%") -- escape % character, normally used in url, avoiding invalid capture in gsub
		return expandBraces(mw.ustring.gsub(parameters.formatting, '$1', escaped_data), parameters.formatting)
	elseif parameters.case then
		return case(data, parameters.case, parameters.lang[1])
	else
		return data
	end
end

local function printDatavalueCoordinate(data, parameter)
	if parameter == 'latitude' then
		return data.latitude
	elseif parameter == 'longitude' then
		return data.longitude
	elseif parameter == 'dimension' then
		return data.dimension
	else --default formatting='globe'
		if data.globe == '' or data.globe == nil or data.globe == 'http://www.wikidata.org/entity/Q2' then
			return 'earth'
		else
			local globenum = mw.text.split(data.globe, 'entity/')[2] -- http://www.wikidata.org/wiki/Q2
			if pcall(require, "Module:Mapa cos celeste/dades") then
				local globetable = mw.loadData('Module:Mapa cos celeste/dades')
				for _, globe in pairs(globetable.maps) do
					if globe.wikidata == globenum then
						return globe.coord_globe
					end
				end
			end
			return globenum
		end
	end
end

local function printDatavalueQuantity(data, parameters)
	-- exemples: 277±1 Centímetre, 1,94 metre
	local amount = data.amount
	amount = mw.ustring.gsub(amount, "%+", "")
	local sortkey = string.format("%09d", amount)
	amount = mw.language.new(parameters.lang[1]):formatNum(tonumber(amount))
	-- This is used to get the unit name for a numeric value
	local suffix = ""
	if parameters.formatting == "unit" or parameters.formatting == "unitcode" then
		-- get the url for the unit entry on Wikidata:
		local unitID = data.unit
		-- and just return the last bit from "Q" to the end (which is the QID):
		unitID = mw.ustring.sub(unitID, mw.ustring.find(unitID, "Q"), -1)
		if mw.ustring.sub(unitID, 1, 1) == "Q" then
			local unit_label, lang = getLabelByLangs(unitID, parameters.lang)
			local unit_symbol
			if parameters.formatting == "unitcode" then
				unit_symbol = unitSymbol(unitID, parameters.lang)
			end
			if lang == wiki.langcode and pcall(require, wiki.module_title .. "/Units") then
				suffix = " " .. require(wiki.module_title .. "/Units").getUnit(amount, unit_label, unitID, parameters.formatting == "unitcode", unit_symbol)
			elseif parameters.formatting == "unitcode" and unit_symbol then
				suffix = " " .. unit_symbol
			else
				suffix = " " .. (unit_label or unitID) .. addEditIcon(unitID, lang, parameters.lang[1], parameters.editicon)
			end
		end
	end
	return amount .. suffix, sortkey
end

local function printDatavalueTime(data, parameters)
	-- Dates and times are stored in ISO 8601 format
	local timestamp = data.time
	local sortkey = timestamp
	local addon = ""
	
	-- calendar model
	local calendar_model = {["Q12138"] = "gregorian", ["Q1985727"] = "gregorian", ["Q11184"] = "julian", ["Q1985786"] = "julian"}
	local calendar_id = mw.text.split(data.calendarmodel, 'entity/')[2]
	local calendar_add = ""
	if (timestamp < "+1582-10-15T00:00:00Z" and calendar_model[calendar_id] == "gregorian")
		or (timestamp > "+1582-10-04T00:00:00Z" and calendar_model[calendar_id] == "julian")
		then
		calendar_add = " <sup>(" .. mw.message.new('Wikibase-time-calendar-' .. calendar_model[calendar_id]):inLanguage(parameters.lang[1]):plain() .. ")</sup>"
	end
	
	-- check for negative date, ex. "-0027-01-16T00:00:00Z"
	if string.sub(timestamp, 1, 1) == '-' then
		timestamp = '+' .. string.sub(timestamp, 2)
		addon = i18n.datetime["bc-addon"]
	elseif string.sub(timestamp, 2, 3) == '00' then
		addon = i18n.datetime["ad-addon"]
	end
	local function d(f, t)
		local ts = t or timestamp
		local form = type(f) == "function" and f(ts) or f -- function in i18n.datetime[precision]
		return mw.language.new(parameters.lang[1]):formatDate(form, ts) .. addon .. calendar_add
	end
	local precision = data.precision or 11
	local intyear = tonumber(mw.ustring.match(timestamp, "^\+?%d+"))
	local ret = ""
	
	-- precision is 10000 years or more
	if precision <= 5 then
		local factor = 10 ^ ((5 - precision) + 4)
		local y2 = math.ceil(math.abs(intyear) / factor)
		local relative = mw.ustring.gsub(i18n.datetime[precision], "$1", tostring(y2))
		if addon == i18n.datetime["bc-addon"] then
			-- negative date
			ret = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative)
		else
			ret = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative)
		end
	-- precision is millennia, centuries or decades
	elseif precision == 6 then
		local card = math.floor((intyear - 1) / 1000) + 1
		if mw.ustring.find(i18n.datetime[6], "$1") then
			ret = mw.ustring.gsub(i18n.datetime[6], "$1", tostring(card)) .. addon .. calendar_add
		else
			ret = d(i18n.datetime[6], string.format("%04d", tostring(card)))
		end
	elseif precision == 7 then
		local card = math.floor((math.abs(intyear) - 1) / 100) + 1
		if mw.ustring.find(i18n.datetime[7], "$1") then
			ret = mw.ustring.gsub(i18n.datetime[7], "$1", tostring(card)) .. addon .. calendar_add
		else
			ret = d(i18n.datetime[7], string.format("%04d", tostring(card)))
		end
	elseif precision == 8 then
		local card = math.floor(math.abs(intyear) / 10) * 10
		ret = mw.ustring.gsub(i18n.datetime[8], "$1", tostring(card)) .. addon .. calendar_add
	-- precision is year
	elseif parameters.formatting == 'Y' or precision == 9 then
		ret = tostring(intyear) .. addon .. calendar_add
	-- precision is month
	elseif precision == 10 then
		timestamp = timestamp .. " + 1 day" -- formatDate yyyy-mm-00 returns the previous month
		ret, _ = string.gsub(d(i18n.datetime[10]), " 0+", " ") -- supress leading zeros in year
	elseif parameters.formatting then
		ret, _ = string.gsub(d(parameters.formatting), "([ %[])0+", "%1") -- supress leading zeros in year optionally linked
	else
		ret, _ = string.gsub(d(i18n.datetime[11]), " 0+", " ")
	end
	return ret, sortkey
end

local function printDatavalueEntity(data, parameters)
	local entityId = data['id']
	local entityIdPreffix = data['entity-type'] == 'property' and "Property:" .. entityId or entityId
	if parameters.formatting == 'raw' then
		return entityId, entityId
	end
	local label, lang = getLabelByLangs(entityId, parameters.lang)
	local sitelink = mw.wikibase.getSitelink(entityId)
	local parameter = parameters.formatting
	local labelcase = label or sitelink
	if parameters.gender == 'feminineform' and lang ~= nil then -- case gender and item is female
		labelcase = feminineForm(entityId, lang) or labelcase
	end
	if parameters.case then
		labelcase = case(labelcase, parameters.case, lang)
	end
	local ret1, ret2
	if parameter == 'label' then
		ret1 = (labelcase or entityId)
		ret2 = labelcase or entityId
	elseif parameter == 'sitelink' then
		ret1 = (sitelink or 'wikidata:' .. entityIdPreffix)
		ret2 = sitelink or entityId
	elseif mw.ustring.find((parameter or ''), '$1', 1, true) then -- formatting = a pattern
		ret1 = mw.ustring.gsub(parameter, '$1', labelcase or entityId)
		ret1 = expandBraces(ret1, parameter)
		ret2 = labelcase or entityId
	else
		if parameter == "ucfirst" or parameter == "ucinternallink" then
			labelcase = labelcase and mw.language.new(lang):ucfirst(labelcase)
			-- only first of a list, reset formatting for next ones
			if parameter == "ucinterlanllink" then
				parameters.formatting = 'internallink'
			else
				parameters.formatting = nil -- default format
			end
		end
		
		if sitelink then
			ret1 = '[[' .. sitelink .. '|' .. labelcase .. ']]'
			ret2 = labelcase
		elseif label and (parameter == 'internallink' or parameter == 'ucinternallink') then
			ret1 = '[[' .. label .. '|' .. labelcase .. ']]'
			ret2 = labelcase
		else
			ret1 = '[[wikidata:' .. entityIdPreffix .. '|' .. (labelcase or entityId) .. ']]'
			ret2 = labelcase or entityId
		end
	end
	
	return ret1 .. addEditIcon(entityIdPreffix, lang, parameters.lang[1], parameters.editicon), ret2
end

local function printDatavalueMonolingualText(data, parameters)
	-- data fields: language [string], text [string]
	
	if parameters.list == "lang" and data["language"] ~= parameters.lang[1] then
		return
	elseif parameters.formatting == "language" or parameters.formatting == "text" then
		return data[parameters.formatting]
	end
	local result = data["text"]
	if data["language"] ~= wiki.langcode then
		result = mw.ustring.gsub(mw.ustring.gsub(i18n.monolingualtext, "%%language", data["language"]), "%%text", data["text"])
	end
	if mw.ustring.find((parameters.formatting or ''), '$', 1, true) then
		-- output format defined with $text, $language
		result = mw.ustring.gsub(parameters.formatting, '$text', result)
		result = mw.ustring.gsub(result, '$language', data["language"])
	end
	return result
end

local function printDatatypeMath(data)
	return mw.getCurrentFrame():callParserFunction('#tag:math', data)
end

local function printError(key)
    return '<span class="error">' .. i18n.errors[key] .. '</span>'
end

-- the "qualifiers" and "snaks" field have a respective "qualifiers-order" and "snaks-order" field
-- use these as the second parameter and this function instead of the built-in "pairs" function
-- to iterate over all qualifiers and snaks in the intended order.
local function orderedpairs(array, order)
	if not order then return pairs(array) end

	-- return iterator function
	local i = 0
	return function()
		i = i + 1
		if order[i] then
			return order[i], array[order[i]]
		end
	end
end

function findClaims(entity, property)
	if not property or not entity or not entity.claims then return end
	
	if not mw.ustring.match(property, "^P%d+$") then
		-- get property id for the given label
		property = mw.wikibase.resolvePropertyId(property)
		if not property then return end
	end
	
	return entity.claims[property]
end

local function getSnakValue(snak, parameters)
	if snak.snaktype == 'value' then
		-- call the respective snak parser
		if snak.datatype == 'math' then
			return printDatatypeMath(snak.datavalue.value)
		elseif snak.datavalue.type == "string" then
			return printDatavalueString(snak.datavalue.value, parameters)
		elseif snak.datavalue.type == "globecoordinate" then
			return printDatavalueCoordinate(snak.datavalue.value, parameters.formatting)
		elseif snak.datavalue.type == "quantity" then
			return printDatavalueQuantity(snak.datavalue.value, parameters)
		elseif snak.datavalue.type == "time" then
			return printDatavalueTime(snak.datavalue.value, parameters)
		elseif snak.datavalue.type == 'wikibase-entityid' then
			return printDatavalueEntity(snak.datavalue.value, parameters)
		elseif snak.datavalue.type == 'monolingualtext' then
			return printDatavalueMonolingualText(snak.datavalue.value, parameters)
		end
	elseif snak.snaktype == 'novalue' then
		return mw.message.new('Wikibase-snakview-snaktypeselector-novalue'):inLanguage(parameters.lang[1]):plain()
	elseif snak.snaktype == 'somevalue' then
		return mw.message.new('Wikibase-snakview-snaktypeselector-somevalue'):inLanguage(parameters.lang[1]):plain()
	end
	return mw.wikibase.renderSnak(snak)
end

local function getQualifierSnak(claim, qualifierId, parameters)
	-- a "snak" is Wikidata terminology for a typed key/value pair
	-- a claim consists of a main snak holding the main information of this claim,
	-- as well as a list of attribute snaks and a list of references snaks
	if qualifierId then
		-- search the attribute snak with the given qualifier as key
		if claim.qualifiers then
			local qualifier = claim.qualifiers[qualifierId]
			if qualifier then
				if qualifier[1].datatype == "monolingualtext" then
					-- iterate over monolingualtext qualifiers to get local language
					for idx in pairs(qualifier) do
						if qualifier[idx].datavalue.value and qualifier[idx].datavalue.value.language == parameters.lang[1] then
							return qualifier[idx]
						end
					end
				elseif parameters.list then
					return qualifier
				else
					return qualifier[1]
				end
			end
		end
		return nil, printError("qualifier-not-found")
	else
		-- otherwise return the main snak
		return claim.mainsnak
	end
end

function getValueOfClaim(claim, qualifierId, parameters)
	local error
	local snak
	snak, error = getQualifierSnak(claim, qualifierId, parameters)
	if not snak then
		return nil, nil, error
	elseif snak[1] then -- a multi qualifier
		local result = {}
		local sortkey = {}
		for idx in pairs(snak) do
			result[#result + 1], sortkey[#sortkey + 1] = getSnakValue(snak[idx], parameters)
		end
		return mw.text.listToText(result, parameters.qseparator, parameters.qconjunction), sortkey[1]
	else -- a property or a qualifier
		return getSnakValue(snak, parameters)
	end
end

local function getReferences(claim)
	local refaliases = {
		citeWeb         = "Q5637226",
		author          = "P50",
		publisher       = "P123",
		importedFrom    = "P143",
		statedIn        = "P248",
		pages           = "P304",
		publicationDate = "P577",
		startTime       = "P580",
		endTime         = "P582",
		chapter         = "P792",
		retrieved       = "P813",
		referenceURL    = "P854",
		archiveURL      = "P1065",
		title           = "P1476",
		quote           = "P1683",
		shortName       = "P1813",
		language        = "P2439",
		archiveDate     = "P2960"
	}
	local result = ""
	-- traverse through all references
	for ref in pairs(claim.references or {}) do
		local refparts
		local refs = {}
		-- traverse through all parts of the current reference
		for snakkey, snakval in pairs(claim.references[ref].snaks or {}) do
			if snakkey ~= refaliases.importedFrom then -- "imported from" is not a proper reference
				for snakidx = 1, #snakval do
					if snakidx > 1 then refparts = refparts .. ", " end
					refparts = refparts or '' .. getSnakValue(snakval[snakidx], {lang="wiki.langcode"})
				end
				refs[snakkey] = refparts
				refparts = nil
			end
		end
		
		-- get title of general template for citing web references
		local template = mw.wikibase.getSitelink(refaliases.citeWeb) or ""
		template = mw.text.split(template, ":")[2]  -- split off namespace from front
		
		-- (1) if both "reference URL" and "title" are present, then use the general template for citing web references
		if refs[refaliases.referenceURL] and (refs[refaliases.title] or refs[refaliases.statedIn]) and template then
			local citeParams = {}
			citeParams[i18n['cite']['url']] = refs[refaliases.referenceURL]
			citeParams[i18n['cite']['title']] = refs[refaliases.title] or refs[refaliases.statedIn]:match("^%[%[.-|(.-)%]%]")
			citeParams[i18n['cite']['website']] = refs[refaliases.statedIn]
			citeParams[i18n['cite']['language']] = refs[refaliases.language]
			citeParams[i18n['cite']['date']] = refs[refaliases.publicationDate]
			citeParams[i18n['cite']['access-date']] = refs[refaliases.retrieved]
			citeParams[i18n['cite']['archive-url']] = refs[refaliases.archiveURL]
			citeParams[i18n['cite']['archive-date']] = refs[refaliases.archiveDate]
			citeParams[i18n['cite']['publisher']] = refs[refaliases.publisher]
			citeParams[i18n['cite']['quote']] = refs[refaliases.quote]
			citeParams[i18n['cite']['pages']] = refs[refaliases.pages]
			citeParams[i18n['cite']['author']] = refs[refaliases.author]
			refparts = mw.getCurrentFrame():expandTemplate{title=template, args=citeParams}
		else
			-- raw ouput
			for k, v in orderedpairs(refs or {}, claim.references[ref]["snaks-order"]) do
				if k and v then
					if refparts then refparts = refparts .. ", " else refparts = "" end
					refparts = refparts .. tostring(mw.wikibase.getLabel(k)) .. ": "
					refparts = refparts .. v
				end
			end
		end
		if refparts then result = result .. mw.getCurrentFrame():extensionTag("ref", refparts) end
	end
	return result
end

-- Return the site link (for the current site) for a given data item.
function p.getSiteLink(frame)
    if frame.args[1] == nil then
        entity = mw.wikibase.getEntity()
        if not entity then
        	return nil
        end
        id = entity.id
    else
        id = frame.args[1]
    end
 
    return mw.wikibase.getSitelink(id)
end

-- Set whitelist or blacklist values
local function setWhiteOrBlackList(type_list, num_qual, args)
	local i = 0
	local listed = false
	local list = {}
	while i <= num_qual do
		if args[type_list .. i] and args[type_list .. i] ~= '' then
			listed = true
			list[tostring(i)] = {}
			local values = mw.text.split(args[type_list .. i], "/", true)
			for _, v in ipairs(values) do
				list[tostring(i)][v] = true
			end
		end
		i = i + 1
	end
	return list, listed
end

function p.claim(frame)
	if mw.title.new(frame:getParent():getTitle()).isContentPage then
		if not mw.title.new(frame:getTitle()).isSubpage then
			-- invoked from a content page and not invoking a module subpage
			return printError("not-from-content-page")
		end
	end
	return p._main(frame.args, frame:getParent().args)
end

-- Entry point from other modules or debugging, with a list of arguments.
-- From other modules use: require("Module:Wikidata")._main({item="Q...", property="P...", ...})
-- On debug console use: =p._main({item="Q...", lang="xx", property="P...", ...})
function p._main(args, pargs)
	--If a value is already set, use it
	if args.value and args.value ~= '' then
		return args.value
	end
	
	-- arguments
	local id = args.item or (pargs and pargs.item); if id == "" then id = nil end
	local languages = findLang(args.lang)
	local idgender = args["itemgender"]
	if idgender and not string.match(idgender, "^Q%d+$") then -- id malformed, maybe "unknown value"
		idgender = nil
	end
	local property = string.upper(args["property"] or "")
	local qualifierId = {}
	qualifierId[1] = args["qualifier"] and string.upper(args["qualifier"]) or nil
	local i = 2
	while args["qualifier" .. i] do
		qualifierId[i] = string.upper(args["qualifier" .. i])
		i = i + 1
	end
	local parameter = args["formatting"] or ''; if parameter == "" then parameter = nil end
	local case = args.case
	local list = args["list"] or true; if (list == "false" or list == "no") then list = false end
	local sorting_col = args.tablesort
	local sorting_col_alt = args.tablesortalt or ''
	local sorting_up = (args.sorting or "") ~= "-1"
	local separator = args.separator
	local conjunction = args.conjunction or args.separator
	local rowformat = args.rowformat
	local references = args["references"]
	local showerrors = args["showerrors"]
	local default = args["default"]
	local editicon = not (args.editicon == "false" or args.editicon == "no")
	
	local parameters = {["formatting"] = parameter, ["list"] = list, ["case"] = case, ["lang"] = languages, ["editicon"] = editicon,
		["separator"] = separator, ["conjunction"] = conjunction, ["qseparator"] = separator, ["qconjunction"] = conjunction}
	
	-- defaults for table
	local preformat, postformat = "", ""
	local whitelisted, blacklisted = false, false
	local whitelist, blacklist = {}, {}
	if parameters.formatting == "table" then
		parameters.separator = parameters.separator or "<br />"
		parameters.conjunction = parameters.conjunction or "<br />"
		parameters.qseparator = ", "
		parameters.qconjunction = ", "
		if not rowformat then
			rowformat = "$0 ($1"
			i = 2
			while qualifierId[i] do
				rowformat = rowformat .. ", $" .. i
				i = i + 1
			end
			rowformat = rowformat .. ")"
		elseif mw.ustring.find(rowformat, "^[*#]") then
			parameters.separator = "</li><li>"
			parameters.conjunction = "</li><li>"
			if mw.ustring.match(rowformat, "^[*#]") == "*" then
				preformat = "<ul><li>"
				postformat = "</li></ul>"
			else
				preformat = "<ol><li>"
				postformat = "</li></ol>"
			end
			rowformat = mw.ustring.gsub(rowformat, "^[*#] ?", "")
		end
		
		-- set whitelist and blacklist values
		whitelist, whitelisted = setWhiteOrBlackList("whitelist", #qualifierId, args)
		blacklist, blacklisted = setWhiteOrBlackList("blacklist", #qualifierId, args)
	end
	if default then showerrors = nil end
	
	-- get wikidata entity
	local entity = mw.wikibase.getEntity(id)
	if not entity then
		if showerrors then return printError("entity-not-found") else return default end
	end
	-- fetch the first claim of satisfying the given property
	local claims = findClaims(entity, property)
	if not claims or not claims[1] then
		if showerrors then return printError("property-not-found") else return default end
	end
	
	-- set feminine case if gender is requested
	local genderCase
	if parameters.case == "gender" or idgender or parameters.formatting == "table" then
		if feminineGender(idgender or id) then
			genderCase = "feminineform"
			if parameters.case == "gender" or idgender then
				parameters.gender = genderCase
			end
		end
	end
	
	-- get initial sort indices
	local sortindices = {}
	for idx in pairs(claims) do
		sortindices[#sortindices + 1] = idx
	end
	-- sort by claim rank
	local comparator = function(a, b)
		local rankmap = { deprecated = 2, normal = 1, preferred = 0 }
		local ranka = rankmap[claims[a].rank or "normal"] ..  string.format("%08d", a)
		local rankb = rankmap[claims[b].rank or "normal"] ..  string.format("%08d", b)
		return ranka < rankb
	end
	table.sort(sortindices, comparator)
	
	local result
	local error
	if parameters.list or parameters.formatting == "table" then
		-- convert LF to line feed, <br /> may not work on some cases
		parameters.separator = parameters.separator == "LF" and "\010" or parameters.separator
		parameters.conjunction = parameters.conjunction == "LF" and "\010" or parameters.conjunction
		-- i18n separators
		parameters.separator = parameters.separator or mw.message.new('Comma-separator'):inLanguage(parameters.lang[1]):plain()
		parameters.conjunction = parameters.conjunction or (mw.message.new('And'):inLanguage(parameters.lang[1]):plain() .. mw.message.new('Word-separator'):inLanguage(parameters.lang[1]):plain())
		-- iterate over all elements and return their value (if existing)
		local value, valueq
		local sortkey, sortkeyq
		local values = {}
		local sortkeys = {}
		local firstrank = parameters.list == "firstrank" and claims[sortindices[1]].rank or ''
		local rowlist = {} -- rows to list with whitelist or blacklist
		for idx in pairs(claims) do
			local claim = claims[sortindices[idx]]
			if not whitelisted then rowlist[sortindices[idx]] = true end
			if firstrank ~= '' and firstrank ~= claim.rank then
				break
			end
			if parameters.formatting == "table" then
				local params = mw.clone(parameters)
				params.formatting = args["colformat0"]
				if args["case0"] then
					params.gender = args["case0"] == "gender" and genderCase
				end
				value, sortkey, error =  getValueOfClaim(claim, nil, params)
				if value then
					values[#values + 1] = {}
					sortkeys[#sortkeys + 1] = {}
					if whitelist["0"] or blacklist["0"] then
						local valueraw, _, _ =  getValueOfClaim(claim, nil, {["formatting"]="raw"})
						if whitelist["0"] and whitelist["0"][valueraw] then
							rowlist[#values] = true
						elseif blacklist["0"] and blacklist["0"][valueraw] then
							rowlist[#values] = false
						end
					end
					for i, qual in ipairs(qualifierId) do
						local j = tostring(i)
						params.formatting = args["colformat" .. j]
						if args["case" .. j] then
							params.gender = args["case" .. j] == "gender" and genderCase
						else
							params.case = parameters.case
							params.gender = parameters.gender
						end
						if qual == property then qual = nil end -- hack for getting the property with another formatting, i.e. colformat1=raw
						local valueq, sortkeyq, _ =  getValueOfClaim(claim, qual, params)
						values[#values]["col" .. j] = valueq
						sortkeys[#sortkeys]["col" .. j] = sortkeyq or valueq
						if whitelist[j] or blacklist[j] then
							valueq, _, _ =  getValueOfClaim(claim, qual, {["formatting"]="raw"})
							if whitelist[j] and whitelist[j][valueq] then
								rowlist[#values] = true
							elseif blacklist[j] and blacklist[j][valueq] then
								rowlist[#values] = false
							end
						end
					end
				end
			else
				value, sortkey, error =  getValueOfClaim(claim, qualifierId[1], parameters)
				values[#values + 1] = {}
				sortkeys[#sortkeys + 1] = {}
			end
			if not value and showerrors then value = error end
			if value then
				if references then value = value .. getReferences(claim) end
				values[#values]["col0"] = value
				sortkeys[#sortkeys]["col0"] = sortkey or value
			end
		end
		-- sort and format results
		sortindices = {}
		for idx in pairs(values) do
			sortindices[#sortindices + 1] = idx
		end
		if sorting_col then
			local comparator = function(a, b)
				local valuea = sortkeys[a]["col" .. sorting_col] or sortkeys[a]["col" .. sorting_col_alt] or ''
				local valueb = sortkeys[b]["col" .. sorting_col] or sortkeys[b]["col" .. sorting_col_alt] or ''
				if sorting_up then
					return valuea < valueb
				end
				return valuea > valueb
			end
			table.sort(sortindices, comparator)
		end
		result = {}
		for idx in pairs(values) do
			local valuerow = values[sortindices[idx]]
			value = valuerow["col0"]
			if parameters.formatting == "table" then
				if not rowlist[sortindices[idx]] then
					value = nil
				else
					value = mw.ustring.gsub(rowformat .. "$", "$0", value) -- fake end character added for easy gsub
					for i, _ in ipairs(qualifierId) do
						local valueq = valuerow["col" .. i]
						if args["rowsubformat" .. i] and valueq then
							-- add fake end character $
							-- gsub $i not followed by a number so $1 doesn't match $10, $11...
							-- remove fake end character
							valueq = mw.ustring.gsub(args["rowsubformat" .. i] .. "$", "$" .. i .. "(%D)", valueq .. "%1")
							valueq = string.sub(valueq, 1, -2)
						end
						value = mw.ustring.gsub(value, "$" .. i .. "(%D)", (valueq or '') .. "%1")
					end
					value = string.sub(value, 1, -2) -- remove fake end character
					value = expandBraces(value, rowformat)
				end
			else
				value = expandBraces(value, parameters.formatting)
			end
			result[#result + 1] = value
			if not parameters.list then
				break
			end
		end
		result = preformat .. mw.text.listToText(result, parameters.separator, parameters.conjunction) .. postformat
	else
		-- return first element
		local claim = claims[sortindices[1]]
		result, _, error = getValueOfClaim(claim, qualifierId[1], parameters)
		if result and references then result = result .. getReferences(claim) end
	end
	
	if result then return result else
		if showerrors then return error else return default end
	end
end

-- This is used to get the TA98 (Terminologia Anatomica first edition 1998) values like 'A01.1.00.005' (property P1323)
-- which are then linked to http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/01.1.00.005%20Entity%20TA98%20EN.htm
-- uses the newer mw.wikibase calls instead of directly using the snaks
-- formatPropertyValues returns a table with the P1323 values concatenated with ", " so we have to split them out into a table in order to construct the return string
p.getTAValue = function(frame)
    local ent = mw.wikibase.getEntity()
    local props = ent:formatPropertyValues('P1323')
    local out = {}
    local t = {}
    for k, v in pairs(props) do
        if k == 'value' then
            t = mw.text.split( v, ", ")
            for k2, v2 in pairs(t) do
                out[#out + 1] = "[http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/" .. string.sub(v2, 2) .. "%20Entity%20TA98%20EN.htm " .. v2 .. "]"
            end
        end
    end
    local ret = table.concat(out, "<br> ")
    if #ret == 0 then
        ret = "Invalid TA"
    end
    return ret
end

-- look into entity object
function p.ViewSomething(frame)
	local f = (frame.args[1] or frame.args.item) and frame or frame:getParent()
	local id = f.args.item
	if id and (#id == 0) then
		id = nil
	end
	local data = mw.wikibase.getEntity(id)
	if not data then
		return nil
	end

	local i = 1
	while true do
		local index = f.args[i]
		if not index then
			if type(data) == "table" then
				return frame:extensionTag('syntaxhighlight', mw.text.jsonEncode(data, mw.text.JSON_PRETTY), {lang = 'json'})
			else
				return tostring(data)
			end
		end
		
		data = data[index] or data[tonumber(index)]
		if not data then
			return
		end
		
		i = i + 1
	end
end

-- Dump data tree structure
-- From pl:Module:Wikidane, by User:Paweł Ziemian
-- Funció pensada com a eina d'ajuda en previsualització.
function p.Dump(frame)
	local data = mw.wikibase.getEntity()
	if not data then
		return i18n.warnDump
	end
	
	local f = frame.args[1] and frame or frame:getParent()

	local i = 1
	while true do
		local index = f.args[i]
		if not index then
			return frame:extensionTag('syntaxhighlight', mw.dumpObject(data), {lang = 'json'}) .. i18n.warnDump
		end
		
		data = data[index] or data[tonumber(index)]
		if not data then
			return i18n.warnDump
		end
		
		i = i + 1
	end
end

-- Look into entity object
-- From pl:Module:Wikidane, function V, by User:Paweł Ziemian
function p.getEntityFromTree(frame)
	local data = mw.wikibase.getEntity()
	if not data then
		return nil
	end
	
	local f = frame.args[1] and frame or frame:getParent()
	
	local i = 1
	while true do
		local index = f.args[i]
		if not index then
			return tostring(data)
		end
		
		data = data[index] or data[tonumber(index)]
		if not data then
			return
		end
		
		i = i + 1
	end
end

-- getParentValues: returns a property value with its instance label fetching a recursive tree

local function uc_first(word)
	return mw.ustring.upper(mw.ustring.sub(word, 1, 1)) .. mw.ustring.sub(word, 2)
end

local function getPropertyValue(id, property, parameter, langs, editicon)
	local snaks = mw.wikibase.getBestStatements(id, property)
	local mysnak
	if snaks and snaks[1] and snaks[1].mainsnak then
		mysnak = snaks[1].mainsnak
	else
		return
	end
	
	local entityId
	local result = '-' -- default for 'no value'
	if mysnak.datavalue then
		entityId = "Q" .. tostring(mysnak.datavalue.value['numeric-id'])
		result, _ = getSnakValue(mysnak, {formatting=parameter, lang=langs, editicon=editicon})
	end
	
	return entityId, result
end

function p.getParentValues(frame)
	local args = frame.args
	local id = args.item or frame:getParent().args.item
	if id == "" or id == nil then
		id = mw.wikibase.getEntityIdForCurrentPage()
	end
	local languages = findLang(args.lang)
	local propertySup = args["property"]; if (propertySup == nil or propertySup == "") then propertySup = "P131" end --administrative entity
	local propertyLabel = args["label"]; if (propertyLabel == nil or propertyLabel == "") then propertyLabel = "P31" end --instance
	local propertyLink = args["valuetext"]; if propertyLink == "" then propertyLink = nil end --internallink
	local upto = args["upto"]; if upto == "" then upto = nil end
	local labelShow = args["labelshow"]; if labelShow == "" then labelShow = nil end
	local rowformat = args["rowformat"]; if (rowformat == nil or rowformat == "") then rowformat = "$0 = $1" end
	local separator = args["separator"]; if (separator == nil or separator == "") then separator = "<br />" end
	local sorting = args["sorting"]; if sorting == "" then sorting = nil end
	local editicon = not (args.editicon == "false" or args.editicon == "no")
	
	local lastlabel = uc_first(upto or '')
	local maxloop = tonumber(upto) or (lastlabel == '' and 10 or 50)
	
	local labelFilter = {}
	if labelShow then
		for i, v in ipairs(mw.text.split(labelShow, "/")) do
			labelFilter[uc_first(v)] = true
		end
	end
	
	local result = {}
	local label, link, linktext
	
	for iter = 1, maxloop do
		local label, link
		id, link = getPropertyValue(id, propertySup, args.formatting, languages, editicon)
		if id then
			_, label = getPropertyValue(id, propertyLabel, "label", languages)
			if label and link then
				if propertyLink then
					_, linktext = getPropertyValue(id, propertyLink, "label", languages)
					if linktext then
						link = mw.ustring.gsub(link, "%[%[(.*)%|.+%]%]", "[[%1|" .. linktext .. "]]")
					end
				end
				label = case(label, "infoboxlabel", languages[1])
				if labelShow == nil or labelFilter[label] then
					result[#result + 1] = {label, link}
					labelFilter[label] = nil -- only first label found
				end
				if label == lastlabel then
					break
				end
			else
				break
			end
		else
			break
		end
	end
	
	local ret = {}
	local first = 1
	local last = #result
	local iter = 1
	if sorting == "-1" then first = #result; last = 1; iter = -1 end

	for i = first, last, iter do
		local rowtext = mw.ustring.gsub(rowformat, "$[01]", {["$0"] = result[i][1], ["$1"] = result[i][2]})
		ret[#ret +1] = expandBraces(rowtext, rowformat)
	end
	return mw.text.listToText(ret, separator, separator)
end

function p.linkWithParentLabel(frame)
	local args = {}
	for k, v in pairs(frame.args) do -- metatable
		args[k] = v
	end
	
	-- get internal link of property/qualifier
	args.list = "true"
	args.formatting = "internallink"
	args.separator = "/·/"
	local pargs = frame:getParent().args
	local link_list = p._main(args, pargs)
	if link_list == nil or link_list == "" then
		return
	end
	local link_table = mw.text.split(link_list, "/·/", true)
	
	-- get id value of property/qualifier
	args.formatting = "raw"
	local items_list = p._main(args, pargs)
	local items_table = mw.text.split(items_list, "/·/", true)
	
	-- get label of parent property
	args.property = args.parent
	args.qualifier = nil
	local parent_claims = findClaims(mw.wikibase.getEntity(items_table[1]), args.parent)
	if parent_claims and parent_claims[1].mainsnak.datatype == 'monolingualtext' then
		args.formatting = nil
		args.list = 'lang'
	else
		args.formatting = "label"
		args.list = "false"
	end
	for i, v in ipairs(items_table) do
		args.item = v
		local link_label = p._main(args, pargs)
		if link_label and link_label ~= '' then
			link_table[i] = mw.ustring.gsub(link_table[i] or '', "%[%[(.*)%|.+%]%]", "[[%1|" .. link_label .. "]]")
		end
	end
	
	return mw.text.listToText(link_table)
end

function p.years_old(frame)
	local args = frame.args
	local id = args.item
	if id == '' or id == nil then
		id = mw.wikibase.getEntityIdForCurrentPage()
	end
	local lang = mw.language.new('en')
	
	local function getBestValue(id, prop)
		local snak = mw.wikibase.getBestStatements(id, prop)[1]
		if snak and snak.mainsnak and snak.mainsnak.datavalue and snak.mainsnak.datavalue.value then
			return snak.mainsnak.datavalue.value
		end
	end
	
	local birth = getBestValue(id, 'P569')
	if type(birth) ~= 'table' or birth.time == nil or birth.precision == nil or birth.precision < 8 then
		return
	end
	local death = getBestValue(id, 'P570')
	if type(death) ~= 'table' or death.time == nil or death.precision == nil then
		death = {['time'] = lang:formatDate('c'), ['precision'] = 11} -- current date
	elseif death.precision < 8 then
		return
	end
	
	local dates = {}
	dates[1] = {['min'] = {}, ['max'] = {}, ['precision'] = birth.precision}
	dates[1].min.year = tonumber(mw.ustring.match(birth.time, "^[+-]?%d+"))
	dates[1].min.month = tonumber(mw.ustring.match(birth.time, "\-(%d%d)\-"))
	dates[1].min.day = tonumber(mw.ustring.match(birth.time, "\-(%d%d)T"))
	dates[1].max = mw.clone(dates[1].min)
	dates[2] = {['min'] = {}, ['max'] = {}, ['precision'] = death.precision}
	dates[2].min.year = tonumber(mw.ustring.match(death.time, "^[+-]?%d+"))
	dates[2].min.month = tonumber(mw.ustring.match(death.time, "\-(%d%d)\-"))
	dates[2].min.day = tonumber(mw.ustring.match(death.time, "\-(%d%d)T"))
	dates[2].max = mw.clone(dates[2].min)
	
	for i, d in ipairs(dates) do
		if d.precision == 10 then -- month
			d.min.day = 1
			local timestamp = string.format("%04d", tostring(math.abs(d.max.year)))
				.. string.format("%02d", tostring(d.max.month))
				.. "01"
			d.max.day = tonumber(lang:formatDate("j", timestamp .. " + 1 month - 1 day"))
		elseif d.precision < 10 then -- year or decade
			d.min.day = 1
			d.min.month = 1
			d.max.day = 31
			d.max.month = 12
			if d.precision == 8 then -- decade
				d.max.year = d.max.year + 9
			end
		end
	end
	
	local function age(d1, d2)
		local years = d2.year - d1.year
		if d2.month < d1.month or (d2.month == d1.month and d2.day < d1.day) then
			years = years - 1
		end
		if d2.year > 0 and d1.year < 0 then
			years = years - 1 -- no year 0
		end
		return years
	end
	
	local old_min = age(dates[1].max, dates[2].min)
	local old_max = age(dates[1].min, dates[2].max)
	local old = old_min == old_max and old_min or old_min .. "/" .. old_max
	if args.formatting then
		old = expandBraces(mw.ustring.gsub(args.formatting, '$1', old), args.formatting)
	end
	
	return old
end

-- Gets a label in a given language (content language by default) or its fallbacks, optionnally linked.
function p.getLabel(frame)
	local args = frame.args or frame -- via invoke or require
	local id = mw.text.trim(args[1] or "")
	if id == "" then return end
	local editicon = not (args.editicon == "false" or args.editicon == "no")
	
	local pencil = ''
	local label, lang
	if args.label then
		label = args.label
	else
		local languages = findLang(args.lang)
		if languages[1] == wiki.langcode then
			 -- exceptions or labels fixed
			local exist, labels = pcall(require, wiki.module_title .. "/labels")
			if exist and next(labels.infoboxLabelsFromId) ~= nil then
				label = labels.infoboxLabelsFromId[id]
			end
		end
		
		if label == nil then
			label, lang = getLabelByLangs(id, languages)
			if label then
				if args.itemgender and feminineGender(args.itemgender) then
					label = feminineForm(id, lang) or label
				end
				label = mw.language.new(lang):ucfirst(mw.text.nowiki(label)) -- sanitize
			end
			pencil = addEditIcon(id, lang, languages[1], editicon)
		end
	end
	
	local linked = args.linked
	if linked and linked ~= "" and linked ~= "no" then
		local article = mw.wikibase.getSitelink(id) or ("d:" .. id)
		return "[[" .. article .. "|" .. (label or id) .. "]]" .. pencil
	else
		return (label or id) .. pencil
	end
end

-- Return default language used
function p.lang(frame)
	return findLang(frame.args[1])[1]
end

return p