Module:Size
From Neodyland Wiki
More actions
This documentation is transcluded from Module:Size/doc.
--[[
Module:Size (lightweight Neodyland version)
Displays 1D/2D/3D sizes with unit conversion between metric and imperial.
Wikidata-free: unit names are taken from the static Module:I18n/units dictionary.
]]
local p = {}
local yesno = require('Module:Yesno')
local langSwitch = require('Module:LangSwitch')
local units = require('Module:I18n/units')
-- unit list order (indices used in conversions)
-- 1..6 metric length: nm, um, mm, cm, m, km
-- 7..10 imperial length: in, ft, yd, mi
local unitList = { 'nm', 'um', 'mm', 'cm', 'm', 'km', 'in', 'ft', 'yd', 'mi' }
local unitType = { 'm', 'm', 'm', 'm', 'm', 'm', 'i', 'i', 'i', 'i' }
-- meters per unit
local unitMult = {
1e-9, -- nm
1e-6, -- um
1e-3, -- mm
1e-2, -- cm
1, -- m
1e3, -- km
0.0254, -- in
0.3048, -- ft
0.9144, -- yd
1609.344 -- mi
}
local dimOrder = { 'length', 'height', 'width', 'depth', 'thickness', 'diameter' }
local dimName = {
length = 'Length', height = 'Height', width = 'Width', depth = 'Depth',
thickness = 'Thickness', diameter = 'Diameter'
}
local function getUnitLabel(unit, lang)
local tbl = units[unit]
if tbl and tbl[lang] then return tbl[lang] end
if tbl then
-- fallback chain: en, then first entry
if tbl.en then return tbl.en end
for _, v in pairs(tbl) do return v end
end
return unit
end
local function formatNum(value, lang, precision)
-- keep precision via format string
local pat = '%.' .. tostring(precision) .. 'f'
local str = string.format(pat, value)
str = mw.ustring.gsub(str, "[,%.]0+$", "")
return str
end
local function niceNumber(v, iMin, iMax)
local s = 10
if v < s * unitMult[iMin] then return iMin end
for k = iMin, iMax - 1 do
if v >= s * unitMult[k] and v < s * unitMult[k + 1] then return k end
end
return iMax
end
local function unitConversion(val, unit, prec, lang)
-- find k1 (input unit index)
local k1
for i, u in ipairs(unitList) do
if u == unit then k1 = i; break end
end
if not k1 then return nil end
local valInM = val * unitMult[k1]
local k2
if unitType[k1] == 'm' then
k2 = niceNumber(valInM, 7, 10)
else
k2 = niceNumber(valInM, 1, 6)
end
local factor = unitMult[k1] / unitMult[k2]
local unit1 = getUnitLabel(unit, lang)
local unit2 = getUnitLabel(unitList[k2], lang)
return unit1, unit2, factor, unitType[k1]
end
local function oneDim(val, unit, prec, lang, withLabel)
local unit1, unit2, factor, system = unitConversion(val, unit, prec, lang)
if not unit1 then return '' end
local wordsep = mw.message.new('Word-separator'):inLanguage(lang):plain()
local numStr1 = formatNum(val, lang, prec) .. wordsep .. unit1
if (lang ~= 'en' and lang ~= 'en-US' and system == 'm') or system == '' then
return numStr1
end
local numStr2 = formatNum(val * factor, lang, prec)
local str = numStr1 .. wordsep .. '(' .. numStr2 .. wordsep .. unit2 .. ')'
str = mw.ustring.gsub(str, '(%d)%s(%p)', '%1%2')
return str
end
function p._size(args, unit, prec, lang)
if not prec then prec = 1; if unit == 'mm' then prec = 2 end end
local colon = mw.message.new('Colon-separator'):inLanguage(lang):plain()
local semicolon = mw.message.new('Semicolon-separator'):inLanguage(lang):plain()
local wordsep = mw.message.new('Word-separator'):inLanguage(lang):plain()
local results = {}
for _, field in ipairs(dimOrder) do
local val = args[field]
if val then
val = string.gsub(val, ',', '.')
val = tonumber(val)
if type(val) == 'number' and val == val then
local label = dimName[field]
local dimStr = label .. colon
local valStr = oneDim(val, unit, prec, lang)
table.insert(results, dimStr .. valStr)
end
end
end
return table.concat(results, semicolon)
end
function p._sizeOld(args, unit, prec, lang)
-- unnamed positional dimensions: {{Size|unit|12|98}}
if not prec then prec = 1; if unit == 'mm' then prec = 2 end end
local wordsep = mw.message.new('Word-separator'):inLanguage(lang):plain()
local semicolon = mw.message.new('Semicolon-separator'):inLanguage(lang):plain()
local results = {}
local vals = {}
for i = 1, 4 do
if args[i] then
local v = string.gsub(args[i], ',', '.')
v = tonumber(v)
if type(v) == 'number' and v == v then table.insert(vals, v) end
end
end
for _, v in ipairs(vals) do
table.insert(results, oneDim(v, unit, prec, lang))
end
return table.concat(results, wordsep .. '×' .. wordsep)
end
function p.size(frame)
local args = require('Module:Arguments').getArgs(frame)
local unit = args[1] or args.unit or args.units
if not unit then return '' end
unit = units.aliases[unit] or unit
-- normalize unit key
local ukey
for _, u in ipairs(unitList) do if u == unit then ukey = u; break end end
if not ukey then
-- check aliases
for k, v in pairs(units.aliases) do
if tostring(k):lower() == tostring(unit):lower() then ukey = v; break end
end
end
if not ukey then return '' end
unit = ukey
local lang = args.lang or mw.language.getContentLanguage().code
local prec = args.prec and tonumber(args.prec) or nil
-- positional unnamed args
local hasPos = args[1] or args[2] or args[3] or args[4]
if hasPos then
return p._sizeOld(args, unit, prec, lang)
end
return p._size(args, unit, prec, lang)
end
return p