Logo Voyage

Module:Exchangerate Voyage Tips and guide

You can check the original Wikivoyage article Here
[view] [edit] [history] [purge] Documentation

Module status

[edit]

    The module is currently only able to convert euro in currencies available at c:Data:ECB euro foreign exchange reference rates.tab and c:Data:Xe.com exchange rates.tab.

    Functionality

    [edit]

    The function rate returns the number of 1 unit of the currency given as "source" in the currency given as "target" as the raw value calculated from available numbers. If "verbose" is set, the module throws an error if no conversion rate is available.

    The function revisionTime takes "source", "target" and "verbose" and returns the date of the last update for the rate.

    The function convert takes "source", "target" and "verbose" and additionally "amount". It converts the number given in "amount" in the "source" currency into the "target" currency with rounded digits.

    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 .. '&ndash;' .. 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
    


    Discover



    Powered by GetYourGuide