This module is intended to fetch data from Wikidata with or without a link to the connected Wikipedia article and with many other features.
Usage
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.
{{#invoke:wd|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
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 |
---|---|
{{#invoke:wd|label|raw}} | Returns the Q-identifier of the Wikidata item connected to the current page (e.g. "Q55"). |
{{#if: | 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 |
Commands
The commands (command1
, command2
, ...) determine what kind of values are returned. One call can only contain commands from a single class.
Claim class
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[a] | {{#invoke:wd|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 | {{#invoke:wd|properties|P1}} | ||
II | qualifier | first match[b] | {{#invoke:wd|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 | {{#invoke:wd|qualifiers|P1|P2}} | ||
III | reference | first match[b] | {{#invoke:wd|reference|P1}} | Returns a reference – or list of references – from the given property of the current item-entity or of a given entity.[c] This command can be given only once in one call. |
references | all matches | {{#invoke:wd|references|P1}} | ||
General class
The general class commands cannot be combined.
Type | Command | Returns | Basic usage | Description |
---|---|---|---|---|
I | label | {{#invoke:wd|label}} | Returns the label of the current item-entity or of a given entity if present. | |
II | title | {{#invoke:wd|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 | {{#invoke:wd|description}} | Returns the description of the current item-entity or of a given entity if present. | |
IV | alias | first match[a] | {{#invoke:wd|alias}} | Returns an alias – or list of aliases – of the current item-entity or of a given entity if present. |
aliases | all matches | {{#invoke:wd|aliases}} | ||
V | badge | first match[a] | {{#invoke:wd|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 | {{#invoke:wd|badges}} | ||
Flags
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
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 If this flag is used with time datatypes, then the returned date will be in the format of If it is used with globe coordinate datatypes, then it replaces the various symbols with forward slashes in the returned value (e.g. |
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 short name (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
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 If the The default is 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 start time (P580) and end time (P582) to determine if the claim is valid for the selected time period(s). The default is | 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 | claim, general |
edit@end |
Arguments
The arguments determine the sources from which all the returned values are fetched.
Positional arguments
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) | |||
{{#invoke:wd | 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 If this parameter is omitted, then the item-entity connected to the current page will be used (except when |
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 Globe coordinates as literal values must be formatted with forward slashes (i.e. The special type 'no value' can be given by entering the empty string (i.e. To get a literal vertical bar 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
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 This argument only has effect if the positional argument | 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 | 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 start time (P580) and end time (P582)).The date value must be formatted | 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, Example: Multiple arguments of this type can be given to match multiple qualifier values simultaneously for each claim. | claim |
Property aliases
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
When either the reference
or the references
command is used and a reference is encountered (in Wikidata), the module attempts to display it using the {{Cite web}} template. The reference to be displayed has to have at least title (P1476) and reference URL (P854) properties. The below table shows the mapping of Wikidata properties to parameters of Cite web.
Wikidata property | Parameter of Cite web | Notes |
---|---|---|
archive date (P2960) | archive-date | |
archive URL (P1065) | archive-url | |
author (P50) | authorN | N can be 1, 2, 3... |
author name string (P2093) | ||
language of work or name (P407) | language | Ignored when the same as the local language. |
page(s) (P304) | pages | |
publication date (P577) | date | |
publisher (P123) | publisher | |
quotation (P1683) | quote | |
reference URL (P854) | url | |
retrieved (P813) | access-date | Ignored when Wikimedia import URL (P4656) is present but reference URL (P854) is not. |
section, verse, paragraph, or clause (P958) | at | |
stated in (P248) | website | |
subject named as (P1810) | title | Used only when title (P1476) is not present, but a URL (either from reference URL (P854) or from an external identifier, as described below) is, otherwise ignored. |
title (P1476) | title |
The following properties are ignored: image (P18), imported from Wikimedia project (P143), inferred from (P3452), type of reference (P3865), Wikimedia import URL (P4656).
If there is no reference 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 Wikidata property (P1687) of the item in stated in (P248), a URL is generated from its content and is used in the same manner as a URL given in reference URL (P854).
If a title (P1476) or a reference URL (P854) property is missing or the reference has unknown properties, the module attempts to display it using the {{Cite Q}} template. The stated in (P248) property is needed. It's used for the first (unnamed) parameter of Cite Q. The below table shows the mapping of other properties to Cite Q parameters.
Wikidata property | Parameter of Cite Q | Notes |
---|---|---|
chapter (P792) | chapter | |
column (P3903) | at | |
page(s) (P304) | pages | |
publication date (P577) | date | |
retrieved (P813) | access-date | |
section, verse, paragraph, or clause (P958) | section | |
title (P1476) | title | |
any property of the "External identifier" data type | id | The label 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 stated in (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, the following error is returned:
Error: Unable to display the reference properly. See the documentation for details.
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.
Note: Users copying this template/module to another wiki: The local names of the Cite web and Cite Q templates are fetched from the sitelinks of the Q5637226 or the Q22321052 item, respectively. If the local citation template isn't linked from its Wikidata item or it doesn't exist at all, this module skips attempting to display citations using it.
Advanced usage
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 |
.
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.
Optional parameters can be given by encapsulating them between square brackets: To use two opening square brackets that directly follow each other (i.e. At least one parameter must be given that is not optional, while the To get a literal | ||||||||||||||||
%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 | ||||||||||||||||
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 | ||||||||||||||||
;_ | 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
Parameters and output types | Example | Description |
---|---|---|
Q55 = "Netherlands", P395 = "licence plate code"
[string] | {{#invoke:wd|property|Q55|P395}}
| Gets a literal string value. |
P395 = "licence plate code"
[string] | {{#invoke:wd|property|P395}}
| 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] | {{#invoke:wd|property|eid=Q55|P395}}
| An entity-ID can also be given using the eid= argument. |
P395 = "NL"
[string] | {{#invoke:wd|property|page=Netherlands|P395}}
| A page title can be given instead of an entity-ID using the page= argument. |
Q55 = "Netherlands", P395 = "licence plate code"
[string] | {{#invoke:wd|property|edit|Q55|P395}} | Adds a clickable icon that may be used to edit the returned value on Wikidata. |
Q55 = "Netherlands", P395 = "licence plate code"
[string] | {{#invoke:wd|property|edit@end|Q55|P395}} | Places the edit icon at the end of the line. |
Q55 = "Netherlands", P1082 = "population"
[quantity] | {{#invoke:wd|property|normal+|Q55|P1082}}
| Gets a single property value from claims with a 'normal' rank or higher. |
Q55 = "Netherlands", P1082 = "population"
[quantity] | {{#invoke:wd|properties|normal+|Q55|P1082}}
| Gets multiple property values from claims with a 'normal' rank or higher. |
Q55 = "Netherlands", P1082 = "population", P585 = "point in time"
[quantity], [time] | {{#invoke:wd|properties|qualifier|normal+|Q55|P1082|P585}}
| Gets a single qualifier value for each claim, additional to the property value. |
Q55 = "Netherlands", P1082 = "population", P585 = "point in time"
[quantity], [time], [reference] | {{#invoke:wd|properties|qualifier|references|normal+|Q55|P1082|P585}} | Gets references for each claim. |
Q55 = "Netherlands", P1082 = "population"
[quantity], [reference] | A total of
| Gets a property with its references. |
Q55 = "Netherlands", P1082 = "population"
[quantity], [reference] | The Netherlands has a population of
| 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>
| Returns the output in a custom format. |
Q55 = "Netherlands", P1082 = "population", P585 = "point in time"
[time] | {{#invoke:wd|qualifier|normal+|Q55|P1082|P585}}
| Gets a single qualifier per claim, by default for multiple matching claims. |
Q55 = "Netherlands", P1082 = "population", P585 = "point in time"
[time] | {{#invoke:wd|qualifier|normal+|single|Q55|P1082|P585}}
| 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] | {{#invoke:wd|qualifier|Q55|P1082|10026773|P585}}
| 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] | {{#invoke:wd|qualifier|mdy|Q55|P1082|10026773|P585}}
| Gets dates in month-day-year order. |
Q55 = "Netherlands", P1082 = "population", P585 = "point in time"
[time] | {{#invoke:wd|qualifier|raw|Q55|P1082|10026773|P585}}
| Gets a raw date value. |
Q55 = "Netherlands", P1082 = "population"
[reference] | {{#invoke:wd|references|Q55|P1082|10026773}}
| Gets the references from a particular claim. |
Q55 = "Netherlands", P1082 = "population"
[reference] | {{#invoke:wd|references|raw|Q55|P1082|10026773}}
| Gets references from a particular claim in their raw form. |
Q55 = "Netherlands", P1081 = "Human Development Index"
[quantity], [reference] | {{#invoke:wd|properties|references|normal+|Q55|P1081}}
| Gets properties from each claim with any references they have. |
Q55 = "Netherlands", P1081 = "Human Development Index"
[quantity], [reference] | {{#invoke:wd|properties|references|normal+|sourced|Q55|P1081}}
| Only gets properties from claims that have at least one reference. |
Q55 = "Netherlands", P2855 = "VAT rate", P518 = "applies to part"
[entity label] | {{#invoke:wd|qualifier|Q55|P2855|P518}}
| Gets a single qualifier value (for each matching claim). |
Q55 = "Netherlands", P2855 = "VAT rate", P518 = "applies to part"
[entity label] | {{#invoke:wd|qualifiers|Q55|P2855|P518}}
| Gets multiple qualifier values (for each matching claim). |
Q55 = "Netherlands", P2855 = "VAT rate", P518 = "applies to part"
[quantity], [entity label] | {{#invoke:wd|properties|qualifiers|Q55|P2855|P518}}
| Gets multiple property values along with multiple qualifier values. |
Q55 = "Netherlands", P2855 = "VAT rate", P518 = "applies to part"
[quantity], [entity label] | {{#invoke:wd|properties|qualifiers|Q55|P2855|P518|sep=_+_|sep%s=|sep%q=_/_}}
| Returns the output with custom separators. |
Q55 = "Netherlands", P35 = "head of state", P580 = "start time", P582 = "end time"
[entity label], [time] | {{#invoke:wd|properties|qualifier|qualifier|normal+|Q55|P35|P580|P582}}
| Gets two different qualifier values for each claim. |
Q55 = "Netherlands", P35 = "head of state", P580 = "start time", P582 = "end time"
[entity label], [time] | {{#invoke:wd|properties|qualifier|qualifier|normal+|Q55|P35|P580|P582|sep%q=_–_}}
| Returns the output with a custom separator. |
Q55 = "Netherlands", P35 = "head of state", P580 = "start time", P582 = "end time"
[entity label], [time] | {{#invoke:wd|properties|qualifier|qualifier|normal+|Q55|P35|P580|P582|format=%p[ <span style="font-size:85\%">(%q1[ – %q2])</span>][%s][%r]}}
| 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] | {{#invoke:wd|properties|qualifier|qualifier|normal+|Q55|P35|P580|P582|format=%p[ <span style="font-size:85\%">([<![]--%q2]since [%q2--[]>]%q1[ – %q2])</span>][%s][%r]}}
| 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] | {{#invoke:wd|properties|qualifier|raw|qualifier|normal+|Q55|P35|Q29574|P580|P582|format=%p[ <span style="font-size:85\%">(%q1[ – %q2])</span>][%s][%r]}}
| 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] | {{#invoke:wd|properties|qualifiers|normal+|current|Q55|P38|P518}}
| Gets claims that are currently valid. |
Q55 = "Netherlands", P38 = currency", P518 = "applies to part"
[entity label] | {{#invoke:wd|properties|linked|qualifiers|normal+|current|Q55|P38|P518}}
| Gets claims with linked property values. |
Q55 = "Netherlands", P38 = currency", P518 = "applies to part"
[entity label] | {{#invoke:wd|properties|qualifiers|linked|normal+|current|Q55|P38|P518}}
| Gets claims with linked qualifier values. |
Q55 = "Netherlands", P38 = currency", P518 = "applies to part"
[entity label] | {{#invoke:wd|properties|linked|short|qualifiers|linked|normal+|current|Q55|P38|P518}}
| 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] | {{#invoke:wd|qualifiers|normal+|current|Q55|P38|Q4917|P518}}
| 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] | {{#invoke:wd|properties|normal+|current|Q55|P38|P518=Q27561}}
| Gets properties from claims for which a (raw) qualifier value matches a given Q-identifier. |
Q55 = "Netherlands", P38 = currency"
[entity label] | {{#invoke:wd|properties|normal+|former|Q55|P38}}
| Gets claims that were valid in the past. |
Q55 = "Netherlands", P38 = currency"
[entity label] | {{#invoke:wd|properties|raw|normal+|former|Q55|P38}}
| Gets raw property values. |
Q55 = "Netherlands", P38 = currency"
[entity label] | {{#invoke:wd|properties|raw|linked|normal+|former|Q55|P38}} | Gets raw property values that are linked to Wikidata. |
Q55 = "Netherlands", P1549 = "demonym"
[monolingual text] | {{#invoke:wd|property|Q55|P1549}}
| 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] | {{#invoke:wd|property|multilanguage|Q55|P1549|P407=Q36846}}
| Gets a monolingual text value in any available language. |
Q55 = "Netherlands", P2884 = "mains voltage"
[quantity] | {{#invoke:wd|property|Q55|P2884}}
| Gets a quantity value with its associated unit of measurement. |
Q55 = "Netherlands", P2884 = "mains voltage"
[quantity] | {{#invoke:wd|property|linked|Q55|P2884}}
| Gets a quantity value with a linked unit of measurement. |
Q55 = "Netherlands", P2884 = "mains voltage"
[quantity] | {{#invoke:wd|property|raw|Q55|P2884}}
| Gets a raw quantity value. |
Q55 = "Netherlands", P2884 = "mains voltage"
[quantity] | {{#invoke:wd|property|unit|Q55|P2884}}
| Gets only the unit of measurement. |
Q55 = "Netherlands", P2884 = "mains voltage"
[quantity] | {{#invoke:wd|property|unit|raw|Q55|P2884}}
| Gets the raw unit of measurement. |
Q55 = "Netherlands", P625 = "coordinate location"
[globe coordinate] | {{#invoke:wd|property|Q55|P625}}
| Gets a globe coordinate value. |
Q55 = "Netherlands", P625 = "coordinate location"
[globe coordinate] | {{#invoke:wd|property|linked|Q55|P625}} | Gets a linked globe coordinate value. |
Q55 = "Netherlands", P625 = "coordinate location"
[globe coordinate] | {{#invoke:wd|property|raw|Q55|P625}}
| Gets a raw globe coordinate value. |
Q55 = "Netherlands", P625 = "coordinate location"
[globe coordinate] | {{#invoke:wd|property|Q55|coord}}
| A property alias can be used instead of the P-identifier. |
Q55 = "Netherlands", P41 = "flag image"
[commons media] | {{#invoke:wd|property|linked|Q55|P41}} | Gets a media file name and links to it on Commons. |
Q55 = "Netherlands", P41 = "flag image"
[commons media] | {{#invoke:wd|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] | {{#invoke:wd|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] | {{#invoke:wd|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] | {{#invoke:wd|property|Q915684|P2534}} | Gets a mathematical expression. |
Q915684 = "Lorentz–Lorenz equation", P7235 = "in defining formula", P9758 = "symbol represents"
[entity label], [math] | <ul>
| Mathematical expressions can be combined with regular text as usual. |
Q6256 = "country", P3896 = "geoshape"
[geographic shape] | {{#invoke:wd|property|linked|Q6256|P3896}} | Gets a geographic shape data file name and links to it on Commons. |
Q4917 = "United States dollar"
[entity label] | {{#invoke:wd|label|Q4917}}
| Gets an item's label. |
Q4917 = "United States dollar"
[entity label] | {{#invoke:wd|label|short|linked|Q4917}} | Gets an item's short and linked label. |
P38 = currency"
[entity label] | {{#invoke:wd|label|P38}}
| Gets a property's label. |
P38 = currency"
[entity label] | {{#invoke:wd|label|linked|P38}} | Gets a property's label that is linked to Wikidata. |
Q776 = "Utrecht"
[entity label] | {{#invoke:wd|label|Q776}}
| Gets an item's label. |
Q776 = "Utrecht"
[entity label] | {{#invoke:wd|label|linked|Q776}} | Gets an item's linked label. |
[entity label] | {{#invoke:wd|label}}
| If the module is transcluded on the Utrecht (province) page (which is linked to Q776), then the Q776 can be omitted. |
[entity label] | {{#invoke:wd|label|raw}}
| 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] | {{#invoke:wd|label|raw|linked}}
| 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] | {{#invoke:wd|title|Q776}}
| Gets the title of the page on the current wiki that is linked to the given item. |
Q776 = "Utrecht"
[page title] | {{#invoke:wd|title|linked|Q776}} | Gets the linked title of the page on the current wiki that is linked to the given item. |
[page title] | {{#invoke:wd|title}}
| 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] | {{#invoke:wd|description|Q55}}
| Gets an item's description. |
[entity description] | {{#invoke:wd|description}}
| If the module is transcluded on the Netherlands page (which is linked to Q55), then the Q55 can be omitted. |
Q55 = "Netherlands"
[entity alias] | {{#invoke:wd|alias|Q55}}
| Gets one of an item's aliases. |
Q55 = "Netherlands"
[entity alias] | {{#invoke:wd|aliases|Q55}}
| Gets all of an item's aliases. |
Q55 = "Netherlands"
[entity alias] | {{#invoke:wd|alias|linked|Q55}} | Gets a linked alias from an item. |
[entity alias] | {{#invoke:wd|alias}}
| If the module is transcluded on the Netherlands page (which is linked to Q55), then the Q55 can be omitted. |
Q2 = "Earth"
[page badge] | {{#invoke:wd|badges|Q2}}
| Gets the badges for the page on the current wiki that is linked to the given item. |
Q2 = "Earth"
[page badge] | {{#invoke:wd|badges|raw|Q2}}
| Gets the raw badges for the page on the current wiki that is linked to the given item. |
[page badge] | {{#invoke:wd|badges}}
| 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] | {{#invoke:wd|property|reference|edit|Q28865|P548=Q2804309|P348}}
| 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
TemplateData
This template fetches data from the centralized knowledge base Wikidata. To edit the data, click on "Wikidata item" in the left sidebar.
Parameter | Description | Type | Status | |||
---|---|---|---|---|---|---|
No parameters specified |
See also
- {{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
-- Original module located at [[:en:Module:Wd]] and [[:en:Module:Wd/i18n]].require("strict")local p = {}local arg = ...local i18nlocal function loadI18n(aliasesP, frame)local titleif frame then-- current module invoked by page/template, get its title from frametitle = frame:getTitle()else-- current module included by other module, get its title from ...title = argendif not i18n theni18n = require(title .. "/i18n").init(aliasesP)endendp.claimCommands = {property = "property",properties = "properties",qualifier = "qualifier",qualifiers = "qualifiers",reference = "reference",references = "references"}p.generalCommands = {label = "label",title = "title",description = "description",alias = "alias",aliases = "aliases",badge = "badge",badges = "badges"}p.flags = {linked = "linked",short = "short",raw = "raw",multilanguage = "multilanguage",unit = "unit",-------------preferred = "preferred",normal = "normal",deprecated = "deprecated",best = "best",future = "future",current = "current",former = "former",edit = "edit",editAtEnd = "edit@end",mdy = "mdy",single = "single",sourced = "sourced"}p.args = {eid = "eid",page = "page",date = "date",globalSiteId = "globalSiteId"}local aliasesP = {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",publishedIn = "P1433"}local aliasesQ = {percentage = "Q11229",prolepticJulianCalendar = "Q1985786",citeWeb = "Q5637226",citeQ = "Q22321052"}local parameters = {property = "%p",qualifier = "%q",reference = "%r",alias = "%a",badge = "%b",separator = "%s",general = "%x"}local formats = {property = "%p[%s][%r]",qualifier = "%q[%s][%r]",reference = "%r",propertyWithQualifier = "%p[ <span style=\"font-size:85\\%\">(%q)</span>][%s][%r]",alias = "%a[%s]",badge = "%b[%s]"}local hookNames = { -- {level_1, level_2}[parameters.property] = {"getProperty"},[parameters.reference] = {"getReferences", "getReference"},[parameters.qualifier] = {"getAllQualifiers"},[parameters.qualifier.."\\d"] = {"getQualifiers", "getQualifier"},[parameters.alias] = {"getAlias"},[parameters.badge] = {"getBadge"}}-- default value objects, should NOT be mutated but instead copiedlocal defaultSeparators = {["sep"] = {" "},["sep%s"] = {","},["sep%q"] = {"; "},["sep%q\\d"] = {", "},["sep%r"] = nil, -- none["punc"] = nil -- none}local rankTable = {["preferred"] = 1,["normal"] = 2,["deprecated"] = 3}local function replaceAlias(id)if aliasesP[id] thenid = aliasesP[id]endreturn idendlocal function errorText(code, param)local text = i18n["errors"][code]if param then text = mw.ustring.gsub(text, "$1", param) endreturn textendlocal function throwError(errorMessage, param)error(errorText(errorMessage, param))endlocal function replaceDecimalMark(num)return mw.ustring.gsub(num, "[.]", i18n['numeric']['decimal-mark'], 1)endlocal function padZeros(num, numDigits)local numZeroslocal negative = falseif num < 0 thennegative = truenum = num * -1endnum = tostring(num)numZeros = numDigits - num:len()for _ = 1, numZeros donum = "0"..numendif negative thennum = "-"..numendreturn numendlocal function replaceSpecialChar(chr)if chr == '_' then-- replace underscores with spacesreturn ' 'elsereturn chrendendlocal function replaceSpecialChars(str)local chrlocal esc = falselocal strOut = ""for i = 1, #str dochr = str:sub(i,i)if not esc thenif chr == '\\' thenesc = trueelsestrOut = strOut .. replaceSpecialChar(chr)endelsestrOut = strOut .. chresc = falseendendreturn strOutendlocal function buildWikilink(target, label)if not label or target == label thenreturn "[[" .. target .. "]]"elsereturn "[[" .. target .. "|" .. label .. "]]"endend-- used to make frame.args mutable, to replace #frame.args (which is always 0)-- with the actual amount and to simply copy tableslocal function copyTable(tIn)if not tIn thenreturn nilendlocal tOut = {}for i, v in pairs(tIn) dotOut[i] = vendreturn tOutend-- used to merge output arrays together;-- note that it currently mutates the first input arraylocal function mergeArrays(a1, a2)for i = 1, #a2 doa1[#a1 + 1] = a2[i]endreturn a1endlocal function split(str, del)local out = {}local i, j = str:find(del)if i and j thenout[1] = str:sub(1, i - 1)out[2] = str:sub(j + 1)elseout[1] = strendreturn outendlocal function parseWikidataURL(url)local idif url:match('^http[s]?://') thenid = split(url, "Q")if id[2] thenreturn "Q" .. id[2]endendreturn nilendlocal function parseDate(dateStr, precision)precision = precision or "d"local i, j, index, ptrlocal parts = {nil, nil, nil}if dateStr == nil thenreturn parts[1], parts[2], parts[3] -- year, month, dayend-- 'T' for snak values, '/' for outputs with '/Julian' attachedi, j = dateStr:find("[T/]")if i thendateStr = dateStr:sub(1, i-1)endlocal from = 1if dateStr:sub(1,1) == "-" then-- this is a negative number, look further aheadfrom = 2endindex = 1ptr = 1i, j = dateStr:find("-", from)if i then-- yearparts[index] = tonumber(dateStr:sub(ptr, i-1), 10) -- explicitly give base 10 to prevent errorif parts[index] == -0 thenparts[index] = tonumber("0") -- for some reason, 'parts[index] = 0' may actually store '-0', so parse from string insteadendif precision == "y" then-- we're donereturn parts[1], parts[2], parts[3] -- year, month, dayendindex = index + 1ptr = i + 1i, j = dateStr:find("-", ptr)if i then-- monthparts[index] = tonumber(dateStr:sub(ptr, i-1), 10)if precision == "m" then-- we're donereturn parts[1], parts[2], parts[3] -- year, month, dayendindex = index + 1ptr = i + 1endendif dateStr:sub(ptr) ~= "" then-- day if we have month, month if we have year, or yearparts[index] = tonumber(dateStr:sub(ptr), 10)endreturn parts[1], parts[2], parts[3] -- year, month, dayendlocal function datePrecedesDate(aY, aM, aD, bY, bM, bD)if aY == nil or bY == nil thenreturn nilendaM = aM or 1aD = aD or 1bM = bM or 1bD = bD or 1if aY < bY thenreturn trueendif aY > bY thenreturn falseendif aM < bM thenreturn trueendif aM > bM thenreturn falseendif aD < bD thenreturn trueendreturn falseendlocal function getHookName(param, index)if hookNames[param] thenreturn hookNames[param][index]elseif param:len() > 2 thenreturn hookNames[param:sub(1, 2).."\\d"][index]elsereturn nilendendlocal function alwaysTrue()return trueend-- The following function parses a format string.---- The example below shows how a parsed string is structured in memory.-- Variables other than 'str' and 'child' are left out for clarity's sake.---- Example:-- "A %p B [%s[%q1]] C [%r] D"---- Structure:-- [-- {-- str = "A "-- },-- {-- str = "%p"-- },-- {-- str = " B ",-- child =-- [-- {-- str = "%s",-- child =-- [-- {-- str = "%q1"-- }-- ]-- }-- ]-- },-- {-- str = " C ",-- child =-- [-- {-- str = "%r"-- }-- ]-- },-- {-- str = " D"-- }-- ]--local function parseFormat(str)local chr, esc, param, root, cur, prev, newlocal params = {}local function newObject(array)local obj = {} -- new objectobj.str = ""array[#array + 1] = obj -- array{object}obj.parent = arrayreturn objendlocal function endParam()if param > 0 thenif cur.str ~= "" thencur.str = "%"..cur.strcur.param = trueparams[cur.str] = truecur.parent.req[cur.str] = trueprev = curcur = newObject(cur.parent)endparam = 0endendroot = {} -- arrayroot.req = {}cur = newObject(root)prev = nilesc = falseparam = 0for i = 1, #str dochr = str:sub(i,i)if not esc thenif chr == '\\' thenendParam()esc = trueelseif chr == '%' thenendParam()if cur.str ~= "" thencur = newObject(cur.parent)endparam = 2elseif chr == '[' thenendParam()if prev and cur.str == "" thentable.remove(cur.parent)cur = prevendcur.child = {} -- new arraycur.child.req = {}cur.child.parent = curcur = newObject(cur.child)elseif chr == ']' thenendParam()if cur.parent.parent thennew = newObject(cur.parent.parent.parent)if cur.str == "" thentable.remove(cur.parent)endcur = newendelseif param > 1 thenparam = param - 1elseif param == 1 thenif not chr:match('%d') thenendParam()endendcur.str = cur.str .. replaceSpecialChar(chr)endelsecur.str = cur.str .. chresc = falseendprev = nilendendParam()-- make sure that at least one required parameter has been definedif not next(root.req) thenthrowError("missing-required-parameter")end-- make sure that the separator parameter "%s" is not amongst the required parametersif root.req[parameters.separator] thenthrowError("extra-required-parameter", parameters.separator)endreturn root, paramsendlocal function sortOnRank(claims)local rankPoslocal ranks = {{}, {}, {}, {}} -- preferred, normal, deprecated, (default)local sorted = {}for _, v in ipairs(claims) dorankPos = rankTable[v.rank] or 4ranks[rankPos][#ranks[rankPos] + 1] = vendsorted = ranks[1]sorted = mergeArrays(sorted, ranks[2])sorted = mergeArrays(sorted, ranks[3])return sortedendlocal Config = {}-- allows for recursive callsfunction Config:new()local cfg = {}setmetatable(cfg, self)self.__index = selfcfg.separators = {-- single value objects wrapped in arrays so that we can pass by reference["sep"] = {copyTable(defaultSeparators["sep"])},["sep%s"] = {copyTable(defaultSeparators["sep%s"])},["sep%q"] = {copyTable(defaultSeparators["sep%q"])},["sep%r"] = {copyTable(defaultSeparators["sep%r"])},["punc"] = {copyTable(defaultSeparators["punc"])}}cfg.entity = nilcfg.entityID = nilcfg.propertyID = nilcfg.propertyValue = nilcfg.qualifierIDs = {}cfg.qualifierIDsAndValues = {}cfg.bestRank = truecfg.ranks = {true, true, false} -- preferred = true, normal = true, deprecated = falsecfg.foundRank = #cfg.rankscfg.flagBest = falsecfg.flagRank = falsecfg.periods = {true, true, true} -- future = true, current = true, former = truecfg.flagPeriod = falsecfg.atDate = {parseDate(os.date('!%Y-%m-%d'))} -- today as {year, month, day}cfg.mdyDate = falsecfg.singleClaim = falsecfg.sourcedOnly = falsecfg.editable = falsecfg.editAtEnd = falsecfg.inSitelinks = falsecfg.langCode = mw.language.getContentLanguage().codecfg.langName = mw.language.fetchLanguageName(cfg.langCode, cfg.langCode)cfg.langObj = mw.language.new(cfg.langCode)cfg.siteID = mw.wikibase.getGlobalSiteId()cfg.states = {}cfg.states.qualifiersCount = 0cfg.curState = nilcfg.prefetchedRefs = nilreturn cfgendlocal State = {}function State:new(cfg, type)local stt = {}setmetatable(stt, self)self.__index = selfstt.conf = cfgstt.type = typestt.results = {}stt.parsedFormat = {}stt.separator = {}stt.movSeparator = {}stt.puncMark = {}stt.linked = falsestt.rawValue = falsestt.shortName = falsestt.anyLanguage = falsestt.unitOnly = falsestt.singleValue = falsereturn sttend-- if id == nil then item connected to current page is usedfunction Config:getLabel(id, raw, link, short)local label = nillocal prefix, title= "", nilif not id thenid = mw.wikibase.getEntityIdForCurrentPage()if not id thenreturn ""endendid = id:upper() -- just to be sureif raw then-- check if given id actually existsif mw.wikibase.isValidEntityId(id) and mw.wikibase.entityExists(id) thenlabel = idendprefix, title = "d:Special:EntityPage/", label -- may be nilelse-- try short name first if requestedif short thenlabel = p._property{aliasesP.shortName, [p.args.eid] = id} -- get short nameif label == "" thenlabel = nilendend-- get labelif not label thenlabel = mw.wikibase.getLabelByLang(id, self.langCode) -- XXX: should use fallback labels?endendif not label thenlabel = ""elseif link then-- build a link if requestedif not title thenif id:sub(1,1) == "Q" thentitle = mw.wikibase.getSitelink(id)elseif id:sub(1,1) == "P" then-- properties have no sitelink, link to Wikidata insteadprefix, title = "d:Special:EntityPage/", idendendlabel = mw.text.nowiki(label) -- escape raw label text so it cannot be wikitext markupif title thenlabel = buildWikilink(prefix .. title, label)endendreturn labelendfunction Config:getEditIcon()local value = ""local prefix = ""local front = " "local back = ""if self.entityID:sub(1,1) == "P" thenprefix = "Property:"endif self.editAtEnd thenfront = '<span style="float:'if self.langObj:isRTL() thenfront = front .. 'left'elsefront = front .. 'right'endfront = front .. '">'back = '</span>'endvalue = "[[File:OOjs UI icon edit-ltr-progressive.svg|frameless|text-top|10px|alt=" .. i18n['info']['edit-on-wikidata'] .. "|link=https://www.wikidata.org/wiki/" .. prefix .. self.entityID .. "?uselang=" .. self.langCodeif self.propertyID thenvalue = value .. "#" .. self.propertyIDelseif self.inSitelinks thenvalue = value .. "#sitelinks-wikipedia"endvalue = value .. "|" .. i18n['info']['edit-on-wikidata'] .. "]]"return front .. value .. backend-- used to create the final output string when it's all done, so that for references the-- function extensionTag("ref", ...) is only called when they really ended up in the final outputfunction Config:concatValues(valuesArray)local outString = ""local j, skipfor i = 1, #valuesArray do-- check if this is a referenceif valuesArray[i].refHash thenj = i - 1skip = false-- skip this reference if it is part of a continuous row of references that already contains the exact same referencewhile valuesArray[j] and valuesArray[j].refHash doif valuesArray[i].refHash == valuesArray[j].refHash thenskip = truebreakendj = j - 1endif not skip then-- add <ref> tag with the reference's hash as its name (to deduplicate references)outString = outString .. mw.getCurrentFrame():extensionTag("ref", valuesArray[i][1], {name = valuesArray[i].refHash})endelseoutString = outString .. valuesArray[i][1]endendreturn outStringendfunction Config:convertUnit(unit, raw, link, short, unitOnly)local space = " "local label = ""local itemIDif unit == "" or unit == "1" thenreturn nilendif unitOnly thenspace = ""enditemID = parseWikidataURL(unit)if itemID thenif itemID == aliasesQ.percentage thenreturn "%"elselabel = self:getLabel(itemID, raw, link, short)if label ~= "" thenreturn space .. labelendendendreturn ""endfunction State:getValue(snak)return self.conf:getValue(snak, self.rawValue, self.linked, self.shortName, self.anyLanguage, self.unitOnly, false, self.type:sub(1,2))endfunction Config:getValue(snak, raw, link, short, anyLang, unitOnly, noSpecial, type)if snak.snaktype == 'value' thenlocal datatype = snak.datavalue.typelocal subtype = snak.datatypelocal datavalue = snak.datavalue.valueif datatype == 'string' thenif subtype == 'url' and link then-- create link explicitlyif raw then-- will render as a linked number like [1]return "[" .. datavalue .. "]"elsereturn "[" .. datavalue .. " " .. datavalue .. "]"endelseif subtype == 'commonsMedia' thenif link thenreturn buildWikilink("c:File:" .. datavalue, datavalue)elseif not raw thenreturn "[[File:" .. datavalue .. "]]"elsereturn datavalueendelseif subtype == 'geo-shape' and link thenreturn buildWikilink("c:" .. datavalue, datavalue)elseif subtype == 'math' and not raw thenlocal attribute = nilif (type == parameters.property or (type == parameters.qualifier and self.propertyID == aliasesP.hasPart)) and snak.property == aliasesP.definingFormula thenattribute = {qid = self.entityID}endreturn mw.getCurrentFrame():extensionTag("math", datavalue, attribute)elseif subtype == 'external-id' and link thenlocal url = p._property{aliasesP.formatterURL, [p.args.eid] = snak.property} -- get formatter URLif url ~= "" thenurl = mw.ustring.gsub(url, "$1", datavalue)return "[" .. url .. " " .. datavalue .. "]"elsereturn datavalueendelsereturn datavalueendelseif datatype == 'monolingualtext' thenif anyLang or datavalue['language'] == self.langCode thenreturn datavalue['text']elsereturn nilendelseif datatype == 'quantity' thenlocal value = ""local unitif not unitOnly then-- get value and strip + signs from frontvalue = mw.ustring.gsub(datavalue['amount'], "^%+(.+)$", "%1")if raw thenreturn valueend-- replace decimal mark based on localevalue = replaceDecimalMark(value)-- add delimiters for readabilityvalue = i18n.addDelimiters(value)endunit = self:convertUnit(datavalue['unit'], raw, link, short, unitOnly)if unit thenvalue = value .. unitendreturn valueelseif datatype == 'time' thenlocal y, m, d, p, yDiv, yRound, yFull, value, calendarID, dateStrlocal yFactor = 1local sign = 1local prefix = ""local suffix = ""local mayAddCalendar = falselocal calendar = ""local precision = datavalue['precision']if precision == 11 thenp = "d"elseif precision == 10 thenp = "m"elsep = "y"yFactor = 10^(9-precision)endy, m, d = parseDate(datavalue['time'], p)if y < 0 thensign = -1y = y * signend-- if precision is tens/hundreds/thousands/millions/billions of yearsif precision <= 8 thenyDiv = y / yFactor-- if precision is tens/hundreds/thousands of yearsif precision >= 6 thenmayAddCalendar = trueif precision <= 7 then-- round centuries/millenniums up (e.g. 20th century or 3rd millennium)yRound = math.ceil(yDiv)if not raw thenif precision == 6 thensuffix = i18n['datetime']['suffixes']['millennium']elsesuffix = i18n['datetime']['suffixes']['century']endsuffix = i18n.getOrdinalSuffix(yRound) .. suffixelse-- if not verbose, take the first year of the century/millennium-- (e.g. 1901 for 20th century or 2001 for 3rd millennium)yRound = (yRound - 1) * yFactor + 1endelse-- precision == 8-- round decades down (e.g. 2010s)yRound = math.floor(yDiv) * yFactorif not raw thenprefix = i18n['datetime']['prefixes']['decade-period']suffix = i18n['datetime']['suffixes']['decade-period']endendif raw and sign < 0 then-- if BCE then compensate for "counting backwards"-- (e.g. -2019 for 2010s BCE, -2000 for 20th century BCE or -3000 for 3rd millennium BCE)yRound = yRound + yFactor - 1endelselocal yReFactor, yReDiv, yReRound-- round to nearest for tens of thousands of years or moreyRound = math.floor(yDiv + 0.5)if yRound == 0 thenif precision <= 2 and y ~= 0 thenyReFactor = 1e6yReDiv = y / yReFactoryReRound = math.floor(yReDiv + 0.5)if yReDiv == yReRound then-- change precision to millions of years only if we have a whole number of themprecision = 3yFactor = yReFactoryRound = yReRoundendendif yRound == 0 then-- otherwise, take the unrounded (original) number of yearsprecision = 5yFactor = 1yRound = ymayAddCalendar = trueendendif precision >= 1 and y ~= 0 thenyFull = yRound * yFactoryReFactor = 1e9yReDiv = yFull / yReFactoryReRound = math.floor(yReDiv + 0.5)if yReDiv == yReRound then-- change precision to billions of years if we're in that rangeprecision = 0yFactor = yReFactoryRound = yReRoundelseyReFactor = 1e6yReDiv = yFull / yReFactoryReRound = math.floor(yReDiv + 0.5)if yReDiv == yReRound then-- change precision to millions of years if we're in that rangeprecision = 3yFactor = yReFactoryRound = yReRoundendendendif not raw thenif precision == 3 thensuffix = i18n['datetime']['suffixes']['million-years']elseif precision == 0 thensuffix = i18n['datetime']['suffixes']['billion-years']elseyRound = yRound * yFactorif yRound == 1 thensuffix = i18n['datetime']['suffixes']['year']elsesuffix = i18n['datetime']['suffixes']['years']endendelseyRound = yRound * yFactorendendelseyRound = ymayAddCalendar = trueendif mayAddCalendar thencalendarID = parseWikidataURL(datavalue['calendarmodel'])if calendarID and calendarID == aliasesQ.prolepticJulianCalendar thenif not raw thenif link thencalendar = " ("..buildWikilink(i18n['datetime']['julian-calendar'], i18n['datetime']['julian'])..")"elsecalendar = " ("..i18n['datetime']['julian']..")"endelsecalendar = "/"..i18n['datetime']['julian']endendendif not raw thenlocal ce = nilif sign < 0 thence = i18n['datetime']['BCE']elseif precision <= 5 thence = i18n['datetime']['CE']endif ce thenif link thence = buildWikilink(i18n['datetime']['common-era'], ce)endsuffix = suffix .. " " .. ceendvalue = tostring(yRound)if m thendateStr = self.langObj:formatDate("F", "1-"..m.."-1")if d thenif self.mdyDate thendateStr = dateStr .. " " .. d .. ","elsedateStr = d .. " " .. dateStrendendvalue = dateStr .. " " .. valueendvalue = prefix .. value .. suffix .. calendarelsevalue = padZeros(yRound * sign, 4)if m thenvalue = value .. "-" .. padZeros(m, 2)if d thenvalue = value .. "-" .. padZeros(d, 2)endendvalue = value .. calendarendreturn valueelseif datatype == 'globecoordinate' then-- logic from https://github.com/DataValues/Geo (v4.0.1)local precision, unitsPerDegree, numDigits, strFormat, value, globelocal latitude, latConv, latValue, latLinklocal longitude, lonConv, lonValue, lonLinklocal latDirection, latDirectionN, latDirectionS, latDirectionENlocal lonDirection, lonDirectionE, lonDirectionW, lonDirectionENlocal degSymbol, minSymbol, secSymbol, separatorlocal latDegrees = nillocal latMinutes = nillocal latSeconds = nillocal lonDegrees = nillocal lonMinutes = nillocal lonSeconds = nillocal latDegSym = ""local latMinSym = ""local latSecSym = ""local lonDegSym = ""local lonMinSym = ""local lonSecSym = ""local latDirectionEN_N = "N"local latDirectionEN_S = "S"local lonDirectionEN_E = "E"local lonDirectionEN_W = "W"if not raw thenlatDirectionN = i18n['coord']['latitude-north']latDirectionS = i18n['coord']['latitude-south']lonDirectionE = i18n['coord']['longitude-east']lonDirectionW = i18n['coord']['longitude-west']degSymbol = i18n['coord']['degrees']minSymbol = i18n['coord']['minutes']secSymbol = i18n['coord']['seconds']separator = i18n['coord']['separator']elselatDirectionN = latDirectionEN_NlatDirectionS = latDirectionEN_SlonDirectionE = lonDirectionEN_ElonDirectionW = lonDirectionEN_WdegSymbol = "/"minSymbol = "/"secSymbol = "/"separator = "/"endlatitude = datavalue['latitude']longitude = datavalue['longitude']if latitude < 0 thenlatDirection = latDirectionSlatDirectionEN = latDirectionEN_Slatitude = math.abs(latitude)elselatDirection = latDirectionNlatDirectionEN = latDirectionEN_Nendif longitude < 0 thenlonDirection = lonDirectionWlonDirectionEN = lonDirectionEN_Wlongitude = math.abs(longitude)elselonDirection = lonDirectionElonDirectionEN = lonDirectionEN_Eendprecision = datavalue['precision']if not precision or precision <= 0 thenprecision = 1 / 3600 -- precision not set (correctly), set to arcsecondend-- remove insignificant detaillatitude = math.floor(latitude / precision + 0.5) * precisionlongitude = math.floor(longitude / precision + 0.5) * precisionif precision >= 1 - (1 / 60) and precision < 1 thenprecision = 1elseif precision >= (1 / 60) - (1 / 3600) and precision < (1 / 60) thenprecision = 1 / 60endif precision >= 1 thenunitsPerDegree = 1elseif precision >= (1 / 60) thenunitsPerDegree = 60elseunitsPerDegree = 3600endnumDigits = math.ceil(-math.log10(unitsPerDegree * precision))if numDigits <= 0 thennumDigits = tonumber("0") -- for some reason, 'numDigits = 0' may actually store '-0', so parse from string insteadendstrFormat = "%." .. numDigits .. "f"if precision >= 1 thenlatDegrees = strFormat:format(latitude)lonDegrees = strFormat:format(longitude)if not raw thenlatDegSym = replaceDecimalMark(latDegrees) .. degSymbollonDegSym = replaceDecimalMark(lonDegrees) .. degSymbolelselatDegSym = latDegrees .. degSymbollonDegSym = lonDegrees .. degSymbolendelselatConv = math.floor(latitude * unitsPerDegree * 10^numDigits + 0.5) / 10^numDigitslonConv = math.floor(longitude * unitsPerDegree * 10^numDigits + 0.5) / 10^numDigitsif precision >= (1 / 60) thenlatMinutes = latConvlonMinutes = lonConvelselatSeconds = latConvlonSeconds = lonConvlatMinutes = math.floor(latSeconds / 60)lonMinutes = math.floor(lonSeconds / 60)latSeconds = strFormat:format(latSeconds - (latMinutes * 60))lonSeconds = strFormat:format(lonSeconds - (lonMinutes * 60))if not raw thenlatSecSym = replaceDecimalMark(latSeconds) .. secSymbollonSecSym = replaceDecimalMark(lonSeconds) .. secSymbolelselatSecSym = latSeconds .. secSymbollonSecSym = lonSeconds .. secSymbolendendlatDegrees = math.floor(latMinutes / 60)lonDegrees = math.floor(lonMinutes / 60)latDegSym = latDegrees .. degSymbollonDegSym = lonDegrees .. degSymbollatMinutes = latMinutes - (latDegrees * 60)lonMinutes = lonMinutes - (lonDegrees * 60)if precision >= (1 / 60) thenlatMinutes = strFormat:format(latMinutes)lonMinutes = strFormat:format(lonMinutes)if not raw thenlatMinSym = replaceDecimalMark(latMinutes) .. minSymbollonMinSym = replaceDecimalMark(lonMinutes) .. minSymbolelselatMinSym = latMinutes .. minSymbollonMinSym = lonMinutes .. minSymbolendelselatMinSym = latMinutes .. minSymbollonMinSym = lonMinutes .. minSymbolendendlatValue = latDegSym .. latMinSym .. latSecSym .. latDirectionlonValue = lonDegSym .. lonMinSym .. lonSecSym .. lonDirectionvalue = latValue .. separator .. lonValueif link thenglobe = parseWikidataURL(datavalue['globe'])if globe thenglobe = mw.wikibase.getLabelByLang(globe, "en"):lower()elseglobe = "earth"endlatLink = table.concat({latDegrees, latMinutes, latSeconds}, "_")lonLink = table.concat({lonDegrees, lonMinutes, lonSeconds}, "_")value = "[https://geohack.toolforge.org/geohack.php?language="..self.langCode.."¶ms="..latLink.."_"..latDirectionEN.."_"..lonLink.."_"..lonDirectionEN.."_globe:"..globe.." "..value.."]"endreturn valueelseif datatype == 'wikibase-entityid' thenlocal labellocal itemID = datavalue['numeric-id']if subtype == 'wikibase-item' thenitemID = "Q" .. itemIDelseif subtype == 'wikibase-property' thenitemID = "P" .. itemIDelsereturn '<strong class="error">' .. errorText('unknown-data-type', subtype) .. '</strong>'endlabel = self:getLabel(itemID, raw, link, short)if label == "" thenlabel = nilendreturn labelelsereturn '<strong class="error">' .. errorText('unknown-data-type', datatype) .. '</strong>'endelseif snak.snaktype == 'somevalue' and not noSpecial thenif raw thenreturn " " -- single space represents 'somevalue'elsereturn i18n['values']['unknown']endelseif snak.snaktype == 'novalue' and not noSpecial thenif raw thenreturn "" -- empty string represents 'novalue'elsereturn i18n['values']['none']endelsereturn nilendendfunction Config:getSingleRawQualifier(claim, qualifierID)local qualifiersif claim.qualifiers then qualifiers = claim.qualifiers[qualifierID] endif qualifiers and qualifiers[1] thenreturn self:getValue(qualifiers[1], true) -- raw = trueelsereturn nilendendfunction Config:snakEqualsValue(snak, value)local snakValue = self:getValue(snak, true) -- raw = trueif snakValue and snak.snaktype == 'value' and snak.datavalue.type == 'wikibase-entityid' then value = value:upper() endreturn snakValue == valueendfunction Config:setRank(rank)local rankPosif rank == p.flags.best thenself.bestRank = trueself.flagBest = true -- mark that 'best' flag was givenreturnendif rank:sub(1,9) == p.flags.preferred thenrankPos = 1elseif rank:sub(1,6) == p.flags.normal thenrankPos = 2elseif rank:sub(1,10) == p.flags.deprecated thenrankPos = 3elsereturnend-- one of the rank flags was given, check if another one was given beforeif not self.flagRank thenself.ranks = {false, false, false} -- no other rank flag given before, so unset ranksself.bestRank = self.flagBest -- unsets bestRank only if 'best' flag was not given beforeself.flagRank = true -- mark that a rank flag was givenendif rank:sub(-1) == "+" thenfor i = rankPos, 1, -1 doself.ranks[i] = trueendelseif rank:sub(-1) == "-" thenfor i = rankPos, #self.ranks doself.ranks[i] = trueendelseself.ranks[rankPos] = trueendendfunction Config:setPeriod(period)local periodPosif period == p.flags.future thenperiodPos = 1elseif period == p.flags.current thenperiodPos = 2elseif period == p.flags.former thenperiodPos = 3elsereturnend-- one of the period flags was given, check if another one was given beforeif not self.flagPeriod thenself.periods = {false, false, false} -- no other period flag given before, so unset periodsself.flagPeriod = true -- mark that a period flag was givenendself.periods[periodPos] = trueendfunction Config:qualifierMatches(claim, id, value)local qualifiersif claim.qualifiers then qualifiers = claim.qualifiers[id] endif qualifiers thenfor _, v in pairs(qualifiers) doif self:snakEqualsValue(v, value) thenreturn trueendendelseif value == "" then-- if the qualifier is not present then treat it the same as the special value 'novalue'return trueendreturn falseendfunction Config:rankMatches(rankPos)if self.bestRank thenreturn (self.ranks[rankPos] and self.foundRank >= rankPos)elsereturn self.ranks[rankPos]endendfunction Config:timeMatches(claim)local startTime = nillocal startTimeY = nillocal startTimeM = nillocal startTimeD = nillocal endTime = nillocal endTimeY = nillocal endTimeM = nillocal endTimeD = nilif self.periods[1] and self.periods[2] and self.periods[3] then-- any timereturn trueendstartTime = self:getSingleRawQualifier(claim, aliasesP.startTime)if startTime and startTime ~= "" and startTime ~= " " thenstartTimeY, startTimeM, startTimeD = parseDate(startTime)endendTime = self:getSingleRawQualifier(claim, aliasesP.endTime)if endTime and endTime ~= "" and endTime ~= " " thenendTimeY, endTimeM, endTimeD = parseDate(endTime)endif startTimeY ~= nil and endTimeY ~= nil and datePrecedesDate(endTimeY, endTimeM, endTimeD, startTimeY, startTimeM, startTimeD) then-- invalidate end time if it precedes start timeendTimeY = nilendTimeM = nilendTimeD = nilendif self.periods[1] then-- futureif startTimeY and datePrecedesDate(self.atDate[1], self.atDate[2], self.atDate[3], startTimeY, startTimeM, startTimeD) thenreturn trueendendif self.periods[2] then-- currentif (startTimeY == nil or not datePrecedesDate(self.atDate[1], self.atDate[2], self.atDate[3], startTimeY, startTimeM, startTimeD)) and (endTimeY == nil or datePrecedesDate(self.atDate[1], self.atDate[2], self.atDate[3], endTimeY, endTimeM, endTimeD)) thenreturn trueendendif self.periods[3] then-- formerif endTimeY and not datePrecedesDate(self.atDate[1], self.atDate[2], self.atDate[3], endTimeY, endTimeM, endTimeD) thenreturn trueendendreturn falseendfunction Config:processFlag(flag)if not flag thenreturn falseendif flag == p.flags.linked thenself.curState.linked = truereturn trueelseif flag == p.flags.raw thenself.curState.rawValue = trueif self.curState == self.states[parameters.reference] then-- raw reference values end with periods and require a separator (other than none)self.separators["sep%r"][1] = {" "}endreturn trueelseif flag == p.flags.short thenself.curState.shortName = truereturn trueelseif flag == p.flags.multilanguage thenself.curState.anyLanguage = truereturn trueelseif flag == p.flags.unit thenself.curState.unitOnly = truereturn trueelseif flag == p.flags.mdy thenself.mdyDate = truereturn trueelseif flag == p.flags.single thenself.singleClaim = truereturn trueelseif flag == p.flags.sourced thenself.sourcedOnly = truereturn trueelseif flag == p.flags.edit thenself.editable = truereturn trueelseif flag == p.flags.editAtEnd thenself.editable = trueself.editAtEnd = truereturn trueelseif flag == p.flags.best or flag:match('^'..p.flags.preferred..'[+-]?$') or flag:match('^'..p.flags.normal..'[+-]?$') or flag:match('^'..p.flags.deprecated..'[+-]?$') thenself:setRank(flag)return trueelseif flag == p.flags.future or flag == p.flags.current or flag == p.flags.former thenself:setPeriod(flag)return trueelseif flag == "" then-- ignore empty flags and carry onreturn trueelsereturn falseendendfunction Config:processFlagOrCommand(flag)local param = ""if not flag thenreturn falseendif flag == p.claimCommands.property or flag == p.claimCommands.properties thenparam = parameters.propertyelseif flag == p.claimCommands.qualifier or flag == p.claimCommands.qualifiers thenself.states.qualifiersCount = self.states.qualifiersCount + 1param = parameters.qualifier .. self.states.qualifiersCountself.separators["sep"..param] = {copyTable(defaultSeparators["sep%q\\d"])}elseif flag == p.claimCommands.reference or flag == p.claimCommands.references thenparam = parameters.referenceelsereturn self:processFlag(flag)endif self.states[param] thenreturn falseend-- create a new state for each commandself.states[param] = State:new(self, param)-- use "%x" as the general parameter nameself.states[param].parsedFormat = parseFormat(parameters.general) -- will be overwritten for param=="%p"-- set the separatorself.states[param].separator = self.separators["sep"..param] -- will be nil for param=="%p", which will be set separatelyif flag == p.claimCommands.property or flag == p.claimCommands.qualifier or flag == p.claimCommands.reference thenself.states[param].singleValue = trueendself.curState = self.states[param]return trueendfunction Config:processSeparators(args)local sepfor i, v in pairs(self.separators) doif args[i] thensep = replaceSpecialChars(args[i])if sep ~= "" thenself.separators[i][1] = {sep}elseself.separators[i][1] = nilendendendendfunction Config:setFormatAndSeparators(state, parsedFormat)state.parsedFormat = parsedFormatstate.separator = self.separators["sep"]state.movSeparator = self.separators["sep"..parameters.separator]state.puncMark = self.separators["punc"]end-- determines if a claim has references by prefetching them from the claim using getReferences,-- which applies some filtering that determines if a reference is actually returned,-- and caches the references for later usefunction State:isSourced(claim)self.conf.prefetchedRefs = self:getReferences(claim)return (#self.conf.prefetchedRefs > 0)endfunction State:resetCaches()-- any prefetched references of the previous claim must not be usedself.conf.prefetchedRefs = nilendfunction State:claimMatches(claim)local matches, rankPos-- first of all, reset any cached values used for the previous claimself:resetCaches()-- if a property value was given, check if it matches the claim's property valueif self.conf.propertyValue thenmatches = self.conf:snakEqualsValue(claim.mainsnak, self.conf.propertyValue)elsematches = trueend-- if any qualifier values were given, check if each matches one of the claim's qualifier valuesfor i, v in pairs(self.conf.qualifierIDsAndValues) domatches = (matches and self.conf:qualifierMatches(claim, i, v))end-- check if the claim's rank and time period matchrankPos = rankTable[claim.rank] or 4matches = (matches and self.conf:rankMatches(rankPos) and self.conf:timeMatches(claim))-- if only claims with references must be returned, check if this one has anyif self.conf.sourcedOnly thenmatches = (matches and self:isSourced(claim)) -- prefetches and caches referencesendreturn matches, rankPosendfunction State:out()local result -- collection of arrays with value objectslocal valuesArray -- array with value objectslocal sep = nil -- value objectlocal out = {} -- array with value objectslocal function walk(formatTable, result)local valuesArray = {} -- array with value objectsfor i, v in pairs(formatTable.req) doif not result[i] or not result[i][1] then-- we've got no result for a parameter that is required on this level,-- so skip this level (and its children) by returning an empty resultreturn {}endendfor _, v in ipairs(formatTable) doif v.param thenvaluesArray = mergeArrays(valuesArray, result[v.str])elseif v.str ~= "" thenvaluesArray[#valuesArray + 1] = {v.str}endif v.child thenvaluesArray = mergeArrays(valuesArray, walk(v.child, result))endendreturn valuesArrayend-- iterate through the results from back to front, so that we know when to add separatorsfor i = #self.results, 1, -1 doresult = self.results[i]-- if there is already some output, then add the separatorsif #out > 0 thensep = self.separator[1] -- fixed separatorresult[parameters.separator] = {self.movSeparator[1]} -- movable separatorelsesep = nilresult[parameters.separator] = {self.puncMark[1]} -- optional punctuation markendvaluesArray = walk(self.parsedFormat, result)if #valuesArray > 0 thenif sep thenvaluesArray[#valuesArray + 1] = sependout = mergeArrays(valuesArray, out)endend-- reset state before next iterationself.results = {}return outend-- level 1 hookfunction State:getProperty(claim)local value = {self:getValue(claim.mainsnak)} -- create one value objectif #value > 0 thenreturn {value} -- wrap the value object in an array and return itelsereturn {} -- return empty array if there was no valueendend-- level 1 hookfunction State:getQualifiers(claim, param)local qualifiersif claim.qualifiers then qualifiers = claim.qualifiers[self.conf.qualifierIDs[param]] endif qualifiers then-- iterate through claim's qualifier statements to collect their values;-- return array with multiple value objectsreturn self.conf.states[param]:iterate(qualifiers, {[parameters.general] = hookNames[parameters.qualifier.."\\d"][2], count = 1}) -- pass qualifier state with level 2 hookelsereturn {} -- return empty arrayendend-- level 2 hookfunction State:getQualifier(snak)local value = {self:getValue(snak)} -- create one value objectif #value > 0 thenreturn {value} -- wrap the value object in an array and return itelsereturn {} -- return empty array if there was no valueendend-- level 1 hookfunction State:getAllQualifiers(claim, param, result, hooks)local out = {} -- array with value objectslocal sep = self.conf.separators["sep"..parameters.qualifier][1] -- value object-- iterate through the output of the separate "qualifier(s)" commandsfor i = 1, self.conf.states.qualifiersCount do-- if a hook has not been called yet, call it nowif not result[parameters.qualifier..i] thenself:callHook(parameters.qualifier..i, hooks, claim, result)end-- if there is output for this particular "qualifier(s)" command, then add itif result[parameters.qualifier..i] and result[parameters.qualifier..i][1] then-- if there is already some output, then add the separatorif #out > 0 and sep thenout[#out + 1] = sependout = mergeArrays(out, result[parameters.qualifier..i])endendreturn outend-- level 1 hookfunction State:getReferences(claim)if self.conf.prefetchedRefs then-- return references that have been prefetched by isSourcedreturn self.conf.prefetchedRefsendif claim.references then-- iterate through claim's reference statements to collect their values;-- return array with multiple value objectsreturn self.conf.states[parameters.reference]:iterate(claim.references, {[parameters.general] = hookNames[parameters.reference][2], count = 1}) -- pass reference state with level 2 hookelsereturn {} -- return empty arrayendend-- level 2 hookfunction State:getReference(statement)local key, citeWeb, citeQ, labellocal params = {}local citeParams = {['web'] = {}, ['q'] = {}}local citeMismatch = {}local useCite = nillocal useParams = nillocal value = ""local ref = {}local referenceEmpty = true -- will be set to false if at least one parameter is left unremoved local numAuthorParameters = 0 local numAuthorNameStringParameters = 0 local tempLink local additionalRefProperties = {} -- will hold properties of the reference which are not in statement.snaks, namely backup title from "subject named as" and link from an external ID local wikidataPropertiesOfSource -- will contain "Wikidata property" properties of the item in stated in, if anylocal version = 6 -- increment this each time the below logic is changed to avoid conflict errorsif statement.snaks then-- don't include "imported from", which is added by a botif statement.snaks[aliasesP.importedFrom] thenstatement.snaks[aliasesP.importedFrom] = nilend-- don't include "Wikimedia import URL"if statement.snaks[aliasesP.wikimediaImportURL] thenstatement.snaks[aliasesP.wikimediaImportURL] = nil-- don't include "retrieved" if no "referenceURL" is present,-- as "retrieved" probably belongs to "Wikimedia import URL"if statement.snaks[aliasesP.retrieved] and not statement.snaks[aliasesP.referenceURL] thenstatement.snaks[aliasesP.retrieved] = nilendend-- don't include "inferred from", which is added by a botif statement.snaks[aliasesP.inferredFrom] thenstatement.snaks[aliasesP.inferredFrom] = nilend-- don't include "type of reference"if statement.snaks[aliasesP.typeOfReference] thenstatement.snaks[aliasesP.typeOfReference] = nilend-- don't include "image" to prevent litteringif statement.snaks[aliasesP.image] thenstatement.snaks[aliasesP.image] = nilend-- don't include "language" if it is equal to the local oneif self:getReferenceDetail(statement.snaks, aliasesP.language) == self.conf.langName thenstatement.snaks[aliasesP.language] = nilend if statement.snaks[aliasesP.statedIn] and not statement.snaks[aliasesP.referenceURL] then -- "stated in" was given but "reference URL" was not. -- get "Wikidata property" properties from the item in "stated in" -- if any of the returned properties of the external-id datatype is in statement.snaks, generate a link from it and use the link in the reference -- find the "Wikidata property" properties in the item from "stated in" wikidataPropertiesOfSource = mw.text.split(p._properties{p.flags.raw, aliasesP.wikidataProperty, [p.args.eid] = self.conf:getValue(statement.snaks[aliasesP.statedIn][1], true, false)}, ", ", true) for i, wikidataPropertyOfSource in pairs(wikidataPropertiesOfSource) do if statement.snaks[wikidataPropertyOfSource] and statement.snaks[wikidataPropertyOfSource][1].datatype == "external-id" then tempLink = self.conf:getValue(statement.snaks[wikidataPropertyOfSource][1], false, true) -- not raw, linked if mw.ustring.match(tempLink, "^%[%Z- %Z+%]$") then -- getValue returned a URL. additionalRefProperties[aliasesP.referenceURL] = mw.ustring.gsub(tempLink, "^%[(%Z-) %Z+%]$", "%1") -- the link is in wiki markup, so strip the square brackets and the display text statement.snaks[wikidataPropertyOfSource] = nil break end end end end -- don't include "subject named as", but use it as the title when "title" is not present but a URL is if statement.snaks[aliasesP.subjectNamedAs] then if not statement.snaks[aliasesP.title] and (statement.snaks[aliasesP.referenceURL] or additionalRefProperties[aliasesP.referenceURL]) then additionalRefProperties[aliasesP.title] = statement.snaks[aliasesP.subjectNamedAs][1].datavalue.value end statement.snaks[aliasesP.subjectNamedAs] = nil end-- retrieve all the parametersfor i in pairs(statement.snaks) dolabel = ""-- multiple authors may be givenif i == aliasesP.author or i == aliasesP.authorNameString thenparams[i] = self:getReferenceDetails(statement.snaks, i, false, self.linked, true) -- link = true/false, anyLang = trueelseif i == aliasesP.statedIn then-- Get "stated in" raw, as it is wanted (for Cite Q) even if it doesn't have a local language label.params[aliasesP.statedIn] = {self:getReferenceDetail(statement.snaks, aliasesP.statedIn, true)} -- raw = trueelseparams[i] = {self:getReferenceDetail(statement.snaks, i, false, self.linked and (statement.snaks[i][1].datatype ~= 'url'), true)} -- link = true/false, anyLang = trueendif #params[i] == 0 thenparams[i] = nilelsereferenceEmpty = falseif statement.snaks[i][1].datatype == 'external-id' thenkey = "external-id"label = self.conf:getLabel(i)if label ~= "" thenlabel = label .. " "endelsekey = iend-- add the parameter to each matching type of citationfor j in pairs(citeParams) do-- do so if there was no mismatch with a previous parameterif not citeMismatch[j] then-- check if this parameter is not mismatching itselfif i18n['cite'][j][key] then-- continue if an option is available in the corresponding cite templateif i18n['cite'][j][key] ~= "" then -- handle non-author properties (and author properties ("author" and "author name string"), if they don't use the same template parameter) if (i ~= aliasesP.author and i ~= aliasesP.authorNameString) or (i18n['cite'][j][aliasesP.author] ~= i18n['cite'][j][aliasesP.authorNameString]) then citeParams[j][i18n['cite'][j][key]] = label .. params[i][1] -- to avoid problems with non-author multiple parameters (if existent), the following old code is retained for k=2, #params[i] do citeParams[j][i18n['cite'][j][key]..k] = label .. params[i][k] end -- handle "author" and "author name string" specially if they use the same template parameter elseif i == aliasesP.author or i == aliasesP.authorNameString then if params[aliasesP.author] ~= nil then numAuthorParameters = #params[aliasesP.author] else numAuthorParameters = 0 end if params[aliasesP.authorNameString] ~= nil then numAuthorNameStringParameters = #params[aliasesP.authorNameString] else numAuthorNameStringParameters = 0 end -- execute only if both "author" and "author name string" satisfy this condition: the property is both in params and in statement.snaks or it is neither in params nor in statement.snaks -- reason: parameters are added to params each iteration of the loop, not before the loop if ((statement.snaks[aliasesP.author] == nil) == (numAuthorParameters == 0)) and ((statement.snaks[aliasesP.authorNameString] == nil) == (numAuthorNameStringParameters == 0)) then for k=1, numAuthorParameters + numAuthorNameStringParameters do if k <= numAuthorParameters then -- now handling the authors from the "author" property citeParams[j][i18n['cite'][j][aliasesP.author]..k] = label .. params[aliasesP.author][k] else -- now handling the authors from "author name string" citeParams[j][i18n['cite'][j][aliasesP.authorNameString]..k] = label .. params[aliasesP.authorNameString][k - numAuthorParameters] end end end endendelseciteMismatch[j] = trueendendendendend-- use additional propertiesfor i in pairs(additionalRefProperties) dofor j in pairs(citeParams) doif not citeMismatch[j] and i18n["cite"][j][i] thenciteParams[j][i18n["cite"][j][i]] = additionalRefProperties[i]elseciteMismatch[j] = trueendendend-- get title of general template for citing web referencesciteWeb = split(mw.wikibase.getSitelink(aliasesQ.citeWeb) or "", ":")[2] -- split off namespace from front-- get title of template that expands stated-in references into citationsciteQ = split(mw.wikibase.getSitelink(aliasesQ.citeQ) or "", ":")[2] -- split off namespace from front-- (1) use the general template for citing web references if there is a match and if at least both "reference URL" and "title" are presentif citeWeb and not citeMismatch['web'] and citeParams['web'][i18n['cite']['web'][aliasesP.referenceURL]] and citeParams['web'][i18n['cite']['web'][aliasesP.title]] then-- we need a processed "stated in" for this templateciteParams['web'][i18n['cite']['web'][aliasesP.statedIn]] = self:getReferenceDetail(statement.snaks, aliasesP.statedIn, false, self.linked, true)useCite = citeWebuseParams = citeParams['web']-- (2) use the template that expands stated-in references into citations if there is a match and if at least "stated in" is presentelseif citeQ and not citeMismatch['q'] and citeParams['q'][i18n['cite']['q'][aliasesP.statedIn]] thenuseCite = citeQuseParams = citeParams['q']endif useCite and useParams then-- if this module is being substituted then build a regular template call, otherwise expand the templateif mw.isSubsting() thenfor i, v in pairs(useParams) dovalue = value .. "|" .. i .. "=" .. vendvalue = "{{" .. useCite .. value .. "}}"elsevalue = mw.getCurrentFrame():expandTemplate{title=useCite, args=useParams}end-- (3) if the citation couldn't be displayed using Cite web or Cite Q, but has properties other than the removed ones, throw an errorelseif not referenceEmpty thenvalue = "<span style=\"color:#dd3333\">" .. errorText("malformed-reference") .. "</span>"endif value ~= "" thenvalue = {value} -- create one value objectif not self.rawValue then-- this should become a <ref> tag, so save the reference's hash for latervalue.refHash = "wikidata-" .. statement.hash .. "-v" .. (tonumber(i18n['cite']['version']) + version)endref = {value} -- wrap the value object in an arrayendendreturn refend-- gets a detail of one particular type for a referencefunction State:getReferenceDetail(snaks, dType, raw, link, anyLang)local switchLang = anyLanglocal value = nilif not snaks[dType] thenreturn nilend-- if anyLang, first try the local language and otherwise any languagerepeatfor _, v in ipairs(snaks[dType]) dovalue = self.conf:getValue(v, raw, link, false, anyLang and not switchLang, false, true) -- noSpecial = trueif value thenbreakendendif value or not anyLang thenbreakendswitchLang = not switchLanguntil anyLang and switchLangreturn valueend-- gets the details of one particular type for a referencefunction State:getReferenceDetails(snaks, dType, raw, link, anyLang)local values = {}if not snaks[dType] thenreturn {}endfor _, v in ipairs(snaks[dType]) do-- if nil is returned then it will not be added to the tablevalues[#values + 1] = self.conf:getValue(v, raw, link, false, anyLang, false, true) -- noSpecial = trueendreturn valuesend-- level 1 hookfunction State:getAlias(object)local value = object.valuelocal title = nilif value and self.linked thenif self.conf.entityID:sub(1,1) == "Q" thentitle = mw.wikibase.getSitelink(self.conf.entityID)elseif self.conf.entityID:sub(1,1) == "P" thentitle = "d:Property:" .. self.conf.entityIDendif title thenvalue = buildWikilink(title, value)endendvalue = {value} -- create one value objectif #value > 0 thenreturn {value} -- wrap the value object in an array and return itelsereturn {} -- return empty array if there was no valueendend-- level 1 hookfunction State:getBadge(value)value = self.conf:getLabel(value, self.rawValue, self.linked, self.shortName)if value == "" thenvalue = nilendvalue = {value} -- create one value objectif #value > 0 thenreturn {value} -- wrap the value object in an array and return itelsereturn {} -- return empty array if there was no valueendendfunction State:callHook(param, hooks, statement, result)local valuesArray, refHash-- call a parameter's hook if it has been defined and if it has not been called beforeif not result[param] and hooks[param] thenvaluesArray = self[hooks[param]](self, statement, param, result, hooks) -- array with value objects-- add to the resultif #valuesArray > 0 thenresult[param] = valuesArrayresult.count = result.count + 1elseresult[param] = {} -- an empty array to indicate that we've tried this hook alreadyreturn true -- miss == trueendendreturn falseend-- iterate through claims, claim's qualifiers or claim's references to collect valuesfunction State:iterate(statements, hooks, matchHook)matchHook = matchHook or alwaysTruelocal matches = falselocal rankPos = nillocal result, gotRequiredfor _, v in ipairs(statements) do-- rankPos will be nil for non-claim statements (e.g. qualifiers, references, etc.)matches, rankPos = matchHook(self, v)if matches thenresult = {count = 0} -- collection of arrays with value objectslocal function walk(formatTable)local missfor i2, v2 in pairs(formatTable.req) do-- call a hook, adding its return value to the resultmiss = self:callHook(i2, hooks, v, result)if miss then-- we miss a required value for this level, so return falsereturn falseendif result.count == hooks.count then-- we're done if all hooks have been called;-- returning at this point breaks the loopreturn trueendendfor _, v2 in ipairs(formatTable) doif result.count == hooks.count then-- we're done if all hooks have been called;-- returning at this point prevents further childs from being processedreturn trueendif v2.child thenwalk(v2.child)endendreturn trueendgotRequired = walk(self.parsedFormat)-- only append the result if we got values for all required parameters on the root levelif gotRequired then-- if we have a rankPos (only with matchHook() for complete claims), then update the foundRankif rankPos and self.conf.foundRank > rankPos thenself.conf.foundRank = rankPosend-- append the resultself.results[#self.results + 1] = result-- break if we only need a single valueif self.singleValue thenbreakendendendendreturn self:out()endlocal function getEntityId(arg, eid, page, allowOmitPropPrefix, globalSiteId)local id = nillocal prop = nilif arg thenif arg:sub(1,1) == ":" thenpage = argeid = nilelseif arg:sub(1,1):upper() == "Q" or arg:sub(1,9):lower() == "property:" or allowOmitPropPrefix theneid = argpage = nilelseprop = argendendif eid thenif eid:sub(1,9):lower() == "property:" thenid = replaceAlias(mw.text.trim(eid:sub(10)))if id:sub(1,1):upper() ~= "P" thenid = ""endelseid = replaceAlias(eid)endelseif page thenif page:sub(1,1) == ":" thenpage = mw.text.trim(page:sub(2))endid = mw.wikibase.getEntityIdForTitle(page, globalSiteId) or ""endif not id thenid = mw.wikibase.getEntityIdForCurrentPage() or ""endid = id:upper()if not mw.wikibase.isValidEntityId(id) thenid = ""endreturn id, propendlocal function nextArg(args)local arg = args[args.pointer]if arg thenargs.pointer = args.pointer + 1return mw.text.trim(arg)elsereturn nilendendlocal function claimCommand(args, funcName)local cfg = Config:new()cfg:processFlagOrCommand(funcName) -- process first command (== function name)local lastArg, parsedFormat, formatParams, claims, valuelocal hooks = {count = 0}-- set the date if given;-- must come BEFORE processing the flagsif args[p.args.date] thencfg.atDate = {parseDate(args[p.args.date])}cfg.periods = {false, true, false} -- change default time constraint to 'current'end-- process flags and commandsrepeatlastArg = nextArg(args)until not cfg:processFlagOrCommand(lastArg)-- get the entity ID from either the positional argument, the eid argument or the page argumentcfg.entityID, cfg.propertyID = getEntityId(lastArg, args[p.args.eid], args[p.args.page], false, args[p.args.globalSiteId])if cfg.entityID == "" thenreturn "" -- we cannot continue without a valid entity IDendcfg.entity = mw.wikibase.getEntity(cfg.entityID)if not cfg.propertyID thencfg.propertyID = nextArg(args)endcfg.propertyID = replaceAlias(cfg.propertyID)if not cfg.entity or not cfg.propertyID thenreturn "" -- we cannot continue without an entity or a property IDendcfg.propertyID = cfg.propertyID:upper()if not cfg.entity.claims or not cfg.entity.claims[cfg.propertyID] thenreturn "" -- there is no use to continue without any claimsendclaims = cfg.entity.claims[cfg.propertyID]if cfg.states.qualifiersCount > 0 then-- do further processing if "qualifier(s)" command was givenif #args - args.pointer + 1 > cfg.states.qualifiersCount then-- claim ID or literal value has been givencfg.propertyValue = nextArg(args)endfor i = 1, cfg.states.qualifiersCount do-- check if given qualifier ID is an alias and add itcfg.qualifierIDs[parameters.qualifier..i] = replaceAlias(nextArg(args) or ""):upper()endelseif cfg.states[parameters.reference] then-- do further processing if "reference(s)" command was givencfg.propertyValue = nextArg(args)end-- check for special property value 'somevalue' or 'novalue'if cfg.propertyValue thencfg.propertyValue = replaceSpecialChars(cfg.propertyValue)if cfg.propertyValue ~= "" and mw.text.trim(cfg.propertyValue) == "" thencfg.propertyValue = " " -- single space represents 'somevalue', whereas empty string represents 'novalue'elsecfg.propertyValue = mw.text.trim(cfg.propertyValue)endend-- parse the desired format, or choose an appropriate formatif args["format"] thenparsedFormat, formatParams = parseFormat(args["format"])elseif cfg.states.qualifiersCount > 0 then -- "qualifier(s)" command givenif cfg.states[parameters.property] then -- "propert(y|ies)" command givenparsedFormat, formatParams = parseFormat(formats.propertyWithQualifier)elseparsedFormat, formatParams = parseFormat(formats.qualifier)endelseif cfg.states[parameters.property] then -- "propert(y|ies)" command givenparsedFormat, formatParams = parseFormat(formats.property)else -- "reference(s)" command givenparsedFormat, formatParams = parseFormat(formats.reference)end-- if a "qualifier(s)" command and no "propert(y|ies)" command has been given, make the movable separator a semicolonif cfg.states.qualifiersCount > 0 and not cfg.states[parameters.property] thencfg.separators["sep"..parameters.separator][1] = {";"}end-- if only "reference(s)" has been given, set the default separator to none (except when raw)if cfg.states[parameters.reference] and not cfg.states[parameters.property] and cfg.states.qualifiersCount == 0 and not cfg.states[parameters.reference].rawValue thencfg.separators["sep"][1] = nilend-- if exactly one "qualifier(s)" command has been given, make "sep%q" point to "sep%q1" to make them equivalentif cfg.states.qualifiersCount == 1 thencfg.separators["sep"..parameters.qualifier] = cfg.separators["sep"..parameters.qualifier.."1"]end-- process overridden separator values;-- must come AFTER tweaking the default separatorscfg:processSeparators(args)-- define the hooks that should be called (getProperty, getQualifiers, getReferences);-- only define a hook if both its command ("propert(y|ies)", "reference(s)", "qualifier(s)") and its parameter ("%p", "%r", "%q1", "%q2", "%q3") have been givenfor i, v in pairs(cfg.states) do-- e.g. 'formatParams["%q1"] or formatParams["%q"]' to define hook even if "%q1" was not defined to be able to build a complete value for "%q"if formatParams[i] or formatParams[i:sub(1, 2)] thenhooks[i] = getHookName(i, 1)hooks.count = hooks.count + 1endend-- the "%q" parameter is not attached to a state, but is a collection of the results of multiple states (attached to "%q1", "%q2", "%q3", ...);-- so if this parameter is given then this hook must be defined separately, but only if at least one "qualifier(s)" command has been givenif formatParams[parameters.qualifier] and cfg.states.qualifiersCount > 0 thenhooks[parameters.qualifier] = getHookName(parameters.qualifier, 1)hooks.count = hooks.count + 1end-- create a state for "properties" if it doesn't exist yet, which will be used as a base configuration for each claim iteration;-- must come AFTER defining the hooksif not cfg.states[parameters.property] thencfg.states[parameters.property] = State:new(cfg, parameters.property)-- if the "single" flag has been given then this state should be equivalent to "property" (singular)if cfg.singleClaim thencfg.states[parameters.property].singleValue = trueendend-- if the "sourced" flag has been given then create a state for "reference" if it doesn't exist yet, using default values,-- which must exist in order to be able to determine if a claim has any references;-- must come AFTER defining the hooksif cfg.sourcedOnly and not cfg.states[parameters.reference] thencfg:processFlagOrCommand(p.claimCommands.reference) -- use singular "reference" to minimize overheadend-- set the parsed format and the separators (and optional punctuation mark);-- must come AFTER creating the additonal statescfg:setFormatAndSeparators(cfg.states[parameters.property], parsedFormat)-- process qualifier matching values, analogous to cfg.propertyValuefor i, v in pairs(args) doi = tostring(i)if i:match('^[Pp]%d+$') or aliasesP[i] thenv = replaceSpecialChars(v)-- check for special qualifier value 'somevalue'if v ~= "" and mw.text.trim(v) == "" thenv = " " -- single space represents 'somevalue'endcfg.qualifierIDsAndValues[replaceAlias(i):upper()] = vendend-- first sort the claims on rank to pre-define the order of output (preferred first, then normal, then deprecated)claims = sortOnRank(claims)-- then iterate through the claims to collect valuesvalue = cfg:concatValues(cfg.states[parameters.property]:iterate(claims, hooks, State.claimMatches)) -- pass property state with level 1 hooks and matchHook-- if desired, add a clickable icon that may be used to edit the returned values on Wikidataif cfg.editable and value ~= "" thenvalue = value .. cfg:getEditIcon()endreturn valueendlocal function generalCommand(args, funcName)local cfg = Config:new()cfg.curState = State:new(cfg)local lastArglocal value = nilrepeatlastArg = nextArg(args)until not cfg:processFlag(lastArg)-- get the entity ID from either the positional argument, the eid argument or the page argumentcfg.entityID = getEntityId(lastArg, args[p.args.eid], args[p.args.page], true, args[p.args.globalSiteId])if cfg.entityID == "" or not mw.wikibase.entityExists(cfg.entityID) thenreturn "" -- we cannot continue without an entityend-- serve according to the given commandif funcName == p.generalCommands.label thenvalue = cfg:getLabel(cfg.entityID, cfg.curState.rawValue, cfg.curState.linked, cfg.curState.shortName)elseif funcName == p.generalCommands.title thencfg.inSitelinks = trueif cfg.entityID:sub(1,1) == "Q" thenvalue = mw.wikibase.getSitelink(cfg.entityID)endif cfg.curState.linked and value thenvalue = buildWikilink(value)endelseif funcName == p.generalCommands.description thenvalue = mw.wikibase.getDescription(cfg.entityID)elselocal parsedFormat, formatParamslocal hooks = {count = 0}cfg.entity = mw.wikibase.getEntity(cfg.entityID)if funcName == p.generalCommands.alias or funcName == p.generalCommands.badge thencfg.curState.singleValue = trueendif funcName == p.generalCommands.alias or funcName == p.generalCommands.aliases thenif not cfg.entity.aliases or not cfg.entity.aliases[cfg.langCode] thenreturn "" -- there is no use to continue without any aliassesendlocal aliases = cfg.entity.aliases[cfg.langCode]-- parse the desired format, or parse the default aliases formatif args["format"] thenparsedFormat, formatParams = parseFormat(args["format"])elseparsedFormat, formatParams = parseFormat(formats.alias)end-- process overridden separator values;-- must come AFTER tweaking the default separatorscfg:processSeparators(args)-- define the hook that should be called (getAlias);-- only define the hook if the parameter ("%a") has been givenif formatParams[parameters.alias] thenhooks[parameters.alias] = getHookName(parameters.alias, 1)hooks.count = hooks.count + 1end-- set the parsed format and the separators (and optional punctuation mark)cfg:setFormatAndSeparators(cfg.curState, parsedFormat)-- iterate to collect valuesvalue = cfg:concatValues(cfg.curState:iterate(aliases, hooks))elseif funcName == p.generalCommands.badge or funcName == p.generalCommands.badges thenif not cfg.entity.sitelinks or not cfg.entity.sitelinks[cfg.siteID] or not cfg.entity.sitelinks[cfg.siteID].badges thenreturn "" -- there is no use to continue without any badgesendlocal badges = cfg.entity.sitelinks[cfg.siteID].badgescfg.inSitelinks = true-- parse the desired format, or parse the default aliases formatif args["format"] thenparsedFormat, formatParams = parseFormat(args["format"])elseparsedFormat, formatParams = parseFormat(formats.badge)end-- process overridden separator values;-- must come AFTER tweaking the default separatorscfg:processSeparators(args)-- define the hook that should be called (getBadge);-- only define the hook if the parameter ("%b") has been givenif formatParams[parameters.badge] thenhooks[parameters.badge] = getHookName(parameters.badge, 1)hooks.count = hooks.count + 1end-- set the parsed format and the separators (and optional punctuation mark)cfg:setFormatAndSeparators(cfg.curState, parsedFormat)-- iterate to collect valuesvalue = cfg:concatValues(cfg.curState:iterate(badges, hooks))endendvalue = value or ""if cfg.editable and value ~= "" then-- if desired, add a clickable icon that may be used to edit the returned value on Wikidatavalue = value .. cfg:getEditIcon()endreturn valueend-- modules that include this module should call the functions with an underscore prepended, e.g.: p._property(args)local function establishCommands(commandList, commandFunc)for _, commandName in pairs(commandList) dolocal function wikitextWrapper(frame)local args = copyTable(frame.args)args.pointer = 1loadI18n(aliasesP, frame)return commandFunc(args, commandName)endp[commandName] = wikitextWrapperlocal function luaWrapper(args)args = copyTable(args)args.pointer = 1loadI18n(aliasesP)return commandFunc(args, commandName)endp["_" .. commandName] = luaWrapperendendestablishCommands(p.claimCommands, claimCommand)establishCommands(p.generalCommands, generalCommand)-- main function that is supposed to be used by wrapper templatesfunction p.main(frame)if not mw.wikibase then return nil endlocal f, argsloadI18n(aliasesP, frame)-- get the parent frame to take the arguments that were passed to the wrapper templateframe = frame:getParent() or frameif not frame.args[1] thenthrowError("no-function-specified")endf = mw.text.trim(frame.args[1])if f == "main" thenthrowError("main-called-twice")endassert(p["_"..f], errorText('no-such-function', f))-- copy arguments from immutable to mutable tableargs = copyTable(frame.args)-- remove the function name from the listtable.remove(args, 1)return p["_"..f](args)endreturn p