মডিউল:Convert: সংশোধিত সংস্করণের মধ্যে পার্থক্য

বিষয়বস্তু বিয়োগ হয়েছে বিষয়বস্তু যোগ হয়েছে
Bellayet (আলোচনা | অবদান)
update http://en.wikipedia.org/w/index.php?title=Module:Convert&oldid=559340741
 
Johnuniq (আলোচনা | অবদান)
current version from en:Module:Convert (no visible difference here)
৭ নং লাইন:
local format = string.format
local log10 = math.log10
local ustring = mw.ustring
local ulen = ustring.len
 
-- mw.ustring has two bugs: following works around one of them; see "2013-07-05" for second.
-- Bug has been reported, and the fix will be deployed, possibly before August 2013.
-- local usub = ustring.sub
-- When fix is deployed, remove following usub function, and uncomment above usub variable.
local function usub(s, i, j)
return (j and i > j) and '' or ustring.sub(s, i, j)
end
 
-- Configuration options to keep magic values in one location.
-- The conversion data and message text are defined in separate modules.
-- To allow easy comparison between "require" and "loadData", a config option
-- can be set to control which is used.
local numdot, numsep -- each must be a single byte for simple regex search/replace
local maxsigfig, warnings
local default_exceptions, link_exceptions, units
local SIprefixes, all_categories, all_messages, customary_units, disp_joins
local en_option_value, eng_scales, local_option_name, range_aliases, range_types
local group_method = 3 -- code for how many digits are in a group
local plural_suffix = 's' -- only other useful value is probably '' to disable plural unit names
local from_en_table -- to translate an output string of en digits to local language
local to_en_table -- to translate an input string of digits in local language to en
 
local function boolean(text)
১২ ⟶ ৩৬ নং লাইন:
if text then
text = text:lower()
if text == '1' or text == 'y' or text == 'yes' or text == 'on' or text == 'true' then
return true
end
১৮ ⟶ ৪২ নং লাইন:
end
 
local function from_en(text)
-- Configuration options to keep magic values in one location.
-- Input is a string representing a number in en digits with '.' decimal mark,
local numdot, numsep, maxsigfig, warnings
-- without digit grouping (which is done just after calling this).
-- The conversion data and message text are defined in separate modules.
-- Return the translation of the string with numdot and digits in local language.
-- To allow easy comparison between "require" and "loadData", a config option
if numdot ~= '.' then
-- can be set to control which is used.
text = text:gsub('%.', numdot)
local SIprefixes, default_exceptions, link_exceptions, units
end
local all_categories, all_messages, customary_units, disp_joins, en_option_value
if from_en_table then
local eng_scales, local_option_name, range_aliases, range_types
text = text:gsub('%d', from_en_table)
end
return text
end
 
local function to_en(text)
-- Input is a string representing a number in the local language with
-- an optional numdot decimal mark and numsep digit grouping.
-- Return the translation of the string with '.' mark and en digits,
-- and no separators (they have to be removed here to handle cases like
-- numsep = '.' and numdot = ',' with input "1.234.567,8").
if numsep ~= '' then
text = text:gsub('[' .. numsep .. ']', '') -- use '[x]' in case x is '.'
end
if numdot ~= '.' then
text = text:gsub('[' .. numdot .. ']', '.')
end
if to_en_table then
text = ustring.gsub(text, '%d', to_en_table)
end
return text
end
 
local spell_module -- name of module that can spell numbers
local speller -- function from that module to handle spelling (set if spelling is wanted)
 
local function set_config(frame)
৩১ ⟶ ৮০ নং লাইন:
local args = frame.args
numdot = args.numdot or '.' -- decimal mark before fractional digits
numsep = args.numsep or ',' -- thousandsgroup separator for numbers (',', '.', '')
maxsigfig = args.maxsigfig or 14 -- maximum number of significant figures
warnings = boolean(args.warnings) -- true if want warnings for invalid options
-- Scribunto sets the global variable 'mw'.
-- A testing program can set the global variable 'is_test_run'.
local convertdatadata_module, converttexttext_module, data_moduledata_code, text_moduletext_code
if is_test_run then
data_module = "convertdata"
text_module = "converttext"
spell_module = "ConvertNumeric"
else
data_module = "Module:Convert/data"
text_module = "Module:Convert/text"
spell_module = "Module:ConvertNumeric"
end
if args.use_require then
convertdatadata_code = require(data_module)
converttexttext_code = require(text_module)
else
convertdatadata_code = mw.loadData(data_module)
converttexttext_code = mw.loadData(text_module)
end
default_exceptions = data_code.default_exceptions
link_exceptions = data_code.link_exceptions
units = data_code.units
SIprefixes = text_code.SIprefixes
all_categories = text_code.all_categories
all_messages = text_code.all_messages
customary_units = text_code.customary_units
disp_joins = text_code.disp_joins
en_option_value = text_code.en_option_value
eng_scales = text_code.eng_scales
local_option_name = text_code.local_option_name
range_aliases = text_code.range_aliases
range_types = text_code.range_types
-- LATER: Simplify following by using a translation table if it is defined,
-- without needing to check the current wiki's language. Am using this more
-- generic treatment while testing.
local lang = mw.language.getContentLanguage()
local translation = text_code.translation_table[lang.code]
if translation then
if translation.group then
group_method = translation.group
end
if translation.plural_suffix then
plural_suffix = translation.plural_suffix
end
from_en_table = translation.from_en
local use_workaround = true
if use_workaround then
-- 2013-07-05 workaround bug by making a copy of the required table.
-- mw.ustring.gsub fails with a table (to_en_table) as the replacement,
-- if the table is accessed via mw.loadData.
local source = translation.to_en
if source then
to_en_table = {}
for k, v in pairs(source) do
to_en_table[k] = v
end
end
else
to_en_table = translation.to_en
end
end
end
SIprefixes = convertdata.SIprefixes
 
