Mòdul:Wikidata
Aquest mòdul extrau dades formatades de Wikidata. Funciona en la llengua local del wiki, o en una llengua específica per a proves, i té opcions de configuració.
Funcions
[modifica el codi]Funció bàsica:
claim
: Retorna el valor (o els valors) d'una declaració o d'un qualificador formatat amb paràmetres o amb un format per defecte segons el tipus de dada.
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.yearsOld
: 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.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.
Altres utilitats: getSiteLink, lang, numStatements.
Funció claim
[modifica el codi]Retorna el valor (o els valors) d'una declaració o d'un qualificador formatat amb paràmetres o amb un format per defecte segons el tipus de dada. Per defecte està referit a l'ítem de Wikidata (Qid) associat a la pàgina actual.
Sintaxi completa:
{{#invoke:Wikidata|claim|item= |lang= |property= |qualifier= |value= |list= |tablesort= |formatting= |separator= |conjunction= |editicon= |showerrors= |default= }}
Sintaxi addicional pel format de taula:
{{#invoke:Wikidata|claim|item= |lang= |property= |qualifier= |qualifier2= |...|qualifierx= |formatting=table |tablesort= |sorting= |rowformat= |rowsubformat1= |...|rowsubformatx= |colformat0= |...|colformatx= |case0= |...|casex= |separator= |conjunction= |editicon= |showerrors= |default= |references= }}
Paràmetres generals
[modifica el codi]item=
(opcional) Permet indicar un ítem (Qid) diferent a l'ítem associat a la pàgina actual. Cal fer-lo servir amb moderació pel seu alt consum de recursos. Es pot usar també com a paràmetre de l'entorn superior de la plantilla. Té com a àliesfrom
.
lang=
(opcional) Permet indicar el codi d'una llengua determinada. Es pot usar també com a paràmetre de l'entorn superior de la plantilla. 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 el codi de llengua i una icona d'etiqueta per a traduir-ho a Wikidata. Aquesta icona es pot eliminar amb el paràmetre editicon.
property=
(obligatori) Identificador de la propietat de la declaració (Pid). Es poden definir diferents propietats alternatives amb qualsevol separador, per exemple "P17 o P131", i obtindrà la primera que trobi. 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) Qualificador (Pid) del valor de la propietat.
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 si està buit llavors obté el valor de Wikidata.value=NONE
Amb aquest valor no treu res de Wikidata. Permet configurar un paràmetre per a que no tregui cap valor de Wikidata, o bé treure només valors informats en la plantilla amb{{{paràmetre|NONE}}}
. És equivalent a la sintaxi wiki:{{#ifeq:{{{paràmetre|}}}|NONE|<!-- no res -->}}
.
references=
(opcional) Amb qualsevol valor mostrarà les referències del valor obtingut. Si troba URL de la referència (P854) més o bé títol (P1476) o bé afirmat a (P248) llavors ho formata amb la versió local de Plantilla:Ref-web (Q5637226) i amb els paràmetres traduïts a la taula i18n["cite"] de Module:Wikidata/i18n. Si troba publicat a (P1433), més títol o afirmat, llavors ho formata amb Plantilla:Ref-publicació (Q5624899). En cas contrari ho formata com a text.- En cas d'usar-ho amb formatting=table (vegeu més avall) cal definir on han d'aparèixer les referències en el paràmetre "rowformat".
list=
(opcional):list=true
(per defecte) Mostra una llista de tots els valors (vegeu separator i conjuction més avall).list=false
olist=no
Mostra 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
Mostra una llista dels valors amb el rang més alt. És equivalent a list=true si tots tenen el mateix rang. És equivalent a list=false si només hi ha un valor amb el rang més alt.list=lang
En cas de valors monolingües només treu els corresponents a la llengua del paràmetre lang. Vegeu el paràmetre lang i el formatting pel tipus de valor monolingüe (monolingualtext).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.
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, depenent de la llengua local, o canvis a aplicar en el wiki local definits a Module:Wikidata/i18n. Com a casos generals tractats pel mòdul:- case=gender, segons la definició de sexe o gènere (P21) de l'element (pàgina actual, item o itemgender) treu el valor de forma femenina de l'etiqueta (P2521).
- case=smallcaps, treu l'etiqueta en versaleta.
- Vegeu la documentació de Module:Wikidata/i18n per a altres casos locals.
itemgender=
(opcional) Element on es comprova sexe o gènere (P21) per aplicar la forma femenina si fos necessari, per defecteitem
. S'usa en combinació amb case=gender o case=infoboxlabel.
editicon=
(opcional) Defineix si es posa alguna icona. Per defecte és true. Amb valors editicon=false o editicon=no és false. Les icones poden ser: una icona d'etiqueta en cas que l'etiqueta no s'hagi trobat en la llengua demanada, i un petit llapis com a icona per mostrar i poder editar la declaració a Wikitada (en el futur gestionat per mw:Wikidata Bridge). La icona del llapis es mostrarà si està definida en la configuració pel wiki a Module:Wikidata/i18n amb el valor ["addpencil"] = true.
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.
sandbox=
(opcional) Amb qualsevol valor desvia les crides al Module:Wikidata/proves. El títol de la subpàgina l'obté de MediaWiki:Sandboxlink-subpage-name, en català "proves". El paràmetre es pot usar en l'entorn de plantilla. Com a paràmetre d'invoke o de require no té sentit per les proves. A usar només provisionalment o en previsualització, el mòdul de proves no hauria de tenir cap enllaç permanent.
Paràmetres de formatació
[modifica el codi]formatting=
(opcional) Format desitjat. Valors possibles, per a cada tipus de dada:
Dada amb valor d'element (entity):
formatting=raw
Número identificador de l'element.formatting=label
Etiqueta de l'element en la llengua demanada, alguna de les llengües alternatives o bé com a raw.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 d:.formatting=internallink
Enllaç intern sempre que sigui possible, bé a la pàgina de la Viquipèdia (sitelink) o bé a l'etiqueta (possiblement un enllaç vermell). Com a darrera opció enllaça a Wikidata.formatting=pattern
Format segons un patró usant $1 com a paràmetre a substituir. Pot incloure plantilles o funcions parser amb el format: {{((}}nom-de-la-plantilla{{!}}$1{{))}} o bé {{((}}nom-de-la-plantilla{{!}}nom_paràmetre{{=}}$1{{))}}, o similar.
- 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 valor.formatting=ucinternallink
Combinació del format "ucfirst" i "internallink".
Dada amb valor de text (string):
- General:
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 d'identificador que tenen un enllaç autogenerat per Wikidata, el patró es troba a la pàgina de discussió de la propietat. Pot incloure plantilles i funcions parser (vegeu més amunt per entity).
- Tipus URL:
formatting=weblink
Format d'enllaç extern, posant com a etiqueta el lloc web sense prefixos i amb punts suspensius si enllaça a una pàgina web: [http://www.example.com example.com], [http://example.com/en/page example.com…].
- Tipus identificador extern (external-id):
formatting=externalid
Format d'enllaç extern amb el patró de l'URL definit a format d'URL (P1630) en l'entitat Pid deproperty
.
- Tipus fórmula matemàtica (math):
- El contingut s'engloba amb l'etiqueta <math> que genera una imatge de la fórmula. Vegeu mw:Extension:Math i exemples a fórmula (P2534).
- Tipus notació musical (musical-notation):
- El contingut s'engloba amb l'etiqueta <score> que genera una imatge de la partitura. Vegeu mw:Extension:Score i exemples a motiu musical (P6686). Opcions de format:
formatting=sound
Afegeix l'atribut sound="1" a l'etiqueta generant un fitxer d'àudio que s'incrusta sota la imatge.
Dada amb valor numèric (quantity):
- Per defecte mostra només el número.
formatting=unit
Format numèric incloent la unitat. Si és diferent a 1 ho posa en plural segons Module:Wikidata/Units.formatting=unitcode
Format numèric incloent el codi o l'abreviatura de la unitat definit a símbol de la unitat (P5061). Es pot canviar a Module:Wikidata/Units. Si no el troba usa el nom de la unitat.convert=Qid
Fa una conversió a la unitat indicada pel seu indicador d'element Qid. Les conversions es fan segons els factors indicats en la unitat obtinguda per la unitat Qid en les propietats conversió a unitats del SI (P2370) o conversió a unitats estàndard (P2442), excepte per a temperatures on s'usen fórmules de conversió entre ºC, ºF i ºK. Per exemple, un valor de "74 polzades" amb convert=Q174728 (centímetre (Q174728)) dóna "188 centímetres" segons la conversió "2,54 centímetre" indicada a polzada (Q218593). L'arrodoniment de la conversió es fa mantenint la precisió per defecte del valor original segons el nombre de xifres significatives. Es pot combinar amb formatting=unitcode. Es pot usar també amb formatting=table, vegeu més avall.convert=default
Fa una conversió de les unitats indicades en la taula convert_default de Module:Wikidata/Units.convert=default2
Variant que mostra els dos valors: amb la quantitat convertida i entre parèntesis la quantitat original.convert=M
Fa una conversió a milions, arrodonint sense decimals, si la quantitat és major que 100 milions. Afegeix M davant de la unitat o el codi, per exemple Meuro, M$.
Dada amb valor monolingüe (monolingualtext):
formatting=language
Retorna el codi de llengua corresponent al valor monolingüe, per exemple en el cas de nom oficial (P1448).formatting=text
Recupera el text amb la marca de llengua, si é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 més amunt.
Dada amb valor de coordenades (globecoordinate):
formatting=latitude
Valor de latitud en una declaració de coordenades, en format decimalformatting=longitude
Valor de longitud en una declaració de coordenades, en format decimalformatting=globe
(per defecte) Valor del paràmetre globe amb el format usat en la plantilla {{coord}}, necessari per coordenades fora de la Terra.formatting=$lat...$lon...$globe
Format lliure amb paràmetres $lat i $lon, i opcionalment $globe, a substituir pels valors de latitud i longitud, en format decimal, més globe. Admet la inclusió de plantilles en format no expandit, p. ex. {{((}}coord{{!}}$lat{{!}}$lon{{))}}.formatting=dimension
Valor de dimensió en una declaració de coordenades, en metres, equivalent al paràmetre dim de GeoHack.
Dada amb valor de data (time):
- Per defecte usa el format definit a Module:Wikidata/i18n en la taula datetime segons la precisió de la data. Opcionalment, per precisió de dies:
formatting= sintaxi #time
Accepta qualsevol format vàlid de la funció d'analitzador #time. Per exemple: formatting=d-m-Y (02-11-2024), formatting=[[j xg]] (2 de novembre), formatting=Y (2024). Per defecte, està definit a Module:Wikidata/i18n com "j F Y" (2 novembre 2024), però amb una funció que permet modificar el dia 1r de cada mes.
- Hi afegeix el calendari quan pot ser ambigu: si la data és anterior al 15-10-1582 i està definida en gregorià o si és posterior al 4-10-1582 i està definida en julià. Vegeu calendari gregorià per a més informació.
Paràmetres de taula de propietat i qualificadors
[modifica el codi]propietat | qualificador1 | qualificador2 etc. | |
---|---|---|---|
valors 1a declaració | $0 | $1 | $2, etc. |
2a, etc. | $0 | $1 | $2, etc. |
formatting=table
Una declaració amb qualificadors es considera com una taula de valors mostrada a la dreta. Es pot indicar el format de les files i de cada columna de la taula. Els separadors per a cada fila són per defecte salts de línia (vegeu separator i conjunction més amunt). Si realment voleu el resultat en una taula wiki podeu usar separator=</tr><tr> amb les corresponents etiquetes d'apertura i tancament abans i desprès de l'invoke. Paràmetres específics per a aquest format:
Columnes:
qualifier1 ... qualifierx=
Qualificadors amb un número consecutiu i il·limitat. El paràmetre generalqualifier
és un àlies per qualifier1.qualifierx = Pid1 OR Pid2
Definició alternativa d'un qualificador quan el primer no existeix. Un cas d'ús típic és data (P585) OR data d'inici (P580). No hi ha límit per successius OR. Els espais en blanc d'abans i després són opcionals.qualifierx = Pid1/Pid2
De l'element corresponent a Pid1 (un qualificador o una propietat) obté la propietat superior Pid2. Permet obtenir dades addicionals en la taula encara que definides en l'element superior. Per exemple, per obtenir les línies de metro amb la seva icona: qualifier=P81/P154. Es pot combinar amb l'opció OR prenent prioritat l'OR.qualifierx = /Pid
Equivalent a l'anterior però sense Pid1, obté una segona propietat del mateix element. Permet obtenir dades definides bé en un qualificador o bé en una propietat.
colformat0 ... colformatx=
Format opcional a aplicar a les columnes, usant 0 per la propietat i 1-x pels qualificadors. Accepta la mateixa sintaxi queformatting
per a cada tipus de dada. Vegeu més amunt #Paràmetres de formatació.case0 ... casex=
Cas gramatical a aplicar a cada columna. El paràmetrecase
, sense numeració, s'aplica a tots els valors. Vegeu més amunt #Paràmetres generals.convert0 ... convertx=
Conversió d'unitats a aplicar a cada columna. Vegeu més amunt #Paràmetres de formatació per format numèric.whitelist0 ... whitelistx=
Llista dels ítems a mostrar per a una columna, usant qualsevol separador.blacklist0 ... blacklistx=
Llista dels ítems que no es mostraran per a una columna, usant qualsevol separador. 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)
Files:
rowformat=
Format de les files de propietat més qualificadors. La propietat s'indica amb $0 i els qualificadors $1 a $x. Per defecte ésrowformat=$0 ($1, ... $x)
. Pot incloure marques de llistes * o # i també plantilles o funcions parser amb el format: {{((}}plantilla{{!}}paràmetre{{!}}nom{{=}}paràmetre{{))}}. En cas d'usar el paràmetre "references" (vegeu més amunt) cal indicar on han d'aparèixer les referències amb $R0.rowsubformat1 ... rowsubformatx=
Format previ a aplicar a $1-$x definits en rowformat, només si existeix el valor. Per exemple, "rowformat=$0 $1" i "rowsubformat1=($1)" resulta "$0 ($1)" o bé "$0" si $1 està buit, evitant uns parèntesis buits. Un rowsubformat pot contenir diferents variables $1-$x. Cal tenir en compte que les substitucions en fan de forma seqüencial per ordre numèric, per tant pot incloure un $x posterior però no un d'anterior ja que haurà estat tractat.tablesort=
amb valors de 0 a x, permet ordenar la taula per la propietat (0) o els qualificadors (1 a x). L'ordenació és ascendent alfabèticament, numèricament o per dates, segons el tipus de dada. Accepta múltiples claus usant qualsevol separador, p. ex.tablesort=0/2/1
. Per defecte l'ordenació és pel rang de la propietat (preferent, normal, obsolet) i per l'antiguitat de definició a Wikidata.sorting=-1
inverteix l'ordenació fent-la descendent. Amb qualsevol altre valor, o en el seu defecte, l'ordenació és ascendent. En cas detablesort
amb múltiples claus, el criteri desorting
s'aplicarà a totes per igual.list=false
Treu només la primera fila de la taula, segons l'ordre indicat o l'ordre per defecte.
Funció getLabel
[modifica el codi]Retorna l'etiqueta d'un element.
1=
(primer paràmetre posicional, requerit) Identificador de l'ítem de Wikidata (Qid o Pid). Àlies:item
,from
.lang=
(opcional) Codi de llengua, com en la funció claim. Vegeu més amunt #Paràmetres generals.itemgender=
(opcional) Identificador de l'ítem que determina el gènere a usar, com en la funció claim. Vegeu més amunt #Paràmetres generals.linked=
(opcional) Amb qualsevol valor, excepte 'no', retorna l'etiqueta enllaçada a l'article local o bé a Wikidata.label=
(opcional) Treu l'etiqueta indicada. Només té sentit amb linked= per generar un enllaç amb l'etiqueta de label=.editicon=
(opcional) permet eliminar la icona del llapis, com en la funció claim. Vegeu més amunt #Paràmetres generals.
Funció getParentValues
[modifica el codi]Retorna de forma recursiva valors d'una propietat usant com a etiqueta un valor superior. Per exemple pot estraure l'estructura administativa o la classificació de tàxons.
item=
(opcional) Permet indicar un item (Qid) 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ó (Pid). Per defecte és localitzat a l'entitat territorial administrativa (P131). Admet una llista de valors alternatius usant qualsevol separador.label=
(opcional) Propietat superior a usar com a etiqueta. Per defecte és instància de (P31).upto=
(opcional) Darrera iteració a extraure, si abans no ha trobat cap propietat no existent. Tipus de valors:- upto=etiqueta: darrera etiqueta a consultar, per exemple "upto=estat".
- upto=valor numèric: nombre màxim d'iteracions. Per defecte és 10 com a protecció, normalment un valor més alt del que serà necessari.
uptolabelid=
(opcional) Alternatiu aupto=etiqueta
usant el Qid.uptovalueid=
(opcional) Alternatiu auptolabelid
usant el Qid del valor en lloc de l'etiqueta. Admet valors múltiples usant qualsevol separador. Àlies uptolinkid mantingut provisionalment per compatibilitat.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.showlabelid=
(opcional) Alternatiu alabelshow
usant Qid i qualsevol separador.include_self=true
(opcional) Inclou l'etiqueta de la pròpia pàgina en la llista generada.sorting=-1
(opcional) Ordenació descendent de la llista.last_only=true
(opcional) Només mostra el darrer valor obtingut. Per exemple amb uptolinkid=Qid només mostrarà el valor corresponent a Qid.formatting=
(opcional) Format del valor de la propietat. Per defecte és un enllaç conduït local o a Wikidata (vegeu més amunt formatting de la funció claim per valors entity).valuetext=
(opcional) Propietat a usar com a text de l'enllaç amb el valor 'property' com a enllaç conduït.labelformat=
(opcional) Format de l'etiqueta. Per defecte és "label" (vegeu més amunt formatting de la funció claim per valors entity).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 />.cascade=true
(opcional) opció de presentació amb sagnat. Pot ser útil quan només s'utilitza $1 a rowformat.
Nota: les etiquetes es modifiquen amb un format adequat a les necessitats d'una infotaula segons les definicions a Module:Wikidata/labels. Per exemple, "municipi del Brasil" es presenta com a "Municipi".
Funció linkWithParentLabel
[modifica el codi]Crea un enllaç amb l'etiqueta d'una propietat superior.
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". Accepta valors alternatius amb qualsevol separador, igual que el paràmetre "property" de la funció claim.
Funció yearsOld
[modifica el codi]Retorna l'edat avaluant la data de naixement i la data de defunció o en el seu defecte la data actual. Si les dues dates no tenen precisió de dia mostra el rang amb un marge d'1 o de 10 anys.
La seva sintaxi és: {{#invoke:Wikidata|yearsOld|formatting= |item= }}
. Els paràmetres item
i formatting
són opcionals. Per defecte retorna la quantitat.
formatting=unit
(opcional) Obté la unitat de la taula i18n["years-old"] de Module:Wikidata/i18n pel singular o el plural, a més de paucal usat en llengües eslaves com el rus. Vegeu la funció parser PLURAL a mw:Help:Magic words#Localization.formatting=pattern
(opcional) Format amb un patró usant $1 com a variable per la quantitat. Un exemple típic és " ($1 anys)". En aquest cas no avalua l'expressió en singular, plural o paucal i obté la unitat de anys (Q24564698). Una alternativa és usar un patró uniforme definit en la taula i18n["years-old"] que admet el paràmetre $1.
Utilitats
[modifica el codi]getSiteLink
Retorna el títol de pàgina local per un element donat. Sintaxi:{{#invoke:Wikidata|getSiteLink|<Qid>|<wiki>}}
- Sense cap paràmetre retorna la pròpia pàgina. Proporcionant l'id retornarà la pàgina local enllaçada en l'element corresponent. En cas de no existir o ser erroni no retorna res. Amb un segon paràmetre amb un codi de wiki obté la pàgina en el wiki especificat (enwiki, frwiki,... cawiktionary, etc.)
lang
Retorna el codi de llengua tal com el gestiona la funció claim. Vegeu #Paràmetres generals més amunt. Sintaxi:{{#invoke:Wikidata|lang|{{{lang|}}}}}
- El paràmetre
lang
és el codi de la llengua aportat explícitament.
numStatements
Retorna el nombre d'instàncies que té una propietat multi-valor. Permet decidir el tractament a donar a llistes llargues. Sintaxi:{{#invoke:Wikidata|numStatements|<Pid>|item={{{item|}}}
- Exemple: {{#invoke:Wikidata|numStatements|P47|item=Q1861}} → 6
validProperty
Retorna "null" si la propietat no existeix, o només té valors amb marcador "sense valor" o "valor desconegut" o obsolet. Sintaxi:{{#invoke:<nowiki>{{ROOTPAGENAME}}<nowiki>|validProperty|<Pid>|item={{{item|}}}
- Es pot usar com a alternativa a #property. Per compatibilitat amb aquesta funció parser, el paràmetre
from
és un àlies deitem
.
- Per a funcions de depuració vegeu Module:Wikidata/debug.
Redireccions a Wikidata
[modifica el codi]Un element de Wikidata pot ser una redirecció a un altre element, sovint com a resultat d'una fusió. Els valors d'una propietat poden ser provisionalment una redirecció, normalment corregit per bot al cap d'una setmana. El tractament de les redireccions és el següent:
- Funció claim
- Amb formatting=raw no retorna el Qid redirigit sinó el Qid final de la redirecció.
- Amb paràmetres whitelist o blacklist, si la llista de valors inclou alguna redirecció, considera tant el Qid redirigit com el nou Qid final.
- Funció getLabel
- Si es demana l'etiqueta d'un Qid redirigit, la buscarà en el Qid final.
En tots els casos afegeix un rastreig per poder corregir en les plantilles els Qid redirigits. Es poden trobar a Special:WhatLinksHere/Template:Track/wikidata/redirect.
La resolució de redireccions a Wikidata està pendent de phab:T157868. La solució tècnica adoptada provisionalment pot provocar un alt consum de recursos si un element no té cap etiqueta en la llengua local ni en les llengües alternatives. Es recomana comprovar el rastreig Special:WhatLinksHere/Template:Track/wikidata/label per afegir les etiquetes que manquen.
Crides des d'un altre mòdul
[modifica el codi]Totes les funcions (claim, getLabel, getParentValues, linkWithParentLabel, yearsOld, lang) es poden cridar des d'altres mòduls via require
amb els mateixos paràmetres proporcionats en una taula, per exemple:
- require("Module:Wikidata").claim{item="Q...", property="P...", ...}
- require("Module:Wikidata").getLabel({"Q...", ['lang']="ca"})
Les funcions claim i getLabel retornen com a segon valor la variable untranslated (nil o true) per a tractament específic en mòduls d'infotaules.
Exemples
[modifica el codi]Els exemples a continuació són mostres provades en les pàgines corresponents. Es poden fer proves a w: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 (Q260) 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:
- {{#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:
- berlin.de…
- Llista de valors:
- {{#invoke:Wikidata | claim | property=P47}} a l'Alcoià (Q746061) dóna:
- l'Alacantí, l'Alt Vinalopó, el Comtat, la Marina Baixa, la Vall d'Albaida i el 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.7019
- {{#invoke:Wikidata | claim | property=P625 | formatting=longitude}} dóna: -0.4772
Dependències
[modifica el codi]- Subpàgines relatives al mòdul principal. El títol del mòdul està definit a la variable
module_title =
. En una nova instal·lació amb un títol diferent cal modificar aquesta variable.- ../i18n (opcional): traduccions de missatges i formats locals. Si s'usa
lang
diferent al local cerca la subpàgina corresponent, per exemple ../i18n/eu. Si no existeix, surt en anglès per defecte. - ../Units (opcional): tractament d'unitats, en plural o amb codi. Si no existeix, treu el nom complet de la unitat en singular.
- ../labels (opcional): excepcions i correccions d'etiquetes per a una infotaula.
- ../debug: pot aparèixer ocasionalment per la funció track de manteniment.
- ../i18n (opcional): traduccions de missatges i formats locals. Si s'usa
- Missatges Mediawiki utilitzats depenent de la llengua:
- Mediawiki:Comma-separator, Mediawiki:And, Mediawiki:Word-separator
- Mediawiki:Wikibase-snakview-snaktypeselector-novalue, Mediawiki:Wikibase-snakview-snaktypeselector-somevalue
- Mediawiki:Wikibase-time-calendar-gregorian, Mediawiki:Wikibase-time-calendar-julian
- Mediawiki:Translate-taction-translate
- MediaWiki:Sandboxlink-subpage-name
- Si és necessari es poden crear, o modificar, a Translatewiki. Per accedir-hi directament activeu l'enllaç corresponent amb el títol del missatge i el codi de llengua
[[translatewiki:MediaWiki:<missatge>/<lang>]]
.
Vegeu també
[modifica el codi]- Llibreria mw.wikibase. Són les funcions bàsiques que es poden trobar a Module:Wikibase.
-- version 20210304 from master @cawiki
local p = {}
-- Initialization of variables --------------------
local i18n = { -- internationalisation at [[Module:Wikidata/i18n]]
["errors"] = {
["property-not-found"] = "Property not found.",
["qualifier-not-found"] = "Qualifier not found.",
},
["datetime"] = {
-- $1 is a placeholder for the actual number
["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 1st century AD dates
[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] = "$100000 years", -- precision: hundred thousand years; thousand separators added afterwards
[5] = "$10000 years", -- precision: ten thousand years; thousand separators added afterwards
[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
["hms"] = {["hours"] = "h", ["minutes"] = "m", ["seconds"] = "s"}, -- duration: xh xm xs
},
["years-old"] = {
["singular"] = "", -- year old, as in {{PLURAL:$1|singular|plural}}
["plural"] = "", -- years old
["paucal"] = "", -- for languages with 3 plural forms as in {{PLURAL:$1|singular|paucal|plural}}
},
["cite"] = { -- cite parameters
["title"] = "title",
["author"] = "author",
["date"] = "date",
["pages"] = "pages",
["language"] = "language",
-- cite web parameters
["url"] = "url",
["website"] = "website",
["access-date"] = "access-date",
["archive-url"] = "archive-url",
["archive-date"] = "archive-date",
["publisher"] = "publisher",
["quote"] = "quote",
-- cite journal parameters
["work"] = "work",
["issue"] = "issue",
["issn"] = "issn",
["doi"] = "doi"
},
-- default local wiki settings
["addpencil"] = false, -- adds a pencil icon linked to Wikidata statement, planned to overwrite by Wikidata Bridge
["categorylabels"] = "", -- Category:Pages with Wikidata labels not translated (void for no local category)
["categoryprop"] = "", -- Category:Pages using Wikidata property $1 (void for no local category)
["categoryref"] = "", -- Category:Pages with references from Wikidata (void for no local category)
["addfallback"] = {} -- additional fallback language codes
}
local cases = {} -- functions for local grammatical cases defined at [[Module:Wikidata/i18n]]
local required = ... -- variadic arguments from require function
local wiki =
{
langcode = mw.language.getContentLanguage().code,
module_title = required or mw.getCurrentFrame():getTitle()
}
local untranslated -- used in infobox modules: nil or true
local _ -- variable for unused returned values, avoiding globals
-- 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(lang)
local exist, res = pcall(require, wiki.module_title .. "/i18n")
if exist and next(res) ~= nil then
tableMerge(i18n, res.i18n)
cases = res.cases
end
if lang ~= wiki.langcode then
exist, res = pcall(require, wiki.module_title .. "/i18n/" .. lang)
if exist and next(res) ~= nil then
tableMerge(i18n, res.i18n)
tableMerge(cases, res.cases)
end
end
end
-- Table of language codes: requested or default and its fallbacks
local function findLang(langcode)
if mw.language.isKnownLanguageTag(langcode or '') == false then
local cframe = mw.getCurrentFrame()
local pframe = cframe:getParent()
langcode = pframe and pframe.args.lang
if mw.language.isKnownLanguageTag(langcode or '') == false then
if not mw.title.getCurrentTitle().isContentPage then
langcode = cframe:preprocess('{{int:lang}}')
end
if mw.language.isKnownLanguageTag(langcode or '') == false then
langcode = wiki.langcode
end
end
end
loadI18n(langcode)
local languages = mw.language.getFallbacksFor(langcode)
table.insert(languages, 1, langcode)
if langcode == wiki.langcode then
for _, l in ipairs(i18n.addfallback) do
table.insert(languages, l)
end
end
return languages
end
-- Argument is 'set' when it exists (not nil) or when it is not an empty string.
local function isSet(var)
return not (var == nil or (type(var) == 'string' and mw.text.trim(var) == ''))
end
-- Set local case to a label
local function case(localcase, label, ...)
if not isSet(label) then return label end
if type(localcase) == "function" then
return localcase(label)
elseif localcase == "smallcaps" then
return '<span style="font-variant: small-caps;">' .. label .. '</span>'
elseif cases[localcase] then
return cases[localcase](label, ...)
end
return label
end
-- get safely a serialized snak
local function getSnak(statement, snaks)
local ret = statement
for i, v in ipairs(snaks) do
if not ret then return end
ret = ret[v]
end
return ret
end
-- mw.wikibase.getLabelWithLang or getLabelByLang with a table of languages
local function getLabelByLangs(id, languages)
local label
local lang
for _, l in ipairs(languages) do
if l == wiki.langcode then
-- using getLabelWithLang when possible instead of getLabelByLang, do not solve redirects pending phab:T157868
label, l = mw.wikibase.getLabelWithLang(id)
else
label = mw.wikibase.getLabelByLang(id, l)
end
if label then
lang = l
break
end
end
return label, lang
end
-- getBestStatements if bestrank=true, else getAllStatements with no deprecated
local function getStatements(entityId, property, bestrank)
local claims = {}
if not (entityId and mw.ustring.match(property, "^P%d+$")) then return claims end
if bestrank then
claims = mw.wikibase.getBestStatements(entityId, property)
else
local allclaims = mw.wikibase.getAllStatements(entityId, property)
for _, c in ipairs(allclaims) do
if c.rank ~= "deprecated" then
table.insert(claims, c)
end
end
end
return claims
end
-- Is gender femenine? true or false
local function feminineGender(id)
local claims = mw.wikibase.getBestStatements(id or mw.wikibase.getEntityIdForCurrentPage(),'P21')
local gender_id = getSnak(claims, {1, "mainsnak", "datavalue", "value", "id"})
if gender_id == "Q6581072" or gender_id == "Q1052281" or gender_id == "Q43445" then -- female, transgender female, female organism
return true
end
return false
end
-- Fetch female form of label
local function feminineForm(id, lang)
local feminine_claims = getStatements(id, 'P2521')
for _, feminine_claim in ipairs(feminine_claims) do
if getSnak(feminine_claim, {'mainsnak', 'datavalue', 'value', 'language'}) == lang then
return feminine_claim.mainsnak.datavalue.value.text
end
end
end
-- Add an icon for no label in requested language
local function addLabelIcon(label_id, lang, uselang, icon)
local ret_lang, ret_icon = '', ''
if icon then
if lang and lang ~= uselang then
ret_lang = " <sup>(" .. lang .. ")</sup>"
end
if label_id and (lang == nil or lang ~= uselang) then
local namespace = ''
if string.sub(label_id, 1, 1) == 'P' then
namespace = 'Property:'
end
ret_icon = " [[File:Noun Project label icon 1116097 cc mirror.svg|10px|baseline|"
.. mw.message.new('Translate-taction-translate'):inLanguage(uselang):plain()
.. "|link=https://www.wikidata.org/wiki/" .. namespace .. label_id .. "?uselang=" .. uselang .. "]]"
untranslated = true
end
if isSet(i18n.categorylabels) and lang ~= uselang and uselang == wiki.langcode then
ret_icon = ret_icon .. '[[' .. i18n.categorylabels .. (lang and ']]' or '/Q]]')
end
end
return ret_lang .. ret_icon
end
-- editicon values: true/false (no=false), right, void defaults to i18n.addpencil
-- labelicon only by parameter
local function setIcons(arg, parg)
local val = arg == nil and parg or arg
local edit_icon, label_icon
if not isSet(val) then
edit_icon, label_icon = i18n.addpencil, true
elseif val == false or val == "false" or val == "no" then
edit_icon, label_icon = false, false
else
edit_icon, label_icon = val, true
end
return edit_icon, label_icon
end
-- Add an icon for editing a statement with requirements for Wikidata Bridge
local function addEditIcon(parameters)
local ret = ''
if parameters.editicon and parameters.id and parameters.property then
local icon_style = parameters.editicon == "right" and ' style="float: right;"' or ''
ret = ' <span class="penicon" data-bridge-edit-flow="single-best-value"' .. icon_style .. '>'
.. "[[File:Arbcom ru editing.svg|10px|baseline|"
.. string.gsub(mw.message.new('Wikibase-client-data-bridge-bailout-suggestion-go-to-repo-button'):inLanguage(parameters.lang[1]):plain(), '{{WBREPONAME}}', 'Wikidata')
.. "|link=https://www.wikidata.org/wiki/" .. parameters.id .. "?uselang=" .. parameters.lang[1] .. "#" .. parameters.property .. "]]"
.. "</span>"
if isSet(i18n.categoryprop) then
ret = ret .. "[[" .. string.gsub(i18n.categoryprop, '$1', parameters.property) .. "]]"
end
end
return ret
end
-- add edit icon to the last element of a table
local function addEditIconTable(thetable, parameters)
if #thetable == 0 or parameters.editicon == false then
return thetable
end
local last_element = thetable[#thetable]
local the_icon = addEditIcon(parameters)
-- add it before last html closing tags
local tags = ''
local rev_element = string.reverse(last_element)
for tag in string.gmatch(rev_element, '(>%l+/<)') do
if string.match(rev_element, '^' .. tags .. tag) then
tags = tags .. tag
else
break
end
end
local last_tags = string.reverse(tags)
local offset = string.find(last_element, last_tags .. '$')
if offset then
thetable[#thetable] = string.sub(last_element, 1, offset - 1) .. the_icon .. last_tags
else
thetable[#thetable] = last_element .. the_icon
end
return thetable
end
-- Escape Lua captures
local function captureEscapes(text)
return mw.ustring.gsub(text, "(%%%d)", "%%%1")
end
-- expandTemplate or callParserFunction
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
local subparts = mw.ustring.find(parts[i], "=")
if subparts then
local param_name = mw.ustring.sub(parts[i], 1, subparts - 1)
local param_value = mw.ustring.sub(parts[i], subparts + 1, -1)
-- reconstruct broken links by parts
if i < #parts and mw.ustring.find(param_value, "[[", 1, true) and not mw.ustring.find(param_value, "]]", 1, true) then
parameters[param_name] = param_value
local part_next = i + 1
while parts[part_next] and mw.ustring.find(parts[part_next], "]]", 1, true) do
parameters[param_name] = parameters[param_name] .. "|" .. parts[part_next]
part_next = part_next + 1
end
else
parameters[param_name] = param_value
end
elseif not mw.ustring.find(parts[i], "]]", 1, true) then
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 = captureEscapes(braces_expanded)
text = mw.ustring.gsub(text, "{{" .. braces .. "}}", braces_expanded)
end
return text
end
-- Resolve Wikidata redirects, pending phab:T157868
local function resolveEntityId(id)
if not id or not mw.wikibase.isValidEntityId(id) then return id end
-- if no label in English, maybe it is a redirect
-- not using mw.title.new(id).isRedirect as it is expensive
-- currently getLabelByLang does not follows redirects
if mw.wikibase.getLabelByLang(id, 'en') == nil then
local entity = mw.wikibase.getEntity(id) -- expensive function
if not entity then return nil end
if id ~= entity.id then
-- Qid redirected to be fixed
-- see [[Special:WhatLinksHere/Template:Track/wikidata/redirect]]
require(wiki.module_title .. '/debug').track('redirect')
require(wiki.module_title .. '/debug').track('redirect/' .. id)
else
-- no redirect and no English label, fix it to avoid expensive functions
require(wiki.module_title .. '/debug').track('label')
require(wiki.module_title .. '/debug').track('label/' .. id)
end
return entity.id
end
return id
end
-- format data type math
local function printDatatypeMath(data)
return mw.getCurrentFrame():callParserFunction('#tag:math', data)
end
-- format data type musical-notation
local function printDatatypeMusical(data, formatting)
local attr = {}
if formatting == 'sound' then
attr.sound = 1
end
return mw.getCurrentFrame():extensionTag('score', data, attr)
end
-- format data type string
local function printDatatypeString(data, parameters)
if mw.ustring.find((parameters.formatting or ''), '$1', 1, true) then -- formatting = a pattern
return expandBraces(mw.ustring.gsub(parameters.formatting, '$1', {['$1'] = data}), parameters.formatting)
elseif parameters.case then
return case(parameters.case, data, parameters.lang[1], feminineGender(parameters.id))
end
local data_number = string.match(data, "^%d+")
if data_number then -- sort key by initial number and remaining string
local sortkey = string.format("%019d", data_number * 1000)
return data, sortkey .. string.sub(data, #data_number + 1)
end
return data
end
-- format data type url
local function printDatatypeUrl(data, parameters)
if parameters.formatting == 'weblink' then
local label_parts = mw.text.split(string.gsub(data, '/$', ''), '/')
local label = string.gsub(label_parts[3], '^www%.', '')
if #label_parts > 3 then
label = label .. '…'
end
return '[' .. data .. ' ' .. label .. ']'
end
return printDatatypeString(data, parameters)
end
-- format data type external-id
local function printDatatypeExternal(data, parameters)
if parameters.formatting == 'externalid' then
local p_stat = mw.wikibase.getBestStatements(parameters.property, 'P1630') -- formatter URL
local p_link_pattern = getSnak(p_stat, {1, "mainsnak", "datavalue", "value"})
if p_link_pattern then
local p_link = mw.ustring.gsub(p_link_pattern, '$1', {['$1'] = data})
return '[' .. p_link .. ' ' .. data .. ']'
end
end
return printDatatypeString(data, parameters)
end
-- format data type commonsMedia and geo-shape
local function printDatatypeMedia(data, parameters)
local icon
if not string.find((parameters.formatting or ''), '$1', 1, true) then
icon = "no-icon"
if not string.find(data, '^Data:') then
data = mw.uri.encode(data, 'PATH') -- encode special characters in filename
end
end
return printDatatypeString(data, parameters), icon
end
-- format data type globe-coordinate
local function printDatatypeCoordinate(data, formatting)
local function globes(globe_id)
local globes = {['Q3134']='callisto',['Q596']='ceres',['Q15040']='dione',['Q2']='earth',['Q3303']='enceladus',
['Q3143']='europa',['Q17975']='phoebe',['Q3169']='ganymede',['Q3123']='io',['Q17958']='iapetus',
['Q308']='mercury',['Q15034']='mimas',['Q405']='moon',['Q15050']='rhea',['Q15047']='tethys',
['Q111']='mars',['Q2565']='titan',['Q3359']='triton',['Q313']='venus',['Q3030']='vesta'}
return globes[globe_id]
end
local function roundPrecision(num, prec)
if prec == nil or prec <= 0 then return num end
local sig = 10^math.floor(math.log10(prec)+.5) -- significant figure from sexagesimal precision: 0.00123 -> 0.001
return math.floor(num / sig + 0.5) * sig
end
local precision = data.precision
local latitude = roundPrecision(data.latitude, precision)
local longitude = roundPrecision(data.longitude, precision)
if formatting and string.find(formatting, '$lat', 1, true) and string.find(formatting, '$lon', 1, true) then
local ret = mw.ustring.gsub(formatting, '$l[ao][tn]', {['$lat'] = latitude, ['$lon'] = longitude})
if string.find(formatting, '$globe', 1, true) then
local myglobe = 'earth'
if isSet(data.globe) then
local globenum = mw.text.split(data.globe, 'entity/')[2] -- http://www.wikidata.org/wiki/Q2
myglobe = globes(globenum) or 'earth'
end
ret = mw.ustring.gsub(ret, '$globe', myglobe)
end
return expandBraces(ret, formatting)
elseif formatting == 'latitude' then
return latitude, "no-icon"
elseif formatting == 'longitude' then
return longitude, "no-icon"
elseif formatting == 'dimension' then
return data.dimension, "no-icon"
else --default formatting='globe'
if isSet(data.globe) == false or data.globe == 'http://www.wikidata.org/entity/Q2' then
return 'earth', "no-icon"
else
local globenum = mw.text.split(data.globe, 'entity/')[2]
return globes(globenum) or globenum, "no-icon"
end
end
end
-- Local functions for data value quantity
local function unitSymbol(id, lang) -- get unit symbol or code
local unit_symbol = ''
if lang == wiki.langcode and pcall(require, wiki.module_title .. "/Units") then
unit_symbol = require(wiki.module_title .. "/Units").getUnit(0, '', id, true)
end
if unit_symbol == '' then
-- fetch it
local claims = mw.wikibase.getBestStatements(id, 'P5061')
if #claims > 0 then
local langclaims = {}
table.insert(lang, 'mul') -- multilingual as last try
for _, snak in ipairs(claims) do
local snak_language = getSnak(snak, {"mainsnak", "datavalue", "value", "language"})
if snak_language and not langclaims[snak_language] then -- just the first one by language
langclaims[snak_language] = snak.mainsnak.datavalue.value.text
end
end
for _, l in ipairs(lang) do
if langclaims[l] then
return langclaims[l]
end
end
end
end
return unit_symbol
end
local function getUnit(amount, id, parameters) -- get unit symbol or name
local suffix = ''
if parameters.formatting == "unitcode" then
-- get unit symbol
local unit_symbol = unitSymbol(id, parameters.lang)
if isSet(unit_symbol) then
suffix = unit_symbol
end
end
if suffix == '' then -- formatting=unit, or formatting=unitcode not found
-- get unit name
local unit_label, lang = getLabelByLangs(id, parameters.lang)
if lang == wiki.langcode and pcall(require, wiki.module_title .. "/Units") then
suffix = require(wiki.module_title .. "/Units").getUnit(amount, unit_label, id, false)
else
suffix = (unit_label or id) .. addLabelIcon(id, lang, parameters.lang[1], parameters.labelicon)
end
end
if suffix ~= '' then
suffix = ' ' .. suffix
end
return suffix
end
local function roundDefPrecision(in_num, factor)
-- rounds out_num with significant figures of in_num (default precision)
local out_num = in_num * factor
if factor/60 == math.floor(factor/60) or out_num == 0 then -- sexagesimal integer or avoiding NaN
return out_num
end
-- first, count digits after decimal mark, handling cases like '12.345e6'
local exponent, prec
local integer, dot, decimals, expstr = in_num:match('^(%d*)(%.?)(%d*)(.*)')
local e = expstr:sub(1, 1)
if e == 'e' or e == 'E' then
exponent = tonumber(expstr:sub(2))
end
if dot == '' then
prec = -integer:match('0*$'):len()
else
prec = #decimals
end
if exponent then
-- So '1230' and '1.23e3' both give prec = -1, and '0.00123' and '1.23e-3' give 5.
prec = prec - exponent
end
-- significant figures
local in_bracket = 10^-prec -- -1 -> 10, 5 -> 0.00001
local out_bracket = in_bracket * out_num / in_num
out_bracket = 10^math.floor(math.log10(out_bracket)+.5) -- 1230 -> 1000, 0.00123 -> 0.001
-- round it (credit to Luc Bloom from http://lua-users.org/wiki/SimpleRound)
return math.floor(out_num/out_bracket + (out_num >=0 and 1 or -1) * 0.5) * out_bracket
end
-- format data type quantity
local function printDatatypeQuantity(data, parameters)
local amount = data.amount
amount = mw.ustring.gsub(amount, "%+", "")
local suffix = ""
local conv_amount, conv_suffix
if string.sub(parameters.formatting or '', 1, 4) == "unit" or string.sub(parameters.formatting or '', 1, 8) == "duration" or parameters.convert then
local unit_id = data.unit
unit_id = mw.ustring.sub(unit_id, mw.ustring.find(unit_id, "Q"), -1)
if string.sub(unit_id, 1, 1) == "Q" then
suffix = getUnit(amount, unit_id, parameters)
local convert_to
if parameters.convert == "default" or parameters.convert == "default2" then
local exist, units = pcall(require, wiki.module_title .. "/Units")
if exist and units.convert_default and next(units.convert_default) ~= nil then
convert_to = units.convert_default[unit_id]
end
elseif string.sub(parameters.convert or '', 1, 1) == "Q" then
convert_to = resolveEntityId(parameters.convert)
elseif string.sub(parameters.formatting or '', 1, 8) == "duration" then
convert_to = 'Q11574' -- seconds
end
if convert_to and convert_to ~= unit_id then
-- convert units
local conv_temp = { -- formulae for temperatures ºC, ºF, ªK: [from] = {[to] = 'formula'}
['Q25267'] = {['Q42289'] = '$1*1.8+32', ['Q11597'] = '$1+273.15'},
['Q42289'] = {['Q25267'] = '($1-32)/1.8', ['Q11597'] = '($1+459.67)*5/9'},
['Q11597'] = {['Q25267'] = '$1-273.15', ['Q42289'] = '($1-273.15)*1.8000+32.00'}
}
if conv_temp[unit_id] and conv_temp[unit_id][convert_to] then
local amount_f = mw.getCurrentFrame():callParserFunction('#expr', mw.ustring.gsub(conv_temp[unit_id][convert_to], "$1", amount))
conv_amount = math.floor(tonumber(amount_f) + 0.5)
else
local conversions = getStatements(unit_id, 'P2442') -- conversion to standard unit
table.insert(conversions, mw.wikibase.getBestStatements(unit_id, 'P2370')[1]) -- conversion to SI unit
for _, conv in ipairs(conversions) do
if conv.mainsnak.snaktype == 'value' then -- no somevalue nor novalue
if conv.mainsnak.datavalue.value.unit == "http://www.wikidata.org/entity/" .. convert_to then
conv_amount = roundDefPrecision(amount, tonumber(conv.mainsnak.datavalue.value.amount))
break
end
end
end
end
if conv_amount then
conv_suffix = getUnit(conv_amount, convert_to, parameters)
end
elseif parameters.convert == 'M' and tonumber(amount) > 10^8 then
conv_amount = math.floor(amount/10^6 + 0.5)
conv_suffix = ' M' .. string.sub(suffix, 2)
end
end
end
local lang_obj = mw.language.new(parameters.lang[1])
local sortkey = string.format("%019d", tonumber(amount) * 1000)
if string.sub(parameters.formatting or '', 1, 8) == "duration" then
local sec = tonumber(conv_amount or amount)
if parameters.formatting == 'durationhms' or parameters.formatting == 'durationh:m:s' then
local intervals = {"hours", "minutes", "seconds"}
local sec2table = lang_obj:getDurationIntervals(sec, intervals)
sec2table["seconds"] = (sec2table["seconds"] or 0) + tonumber("." .. (tostring(sec):match("%.(%d+)") or "0")) -- add decimals
local duration = ''
for i, v in ipairs(intervals) do
if parameters.formatting == 'durationh:m:s' then
if i == 1 and sec2table[v] then
duration = duration .. sec2table[v] .. ":"
elseif i == 2 then
duration = duration .. string.format("%02d", sec2table[v] or 0) .. ":"
elseif i == 3 then
local sec_str = tostring(lang_obj:formatNum(sec2table[v] or 0))
duration = duration .. (sec2table[v] < 10 and "0" or "") .. sec_str
end
elseif sec2table[v] then
duration = duration .. lang_obj:formatNum(sec2table[v]) .. i18n.datetime.hms[v] .. (i < 3 and " " or "")
end
end
return duration
else
return lang_obj:formatDuration(sec)
end
end
if parameters.case then
amount = case(parameters.case, amount, parameters.lang[1])
elseif parameters.formatting ~= 'raw' then
amount = lang_obj:formatNum(tonumber(amount))
end
if conv_amount then
local conv_sortkey = string.format("%019d", conv_amount * 1000)
conv_amount = lang_obj:formatNum(conv_amount)
if parameters.convert == 'default2' then
return conv_amount .. conv_suffix .. ' (' .. amount .. suffix .. ')', conv_sortkey
else
return conv_amount .. conv_suffix, conv_sortkey
end
elseif mw.ustring.find((parameters.formatting or ''), '$1', 1, true) then -- formatting with pattern
amount = mw.ustring.gsub(parameters.formatting, '$1', {['$1'] = amount})
end
return amount .. suffix, sortkey
end
-- format data type time
local function printDatatypeTime(data, parameters)
-- Dates and times are stored in ISO 8601 format
local timestamp = data.time
local post_format
local calendar_add = ""
local precision = data.precision or 11
if string.sub(timestamp, 1, 1) == '-' then
post_format = i18n.datetime["bc"]
elseif string.sub(timestamp, 2, 3) == '00' then
post_format = i18n.datetime["ad"]
elseif precision > 8 then
-- calendar model
local calendar_model = {["Q12138"] = "gregorian", ["Q1985727"] = "gregorian", ["Q11184"] = "julian", ["Q1985786"] = "julian"}
local calendar_id = mw.text.split(data.calendarmodel, 'entity/')[2]
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
end
local function formatTime(form, stamp)
local pattern
if type(form) == "function" then
pattern = form(stamp)
else
pattern = form
end
stamp = tostring(stamp)
if mw.ustring.find(pattern, "$1") then
return mw.ustring.gsub(pattern, "$1", stamp)
elseif string.sub(stamp, 1, 1) == '-' then -- formatDate() only supports years from 0
stamp = '+' .. string.sub(stamp, 2)
elseif string.sub(stamp, 1, 1) ~= '+' then -- not a valid timestamp, it is a number
stamp = string.format("%04d", stamp)
end
local ret = mw.language.new(parameters.lang[1]):formatDate(pattern, stamp)
ret = string.gsub(ret, "^(%[?%[?)0+", "%1") -- supress leading zeros
ret = string.gsub(ret, "( %[?%[?)0+", "%1")
return ret
end
local function postFormat(t)
if post_format and mw.ustring.find(post_format, "$1") then
return mw.ustring.gsub(post_format, "$1", t)
end
return t
end
local intyear = tonumber(string.match(timestamp, "[+-](%d+)"))
local ret = ""
if precision <= 5 then -- precision is 10000 years or more
local factor = 10 ^ ((5 - precision) + 4)
local y2 = math.ceil(math.abs(intyear) / factor)
local relative = formatTime(i18n.datetime[precision], y2)
if post_format == i18n.datetime["bc"] then
ret = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative)
else
ret = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative)
end
local ret_number = string.match(ret, "%d+")
if ret_number ~= nil then
ret = mw.ustring.gsub(ret, ret_number, mw.language.new(parameters.lang[1]):formatNum(tonumber(ret_number)))
end
elseif precision == 6 or precision == 7 then -- millennia or centuries
local card = math.floor((intyear - 1) / 10^(9 - precision)) + 1
ret = formatTime(i18n.datetime[precision], card)
ret = postFormat(ret)
elseif precision == 8 then -- decades
local card = math.floor(math.abs(intyear) / 10) * 10
ret = formatTime(i18n.datetime[8], card)
ret = postFormat(ret)
elseif intyear > 9999 then -- not a valid timestamp
return
elseif precision == 9 or parameters.formatting == 'Y' then -- precision is year
ret = formatTime(i18n.datetime[9], intyear)
ret = postFormat(ret) .. calendar_add
elseif precision == 10 then -- month
ret = formatTime(i18n.datetime[10], timestamp .. " + 1 day") -- formatDate yyyy-mm-00 returns the previous month
ret = postFormat(ret) .. calendar_add
else -- precision 11, day
ret = formatTime(parameters.formatting or i18n.datetime[11], timestamp)
ret = postFormat(ret) .. calendar_add
end
return ret, timestamp
end
-- format data value wikibase-entityid: types wikibase-item, wikibase-property
local function printDatatypeEntity(data, parameters)
local entity_id = data['id']
if parameters.formatting == 'raw' then
return entity_id, entity_id
end
local entity_page = 'Special:EntityPage/' .. entity_id
local label, lang = getLabelByLangs(entity_id, parameters.lang)
local sitelink = mw.wikibase.getSitelink(entity_id)
local parameter = parameters.formatting
local labelcase = label or sitelink
if parameters.gender == 'feminineform' then
labelcase = feminineForm(entity_id, lang) or labelcase
end
if parameters.case ~= 'gender' then
labelcase = case(parameters.case, labelcase, lang, parameters.lang[1], entity_id, parameters.id)
end
local ret1, ret2
if parameter == 'label' then
ret1 = labelcase or entity_id
ret2 = labelcase or entity_id
elseif parameter == 'sitelink' then
ret1 = (sitelink or 'd:' .. entity_page)
ret2 = sitelink or entity_id
elseif mw.ustring.find((parameter or ''), '$1', 1, true) then -- formatting = a pattern
ret1 = mw.ustring.gsub(parameter, '$1', labelcase or entity_id)
ret1 = expandBraces(ret1, parameter)
ret2 = labelcase or entity_id
else
if parameter == "ucfirst" or parameter == "ucinternallink" then
if labelcase and lang then
labelcase = mw.language.new(lang):ucfirst(labelcase)
end
-- 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 string.match(parameter or '', 'internallink$') and not mw.wikibase.getEntityIdForTitle(label) then
ret1 = '[[' .. label .. '|' .. labelcase .. ']]'
ret2 = labelcase
else
ret1 = '[[d:' .. entity_page .. '|<span style="color:#5f9cbb;">' .. (labelcase or entity_id) .. '</span>]]'
ret2 = labelcase or entity_id
end
end
return ret1 .. addLabelIcon(entity_id, lang, parameters.lang[1], parameters.labelicon), ret2
end
-- format data type monolingualtext
local function printDatatypeMonolingual(data, parameters)
-- data fields: language [string], text [string]
if parameters.list == "lang" and data["language"] ~= parameters.lang[1] then
return
elseif parameters.list == "notlang" 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('<span lang="$1">$2</span>', '$[12]', {["$1"]=data["language"], ["$2"]=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 getSnakValue(snak, parameters)
if snak.snaktype == 'value' then
-- see Special:ListDatatypes
if snak.datatype == "string" then
return printDatatypeString(snak.datavalue.value, parameters)
-- other data value string, tabular-data not implemented
elseif snak.datatype == "commonsMedia" or snak.datatype == "geo-shape" then
return printDatatypeMedia(snak.datavalue.value, parameters)
elseif snak.datatype == "url" then
return printDatatypeUrl(snak.datavalue.value, parameters)
elseif snak.datatype == "external-id" then
return printDatatypeExternal(snak.datavalue.value, parameters)
elseif snak.datatype == 'math' then
return printDatatypeMath(snak.datavalue.value)
elseif snak.datatype == 'musical-notation' then
return printDatatypeMusical(snak.datavalue.value, parameters.formatting)
-- other data types
elseif snak.datatype == 'wikibase-item' or snak.datatype == 'wikibase-property' then
return printDatatypeEntity(snak.datavalue.value, parameters)
elseif snak.datatype == 'monolingualtext' then
return printDatatypeMonolingual(snak.datavalue.value, parameters)
elseif snak.datatype == "globe-coordinate" then
return printDatatypeCoordinate(snak.datavalue.value, parameters.formatting)
elseif snak.datatype == "quantity" then
return printDatatypeQuantity(snak.datavalue.value, parameters)
elseif snak.datatype == "time" then
return printDatatypeTime(snak.datavalue.value, parameters)
end
elseif snak.snaktype == 'novalue' then
if parameters.formatting == 'raw' or parameters.shownovalue == false then return end
return mw.message.new('Wikibase-snakview-snaktypeselector-novalue'):inLanguage(parameters.lang[1]):plain()
elseif snak.snaktype == 'somevalue' then
if parameters.formatting == 'raw' then return end
return mw.message.new('Wikibase-snakview-snaktypeselector-somevalue'):inLanguage(parameters.lang[1]):plain()
end
return mw.wikibase.renderSnak(snak)
end
local function printError(key)
return '<span class="error">' .. i18n.errors[key] .. '</span>'
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 getSnak(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
local function getValueOfClaim(claim, qualifierId, parameters)
local snak, error = getQualifierSnak(claim, qualifierId, parameters)
if not snak then
return nil, nil, error
elseif snak[1] then -- a multi qualifier
local result, sortkey = {}, {}
local maxvals = tonumber(parameters.list)
for idx in pairs(snak) do
result[#result + 1], sortkey[#sortkey + 1] = getSnakValue(snak[idx], parameters)
if maxvals and maxvals == #result then break end
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 getValueOfParentClaim(claim, qualifierId, parameters)
local qids = mw.text.split(qualifierId, '/', true)
local value, sortkey, valueraw = {}, {}, {}
local parent_raw, value_text
if qids[1] == parameters.property then
parent_raw, _, _ = getValueOfClaim(claim, nil, {["formatting"]="raw", ["lang"]=parameters.lang})
else
parent_raw, _, _ = getValueOfClaim(claim, qids[1], {["formatting"]="raw", ["lang"]=parameters.lang, ["list"]=true, ["qseparator"]='/', ["qconjunction"]='/'})
end
if string.sub(parent_raw or '', 1, 1) == "Q" then -- protection for 'no value'
local parent_qids = mw.text.split(parent_raw, '/', true)
for idx, p_qid in ipairs(parent_qids) do
local parent_claims = mw.wikibase.getBestStatements(p_qid, qids[2])
if parent_claims[1] then
value[idx], sortkey[idx], _ = getValueOfClaim(parent_claims[1], nil, parameters)
-- raw parent value needed for while/black lists, lang for avoiding an error on types other than entity
valueraw[idx], _, _ = getValueOfClaim(parent_claims[1], nil, {["formatting"]="raw", ["lang"]=parameters.lang})
end
end
end
if value[1] then
value_text = mw.text.listToText(value, parameters.qseparator, parameters.qconjunction)
end
return value_text, sortkey[1], valueraw[1]
end
-- see d:Help:Sources
local function getReferences(claim, lang)
local notproperref = {
["P143"] = true, -- imported from
["P3452"] = true, -- inferred from
["P887"] = true, -- based on heuristic
["P4656"] = true -- Wikimedia import URL
}
local result = ""
-- traverse through all references
for ref in pairs(claim.references or {}) do
local refparts
local refs = {}
local validref = true
local ref_name
-- traverse through all parts of the current reference
for snakkey, snakval in pairs(claim.references[ref].snaks or {}) do
for partkey, _ in pairs(claim.references[ref].snaks[snakkey] or {}) do
if notproperref[snakkey] then -- not a proper reference
validref = false
break
end
end
if validref then
for snakidx = 1, #snakval do
if snakidx > 1 then refparts = refparts .. ", " end
refparts = refparts or '' .. (getSnakValue(snakval[snakidx], {lang=lang}) or '')
end
refs[snakkey] = refparts
refparts = nil
if snakkey == "P248" then -- stated in
ref_name = getSnak(snakval, {1, "datavalue", "value", "id"})
end
end
end
-- fill missing values with parent item
if ref_name then
local function refParent(qid, pid, formatting)
local snak = getSnak(mw.wikibase.getBestStatements(qid, pid), {1, "mainsnak"})
return snak and getSnakValue(snak, {formatting=formatting, lang=lang})
end
refs['P50'] = refs['P50'] or refParent(ref_name, 'P50', 'label') -- author
refs['P407'] = refs['P407'] or refParent(ref_name, 'P407', 'label') -- language of work
refs['P123'] = refs['P123'] or refParent(ref_name, 'P123', 'label') -- publisher
refs['P577'] = refs['P577'] or refParent(ref_name, 'P577') -- date
refs['P1433'] = refs['P1433'] or refParent(ref_name, 'P1433', 'label') -- published in
refs['P304'] = refs['P304'] or refParent(ref_name, 'P304') -- page(s)
refs['P433'] = refs['P433'] or refParent(ref_name, 'P433') -- issue
refs['P236'] = refs['P236'] or refParent(ref_name, 'P236') -- ISSN
refs['P356'] = refs['P356'] or refParent(ref_name, 'P356') -- DOI
ref_name = ref_name .. claim.references[ref].hash
end
-- get title of local templates for citing references
local template_web = mw.wikibase.getSitelink('Q5637226') or ""
template_web = mw.text.split(template_web, ":")[2] -- split off namespace from front
local template_journal = mw.wikibase.getSitelink('Q5624899') or ""
template_journal = mw.text.split(template_journal, ":")[2]
local citeParams = {}
if refs['P854'] and (refs['P1476'] or refs['P248']) and template_web then
-- if both "reference URL" and "title" (or "stated in") are present, then use cite web template
citeParams[i18n['cite']['url']] = refs['P854']
if refs['P248'] and refs['P1476'] == nil then
citeParams[i18n['cite']['title']] = refs['P248']:match("^%[%[.-|(.-)%]%]")
else
citeParams[i18n['cite']['title']] = refs['P1476']
citeParams[i18n['cite']['website']] = refs['P248']
end
citeParams[i18n['cite']['author']] = refs['P50']
citeParams[i18n['cite']['language']] = refs['P407']
citeParams[i18n['cite']['publisher']] = refs['P123']
citeParams[i18n['cite']['date']] = refs['P577']
citeParams[i18n['cite']['pages']] = refs['P304']
citeParams[i18n['cite']['access-date']] = refs['P813']
citeParams[i18n['cite']['archive-url']] = refs['P1065']
citeParams[i18n['cite']['archive-date']] = refs['P2960']
citeParams[i18n['cite']['quote']] = refs['P1683']
refparts = mw.getCurrentFrame():expandTemplate{title=template_web, args=citeParams}
elseif refs['P1433'] and (refs['P1476'] or refs['P248']) and template_journal then
-- if both "published in" and "title" (or "stated in") are present, then use cite journal template
citeParams[i18n['cite']['work']] = refs['P1433']
citeParams[i18n['cite']['title']] = refs['P1476'] or refs['P248']
citeParams[i18n['cite']['author']] = refs['P50']
citeParams[i18n['cite']['date']] = refs['P577']
citeParams[i18n['cite']['issue']] = refs['P433']
citeParams[i18n['cite']['pages']] = refs['P304']
citeParams[i18n['cite']['language']] = refs['P407']
citeParams[i18n['cite']['issn']] = refs['P236']
citeParams[i18n['cite']['doi']] = refs['P356']
refparts = mw.getCurrentFrame():expandTemplate{title=template_journal, args=citeParams}
elseif validref then
-- raw ouput
local snaksorder = claim.references[ref]["snaks-order"]
local function indexed(a)
for _, b in ipairs(snaksorder) do
if b == a then return true end
end
return false
end
for k, _ in pairs(refs or {}) do
if not indexed(k) then
table.insert(snaksorder, k)
end
end
local italics = "''"
for _, k in ipairs(snaksorder) do
if refs[k] then
refparts = refparts and refparts .. " " or ""
refparts = refparts .. mw.ustring.gsub(getLabelByLangs(k, lang), "^%l", mw.ustring.upper) .. ": "
refparts = refparts .. italics .. refs[k] .. italics .. "."
italics = ""
end
end
end
if refparts then result = mw.getCurrentFrame():extensionTag("ref", refparts, {name=ref_name}) end
end
if type(result) == 'string' and result ~= "" and isSet(i18n.categoryref) then
result = result .. "[[" ..i18n.categoryref .. "]]"
end
return result
end
-- Set whitelist or blacklist values
local function setWhiteOrBlackList(num_qual, args)
local lists = {['whitelist']={}, ['blacklist']={}, ['ignorevalue']={}, ['selectvalue']={}}
for i = 0, num_qual do
for k, _ in pairs(lists) do
if isSet(args[k .. i]) then
lists[k][tostring(i)] = {}
local pattern = 'Q%d+'
if string.sub(args[k .. i], 1, 1) ~= 'Q' then
pattern = '[^%p%s]+'
end
for q in string.gmatch(args[k .. i], pattern) do
lists[k][tostring(i)][resolveEntityId(q)] = true
end
end
end
end
return lists['whitelist'], lists['blacklist'], lists['ignorevalue'], lists['selectvalue']
end
local function tableParameters(args, parameters, column)
local column_params = mw.clone(parameters)
column_params.formatting = args["colformat"..column]; if column_params.formatting == "" then column_params.formatting = nil end
column_params.convert = args["convert" .. column]
if args["case" .. column] then
column_params.case = args["case" .. column]
end
return column_params
end
local function getEntityId(args, pargs, unnamed)
pargs = pargs or {}
local id = args.item or args.from or (unnamed and mw.text.trim(args[1] or '') or nil)
if not isSet(id) then
id = pargs.item or pargs.from or (unnamed and mw.text.trim(pargs[1] or '') or nil)
end
if isSet(id) then
if string.find(id, ":") then -- remove prefix as Property:Pid
id = mw.text.split(id, ":")[2]
end
else
id = mw.wikibase.getEntityIdForCurrentPage()
end
return id
end
local function getArg(value, default, aliases)
if type(value) == 'boolean' then return value
elseif value == "false" or value == "no" then return false
elseif value == "true" or value == "yes" then return true
elseif value and aliases and aliases[value] then return aliases[value]
elseif isSet(value) then return value
elseif default then return default
else return nil
end
end
-- Main function claim ---------------------------------------------
-- on debug console use: =p.claim{item="Q...", property="P...", ...}
function p.claim(frame)
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
local is_sandbox = isSet(pargs.sandbox)
if not required and is_sandbox then
return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).claim(frame)
end
--If a value is already set, use it
if isSet(args.value) then
if args.value == 'NONE' then
return
else
return args.value
end
end
-- arguments
local parameters = {}
parameters.id = getEntityId(args, pargs)
if parameters.id == nil then return end
parameters.property = string.upper(args.property or "")
local qualifierId = {}
qualifierId[1] = getArg(string.upper(args.qualifier or ""))
local i = 2
while isSet(args["qualifier" .. i]) do
qualifierId[i] = string.upper(args["qualifier" .. i])
i = i + 1
end
parameters.formatting = getArg(args.formatting)
parameters.convert = getArg(args.convert)
parameters.case = args.case
parameters.list = getArg(args.list, true, {firstrank='bestrank'})
parameters.shownovalue = getArg(args.shownovalue, true)
parameters.separator = getArg(args.separator)
parameters.conjunction = getArg(args.conjunction, parameters.separator)
parameters.qseparator = parameters.separator
parameters.qconjunction = parameters.conjunction
local sorting_col = args.tablesort
local sorting_up = (args.sorting or "") ~= "-1"
local rowformat = args.rowformat
local references = args.references
local showerrors = args.showerrors
local default = args.default
if default then showerrors = nil end
parameters.lang = findLang(args.lang)
if parameters.formatting == "raw" then
parameters.editicon, parameters.labelicon = false, false
else
parameters.editicon, parameters.labelicon = setIcons(args.editicon, pargs.editicon) -- needs loadI18n by findLand
end
-- fetch property
local claims = {}
local bestrank = (parameters.list == false or parameters.list == 'bestrank') and parameters.list ~= 'lang'
for p in string.gmatch(parameters.property, 'P%d+') do
claims = getStatements(parameters.id, p, bestrank)
if #claims > 0 then
parameters.property = p
break
end
end
if #claims == 0 then
if showerrors then return printError("property-not-found") else return default end
end
-- defaults for table
local preformat, postformat = "", ""
local whitelisted = false
local whitelist, blacklist, ignorevalue, selectvalue = {}, {}, {}, {}
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, blacklist, ignorevalue, selectvalue = setWhiteOrBlackList(#qualifierId, args)
local next = next
if next(whitelist) ~= nil then whitelisted = true end
end
-- set feminine case if gender is requested
local itemgender = args.itemgender
local idgender
if itemgender then
if string.match(itemgender, "^P%d+$") then
local snak_id = getSnak(mw.wikibase.getBestStatements(parameters.id, itemgender), {1, "mainsnak", "datavalue", "value", "id"})
if snak_id then
idgender = snak_id
end
elseif string.match(itemgender, "^Q%d+$") then
idgender = itemgender
end
end
local gender_requested = false
if parameters.case == "gender" or idgender then
gender_requested = true
elseif parameters.formatting == "table" then
for i=0, #qualifierId do
if args["case" .. i] and args["case" .. i] == "gender" then
gender_requested = true
break
end
end
end
if gender_requested then
if feminineGender(idgender or parameters.id) then
parameters.gender = "feminineform"
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, result2, result_query
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 refs = {}
local rowlist = {} -- rows to list with whitelist or blacklist
for idx in pairs(claims) do
local claim = claims[sortindices[idx]]
local reference = {}
if not whitelisted then rowlist[idx] = true end
if parameters.formatting == "table" then
local params = tableParameters(args, parameters, "0")
value, sortkey, error = getValueOfClaim(claim, nil, params)
if value then
values[#values + 1] = {}
sortkeys[#sortkeys + 1] = {}
refs[#refs + 1] = {}
if whitelist["0"] or blacklist["0"] then
local valueraw, _, _ = getValueOfClaim(claim, nil, {["formatting"]="raw", ["lang"]=params.lang})
if whitelist["0"] and whitelist["0"][valueraw or ""] then
rowlist[#values] = true
elseif blacklist["0"] and blacklist["0"][valueraw or ""] then
rowlist[#values] = false
end
end
for i, qual in ipairs(qualifierId) do
local j = tostring(i)
params = tableParameters(args, parameters, j)
local valueq, sortkeyq, valueraw
if qual == parameters.property then -- hack for getting the property with another formatting, i.e. colformat1=raw
valueq, sortkeyq, _ = getValueOfClaim(claim, nil, params)
else
for q in mw.text.gsplit(qual, '%s*OR%s*') do
if string.find(q, ".+/.+") then
valueq, sortkeyq, valueraw = getValueOfParentClaim(claim, q, params)
elseif string.find(q, "^/.+") then
local claim2 = getStatements(parameters.id, string.sub(q, 2), bestrank)
if #claim2 > 0 then
valueq, sortkeyq, _ = getValueOfClaim(claim2[1], nil, params)
end
else
valueq, sortkeyq, _ = getValueOfClaim(claim, q, params)
end
if valueq then
qual = q
break
end
end
end
values[#values]["col" .. j] = valueq
sortkeys[#sortkeys]["col" .. j] = sortkeyq or valueq
if whitelist[j] or blacklist[j] or ignorevalue[j] or selectvalue[j] then
valueq = valueraw or getValueOfClaim(claim, qual, {["formatting"]="raw", ["lang"]=params.lang})
if whitelist[j] and whitelist[j][valueq or ""] then
rowlist[#values] = true
elseif blacklist[j] and blacklist[j][valueq or ""] then
rowlist[#values] = false
elseif ignorevalue[j] and ignorevalue[j][valueq or ""] then
values[#values]["col" .. j] = nil
elseif selectvalue[j] and not selectvalue[j][valueq or ""] then
values[#values]["col" .. j] = nil
end
end
end
end
else
value, sortkey, error = getValueOfClaim(claim, qualifierId[1], parameters)
values[#values + 1] = {}
sortkeys[#sortkeys + 1] = {}
refs[#refs + 1] = {}
end
if not value and showerrors then value = error end
if value then
if references and claim.references then reference = claim.references end
refs[#refs]["col0"] = reference
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 sorting_table = mw.text.split(sorting_col, '%D+')
local comparator = function(a, b)
local valuea, valueb
local i = 1
while valuea == valueb and i <= #sorting_table do
valuea = sortkeys[a]["col" .. sorting_table[i]] or ''
valueb = sortkeys[b]["col" .. sorting_table[i]] or ''
i = i + 1
end
if sorting_up then
return valueb > valuea
end
return valueb < valuea
end
table.sort(sortindices, comparator)
end
local maxvals = tonumber(parameters.list)
result = {}
for idx in pairs(values) do
local valuerow = values[sortindices[idx]]
local reference = getReferences({["references"] = refs[sortindices[idx]]["col0"]}, parameters.lang)
value = valuerow["col0"]
if parameters.formatting == "table" then
if not rowlist[sortindices[idx]] then
value = nil
else
local rowformatting = rowformat .. "$" -- fake end character added for easy gsub
value = mw.ustring.gsub(rowformatting, "$0", {["$0"] = value})
value = mw.ustring.gsub(value, "$R0", reference) -- add reference
for i, _ in ipairs(qualifierId) do
local valueq = valuerow["col" .. i]
if args["rowsubformat" .. i] and isSet(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 = captureEscapes(valueq)
valueq = mw.ustring.gsub(args["rowsubformat" .. i] .. "$", "$" .. i .. "(%D)", valueq .. "%1")
valueq = string.sub(valueq, 1, -2)
rowformatting = mw.ustring.gsub(rowformatting, "$" .. i .. "(%D)", args["rowsubformat" .. i] .. "%1")
end
valueq = valueq and captureEscapes(valueq) or ''
value = mw.ustring.gsub(value, "$" .. i .. "(%D)", valueq .. "%1")
end
value = string.sub(value, 1, -2) -- remove fake end character
value = expandBraces(value, rowformatting)
end
elseif value then
value = expandBraces(value, parameters.formatting)
value = value .. reference
end
if isSet(value) then
result[#result + 1] = value
if not parameters.list or (maxvals and maxvals == #result) then
break
end
end
end
if args.query == 'num' then
result_query = 0
for _, v in pairs(rowlist) do
result_query = result_query + (v and 1 or 0)
end
end
if #result > 0 then
if parameters.formatting == 'table' then
result = addEditIconTable(result, parameters) -- in a table, add edit icon on last element
end
result = preformat .. mw.text.listToText(result, parameters.separator, parameters.conjunction) .. postformat
else
result = ''
end
else
-- return first element
local claim = claims[sortindices[1]]
result, result2, error = getValueOfClaim(claim, qualifierId[1], parameters)
if result and references then result = result .. getReferences(claim, parameters.lang) end
if args.query == 'num' then result_query = 1 end
end
if isSet(result) then
if not (parameters.formatting == 'table' or (result2 and result2 == 'no-icon')) then
-- add edit icon, except table added previously and except explicit no-icon internal flag
result = result .. addEditIcon(parameters)
end
else
if showerrors then result = error else result = default end
end
if args.query == 'untranslated' and required and not is_sandbox then
result_query = untranslated
end
return result, result_query or ''
end
-- Local functions for getParentValues -----------------------
local function uc_first(word)
if word == nil then return end
return mw.ustring.upper(mw.ustring.sub(word, 1, 1)) .. mw.ustring.sub(word, 2)
end
local function getPropertyValue(id, property, parameter, langs, labelicon, case)
local snaks = mw.wikibase.getBestStatements(id, property)
local mysnak = getSnak(snaks, {1, "mainsnak"})
if mysnak == nil then
return
end
local entity_id
local result = '-' -- default for 'no value'
if mysnak.datavalue then
entity_id = "Q" .. tostring(mysnak.datavalue.value['numeric-id'])
result, _ = getSnakValue(mysnak, {formatting=parameter, lang=langs, labelicon=labelicon, case=case})
end
return entity_id, result
end
local function getParentObjects(id,
prop_format,
label_format,
languages,
propertySupString,
propertyLabel,
propertyLink,
label_show,
labelicon0,
labelicon1,
upto_number,
upto_label,
upto_value,
last_only,
grammatical_case,
include_self)
local propertySups = mw.text.split(propertySupString, '[^P%d]')
local maxloop = 10
if upto_number then
maxloop = tonumber(upto_number)
elseif next(upto_label) or next(upto_value) then
maxloop = 50
end
local labels_filter = next(label_show)
local result = {}
local id_value = id
for iter = 1, maxloop do
local link, label, labelwicon, linktext, id_label
for _, propertySup in pairs(propertySups) do
local _id_value, _link = getPropertyValue(id_value, propertySup, prop_format, languages, labelicon1, grammatical_case)
if _id_value and _link then id_value = _id_value; link = _link break end
end
if not id_value or not link then break end
if propertyLink then
_, linktext = getPropertyValue(id_value, propertyLink, "label", languages)
if linktext then
link = mw.ustring.gsub(link, "%[%[(.*)%|.+%]%]", "[[%1|" .. linktext .. "]]")
end
end
id_label, label = getPropertyValue(id_value, propertyLabel, label_format, languages, false, "infoboxlabel")
if labelicon0 then
_, labelwicon = getPropertyValue(id_value, propertyLabel, label_format, languages, labelicon0, "infoboxlabel")
else
labelwicon = label
end
if labels_filter == nil or (label_show[id_label] or label_show[label]) then
result[#result + 1] = {labelwicon, link}
label_show[id_label or 'none'], label_show[label or 'none'] = nil, nil -- only first label found
end
if upto_label[id_label] or upto_label[label] or upto_value[id_value] then
break
end
end
if last_only then
result = {result[#result]}
end
if include_self then
local label_self, link_self
_, label_self = getPropertyValue(id, propertyLabel, label_format, languages, labelicon0, "infoboxlabel")
link_self, _ = getLabelByLangs(id, languages)
table.insert(result, 1, {label_self, link_self})
end
return result
end
local function parentObjectsToString(result,
rowformat,
cascade,
sorting)
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
if cascade then
local direction = mw.language.new(wiki.langcode):isRTL() and "right" or "left"
local suffix = ""
for i = 1, #ret do
ret[i] = '<ul style="line-height:100%; margin-' .. direction .. ':0.45em; padding-' .. direction .. ':0;"><li>' .. ret[i]
suffix = suffix .. '</li></ul>'
end
ret[#ret] = ret[#ret] .. suffix
end
return ret
end
-- Returns pairs of parent label and property value fetching a recursive tree
function p.getParentValues(frame)
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
if not required and isSet(pargs.sandbox) then
return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).getParentValues(frame)
end
local id = getEntityId(args, pargs)
if id == nil then return end
local languages = findLang(args.lang)
local propertySup = getArg(args.property, "P131") --administrative entity
local propertyLabel = getArg(args.label, "P31") --instance
local propertyLink = getArg(args.valuetext)
local property_format = getArg(args.formatting)
local label_format = getArg(args.labelformat, "label")
local upto_number = getArg(args.upto)
local last_only = getArg(args.last_only, false)
local editicon, labelicon = setIcons(args.editicon, pargs.editicon)
local include_self = getArg(args.include_self, false)
local case = getArg(args.case)
local upto_label = {}
for q in string.gmatch(args.uptolabelid or '', 'Q%d+') do
local checked_q = resolveEntityId(q)
if checked_q then
upto_label[checked_q] = true
end
end
if type(upto_number) == 'string' then
upto_label[uc_first(upto_number)] = true
upto_number = nil
require(wiki.module_title .. '/debug').track('upto') -- replace upto by uptolabelid
end
local upto_value = {}
for q in string.gmatch(args.uptovalueid or args.uptolinkid or '', 'Q%d+') do
local checked_q = resolveEntityId(q)
if checked_q then
upto_value[checked_q] = true
end
end
local label_show = {}
for q in string.gmatch(args.showlabelid or '', 'Q%d+') do
local checked_q = resolveEntityId(q)
if checked_q then
label_show[checked_q] = true
end
end
for _, v in ipairs(mw.text.split(args.labelshow or '', "/")) do
if v ~= '' then
label_show[uc_first(v)] = true
require(wiki.module_title .. '/debug').track('labelshow') -- replace labelshow by showlabelid
end
end
local rowformat = args.rowformat; if not isSet(rowformat) then rowformat = "$0 = $1" end
local labelicon0, labelicon1 = labelicon, labelicon
if string.find(label_format, '{{.*$0.*}}') or (string.find(rowformat, '{{.*$0.*}}') and label_format ~= 'raw') then
labelicon0 = false
end
local result = getParentObjects(id,
property_format,
label_format,
languages,
propertySup,
propertyLabel,
propertyLink,
label_show,
labelicon0,
labelicon1,
upto_number,
upto_label,
upto_value,
last_only,
case,
include_self)
if #result == 0 then return end
local separator = args.separator; if not isSet(separator) then separator = "<br />" end
local sorting = args.sorting; if sorting == "" then sorting = nil end
local cascade = (args.cascade == "true" or args.cascade == "yes")
local ret = parentObjectsToString(result,
rowformat,
cascade,
sorting)
ret = addEditIconTable(ret, {property=propertySup, editicon=editicon, id=id, lang=languages})
return mw.text.listToText(ret, separator, separator)
end
-- Link with a parent label --------------------
function p.linkWithParentLabel(frame)
local pargs = frame.args and frame:getParent().args or {}
if not required and isSet(pargs.sandbox) then
return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).linkWithParentLabel(frame)
end
local args = {}
if frame.args then
for k, v in pairs(frame.args) do -- metatable
args[k] = v
end
else
args = frame -- via require
end
if isSet(args.value) then
return args.value
end
-- get id value of property/qualifier
local largs = mw.clone(args)
largs.list = tonumber(args.list) and args.list or true
largs.formatting = "raw"
largs.separator = "/·/"
largs.editicon = false
local items_list, _ = p.claim(largs)
if not isSet(items_list) then return end
local items_table = mw.text.split(items_list, "/·/", true)
-- get internal link of property/qualifier
largs.formatting = "internallink"
local link_list, _ = p.claim(largs)
local link_table = mw.text.split(link_list, "/·/", true)
-- get label of parent property
local parent_claim = getSnak(getStatements(items_table[1], args.parent, true), {1, "mainsnak", "datatype"})
if parent_claim == 'monolingualtext' then
largs.formatting = nil
largs.list = 'lang'
else
largs.formatting = "label"
largs.list = false
end
largs.property = args.parent
largs.qualifier = nil
for i, v in ipairs(items_table) do
largs.item = v
local link_label, _ = p.claim(largs)
if isSet(link_label) then
link_table[i] = mw.ustring.gsub(link_table[i] or '', "%[%[(.*)%|.+%]%]", "[[%1|" .. link_label .. "]]")
end
end
args.editicon, _ = setIcons(args.editicon, pargs.editicon)
args.id = getEntityId(args, pargs)
args.lang = findLang(args.lang)
return mw.text.listToText(link_table) .. addEditIcon(args)
end
-- Calculate number of years old ----------------------------
function p.yearsOld(frame)
if not required and frame.args and isSet(frame:getParent().args.sandbox) then
return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).yearsOld(frame)
end
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
local id = getEntityId(args, pargs)
if id == nil then return end
local lang = mw.language.new('en')
local function getBestValue(id, prop)
return getSnak(mw.wikibase.getBestStatements(id, prop), {1, "mainsnak", "datavalue", "value"})
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_expr
if old_min == 0 and old_max == 0 then
old = "< 1"
old_max = 1 -- expression in singular
elseif old_min == old_max then
old = old_min
else
old = old_min .. "/" .. old_max
end
if args.formatting == 'unit' then
local langs = findLang(args.lang)
local yo, yo_sg, yo_pl, yo_pau
if langs[1] == wiki.langcode then
yo_sg = i18n["years-old"].singular
yo_pl = i18n["years-old"].plural
yo_pau = i18n["years-old"].paucal
end
if not isSet(yo_pl) then
yo_pl, _ = getLabelByLangs('Q24564698', langs)
yo_sg = yo_pl
end
if not isSet(yo_pau) then
yo_pau = yo_pl
end
yo = mw.language.new(langs[1]):plural(old_max, {yo_sg, yo_pau, yo_pl})
if mw.ustring.find(yo, '$1', 1, true) then
old_expr = mw.ustring.gsub(yo, "$1", old)
else
old_expr = old .. ' ' .. yo
end
elseif args.formatting then
old_expr = expandBraces(mw.ustring.gsub(args.formatting, '$1', old), args.formatting)
else
old_expr = old
end
return old_expr
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 pargs = frame.args and frame:getParent().args or {}
if not required and isSet(pargs.sandbox) then
return require(wiki.module_title .. "/" .. mw.message.new('Sandboxlink-subpage-name'):inLanguage(wiki.langcode):plain()).getLabel(frame)
end
local id = getEntityId(args, pargs, 1)
if id == nil then return end
local languages = findLang(args.lang)
local labelicon = false
if mw.wikibase.isValidEntityId(id) then
_, labelicon = setIcons(args.editicon, pargs.editicon)
end
local label_icon = ''
local label, lang
if args.label then
label = args.label
else
-- exceptions or labels fixed
local exist, labels = pcall(require, wiki.module_title .. "/labels" .. (languages[1] == wiki.langcode and '' or '/' .. languages[1]))
if exist and labels.infoboxLabelsFromId and next(labels.infoboxLabelsFromId) ~= nil then
label = labels.infoboxLabelsFromId[id]
end
if label == nil then
label, lang = getLabelByLangs(id, languages)
if label then
if isSet(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
if args.case then
label = case(args.case, label, lang)
end
end
label_icon = addLabelIcon(id, lang, languages[1], labelicon)
end
end
local linked = args.linked
local ret2 = required and untranslated or ''
if isSet(linked) and linked ~= "no" then
local article = mw.wikibase.getSitelink(id) or ("d:Special:EntityPage/" .. id)
return "[[" .. article .. "|" .. (label or id) .. "]]" .. label_icon, ret2
else
return (label or id) .. label_icon, ret2
end
end
-- Utilities -----------------------------
-- See also module ../debug.
-- Copied from Module:Wikibase
function p.getSiteLink(frame)
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
local id = getEntityId(args, pargs, 1)
if id == nil then return end
return mw.wikibase.getSitelink(id, mw.text.trim(args[2] or ''))
end
-- Helper function for the default language code used
function p.lang(frame)
local lang = frame and frame.args[1] -- nil via require
return findLang(lang)[1]
end
-- Number of statements
function p.numStatements(frame)
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
local id = getEntityId(args, pargs)
if id == nil then return 0 end
local prop = mw.text.trim(args[1] or '')
local num = {}
if not isSet(prop) and frame.args then
args = {}
for k, v in pairs(pargs) do
args[k] = v
end
for k, v in pairs(frame.args) do
args[k] = v
end
args.query = 'num'
_, num = p.claim(args)
return num
elseif args[2] then -- qualifier
local qual = mw.text.trim(args[2])
local values = p.claim{item=id, property=prop, qualifier=qual, formatting='raw', separator='/·/'}
if values then
num = mw.text.split(values, '/·/')
end
else
num = mw.wikibase.getBestStatements(id, prop)
end
return #num
end
-- Returns true if property datavalue is found excluding novalue/somevalue
function p.validProperty(frame)
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
local item = getEntityId(args, pargs)
if item == nil then return end
local property = mw.text.trim(args[1])
local prop_data = getSnak(mw.wikibase.getBestStatements(item, property), {1, "mainsnak", "datavalue"})
return prop_data and true or nil
end
function p.editAtWikidata(frame)
local args = frame.args or frame -- via invoke or require
local pargs = frame.args and frame:getParent().args or {}
local value = isSet(args[1])
if value then return end
local param = {}
param.id = getEntityId(args, pargs)
param.property = args.property
param.lang = findLang(args.lang)
param.editicon, _ = setIcons(args.editicon)
return addEditIcon(param)
end
function p.formatNum(frame)
local num = tonumber(mw.text.trim(frame.args[1]))
local lang = findLang(mw.text.trim(frame.args[2]))
return mw.language.new(lang[1]):formatNum(num)
end
return p