-- Original module located at :en:Module:Wd and :en:Module:Wd/i18n.  
require("strict")
local p = {}
local arg = ...
local i18n  
local function loadI18n(aliasesP, )
local title  
if then
-- current module invoked by page/template, get its title from
title = :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"
}  
local aliasesP = {
coord = "P625",
---
image = "P18",
author = "P50",
authorNameString = "P2093",
publisher = "P123",
importedFrom = "P143",
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"
}  
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, --
["punc"] = nil --
}  
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 "" .. label .. ""
end
end  
-- used to make .args mutable, to replace #.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(mw.ustring.gsub(dateStr:sub(ptr, i-1), "^\+(.+)$", "%1"), 10) -- remove '+' sign (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 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