default_exceptions = convertdata.default_exceptions
local function collection()
link_exceptions = convertdata.link_exceptions
-- Return a table to hold items.
units = convertdata.units
return {
all_categories = converttext.all_categories
n = 0,
all_messages = converttext.all_messages
add = function (self, item)
customary_units = converttext.customary_units
self.n = self.n + 1
disp_joins = converttext.disp_joins
self[self.n] = item
en_option_value = converttext.en_option_value
end,
eng_scales = converttext.eng_scales
}
local_option_name = converttext.local_option_name
end
range_aliases = converttext.range_aliases
 
range_types = converttext.range_types
local function split(text, delimiter)
-- Return a numbered table with fields from splitting text.
-- The delimiter is used in a regex without escaping (for example, '.' would fail).
-- Each field has any leading/trailing whitespace removed.
local t = {}
text = text .. delimiter -- to get last item
for item in text:gmatch('%s*(.-)%s*' .. delimiter) do
table.insert(t, item)
end
return t
end
 
৯৮ ⟶ ২০১ নং লাইন:
end
return 'Convert internal error: unknown message'
end
 
local function add_warning(parms, mcode, text)
-- If enabled, add a warning that will be displayed after the convert result.
-- Currently, only the first warning is displayed.
if warnings then
if parms.warnings == nil then
parms.warnings = message({ mcode, text })
end
end
end
 
local function spell_number(parms, number, numerator, denominator)
-- Return result of spelling (number, numerator, denominator), or
-- return nil if spelling is not available or not supported for given text.
-- Input should use one of these forms:
-- number numerator denominator example output
-- ------ --------- ----------- --------------
-- string nil nil one point two three
-- string string string one and two thirds
-- nil string string two thirds
if not speller then
local function get_speller(module)
return require(module).spell_number
end
local success
success, speller = pcall(get_speller, spell_module)
if not success or type(speller) ~= 'function' then
add_warning(parms, 'cvt_spell_unavailable')
return nil
end
end
local case = parms.opt_spell_upper
parms.opt_spell_upper = nil -- only uppercase first number in a multiple unit
local sp = not parms.opt_sp_us
local adj = parms.opt_adjectival
return speller(number, numerator, denominator, case, sp, adj)
end
 
১৬২ ⟶ ৩০২ নং লাইন:
local unit_mt = {
-- Metatable to get missing values for a unit that does not accept SI prefixes,
-- or a for a unit that accepts prefixes but where no prefix was used.
-- In the latter case, and before use, fields symbol, name1, name1_us
-- must be set from _symbol, _name1, _name1_us respectively.
১৭০ ⟶ ৩১০ নং লাইন:
value = self.symbol
elseif key == 'name2' then
value = self.name1 .. 's'plural_suffix
elseif key == 'name1_us' then
value = self.name1
if not rawget(self, 'name2_us') then
-- If name1_us is 'foot', do not make name2_us by appending 's'plural_suffix.
self.name2_us = self.name2
end
১৮০ ⟶ ৩২০ নং লাইন:
local raw1_us = rawget(self, 'name1_us')
if raw1_us then
value = raw1_us .. 's'plural_suffix
else
value = self.name2
২০৯ ⟶ ৩৪৯ নং লাইন:
local pos = rawget(self, 'prefix_position') or 1
value = self._name1
value = value:subusub(value, 1, pos - 1) .. self.si_name .. value:subusub(value, pos)
elseif key == 'name2' then
value = self.name1 .. 's'plural_suffix
elseif key == 'name1_us' then
value = rawget(self, '_name1_us')
if value then
local pos = rawget(self, 'prefix_position') or 1
value = value:subusub(value, 1, pos - 1) .. self.si_name .. value:subusub(value, pos)
else
value = self.name1
২২২ ⟶ ৩৬২ নং লাইন:
elseif key == 'name2_us' then
if rawget(self, '_name1_us') then
value = self.name1_us .. 's'plural_suffix
else
value = self.name2
৩৬৭ ⟶ ৫০৭ নং লাইন:
-- Look for an SI prefix; should never occur with an alias.
-- Check for longer prefix first ('dam' is decametre).
--local Microprefix = usub(µ)unitcode, is two bytes in utf-81, so is found with plen = 2.)
local prefix = unitcode:sub(1, plen)
local si = SIprefixes[prefix]
if si then
local t = units[unitcode:subusub(unitcode, plen+1)]
if t and t.prefixes then
local result = shallow_copy(t)
৩৯২ ⟶ ৫৩১ নং লাইন:
-- and not if the unit is a combination or multiple,
-- and not if the unit has an offset or is a built-in.
-- Only en digits are accepted.
local exponent, baseunit = unitcode:match('^e(%d+)(.*)')
if exponent then
৫০৯ ⟶ ৬৪৯ নং লাইন:
end
return text
end
 
local function digit_grouper(method, gaps)
-- Return a table to hold groups of digits which can be joined with
-- suitable separators (such as commas).
-- Each group is separately translated to the local language because the
-- separators may include '.' characters which should not be translated.
-- Parameter method is a number or nil:
-- 3 for 3-digit grouping, or
-- 2 for 3-then-2 grouping.
-- Parameter gaps is true to use <span> gaps (numsep ignored).
return {
n = 0,
add = function (self, digits)
self.n = self.n + 1
self[self.n] = from_en(digits)
end,
join = function (self, rhs)
-- Concatenate in reverse order.
if gaps then
local result = ''
for i = 1, self.n - 1 do
result = '<span style="margin-left: 0.25em">' .. self[i] .. '</span>' .. result
end
return '<span style="white-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,
step = 3,
next_position = function (self, previous)
-- Return position of digit just before next group.
-- Digits are grouped from right-to-left (least significant first).
local result = previous - self.step
if method == 2 then
self.step = 2 -- may need more (3, 2, 2, 3, 2, 2, ...) in some languages
end
return (result < 0) and 0 or result
end,
}
end
 
