Jump to content
 







Main menu
   


Navigation  



Main page
Contents
Current events
Random article
About Wikipedia
Contact us
Donate
 




Contribute  



Help
Learn to edit
Community portal
Recent changes
Upload file
 








Search  



























Create account

Log in
 









Create account
 Log in
 




Pages for logged out editors learn more  



Contributions
Talk
 



















Contents

   



(Top)
 


1 Usage  



1.1  Common use cases  







2 Commands  



2.1  Claim class  





2.2  General class  







3 Flags  



3.1  Command flags  





3.2  Configuration flags  







4 Arguments  



4.1  Positional arguments  





4.2  Named arguments  





4.3  Property aliases  







5 References  





6 Advanced usage  





7 Examples  



7.1  Example references  







8 TemplateData  





9 See also  














Module:Wd






Afrikaans
Ænglisc
Аԥсшәа
العربية
ܐܪܡܝܐ

Авар
Azərbaycanca
تۆرکجه
Basa Bali

 / Bân-lâm-gú
Беларуская
Беларуская (тарашкевіца)

Bikol Central
Български
Bosanski
Català
Чӑвашла
Cebuano
Čeština
Corsu
Cymraeg
Dagbanli
Dansk
الدارجة
Eesti
Ελληνικά
Español
Esperanto
فارسی
Français
Gaeilge
Gaelg
Galego
گیلکی

/Hak-kâ-ngî

Hausa
Հայերեն
ि
Hrvatski
Ilokano
Bahasa Indonesia
Interlingua
Ирон
Íslenska
Jawa


Kernowek
Kurdî
Кыргызча
Ladin
Latviešu
Lëtzebuergesch
Lietuvių
Magyar
ि
Македонски



Bahasa Melayu
Minangkabau
 / Mìng-dĕ̤ng-nḡ
Мокшень
Монгол

Nāhuatl
Nederlands
Nedersaksies


Нохчийн
Norsk bokmål
Norsk nynorsk
ି
Oʻzbekcha / ўзбекча

Pangasinan


Português
Română
Русиньскый
Русский

سرائیکی
Scots
Shqip

Simple English
سنڌي
Slovenčina
Slovenščina
کوردی
Српски / srpski
Srpskohrvatski / српскохрватски
Sunda
Svenska
Tagalog
ி
Taqbaylit
Татарча / tatarça
 

Tetun


Тоҷикӣ
Türkçe
Українська
اردو
Vahcuengh
Vèneto
Tiếng Vit
Winaray



 

Edit links
 









Module
Talk
 

















Read
View source
View history
 








Tools
   


Actions  



Read
View source
View history
 




General  



What links here
Related changes
Upload file
Special pages
Permanent link
Page information
Get shortened URL
Download QR code
Wikidata item
 




Print/export  



Download as PDF
Printable version
 




In other projects  



Wikimedia Commons
Meta-Wiki
Wikimedia Outreach
Wikispecies
Wikidata
Wikisource
Wikiversity
Wikivoyage
 

















Permanently protected module

