Module:Exchangerate/sandbox
Appearance
Documentation for this module may be created at Module:Exchangerate/sandbox/doc
local errormsg = ('[[Category:Articles that use unexpected currency]]'
.. '<span class="exchangeinfo" style="display:none;" '
.. 'title="Exchange rate not found">Unexpected currency</span>'
.. 'rate not found')
local function countSigificantDigits(number)
number = string.gsub(number, '%.', '', 1)
number = mw.text.trim(number, '0')
return #number
end
local function round(num, numSigificantDigits)
local numDecimalPlaces = numSigificantDigits - math.floor(math.log10(num)) - 1
local mult = 10^(numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end
local function getTabularDataFieldNames(tabularData)
local fields = {}
for _,field in pairs(tabularData.schema.fields) do
table.insert(fields, field.name)
end
return fields
end
local function getColumnIndices(fields)
local rowCurrencyIndex, dateIndex
local targetCurrencyIndices = {}
local sourceCurrencyIndices = {}
for i,v in pairs(fields) do
if v == 'currency' then
rowCurrencyIndex = i
elseif v == 'date' then
dateIndex = i
elseif string.match(v, '^%u%u%u$') then
sourceCurrencyIndices[v] = i
elseif string.match(v, '^_%u%u%u$') then
targetCurrencyIndices[string.sub(v,2)] = i
end
end
return rowCurrencyIndex, dateIndex, sourceCurrencyIndices, targetCurrencyIndices
end
local function getConversionTable(dataPageName)
local tabularData = mw.ext.data.get(dataPageName)
if not tabularData then return nil end
local fields = getTabularDataFieldNames(tabularData)
local rowCurrencyIndex, dateIndex, sourceCurrencyIndices, targetCurrencyIndices = getColumnIndices(fields)
local conversionTable = {}
if rowCurrencyIndex then
for _,row in pairs(tabularData.data) do
for sourceCurrency,index in pairs(sourceCurrencyIndices) do
if not conversionTable[sourceCurrency] then
conversionTable[sourceCurrency] = {}
end
conversionTable[sourceCurrency][row[rowCurrencyIndex]] = {rate = row[index], revisionTime = row[dateIndex]}
end
for targetCurrency,index in pairs(targetCurrencyIndices) do
if not conversionTable[row[rowCurrencyIndex]] then
conversionTable[row[rowCurrencyIndex]] = {}
end
conversionTable[row[rowCurrencyIndex]][targetCurrency] = {rate = row[index], revisionTime = row[dateIndex]}
end
end
end
return conversionTable
end
local function getDataFromRateDataPage(dataPageName, source, target)
local conversionTable = getConversionTable(dataPageName)
if not conversionTable then return nil end
local rate, revisionTime
if conversionTable[source] and conversionTable[source][target] then
rate = conversionTable[source][target]['rate']
rateSignificantDigits = countSigificantDigits(rate)
revisionTime = conversionTable[source][target]['revisionTime']
elseif conversionTable[target] and conversionTable[target][source] then
local targetToSourceRate = conversionTable[target][source]['rate']
rate = targetToSourceRate^-1
rateSignificantDigits = countSigificantDigits(targetToSourceRate)
revisionTime = conversionTable[target][source]['revisionTime']
end
return rate, rateSignificantDigits, revisionTime
end
local p = {}
function p._rate(source, target, rounded)
local dataPageNames = {
'ECB euro foreign exchange reference rates.tab',
'Xe.com exchange rates.tab'}
local rate, revisionTime, rateSignificantDigits
for _,name in pairs(dataPageNames) do
rate, rateSignificantDigits, revisionTime = getDataFromRateDataPage(name, source, target)
if not rate or not revisionTime then
for _,name in pairs(dataPageNames) do
local USDtoTargetRate, UtoTSigDig, UtoTRevTime = getDataFromRateDataPage(name, 'USD', target)
local USDtoSourceRate, UtoSSigDig, UtoSRevTime = getDataFromRateDataPage(name, 'USD', source)
if USDtoTargetRate and USDtoSourceRate then
rate = USDtoTargetRate/USDtoSourceRate
revisionTime = UtoTRevTime < UtoSRevTime and UtoTRevTime or UtoSRevTime
rateSignificantDigits = UtoTSigDig < UtoSSigDig and UtoTSigDig or UtoSSigDig
end
end
end
if rate and revisionTime then
break
end
end
if rate and revisionTime then
if rounded then
rate = round(rate, rateSignificantDigits)
end
return rate, revisionTime
end
end
function p._convert(source, target, amount)
local rate = p._rate(source, target)
if rate then
local amountSigificantDigitsCount = countSigificantDigits(amount)
return round(amount * rate, amountSigificantDigitsCount + 1)
end
end
function p._convertSingelOrRange(source, target, amounts)
local amounts = string.gsub(amounts, ',', '')
local splitOffset = mw.ustring.find(amounts, '-')
local converted
if splitOffset then
local firstAmount = mw.ustring.sub(amounts, 0, splitOffset -1)
local secondAmount = mw.ustring.sub(amounts, splitOffset + 1)
local first = p._convert(source, target, firstAmount)
local second = p._convert(source, target, secondAmount)
converted = first and second and first .. '–' .. second
else
converted = p._convert(source, target, amounts)
end
return converted
end
function p.rate(frame)
local args = frame.args
local rate = p._rate(args.source, args.target, true)
local result = rate or args.verbose and errormsg
return result
end
function p.revisionTime(frame)
local args = frame.args
local _,revisionTime = p._rate(args.source, args.target)
local result = revisionTime or args.verbose and errormsg
return result
end
function p.convert(frame)
local args = frame.args
local amount = string.gsub(args.amount, ',', '')
local convertedAmount = p._convert(args.source, args.target, amount)
local result = convertedAmount or args.verbose and errormsg
return result
end
function p.convertSingelOrRange(frame)
local args = frame.args
local convertedAmounts = p._convertSingelOrRange(
args.source, args.target, args.amounts)
local result = convertedAmounts or args.verbose and errormsg
return result
end
local function currencyWithSymbol(currency, symbolFormat, amount)
local currencyWithSymbol = (
symbolFormat and string.format(symbolFormat, amount)
or currency .. amount)
return currencyWithSymbol
end
function p.currencyWithConversions(frame)
local args = frame.args
local amount = (args.amount and args.amount ~= '') and args.amount or 1
local i18n = mw.loadData('Module:Exchangerate/i18n')
local currencySymbols = i18n.symbols[args.currency]
local shortSymbol = currencySymbols and currencySymbols.shortSymbol
local currencyWithShortSymbol = currencyWithSymbol(
args.currency, shortSymbol, amount)
local uniqueSymbol = currencySymbols and currencySymbols.uniqueSymbol
local currencyWithUniqueSymbol = currencyWithSymbol(
args.currency, uniqueSymbol, amount)
local conversionCurrencies = i18n.defaultConversions or {'USD', 'EUR'}
local convertedStrings = {}
for _,convCurrency in ipairs(conversionCurrencies) do
if args.currency ~= convCurrency then
local convertedAmount = p._convertSingelOrRange(
args.currency, convCurrency, amount)
local convCurrencyUniqueSymbol = (i18n.symbols[convCurrency]
and i18n.symbols[convCurrency].uniqueSymbol)
local convCurrencyWithSymbol = convertedAmount and currencyWithSymbol(
convCurrency, convCurrencyUniqueSymbol, convertedAmount)
table.insert(convertedStrings, convCurrencyWithSymbol)
end
end
local comma = mw.message.new('comma-separator'):plain()
local allConvertedStrings = table.concat(convertedStrings, comma)
local conversions = (allConvertedStrings ~= '') and ' ≈ ' .. allConvertedStrings or ''
local resultFormat = '<abbr title="%s%s">%s</abbr>'
local result = string.format(resultFormat, currencyWithUniqueSymbol,
conversions, currencyWithShortSymbol)
return result
end
return p