local function with_separator(parms, text)
-- ReturnInput text withis thousanda separatorsnumber in en digits and with inserted,'.' ifdecimal wantedmark.
-- 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 '12345.6789' or '1.23e45'
-- (e notation can only occur when processing an input value).
-- The text has no sign (caller inserts that later, if necessary).
-- Separator is inserted only in the integer part of the significand
-- (not after numdotthe decimal mark, and not after 'e' or 'E').
-- Four-digit integer parts have a separator (like '1,234').
if parms.opt_nocomma or numsep == '' then
return from_en(text)
end
local last = text:match('()[' .. numdot .. 'eE]') -- () returns position
if last == nil then
last = #text
৫২৮ ⟶ ৭১৫ নং লাইন:
last = last - 1 -- index of last character before dot/e/E
end
if last >< 4 or (last == 4 and parms.opt_comma5) then
localreturn groups = {}from_en(text)
local first = last % 3
if first > 0 then
table.insert(groups, text:sub(1, first))
end
first = first + 1
while first < last do
table.insert(groups, text:sub(first, first+2))
first = first + 3
end
return table.concat(groups, numsep) .. text:sub(last+1)
end
local groups = digit_grouper(group_method, parms.opt_gaps)
return text
local i = last
while i > 0 do
local position = groups:next_position(i)
groups:add(text:sub(position+1, i))
i = position
end
return groups:join(text:sub(last+1))
end
 
-- Input values can use values like 1.23e12, but are never displayed
-- using exponentscientific notation like 1.23×10¹².
-- Very small or very large output values use exponentscientific notation.
-- Use format(fmtpower, significand, '10', exponent) where each arg is a string.
local fmtpower = '%s<span style="margin:0 .15em 0 .25em">×</span>10%s<sup>%s</sup>'
 
local function with_exponent(show, exponent)
-- Return wikitext to display the implied value in exponentscientific notation.
-- Input uses en digits; output uses digits in local language.
if #show > 1 then
show = show:sub(1, 1) .. numdot'.' .. show:sub(2)
end
return format(fmtpower, from_en(show), from_en('10'), use_minus(from_en(tostring(exponent))))
end
 
৫৯৫ ⟶ ৭৮০ নং লাইন:
 
