Przejdź do zawartości

Moduł:Wikidane/format/quantity

Z Wikibooks, biblioteki wolnych podręczników.
 Dokumentacja modułu [zobacz] [edytuj] [historia] [odśwież]

Dedykowana uniwersalna wtyczka formatująca wartość cechy z wartością ilościową z opcjonalną jednostką.

Wtyczka obsługuje parametr format, w którym można wskazać identyfikator Wikidanych (Qnnnnn) określający jednostkę miary w jakiej ma być zaprezentowany wynik. Jeśli jest pusty to wyświetlana jest aktualna wartość wraz z jednostką.

Zobacz też

local i18n = mw.loadData("Moduł:Wikidane/data").quantityFormats
local units = mw.loadData("Moduł:Wikidane/data").quantityUnits

local function selectRoundCoefficients(value)
	local num = math.abs(value)
	if num > i18n.maximumAmount then
		return false, "", math.floor(num * i18n.maximumVarFactor)
	end

	for i, v in ipairs(i18n) do
		if num > v.amount then
			return v.factor, v.suffix, v.minvar
		end
	end

	return false, "", 0
end

local function formatVar(snak)
	local amount = tonumber(snak.datavalue.value.amount)
	local upperVar = snak.datavalue.value.upperBound and (tonumber(snak.datavalue.value.upperBound) - amount) or 0
	local lowerVar = snak.datavalue.value.lowerBound and (amount - tonumber(snak.datavalue.value.lowerBound)) or 0
	local lang = mw.getContentLanguage()
	if (upperVar == 0) and (lowerVar == 0) then
		return lang:formatNum(amount), amount
	elseif math.abs(upperVar - lowerVar) < ((upperVar + lowerVar) / 1000) then
		local var = math.max(upperVar, lowerVar)
		var = string.format("%f", var)
		if string.match(var, "%.") then
			var, _ = string.gsub(var, "%.", ",")
			var, _ = string.gsub(var, "0+$", "")
			var, _ = string.gsub(var, ",$", "")
		end
		
		return string.format(i18n.variance, lang:formatNum(amount), var), amount
	else
		return string.format(i18n.between, lang:formatNum(tonumber(snak.datavalue.value.lowerBound)), lang:formatNum(tonumber(snak.datavalue.value.upperBound))), tonumber(snak.datavalue.value.upperBound)
	end		
end

local function formatText(snak)
	local amount = tonumber(snak.datavalue.value.amount)
	local upperVar = snak.datavalue.value.upperBound and (tonumber(snak.datavalue.value.upperBound) - amount) or 0
	local lowerVar = snak.datavalue.value.lowerBound and (amount - tonumber(snak.datavalue.value.lowerBound)) or 0

	local div = false
	local suffix = ""
	local var = 0
	if (upperVar ~= 0) or (lowerVar ~= 0) then
		div, suffix, var = selectRoundCoefficients(amount)
	end
	
	local lang = mw.getContentLanguage()
	if (div == 1) or not div then
		if (upperVar == 0) and (lowerVar == 0) then
			return lang:formatNum(amount), amount
		elseif math.max(upperVar, lowerVar) <= var then
			return string.format(i18n.around, lang:formatNum(amount)), amount
		elseif upperVar == lowerVar then
			return string.format(i18n.variance, lang:formatNum(amount), lang:formatNum(upperVar)), amount
		else
			return string.format(i18n.between, lang:formatNum(tonumber(snak.datavalue.value.lowerBound)), lang:formatNum(tonumber(snak.datavalue.value.upperBound))), tonumber(snak.datavalue.value.upperBound)
		end		
	elseif div then
		if math.max(upperVar, lowerVar) <= var then
			local atxt = lang:formatNum(tonumber(string.format("%.2f", amount / div)))..suffix
			return string.format(i18n.around, atxt), amount / div
		elseif upperVar == lowerVar then
			local atxt = lang:formatNum(tonumber(string.format("%.2f", amount / div)))..suffix
			local vtxt = lang:formatNum(tonumber(string.format("%.2f", upperVar / div)))..suffix
			return string.format(i18n.variance, atxt, vtxt), amount / div
		else
			local ltxt = lang:formatNum(tonumber(string.format("%.2f", tonumber(snak.datavalue.value.lowerBound) / div)))..suffix
			local utxt = lang:formatNum(tonumber(string.format("%.2f", tonumber(snak.datavalue.value.upperBound) / div)))..suffix
			return string.format(i18n.between, ltxt, utxt), tonumber(snak.datavalue.value.lowerBound) / div
		end
	end
end

