local cat = wanted_category(text_code.all_categories[msg[3]]) or ''
local anchor = msg[4] or ''
local fmt = text_code.all_messages[msg.format or 'cvt_format'] or 'convert: bug'
title = title:gsub('"', '"')
return format(fmt, anchor, title, text, cat)
-- If enabled, add a warning that will be displayed after the convert result.
-- To reduce output noise, only the first warning is displayed.
if config.warnings or level < 0 then
if level <= (tonumber(config.warnings) or 1) then
if parms.warnings == nil then
if engscale then
local success, result = lookup(baseunit, opt_sp_us, 'no_combination', utable, fails, depth)
if not success then return false, result end if and not (result.offset or result.builtin or result.engscale) then
result.defkey = unitcode -- key to lookup default exception
result.engscale = engscale
return true
end
end
local function ntsh(num, debug)
-- Return html text to be used for a hidden sort key so that
-- the given number will be sorted in numeric order.
-- If debug == true, output is in a box (not hidden).
-- This implements Template:Ntsh (number table sorting, hidden).
num = num or 0
local result, style
if not valid_number(num) then
if num < 0 then
result = '1000000000000000000'
else
result = '9000000000000000000'
end
elseif num == 0 then
result = '5000000000000000000'
else
local mag = floor(log10(abs(num)) + 1e-14)
local prefix
if num > 0 then
prefix = 7000 + mag
else
prefix = 2999 - mag
num = num + 10^(mag+1)
end
result = format('%d', prefix) .. format('%015.0f', floor(num * 10^(14-mag)))
end
if debug then
style = 'border:1px solid'
else
style = 'display:none'
end
return '<span style="' .. style .. '">' .. result .. '</span>'
end
return name:sub(1, pos+1) .. name:sub(pos+2):gsub(' ', '-')
end
elseif name:sub(-1, -1) == ')' then
pos = name:find('(', 1, true)
if pos then
end
local function digit_grouperdigit_groups(parms, text, method, gaps) -- Return a numbered table to hold of groups of digits which can be joined with -- suitable separators (such as commas). left-to- Each group is separately translated to the right, in local language because -- gap separators include digits which should not be translated).
-- Parameter method is a number or nil:
-- 3 for 3-digit grouping(default), or -- 2 for 3-then-2 grouping(only for digits before decimal mark). local len_right local len_left = text:find('.', 1, true) if len_left then len_right = #text -len_left len_left = len_left - Parameter gaps is true to use <span1 else len_left = #text end local twos = method == 2 and len_left > gaps 5 local groups = collection(numsep ignored) local run = len_left local n if run < 4 or (run == 4 and parms.opt_comma5) then if parms.opt_gaps then n = run else n = #text end return {elseif twos then n = run % 2 == 0,and 1 or 2 else add n = function run % 3 == 0 and 3 or run % 3 end while run > 0 do groups:add(self, digitsn) self.n run = self.run - n + 1 self[self. n] = from_en(digitstwos and run > 3)and 2 or 3 end, if len_right then join if groups.n = function = 0 then groups:add(self, rhs0) end if parms.opt_gaps and len_right > 3 then local want4 = not parms.opt_gaps3 -- Concatenate in reverse order.true gives no gap before trailing single digit if gaps then local result isfirst = ''true for i run = 1, self.n - 1 len_right while run > 0 do result n = '<span style(want4 and run ="margin-left: 0.25em"= 4) and 4 or (run >' .. self3 and 3 or run) if isfirst then isfirst = false groups[igroups.n] = groups[groups.. '</span>' .. resultn] + 1 + n else groups:add(n)
end
return '<span stylerun ="whiterun -space: nowrap">' .. self[self.n] .. result .. from_en(rhs) .. '</span>' else local result = self[1] for i = 2, self.n do result = self[i] .. numsep .. result end return result .. from_en(rhs)
end
end,else step groups[groups.n] = 3,groups[groups.n] + 1 + len_right next_position = function (self, previous)end -- Return position of digit just before next group. end -- Digits are grouped from right-to-left (least significant first). local result pos = previous - self.step1 if method == 2 then for i, length in ipairs(groups) do self.step groups[i] = 2 end return from_en(result < 0text:sub(pos, pos + length - 1)) and 0 or result pos = pos + length end, }return groups
end
function with_separator(parms, text) -- for forward declaration above
-- Input text is a number in en digits and with optional '.' decimal mark. -- Return an equivalent of text, formatted for display:
-- with a custom decimal mark instead of '.', if wanted
-- with thousand separators inserted, if wanted
-- digits in local language
-- The given text is like '123' or '12345123.6789' or '112345.23e456789' -- (at one time e-notation could occur when processing an input value, -- but is now handled elsewhere for scientific notation).
-- The text has no sign (caller inserts that later, if necessary).
-- Separator is When using gaps, they are inserted only in before and after the integer part of the significanddecimal mark. -- (not after Separators are inserted only before the decimal mark, and not after 'e' or 'E'). if #text < 4 or parms.opt_nocomma or numsep == '' then
return from_en(text)
end
local last groups = digit_groups(parms, text:match('(, group_method)[.eE]') -- () returns position if last == nil parms.opt_gaps then last = #text else last = last - 1 -- index of last character before dot/e/E end if last groups.n < 4 or (last == 4 and parms.opt_comma5) 1 then return from_en(text)groups[1] or '' end local groups nowrap = digit_grouper(group_method, parms.opt_gaps)'<span style="white-space: nowrap">' local i gap = last while i > '<span style="margin-left: 0 do.25em">' local position close = groups:next_position(i)'</span>' return nowrap .. groups:add[1] .. gap .. table.concat(text:sub(position+1groups, i)close .. gap, 2, groups.n) i = position.. close .. close
end
return table.concat(groups:join(text:sub(last+1), numsep)
end
local fmtpower = '%s<span style="margin:0 .15em 0 .25em">×</span>%s<sup>%s</sup>'
local function with_exponent(parms, show, exponent)
-- Return wikitext to display the implied value in scientific notation.
-- Input uses en digits; output uses digits in local language.
return format(fmtpower, from_enwith_separator(parms, show), from_en('10'), use_minus(from_en(tostring(exponent))))
end
exponent = exponent,
sign = sign,
show = sign .. with_exponent(parms, significand, exponent-1),
is_scientific = true,
}
-- or return false, t where t is an error message table.
-- Input can use en digits or digits in local language and can
-- have one reference references at the end. Accepting a reference references is intended
-- for use in infoboxes with a field for a value passed to convert.
-- Parameter another = true if the expected value is not the first.
-- clean = cleaned text with any separators and sign removed
-- (en digits and '.' decimal mark)
-- show = text formatted for output, possibly with ref strip markermarkers
-- (digits in local language and custom decimal mark)
-- The resulting show:
-- '+' (if the input text used '+'), or is '' (if no sign in input).
text = strip(text or '')
local t, reference local pos = text:matchfind('^\127', 1, true) if pos then local before = text:sub(.*1, pos - 1) local remainder = text:sub(pos) local refs = {} while #remainder > 0 do local ref, spaces ref, spaces, remainder = remainder:match('^(\127UNIQ%x+[^\127]*%-ref%-%x+%-QINU\127)$(%s*)(.*)') if reference ref then -- found a single strip marker at end containing "- table.insert(refs, ref-") else refs = {} break end end if #refs > 0 then text = strip(tbefore) reference = table.concat(refs) end
end
local clean = to_en(text, parms)
-- that allows input like 2e6 to be spelled as "two million" which works
-- because the spell module converts '2e6' to '2000000' before spelling.
local function rounded(value, default) local precision = parms.input_precisionopt_ri if precision and 0 <= precision and precision <= 8 then
local fmt = '%.' .. format('%d', precision) .. 'f'
return fmt:format(tonumber(value ) + 2e-14) -- fudge for some common cases of bad rounding
end
return default
end
singular = (value == 1)
local significand, exponent = clean:match('^([%d.]+)[Ee]([+%-]?%d+)')
if significand then
show = with_exponent(parms, rounded(tonumber(significand, significand)) or significand, exponent)
scientific = true
else
show = with_separator(parms, rounded(value) or , clean))
end
show = propersign .. show
if parms.opt_spell_in then
show = spell_number(parms, 'in', propersign .. rounded(clean, clean)) or show
scientific = false
end
end
end
elseif en_name == 'stylein' or en_name == 'styleout' then
en_value = loc_value -- accept user text with no validation
else
en_value = text_code.en_option_value[en_name][loc_value]
if en_value and en_value:sub(-1) == '?' then
en_value = en_value:sub(1, -2)
add_warning(parms, -1, 'cvt_deprecated', loc_name .. '=' .. loc_value)
end
if en_value == nil then
if loc_value == '' then
add_warning(parms, 2, 'cvt_empty_option', loc_name)
else
-- loc_value can no longer be nil here add_warning(at one timeparms, that could occur -- with aliases like |sing=off|adj=on)1, 'cvt_unknown_option', but am retaining safety check. local text = loc_value and (loc_name .. '=' .. loc_value) or loc_name add_warning(parms, 1, 'cvt_unknown_option', text)
end
elseif en_value == '' then
elseif type(en_value) == 'string' and en_value:sub(1, 4) == 'opt_' then
for _, v in ipairs(split(en_value, ',')) do
local lhs, rhs = v:match('^(.-)=(.+)$') if rhs then parms[lhs] = tonumber(rhs) or rhs else parms[v] = true end
end
en_value = nil
else
add_warning(parms, 1, 'cvt_unknown_option', loc_name .. '=' .. loc_value)
end
end
if parms.adj then
if parms.adj:sub(1, 2) == 'ri' then
-- It is known that adj is 'riN' where N is a single digit, so precision is valid.
-- Only a single en digit is accepted.
parms.input_precision = tonumber(parms.adj:sub(-1))
parms.adj = nil
end
end
else
parms.abbr = 'out' -- default is to abbreviate output only (use symbol, not name)
end
if parms.opt_spell_out and not abbr_entered then
parms.abbr = 'off' -- should show unit name when spelling the output value
end
if parms.opt_flip then
parms.opt_values = true
end
local align parms.table_align = format('style="text-align: %s;"', parms.opt_table and 'right' or 'center') end if parms.table_align or parms.opt_sortable_on then parms.table_joins need_table_or_sort = { align .. '|', '\n|' .. align .. '|' }true
end
local disp_joins = text_code.disp_joins
-- Testing shows this function is successful for 96% of converts in articles,
-- and that on average it speeds up converts by 8%.
if parms.input_precision opt_ri or parms.opt_spell_in then return end
local clean = to_en(strip(parms[1] or ''), parms)
if #clean > 10 or not clean:match('^[0-9.]+$') then return end
end
return false, { 'cvt_bug_convert' } -- should never occur
end
local function user_style(parms, i)
-- Return text for a user-specified style for a table cell, or '' if none,
-- given i = 1 (input style) or 2 (output style).
local style = parms[(i == 1) and 'stylein' or 'styleout']
if style then
style = style:gsub('"', '')
if style ~= '' then
if style:sub(-1) ~= ';' then
style = style .. ';'
end
return style
end
end
return ''
end
local function make_table_or_sort(parms, invalue, info, in_current)
-- Set options to handle output for a table or a sort key, or both.
-- The text sort key is based on the value resulting from converting
-- the input to a fake base unit with scale = 1, and other properties
-- required for a conversion derived from the input unit.
local sortkey
if parms.opt_sortable_on then
local base = { -- a fake unit with enough fields for a valid convert
scale = 1,
invert = in_current.invert and 1,
iscomplex = in_current.iscomplex,
offset = in_current.offset and 0,
}
local outvalue, extra = convert(parms, invalue, info, in_current, base)
if extra then
outvalue = extra.outvalue
end
if not valid_number(outvalue) then
if outvalue < 0 then
sortkey = '1000000000000000000'
else
sortkey = '9000000000000000000'
end
elseif outvalue == 0 then
sortkey = '5000000000000000000'
else
local mag = floor(log10(abs(outvalue)) + 1e-14)
local prefix
if outvalue > 0 then
prefix = 7000 + mag
else
prefix = 2999 - mag
outvalue = outvalue + 10^(mag+1)
end
sortkey = format('%d', prefix) .. format('%015.0f', floor(outvalue * 10^(14-mag)))
end
end
if sortkey and (parms.opt_sortable_debug or not parms.table_align) then
parms.join_before = parms.opt_sortable_debug and
'<span style="border:1px solid">' .. sortkey .. '</span>' or
'<span style="display:none">' .. sortkey .. '</span>'
end
if parms.table_align then
local style = 'style="text-align:' .. parms.table_align .. ';'
local sort = sortkey and ' data-sort-value="' .. sortkey .. '"' or ''
local joins = {}
for i = 1, 2 do
joins[i] = (i == 1 and '' or '\n|') .. style .. user_style(parms, i) .. '"' .. sort .. '|'
end
parms.table_joins = joins
end
end
end
local outvalue, extra = convert(parms, invalue, info, in_current, out_current)
if parms.need_table_or_sort then
parms.need_table_or_sort = nil -- process using first input value only
make_table_or_sort(parms, invalue, info, in_current)
end
if extra then
if not outvalue then return false, extra end
precision = parms.precision
if not precision then
local sigfig = if parms.sigfig if sigfig then show, exponent = make_sigfig(outvalue, parms.sigfig) elseif parms.opt_round5 or parms.opt_round25 opt_round then local n = parms.opt_round5 and 5 or 25opt_round
show = format('%.0f', floor((outvalue / n) + 0.5) * n)
else
local i = t.multiple and table_len(combo) or 1
ucode = combo[i]
end
else
-- Try for an automatically generated combination.
local item = ucode:match('^(.-)%+') or ucode:match('^(%S+)%s')
if all_units[item] then
return item
end
end
end
info.decorated = true
end if engscale then local inout = unit_table.inout local abbr = parms.abbr if abbr == 'on' or abbr == inout then info.show = info.show ..
'<span style="margin-left:0.2em">×<span style="margin-left:0.1em">' ..
from_en('10') ..
'</span></span><s style="display:none">^</s><sup>' ..
from_en(tostring(engscale.exponent)) .. '</sup>'
else
local number_id
local lk = parms.lk
if lk == 'on' or lk == inout then
number_id = make_link(engscale.link, engscale[1])
else
local number_id local lk = parms.lk if lk == 'on' or lk == inout then number_id = make_link(engscale.link, engscale[1]) else number_id = engscale[1] end -- WP:NUMERAL recommends " " in values like "12 million". info.show = info.show .. (parms.opt_adjectival and '-' or ' ') .. number_id
end
-- WP:NUMERAL recommends " " in values like "12 million".
info.show = info.show .. (parms.opt_adjectival and '-' or ' ') .. number_id
end
end if prefix then info.show = prefix .. info.show end
end
end
local out_unit = parms.out_unit
if out_unit == nil or out_unit == '' then
if bad_input_mcode or parms.opt_input_unit_only then
bad_output = ''
else
end
local flipped = parms.opt_flip and not bad_input_mcode
local sortkey
if parms.opt_sortable_in then
sortkey = ntsh(invalue1, parms.opt_sortable_debug)
end
local parts = {}
for part = 1, 2 do
parts[part] = process_input(parms, in_unit_table)
elseif bad_output then
if bad_output ~= '' then parts[part] = (bad_output == '') and '' or message(bad_output) end
else
local outputs = {}
if not success then return false, item end
table.insert(outputs, item)
end
if parms.opt_sortable_out then
local value
local info = out_first and out_first.valinfo
if info then
info = info[1]
value = info.raw_absvalue
if value and info.sign == MINUS then
value = -value
end
end
sortkey = ntsh(value, parms.opt_sortable_debug)
end
if parms.opt_input_unit_only then
parts[part] = ''
else
local sep if = parms.table_joins then sep = and parms.table_joins[2] .. (sortkey or '') else sep = parms.join_between end
parts[part] = table.concat(outputs, sep)
end
end
end
if sortkey parms.join_before then for i, v in ipairs(parts) do if i [1] == 1 or parms.table_joins then join_before .. parts[i1] = sortkey .. v end end
end
local wikitext