local function format_number(parms, show, exponent, isnegative)
-- Parameter show is a number in en digits and with '.' decimal mark.
-- Return t where t is a table with fields:
-- show = wikitext formatted to display implied value
-- (digits in local language)
-- is_scientific = true if show uses scientific notation
-- clean = unformatted show (possibly adjusted and with inserted numdot'.')
-- (en digits)
-- sign = '' or MINUS
-- exponent = exponent (possibly adjusted)
৬১৬ ⟶ ৮০৪ নং লাইন:
--
-- The formatted result:
-- * Is for an output value and is spelled if wanted and possible.
-- * Includes a Unicode minus if isnegative.
-- * HasUses numsepa insertedcustom wheredecimal necessarymark, if wanted.
-- * UsesHas scientificdigits notationgrouped forwhere verynecessary, smallif or large valueswanted.
-- * Uses scientific notation for very small or large values
-- (which forces output to not be spelled).
-- * Has no more than maxsigfig significant digits
-- (same as old template and {{#expr}}).
৬২৪ ⟶ ৮১৫ নং লাইন:
local maxlen = maxsigfig
if exponent == nil then
local integer, dot, fraction = show:match('^(%d*)([' %.. numdot .. ']?)(.*)')
if #integer >= 10 then
show = integer .. fraction
৬৩২ ⟶ ৮২৩ নং লাইন:
if #figs == 0 then
if #zeros > maxlen then
show = '0.' .. numdot .. zeros:sub(1, maxlen)
end
elseif #zeros >= 4 then
৬৩৮ ⟶ ৮২৯ নং লাইন:
exponent = -#zeros
elseif #figs > maxlen then
show = '0.' .. numdot .. zeros .. figs:sub(1, maxlen)
end
else
৬৫৮ ⟶ ৮৪৯ নং লাইন:
sign = sign,
show = sign .. with_exponent(show, exponent-1),
is_scientific = true },
}
end
if exponent >= #show then
show = show .. string.rep('0', exponent - #show) -- result has no dot
elseif exponent <= 0 then
show = '0.' .. numdot .. string.rep('0', -exponent) .. show
else
show = show:sub(1, exponent) .. numdot'.' .. show:sub(exponent+1)
end
end
if isnegative and show:match('^0.?0*$') then
sign = '' -- don't show minus if result is negative but rounds to zero
end
local formatted_show = sign .. with_separator(parms, show)
if parms.opt_spell_out then
formatted_show = spell_number(parms, sign .. show) or formatted_show
end
return {
clean = show,
sign = sign,
show = sign .. with_separator(parmsformatted_show, show) }
}
end
 
-- Fraction output format (like old template).
-- 2013-07-20 Trying new styles proposed at [[Template talk:Convert]].
-- frac1: sign, numerator, denominator
local fracfmt = {
-- frac2: wholenumber, sign, numerator, denominator
{ -- Like {{frac}} (fraction slash).
local frac1 = '<span style="white-space:nowrap">%s<sup>%s</sup>&frasl;<sub>%s</sub></span>'
-- 1/2 : sign, numerator, denominator
local frac2 = '<span class="frac nowrap">%s<s style="display:none">%s</s><sup>%s</sup>&frasl;<sub>%s</sub></span>'
-- 1+2/3 : signed_wholenumber, numerator, denominator
'<span class="frac nowrap">%s<sup>%s</sup>&frasl;<sub>%s</sub></span>',
'<span class="frac nowrap">%s<sup> %s</sup>&frasl;<sub>%s</sub></span>',
},
{ -- Like {{sfrac}} (fraction horizontal bar).
-- 1//2 : sign, numerator, denominator (sign should probably be before the fraction, but then it can wrap, and html is already too long)
-- 1+2//3 : signed_wholenumber, numerator, denominator
'<span class="sfrac nowrap" style="display:inline-block; vertical-align:-0.5em; font-size:85%%; text-align:center;"><span style="display:block; line-height:1em; padding:0 0.1em;">%s%s</span><span style="display:none;">/</span><span style="display:block; line-height:1em; padding:0 0.1em; border-top:1px solid;">%s</span></span>',
'<span class="sfrac nowrap">%s<span style="display:none;">&nbsp;</span><span style="display:inline-block; vertical-align:-0.5em; font-size:85%%; text-align:center;"><span style="display:block; line-height:1em; padding:0 0.1em;">%s</span><span style="display:none;">/</span><span style="display:block; line-height:1em; padding:0 0.1em; border-top:1px solid;">%s</span></span></span>',
},
{ -- Like old {{convert}} template.
-- 1///2 : sign, numerator, denominator
-- 1+2///3: signed_wholenumber, sign, numerator, denominator
'<span style="white-space:nowrap">%s<sup>%s</sup>&frasl;<sub>%s</sub></span>',
'<span class="frac nowrap">%s<s style="display:none">%s</s><sup>%s</sup>&frasl;<sub>%s</sub></span>',
},
}
 
local function extract_fraction(parms, text, negative)
-- If text represents a fraction, return value, show, spelled where
-- value is a number and(value showof isthe afraction in argument string.text)
-- show is a string (formatted text for display of an input value,
-- and is spelled if wanted and possible)
-- spelled is true if show was spelled
-- Otherwise, return nil.
-- Input uses en digits and '.' decimal mark (input has been translated).
-- Output uses digits in local language and custom decimal mark, if any.
--
-- In the following, '(3/8)' represents the wikitext required to
৭০১ ⟶ ৯২০ নং লাইন:
-- (which may be negative) are also accepted (like old template).
-- Template interprets '1.23e+2+12/24' as '123(12/24)' = 123.5!
local lhs, negfrac, rhs, numstr, numerator, denstr, denominator, wholestr, whole, value
local lhs, slash, denstr = text:match('^%s*([^/]-)%s*(/+)%s*(.-)%s*$')
local denominator = tonumber(denstr)
if denominator == nil then return nil end
local wholestr, negfrac, rhs = lhs:match('^%s*(.-[^eE])%s*([+-])%s*(.-)%s*$')
if wholestr == nil or wholestr == '' then
wholestr = nil
৭১৬ ⟶ ৯৩৫ নং লাইন:
end
negfrac = (negfrac == '-')
local numerator = tonumber(numstr)
if numerator == nil then return nil end
-- Spelling of silly inputs like "-2+3/8" or "2+3/+8" (mixed or excess signs) is not supported.
local do_spell
if negative == negfrac or wholestr == nil then
value = whole + numerator / denominator
do_spell = parms.opt_spell_in
if do_spell then
if not (numstr:match('^%d') and denstr:match('^%d')) then -- if either has a sign
do_spell = false
end
end
else
value = whole - numerator / denominator
numstr = change_sign(numstr)
do_spell = false
end
if not valid_number(value) then
৭২৯ ⟶ ৯৫৭ নং লাইন:
numstr = use_minus(numstr)
denstr = use_minus(denstr)
local style = #slash -- kludge: 1, 2, or 3 slashes can be used to select style
if style > 3 then style = 3 end
local wikitext
if wholestr then
local sign = negative and MINUS or '+'
if negative then
wholestr = change_sign(wholestr)
end
local fmt = fracfmt[style][2]
wikitext = format(frac2, use_minus(wholestr), sign, numstr, denstr)
if style < 3 then
wikitext = format(fmt, use_minus(from_en(wholestr)), from_en(numstr), from_en(denstr))
else
local sign = negative and MINUS or '+'
wikitext = format(fmt, use_minus(from_en(wholestr)), sign, from_en(numstr), from_en(denstr))
end
else
local sign = negative and MINUS or ''
wikitext = format(frac1fracfmt[style][1], sign, from_en(numstr), from_en(denstr))
end
returnif value,do_spell wikitextthen
local numsign = (wholestr or not negative) and '' or '-'
wikitext = spell_number(parms, wholestr, numsign .. numstr, denstr) or wikitext
end
return value, wikitext, do_spell
end
 
local function extract_number(parms, text, another, no_fraction)
local missing = { 'cvt_no_num', 'cvt_no_num2' }
local invalid = { 'cvt_bad_num', 'cvt_bad_num2' }
 
local function extract_number(parms, text, which, no_fraction)
-- Return true, info if can extract a number from text,
-- where info is a table with the result,
-- or return false, t where t is an error message table.
-- Input can use en digits or digits in local language.
-- Parameter 'which' (1 or 2) selects which input value is being
-- processedParameter (toanother select= true if the appropriateexpected errorvalue message,is ifnot the needed)first.
-- Before processing, the input text is cleaned:
-- * Any thousand separators (valid or not) are removed.
৭৬২ ⟶ ৯৯৮ নং লাইন:
-- = false if value is -1 (like old template)
-- clean = cleaned text with any separators and sign removed
-- (en digits and '.' decimal mark)
-- show = text formatted for output
-- (digits in local language and custom decimal mark)
-- For show:
-- *The Valueresulting is rounded, if wanted.show:
-- * ThousandIs separatorsfor arean inserted,input value and is spelled if wanted and possible.
-- * Has a rounded value, if wanted.
-- * Has digits grouped where necessary, if wanted.
-- * If negative, a Unicode minus is used; otherwise the sign is
-- '+' (if the input text used '+'), or is '' (if no sign in input).
text = strip(text or '')
local clean = to_en(text)
if text == nil or text == '' then return false, { missing[which] } end
localif clean, sign== '' then
return false, { another and 'cvt_no_num2' or 'cvt_no_num' }
if numsep == '' then
clean = text
else
clean = text:gsub('[' .. numsep .. ']', '') -- use '[x]' in case x is '.'
end
local isnegative, propersign = false, '' -- most common case
-- Remove any sign character (assuming a number starts with '.' or a digit).
local singular, show
sign, clean = clean:match('^%s*([^ .%d]*)%s*(.*)')
if sign == nil or clean == nil then
return false, { missing[which] } -- should never occur
end
local propersign, isnegative
if sign == MINUS or sign == '-' or sign == '&minus;' then
propersign = MINUS
isnegative = true
elseif sign == '+' then
propersign = '+'
isnegative = false
elseif sign == '' then
propersign = ''
isnegative = false
else
return false, { invalid[which], text }
end
local show, singular
local value = tonumber(clean)
if value == nil then
iflocal notsign no_fraction= thenclean:sub(1, 1)
if sign == '+' value,or showsign == extract_fraction(clean,'-' isnegative)then
propersign = (sign == '+') and '+' or MINUS
clean = clean:sub(2)
end
if value < 0 then
isnegative = true
value = -value
end
else
local valstr
for _, prefix in ipairs({ '-', MINUS, '&minus;' }) do
-- Including '-' means inputs like '- 2' (with space) are accepted as -2.
-- It also sets isnegative in case input is a fraction like '-2-3/4'.
local plen = #prefix
if clean:sub(1, plen) == prefix then
valstr = clean:sub(plen + 1)
break
end
end
if valstr then
isnegative = true
propersign = MINUS
clean = valstr
value = tonumber(clean)
end
if value == nil then
returnlocal false, { invalid[which], text }spelled
if not no_fraction then
value, show, spelled = extract_fraction(parms, clean, isnegative)
end
if value == nil then
return false, { 'cvt_bad_num', text }
end
if spelled and value <= 1 then
singular = true -- for example, "one half mile" (singular unit)
else
singular = false -- any numeric fraction (even with value 1) is regarded as plural
end
end
singular = false -- any fraction (even with value 1) is regarded as plural
end
if not valid_number(value) then -- for example, "1e310" overflows
৮১৯ ⟶ ১,০৭১ নং লাইন:
end
show = propersign .. with_separator(parms, show)
if parms.opt_spell_in then
show = spell_number(parms, propersign .. clean) or show
end
end
if isnegative and (value ~= 0) then
৮২৭ ⟶ ১,০৮২ নং লাইন:
singular = singular,
clean = clean,
show = show,
}
end
 