local function formatUnit(unitEntityId, options, value)
	local quantityUnits = units[unitEntityId]
	if type(quantityUnits) == "table" then
		return mw.getContentLanguage():convertPlural(value, quantityUnits)
	end
	
	local symbol = false
	local unitSymbols = mw.wikibase.getBestStatements(unitEntityId, "P5061")
	for _, v in ipairs(unitSymbols) do
		if (v.mainsnak.snaktype == "value") and (v.mainsnak.datatype == "monolingualtext") and (v.mainsnak.datavalue.value.language == "pl") then
			symbol = v.mainsnak.datavalue.value.text
			break
		end
	end
	
	if not symbol then
		for _, v in ipairs(unitSymbols) do
			if (v.mainsnak.snaktype == "value") and (v.mainsnak.datatype == "monolingualtext") and (v.mainsnak.datavalue.value.language == "en") then
				symbol = v.mainsnak.datavalue.value.text
				break
			end
		end
	end
	
	if not symbol then
		for _, s in ipairs(mw.wikibase.getBestStatements(unitEntityId, "P487")) do
			if (s.mainsnak.snaktype == "value") and (s.mainsnak.datatype == "string") and (s.mainsnak.datavalue.type == "string") then
				symbol = s.mainsnak.datavalue.value
				break
			end
		end
	end

	if not symbol then
		symbol = mw.wikibase.getLabel(unitEntityId)
	end
	
	local sitelink = options.linkItem and mw.wikibase.getSitelink(unitEntityId)
	if symbol and sitelink then
		return "[["..sitelink.."|"..symbol.."]]"
	elseif symbol then
		return symbol
	else
		return unitEntityId
	end
end

local autoUnitConverter = {
	-- temperatura
	Q42289   = function(value) return "Q25267", (value - 32) * 5/9 end, -- stopień Fahrenheita [°C]
	Q223061  = function(value) return "Q25267", value * 5/4 end, -- skala Réaumura [°C]
	Q488013  = function(value) return "Q25267", (value - 7.5) * 40/21 end, -- skala Rømera [°C]
	Q839449  = function(value) return "Q25267", 100 - value * 2/3 end, -- skala Delisle [°C]
	Q1133606 = function(value) return "Q25267", value * 100/33 end, -- Skala Newtona [°C]
	-- odległość
	Q3710    = function(value) return "Q11573", value * 0.3048006 end, -- stopa angielska [m]
	Q253276  = function(value) return "Q828224", value * 1.609344 end, -- mila [km]
	Q482798  = function(value) return "Q11573", value * 0.9144 end, -- jard [m]
	Q218593  = function(value) return "Q174728", value * 2.54 end, -- cal [cm]
	-- masa
	Q48013   = function(value) return "Q41803", value * 28.34952 end, -- uncja [g]
	Q100995  = function(value) return "Q11570", value * 0.4535923 end, -- funt [kg]
	-- prędkość
	Q748716  = function(value) return "Q182429", value * 0.3048006 end, -- stopy na sekundę [m/s]
	Q22673229= function(value) return "Q21014455", value * 0.3048006 end, -- stopy na minutę [m/min]
	Q6014364 = function(value) return "Q18413919", value * 2.54 end, -- cale na sekundę [cm/s]
	Q211256  = function(value) return "Q180154", value * 1.609344 end, -- mila na godzinę [km/h]
}

local function round(value)
	if not tonumber(value) or (value == 0) then
		return value
	end
	
	local abs = math.abs(value)
	local fix = value >= 0 and 0.5 or -0.5
	if abs >= 1000 then
		return math.floor(value + fix)
	elseif abs >= 100 then
		return math.floor(10*value + fix) / 10
	elseif abs >= 10 then
		return math.floor(100*value + fix) / 100
	elseif abs >= 1 then
		return math.floor(1000*value + fix) / 1000
	elseif abs >= 0.1 then
		return math.floor(10000*value + fix) / 10000
	else
		return value
	end
end

return {

scope = "snak",

options = {
	default = {
		linkItem = false,
	},
},

format = function(snak, options)
	local value, last
	if options.format == "tekst" then
		value, last = formatText(snak)
	else
		value, last = formatVar(snak)
	end

	if snak.datavalue.value.unit == "1" then
		return value
	end
	
	local unitEntityId = string.match(snak.datavalue.value.unit, "^http://www%.wikidata%.org/entity/(Q%d+)$")
	if not unitEntityId then
		mw.log("unrecognized unit: "..snak.datavalue.value.unit)
		return value.." ?"
	end
	
	local unit = formatUnit(unitEntityId, options, last)
	
	local builder = mw.html.create()
	
	local converter = autoUnitConverter[unitEntityId]
	if converter then
		local unitId2, amount2 = converter(snak.datavalue.value.amount)
		local _, upperBound = snak.datavalue.value.upperBound and converter(snak.datavalue.value.upperBound) or nil
		local _, lowerBound = snak.datavalue.value.upperBound and converter(snak.datavalue.value.lowerBound) or nil
		local v2, l2 = formatText( { datavalue = { value = { amount = round(amount2), upperBount = round(upperBound), lowerBound = round(lowerBound) } } } )
		local u2 = formatUnit(unitId2, options, last)
		
		builder:tag("span")
			:addClass("wd-auto-converted")
			:attr("title", value.." "..unit)
			:wikitext(v2, " ", u2)
	else
		builder:wikitext(value, " ", unit or "!")
	end

	return tostring(builder)
end,

}