Module:Currency
Appearance
![]() | This Lua module is used on approximately 4,700 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them. |
Related pages |
---|
This code is invoked from {{Currency}}
. All of the template parameters are passed in the module's frame.
{{#invoke:Currency|currency|<amount>|<code>|<first>|<linked>|<passthrough>}}
See the template code for a description of the parameters.
Other modules may use this code. The entry point for other modules is _render_currency (amount, code, long_form, linked)
. See the function render_currency()
for detail.
The data file Module:Currency/Presentation holds required currency presentation characteristics.
require('Module:No globals')
local getArgs = require('Module:Arguments').getArgs
local p = {}
local presentation ={}; -- table of tables that contain currency presentation data
local lang = mw.language.getContentLanguage(); -- language object for this wiki
--[[--------------------------< I S _ S E T >------------------------------------------------------------------
Whether variable is set or not. A variable is set when it is not nil and not empty.
]]
local function is_set( var )
return not (var == nil or var == '');
end
--[[--------------------------< G R O U P I N G >--------------------------------------------------------------
Takes a number string in the form nnnn.nn and adds grouping to it, return n,nnn.nn
Grouping is added by reversing the digits portion of the value:
123456789.nn
becomes
987654321
Then, string.gsub replaces each group of three digits with the same three digits (the capture) followed by a comma:
987,654,321,
The string is reversed again:
,123,456,789
and the leading comma (if present) is removed:
123,456,789
At the end, the digits and decimal portions are reunited with a decimal point which is returned to calling function.
Unrecognized 'numbers' return '0.00'
]]
local function grouping (val)
local digits; -- left side of the decimal point
local decimals; -- right side of the decimal point
if val:match ('^%d+%.%d+$') then -- has digits and decimals
digits, decimals = val:match ('(%d+)%.(%d+)');
elseif val:match ('^%d+%.$') then -- has digits and decimal point but no decimals
digits = val:match ('(%d+)%.')
elseif val:match ('^%.%d+$') then -- has no digits but has decimal point and decimals
decimals = val:match ('%.(%d+)')
elseif val:match ('^%d+$') then -- just has digits
digits = val;
else
return '0.00'; -- something that isn't a number; return default TODO: error message here
end
if is_set (digits) then
digits = digits:reverse():gsub ('%d%d%d', '%1,'):reverse():gsub('^,', ''); -- apply grouping
else
digits = '0'; -- otherwise set default value
end
if not is_set (decimals) then
decimals = '00'; -- set to default
end
return digits .. '.' .. decimals; -- return formatted value
end
--[[--------------------------< M A K E _ S H O R T _ F O R M _ N A M E >-------------------------------------
Assembles value and symbol according to the order specified in the properties table for this currency code
]]
local function make_short_form_name (amount, code)
local symbol = string.format ('[[%s|%s]]', presentation.currency_properties[code].page, presentation.currency_properties[code].symbol); -- make wikilink of page and symbol
local position = presentation.currency_properties[code].position;
-- amount = grouping (amount);
amount = lang:formatNum (tonumber(amount));
if 'b' == position then -- choose appropriate format: unspaced before the amount
return string.format ('%s%s', symbol, amount);
elseif 'bs' == position then -- spaced before the amount
return string.format ('%s %s', symbol, amount);
elseif 'a' == position then -- unspaced after the amount
return string.format ('%s%s', amount, symbol);
elseif 'as' == position then -- spaced after the amount
return string.format ('%s %s', amount, symbol);
else
return amount .. ' <span style="font-size:inherit" class="error">{{currency}} – definition missing position</span>'; -- position not defined
end
end
--[[--------------------------< M A K E _ L O N G _ F O R M _ N A M E >---------------------------------------
assembles a long-form currency name from amount and name the tables; plural for all values not equal to 1
]]
local function make_long_form_name (amount, code)
local properties;
local name;
if presentation.currency_properties[code] then
properties = presentation.currency_properties;
elseif presentation.non_standard_properties[code] then
properties = presentation.non_standard_properties;
else
return '<span style="font-size:inherit" class="error">{{currency}} – cannot find code: ' .. code .. '</span>'; -- should not be here
end
amount = tonumber (amount); -- make sure it's a number
if 1 == amount then
name = string.format ('[[%s]]', properties[code].page); -- the singular form
elseif 's' == properties[code].plural then
name = string.format ('[[%s]]s', properties[code].page); -- a plural form
elseif is_set (properties[code].plural) then -- plural is not an 's' form
name = string.format ('[[%s]]', properties[code].plural); -- another plural form (pounds sterling v. dollars)
else
name = string.format ('[[%s]]', properties[code].page); -- no plural form so use the singular form
end
return lang:formatNum (amount) .. ' ' .. name; -- put it all together
-- return grouping (amount) .. ' ' .. name; -- put it all together
end
--[[--------------------------< R E N D E R _ C U R R E N C Y >------------------------------------------------
Renders currency amount with symbol or long-form name.
Also, entry point for other modules. Assumes that parameters have been vetted; amount is a number, code is upper
case string, long_form is boolean; all are required.
]]
local function render_currency (amount, code, long_form)
local name;
local ouput;
presentation = mw.loadData ('Module:Currency/Presentation'); -- get presentation data
if nil == presentation.currency_properties[code] then -- if not an iso 4217 code
if presentation.code_translation[code] then -- but can be translated
code = presentation.code_translation[code]; -- then translate
elseif nil == presentation.non_standard_properties[code] then -- last chance, is it a non-standard code?
return '<span style="font-size:inherit" class="error">{{currency}} – invalid code</span>';
end
end
if long_form then
return make_long_form_name (amount, code); --
else
return make_short_form_name (amount, code);
end
return amount;
end
--[[--------------------------< C U R R E N C Y >--------------------------------------------------------------
Template:Currency entry point. The template takes three parameters:
positional (1st), |amount=, |Amount= : digits and decimal points only
positional (2nd), |type=, |Type= : code that identifies the currency
|first= : uses currency name instead of symbol
]]
local function currency (frame)
local args = getArgs(frame);
local amount, code;
local long_form = false;
-- if not tonumber (args[1]) then -- if args[1] can't be converted to a number then error
amount = lang:parseFormattedNumber(args[1]); -- if args[1] can't be converted to a number then error (this just strips grouping characters)
if not amount then -- non-digit characters or more than one decimal point
return '<span style="font-size:inherit" class="error">{{currency}} – invalid amount</span>';
end
if nil == args[2] then -- if not provided
code = USD; -- default to USD
else
code = args[2]:upper(); -- always upper case; used as index into data tables which all use upper case
end
if args[3] then -- this is the |first= parameter TODO: make this value meaningful? y, yes, true?
long_form = true;
end
-- return render_currency (args[1], code, long_form)
return render_currency (amount, code, long_form)
end
return {
currency = currency, -- template entry point
_render_currency = render_currency, -- other modules entry point
}