local function require_integerget_number(text, invalid)
-- Return truev, nf where n = integer equivalent to given text,:
-- or return false,v t= wherenil t(text is annot errora message table.number)
-- or
-- Input should be the text for a simple integer (no separators, no Unicode minus,
-- v = value of text (text is a number)
-- limited size). Using regex avoids irritations with input like '-0.000001'.
if-- text == nilf then= returntrue false,if {value 'cvt_no_num'is }an endinteger
-- Input can use en digits or digits in local language,
if #text > 9 or text:match('^-?%d+$') == nil then
-- but no return falseseparators, {no invalidUnicode minus, textand no }fraction.
if text then
local number = tonumber(to_en(text))
if number then
local integer, fraction = math.modf(number)
return number, (fraction == 0)
end
end
return true, tonumber(text)
end
 
৮৫৩ ⟶ ১,১১৩ নং লাইন:
-- p1 is text to insert before the input unit
-- p2 is text to insert before the output unit
-- p1 or p2 may be nil to mean "no preunit"
-- p1 or p2 may be nil to mean "no preunit"
-- Using '+ ' gives output like "5+ feet" (no preceding space).
৯২৬ ⟶ ১,১৮৫ নং লাইন:
end
return before .. rtext .. after
end
 
local function add_warning(parms, mcode, text)
-- If enabled, add a warning that will be displayed after the convert result.
-- Currently, only the first warning is displayed.
if warnings then
if parms.warnings == nil then
parms.warnings = message({ mcode, text })
end
end
end
 
৯৬২ ⟶ ১,২১১ নং লাইন:
success, subunit = lookup(subcode, parms.opt_sp_us, 'no_combination')
if not success then return false, subunit end -- should never occur
success, subinfo = extract_number(parms, parms[iparm], 1)
if not success then return false, subinfo end
iparm = iparm + 2
১,০২৪ ⟶ ১,২৭৩ নং লাইন:
en_value = nil
elseif en_value:sub(1, 4) == 'opt_' then
parms[for _, v in ipairs(split(en_value], =',')) truedo
parms[v] = true
end
en_value = nil
end
১,০৩৪ ⟶ ১,২৮৫ নং লাইন:
if parms.adj:sub(1, 2) == 'ri' then
-- It is known that adj is 'ri1' or 'ri2' or 'ri3', so precision is valid.
-- Only en digits are accepted.
parms.input_precision = tonumber(parms.adj:sub(-1))
parms.adj = nil
end
end
if parms.disp then
if parms.disp == 'special_flip5' then
parms.opt_round5 = true
parms.opt_flip = true
parms.disp = nil
end
end
১,০৪৯ ⟶ ১,২৯৪ নং লাইন:
else
parms.abbr = 'out' -- default is to abbreviate output only (use symbol, not name)
end
local function swap_in_out(option)
local value = parms[option]
if value == 'in' then
parms[option] = 'out'
elseif value == 'out' then
parms[option] = 'in'
end
end
if parms.opt_flip then
if parms.abbr == swap_in_out('inabbr' then)
parms.abbr = swap_in_out('outlk')
elseifif parms.abbr == 'out'opt_spell_in then
-- For simplicity, and because it does not appear to be needed,
parms.abbr = 'in'
-- user cannot set the option to spell the output.
end
if parms.lkopt_spell_in == 'in' thennil
parms.lkopt_spell_out = 'out'true
elseif parms.lk == 'out' then
parms.lk = 'in'
end
end
১,০৬৮ ⟶ ১,৩১৯ নং লাইন:
local align = format('align="%s"', parms.opt_table and 'right' or 'center')
parms.table_joins = { align .. '|', '\n|' .. align .. '|' }
end
if parms.opt_lang_en then
from_en_table = nil
end
end
 
