Gaa na ọdịnaya

Module:Wikidata

Shí Wikipedia, njikotá édémédé nke onyobulạ

This module is intended to fetch data from Wikidata with or without a link to the connected Wikipedia article and with many other features.

The general structure of a call to this module is as follows. Note that the basic structure consists of positional commands, flags and arguments, which all have a fixed position.

{{wikidata|command1|flag1a|flag1b|flag1c|command2|flag2a|flag2b|flag2c|flag0a|flag0b|flag0c|arg1|arg2|arg3}}

Use different commands to get different kinds of values from Wikidata. At least one command must be given and multiple commands can be combined into one call as shown above (in any order, more than two is also possible), but this only applies to commands from the claim class; calls containing a command from the general class cannot contain any other command. Each command can be followed by any number of command flags, which are optional and can be used to tweak the output generated by that command.

The commands and their flags may be followed by any number of configuration flags, which are also optional and affect the selection of data and the module's behaviour in general. The call is closed with the positional arguments, which may be required depending on the given command(s). Some named arguments (i.e. name-value pairs) also exist, as well as a set of named flags for advanced usage that can be used to change the way the fetched values are merged together into the output.

This module was designed to provide the basic needs for fetching data from Wikidata, but a lot can be achieved through different combinations of calls. For convenience, such combinations could be wrapped into new templates that serve a specific need. See also the section on common use cases below for some examples of useful "building blocks". Likewise, the functionality of this module can be extended by creating wrapper templates that use the main command provided by this module (just like {{WikidataOI}} does).

Common use cases

[dezie ebe o si]

Below follows a list of common use cases. In the future, shortcut commands may be implemented that are equivalent to these calls for convenience.