From Wikipedia, the free encyclopedia
 


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:{{#invoke:wd|label|raw}}|...}} Performs a check to determine if the current page has a Wikidata item.

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

Commands

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}}
  1. ^ Returns only a single value instead of multiple (if multiple claims or statements match). The returned value is the first match found from the best-ranked claims.
  • ^ a b Returns only a single value instead of multiple for each matching claim. To get at most one value in total in case the property command is not also used, additionally use the single configuration flag.
  • ^ See the section on references for details.
  • 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}}
    1. ^ a b Returns only a single value instead of multiple (if multiple values are present).

    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 unit flag is also given in which case the raw unit of measurement (its Q-identifier) will be returned.

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

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

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

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

    short [EXPENSIVE] Returns the 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 + or a -, e.g. normal+orpreferred-, where the first selects claims with a 'normal' rank or higher and the second selects claims with a 'preferred' rank or lower. To get claims of all ranks, use preferred-ordeprecated+.

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

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

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

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

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

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

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

    claim, general
    edit@end

    Arguments

    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 Property: prefix may be omitted for P-identifiers (e.g. P38).

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

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

    (optional)

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

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

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

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

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

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

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


    Named arguments

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

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

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

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

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

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

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

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

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

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

    Example: |P518=Q27561

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

    claim

    Property aliases

    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.

    information 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&#124;.

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

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

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

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

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

    %q[%s][%r] if the property/properties command was not given and the qualifier/qualifiers command was given
    %r ifonly 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.
    ifonly the reference/references command was given without the raw flag
    sep%s= , default The movable separator between each pair of claims, aliases or badges. This will be the value of the %s parameter applied to all claims, aliases or badges, except for the last in the list (which can be set with the punc flag).
    ; if the property/properties command was not given and the qualifier/qualifiers command was given
    sep%q1=, sep%q2=, sep%q3=, ... ,_ default The separator between each pair of qualifiers of a single claim. These are the value separators for the %q1, %q2, %q3, ... parameters.

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

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

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

    ;_ ifmore 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}}

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

    [string]

    {{#invoke:wd|property|P395}}

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

    [string]

    {{#invoke:wd|property|eid=Q55|P395}}

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

    [string]

    {{#invoke:wd|property|page=Netherlands|P395}}

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

    [string]

    {{#invoke:wd|property|edit|Q55|P395}}

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

    [string]

    {{#invoke:wd|property|edit@end|Q55|P395}}

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

    [quantity]

    {{#invoke:wd|property|normal+|Q55|P1082}}

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

    [quantity]

    {{#invoke:wd|properties|normal+|Q55|P1082}}

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

    [quantity], [time]

    {{#invoke:wd|properties|qualifier|normal+|Q55|P1082|P585}}

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

    [quantity], [time], [reference]

    {{#invoke:wd|properties|qualifier|references|normal+|Q55|P1082|P585}}

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

    [quantity], [reference]

    A total of {{#invoke:wd|property|references|Q55|P1082}} people live in the Netherlands.

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

    [quantity], [reference]

    The Netherlands has a population of {{#invoke:wd|property|references|Q55|P1082|punc=.}}

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

    [quantity], [time], [reference]

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

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

    [time]

    {{#invoke:wd|qualifier|normal+|Q55|P1082|P585}}

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

    [time]

    {{#invoke:wd|qualifier|normal+|single|Q55|P1082|P585}}

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

    [time]

    {{#invoke:wd|qualifier|Q55|P1082|10026773|P585}}

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

    [time]

    {{#invoke:wd|qualifier|mdy|Q55|P1082|10026773|P585}}

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

    [time]

    {{#invoke:wd|qualifier|raw|Q55|P1082|10026773|P585}}

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

    [reference]

    {{#invoke:wd|references|Q55|P1082|10026773}}

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

    [reference]

    {{#invoke:wd|references|raw|Q55|P1082|10026773}}

    "CBS StatLine - Bevolking; kerncijfers". Statistics Netherlands. Archived from the original on 27 August 2015. Retrieved 22 August 2015.
    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}}

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

    [quantity], [reference]

    {{#invoke:wd|properties|references|normal+|sourced|Q55|P1081}}

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

    [entity label]

    {{#invoke:wd|qualifier|Q55|P2855|P518}}

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

    [entity label]

    {{#invoke:wd|qualifiers|Q55|P2855|P518}}

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

    [quantity], [entity label]

    {{#invoke:wd|properties|qualifiers|Q55|P2855|P518}}

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

    [quantity], [entity label]

    {{#invoke:wd|properties|qualifiers|Q55|P2855|P518|sep=_+_|sep%s=|sep%q=_/_}}

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

    [entity label], [time]

    {{#invoke:wd|properties|qualifier|qualifier|normal+|Q55|P35|P580|P582}}

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

    [entity label], [time]

    {{#invoke:wd|properties|qualifier|qualifier|normal+|Q55|P35|P580|P582|sep%q=_–_}}

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

    [entity label], [time]

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

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

    [entity label], [time]

    {{#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]}}

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

    [entity label], [time]

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

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

    [entity label]

    {{#invoke:wd|properties|qualifiers|normal+|current|Q55|P38|P518}}

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

    [entity label]

    {{#invoke:wd|properties|linked|qualifiers|normal+|current|Q55|P38|P518}}

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

    [entity label]

    {{#invoke:wd|properties|qualifiers|linked|normal+|current|Q55|P38|P518}}

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

    [entity label]

    {{#invoke:wd|properties|linked|short|qualifiers|linked|normal+|current|Q55|P38|P518}}

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

    [entity label]

    {{#invoke:wd|qualifiers|normal+|current|Q55|P38|Q4917|P518}}

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

    [entity label]

    {{#invoke:wd|properties|normal+|current|Q55|P38|P518=Q27561}}

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

    [entity label]

    {{#invoke:wd|properties|normal+|former|Q55|P38}}

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

    [entity label]

    {{#invoke:wd|properties|raw|normal+|former|Q55|P38}}

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

    [entity label]

    {{#invoke:wd|properties|raw|linked|normal+|former|Q55|P38}}

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

    [monolingual text]

    {{#invoke:wd|property|Q55|P1549}}

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

    [monolingual text]

    {{#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}}

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

    [quantity]

    {{#invoke:wd|property|linked|Q55|P2884}}

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

    [quantity]

    {{#invoke:wd|property|raw|Q55|P2884}}

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

    [quantity]

    {{#invoke:wd|property|unit|Q55|P2884}}

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

    [quantity]

    {{#invoke:wd|property|unit|raw|Q55|P2884}}

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

    [globe coordinate]

    {{#invoke:wd|property|Q55|P625}}

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

    [globe coordinate]

    {{#invoke:wd|property|linked|Q55|P625}}

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

    [globe coordinate]

    {{#invoke:wd|property|raw|Q55|P625}}

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

    [globe coordinate]

    {{#invoke:wd|property|Q55|coord}}

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

    [commons media]

    {{#invoke:wd|property|linked|Q55|P41}}

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

    [commons media]

    {{#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>{{#invoke:wd|properties|qualifier|linked|Q915684|P7235|P9758|format=<li>%q[ (%p)]</li>}}</ul>

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

    [geographic shape]

    {{#invoke:wd|property|linked|Q6256|P3896}}

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

    [entity label]

    {{#invoke:wd|label|Q4917}}

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

    [entity label]

    {{#invoke:wd|label|short|linked|Q4917}}

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

    [entity label]

    {{#invoke:wd|label|P38}}

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

    [entity label]

    {{#invoke:wd|label|linked|P38}}

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

    [entity label]

    {{#invoke:wd|label|Q776}}

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

    [entity label]

    {{#invoke:wd|label|linked|Q776}}

    Utrecht
    Gets an item's linked label.


    [entity label]

    {{#invoke:wd|label}}

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


    [entity label]

    {{#invoke:wd|label|raw}}

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


    [entity label]

    {{#invoke:wd|label|raw|linked}}

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

    [page title]

    {{#invoke:wd|title|Q776}}

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

    [page title]

    {{#invoke:wd|title|linked|Q776}}

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


    [page title]

    {{#invoke:wd|title}}

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

    [entity description]

    {{#invoke:wd|description|Q55}}

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


    [entity description]

    {{#invoke:wd|description}}

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

    [entity alias]

    {{#invoke:wd|alias|Q55}}

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

    [entity alias]

    {{#invoke:wd|aliases|Q55}}

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

    [entity alias]

    {{#invoke:wd|alias|linked|Q55}}

    Holland
    Gets a linked alias from an item.


    [entity alias]

    {{#invoke:wd|alias}}

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

    [page badge]

    {{#invoke:wd|badges|Q2}}

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

    [page badge]

    {{#invoke:wd|badges|raw|Q2}}

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


    [page badge]

    {{#invoke:wd|badges}}

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

    [version], [reference]

    {{#invoke:wd|property|reference|edit|Q28865|P548=Q2804309|P348}}

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

    Example references

  • ^ a b c d e "CBS StatLine - Bevolking; kerncijfers". Statistics Netherlands. Archived from the original on 27 August 2015. Retrieved 22 August 2015.
  • ^ a b "CBS StatLine - Bevolking; kerncijfers". Archived from the original on 3 September 2014. Retrieved 26 August 2014.
  • ^ a b "Nederland telt 17 miljoen inwoners". 21 March 2016.
  • ^ a b "Bevolking; kerncijfers, 1950-2022". Retrieved 18 March 2023.
  • ^ a b c d e f g h i j k l m n o p q r s t u v w x y z aa ab ac ad ae af ag ah ai aj ak al am an ao ap aq ar as at au av aw ax ay az ba bb bc bd "Human Development Data (1990-2017)". Human Development Report. Archived from the original on 30 December 2018.
  • ^ a b c d e f g h i j k l m n "Netherlands". Archived from the original on 2 February 2017.
  • ^ "It's time for another set of Python releases! Python 3.11.3, 3.10.11 and 3.12 alpha 7 are now available". 5 April 2023. Retrieved 6 April 2023.
  • TemplateData

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

    Template parameters[Edit template data]

    ParameterDescriptionTypeStatus
    No parameters specified

    See also

    -- Original module located at [[:en:Module:Wd]] and [[:en:Module:Wd/i18n]].
    
    require("strict")
    local p = {}
    local arg = ...
    local i18n
    
    local function loadI18n(aliasesP, frame)
     local title
    
     if frame then
      -- current module invoked by page/template, get its title from frame
      title = frame:getTitle()
     else
      -- current module included by other module, get its title from ...
      title = arg
     end
    
     if not i18n then
      i18n = require(title .. "/i18n").init(aliasesP)
     end
    end
    
    p.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 copied
    local 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] then
      id = aliasesP[id]
     end
    
     return id
    end
    
    local function errorText(code, param)
     local text = i18n["errors"][code]
     if param then text = mw.ustring.gsub(text, "$1", param) end
     return text
    end
    
    local function throwError(errorMessage, param)
     error(errorText(errorMessage, param))
    end
    
    local function replaceDecimalMark(num)
     return mw.ustring.gsub(num, "[.]", i18n['numeric']['decimal-mark'], 1)
    end
    
    local function padZeros(num, numDigits)
     local numZeros
     local negative = false
    
     if num < 0 then
      negative = true
      num = num * -1
     end
    
     num = tostring(num)
     numZeros = numDigits - num:len()
    
     for _ = 1, numZeros do
      num = "0"..num
     end
    
     if negative then
      num = "-"..num
     end
    
     return num
    end
    
    local function replaceSpecialChar(chr)
     if chr == '_' then
      -- replace underscores with spaces
      return ' '
     else
      return chr
     end
    end
    
    local function replaceSpecialChars(str)
     local chr
     local esc = false
     local strOut = ""
    
     for i = 1, #str do
      chr = str:sub(i,i)
    
      if not esc then
       if chr == '\\' then
        esc = true
       else
        strOut = strOut .. replaceSpecialChar(chr)
       end
      else
       strOut = strOut .. chr
       esc = false
      end
     end
    
     return strOut
    end
    
    local function buildWikilink(target, label)
     if not label or target == label then
      return "[[" .. target .. "]]"
     else
      return "[[" .. target .. "|" .. label .. "]]"
     end
    end
    
    -- used to make frame.args mutable, to replace #frame.args (which is always 0)
    -- with the actual amount and to simply copy tables
    local function copyTable(tIn)
     if not tIn then
      return nil
     end
    
     local tOut = {}
    
     for i, v in pairs(tIn) do
      tOut[i] = v
     end
    
     return tOut
    end
    
    -- used to merge output arrays together;
    -- note that it currently mutates the first input array
    local function mergeArrays(a1, a2)
     for i = 1, #a2 do
      a1[#a1 + 1] = a2[i]
     end
    
     return a1
    end
    
    local function split(str, del)
     local out = {}
     local i, j = str:find(del)
    
     if i and j then
      out[1] = str:sub(1, i - 1)
      out[2] = str:sub(j + 1)
     else
      out[1] = str
     end
    
     return out
    end
    
    local function parseWikidataURL(url)
     local id
    
     if url:match('^http[s]?://') then
      id = split(url, "Q")
    
      if id[2] then
       return "Q" .. id[2]
      end
     end
    
     return nil
    end
    
    local function parseDate(dateStr, precision)
     precision = precision or "d"
    
     local i, j, index, ptr
     local parts = {nil, nil, nil}
    
     if dateStr == nil then
      return parts[1], parts[2], parts[3]  -- year, month, day
     end
    
     -- 'T' for snak values, '/' for outputs with '/Julian' attached
     i, j = dateStr:find("[T/]")
    
     if i then
      dateStr = dateStr:sub(1, i-1)
     end
    
     local from = 1
    
     if dateStr:sub(1,1) == "-" then
      -- this is a negative number, look further ahead
      from = 2
     end
    
     index = 1
     ptr = 1
    
     i, j = dateStr:find("-", from)
    
     if i then
      -- year
      parts[index] = tonumber(dateStr:sub(ptr, i-1), 10)  -- explicitly give base 10 to prevent error
    
      if parts[index] == -0 then
       parts[index] = tonumber("0")  -- for some reason, 'parts[index] = 0' may actually store '-0', so parse from string instead
      end
    
      if precision == "y" then
       -- we're done
       return parts[1], parts[2], parts[3]  -- year, month, day
      end
    
      index = index + 1
      ptr = i + 1
    
      i, j = dateStr:find("-", ptr)
    
      if i then
       -- month
       parts[index] = tonumber(dateStr:sub(ptr, i-1), 10)
    
       if precision == "m" then
        -- we're done
        return parts[1], parts[2], parts[3]  -- year, month, day
       end
    
       index = index + 1
       ptr = i + 1
      end
     end
    
     if dateStr:sub(ptr) ~= "" then
      -- day if we have month, month if we have year, or year
      parts[index] = tonumber(dateStr:sub(ptr), 10)
     end
    
     return parts[1], parts[2], parts[3]  -- year, month, day
    end
    
    local function datePrecedesDate(aY, aM, aD, bY, bM, bD)
     if aY == nil or bY == nil then
      return nil
     end
     aM = aM or 1
     aD = aD or 1
     bM = bM or 1
     bD = bD or 1
    
     if aY < bY then
      return true
     end
    
     if aY > bY then
      return false
     end
    
     if aM < bM then
      return true
     end
    
     if aM > bM then
      return false
     end
    
     if aD < bD then
      return true
     end
    
     return false
    end
    
    local function getHookName(param, index)
     if hookNames[param] then
      return hookNames[param][index]
     elseif param:len() > 2 then
      return hookNames[param:sub(1, 2).."\\d"][index]
     else
      return nil
     end
    end
    
    local function alwaysTrue()
     return true
    end
    
    -- 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, new
     local params = {}
    
     local function newObject(array)
      local obj = {}  -- new object
      obj.str = ""
    
      array[#array + 1] = obj  -- array{object}
      obj.parent = array
    
      return obj
     end
    
     local function endParam()
      if param > 0 then
       if cur.str ~= "" then
        cur.str = "%"..cur.str
        cur.param = true
        params[cur.str] = true
        cur.parent.req[cur.str] = true
        prev = cur
        cur = newObject(cur.parent)
       end
       param = 0
      end
     end
    
     root = {}  -- array
     root.req = {}
     cur = newObject(root)
     prev = nil
    
     esc = false
     param = 0
    
     for i = 1, #str do
      chr = str:sub(i,i)
    
      if not esc then
       if chr == '\\' then
        endParam()
        esc = true
       elseif chr == '%' then
        endParam()
        if cur.str ~= "" then
         cur = newObject(cur.parent)
        end
        param = 2
       elseif chr == '[' then
        endParam()
        if prev and cur.str == "" then
         table.remove(cur.parent)
         cur = prev
        end
        cur.child = {}  -- new array
        cur.child.req = {}
        cur.child.parent = cur
        cur = newObject(cur.child)
       elseif chr == ']' then
        endParam()
        if cur.parent.parent then
         new = newObject(cur.parent.parent.parent)
         if cur.str == "" then
          table.remove(cur.parent)
         end
         cur = new
        end
       else
        if param > 1 then
         param = param - 1
        elseif param == 1 then
         if not chr:match('%d') then
          endParam()
         end
        end
    
        cur.str = cur.str .. replaceSpecialChar(chr)
       end
      else
       cur.str = cur.str .. chr
       esc = false
      end
    
      prev = nil
     end
    
     endParam()
    
     -- make sure that at least one required parameter has been defined
     if not next(root.req) then
      throwError("missing-required-parameter")
     end
    
     -- make sure that the separator parameter "%s" is not amongst the required parameters
     if root.req[parameters.separator] then
      throwError("extra-required-parameter", parameters.separator)
     end
    
     return root, params
    end
    
    local function sortOnRank(claims)
     local rankPos
     local ranks = {{}, {}, {}, {}}  -- preferred, normal, deprecated, (default)
     local sorted = {}
    
     for _, v in ipairs(claims) do
      rankPos = rankTable[v.rank] or 4
      ranks[rankPos][#ranks[rankPos] + 1] = v
     end
    
     sorted = ranks[1]
     sorted = mergeArrays(sorted, ranks[2])
     sorted = mergeArrays(sorted, ranks[3])
    
     return sorted
    end
    
    local Config = {}
    
    -- allows for recursive calls
    function Config:new()
     local cfg = {}
     setmetatable(cfg, self)
     self.__index = self
    
     cfg.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 = nil
     cfg.entityID = nil
     cfg.propertyID = nil
     cfg.propertyValue = nil
     cfg.qualifierIDs = {}
     cfg.qualifierIDsAndValues = {}
    
     cfg.bestRank = true
     cfg.ranks = {true, true, false}  -- preferred = true, normal = true, deprecated = false
     cfg.foundRank = #cfg.ranks
     cfg.flagBest = false
     cfg.flagRank = false
    
     cfg.periods = {true, true, true}  -- future = true, current = true, former = true
     cfg.flagPeriod = false
     cfg.atDate = {parseDate(os.date('!%Y-%m-%d'))}  -- today as {year, month, day}
    
     cfg.mdyDate = false
     cfg.singleClaim = false
     cfg.sourcedOnly = false
     cfg.editable = false
     cfg.editAtEnd = false
    
     cfg.inSitelinks = false
    
     cfg.langCode = mw.language.getContentLanguage().code
     cfg.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 = 0
     cfg.curState = nil
    
     cfg.prefetchedRefs = nil
    
     return cfg
    end
    
    local State = {}
    
    function State:new(cfg, type)
     local stt = {}
     setmetatable(stt, self)
     self.__index = self
    
     stt.conf = cfg
     stt.type = type
    
     stt.results = {}
    
     stt.parsedFormat = {}
     stt.separator = {}
     stt.movSeparator = {}
     stt.puncMark = {}
    
     stt.linked = false
     stt.rawValue = false
     stt.shortName = false
     stt.anyLanguage = false
     stt.unitOnly = false
     stt.singleValue = false
    
     return stt
    end
    
    -- if id == nil then item connected to current page is used
    function Config:getLabel(id, raw, link, short)
     local label = nil
     local prefix, title= "", nil
    
     if not id then
      id = mw.wikibase.getEntityIdForCurrentPage()
    
      if not id then
       return ""
      end
     end
    
     id = id:upper()  -- just to be sure
    
     if raw then
      -- check if given id actually exists
      if mw.wikibase.isValidEntityId(id) and mw.wikibase.entityExists(id) then
       label = id
      end
    
      prefix, title = "d:Special:EntityPage/", label -- may be nil
     else
      -- try short name first if requested
      if short then
       label = p._property{aliasesP.shortName, [p.args.eid] = id}  -- get short name
    
       if label == "" then
        label = nil
       end
      end
    
      -- get label
      if not label then
       label = mw.wikibase.getLabelByLang(id, self.langCode) -- XXX: should use fallback labels?
      end
     end
    
     if not label then
      label = ""
     elseif link then
      -- build a link if requested
      if not title then
       if id:sub(1,1) == "Q" then
        title = mw.wikibase.getSitelink(id)
       elseif id:sub(1,1) == "P" then
        -- properties have no sitelink, link to Wikidata instead
        prefix, title = "d:Special:EntityPage/", id
       end
      end
    
      label = mw.text.nowiki(label) -- escape raw label text so it cannot be wikitext markup
      if title then
       label = buildWikilink(prefix .. title, label)
      end
     end
    
     return label
    end
    
    function Config:getEditIcon()
     local value = ""
     local prefix = ""
     local front = "&nbsp;"
     local back = ""
    
     if self.entityID:sub(1,1) == "P" then
      prefix = "Property:"
     end
    
     if self.editAtEnd then
      front = '<span style="float:'
    
      if self.langObj:isRTL() then
       front = front .. 'left'
      else
       front = front .. 'right'
      end
    
      front = front .. '">'
      back = '</span>'
     end
    
     value = "[[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.langCode
    
     if self.propertyID then
      value = value .. "#" .. self.propertyID
     elseif self.inSitelinks then
      value = value .. "#sitelinks-wikipedia"
     end
    
     value = value .. "|" .. i18n['info']['edit-on-wikidata'] .. "]]"
    
     return front .. value .. back
    end
    
    -- 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 output
    function Config:concatValues(valuesArray)
     local outString = ""
     local j, skip
    
     for i = 1, #valuesArray do
      -- check if this is a reference
      if valuesArray[i].refHash then
       j = i - 1
       skip = false
    
       -- skip this reference if it is part of a continuous row of references that already contains the exact same reference
       while valuesArray[j] and valuesArray[j].refHash do
        if valuesArray[i].refHash == valuesArray[j].refHash then
         skip = true
         break
        end
        j = j - 1
       end
    
       if 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})
       end
      else
       outString = outString .. valuesArray[i][1]
      end
     end
    
     return outString
    end
    
    function Config:convertUnit(unit, raw, link, short, unitOnly)
     local space = " "
     local label = ""
     local itemID
    
     if unit == "" or unit == "1" then
      return nil
     end
    
     if unitOnly then
      space = ""
     end
    
     itemID = parseWikidataURL(unit)
    
     if itemID then
      if itemID == aliasesQ.percentage then
       return "%"
      else
       label = self:getLabel(itemID, raw, link, short)
    
       if label ~= "" then
        return space .. label
       end
      end
     end
    
     return ""
    end
    
    function State:getValue(snak)
     return self.conf:getValue(snak, self.rawValue, self.linked, self.shortName, self.anyLanguage, self.unitOnly, false, self.type:sub(1,2))
    end
    
    function Config:getValue(snak, raw, link, short, anyLang, unitOnly, noSpecial, type)
     if snak.snaktype == 'value' then
      local datatype = snak.datavalue.type
      local subtype = snak.datatype
      local datavalue = snak.datavalue.value
    
      if datatype == 'string' then
       if subtype == 'url' and link then
        -- create link explicitly
        if raw then
         -- will render as a linked number like [1]
         return "[" .. datavalue .. "]"
        else
         return "[" .. datavalue .. " " .. datavalue .. "]"
        end
       elseif subtype == 'commonsMedia' then
        if link then
         return buildWikilink("c:File:" .. datavalue, datavalue)
        elseif not raw then
         return "[[File:" .. datavalue .. "]]"
        else
         return datavalue
        end
       elseif subtype == 'geo-shape' and link then
        return buildWikilink("c:" .. datavalue, datavalue)
       elseif subtype == 'math' and not raw then
        local attribute = nil
    
        if (type == parameters.property or (type == parameters.qualifier and self.propertyID == aliasesP.hasPart)) and snak.property == aliasesP.definingFormula then
         attribute = {qid = self.entityID}
        end
    
        return mw.getCurrentFrame():extensionTag("math", datavalue, attribute)
       elseif subtype == 'external-id' and link then
        local url = p._property{aliasesP.formatterURL, [p.args.eid] = snak.property}  -- get formatter URL
    
        if url ~= "" then
         url = mw.ustring.gsub(url, "$1", datavalue)
         return "[" .. url .. " " .. datavalue .. "]"
        else
         return datavalue
        end
       else
        return datavalue
       end
      elseif datatype == 'monolingualtext' then
       if anyLang or datavalue['language'] == self.langCode then
        return datavalue['text']
       else
        return nil
       end
      elseif datatype == 'quantity' then
       local value = ""
       local unit
    
       if not unitOnly then
        -- get value and strip + signs from front
        value = mw.ustring.gsub(datavalue['amount'], "^%+(.+)$", "%1")
    
        if raw then
         return value
        end
    
        -- replace decimal mark based on locale
        value = replaceDecimalMark(value)
    
        -- add delimiters for readability
        value = i18n.addDelimiters(value)
       end
    
       unit = self:convertUnit(datavalue['unit'], raw, link, short, unitOnly)
    
       if unit then
        value = value .. unit
       end
    
       return value
      elseif datatype == 'time' then
       local y, m, d, p, yDiv, yRound, yFull, value, calendarID, dateStr
       local yFactor = 1
       local sign = 1
       local prefix = ""
       local suffix = ""
       local mayAddCalendar = false
       local calendar = ""
       local precision = datavalue['precision']
    
       if precision == 11 then
        p = "d"
       elseif precision == 10 then
        p = "m"
       else
        p = "y"
        yFactor = 10^(9-precision)
       end
    
       y, m, d = parseDate(datavalue['time'], p)
    
       if y < 0 then
        sign = -1
        y = y * sign
       end
    
       -- if precision is tens/hundreds/thousands/millions/billions of years
       if precision <= 8 then
        yDiv = y / yFactor
    
        -- if precision is tens/hundreds/thousands of years
        if precision >= 6 then
         mayAddCalendar = true
    
         if precision <= 7 then
          -- round centuries/millenniums up (e.g. 20th century or 3rd millennium)
          yRound = math.ceil(yDiv)
    
          if not raw then
           if precision == 6 then
            suffix = i18n['datetime']['suffixes']['millennium']
           else
            suffix = i18n['datetime']['suffixes']['century']
           end
    
           suffix = i18n.getOrdinalSuffix(yRound) .. suffix
          else
           -- 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 + 1
          end
         else
          -- precision == 8
          -- round decades down (e.g. 2010s)
          yRound = math.floor(yDiv) * yFactor
    
          if not raw then
           prefix = i18n['datetime']['prefixes']['decade-period']
           suffix = i18n['datetime']['suffixes']['decade-period']
          end
         end
    
         if 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 - 1
         end
        else
         local yReFactor, yReDiv, yReRound
    
         -- round to nearest for tens of thousands of years or more
         yRound = math.floor(yDiv + 0.5)
    
         if yRound == 0 then
          if precision <= 2 and y ~= 0 then
           yReFactor = 1e6
           yReDiv = y / yReFactor
           yReRound = math.floor(yReDiv + 0.5)
    
           if yReDiv == yReRound then
            -- change precision to millions of years only if we have a whole number of them
            precision = 3
            yFactor = yReFactor
            yRound = yReRound
           end
          end
    
          if yRound == 0 then
           -- otherwise, take the unrounded (original) number of years
           precision = 5
           yFactor = 1
           yRound = y
           mayAddCalendar = true
          end
         end
    
         if precision >= 1 and y ~= 0 then
          yFull = yRound * yFactor
    
          yReFactor = 1e9
          yReDiv = yFull / yReFactor
          yReRound = math.floor(yReDiv + 0.5)
    
          if yReDiv == yReRound then
           -- change precision to billions of years if we're in that range
           precision = 0
           yFactor = yReFactor
           yRound = yReRound
          else
           yReFactor = 1e6
           yReDiv = yFull / yReFactor
           yReRound = math.floor(yReDiv + 0.5)
    
           if yReDiv == yReRound then
            -- change precision to millions of years if we're in that range
            precision = 3
            yFactor = yReFactor
            yRound = yReRound
           end
          end
         end
    
         if not raw then
          if precision == 3 then
           suffix = i18n['datetime']['suffixes']['million-years']
          elseif precision == 0 then
           suffix = i18n['datetime']['suffixes']['billion-years']
          else
           yRound = yRound * yFactor
           if yRound == 1 then
            suffix = i18n['datetime']['suffixes']['year']
           else
            suffix = i18n['datetime']['suffixes']['years']
           end
          end
         else
          yRound = yRound * yFactor
         end
        end
       else
        yRound = y
        mayAddCalendar = true
       end
    
       if mayAddCalendar then
        calendarID = parseWikidataURL(datavalue['calendarmodel'])
    
        if calendarID and calendarID == aliasesQ.prolepticJulianCalendar then
         if not raw then
          if link then
           calendar = " ("..buildWikilink(i18n['datetime']['julian-calendar'], i18n['datetime']['julian'])..")"
          else
           calendar = " ("..i18n['datetime']['julian']..")"
          end
         else
          calendar = "/"..i18n['datetime']['julian']
         end
        end
       end
    
       if not raw then
        local ce = nil
    
        if sign < 0 then
         ce = i18n['datetime']['BCE']
        elseif precision <= 5 then
         ce = i18n['datetime']['CE']
        end
    
        if ce then
         if link then
          ce = buildWikilink(i18n['datetime']['common-era'], ce)
         end
         suffix = suffix .. " " .. ce
        end
    
        value = tostring(yRound)
    
        if m then
         dateStr = self.langObj:formatDate("F", "1-"..m.."-1")
    
         if d then
          if self.mdyDate then
           dateStr = dateStr .. " " .. d .. ","
          else
           dateStr = d .. " " .. dateStr
          end
         end
    
         value = dateStr .. " " .. value
        end
    
        value = prefix .. value .. suffix .. calendar
       else
        value = padZeros(yRound * sign, 4)
    
        if m then
         value = value .. "-" .. padZeros(m, 2)
    
         if d then
          value = value .. "-" .. padZeros(d, 2)
         end
        end
    
        value = value .. calendar
       end
    
       return value
      elseif datatype == 'globecoordinate' then
       -- logic from https://github.com/DataValues/Geo (v4.0.1)
    
       local precision, unitsPerDegree, numDigits, strFormat, value, globe
       local latitude, latConv, latValue, latLink
       local longitude, lonConv, lonValue, lonLink
       local latDirection, latDirectionN, latDirectionS, latDirectionEN
       local lonDirection, lonDirectionE, lonDirectionW, lonDirectionEN
       local degSymbol, minSymbol, secSymbol, separator
    
       local latDegrees = nil
       local latMinutes = nil
       local latSeconds = nil
       local lonDegrees = nil
       local lonMinutes = nil
       local lonSeconds = nil
    
       local 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 then
        latDirectionN = 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']
       else
        latDirectionN = latDirectionEN_N
        latDirectionS = latDirectionEN_S
        lonDirectionE = lonDirectionEN_E
        lonDirectionW = lonDirectionEN_W
    
        degSymbol = "/"
        minSymbol = "/"
        secSymbol = "/"
        separator = "/"
       end
    
       latitude = datavalue['latitude']
       longitude = datavalue['longitude']
    
       if latitude < 0 then
        latDirection = latDirectionS
        latDirectionEN = latDirectionEN_S
        latitude = math.abs(latitude)
       else
        latDirection = latDirectionN
        latDirectionEN = latDirectionEN_N
       end
    
       if longitude < 0 then
        lonDirection = lonDirectionW
        lonDirectionEN = lonDirectionEN_W
        longitude = math.abs(longitude)
       else
        lonDirection = lonDirectionE
        lonDirectionEN = lonDirectionEN_E
       end
    
       precision = datavalue['precision']
    
       if not precision or precision <= 0 then
        precision = 1 / 3600  -- precision not set (correctly), set to arcsecond
       end
    
       -- remove insignificant detail
       latitude = math.floor(latitude / precision + 0.5) * precision
       longitude = math.floor(longitude / precision + 0.5) * precision
    
       if precision >= 1 - (1 / 60) and precision < 1 then
        precision = 1
       elseif precision >= (1 / 60) - (1 / 3600) and precision < (1 / 60) then
        precision = 1 / 60
       end
    
       if precision >= 1 then
        unitsPerDegree = 1
       elseif precision >= (1 / 60)  then
        unitsPerDegree = 60
       else
        unitsPerDegree = 3600
       end
    
       numDigits = math.ceil(-math.log10(unitsPerDegree * precision))
    
       if numDigits <= 0 then
        numDigits = tonumber("0")  -- for some reason, 'numDigits = 0' may actually store '-0', so parse from string instead
       end
    
       strFormat = "%." .. numDigits .. "f"
    
       if precision >= 1 then
        latDegrees = strFormat:format(latitude)
        lonDegrees = strFormat:format(longitude)
    
        if not raw then
         latDegSym = replaceDecimalMark(latDegrees) .. degSymbol
         lonDegSym = replaceDecimalMark(lonDegrees) .. degSymbol
        else
         latDegSym = latDegrees .. degSymbol
         lonDegSym = lonDegrees .. degSymbol
        end
       else
        latConv = math.floor(latitude * unitsPerDegree * 10^numDigits + 0.5) / 10^numDigits
        lonConv = math.floor(longitude * unitsPerDegree * 10^numDigits + 0.5) / 10^numDigits
    
        if precision >= (1 / 60) then
         latMinutes = latConv
         lonMinutes = lonConv
        else
         latSeconds = latConv
         lonSeconds = lonConv
    
         latMinutes = math.floor(latSeconds / 60)
         lonMinutes = math.floor(lonSeconds / 60)
    
         latSeconds = strFormat:format(latSeconds - (latMinutes * 60))
         lonSeconds = strFormat:format(lonSeconds - (lonMinutes * 60))
    
         if not raw then
          latSecSym = replaceDecimalMark(latSeconds) .. secSymbol
          lonSecSym = replaceDecimalMark(lonSeconds) .. secSymbol
         else
          latSecSym = latSeconds .. secSymbol
          lonSecSym = lonSeconds .. secSymbol
         end
        end
    
        latDegrees = math.floor(latMinutes / 60)
        lonDegrees = math.floor(lonMinutes / 60)
    
        latDegSym = latDegrees .. degSymbol
        lonDegSym = lonDegrees .. degSymbol
    
        latMinutes = latMinutes - (latDegrees * 60)
        lonMinutes = lonMinutes - (lonDegrees * 60)
    
        if precision >= (1 / 60) then
         latMinutes = strFormat:format(latMinutes)
         lonMinutes = strFormat:format(lonMinutes)
    
         if not raw then
          latMinSym = replaceDecimalMark(latMinutes) .. minSymbol
          lonMinSym = replaceDecimalMark(lonMinutes) .. minSymbol
         else
          latMinSym = latMinutes .. minSymbol
          lonMinSym = lonMinutes .. minSymbol
         end
        else
         latMinSym = latMinutes .. minSymbol
         lonMinSym = lonMinutes .. minSymbol
        end
       end
    
       latValue = latDegSym .. latMinSym .. latSecSym .. latDirection
       lonValue = lonDegSym .. lonMinSym .. lonSecSym .. lonDirection
    
       value = latValue .. separator .. lonValue
    
       if link then
        globe = parseWikidataURL(datavalue['globe'])
    
        if globe then
         globe = mw.wikibase.getLabelByLang(globe, "en"):lower()
        else
         globe = "earth"
        end
    
        latLink = table.concat({latDegrees, latMinutes, latSeconds}, "_")
        lonLink = table.concat({lonDegrees, lonMinutes, lonSeconds}, "_")
    
        value = "[https://geohack.toolforge.org/geohack.php?language="..self.langCode.."&params="..latLink.."_"..latDirectionEN.."_"..lonLink.."_"..lonDirectionEN.."_globe:"..globe.." "..value.."]"
       end
    
       return value
      elseif datatype == 'wikibase-entityid' then
       local label
       local itemID = datavalue['numeric-id']
    
       if subtype == 'wikibase-item' then
        itemID = "Q" .. itemID
       elseif subtype == 'wikibase-property' then
        itemID = "P" .. itemID
       else
        return '<strong class="error">' .. errorText('unknown-data-type', subtype) .. '</strong>'
       end
    
       label = self:getLabel(itemID, raw, link, short)
    
       if label == "" then
        label = nil
       end
    
       return label
      else
       return '<strong class="error">' .. errorText('unknown-data-type', datatype) .. '</strong>'
      end
     elseif snak.snaktype == 'somevalue' and not noSpecial then
      if raw then
       return " "  -- single space represents 'somevalue'
      else
       return i18n['values']['unknown']
      end
     elseif snak.snaktype == 'novalue' and not noSpecial then
      if raw then
       return ""  -- empty string represents 'novalue'
      else
       return i18n['values']['none']
      end
     else
      return nil
     end
    end
    
    function Config:getSingleRawQualifier(claim, qualifierID)
     local qualifiers
    
     if claim.qualifiers then qualifiers = claim.qualifiers[qualifierID] end
    
     if qualifiers and qualifiers[1] then
      return self:getValue(qualifiers[1], true)  -- raw = true
     else
      return nil
     end
    end
    
    function Config:snakEqualsValue(snak, value)
     local snakValue = self:getValue(snak, true)  -- raw = true
    
     if snakValue and snak.snaktype == 'value' and snak.datavalue.type == 'wikibase-entityid' then value = value:upper() end
    
     return snakValue == value
    end
    
    function Config:setRank(rank)
     local rankPos
    
     if rank == p.flags.best then
      self.bestRank = true
      self.flagBest = true  -- mark that 'best' flag was given
      return
     end
    
     if rank:sub(1,9) == p.flags.preferred then
      rankPos = 1
     elseif rank:sub(1,6) == p.flags.normal then
      rankPos = 2
     elseif rank:sub(1,10) == p.flags.deprecated then
      rankPos = 3
     else
      return
     end
    
     -- one of the rank flags was given, check if another one was given before
     if not self.flagRank then
      self.ranks = {false, false, false}  -- no other rank flag given before, so unset ranks
      self.bestRank = self.flagBest       -- unsets bestRank only if 'best' flag was not given before
      self.flagRank = true                -- mark that a rank flag was given
     end
    
     if rank:sub(-1) == "+" then
      for i = rankPos, 1, -1 do
       self.ranks[i] = true
      end
     elseif rank:sub(-1) == "-" then
      for i = rankPos, #self.ranks do
       self.ranks[i] = true
      end
     else
      self.ranks[rankPos] = true
     end
    end
    
    function Config:setPeriod(period)
     local periodPos
    
     if period == p.flags.future then
      periodPos = 1
     elseif period == p.flags.current then
      periodPos = 2
     elseif period == p.flags.former then
      periodPos = 3
     else
      return
     end
    
     -- one of the period flags was given, check if another one was given before
     if not self.flagPeriod then
      self.periods = {false, false, false}  -- no other period flag given before, so unset periods
      self.flagPeriod = true                -- mark that a period flag was given
     end
    
     self.periods[periodPos] = true
    end
    
    function Config:qualifierMatches(claim, id, value)
     local qualifiers
    
     if claim.qualifiers then qualifiers = claim.qualifiers[id] end
     if qualifiers then
      for _, v in pairs(qualifiers) do
       if self:snakEqualsValue(v, value) then
        return true
       end
      end
     elseif value == "" then
      -- if the qualifier is not present then treat it the same as the special value 'novalue'
      return true
     end
    
     return false
    end
    
    function Config:rankMatches(rankPos)
     if self.bestRank then
      return (self.ranks[rankPos] and self.foundRank >= rankPos)
     else
      return self.ranks[rankPos]
     end
    end
    
    function Config:timeMatches(claim)
     local startTime = nil
     local startTimeY = nil
     local startTimeM = nil
     local startTimeD = nil
     local endTime = nil
     local endTimeY = nil
     local endTimeM = nil
     local endTimeD = nil
    
     if self.periods[1] and self.periods[2] and self.periods[3] then
      -- any time
      return true
     end
    
     startTime = self:getSingleRawQualifier(claim, aliasesP.startTime)
     if startTime and startTime ~= "" and startTime ~= " " then
      startTimeY, startTimeM, startTimeD = parseDate(startTime)
     end
    
     endTime = self:getSingleRawQualifier(claim, aliasesP.endTime)
     if endTime and endTime ~= "" and endTime ~= " " then
      endTimeY, endTimeM, endTimeD = parseDate(endTime)
     end
    
     if startTimeY ~= nil and endTimeY ~= nil and datePrecedesDate(endTimeY, endTimeM, endTimeD, startTimeY, startTimeM, startTimeD) then
      -- invalidate end time if it precedes start time
      endTimeY = nil
      endTimeM = nil
      endTimeD = nil
     end
    
     if self.periods[1] then
      -- future
      if startTimeY and datePrecedesDate(self.atDate[1], self.atDate[2], self.atDate[3], startTimeY, startTimeM, startTimeD) then
       return true
      end
     end
    
     if self.periods[2] then
      -- current
      if (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)) then
       return true
      end
     end
    
     if self.periods[3] then
      -- former
      if endTimeY and not datePrecedesDate(self.atDate[1], self.atDate[2], self.atDate[3], endTimeY, endTimeM, endTimeD) then
       return true
      end
     end
    
     return false
    end
    
    function Config:processFlag(flag)
     if not flag then
      return false
     end
    
     if flag == p.flags.linked then
      self.curState.linked = true
      return true
     elseif flag == p.flags.raw then
      self.curState.rawValue = true
    
      if 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] = {" "}
      end
    
      return true
     elseif flag == p.flags.short then
      self.curState.shortName = true
      return true
     elseif flag == p.flags.multilanguage then
      self.curState.anyLanguage = true
      return true
     elseif flag == p.flags.unit then
      self.curState.unitOnly = true
      return true
     elseif flag == p.flags.mdy then
      self.mdyDate = true
      return true
     elseif flag == p.flags.single then
      self.singleClaim = true
      return true
     elseif flag == p.flags.sourced then
      self.sourcedOnly = true
      return true
     elseif flag == p.flags.edit then
      self.editable = true
      return true
     elseif flag == p.flags.editAtEnd then
      self.editable = true
      self.editAtEnd = true
      return true
     elseif flag == p.flags.best or flag:match('^'..p.flags.preferred..'[+-]?$') or flag:match('^'..p.flags.normal..'[+-]?$') or flag:match('^'..p.flags.deprecated..'[+-]?$') then
      self:setRank(flag)
      return true
     elseif flag == p.flags.future or flag == p.flags.current or flag == p.flags.former then
      self:setPeriod(flag)
      return true
     elseif flag == "" then
      -- ignore empty flags and carry on
      return true
     else
      return false
     end
    end
    
    function Config:processFlagOrCommand(flag)
     local param = ""
    
     if not flag then
      return false
     end
    
     if flag == p.claimCommands.property or flag == p.claimCommands.properties then
      param = parameters.property
     elseif flag == p.claimCommands.qualifier or flag == p.claimCommands.qualifiers then
      self.states.qualifiersCount = self.states.qualifiersCount + 1
      param = parameters.qualifier .. self.states.qualifiersCount
      self.separators["sep"..param] = {copyTable(defaultSeparators["sep%q\\d"])}
     elseif flag == p.claimCommands.reference or flag == p.claimCommands.references then
      param = parameters.reference
     else
      return self:processFlag(flag)
     end
    
     if self.states[param] then
      return false
     end
    
     -- create a new state for each command
     self.states[param] = State:new(self, param)
    
     -- use "%x" as the general parameter name
     self.states[param].parsedFormat = parseFormat(parameters.general)  -- will be overwritten for param=="%p"
    
     -- set the separator
     self.states[param].separator = self.separators["sep"..param]  -- will be nil for param=="%p", which will be set separately
    
     if flag == p.claimCommands.property or flag == p.claimCommands.qualifier or flag == p.claimCommands.reference then
      self.states[param].singleValue = true
     end
    
     self.curState = self.states[param]
    
     return true
    end
    
    function Config:processSeparators(args)
     local sep
    
     for i, v in pairs(self.separators) do
      if args[i] then
       sep = replaceSpecialChars(args[i])
    
       if sep ~= "" then
        self.separators[i][1] = {sep}
       else
        self.separators[i][1] = nil
       end
      end
     end
    end
    
    function Config:setFormatAndSeparators(state, parsedFormat)
     state.parsedFormat = parsedFormat
     state.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 use
    function State:isSourced(claim)
     self.conf.prefetchedRefs = self:getReferences(claim)
     return (#self.conf.prefetchedRefs > 0)
    end
    
    function State:resetCaches()
     -- any prefetched references of the previous claim must not be used
     self.conf.prefetchedRefs = nil
    end
    
    function State:claimMatches(claim)
     local matches, rankPos
    
     -- first of all, reset any cached values used for the previous claim
     self:resetCaches()
    
     -- if a property value was given, check if it matches the claim's property value
     if self.conf.propertyValue then
      matches = self.conf:snakEqualsValue(claim.mainsnak, self.conf.propertyValue)
     else
      matches = true
     end
    
     -- if any qualifier values were given, check if each matches one of the claim's qualifier values
     for i, v in pairs(self.conf.qualifierIDsAndValues) do
      matches = (matches and self.conf:qualifierMatches(claim, i, v))
     end
    
     -- check if the claim's rank and time period match
     rankPos = rankTable[claim.rank] or 4
     matches = (matches and self.conf:rankMatches(rankPos) and self.conf:timeMatches(claim))
    
     -- if only claims with references must be returned, check if this one has any
     if self.conf.sourcedOnly then
      matches = (matches and self:isSourced(claim))  -- prefetches and caches references
     end
    
     return matches, rankPos
    end
    
    function State:out()
     local result  -- collection of arrays with value objects
     local valuesArray  -- array with value objects
     local sep = nil  -- value object
     local out = {}  -- array with value objects
    
     local function walk(formatTable, result)
      local valuesArray = {}  -- array with value objects
    
      for i, v in pairs(formatTable.req) do
       if 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 result
        return {}
       end
      end
    
      for _, v in ipairs(formatTable) do
       if v.param then
        valuesArray = mergeArrays(valuesArray, result[v.str])
       elseif v.str ~= "" then
        valuesArray[#valuesArray + 1] = {v.str}
       end
    
       if v.child then
        valuesArray = mergeArrays(valuesArray, walk(v.child, result))
       end
      end
    
      return valuesArray
     end
    
     -- iterate through the results from back to front, so that we know when to add separators
     for i = #self.results, 1, -1 do
      result = self.results[i]
    
      -- if there is already some output, then add the separators
      if #out > 0 then
       sep = self.separator[1]  -- fixed separator
       result[parameters.separator] = {self.movSeparator[1]}  -- movable separator
      else
       sep = nil
       result[parameters.separator] = {self.puncMark[1]}  -- optional punctuation mark
      end
    
      valuesArray = walk(self.parsedFormat, result)
    
      if #valuesArray > 0 then
       if sep then
        valuesArray[#valuesArray + 1] = sep
       end
    
       out = mergeArrays(valuesArray, out)
      end
     end
    
     -- reset state before next iteration
     self.results = {}
    
     return out
    end
    
    -- level 1 hook
    function State:getProperty(claim)
     local value = {self:getValue(claim.mainsnak)}  -- create one value object
    
     if #value > 0 then
      return {value}  -- wrap the value object in an array and return it
     else
      return {}  -- return empty array if there was no value
     end
    end
    
    -- level 1 hook
    function State:getQualifiers(claim, param)
     local qualifiers
    
     if claim.qualifiers then qualifiers = claim.qualifiers[self.conf.qualifierIDs[param]] end
     if qualifiers then
      -- iterate through claim's qualifier statements to collect their values;
      -- return array with multiple value objects
      return self.conf.states[param]:iterate(qualifiers, {[parameters.general] = hookNames[parameters.qualifier.."\\d"][2], count = 1})  -- pass qualifier state with level 2 hook
     else
      return {}  -- return empty array
     end
    end
    
    -- level 2 hook
    function State:getQualifier(snak)
     local value = {self:getValue(snak)}  -- create one value object
    
     if #value > 0 then
      return {value}  -- wrap the value object in an array and return it
     else
      return {}  -- return empty array if there was no value
     end
    end
    
    -- level 1 hook
    function State:getAllQualifiers(claim, param, result, hooks)
     local out = {}  -- array with value objects
     local sep = self.conf.separators["sep"..parameters.qualifier][1]  -- value object
    
     -- iterate through the output of the separate "qualifier(s)" commands
     for i = 1, self.conf.states.qualifiersCount do
    
      -- if a hook has not been called yet, call it now
      if not result[parameters.qualifier..i] then
       self:callHook(parameters.qualifier..i, hooks, claim, result)
      end
    
      -- if there is output for this particular "qualifier(s)" command, then add it
      if result[parameters.qualifier..i] and result[parameters.qualifier..i][1] then
    
       -- if there is already some output, then add the separator
       if #out > 0 and sep then
        out[#out + 1] = sep
       end
    
       out = mergeArrays(out, result[parameters.qualifier..i])
      end
     end
    
     return out
    end
    
    -- level 1 hook
    function State:getReferences(claim)
     if self.conf.prefetchedRefs then
      -- return references that have been prefetched by isSourced
      return self.conf.prefetchedRefs
     end
    
     if claim.references then
      -- iterate through claim's reference statements to collect their values;
      -- return array with multiple value objects
      return self.conf.states[parameters.reference]:iterate(claim.references, {[parameters.general] = hookNames[parameters.reference][2], count = 1})  -- pass reference state with level 2 hook
     else
      return {}  -- return empty array
     end
    end
    
    -- level 2 hook
    function State:getReference(statement)
     local key, citeWeb, citeQ, label
     local params = {}
     local citeParams = {['web'] = {}, ['q'] = {}}
     local citeMismatch = {}
     local useCite = nil
     local useParams = nil
     local 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 any
    
     local version = 6  -- increment this each time the below logic is changed to avoid conflict errors
    
     if statement.snaks then
      -- don't include "imported from", which is added by a bot
      if statement.snaks[aliasesP.importedFrom] then
       statement.snaks[aliasesP.importedFrom] = nil
      end
      
      -- don't include "Wikimedia import URL"
      if statement.snaks[aliasesP.wikimediaImportURL] then
       statement.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] then
        statement.snaks[aliasesP.retrieved] = nil
       end
      end
    
      -- don't include "inferred from", which is added by a bot
      if statement.snaks[aliasesP.inferredFrom] then
       statement.snaks[aliasesP.inferredFrom] = nil
      end
    
      -- don't include "type of reference"
      if statement.snaks[aliasesP.typeOfReference] then
       statement.snaks[aliasesP.typeOfReference] = nil
      end
    
      -- don't include "image" to prevent littering
      if statement.snaks[aliasesP.image] then
       statement.snaks[aliasesP.image] = nil
      end
    
      -- don't include "language" if it is equal to the local one
      if self:getReferenceDetail(statement.snaks, aliasesP.language) == self.conf.langName then
       statement.snaks[aliasesP.language] = nil
      end
            
            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 parameters
      for i in pairs(statement.snaks) do
       label = ""
    
       -- multiple authors may be given
       if i == aliasesP.author or i == aliasesP.authorNameString then
        params[i] = self:getReferenceDetails(statement.snaks, i, false, self.linked, true)  -- link = true/false, anyLang = true
       elseif 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 = true
       else
        params[i] = {self:getReferenceDetail(statement.snaks, i, false, self.linked and (statement.snaks[i][1].datatype ~= 'url'), true)}  -- link = true/false, anyLang = true
       end
       
       if #params[i] == 0 then
        params[i] = nil
       else
        referenceEmpty = false
        
        if statement.snaks[i][1].datatype == 'external-id' then
         key = "external-id"
         label = self.conf:getLabel(i)
    
         if label ~= "" then
          label = label .. " "
         end
        else
         key = i
        end
    
        -- add the parameter to each matching type of citation
        for j in pairs(citeParams) do
         -- do so if there was no mismatch with a previous parameter
         if not citeMismatch[j] then
          -- check if this parameter is not mismatching itself
          if i18n['cite'][j][key] then
           -- continue if an option is available in the corresponding cite template
           if 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
                                    end
           end
          else
           citeMismatch[j] = true
          end
         end
        end
       end
      end
      
      -- use additional properties
      for i in pairs(additionalRefProperties) do
       for j in pairs(citeParams) do
        if not citeMismatch[j] and i18n["cite"][j][i] then
         citeParams[j][i18n["cite"][j][i]] = additionalRefProperties[i]
        else
         citeMismatch[j] = true
        end
       end
      end
    
      -- get title of general template for citing web references
      citeWeb = split(mw.wikibase.getSitelink(aliasesQ.citeWeb) or "", ":")[2]  -- split off namespace from front
    
      -- get title of template that expands stated-in references into citations
      citeQ = 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 present
      if 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 template
       citeParams['web'][i18n['cite']['web'][aliasesP.statedIn]] = self:getReferenceDetail(statement.snaks, aliasesP.statedIn, false, self.linked, true)
       useCite = citeWeb
       useParams = 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 present
      elseif citeQ and not citeMismatch['q'] and citeParams['q'][i18n['cite']['q'][aliasesP.statedIn]] then
       useCite = citeQ
       useParams = citeParams['q']
      end
    
      if useCite and useParams then
       -- if this module is being substituted then build a regular template call, otherwise expand the template
       if mw.isSubsting() then
        for i, v in pairs(useParams) do
         value = value .. "|" .. i .. "=" .. v
        end
    
        value = "{{" .. useCite .. value .. "}}"
       else
        value = 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 error
      elseif not referenceEmpty then
       value = "<span style=\"color:#dd3333\">" .. errorText("malformed-reference") .. "</span>"
      end
     
      if value ~= "" then
       value = {value}  -- create one value object
    
       if not self.rawValue then
        -- this should become a <ref> tag, so save the reference's hash for later
        value.refHash = "wikidata-" .. statement.hash .. "-v" .. (tonumber(i18n['cite']['version']) + version)
       end
    
       ref = {value}  -- wrap the value object in an array
      end
     end
    
     return ref
    end
    
    -- gets a detail of one particular type for a reference
    function State:getReferenceDetail(snaks, dType, raw, link, anyLang)
     local switchLang = anyLang
     local value = nil
    
     if not snaks[dType] then
      return nil
     end
    
     -- if anyLang, first try the local language and otherwise any language
     repeat
      for _, v in ipairs(snaks[dType]) do
       value = self.conf:getValue(v, raw, link, false, anyLang and not switchLang, false, true)  -- noSpecial = true
    
       if value then
        break
       end
      end
    
      if value or not anyLang then
       break
      end
    
      switchLang = not switchLang
     until anyLang and switchLang
    
     return value
    end
    
    -- gets the details of one particular type for a reference
    function State:getReferenceDetails(snaks, dType, raw, link, anyLang)
     local values = {}
    
     if not snaks[dType] then
      return {}
     end
    
     for _, v in ipairs(snaks[dType]) do
      -- if nil is returned then it will not be added to the table
      values[#values + 1] = self.conf:getValue(v, raw, link, false, anyLang, false, true)  -- noSpecial = true
     end
    
     return values
    end
    
    -- level 1 hook
    function State:getAlias(object)
     local value = object.value
     local title = nil
    
     if value and self.linked then
      if self.conf.entityID:sub(1,1) == "Q" then
       title = mw.wikibase.getSitelink(self.conf.entityID)
      elseif self.conf.entityID:sub(1,1) == "P" then
       title = "d:Property:" .. self.conf.entityID
      end
    
      if title then
       value = buildWikilink(title, value)
      end
     end
    
     value = {value}  -- create one value object
    
     if #value > 0 then
      return {value}  -- wrap the value object in an array and return it
     else
      return {}  -- return empty array if there was no value
     end
    end
    
    -- level 1 hook
    function State:getBadge(value)
     value = self.conf:getLabel(value, self.rawValue, self.linked, self.shortName)
    
     if value == "" then
      value = nil
     end
    
     value = {value}  -- create one value object
    
     if #value > 0 then
      return {value}  -- wrap the value object in an array and return it
     else
      return {}  -- return empty array if there was no value
     end
    end
    
    function 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 before
     if not result[param] and hooks[param] then
      valuesArray = self[hooks[param]](self, statement, param, result, hooks)  -- array with value objects
    
      -- add to the result
      if #valuesArray > 0 then
       result[param] = valuesArray
       result.count = result.count + 1
      else
       result[param] = {}  -- an empty array to indicate that we've tried this hook already
       return true  -- miss == true
      end
     end
    
     return false
    end
    
    -- iterate through claims, claim's qualifiers or claim's references to collect values
    function State:iterate(statements, hooks, matchHook)
     matchHook = matchHook or alwaysTrue
    
     local matches = false
     local rankPos = nil
     local result, gotRequired
    
     for _, 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 then
       result = {count = 0}  -- collection of arrays with value objects
    
       local function walk(formatTable)
        local miss
    
        for i2, v2 in pairs(formatTable.req) do
         -- call a hook, adding its return value to the result
         miss = self:callHook(i2, hooks, v, result)
    
         if miss then
          -- we miss a required value for this level, so return false
          return false
         end
    
         if result.count == hooks.count then
          -- we're done if all hooks have been called;
          -- returning at this point breaks the loop
          return true
         end
        end
    
        for _, v2 in ipairs(formatTable) do
         if result.count == hooks.count then
          -- we're done if all hooks have been called;
          -- returning at this point prevents further childs from being processed
          return true
         end
    
         if v2.child then
          walk(v2.child)
         end
        end
    
        return true
       end
       gotRequired = walk(self.parsedFormat)
    
       -- only append the result if we got values for all required parameters on the root level
       if gotRequired then
        -- if we have a rankPos (only with matchHook() for complete claims), then update the foundRank
        if rankPos and self.conf.foundRank > rankPos then
         self.conf.foundRank = rankPos
        end
    
        -- append the result
        self.results[#self.results + 1] = result
    
        -- break if we only need a single value
        if self.singleValue then
         break
        end
       end
      end
     end
    
     return self:out()
    end
    
    local function getEntityId(arg, eid, page, allowOmitPropPrefix, globalSiteId)
     local id = nil
     local prop = nil
    
     if arg then
      if arg:sub(1,1) == ":" then
       page = arg
       eid = nil
      elseif arg:sub(1,1):upper() == "Q" or arg:sub(1,9):lower() == "property:" or allowOmitPropPrefix then
       eid = arg
       page = nil
      else
       prop = arg
      end
     end
    
     if eid then
      if eid:sub(1,9):lower() == "property:" then
       id = replaceAlias(mw.text.trim(eid:sub(10)))
    
       if id:sub(1,1):upper() ~= "P" then
        id = ""
       end
      else
       id = replaceAlias(eid)
      end
     elseif page then
      if page:sub(1,1) == ":" then
       page = mw.text.trim(page:sub(2))
      end
    
      id = mw.wikibase.getEntityIdForTitle(page, globalSiteId) or ""
     end
    
     if not id then
      id = mw.wikibase.getEntityIdForCurrentPage() or ""
     end
    
     id = id:upper()
    
     if not mw.wikibase.isValidEntityId(id) then
      id = ""
     end
    
     return id, prop
    end
    
    local function nextArg(args)
     local arg = args[args.pointer]
    
     if arg then
      args.pointer = args.pointer + 1
      return mw.text.trim(arg)
     else
      return nil
     end
    end
    
    local function claimCommand(args, funcName)
     local cfg = Config:new()
     cfg:processFlagOrCommand(funcName)  -- process first command (== function name)
    
     local lastArg, parsedFormat, formatParams, claims, value
     local hooks = {count = 0}
    
     -- set the date if given;
     -- must come BEFORE processing the flags
     if args[p.args.date] then
      cfg.atDate = {parseDate(args[p.args.date])}
      cfg.periods = {false, true, false}  -- change default time constraint to 'current'
     end
    
     -- process flags and commands
     repeat
      lastArg = nextArg(args)
     until not cfg:processFlagOrCommand(lastArg)
    
     -- get the entity ID from either the positional argument, the eid argument or the page argument
     cfg.entityID, cfg.propertyID = getEntityId(lastArg, args[p.args.eid], args[p.args.page], false, args[p.args.globalSiteId])
    
     if cfg.entityID == "" then
      return ""  -- we cannot continue without a valid entity ID
     end
    
     cfg.entity = mw.wikibase.getEntity(cfg.entityID)
    
     if not cfg.propertyID then
      cfg.propertyID = nextArg(args)
     end
    
     cfg.propertyID = replaceAlias(cfg.propertyID)
    
     if not cfg.entity or not cfg.propertyID then
      return ""  -- we cannot continue without an entity or a property ID
     end
    
     cfg.propertyID = cfg.propertyID:upper()
    
     if not cfg.entity.claims or not cfg.entity.claims[cfg.propertyID] then
      return ""  -- there is no use to continue without any claims
     end
    
     claims = cfg.entity.claims[cfg.propertyID]
    
     if cfg.states.qualifiersCount > 0 then
      -- do further processing if "qualifier(s)" command was given
    
      if #args - args.pointer + 1 > cfg.states.qualifiersCount then
       -- claim ID or literal value has been given
    
       cfg.propertyValue = nextArg(args)
      end
    
      for i = 1, cfg.states.qualifiersCount do
       -- check if given qualifier ID is an alias and add it
       cfg.qualifierIDs[parameters.qualifier..i] = replaceAlias(nextArg(args) or ""):upper()
      end
     elseif cfg.states[parameters.reference] then
      -- do further processing if "reference(s)" command was given
    
      cfg.propertyValue = nextArg(args)
     end
    
     -- check for special property value 'somevalue' or 'novalue'
     if cfg.propertyValue then
      cfg.propertyValue = replaceSpecialChars(cfg.propertyValue)
    
      if cfg.propertyValue ~= "" and mw.text.trim(cfg.propertyValue) == "" then
       cfg.propertyValue = " "  -- single space represents 'somevalue', whereas empty string represents 'novalue'
      else
       cfg.propertyValue = mw.text.trim(cfg.propertyValue)
      end
     end
    
     -- parse the desired format, or choose an appropriate format
     if args["format"] then
      parsedFormat, formatParams = parseFormat(args["format"])
     elseif cfg.states.qualifiersCount > 0 then  -- "qualifier(s)" command given
      if cfg.states[parameters.property] then  -- "propert(y|ies)" command given
       parsedFormat, formatParams = parseFormat(formats.propertyWithQualifier)
      else
       parsedFormat, formatParams = parseFormat(formats.qualifier)
      end
     elseif cfg.states[parameters.property] then  -- "propert(y|ies)" command given
      parsedFormat, formatParams = parseFormat(formats.property)
     else  -- "reference(s)" command given
      parsedFormat, formatParams = parseFormat(formats.reference)
     end
    
     -- if a "qualifier(s)" command and no "propert(y|ies)" command has been given, make the movable separator a semicolon
     if cfg.states.qualifiersCount > 0 and not cfg.states[parameters.property] then
      cfg.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 then
      cfg.separators["sep"][1] = nil
     end
    
     -- if exactly one "qualifier(s)" command has been given, make "sep%q" point to "sep%q1" to make them equivalent
     if cfg.states.qualifiersCount == 1 then
      cfg.separators["sep"..parameters.qualifier] = cfg.separators["sep"..parameters.qualifier.."1"]
     end
    
     -- process overridden separator values;
     -- must come AFTER tweaking the default separators
     cfg: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 given
     for 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)] then
       hooks[i] = getHookName(i, 1)
       hooks.count = hooks.count + 1
      end
     end
    
     -- 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 given
     if formatParams[parameters.qualifier] and cfg.states.qualifiersCount > 0 then
      hooks[parameters.qualifier] = getHookName(parameters.qualifier, 1)
      hooks.count = hooks.count + 1
     end
    
     -- 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 hooks
     if not cfg.states[parameters.property] then
      cfg.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 then
       cfg.states[parameters.property].singleValue = true
      end
     end
    
     -- 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 hooks
     if cfg.sourcedOnly and not cfg.states[parameters.reference] then
      cfg:processFlagOrCommand(p.claimCommands.reference)  -- use singular "reference" to minimize overhead
     end
    
     -- set the parsed format and the separators (and optional punctuation mark);
     -- must come AFTER creating the additonal states
     cfg:setFormatAndSeparators(cfg.states[parameters.property], parsedFormat)
    
     -- process qualifier matching values, analogous to cfg.propertyValue
     for i, v in pairs(args) do
      i = tostring(i)
    
      if i:match('^[Pp]%d+$') or aliasesP[i] then
       v = replaceSpecialChars(v)
    
       -- check for special qualifier value 'somevalue'
       if v ~= "" and mw.text.trim(v) == "" then
        v = " "  -- single space represents 'somevalue'
       end
    
       cfg.qualifierIDsAndValues[replaceAlias(i):upper()] = v
      end
     end
    
     -- 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 values
     value = 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 Wikidata
     if cfg.editable and value ~= "" then
      value = value .. cfg:getEditIcon()
     end
    
     return value
    end
    
    local function generalCommand(args, funcName)
     local cfg = Config:new()
     cfg.curState = State:new(cfg)
    
     local lastArg
     local value = nil
    
     repeat
      lastArg = nextArg(args)
     until not cfg:processFlag(lastArg)
    
     -- get the entity ID from either the positional argument, the eid argument or the page argument
     cfg.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) then
      return ""  -- we cannot continue without an entity
     end
    
     -- serve according to the given command
     if funcName == p.generalCommands.label then
      value = cfg:getLabel(cfg.entityID, cfg.curState.rawValue, cfg.curState.linked, cfg.curState.shortName)
     elseif funcName == p.generalCommands.title then
      cfg.inSitelinks = true
    
      if cfg.entityID:sub(1,1) == "Q" then
       value = mw.wikibase.getSitelink(cfg.entityID)
      end
    
      if cfg.curState.linked and value then
       value = buildWikilink(value)
      end
     elseif funcName == p.generalCommands.description then
      value = mw.wikibase.getDescription(cfg.entityID)
     else
      local parsedFormat, formatParams
      local hooks = {count = 0}
    
      cfg.entity = mw.wikibase.getEntity(cfg.entityID)
    
      if funcName == p.generalCommands.alias or funcName == p.generalCommands.badge then
       cfg.curState.singleValue = true
      end
    
      if funcName == p.generalCommands.alias or funcName == p.generalCommands.aliases then
       if not cfg.entity.aliases or not cfg.entity.aliases[cfg.langCode] then
        return ""  -- there is no use to continue without any aliasses
       end
    
       local aliases = cfg.entity.aliases[cfg.langCode]
    
       -- parse the desired format, or parse the default aliases format
       if args["format"] then
        parsedFormat, formatParams = parseFormat(args["format"])
       else
        parsedFormat, formatParams = parseFormat(formats.alias)
       end
    
       -- process overridden separator values;
       -- must come AFTER tweaking the default separators
       cfg:processSeparators(args)
    
       -- define the hook that should be called (getAlias);
       -- only define the hook if the parameter ("%a") has been given
       if formatParams[parameters.alias] then
        hooks[parameters.alias] = getHookName(parameters.alias, 1)
        hooks.count = hooks.count + 1
       end
    
       -- set the parsed format and the separators (and optional punctuation mark)
       cfg:setFormatAndSeparators(cfg.curState, parsedFormat)
    
       -- iterate to collect values
       value = cfg:concatValues(cfg.curState:iterate(aliases, hooks))
      elseif funcName == p.generalCommands.badge or funcName == p.generalCommands.badges then
       if not cfg.entity.sitelinks or not cfg.entity.sitelinks[cfg.siteID] or not cfg.entity.sitelinks[cfg.siteID].badges then
        return ""  -- there is no use to continue without any badges
       end
    
       local badges = cfg.entity.sitelinks[cfg.siteID].badges
    
       cfg.inSitelinks = true
    
       -- parse the desired format, or parse the default aliases format
       if args["format"] then
        parsedFormat, formatParams = parseFormat(args["format"])
       else
        parsedFormat, formatParams = parseFormat(formats.badge)
       end
    
       -- process overridden separator values;
       -- must come AFTER tweaking the default separators
       cfg:processSeparators(args)
    
       -- define the hook that should be called (getBadge);
       -- only define the hook if the parameter ("%b") has been given
       if formatParams[parameters.badge] then
        hooks[parameters.badge] = getHookName(parameters.badge, 1)
        hooks.count = hooks.count + 1
       end
    
       -- set the parsed format and the separators (and optional punctuation mark)
       cfg:setFormatAndSeparators(cfg.curState, parsedFormat)
    
       -- iterate to collect values
       value = cfg:concatValues(cfg.curState:iterate(badges, hooks))
      end
     end
    
     value = value or ""
    
     if cfg.editable and value ~= "" then
      -- if desired, add a clickable icon that may be used to edit the returned value on Wikidata
      value = value .. cfg:getEditIcon()
     end
    
     return value
    end
    
    -- 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) do
      local function wikitextWrapper(frame)
       local args = copyTable(frame.args)
       args.pointer = 1
       loadI18n(aliasesP, frame)
       return commandFunc(args, commandName)
      end
      p[commandName] = wikitextWrapper
    
      local function luaWrapper(args)
       args = copyTable(args)
       args.pointer = 1
       loadI18n(aliasesP)
       return commandFunc(args, commandName)
      end
      p["_" .. commandName] = luaWrapper
     end
    end
    
    establishCommands(p.claimCommands, claimCommand)
    establishCommands(p.generalCommands, generalCommand)
    
    -- main function that is supposed to be used by wrapper templates
    function p.main(frame)
     if not mw.wikibase then return nil end
    
     local f, args
    
     loadI18n(aliasesP, frame)
    
     -- get the parent frame to take the arguments that were passed to the wrapper template
     frame = frame:getParent() or frame
    
     if not frame.args[1] then
      throwError("no-function-specified")
     end
    
     f = mw.text.trim(frame.args[1])
    
     if f == "main" then
      throwError("main-called-twice")
     end
    
     assert(p["_"..f], errorText('no-such-function', f))
    
     -- copy arguments from immutable to mutable table
     args = copyTable(frame.args)
    
     -- remove the function name from the list
     table.remove(args, 1)
    
     return p["_"..f](args)
    end
    
    return p
    

    Retrieved from "https://en.wikipedia.org/w/index.php?title=Module:Wd&oldid=1216656550"

    Categories: 
    Modules subject to page protection
    Wikidata modules
    Modules using data from Wikidata
    Hidden category: 
    Wikipedia template-protected modules
     



    This page was last edited on 1 April 2024, at 08:09 (UTC).

    Text is available under the Creative Commons Attribution-ShareAlike License 4.0; additional terms may apply. By using this site, you agree to the Terms of Use and Privacy Policy. Wikipedia® is a registered trademark of the Wikimedia Foundation, Inc., a non-profit organization.



    Privacy policy

    About Wikipedia

    Disclaimers

    Contact Wikipedia

    Code of Conduct

    Developers

    Statistics

    Cookie statement

    Mobile view



    Wikimedia Foundation
    Powered by MediaWiki