local function get_values(parms)
-- If successful, update parms and return true, v, i where
-- v = table of input values
-- i = index to next entry in parms after those processed here
-- or return false, t where t is an error message table.
local valinfo = collection() -- numbered table of input values
local range = collection() -- numbered table of range items (having, for example, 2 range items requires 3 input values)
local had_nocomma -- true if removed "nocomma" kludge from second parameter (like "tonocomma")
local parm2 = strip(parms[2])
if parm2 and parm2:sub(-7, -1) == 'nocomma' then
parms[2] = strip(parm2:sub(1, -8))
parms.opt_nocomma = true
had_nocomma = true
end
local i = 1
while true do
local success, info = extract_number(parms, parms[i], i > 1) -- need to set parms.opt_nocomma before calling this
if not success then return false, info end
i = i + 1
valinfo:add(info)
local next = strip(parms[i])
local range_item = range_types[next] or range_types[range_aliases[next]]
if not range_item then
break
end
i = i + 1
range:add(range_item)
parms.is_range_x = (type(range_item) == 'table') and range_item.is_range_x or nil
end
-- TODO Should limit the number of valinfo/range items!
if range.n > 0 then
parms.range = range
elseif had_nocomma then
return { 'cvt_unknown', parm2 }
end
return true, valinfo, i
end
 
