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