Logo Voyage

Module:RouteSection Voyage Tips and guide

You can check the original Wikivoyage article Here

Documentation for this module may be created at Module:RouteSection/doc

local p = {}

-- ─────────────────────────────────────────────────────────────────────────────
-- Helpers
-- ─────────────────────────────────────────────────────────────────────────────

local unitMap = {
	["Q828224"] = { symbol = "km",  type = "length"   }, -- kilometre
	["Q11573"]  = { symbol = "m",   type = "length"   }, -- metre
	["Q253276"] = { symbol = "mi",  type = "length"   }, -- mile
	["Q3710"]   = { symbol = "ft",  type = "length"   }, -- foot
	["Q25235"]  = { symbol = "hr",  type = "duration" }, -- hour
	["Q7727"]   = { symbol = "min", type = "duration" }, -- minute
}

local function trim(s) return mw.text.trim(s or "") end

-- Prefer a "preferred" statement if present; otherwise first non-deprecated.
local function pickStmt(statements)
	if not statements then return nil end
	for _, s in ipairs(statements) do
		if s.rank == "preferred" then return s end
	end
	for _, s in ipairs(statements) do
		if s.rank ~= "deprecated" then return s end
	end
end

local function getSnakValue(statement)
	local snak = statement and statement.mainsnak
	if not snak or snak.snaktype ~= "value" then return nil end
	return snak.datavalue and snak.datavalue.value or nil
end

local function getLabel(id, lang)
	if not id or id == "" then return "" end
	return mw.wikibase.getLabelByLang(id, lang:getCode())
		or mw.wikibase.getLabel(id) or ""
end

local function itemId(entity, pid)
	if not entity or not entity.claims then return nil end
	local v = getSnakValue(pickStmt(entity.claims[pid]))
	return v and v.id or nil
end

local function quantity(entity, pid)
	if not entity or not entity.claims then return nil end
	local v = getSnakValue(pickStmt(entity.claims[pid]))
	if not v or not v.amount then return nil end
	local n = tonumber(v.amount); if not n then return nil end
	local unitQID = v.unit and v.unit:match("Q%d+") or ""
	local info = unitMap[unitQID]
	return {
		amount  = n,
		symbol  = info and info.symbol or "",
		type    = info and info.type   or "unknown",
		unitQID = unitQID,
	}
end

local function convertAmount(amount, fromSymbol, toSymbol)
	if not amount or not fromSymbol or not toSymbol or fromSymbol == toSymbol then
		return amount
	end
	if fromSymbol == "m"  and toSymbol == "ft" then return amount * 3.280839895 end
	if fromSymbol == "ft" and toSymbol == "m"  then return amount / 3.280839895 end
	return nil -- only convert m↔ft
end

local function fmtQuantity(frame, q, doConvert)
	if not q then return nil end
	if doConvert and q.type == "length" then
		return frame:preprocess(string.format("{{convert|%s|%s|abbr=on}}", q.amount, q.symbol))
	end
	local unit = q.symbol ~= "" and (" " .. q.symbol) or ""
	return mw.language.getContentLanguage():formatNum(q.amount) .. unit
end

local function firstNonEmpty(args, keys)
	for _, k in ipairs(keys) do
		local v = trim(args[k])
		if v ~= "" then return v end
	end
	return ""
end

local function truthy(s)
	s = trim(s):lower()
	return s == "yes" or s == "true" or s == "on" or s == "1"
end

local function compute(frame)
	local args = frame.args
	local lang = mw.language.getContentLanguage()
	local convertFlag = truthy(args.convert)

	-- Only use Wikidata if an explicit, non-empty ID is provided
	local wikidataId = trim(args.wikidata)
	local entity = (wikidataId ~= "" and mw.wikibase.getEntityObject(wikidataId)) or nil

	-- Names ----------------------------------------------------------
	local name = firstNonEmpty(args, {"name"})
	if name == "" and entity then
		name = getLabel(entity.id, lang) or ""
	end

	-- Endpoints ------------------------------------------------------
	local start_id = entity and itemId(entity, "P1427") or nil -- start point
	local dest_id  = entity and itemId(entity, "P1444") or nil -- end point

	local from_str = firstNonEmpty(args, {"from"})
	if from_str == "" and start_id then from_str = getLabel(start_id, lang) end

	local to_str = firstNonEmpty(args, {"to"})
	if to_str == "" and dest_id then to_str = getLabel(dest_id, lang) end

	-- Quantities -----------------------------------------------------
	local length_str = firstNonEmpty(args, {"length"})
	if length_str == "" and entity then
		length_str = fmtQuantity(frame, quantity(entity, "P2043"), convertFlag) or ""
	end

	local duration_str = firstNonEmpty(args, {"duration"})
	if duration_str == "" and entity then
		duration_str = fmtQuantity(frame, quantity(entity, "P2047"), false) or ""
	end

	local ascent_str, ascent_data
	ascent_str = firstNonEmpty(args, {"ascent"})
	if ascent_str == "" and entity then
		ascent_data = quantity(entity, "P7297")
		ascent_str  = fmtQuantity(frame, ascent_data, convertFlag) or ""
	end

	-- Descent (derived) ---------------------------------------------
	local function toAscentUnits(q)
		if not q or not ascent_data or q.type ~= "length" then return nil end
		if q.symbol == ascent_data.symbol then return q.amount end
		return convertAmount(q.amount, q.symbol, ascent_data.symbol)
	end

	local descent_str = ""
	if ascent_data and start_id and dest_id then
		local start_entity = mw.wikibase.getEntityObject(start_id)
		local dest_entity  = mw.wikibase.getEntityObject(dest_id)
		local start_elev = start_entity and quantity(start_entity, "P2044") or nil
		local dest_elev  = dest_entity  and quantity(dest_entity,  "P2044") or nil
		local s, d = toAscentUnits(start_elev), toAscentUnits(dest_elev)
		if s and d then
			local net_gain = d - s
			local descent_amount = ascent_data.amount - net_gain
			if descent_amount < 0 then descent_amount = 0 end
			descent_str = fmtQuantity(frame,
				{ amount = descent_amount, symbol = ascent_data.symbol, type = "length" },
				convertFlag) or ""
		end
	end

	return {
		name        = name,
		from        = from_str,
		to          = to_str,
		length      = length_str,
		duration    = duration_str,
		ascent      = ascent_str,
		descent     = descent_str,
		wikidata    = wikidataId
	}
end

function p.show(frame)
	local data = compute(frame)
	return frame:expandTemplate{
		title = 'Template:RouteSection/table',
		args  = data
	}
end

return p


Discover



Powered by GetYourGuide