১,০৮১ ⟶ ১,৩৭৩ নং লাইন:
-- whitespace entered in the template, and whitespace is used by some
-- parameters (example: the numbered parameters associated with "disp=x").
local success, info1, info2
local parms = {} -- arguments passed to template
for k, v in pairs(pframe.args) do
১,০৮৭ ⟶ ১,৩৭৮ নং লাইন:
end
translate_parms(parms)
local rangesuccess, valinfo, i = get_values(parms)
if not success then return false, valinfo end
local next = strip(parms[2])
local iin_unit = 3strip(parms[i])
ifi next= theni + 1
range = range_types[next] or range_types[range_aliases[next]]
if range == nil and next:sub(-7, -1) == 'nocomma' then
local base = strip(next:sub(1, -8))
range = range_types[base] or range_types[range_aliases[base]]
if range then
parms.opt_nocomma = true
end
end
end
success, info1 = extract_number(parms, parms[1], 1) -- need to set parms.opt_nocomma before calling this
if not success then return false, info1 end
local in_unit
if range == nil then
in_unit = next
else
parms.range = range
parms.is_range_x = range.is_range_x
success, info2 = extract_number(parms, parms[3], 2)
if not success then return false, info2 end
in_unit = strip(parms[4])
i = 5
end
local success, in_unit_table = lookup(in_unit, parms.opt_sp_us, 'no_combination')
if not success then return false, in_unit_table end
১,১২৬ ⟶ ১,৩৯৫ নং লাইন:
end
end
in_unit_table.valinfo = { info1, info2 } -- info2 is nil if no rangevalinfo
in_unit_table.inout = 'in' -- this is an input unit
if not parms.range then
local success, inext, composite_unit = get_composite(parms, i, info1valinfo[1].value, in_unit_table)
if not success then return false, inext end
if composite_unit then
১,১৪১ ⟶ ১,৪১০ নং লাইন:
-- Could put more code in this function to get any output unit and check for
-- an altitude following that unit.
local success, info = extract_number(parms, parms[i], 1false, true)
if success then
i = i + 1
১,১৪৭ ⟶ ১,৪১৬ নং লাইন:
end
end
local next = strip(parms[i])
i = i + 1
local precision, is_bad_precision
local function set_precision(text)
if tonumber(next) then
precisionlocal number, is_integer = nextget_number(text)
if number then
else
if is_integer then
precision = number
else
precision = text
is_bad_precision = true
end
return true -- text was used for precision, good or bad
end
end
if not set_precision(next) then
parms.out_unit = next
next =if set_precision(strip(parms[i])) then
if tonumber(next) then
i = i + 1
precision = next
end
end
১,১৯৯ ⟶ ১,৪৭৬ নং লাইন:
end
if precision == nil then
if tonumberset_precision(strip(parms[i])) then
precision = strip(parms[i])
i = i + 1
end
end
if is_bad_precision then
return false, { 'cvt_bad_prec', precision }
end
parms.precision = precision
local sigfig = parms.sigfig
if sigfig then
local number, is_integer = get_number(sigfig)
if not number or not is_integer or number <= 0 then
return false, { 'cvt_bad_sigfig', sigfig }
end
parms.sigfig = number
end
return true, parms, in_unit_table
end
১,২২৫ ⟶ ১,৫১২ নং লাইন:
-- Count digits after decimal mark, handling cases like '12.345e6'.
local exponent
local integer, dot, fraction, expstr = inclean:match('^(%d*)([' %.. numdot .. ']?)(%d*)(.*)')
local e = expstr:sub(1, 1)
local boost = 0 -- can increase default precision
১,৩৪৩ ⟶ ১,৬৩০ নং লাইন:
local outvalue = (integer + 2.5 * fraction) * (inscale / outscale)
local inch_value = 4 * integer + 10 * fraction -- equivalent number of inches
local fractionfracstr = inclean:match('[' %.. numdot .. '](.*)') or ''
local fmt
if fractionfracstr == '' then
fmt = '%.0f'
else
fmt = '%.' .. format('%d', #fractionfracstr - 1) .. 'f'
end
return true, {
১,৩৬৩ ⟶ ১,৬৫০ নং লাইন:
local function cvtround(parms, info, in_current, out_current)
-- Return true, t where t is a table with the conversion results; fields:
-- show = rounded, formatted string fromwith the result of converting value in info,
-- using the rounding specified in parms.
-- singular = true if result is positive, and (after rounding)
১,৩৭০ ⟶ ১,৬৫৭ নং লাইন:
-- or return true, nil if no value specified;
-- or return false, t where t is an error message table.
-- Input info.clean uses en digits (it has been translated, if necessary).
-- This code combines convert/round because some rounding requires
-- Output show uses en or non-en digits as appropriate, or can be spelled.
-- knowledge of what we are converting.
local invalue, inclean, show, exponent, singular
if info then
১,৩৮১ ⟶ ১,৬৬৮ নং লাইন:
if out_current.builtin == 'hand' then
-- Convert to hands, then convert the fractional part to inches.
-- LATER: Code is not correct when output is spelled (but that's very rare).
local dummy_unit_table = { scale = out_current.scale }
local success, outinfo = cvtround(parms, info, in_current, dummy_unit_table)
if not success then return false, outinfo end
local fmt
local fraction = (outinfo.show):match('[' .. numdot .. '](.*)') or '' -- outinfo.show is in local language
if fraction == '' then
if not outinfo.use_default_precision then
১,৩৯২ ⟶ ১,৬৮০ নং লাইন:
fmt = '%.0f'
else
fmt = '%.' .. format('%d', #ulen(fraction) - 1) .. 'f'
end
local hands, inches = math.modf(tonumber(outinfo.raw_absvalue))
inches = format(fmt, inches * 4)
if inches:sub(1, 1) == '4' then
১,৪০৩ ⟶ ১,৬৯১ নং লাইন:
end
end
if inches:sub(2, 2) == numdot'.' then
inches = inches:sub(1, 1) .. inches:sub(3)
end
১,৪০৯ ⟶ ১,৬৯৭ নং লাইন:
sign = outinfo.sign,
singular = outinfo.singular,
show = outinfo.sign .. with_separator(parms, format('%d', hands)) .. '.'numdot .. from_en(inches)
}
end
১,৪২৯ ⟶ ১,৭১৭ নং লাইন:
local success, use_default_precision
local precision = parms.precision
if not precision then
local sigfig = parms.sigfig
local sigfig = parms.sigfig
if precision then
if sigfig then
success, precision = require_integer(precision, 'cvt_bad_prec')
show, exponent = make_sigfig(outvalue, sigfig)
if not success then return false, precision end
elseif sigfigparms.opt_round5 then
show = format('%.0f', floor((outvalue / 5) + 0.5) * 5)
success, sigfig = require_integer(sigfig, 'cvt_bad_sigfig')
else
if not success then return false, sigfig end
if sigfig <= 0 thenuse_default_precision = true
precision = default_precision(invalue, inclean, outvalue, in_current, out_current, extra)
return false, { 'cvt_sigfig_pos', parms.sigfig }
end
show, exponent = make_sigfig(outvalue, sigfig)
elseif parms.opt_round5 then
show = format('%.0f', floor((outvalue / 5) + 0.5) * 5)
else
use_default_precision = true
precision = default_precision(invalue, inclean, outvalue, in_current, out_current, extra)
end
if precision then
১,৫০৩ ⟶ ১,৭৮৫ নং লাইন:
-- 'v' is replaced with value
-- 9 is any number (as defined by Lua tonumber)
-- only en digits are accepted
-- '<' can also be '<=' or '>' or '>='
-- In addition, the following form is supported:
১,৫৫১ ⟶ ১,৮৩৪ নং লাইন:
-- evaluates 'v < 120' as a boolean with result
-- 'smallsuffix' if (value < 120), or 'bigsuffix' otherwise.
-- Input must use en digits and '.' decimal mark.
local default = default_exceptions[unit_table.defkey or unit_table.symbol] or unit_table.default
if default == nil then
১,৫৫৮ ⟶ ১,৮৪২ নং লাইন:
return true, default
end
local t = {}split(default, '!')
default = default .. '!' -- to get last item
for item in default:gmatch('%s*(.-)%s*!') do
table.insert(t, item) -- split on '!', removing leading/trailing whitespace
end
if #t == 3 or #t == 4 then
local success, result = pcall(evaluate_condition, value, t[1])
১,৫৯৪ ⟶ ১,৮৭৪ নং লাইন:
end
linked_pages[link_key] = true
-- Following only works for language en, but it should be safe on other wikis,
-- and overhead of doing it generally does not seem worthwhile.
local l = link:sub(1, 1):lower() .. link:sub(2)
if link == id or l == id then
১,৬৮১ ⟶ ১,৯৬৩ নং লাইন:
local customary = customary_units[i]
if customary then
-- LATER: This works for language en only, but it's esoteric so ignore for now.
local pertext
if id:sub(1, 1) == '/' then
১,৮২২ ⟶ ২,১০৫ নং লাইন:
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 result = prefix .. valinfo[1].show
if range then
-- For simplicity and because more not needed, handle one range item only.
local prefix2 = make_id(parms, 2, first_unit) .. '&nbsp;'
result = range_text(range[1], want_name, parms, result, prefix2 .. valinfo[2].show)
end
return preunit .. result
১,৯৬৩ ⟶ ২,২৪৯ নং লাইন:
local valinfo = first_unit.valinfo
if range then
localif sep1range.n == first_unit.sep1 then
-- Like {{convert|1|x|2|ft}} (one range item; two values).
if mos then
decorate_value(parms,-- in_current,Do 1)what old template did.
decorate_value(parms,local in_current,sep1 2)= first_unit.sep
resultif =mos valinfo[1].show .. sep1 .. id1then
elseif parms.is_range_x and not want_name then
if abbr == 'in' or abbr == 'on' then
decorate_value(parms, in_current, 1)
decorate_value(parms, in_current, 2)
result = valinfo[1].show .. sep1 .. id1
elseif parms.is_range_x and not want_name then
if abbr == 'in' or abbr == 'on' then
decorate_value(parms, in_current, 1)
end
decorate_value(parms, in_current, 2)
result = valinfo[1].show .. sep1 .. id1
else
if abbr == 'in' or abbr == 'on' then
decorate_value(parms, in_current, 1)
end
decorate_value(parms, in_current, 2)
result = valinfo[1].show
end
decorate_valueresult = range_text(range[1], want_name, parms, in_currentresult, valinfo[2].show)
result = valinfo[1].show .. sep1 .. id1
else
if-- abbrLike =={{convert|1|x|2|x|3|ft}} 'in'(two or abbrmore ==range 'on'items): thensimplify.
decorate_value(parms, in_current, 1)
end
decorate_value(parms, in_current, 2)
result = valinfo[1].show
for i = 1, range.n do
decorate_value(parms, in_current, i+1)
result = range_text(range[i], want_name, parms, result, valinfo[i+1].show)
end
end
result = range_text(range, want_name, parms, result, valinfo[2].show)
else
decorate_value(parms, first_unit, 1)
২,০১২ ⟶ ২,৩১০ নং লাইন:
local result = prefix .. valinfo[1].show
if range then
-- For simplicity and because more not needed, handle one range item only.
result = range_text(range, want_name, parms, result, prefix .. valinfo[2].show)
result = range_text(range[1], want_name, parms, result, prefix .. valinfo[2].show)
end
return preunit .. result
২,০২৭ ⟶ ২,৩২৬ নং লাইন:
local valinfo = out_current.valinfo
if range then
localif sep1range.n == out_current.sep1 then
local abbrsep1 = parmsout_current.abbrsep
if parms.is_range_x and not want_namelocal thenabbr = parms.abbr
if abbrparms.is_range_x ==and 'out'not or abbr == 'on'want_name then
decorate_value(parms,if out_current,abbr 1)== 'out' or abbr == 'on' then
decorate_value(parms, out_current, 1)
end
decorate_value(parms, out_current, 2)
result = valinfo[1].show .. sep1 .. id1
else
if abbr == 'out' or abbr == 'on' then
decorate_value(parms, out_current, 1)
end
decorate_value(parms, out_current, 2)
result = valinfo[1].show
end
decorate_valueresult = range_text(range[1], want_name, parms, out_currentresult, valinfo[2].show)
result = valinfo[1].show .. sep1 .. id1
else
if-- abbrLike =={{convert|1|x|2|x|3|ft}} 'out'(two or abbrmore ==range 'on'items): thensimplify.
decorate_value(parms, out_current, 1)
end
decorate_value(parms, out_current, 2)
result = valinfo[1].show
for i = 1, range.n do
decorate_value(parms, out_current, i+1)
result = range_text(range[i], want_name, parms, result, valinfo[i+1].show)
end
end
result = range_text(range, want_name, parms, result, valinfo[2].show)
else
decorate_value(parms, out_current, 1)
২,০৫৭ ⟶ ২,৩৬৬ নং লাইন:
-- for a single output (which is not a combination or a multiple);
-- or return false, t where t is an error message table.
out_unit_table.valinfo = collection()
local success, info1, info2
local valinforange = in_unit_tableparms.valinforange
for i = 1, (range and (range.n + 1) or 1) do
success, info1 = cvtround(parms, valinfo[1], in_unit_table, out_unit_table)
local success, info = cvtround(parms, in_unit_table.valinfo[i], in_unit_table, out_unit_table)
if not success then return false, info1 end
if not success then return false, info end
success, info2 = cvtround(parms, valinfo[2], in_unit_table, out_unit_table)
out_unit_table.valinfo:add(info)
if not success then return false, info2 end
end
out_unit_table.valinfo = { info1, info2 }
return true, process_one_output(parms, out_unit_table)
end
২,১০৩ ⟶ ২,৪১২ নং লাইন:
if not success then return false, outinfo end
sign = outinfo.sign
local fraction = (outinfo.show):match('[' .. numdot .. '](.*)') or '' -- outinfo.show is in local language
fmt = '%.' .. #ulen(fraction) .. 'f' -- to reproduce precision
if fraction == '' then
outvalue = floor(outinfo.raw_absvalue + 0.5) -- keep all integer digits of least significant unit
২,১২৮ ⟶ ২,৪৩৭ নং লাইন:
end
end
local strval = (thisvalue == 0) and from_en('0') or with_separator(parms, format(fmt, thisvalue))
table.insert(results, strval .. sep1 .. id)
if outvalue == 0 then
২,১৪৬ ⟶ ২,৪৫৫ নং লাইন:
local range = parms.range
if range then
localfor success, result2i = make_result(valinfo[2])1, range.n do
if not success then returnlocal falsesuccess, result2 end= make_result(valinfo[i+1])
result = range_text(range, want_name, parms,if resultnot success then return false, result2) end
result = range_text(range[i], want_name, parms, result, result2)
end
end
return true, result .. mid