Call Use case
{{wikidata|label|raw}} Returns the Q-identifier of the Wikidata item connected to the current page (e.g. "Q55").
{{#if:{{wikidata|label|raw}}|...}} Performs a check to determine if the current page has a Wikidata item.

Note that this statement relies on a returned value that is either empty or non-empty and that the raw flag is important to include. Without this flag, an existing item's regular label would be returned which could be empty, giving an undesired result. If the flag is given on the other hand, then a non-empty Q-identifier is always returned if an item exists and an empty value if an item does not exist.

Commands

[dezie ebe o si]

The commands (command1, command2, ...) determine what kind of values are returned. One call can only contain commands from a single class.

Claim class

[dezie ebe o si]

The claim class commands can be combined, meaning that multiple commands of different types from this class can be given at one time (see above for usage).

Combine multiple commands into one call to this module, instead of making multiple calls to this module with one command each, to be sure that all the returned pieces of information belong to each other (see also the examples below).

Type Command Returns Basic usage Description
I property first match[lower-alpha 1] {{wikidata|property|P1}} Returns the requested property – or list of properties – from the current item-entity or from a given entity.

This command can be given only once in one call.

properties all matches {{wikidata|properties|P1}}
II qualifier first match[lower-alpha 2] {{wikidata|qualifier|P1|P2}} Returns the requested qualifier – or list of qualifiers – from the given property of the current item-entity or of a given entity.

Unlike the other claim class commands, this command can be given multiple times to retrieve different qualifiers in one call.

qualifiers all matches {{wikidata|qualifiers|P1|P2}}
III reference first match[lower-alpha 2] {{wikidata|reference|P1}} Returns a reference – or list of references – from the given property of the current item-entity or of a given entity.[lower-alpha 3]

This command can be given only once in one call.

references all matches {{wikidata|references|P1}}
  1. Returns only a single value instead of multiple (if multiple claims or statements match). The returned value is the first match found from the best-ranked claims.
  2. 2.0 2.1 Returns only a single value instead of multiple for each matching claim. To get at most one value in total in case the property command is not also used, additionally use the single configuration flag.
  3. See the section on references for details.

General class

[dezie ebe o si]

The general class commands cannot be combined.

Type Command Returns Basic usage Description
I label {{wikidata|label}} Returns the label of the current item-entity or of a given entity if present.
II title {{wikidata|title}} Returns the title of the page connected to the current item-entity or to a given item-entity if such page exists.
III description {{wikidata|description}} Returns the description of the current item-entity or of a given entity if present.
IV alias first match[lower-alpha 1] {{wikidata|alias}} Returns an alias – or list of aliases – of the current item-entity or of a given entity if present.
aliases all matches {{wikidata|aliases}}
V badge first match[lower-alpha 1] {{wikidata|badge}} Returns a badge – or list of badges – for the page connected to the current item-entity or to a given item-entity if such page exists.
badges all matches {{wikidata|badges}}
  1. 1.0 1.1 Returns only a single value instead of multiple (if multiple values are present).

The following (optional) flags are available which can be used to alter this module's behaviour. They must be given after the (first) command and before the positional arguments. For convenience, empty flags (i.e. ||) are allowed and will simply be ignored.

Command flags

[dezie ebe o si]

These flags (flag1*, flag2*, ...) apply to the command that precedes them directly.

Flag Description
raw Returns the raw value if applicable.

If this flag is used with item or property datatypes, then this will return the Q-identifier or P-identifier instead of the regular label.

For quantity datatypes, this flag will strip off any units of measurement, unless the unit flag is also given in which case the raw unit of measurement (its Q-identifier) will be returned.

If this flag is used with time datatypes, then the returned date will be in the format of yyyy-mm-dd (e.g. 1731-02-11), or yyyy-mm, or yyyy depending on the date's precision. Dates in the Julian calendar stored with a precision of days through millenniums will have /Julian attached to the output (e.g. 1731-02-11/Julian, which may be split off using the {{#titleparts}} parser function).

If it is used with globe coordinate datatypes, then it replaces the various symbols with forward slashes in the returned value (e.g. 52/5/3/N/4/19/3/E, which may be split into parts using the {{#titleparts}} parser function).

linked Creates a link to the Wikipedia article that is connected to the property or qualifier if it exists. Also links units of measurement that may be appended to values.

If this parameter is omitted, then the plain property or qualifier value will be returned.

short [EXPENSIVE] Returns the aha mkpirisi (P1813) of any entity returned if they have one attached. If that is not the case, then the default behaviour of returning the entity's label will occur.
multilanguage Returns monolingual text values in any available language, not just the current wiki's language.
unit Returns only the unit of measurement for quantity datatypes.

Configuration flags

[dezie ebe o si]

These flags (flag0*) are general configuration flags and can be given anywhere after the first command (but before the positional arguments).

Flag Description Command class
Combination of: preferred Sets a rank constraint for the selected claim(s).

The first three set the ranks for which claim(s) will be selected. They can optionally be followed by a + or a -, e.g. normal+ or preferred-, where the first selects claims with a 'normal' rank or higher and the second selects claims with a 'preferred' rank or lower. To get claims of all ranks, use preferred- or deprecated+.

If the best flag is given additionally, then only the claims that have the highest rank amongst the selected claims will be returned.

The default is normal+|best (so by default claims with a 'deprecated' rank are never returned).

Output is always sorted from highest rank to lowest (regardless of any of these flags being set).

claim
normal
deprecated
best
Combination of: future Sets a time constraint for the selected claim(s). Uses the claims' qualifiers of oge obidoro (P580) and oge ngwụcha (P582) to determine if the claim is valid for the selected time period(s).

The default is future|current|former (so by default claims that are valid for any time period are returned), except when date= is given (see below) in which case the default is current.

claim
current
former
mdy Returns date values in month-day-year order instead of day-month-year order. claim
single Returns only a single claim instead of multiple (if multiple claims match). Has no effect if the property/properties command is given, in which case this flag would be redundant. claim
sourced Only returns claims that have at least one non-empty reference. (References having only ignored parameters are considered empty.) claim
One of: edit Adds a clickable icon after the output that may be used by readers to edit the returned claim on Wikidata.

If edit@end is used, then the icon will be placed at the end of the line for neat alignment in infoboxes.

claim, general
edit@end

Arguments

[dezie ebe o si]

The arguments determine the sources from which all the returned values are fetched.

Positional arguments

[dezie ebe o si]

The following table shows the available positional arguments (arg*) in their fixed order. For each command, the applicable set of arguments is marked. If multiple commands are given, then the applicable set is the union of the individual sets. For instance, if the commands properties and qualifiers have been given, then at least both the arguments property_id and qualifier_id should be given as well.

More than one qualifier/qualifiers command can be given. The order in which these commands with their flags are given matches the order in which the respective qualifier_id arguments are given.

(required) (optional) (optional) (required) (optional) (required) (required)
{{wikidata commands flags entity_id property_id raw_value qualifier_id qualifier_id }}
label, title,
description,
alias/aliases,
badge/badges
property/properties
reference/references
qualifier/qualifiers
qualifier/qualifiers (optional 2nd, 3rd, etc.)

Below follows a description of all positional arguments.

Argument Description
entity_id

(optional)

[EXPENSIVE] Q-identifier of the item-entity to be accessed (e.g. Q55), P-identifier (or an available alias) of the property-entity to be accessed preceded by the Property: prefix (e.g. Property:P38), or page title of the Wikipedia article whose connected item-entity is to be accessed preceded by :, a prefixed colon (e.g. :Netherlands).

In case of the general class commands, the Property: prefix may be omitted for P-identifiers (e.g. P38).

If this parameter is omitted, then the item-entity connected to the current page will be used (except when eid= or page= is given, see below). If this parameter is given, but empty (i.e. ||), then due to its position it will be interpreted as an empty flag and thus be ignored, giving the same result as if it were omitted. See also the named arguments eid= and page= below that can be used to give an entity-ID or page title too, but without the item-entity connected to the current page being used as a default.

property_id P-identifier (or an available alias) of the property within the entity to be accessed, without the Property: prefix (e.g. P35).
raw_value

(optional)

Either the Q-identifier equal to the property value (e.g. Q29574) or a literal value (i.e. string or quantity etc., no entity label) equal to the raw property value of the particular claim to be accessed.

Dates as literal values must be formatted yyyy-mm-dd (e.g. 1731-02-11) for dates with a precision of days, yyyy-mm (e.g. 1731-02) for dates with a precision of months, and yyyy (e.g. 1731) for dates of lesser precision. Dates BCE require a minus sign in front of the year (e.g. -2950-01-31). Dates stored in the Julian calendar must have /Julian attached to the end (e.g. 1731-02-11/Julian). Decades like the 2010s must be given as 2010 (but the 2010s BCE as -2019), centuries like the 20th century as 1901 (but the 20th century BCE as -2000), and millenniums like the 3rd millennium as 2001 (but the 3rd millennium BCE as -3000).

Globe coordinates as literal values must be formatted with forward slashes (i.e. /) between the parts and no symbols (e.g. 52/5/3/N/4/19/3/E) without any spaces or leading zeros.

The special type 'no value' can be given by entering the empty string (i.e. ||) and the special type 'unknown value' can be given by entering a single underscore (i.e. |_|). To get a literal underscore, escape it by placing a backslash \ directly in front of it (i.e. \_); the same holds for a literal backslash (i.e. \\).

To get a literal vertical bar |, use {{!}} or |.

If this parameter is omitted, then all claims (matching any other constraints) within the property will be accessed.

qualifier_id P-identifier (or an available alias) of the qualifier within the entity to be accessed, without the Property: prefix (e.g. P580).


Named arguments

[dezie ebe o si]

Below follows a description of all named arguments, which are name-value pairs (i.e. |name=value). These are all optional and can be given anywhere after the first command.

Argument Description Command class
eid= [EXPENSIVE] This argument can be used to give the Q-identifier (e.g. |eid=Q55) or P-identifier (or an available alias) of the entity to be accessed. It offers the same functionality as the positional argument entity_id, with one difference: if the argument is given but its value is left empty (i.e. |eid=), then no entity is accessed at all instead of the item-entity connected to the current page. This is useful in some cases where a variable entity-ID is expected, but where the item-entity connected to the current page should not be accessed as the default.

Also, the Property: prefix may be omitted for P-identifiers (e.g. |eid=P38) for all commands.

This argument only has effect if the positional argument entity_id is omitted.

claim, general
page= [EXPENSIVE] This argument can be used to give the page title (e.g. |page=Netherlands) of the Wikipedia article whose connected item-entity is to be accessed. It behaves similar to the named argument eid= and can be used instead of the positional argument entity_id (note that no prefixed colon, :, is required). If the argument is given but its value is left empty (i.e. |page=), then no entity is accessed at all instead of the item-entity connected to the current page.

This argument only has effect if the positional argument entity_id and the named argument eid= are omitted.

claim, general
date= This argument can be used to set a particular date (e.g. |date=1731-02-11) relative to which claim matching using the future, current and former flags is done, instead of relative to today. It overrides the default of these flags to current so that by default only claims that were valid at the given date are returned (based on the claims' qualifiers of oge obidoro (P580) and oge ngwụcha (P582)).

The date value must be formatted yyyy-mm-dd (e.g. 1731-02-11), yyyy-mm (e.g. 1731-02) or yyyy (e.g. 1731).

claim
<qualifier>= The <qualifier> is a placeholder for a set of arguments that determine which claims should be accessed based on qualifier value, analogous to the pair of positional arguments property_id and raw_value (that determine access based on property value).

As such, <qualifier> is any qualifier's P-identifier (or an available alias) without the Property: prefix (e.g. P518). Its value is either the Q-identifier equal to one of the qualifier values (e.g. Q27561) or a literal value (i.e. string or quantity etc., no entity label) equal to one of the raw qualifier values of the particular claim to be accessed. The value format is the same as for the positional argument raw_value. The special type 'no value' given by the empty string also matches the total absence within the claim of the particular qualifier.

Example: |P518=Q27561

Multiple arguments of this type can be given to match multiple qualifier values simultaneously for each claim.

claim

Property aliases

[dezie ebe o si]

Property aliases are other names for P-identifiers that can be used instead. The following property aliases (which are case-sensitive) are currently available:

Alias translates
to
P-identifier
coord P625
image P18
author P50
authorNameString P2093
publisher P123
importedFrom P143
wikimediaImportURL P4656
statedIn P248
pages P304
language P407
hasPart P527
publicationDate P577
startTime P580
endTime P582
chapter P792
retrieved P813
referenceURL P854
sectionVerseOrParagraph P958
archiveURL P1065
title P1476
formatterURL P1630
quote P1683
shortName P1813
definingFormula P2534
archiveDate P2960
inferredFrom P3452
typeOfReference P3865
column P3903
subjectNamedAs P1810
wikidataProperty P1687

References

[dezie ebe o si]

When either the reference or the references command is used and a reference is encountered (in Wikidata), the module checks if the reference contains an sitere na oru ngo nke Wikimedia bubata (P143), sitere na (P3452) or URL mbubata Wikimedia (P4656) property. In the case one of these properties is present, the whole reference is ignored (i.e. it is treated as if it wasn't present).

Else, the module attempts to display the reference using the {{Cite web}} template. The reference has to have a Ntụaka URL (P854) property. The below table shows the mapping of Wikidata properties to parameters of Cite web.

Wikidata property Parameter of Cite web Notes
ụbọchị ndekọ (P2960) archive-date
URL ebe nchekwa (P1065) archive-url
Odee akwụkwọ (P50) author/authorN N can be 1, 2, 3...
onye edemede (P2093)
asụsụ eji dee ọrụ (P407) language Ignored when the same as the local language.
ibe (P304) pages
afọ/ụbọchị mbipụta (P577) date
ndị mbipụta (P123) publisher
nhota (P1683) quote
Ntụaka URL (P854) url
ewepụtara (P813) access-date
ngalaba, amaokwu, paragraf, ma ọ bụ nkebiokwu (P958) at
Kwuru na (P248) website
isiokwu akpọrọ dị ka (P1810) title Used only when aha (P1476) is not present, but a URL (either from Ntụaka URL (P854) or from an external identifier, as described below) is, otherwise ignored.
aha (P1476) title

The following properties are ignored: foto (P18), type of reference (P3865).

If there is no Ntụaka URL (P854) property present in the reference, but a property of the "External identifier" data type is present both in the reference and in the Ihe onwunwe Wikidata (P1687) of the item in Kwuru na (P248), a URL is generated from its content and is used in the same manner as a URL given in Ntụaka URL (P854).

If there is no Ntụaka URL (P854) property, or the reference has unknown properties, the module attempts to display it using the {{Cite Q}} template. The Kwuru na (P248) property is mandatory. The below table shows the mapping of properties to Cite Q parameters.

Wikidata property Parameter of Cite Q Notes
Kwuru na (P248) 1 Value supplied to the parameter is raw, i.e. it is just the plain QID.
Isi (P792) chapter
column (P3903) at
ibe (P304) pages
afọ/ụbọchị mbipụta (P577) date
ewepụtara (P813) access-date
ngalaba, amaokwu, paragraf, ma ọ bụ nkebiokwu (P958) section
aha (P1476) title
any property of the "External identifier" data type id The label ("name") of the property is prepended before its content.

The properties listed under the first table (in this section) are also ignored when using Cite Q.

A reference could be displayed using Cite Q only if the reference has a Kwuru na (P248) property and has only properties listed in the table above. If neither Cite web nor Cite Q could be used to display a reference, an error message with an explanation is returned.

To fix this error, check if the reference has the required properties and doesn't have any unknown properties, as described above. The Wikidata help page on references can also be helpful when sourcing statements.

Advanced usage

[dezie ebe o si]

The layout of the output from (a combination of) commands that have both a singular and a plural form (e.g. property/properties) can be customized by using a number of named flags, which are name-value pairs (i.e. |flag=value), that can be given anywhere after the first command. The table below shows the available named flags.

To insert a space at the beginning or end of a value, use an underscore _. To get a literal underscore, escape it by placing a backslash \ directly in front of it (i.e. \_); the same holds for a literal backslash (i.e. \\). To get a literal vertical bar |, use {{!}} or &#124;.

Named flag Default value Default condition Description
format= %p[%s][%r] if the property/properties command was given and the qualifier/qualifiers command was not given The format of a single claim. The available parameters are as follows.
Parameter Description
%p The claim's property value applied by the property/properties command.
%q1, %q2, %q3, ... The claim's qualifier value or list of qualifier values applied by the corresponding qualifier/qualifiers command.
%q The collection of the qualifier values applied by each qualifier/qualifiers command (i.e. %q1 + %q2 + %q3 + ...). If only one qualifier/qualifiers command was given, then this parameter is equivalent to %q1.
%r The claim's reference value or list of reference values applied by the reference/references command.
%a The entity's alias applied by the alias/aliases command.
%b The entity's page badge applied by the badge/badges command.
%s The movable separator placeholder. This is a special parameter that is not applied by a command, but instead is filled automatically between each pair of claims, aliases or badges (if a list of claims, aliases or badges is returned). This is particularly handy in case a claim's reference is returned as well, since it allows the reference to be placed after the punctuation mark as prescribed by Wikipedia's manual of style. The default value is a comma (,) and can be overridden with the sep%s flag (see below).

Optional parameters can be given by encapsulating them between square brackets: [...]. All content between the square brackets is only displayed if a value for each optional parameter that has been defined between the same brackets has been found. Optional content can also be nested.

To use two opening square brackets that directly follow each other (i.e. [[), use {{!((}}.

At least one parameter must be given that is not optional, while the %s parameter must always be defined as optional.

To get a literal [, ], % or \, escape the character by placing a backslash \ directly in front of it (e.g. \%). See also the description directly above this table for more.

%q[%s][%r] if the property/properties command was not given and the qualifier/qualifiers command was given
%r if only the reference/references command was given
%p[ <span style="font-size:85\%">(%q)</span>][%s][%r]
if the property/properties command was given and the qualifier/qualifiers command was given
%a[%s] if the alias/aliases command was given
%b[%s] if the badge/badges command was given
sep= _ default The fixed separator between each pair of claims, aliases or badges.
if only the reference/references command was given without the raw flag
sep%s= , default The movable separator between each pair of claims, aliases or badges. This will be the value of the %s parameter applied to all claims, aliases or badges, except for the last in the list (which can be set with the punc flag).
; if the property/properties command was not given and the qualifier/qualifiers command was given
sep%q1=, sep%q2=, sep%q3=, ... ,_ default The separator between each pair of qualifiers of a single claim. These are the value separators for the %q1, %q2, %q3, ... parameters.

If only one qualifier/qualifiers command was given, then the sep%q1 flag is equivalent to sep%q.

sep%q= ,_ if exactly one qualifier/qualifiers command was given The separator between each set of qualifiers of a single claim. This is the value separator for the %q parameter.

If only one qualifier/qualifiers command was given, then this flag is equivalent to sep%q1.

;_ if more than one qualifier/qualifiers command was given
sep%r= default The separator between each pair of references of a single claim. This is the value separator for the %r parameter.
_ if the raw flag was given for the reference/references command
punc= default A punctuation mark placed at the end of the output. This will be placed on the %s parameter applied to the last claim (or alias or badge) in the list.

This allows the last claim's references to be placed after the punctuation mark when the output is used as part of a sentence.

Examples

[dezie ebe o si]
Parameters and output types Example Description
Q55 = "Netherlands", P395 = "licence plate code"

[string]

{{wikidata|property|Q55|P395}}

NL
Gets a literal string value.
P395 = "licence plate code"

[string]

{{wikidata|property|P395}}

NL
If the module is transcluded on the Netherlands page (which is linked to Q55), then the Q55 can be omitted.
Q55 = "Netherlands", P395 = "NL"

[string]

{{wikidata|property|eid=Q55|P395}}

NL
An entity-ID can also be given using the eid= argument.
P395 = "NL"

[string]

{{wikidata|property|page=Netherlands|P395}}

NL
A page title can be given instead of an entity-ID using the page= argument.
Q55 = "Netherlands", P395 = "licence plate code"

[string]

{{wikidata|property|edit|Q55|P395}}

NL Edit this on Wikidata
Adds a clickable icon that may be used to edit the returned value on Wikidata.
Q55 = "Netherlands", P395 = "licence plate code"

[string]

{{wikidata|property|edit@end|Q55|P395}}

NLEdit this on Wikidata
Places the edit icon at the end of the line.
Q55 = "Netherlands", P1082 = "population"

[quantity]

{{wikidata|property|normal+|Q55|P1082}}

17,590,672
Gets a single property value from claims with a 'normal' rank or higher.
Q55 = "Netherlands", P1082 = "population"

[quantity]

{{wikidata|properties|normal+|Q55|P1082}}

17,590,672, 10,026,773, 16,779,575, 16,829,289, 17,000,000, 17,081,507, 17,181,084, 17,282,163, 17,407,585
Gets multiple property values from claims with a 'normal' rank or higher.
Q55 = "Netherlands", P1082 = "population", P585 = "point in time"

[quantity], [time]

{{wikidata|properties|qualifier|normal+|Q55|P1082|P585}}

17,590,672 (1 January 2022), 10,026,773 (1950), 16,779,575 (2013), 16,829,289 (26 August 2014), 17,000,000 (21 March 2016), 17,081,507 (1 January 2017), 17,181,084 (1 January 2018), 17,282,163 (1 January 2019), 17,407,585 (1 January 2020)
Gets a single qualifier value for each claim, additional to the property value.
Q55 = "Netherlands", P1082 = "population", P585 = "point in time"

[quantity], [time], [reference]

{{wikidata|properties|qualifier|references|normal+|Q55|P1082|P585}}

17,590,672 (1 January 2022),[1] 10,026,773 (1950),[2] 16,779,575 (2013),[2] 16,829,289 (26 August 2014),[3] 17,000,000 (21 March 2016),[4] 17,081,507 (1 January 2017),[5] 17,181,084 (1 January 2018),[1] 17,282,163 (1 January 2019),[1] 17,407,585 (1 January 2020)[1]
Gets references for each claim.
Q55 = "Netherlands", P1082 = "population"

[quantity], [reference]

A total of {{wikidata|property|references|Q55|P1082}} people live in the Netherlands.

A total of 17,590,672[1] people live in the Netherlands.
Gets a property with its references.
Q55 = "Netherlands", P1082 = "population"

[quantity], [reference]

The Netherlands has a population of {{wikidata|property|references|Q55|P1082|punc=.}}

The Netherlands has a population of 17,590,672.[1]
Adds a punctuation mark at the end of the output, in front of the references.
Q55 = "Netherlands", P1082 = "population", P585 = "point in time"

[quantity], [time], [reference]

<ul>{{wikidata|properties|qualifier|references|normal+|Q55|P1082|P585|format=<li>%p[%r][<ul><li>%q</li></ul>]</li>}}</ul>

  • 17,590,672[1]
    • 1 January 2022
  • 10,026,773[2]
    • 1950
  • 16,779,575[2]
    • 2013
  • 16,829,289[3]
    • 26 August 2014
  • 17,000,000[4]
    • 21 March 2016
  • 17,081,507[5]
    • 1 January 2017
  • 17,181,084[1]
    • 1 January 2018
  • 17,282,163[1]
    • 1 January 2019
  • 17,407,585[1]
    • 1 January 2020
Returns the output in a custom format.
Q55 = "Netherlands", P1082 = "population", P585 = "point in time"

[time]

{{wikidata|qualifier|normal+|Q55|P1082|P585}}

1 January 2022; 1950; 2013; 26 August 2014; 21 March 2016; 1 January 2017; 1 January 2018; 1 January 2019; 1 January 2020
Gets a single qualifier per claim, by default for multiple matching claims.
Q55 = "Netherlands", P1082 = "population", P585 = "point in time"

[time]

{{wikidata|qualifier|normal+|single|Q55|P1082|P585}}

1 January 2022
To get a single qualifier for only a single claim, give the single flag too so that only a single claim will be accessed.
Q55 = "Netherlands", P1082 = "population", P585 = "point in time"

[time]

{{wikidata|qualifier|Q55|P1082|10026773|P585}}

1950
Gets a qualifier from claims for which the (raw) property value matches a given literal value.
Q55 = "Netherlands", P1082 = "population", P585 = "point in time"

[time]

{{wikidata|qualifier|mdy|Q55|P1082|10026773|P585}}

1950
Gets dates in month-day-year order.
Q55 = "Netherlands", P1082 = "population", P585 = "point in time"

[time]

{{wikidata|qualifier|raw|Q55|P1082|10026773|P585}}

1950
Gets a raw date value.
Q55 = "Netherlands", P1082 = "population"

[reference]

{{wikidata|references|Q55|P1082|10026773}}

[2]
Gets the references from a particular claim.
Q55 = "Netherlands", P1082 = "population"

[reference]

{{wikidata|references|raw|Q55|P1082|10026773}}

CBS StatLine - Bevolking; kerncijfers. Statistics Netherlands.
Gets references from a particular claim in their raw form.
Q55 = "Netherlands", P1081 = "Human Development Index"

[quantity], [reference]

{{wikidata|properties|references|normal+|Q55|P1081}}

0.931,[6] 0.787, 0.799, 0.829,[7][6] 0.861,[6] 0.877,[7] 0.891,[6] 0.909,[7] 0.919,[7] 0.920,[7] 0.920,[7] 0.922,[7] 0.834,[6] 0.835,[6] 0.839,[6] 0.864,[6] 0.866,[6] 0.865,[6] 0.867,[6] 0.870,[6] 0.876,[6] 0.879,[6] 0.878,[6] 0.883,[6] 0.886,[6] 0.897,[6] 0.904,[6] 0.906,[6] 0.906,[6] 0.910,[6] 0.921,[6] 0.921,[6] 0.923,[6] 0.924,[6] 0.926,[6] 0.928[6]
Gets properties from each claim with any references they have.
Q55 = "Netherlands", P1081 = "Human Development Index"

[quantity], [reference]

{{wikidata|properties|references|normal+|sourced|Q55|P1081}}

0.931,[6] 0.829,[7][6] 0.861,[6] 0.877,[7] 0.891,[6] 0.909,[7] 0.919,[7] 0.920,[7] 0.920,[7] 0.922,[7] 0.834,[6] 0.835,[6] 0.839,[6] 0.864,[6] 0.866,[6] 0.865,[6] 0.867,[6] 0.870,[6] 0.876,[6] 0.879,[6] 0.878,[6] 0.883,[6] 0.886,[6] 0.897,[6] 0.904,[6] 0.906,[6] 0.906,[6] 0.910,[6] 0.921,[6] 0.921,[6] 0.923,[6] 0.924,[6] 0.926,[6] 0.928[6]
Only gets properties from claims that have at least one reference.
Q55 = "Netherlands", P2855 = "VAT rate", P518 = "applies to part"

[entity label]

{{wikidata|qualifier|Q55|P2855|P518}}

food
Gets a single qualifier value (for each matching claim).
Q55 = "Netherlands", P2855 = "VAT rate", P518 = "applies to part"

[entity label]

{{wikidata|qualifiers|Q55|P2855|P518}}

food, medication, assistive technology, magazine, book, art, antique, hairdresser, hotel, campsite, recreation, sport, water
Gets multiple qualifier values (for each matching claim).
Q55 = "Netherlands", P2855 = "VAT rate", P518 = "applies to part"

[quantity], [entity label]

{{wikidata|properties|qualifiers|Q55|P2855|P518}}

21%, 6% (food, medication, assistive technology, magazine, book, art, antique, hairdresser, hotel, campsite, recreation, sport, water)
Gets multiple property values along with multiple qualifier values.
Q55 = "Netherlands", P2855 = "VAT rate", P518 = "applies to part"

[quantity], [entity label]

{{wikidata|properties|qualifiers|Q55|P2855|P518|sep=_+_|sep%s=|sep%q=_/_}}

21% + 6% (food / medication / assistive technology / magazine / book / art / antique / hairdresser / hotel / campsite / recreation / sport / water)
Returns the output with custom separators.
Q55 = "Netherlands", P35 = "head of state", P580 = "start time", P582 = "end time"

[entity label], [time]

{{wikidata|properties|qualifier|qualifier|normal+|Q55|P35|P580|P582}}

Willem-Alexander of the Netherlands (30 April 2013), Beatrix of the Netherlands (30 April 1980; 30 April 2013), Juliana of the Netherlands (4 September 1948; 30 April 1980), Wilhelmina of the Netherlands (23 November 1890; 4 September 1948), Willem III of the Netherlands (17 March 1849; 23 November 1890), Willem II of the Netherlands (7 October 1840; 17 March 1849), William I of the Netherlands (16 March 1815; 7 October 1840)
Gets two different qualifier values for each claim.
Q55 = "Netherlands", P35 = "head of state", P580 = "start time", P582 = "end time"

[entity label], [time]

{{wikidata|properties|qualifier|qualifier|normal+|Q55|P35|P580|P582|sep%q=_–_}}

Willem-Alexander of the Netherlands (30 April 2013), Beatrix of the Netherlands (30 April 1980 – 30 April 2013), Juliana of the Netherlands (4 September 1948 – 30 April 1980), Wilhelmina of the Netherlands (23 November 1890 – 4 September 1948), Willem III of the Netherlands (17 March 1849 – 23 November 1890), Willem II of the Netherlands (7 October 1840 – 17 March 1849), William I of the Netherlands (16 March 1815 – 7 October 1840)
Returns the output with a custom separator.
Q55 = "Netherlands", P35 = "head of state", P580 = "start time", P582 = "end time"

[entity label], [time]

{{wikidata|properties|qualifier|qualifier|normal+|Q55|P35|P580|P582|format=%p[ <span style="font-size:85\%">(%q1[ – %q2])</span>][%s][%r]}}

Willem-Alexander of the Netherlands (30 April 2013), Beatrix of the Netherlands (30 April 1980 – 30 April 2013), Juliana of the Netherlands (4 September 1948 – 30 April 1980), Wilhelmina of the Netherlands (23 November 1890 – 4 September 1948), Willem III of the Netherlands (17 March 1849 – 23 November 1890), Willem II of the Netherlands (7 October 1840 – 17 March 1849), William I of the Netherlands (16 March 1815 – 7 October 1840)
Returns the output in a custom format instead of with a custom separator.
Q55 = "Netherlands", P35 = "head of state", P580 = "start time", P582 = "end time"

[entity label], [time]

{{wikidata|properties|qualifier|qualifier|normal+|Q55|P35|P580|P582|format=%p[ <span style="font-size:85\%">([<![]--%q2]since [%q2--[]>]%q1[ – %q2])</span>][%s][%r]}}

Willem-Alexander of the Netherlands (since 30 April 2013), Beatrix of the Netherlands (30 April 1980 – 30 April 2013), Juliana of the Netherlands (4 September 1948 – 30 April 1980), Wilhelmina of the Netherlands (23 November 1890 – 4 September 1948), Willem III of the Netherlands (17 March 1849 – 23 November 1890), Willem II of the Netherlands (7 October 1840 – 17 March 1849), William I of the Netherlands (16 March 1815 – 7 October 1840)
To add text only when a certain value is not present, like adding the word since if there is no end time, wrap it in between two optional blocks containing HTML comment tags and the relevant parameter (this also prevents the text from being added to the page source).
Q55 = "Netherlands", P35 = "head of state", Q29574 = "Beatrix of the Netherlands", P580 = "start time", P582 = "end time"

[entity label], [time]

{{wikidata|properties|qualifier|raw|qualifier|normal+|Q55|P35|Q29574|P580|P582|format=%p[ <span style="font-size:85\%">(%q1[ – %q2])</span>][%s][%r]}}

Beatrix of the Netherlands (1980-04-30 – 30 April 2013)
Gets a property with qualifiers from claims for which the property matches a given Q-identifier, with one of the qualifier values in its raw form.
Q55 = "Netherlands", P38 = "currency", P518 = "applies to part"

[entity label]

{{wikidata|properties|qualifiers|normal+|current|Q55|P38|P518}}

euro (European Netherlands), United States dollar (Caribbean Netherlands)
Gets claims that are currently valid.
Q55 = "Netherlands", P38 = currency", P518 = "applies to part"

[entity label]

{{wikidata|properties|linked|qualifiers|normal+|current|Q55|P38|P518}}

euro (European Netherlands), United States dollar (Caribbean Netherlands)
Gets claims with linked property values.
Q55 = "Netherlands", P38 = currency", P518 = "applies to part"

[entity label]

{{wikidata|properties|qualifiers|linked|normal+|current|Q55|P38|P518}}

euro (European Netherlands), United States dollar (Caribbean Netherlands)
Gets claims with linked qualifier values.
Q55 = "Netherlands", P38 = currency", P518 = "applies to part"

[entity label]

{{wikidata|properties|linked|short|qualifiers|linked|normal+|current|Q55|P38|P518}}

euro (European Netherlands), US dollar (Caribbean Netherlands)
Gets claims with linked property and qualifier values, with short property values wherever available.
Q55 = "Netherlands", P38 = currency", Q4917 = "United States dollar", P518 = "applies to part"

[entity label]

{{wikidata|qualifiers|normal+|current|Q55|P38|Q4917|P518}}

Caribbean Netherlands
Gets qualifiers from claims for which the (raw) property value matches a given Q-identifier.
Q55 = "Netherlands", P38 = currency", P518 = "applies to part", Q27561 = "Caribbean Netherlands"

[entity label]

{{wikidata|properties|normal+|current|Q55|P38|P518=Q27561}}

United States dollar
Gets properties from claims for which a (raw) qualifier value matches a given Q-identifier.
Q55 = "Netherlands", P38 = currency"

[entity label]

{{wikidata|properties|normal+|former|Q55|P38}}

Dutch guilder
Gets claims that were valid in the past.
Q55 = "Netherlands", P38 = currency"

[entity label]

{{wikidata|properties|raw|normal+|former|Q55|P38}}

Q788472
Gets raw property values.
Q55 = "Netherlands", P38 = currency"

[entity label]

{{wikidata|properties|raw|linked|normal+|former|Q55|P38}}

Q788472
Gets raw property values that are linked to Wikidata.
Q55 = "Netherlands", P1549 = "demonym"

[monolingual text]

{{wikidata|property|Q55|P1549}}

Dutch
Gets a monolingual text value in the current wiki's language.
Q55 = "Netherlands", P1549 = "demonym", P407 = "language of work or name", Q36846 = "Toki Pona"

[monolingual text]

{{wikidata|property|multilanguage|Q55|P1549|P407=Q36846}}

Gets a monolingual text value in any available language.
Q55 = "Netherlands", P2884 = "mains voltage"

[quantity]

{{wikidata|property|Q55|P2884}}

230 volt
Gets a quantity value with its associated unit of measurement.
Q55 = "Netherlands", P2884 = "mains voltage"

[quantity]

{{wikidata|property|linked|Q55|P2884}}

230 volt
Gets a quantity value with a linked unit of measurement.
Q55 = "Netherlands", P2884 = "mains voltage"

[quantity]

{{wikidata|property|raw|Q55|P2884}}

230
Gets a raw quantity value.
Q55 = "Netherlands", P2884 = "mains voltage"

[quantity]

{{wikidata|property|unit|Q55|P2884}}

volt
Gets only the unit of measurement.
Q55 = "Netherlands", P2884 = "mains voltage"

[quantity]

{{wikidata|property|unit|raw|Q55|P2884}}

Q25250
Gets the raw unit of measurement.
Q55 = "Netherlands", P625 = "coordinate location"

[globe coordinate]

{{wikidata|property|Q55|P625}}

52°19'N, 5°33'E
Gets a globe coordinate value.
Q55 = "Netherlands", P625 = "coordinate location"

[globe coordinate]

{{wikidata|property|linked|Q55|P625}}

52°19'N, 5°33'E
Gets a linked globe coordinate value.
Q55 = "Netherlands", P625 = "coordinate location"

[globe coordinate]

{{wikidata|property|raw|Q55|P625}}

52/19/N/5/33/E
Gets a raw globe coordinate value.
Q55 = "Netherlands", P625 = "coordinate location"

[globe coordinate]

{{wikidata|property|Q55|coord}}

52°19'N, 5°33'E
A property alias can be used instead of the P-identifier.
Q55 = "Netherlands", P41 = "flag image"

[commons media]

{{wikidata|property|linked|Q55|P41}}

Flag of the Netherlands.svg
Gets a media file name and links to it on Commons.
Q55 = "Netherlands", P41 = "flag image"

[commons media]

{{wikidata|property|raw|Q55|P41|format=\[\[File:%p {{!}} thumb {{!}} left\]\]}}

A Commons media file can be included on the page as-is by omitting the linked and raw flags, but by using the raw flag it can be freely formatted.
Q55 = "Netherlands", P41 = "flag image"

[commons media]

{{wikidata|property|raw|date=1700-05-06|Q55|P41|format=\[\[File:%p {{!}} thumb {{!}} left\]\]}}

To get the value of a property that was valid at a given time, the date= argument can be used.
Q55 = "Netherlands", P41 = "flag image"

[commons media]

{{wikidata|property|raw|date=1700-05-06|former|Q55|P41|format=\[\[File:%p {{!}} thumb {{!}} left\]\]}}

The time constraint flags work relatively to the date value given for the date= argument.
Q915684 = "Lorentz–Lorenz equation", P2534 = "defining formula"

[math]

{{wikidata|property|Q915684|P2534}}

Gets a mathematical expression.
Q915684 = "Lorentz–Lorenz equation", P7235 = "in defining formula", P9758 = "symbol represents"

[entity label], [math]

<ul>{{wikidata|properties|qualifier|linked|Q915684|P7235|P9758|format=<li>%q[ (%p)]</li>}}</ul>

Mathematical expressions can be combined with regular text as usual.
Q6256 = "country", P3896 = "geoshape"

[geographic shape]

{{wikidata|property|linked|Q6256|P3896}}

Data:Naturalearthdata.com/admin-0-countries-no-antarctica.map
Gets a geographic shape data file name and links to it on Commons.
Q4917 = "United States dollar"

[entity label]

{{wikidata|label|Q4917}}

United States dollar
Gets an item's label.
Q4917 = "United States dollar"

[entity label]

{{wikidata|label|short|linked|Q4917}}

US dollar
Gets an item's short and linked label.
P38 = currency"

[entity label]

{{wikidata|label|P38}}

currency
Gets a property's label.
P38 = currency"

[entity label]

{{wikidata|label|linked|P38}}

currency
Gets a property's label that is linked to Wikidata.
Q776 = "Utrecht"

[entity label]

{{wikidata|label|Q776}}

Utrecht
Gets an item's label.
Q776 = "Utrecht"

[entity label]

{{wikidata|label|linked|Q776}}

Utrecht
Gets an item's linked label.


[entity label]

{{wikidata|label}}

Utrecht
If the module is transcluded on the Utrecht (province) page (which is linked to Q776), then the Q776 can be omitted.


[entity label]

{{wikidata|label|raw}}

Q776
If just the label command with the raw flag is given, then the Q-identifier of the item connected to the current page is returned.


[entity label]

{{wikidata|label|raw|linked}}

Q776
If additionally the linked flag is given, then the Q-identifier of the item connected to the current page is linked to Wikidata.
Q776 = "Utrecht"

[page title]

{{wikidata|title|Q776}}

Utrecht (province)
Gets the title of the page on the current wiki that is linked to the given item.
Q776 = "Utrecht"

[page title]

{{wikidata|title|linked|Q776}}

Utrecht (province)
Gets the linked title of the page on the current wiki that is linked to the given item.


[page title]

{{wikidata|title}}

Utrecht (province)
If the module is transcluded on the Utrecht (province) page (which is linked to Q776), then the Q776 can be omitted.
Q55 = "Netherlands"

[entity description]

{{wikidata|description|Q55}}

country in Northwestern Europe with territories in the Caribbean
Gets an item's description.


[entity description]

{{wikidata|description}}

country in Northwestern Europe with territories in the Caribbean
If the module is transcluded on the Netherlands page (which is linked to Q55), then the Q55 can be omitted.
Q55 = "Netherlands"

[entity alias]

{{wikidata|alias|Q55}}

Holland
Gets one of an item's aliases.
Q55 = "Netherlands"

[entity alias]

{{wikidata|aliases|Q55}}

Holland, the Netherlands, NL, NED, Nederland, nl, 🇳🇱, Netherlands (after 1945)
Gets all of an item's aliases.
Q55 = "Netherlands"

[entity alias]

{{wikidata|alias|linked|Q55}}

Holland
Gets a linked alias from an item.


[entity alias]

{{wikidata|alias}}

Holland
If the module is transcluded on the Netherlands page (which is linked to Q55), then the Q55 can be omitted.
Q2 = "Earth"

[page badge]

{{wikidata|badges|Q2}}

featured article badge
Gets the badges for the page on the current wiki that is linked to the given item.
Q2 = "Earth"

[page badge]

{{wikidata|badges|raw|Q2}}

Q17437796
Gets the raw badges for the page on the current wiki that is linked to the given item.


[page badge]

{{wikidata|badges}}

featured article badge
If the module is transcluded on the Earth page (which is linked to Q2), then the Q2 can be omitted.
Q28865 = "Python", P548 = "version type", P348 = "software version identifier",

[version], [reference]

{{wikidata|property|reference|edit|Q28865|P548=Q2804309|P348}}

3.11.3[8] Edit this on Wikidata
Get Python's latest stable release version with its references. You may want to use P548=Q2122918 to get the latest preview release version.

Example references

[dezie ebe o si]

TemplateData

[dezie ebe o si]

This template fetches data from the centralized knowledge base Wikidata. To edit the data, click on "Wikidata item" in the left sidebar.

Ụdị ụkpụrụ[Dezie data ndebiri]

OkeNkọwaDeeỌnọdụ
Enweghị ụkwọ akọwapụtara

See also

[dezie ebe o si]
  • {{Wikidata}}, a user-friendly wrapper template for this module.
  • {{WikidataOI}}, a wrapper template for this module that adds an opt-in toggle.
  • {{Pageid to title}}, to get a page title using its local page id, rather than Wikidata



-- version 20200118 from master @cawiki

local p = {}

-- Initialization of variables --------------------

local i18n = {						-- internationalisation at [[Module:Wikidata/i18n]]
	["errors"] = {
		["property-not-found"] = "Property not found.",
		["entity-not-found"] = "Wikidata entity 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
	},
	
	["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 web parameters
		["url"]			= "url",
		["title"]		= "title",
		["website"]		= "website",
		["access-date"]	= "access-date",
		["archive-url"]	= "archive-url",
		["archive-date"]= "archive-date",
		["author"]		= "author",
		["publisher"]	= "publisher",
		["quote"]		= "quote",
		["language"]	= "language",
		["date"]		= "date",
		["pages"]		= "pages"
	}
}

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

local required = ... -- variadic arguments from require function
local wiki = 
{
	langcode = mw.language.getContentLanguage().code,
	module_title = required or mw.getCurrentFrame():getTitle()
}

-- Module local functions --------------------------------------------

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

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

loadI18n()

-- 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 var == '')
end

-- Set local case to a label
local function case(localcase, label, ...)
	if not isSet(label) then return label end
	
	if localcase == "smallcaps" then
		return '<span style="font-variant: small-caps;">' .. label .. '</span>'
	elseif cases[localcase] then
		return cases[localcase](label, ...)
	end
	
	return label
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
	local languages = mw.language.getFallbacksFor(langcode)
	table.insert(languages, 1, langcode)
	return languages
end

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

-- Is gender femenine? true or false
local function feminineGender(id)
	local claims = mw.wikibase.getBestStatements(id or mw.wikibase.getEntityIdForCurrentPage(),'P21')
	if #claims == 0 then
		return false
	elseif claims[1].mainsnak.datavalue == nil then -- novalue or somevalue
		return false
	else
		local genderId = claims[1].mainsnak.datavalue.value.id
		if genderId == "Q6581072" or genderId == "Q1052281" or genderId == "Q43445" then -- female, transgender female, female organism
			return true
		end
	end
	return false
end

-- Fetch female form of label
local function feminineForm(id, lang)
	local feminine_claims = mw.wikibase.getBestStatements(id, 'P2521') -- female form of label
	for _, feminine_claim in ipairs(feminine_claims) do
		if feminine_claim.mainsnak.datavalue.value.language == lang then
			return feminine_claim.mainsnak.datavalue.value.text
		end
	end
end

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

-- Add 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
			ret_icon = " [[File:Noun Project label icon 1116097 cc mirror.svg|12px|"
				.. mw.message.new('Translate-taction-translate'):inLanguage(uselang):plain()
				.. "|link=https://www.wikidata.org/wiki/Special:EntityPage/" .. label_id .. "?uselang=" .. uselang .. "]]"
		end
	end
	return ret_lang .. ret_icon
end

-- Escape URL escapes to avoid Lua captures
local function urlEscapes(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
				parameters[mw.ustring.sub(parts[i], 1, subparts-1)] = mw.ustring.sub(parts[i], subparts+1, -1)
			else
				table.insert(parameters, parts[i])
			end
		end
		
		local braces_expanded
		if mw.ustring.find(title_part, ":")
			and mw.text.split(title_part, ":")[1] ~= mw.site.namespaces[10].name -- not a prefix Template:
			then
			braces_expanded = mw.getCurrentFrame():callParserFunction{name=title_part, args=parameters}
		else
			braces_expanded = mw.getCurrentFrame():expandTemplate{title=title_part, args=parameters}
		end
		braces = mw.ustring.gsub(braces, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1") -- escape magic characters
		braces_expanded = urlEscapes(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 local language nor its fallbacks, maybe it is a redirect
	-- not using mw.title.new(id).isRedirect as it is expensive
	if mw.wikibase.getLabel(id) == 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 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 value string
local function printDatavalueString(data, parameters)
	if parameters.formatting == 'weblink' then 
		return '[' .. data .. ' ' .. mw.text.split(data, '//' )[2] .. ']'
	elseif mw.ustring.find((parameters.formatting or ''), '$1', 1, true) then -- formatting = a pattern
		return expandBraces(mw.ustring.gsub(parameters.formatting, '$1', {['$1']=data}), parameters.formatting)
	elseif parameters.case then
		return case(parameters.case, data, parameters.lang[1])
	else
		return data
	end
end

-- format data type url
local function printDatatypeUrl(data, parameters)
	return printDatavalueString(urlEscapes(data), parameters)
end

-- format data value globecoordinate
local function printDatavalueCoordinate(data, parameter)
	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'}
	if parameter and string.find(parameter, '$lat', 1, true) and string.find(parameter, '$lon', 1, true) then
		local ret = mw.ustring.gsub(parameter, '$l[ao][tn]', {['$lat'] = data.latitude, ['$lon'] = data.longitude})
		if string.find(parameter, '$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, parameter)
	elseif parameter == 'latitude' then
		return data.latitude
	elseif parameter == 'longitude' then
		return data.longitude
	elseif parameter == 'dimension' then
		return data.dimension
	else --default formatting='globe'
		if data.globe == '' or data.globe == nil or data.globe == 'http://www.wikidata.org/entity/Q2' then
			return 'earth'
		else
			local globenum = mw.text.split(data.globe, 'entity/')[2]
			return globes[globenum] or globenum
		end
	end
end

local function roundPrecision(in_num, out_num)
	-- rounds out_num with significant figures of in_num (default precision)
	-- 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 value quantity
local function printDatavalueQuantity(data, parameters)
	local amount = data.amount
	amount = mw.ustring.gsub(amount, "%+", "")
	local sortkey = string.format("%09d", amount)
	local suffix = ""
	if string.sub(parameters.formatting or '', 1, 4) == "unit" or parameters.convert then
		-- example "unit": "http://www.wikidata.org/entity/Q174728"
		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
			local convert_to = parameters.convert
			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))
					amount = math.floor(tonumber(amount_f) + 0.5)
					unit_id = convert_to
				else
					local conversions = mw.wikibase.getAllStatements(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
								amount = roundPrecision(amount, amount * tonumber(conv.mainsnak.datavalue.value.amount))
								unit_id = convert_to
								break
							end
						end
					end
				end
			end
			if parameters.formatting == "unitcode" then
				-- get unit symbol
				local unit_symbol = ''
				if parameters.lang[1] == wiki.langcode and pcall(require, wiki.module_title .. "/Units") then
					unit_symbol = require(wiki.module_title .. "/Units").getUnit(amount, '', unit_id, true, '')
				end
				if unit_symbol == '' then
					unit_symbol = unitSymbol(unit_id, parameters.lang)
				end
				if unit_symbol then
					suffix = " " .. unit_symbol
				end
			end
			if suffix == '' then
				-- get unit name
				local unit_label, lang = getLabelByLangs(unit_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, unit_id, false, '')
				else
					suffix = " " .. (unit_label or unit_id) .. addLabelIcon(unit_id, lang, parameters.lang[1], parameters.editicon)
				end
			end
		end
	end
	amount = mw.language.new(parameters.lang[1]):formatNum(tonumber(amount))
	return amount .. suffix, sortkey
end

-- format data value time
local function printDatavalueTime(data, parameters)
	-- Dates and times are stored in ISO 8601 format
	local timestamp = data.time
	local post_format
	local calendar_add = ""
	
	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"]
	else
		-- 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 d(f, t)
		local ts = t or timestamp
		local form = type(f) == "function" and f(ts) or f -- function in i18n.datetime[precision]
		if string.sub(ts, 1, 1) == '-' then ts = '+' .. string.sub(ts, 2) end -- formatDate() only supports years from 0
		return mw.language.new(parameters.lang[1]):formatDate(form, ts)
	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 precision = data.precision or 11
	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 = mw.ustring.gsub(i18n.datetime[precision], "$1", tostring(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 then -- millennia
		local card = math.floor((intyear - 1) / 1000) + 1
		if mw.ustring.find(i18n.datetime[6], "$1") then
			ret = mw.ustring.gsub(i18n.datetime[6], "$1", tostring(card))
		else
			ret = d(i18n.datetime[6], string.format("%04d", tostring(card)))
		end
		ret = postFormat(ret)
	elseif precision == 7 then -- centuries
		local card = math.floor((math.abs(intyear) - 1) / 100) + 1
		if mw.ustring.find(i18n.datetime[7], "$1") then
			ret = mw.ustring.gsub(i18n.datetime[7], "$1", tostring(card))
		else
			ret = d(i18n.datetime[7], string.format("%04d", tostring(card)))
		end
		ret = postFormat(ret) .. calendar_add
	elseif precision == 8 then -- decades
		local card = math.floor(math.abs(intyear) / 10) * 10
		ret = postFormat(mw.ustring.gsub(i18n.datetime[8], "$1", tostring(card))) .. calendar_add
	elseif precision == 9 or parameters.formatting == 'Y' then -- precision is year
		ret = postFormat(tostring(intyear)) .. calendar_add
	elseif precision == 10 then -- month
		timestamp = timestamp .. " + 1 day" -- formatDate yyyy-mm-00 returns the previous month
		ret = d(i18n.datetime[10])
		ret = postFormat(ret) .. calendar_add
		ret, _ = string.gsub(ret, "([ %[])0+", "%1") -- supress leading zeros in year, optionally linked
	else -- precision 11, day
		ret = d(parameters.formatting or i18n.datetime[11])
		ret = postFormat(ret) .. calendar_add
		ret, _ = string.gsub(ret, "([ %[])0+", "%1")
	end
	return ret, timestamp
end

-- format data value entity
local function printDatavalueEntity(data, parameters)
	local entity_id = data['id']
	local entity_page = 'Special:EntityPage/' .. entity_id
	if parameters.formatting == 'raw' then
		if data['entity-type'] == 'item' then
			entity_id = resolveEntityId(entity_id)
		end
		return entity_id, entity_id
	end
	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, 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 'wikidata:' .. 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 (parameter == 'internallink' or parameter == 'ucinternallink') then
			ret1 = '[[' .. label .. '|' .. labelcase .. ']]'
			ret2 = labelcase
		else
			ret1 = '[[wikidata:' .. entity_page .. '|' .. (labelcase or entity_id) .. ']]'
			ret2 = labelcase or entity_id
		end
	end
	
	return ret1 .. addLabelIcon(entity_id, lang, parameters.lang[1], parameters.editicon), ret2
end

-- format data value monolingualtext
local function printDatavalueMonolingualText(data, parameters)
	-- data fields: language [string], text [string]
	
	if parameters.list == "lang" and data["language"] ~= parameters.lang[1] then
		return
	elseif parameters.formatting == "language" or parameters.formatting == "text" then
		return data[parameters.formatting]
	end
	local result = data["text"]
	if data["language"] ~= wiki.langcode then
		result = mw.ustring.gsub('<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 printError(key)
	return '<span class="error">' .. i18n.errors[key] .. '</span>'
end

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

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

function findClaims(entityId, property)
	if not property or not entityId then return end
	
	if not mw.ustring.match(property, "^P%d+$") then
		-- get property id for the given label
		property = mw.wikibase.resolvePropertyId(property)
		if not property then return end
	end
	local claims = mw.wikibase.getAllStatements(entityId, property)
	if #claims == 0 then
		claims = nil
	end
	return claims
end

local function getSnakValue(snak, parameters)
	if snak.snaktype == 'value' then
		-- call the respective snak parser
		if snak.datatype == 'math' then
			return printDatatypeMath(snak.datavalue.value)
		elseif snak.datatype == 'musical-notation' then
			return printDatatypeMusical(snak.datavalue.value, parameters.formatting)
		elseif snak.datatype == "url" then
			return printDatatypeUrl(snak.datavalue.value, parameters)
		elseif snak.datavalue.type == "string" then
			return printDatavalueString(snak.datavalue.value, parameters)
		elseif snak.datavalue.type == "globecoordinate" then
			return printDatavalueCoordinate(snak.datavalue.value, parameters.formatting)
		elseif snak.datavalue.type == "quantity" then
			return printDatavalueQuantity(snak.datavalue.value, parameters)
		elseif snak.datavalue.type == "time" then
			return printDatavalueTime(snak.datavalue.value, parameters)
		elseif snak.datavalue.type == 'wikibase-entityid' then
			return printDatavalueEntity(snak.datavalue.value, parameters)
		elseif snak.datavalue.type == 'monolingualtext' then
			return printDatavalueMonolingualText(snak.datavalue.value, parameters)
		end
	elseif snak.snaktype == 'novalue' then
		if parameters.formatting == 'raw' 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 getQualifierSnak(claim, qualifierId, parameters)
	-- a "snak" is Wikidata terminology for a typed key/value pair
	-- a claim consists of a main snak holding the main information of this claim,
	-- as well as a list of attribute snaks and a list of references snaks
	if qualifierId then
		-- search the attribute snak with the given qualifier as key
		if claim.qualifiers then
			local qualifier = claim.qualifiers[qualifierId]
			if qualifier then
				if qualifier[1].datatype == "monolingualtext" then
					-- iterate over monolingualtext qualifiers to get local language
					for idx in pairs(qualifier) do
						if qualifier[idx].datavalue.value and qualifier[idx].datavalue.value.language == parameters.lang[1] then
							return qualifier[idx]
						end
					end
				elseif parameters.list then
					return qualifier
				else
					return qualifier[1]
				end
			end
		end
		return nil, printError("qualifier-not-found")
	else
		-- otherwise return the main snak
		return claim.mainsnak
	end
end

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

local function getValueOfParentClaim(claim, qualifierId, parameters)
	local qids = mw.text.split(qualifierId, '/', true)
	local valueraw, parent_claims, value, sortkey
	if qids[1] == parameters.property then
		valueraw, _, _ = getValueOfClaim(claim, nil, {["formatting"]="raw", ["lang"]=parameters.lang})
	else
		valueraw, _, _ = getValueOfClaim(claim, qids[1], {["formatting"]="raw", ["lang"]=parameters.lang})
	end
	if string.sub(valueraw or '', 1, 1) == "Q" then -- protection for 'no value'
		parent_claims = mw.wikibase.getBestStatements(valueraw, qids[2])
		if parent_claims[1] ~= nil then
			value, sortkey, _ = 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, _, _ = getValueOfClaim(parent_claims[1], nil, {["formatting"]="raw", ["lang"]=parameters.lang})
		end
	end
	return value, sortkey, valueraw
end

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

-- Set whitelist or blacklist values
local function setWhiteOrBlackList(type_list, num_qual, args)
	local listed = false
	local list = {}
	for i = 0, num_qual do
		if isSet(args[type_list .. i]) then
			listed = true
			list[tostring(i)] = {}
			local values = mw.text.split(args[type_list .. i], "/", true)
			for _, v in ipairs(values) do
				list[tostring(i)][v] = true
				list[tostring(i)][resolveEntityId(v)] = true
			end
		end
	end
	return list, listed
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

-- 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
	--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 pargs = frame.args and frame:getParent().args
	local id = args.item or (pargs and pargs.item)
	if not isSet(id) then
		id = mw.wikibase.getEntityIdForCurrentPage()
		if id == nil then return end
	end
	local property = string.upper(args.property or "")
	local qualifierId = {}
	qualifierId[1] = isSet(args.qualifier) and string.upper(args.qualifier) or nil
	local i = 2
	while isSet(args["qualifier" .. i]) do
		qualifierId[i] = string.upper(args["qualifier" .. i])
		i = i + 1
	end
	local formatting = args.formatting; if formatting == "" then formatting = nil end
	local convert = args.convert; if convert == "" then convert = nil end
	if convert and string.sub(convert, 1, 1) ~= "Q" then convert = nil end
	local case = args.case
	local list = args.list or true; if (list == "false" or list == "no") then list = false end
	local sorting_col = args.tablesort
	local sorting_up = (args.sorting or "") ~= "-1"
	local separator = args.separator
	local conjunction = args.conjunction or args.separator
	local rowformat = args.rowformat
	local references = args.references
	local showerrors = args.showerrors
	local default = args.default
	if default then showerrors = nil end
	local editicon = not (args.editicon == "false" or args.editicon == "no")
	
	local parameters = {["id"] = id, ["property"] = property, ["formatting"] = formatting, ["convert"] = convert,
		["list"] = list, ["case"] = case, ["editicon"] = editicon,
		["separator"] = separator, ["conjunction"] = conjunction, ["qseparator"] = separator, ["qconjunction"] = conjunction}
	
	-- defaults for table
	local preformat, postformat = "", ""
	local whitelisted, blacklisted = false, false
	local whitelist, blacklist = {}, {}
	if parameters.formatting == "table" then
		parameters.separator = parameters.separator or "<br />"
		parameters.conjunction = parameters.conjunction or "<br />"
		parameters.qseparator = ", "
		parameters.qconjunction = ", "
		if not rowformat then
			rowformat = "$0 ($1"
			i = 2
			while qualifierId[i] do
				rowformat = rowformat .. ", $" .. i
				i = i + 1
			end
			rowformat = rowformat .. ")"
		elseif mw.ustring.find(rowformat, "^[*#]") then
			parameters.separator = "</li><li>"
			parameters.conjunction = "</li><li>"
			if mw.ustring.match(rowformat, "^[*#]") == "*" then
				preformat = "<ul><li>"
				postformat = "</li></ul>"
			else
				preformat = "<ol><li>"
				postformat = "</li></ol>"
			end
			rowformat = mw.ustring.gsub(rowformat, "^[*#] ?", "")
		end
		
		-- set whitelist and blacklist values
		whitelist, whitelisted = setWhiteOrBlackList("whitelist", #qualifierId, args)
		blacklist, blacklisted = setWhiteOrBlackList("blacklist", #qualifierId, args)
	end
	
	-- fetch property
	local claims
	for p in string.gmatch(property, 'P%d+') do
		claims = findClaims(id, p)
		if claims and claims[1] then
			break
		end
	end
	if not claims or not claims[1] then
		if showerrors then return printError("property-not-found") else return default end
	end
	
	-- find language and defaults
	parameters.lang = findLang(args.lang)
	
	-- 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 = mw.wikibase.getBestStatements(id, itemgender)[1]
			if snak and snak.mainsnak and snak.mainsnak.datavalue and snak.mainsnak.datavalue.value then
				idgender = snak.mainsnak.datavalue.value.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 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
	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 firstrank = parameters.list == "firstrank" and claims[sortindices[1]].rank or ''
		local rowlist = {} -- rows to list with whitelist or blacklist
		for idx in pairs(claims) do
			local claim = claims[sortindices[idx]]
			local reference = {}
			if not whitelisted then rowlist[idx] = true end
			if firstrank ~= '' and firstrank ~= claim.rank then
				break
			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 == 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 = findClaims(id, string.sub(q, 2))
									if claim2 then
										valueq, sortkeyq, _ = getValueOfClaim(claim2[1], nil, params)
									end
								else
									valueq, sortkeyq, _ = getValueOfClaim(claim, q, params)
								end
								if valueq then break end
							end
						end
						values[#values]["col" .. j] = valueq
						sortkeys[#sortkeys]["col" .. j] = sortkeyq or valueq
						if whitelist[j] or blacklist[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
							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, '/', true)
			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
		result = {}
		for idx in pairs(values) do
			local valuerow = values[sortindices[idx]]
			local reference = getReferences({["references"] = refs[sortindices[idx]]["col0"]})
			
			value = valuerow["col0"]
			if parameters.formatting == "table" then
				if not rowlist[sortindices[idx]] then
					value = nil
				else
					value = mw.ustring.gsub(rowformat .. "$", "$0", value) -- fake end character added for easy gsub
					value = mw.ustring.gsub(value, "$R0", reference) -- add reference
					local rowformatting = rowformat .. "$"
					for i, _ in ipairs(qualifierId) do
						local valueq = valuerow["col" .. i]
						if args["rowsubformat" .. i] and valueq then
							-- add fake end character $
							-- gsub $i not followed by a number so $1 doesn't match $10, $11...
							-- remove fake end character
							valueq = mw.ustring.gsub(args["rowsubformat" .. i] .. "$", "$" .. i .. "(%D)", valueq .. "%1")
							valueq = string.sub(valueq, 1, -2)
							rowformatting = mw.ustring.gsub(rowformatting, "$" .. i .. "(%D)", args["rowsubformat" .. i] .. "%1")
						end
						valueq = valueq and urlEscapes(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
				if isSet(value) then
					result[#result + 1] = value
				end
			end
			if not parameters.list then
				break
			end
		end
		result = preformat .. mw.text.listToText(result, parameters.separator, parameters.conjunction) .. postformat
	else
		-- return first element
		local claim = claims[sortindices[1]]
		result, _, error = getValueOfClaim(claim, qualifierId[1], parameters)
		if result and references then result = result .. getReferences(claim) end
	end
	
	if isSet(result) then
		return result
	else
		if showerrors then return error else return default end
	end
end

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

-- Local functions for getParentValues -----------------------

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

local function getPropertyValue(id, property, parameter, langs, editicon, case)
	local snaks = mw.wikibase.getBestStatements(id, property)
	local mysnak
	if snaks and snaks[1] and snaks[1].mainsnak then
		mysnak = snaks[1].mainsnak
	else
		return
	end
	
	local 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, editicon=editicon, case=case})
	end
	
	return entity_id, result
end

local function contains(tab, val)
	for index, value in ipairs(tab) do
		if value == val then
			return true
		end
	end
	
	return false
end

local function getParentObjects(id,
	formatting,
	languages, 
	propertySupString, 
	propertyLabel,
	propertyLink,
	labelShow,
	editicon,
	upto,
	upto_linkId,
	last_only,
	grammatical_case,
	include_self)
	
	if (upto_linkId == nil) then upto_linkId = "" end
	local upto_link_ids = mw.text.split(upto_linkId, '[/%s]+')
	local propertySups = mw.text.split(propertySupString, '[/%s]+')
	
	local lastlabel = uc_first(upto or '')
	local maxloop = tonumber(upto) or (lastlabel == '' and 10 or 50)
	
	local labelFilter = {}
	if labelShow then
		for i, v in ipairs(mw.text.split(labelShow, "/")) do
			labelFilter[uc_first(v)] = true
		end
	end
	
	local label_self
	_, label_self = getPropertyValue(id, propertyLabel, "label", languages)
	
	local result = {}
	
	local label, link, linktext
	
	for iter = 1, maxloop do
		local label, link
		for _, propertySup in pairs(propertySups) do 	
			_id, _link = getPropertyValue(id, propertySup, formatting, languages, editicon, grammatical_case)
			if _id and _link then id = _id link = _link break end
		end
		
		if not id or not link then break end
		
		if propertyLink then
			_, linktext = getPropertyValue(id, propertyLink, "label", languages)
			if linktext then
				link = mw.ustring.gsub(link, "%[%[(.*)%|.+%]%]", "[[%1|" .. linktext .. "]]")
			end
		end
		
		--_, label = getPropertyValue(id, propertyLabel, "label", languages, editicon, "infoboxlabel")
		_, label = getPropertyValue(id, propertyLabel, "label", languages, false, "infoboxlabel") -- check Template:Automatic taxobox
		
		if labelShow == nil or labelFilter[label] then
			result[#result + 1] = {label, link}
			
			if label then 
				labelFilter[label] = nil -- only first label found
			end
		end
		
		if not tonumber(upto) and label == lastlabel then
			break
		end
		
		if contains(upto_link_ids, id) then
			break
		end
	end
	
	if last_only then
		result = {result[#result]}
	end
	
	if include_self then table.insert(result, 1, {label_self, mw.title.getCurrentTitle().text}) end
	
	return result
end

local function parentObjectsToString(result,
	rowformat,
	separator, 
	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 prefix = ""
		for i = 1, #ret do
			ret[i] = prefix .. "• " .. ret[i]
			prefix = prefix .. "&nbsp;"
		end
	end
	
	return mw.text.listToText(ret, separator, separator)
end

-- Returns pairs of instance 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
	local id = args.item or (pargs and pargs.item)
	if not isSet(id) then
		id = mw.wikibase.getEntityIdForCurrentPage()
		if id == nil then return end
	end
	local languages = findLang(args.lang)
	local propertySup = args["property"]; if not isSet(propertySup) then propertySup = "P131" end --administrative entity
	local propertyLabel = args["label"]; if not isSet(propertyLabel) then propertyLabel = "P31" end --instance
	local propertyLink = args["valuetext"]; if propertyLink == "" then propertyLink = nil end --internallink
	local upto = args["upto"]; if upto == "" then upto = nil end
	local last_only = (args.last_only == "true" or args.last_only == "yes")
	local labelShow = args["labelshow"]; if labelShow == "" then labelShow = nil end
	local editicon = not (args.editicon == "false" or args.editicon == "no")
	local include_self = (args.include_self == "true" or args.include_self == "yes")
	local case = args["case"]; if case == "" then case = nil end
	
	if isSet(args.uptolabelid) then
		upto = mw.wikibase.getLabel(args.uptolabelid)
	end
	
	if isSet(args.showlabelid) then
		local showLabelList = {} for substring in mw.text.gsplit(args.showlabelid, '[/%s]+') do table.insert(showLabelList, mw.wikibase.getLabel(substring)) end
		if #showLabelList > 0 then
			labelShow = table.concat(showLabelList,"/")
		end
	end
	
	local result = getParentObjects(id,
		args.formatting,
		languages,
		propertySup,
		propertyLabel,
		propertyLink,
		labelShow,
		editicon,
		upto,
		args.uptolinkid,
		last_only,
		case,
		include_self)
	
	local rowformat = args["rowformat"]; if not isSet(rowformat) then rowformat = "$0 = $1" 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")
	
	return parentObjectsToString(result,
		rowformat,
		separator,
		cascade,
		sorting)
end

-- Link with a parent label --------------------
function p.linkWithParentLabel(frame)
	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 internal link of property/qualifier
	local largs = mw.clone(args)
	largs.list = "true"
	largs.formatting = "internallink"
	largs.separator = "/·/"
	largs.editicon = "false"
	local link_list = p.claim(largs)
	if not isSet(link_list) then
		return
	end
	local link_table = mw.text.split(link_list, "/·/", true)
	
	-- get id value of property/qualifier
	largs.formatting = "raw"
	local items_list = p.claim(largs)
	local items_table = mw.text.split(items_list, "/·/", true)
	
	-- get label of parent property
	local parent_claims = findClaims(items_table[1], args.parent)
	if parent_claims and parent_claims[1].mainsnak.datatype == '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 = not (args.editicon == "false" or args.editicon == "no")
	args.id = args.item or mw.wikibase.getEntityIdForCurrentPage()
	args.lang = findLang(args.lang)
	return mw.text.listToText(link_table)
end

-- Calculate number of years old ----------------------------
function p.yearsOld(frame)
	local args = frame.args or frame -- via invoke or require
	local id = args.item
	if not isSet(id) then
		id = mw.wikibase.getEntityIdForCurrentPage()
	end
	local lang = mw.language.new('en')
	
	local function getBestValue(id, prop)
		local snak = mw.wikibase.getBestStatements(id, prop)[1]
		if snak and snak.mainsnak and snak.mainsnak.datavalue and snak.mainsnak.datavalue.value then
			return snak.mainsnak.datavalue.value
		end
	end
	
	local birth = getBestValue(id, 'P569')
	if type(birth) ~= 'table' or birth.time == nil or birth.precision == nil or birth.precision < 8 then
		return
	end
	local death = getBestValue(id, 'P570')
	if type(death) ~= 'table' or death.time == nil or death.precision == nil then
		death = {['time'] = lang:formatDate('c'), ['precision'] = 11} -- current date
	elseif death.precision < 8 then
		return
	end
	
	local dates = {}
	dates[1] = {['min'] = {}, ['max'] = {}, ['precision'] = birth.precision}
	dates[1].min.year = tonumber(mw.ustring.match(birth.time, "^[+-]?%d+"))
	dates[1].min.month = tonumber(mw.ustring.match(birth.time, "\-(%d%d)\-"))
	dates[1].min.day = tonumber(mw.ustring.match(birth.time, "\-(%d%d)T"))
	dates[1].max = mw.clone(dates[1].min)
	dates[2] = {['min'] = {}, ['max'] = {}, ['precision'] = death.precision}
	dates[2].min.year = tonumber(mw.ustring.match(death.time, "^[+-]?%d+"))
	dates[2].min.month = tonumber(mw.ustring.match(death.time, "\-(%d%d)\-"))
	dates[2].min.day = tonumber(mw.ustring.match(death.time, "\-(%d%d)T"))
	dates[2].max = mw.clone(dates[2].min)
	
	for i, d in ipairs(dates) do
		if d.precision == 10 then -- month
			d.min.day = 1
			local timestamp = string.format("%04d", tostring(math.abs(d.max.year)))
				.. string.format("%02d", tostring(d.max.month))
				.. "01"
			d.max.day = tonumber(lang:formatDate("j", timestamp .. " + 1 month - 1 day"))
		elseif d.precision < 10 then -- year or decade
			d.min.day = 1
			d.min.month = 1
			d.max.day = 31
			d.max.month = 12
			if d.precision == 8 then -- decade
				d.max.year = d.max.year + 9
			end
		end
	end
	
	local function age(d1, d2)
		local years = d2.year - d1.year
		if d2.month < d1.month or (d2.month == d1.month and d2.day < d1.day) then
			years = years - 1
		end
		if d2.year > 0 and d1.year < 0 then
			years = years - 1 -- no year 0
		end
		return years
	end
	
	local old_min = age(dates[1].max, dates[2].min)
	local old_max = age(dates[1].min, dates[2].max)
	local old, old_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 .. '&nbsp;' .. 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 id = mw.text.trim(args[1] or "")
	if not isSet(id) then return end
	local editicon = not (args.editicon == "false" or args.editicon == "no") and mw.wikibase.isValidEntityId(id)
	
	local label_icon = ''
	local label, lang
	if args.label then
		label = args.label
	else
		local languages = findLang(args.lang)
		-- exceptions or labels fixed
		local exist, labels = pcall(require, wiki.module_title .. "/labels" .. (languages[1] == wiki.langcode and '' or '/' .. languages[1]))
		if exist and next(labels.infoboxLabelsFromId) ~= nil then
			label = labels.infoboxLabelsFromId[id]
		end
		
		if label == nil then
			local new_id = resolveEntityId(id)
			if new_id then
				label, lang = getLabelByLangs(new_id, languages)
				if label then
					if args.itemgender and feminineGender(args.itemgender) then
						label = feminineForm(new_id, lang) or label
					end
					label = mw.language.new(lang):ucfirst(mw.text.nowiki(label)) -- sanitize
				end
				label_icon = addLabelIcon(new_id or id, lang, languages[1], editicon)
			end
		end
	end
	
	local linked = args.linked
	if isSet(linked) and linked ~= "no" then
		local article = mw.wikibase.getSitelink(id) or ("d:" .. id)
		return "[[" .. article .. "|" .. (label or id) .. "]]" .. label_icon
	else
		return (label or id) .. label_icon
	end
end

-- Utilities -----------------------------

-- debugging functions, see module ../debug.
function p.ViewSomething(frame)
	return require(wiki.module_title .. "/debug").ViewSomething(frame)
end

function p.Dump(frame)
	return require(wiki.module_title .. "/debug").Dump(frame)
end

function p.getEntityFromTree(frame)
	return require(wiki.module_title .. "/debug").getEntityFromTree(frame)
end

-- Copied from Module:Wikibase
function p.getSiteLink(frame)
	local id = frame.args[1]
	if not isSet(id) then
		id = mw.wikibase.getEntityIdForCurrentPage()
		if id == nil then
			return
		end
	end
	return mw.wikibase.getSitelink(id, frame.args[2])
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
	local id = args.item
	if id == '' or id == nil then
		id = mw.wikibase.getEntityIdForCurrentPage()
		if id == nil then
			return 0
		end
	end
	local prop = mw.text.trim(args[1])
	local num = mw.wikibase.getBestStatements(id, prop)
	return #num
end

-- Returns the first id or value of given property or nil if not found, not isValidEntityId or novalue/somevalue
-- See Module:Wikibase
function p.validProperty(frame)
	local property = mw.text.trim(frame.args[1])
	local item = frame.args.item or frame.args.from; if item == '' then item = nil end
	local type = frame.args.type or "id"
	local entity = mw.wikibase.getEntity(item)
	if not entity then return end
	if not entity.claims then return end
	local hasProp = entity.claims[property]
	if not hasProp then return end
	if not hasProp[1].mainsnak.datavalue then return end
	if type == "value" then return hasProp[1].mainsnak.datavalue.value end
	if not hasProp[1].mainsnak.datavalue.value.id then return end
	if not mw.wikibase.isValidEntityId(hasProp[1].mainsnak.datavalue.value.id) then return end
	return hasProp[1].mainsnak.datavalue.value.id
end

function p.labelOf(frame)
	local id = frame.args[1]
	-- returns the label of the given entity/property id
	-- if no id is given, the one from the entity associated with the calling Wikipedia article is used
	if not id then
		local entity = mw.wikibase.getEntity()
		if not entity then return printError("entity-not-found") end
		id = entity.id
	end
	return mw.wikibase.getLabel(id)
end

local function bestranked(claims)
	if not claims then
		return nil
	end
	local preferred, normal = {}, {}
	for i, j in pairs(claims) do
		if j.rank == 'preferred' then
			table.insert(preferred, j)
		elseif j.rank == 'normal' then
			table.insert(normal, j)
		end
	end
	if #preferred > 0 then
		return preferred
	else
		return normal
	end
end

function p.labelIn(frame)
	local langcode = frame.args[1] or wiki.langcode
	local id = frame.args[2]
	local property_id = frame.args["p"]

	local entity = mw.wikibase.getEntity(id)
	
	if property_id ~= nil then
		local claims = findClaims(entity.id, property_id)
		if not claims or not claims[1] then
			return nil
		end
		claims = bestranked(claims)
		local claim_id = getValueOfClaim(claims[1], nil, {["formatting"]="raw"})
		entity = mw.wikibase.getEntity(claim_id)
	end
	
	-- return label of a Wikidata entity in the given language or the default language of this Wikipedia site
	return entity.labels[langcode].value
end

function p.internalLinkOf(frame)
	local id = frame.args[1]
	if id == nil then
		return nil
	end
	
	local entity = mw.wikibase.getEntity(id)
	if entity == nil then
		return nil
	end
	
	local res = printDatavalueEntity(entity, { formatting ="ucinternallink", lang = findLang()})
	return res
end

function p.claimsCount(frame)
	local property = frame.args["property"]
	local id = frame.args["id"]
	-- get wikidata entity
	local entity = mw.wikibase.getEntity(id)
	if not entity then
		if showerrors then return printError("entity-not-found") else return default end
	end
	-- fetch the first claim of satisfying the given property
	local claims = findClaims(id, property)
	if not claims or not claims[1] then
		if showerrors then return printError("property-not-found") else return default end
	end

	return #claims
end

function p.processMarkup(frame)
	local f = (frame.args[1] or frame.args.item) and frame or frame:getParent()
	return f:preprocess(f.args[1])
end

return p