[editar] [purgar]

Documentación del módulo

Version check

Designación de la versión en Wikidata: 2024-02-24 Ok!

Uso

This modules provides functions for use of currency exchange rates.
Esta documentación es transcluida desde Módulo:Exchange rate/doc.
Los editores pueden experimentar en la zona de pruebas de la plantilla.
Por favor, añade las categorías a la subpágina de documentación. Subpáginas de esta plantilla.

--[[ 	Thanks to GiftBot who is uploading/updating currency exchange rates to Wikimedia 	Commons. This service is available since March of 2022. ]]--  -- module variable and administration local er = { 	moduleInterface = { 		suite  = 'Exchange rate', 		serial = '2024-02-24', 		item   = 112066294 	} }  -- require( 'strict' )  -- Exchange-rate tables stored on Wikimedia Commons local tableNames =  { 	'ECB euro foreign exchange reference rates.tab',  	'Xe.com exchange rates.tab' }  -- language-dependent error messages local messages = { 	unknownIsoCode = '[[Category:Währung: Seiten mit unbekanntem Währungscode]] <span class="error">Unbekannter Währungscode</span>', 	wrongParams    = '[[Category:Währung: Fehlerhafte Parameter]] <span class="error">Fehlerhafte(r) Parameter</span>' }  -- language-dependent constants local language = { 	defaultUnits     = { 'EUR', 'CHF', 'USD' }, 	decimalSep       = ',', -- decimal separator 	thousandsSep     = '.', 	commaSep         = mw.message.new( 'comma-separator' ):plain(), 	dateFormat       = 'j. M Y', 	convertFormatter = '≈ %s', 	defaultFormatter = '%s&#x202F;unit', 	wrapperClass     = 'voy-currency', 	conversionVia    = 'EUR', -- EUR or USD 	all              = 'alle', -- lowercase letters 	date             = 'datum' }  -- variables for internal use local cu -- for currencies-table module local rateTables = {} -- to prevent multiple fetching  -- check if arg is set local function isSet( arg ) 	return arg and arg ~= '' end  -- returns a currency formatter string for isoCode -- the following function must be localized local function getFormatter( isoCode, externalFormatter ) 	isoCode = isSet( isoCode ) and isoCode:upper() or 'XXX'  	if externalFormatter then 		return externalFormatter( isoCode ) 	elseif not cu then 		cu = mw.loadData( 'Module:CountryData/Currencies' ) 	end  	local tab = cu.isoToQid[ isoCode ] and cu.currencies[ cu.isoToQid[ isoCode ] ] 	local default = cu.currencies.default or language.defaultFormatter 	if tab then 		if tab.f then 			return tab.f 		else 			local unit = tab.add and tab.add:gsub( ',.*', '' ) or tab.iso 			return default:gsub( 'unit', unit ) 		end 	end 	return default:gsub( 'unit', isoCode ) end  -- returns count of significant digits -- zeros after decimal separator are significant local function getDigitCount( num ) 	num = num:gsub( '%.', '' ):gsub( '^0+', '' ) 	return #num end  -- rounds mantissa/significand of number num to digit count digitCount local function round( num, digitCount ) 	return tonumber( string.format( '%.' .. digitCount .. 'g', num ) ) end  -- returns tabularData fields schema as associative table local function getFields( tabularData ) 	local fields = {} 	local tFields = tabularData.schema.fields 	for i = 1, #tFields do 		fields[ tFields[ i ].name ] = i 	end 	return fields end  -- returns currency-rates table as associative table -- this is an expensive function: the rateTables should be established only once local function getRateTable( tableName ) 	local rows = {} 	local colNo, fields, row, tData 	if not rateTables[ tableName ] then 		local tabularData = mw.ext.data.get( tableName ) 		if not tabularData then 			return nil 		end 		fields = getFields( tabularData ) 		colNo = fields[ 'currency' ] 		tData = tabularData.data 		for i = 1, #tData do 			row = tData[ i ] 			rows[ row[ colNo ] ] = row 		end 		rateTables[ tableName ] = { 			fields = fields, 			rows = rows 		} 	end 	return rateTables[ tableName ] end  -- returns exchange-rate properties for source -> target iso codes local function getCurrencyData( rateTable, source, target ) 	local rate, digitCount, asOf 	local fields = rateTable.fields 	local row = rateTable.rows[ source ] 	if row then 		rate = row[ fields[ target ] ]:gsub( ',', '' ) 			-- remove English thousands separator 		digitCount = getDigitCount( rate ) 		rate = tonumber( rate ) 		asOf = row[ fields[ 'date' ] ] 	end 	return rate, digitCount, asOf end  -- returns exchange rate for source -> target iso codes -- toRound: Boolean function er.getRate( source, target, toRound ) 	-- source, target are three-letter ISO 4217 codes 	if not source:match( '^%a%a%a$' ) or not target:match( '^%a%a%a$' ) then 		return nil 	end  	local rateTable, fields, rate, rows, digitCount, asOf 	source = source:upper() 	target = target:upper()  	for i = 1, #tableNames do 		rateTable = getRateTable( tableNames[ i ] ) 		if rateTable then 			fields = rateTable.fields 			if fields[ target ] then 				rate, digitCount, asOf = getCurrencyData( rateTable, source, target ) 				if rate then 					rate = 1/rate 				end 			elseif fields[ source ] then  				rate, digitCount, asOf = getCurrencyData( rateTable, target, source ) 			elseif fields[ language.conversionVia ] then 				local rate1, digitCount1, asOf1 = getCurrencyData( rateTable, source, language.conversionVia ) 				local rate2, digitCount2, asOf2 = getCurrencyData( rateTable, target, language.conversionVia ) 				if rate1 and rate2 then 					rate = rate2/rate1 					digitCount = digitCount1 < digitCount2 and digitCount1 or digitCount2 					asOf = asOf1 < asOf2 and asOf1 or asOf2 				end 			end 		end 		if rate then 			break 		end 	end 	if rate and toRound then 		rate = round( rate, digitCount ) 	end 	return rate, asOf, digitCount end  -- returns a converted date for aDate due to formatStr local function getDate( aDate, formatStr ) 	local function formatDate( aDate, formatStr ) 		return mw.getContentLanguage():formatDate( formatStr, aDate, true ) 	end  	if isSet( aDate ) then 		local success, t = pcall( formatDate, aDate, formatStr ) 		return success and t or '' 	else 		return '' 	end end  -- inserts thousands separators in amount string local function insertThousandsSep( amount ) 	local k 	local sep = '%1' .. language.thousandsSep .. '%2' 	while true do   		amount, k = amount:gsub( '^(-?%d+)(%d%d%d)', sep ) 		if k == 0 then 			break 		end 	end 	return amount end  -- localizes a number string local function formatNumber( num ) 	if language.decimalSep ~= '.' then 		num = num:gsub( '%.', language.decimalSep ) 	end 	return insertThousandsSep( num ) end  -- adds the currency unit of isoCode to amount string local function addUnit( amount, isoCode, externalFormatter ) 	local formatStr = getFormatter( isoCode, externalFormatter ) 	return mw.ustring.format( mw.text.decode( formatStr ), amount ) end  local function outputFormat( digits ) 	digits = math.floor( tonumber( digits ) or 2 ) 	if digits < 0 or digits > 6 then 		digits = 2 	end 	return '%.'.. digits .. 'f' end  -- selects different rate outputs due to show local function formatRate( rate, asOf, show, digits, target ) 	show = ( show or '' ):lower() 	rate = formatNumber( isSet( digits ) and outputFormat( digits ):format( rate ) 		or tostring( rate ) ) 	if isSet( digits ) or show == 'all' or show == language.all then 		rate = addUnit( rate, target ) 	end 		 	if show == 'all' or show == language.all then 		return rate .. ' (' .. getDate( asOf, language.dateFormat ) .. ')' 	elseif show == 'date' or show == language.date then 		return getDate( asOf, language.dateFormat ) 	else 		return rate 	end end  -- converts a single currency amount without adding the currency unit local function convertSingle( source, target, amount, digits ) 	local rate, asOf, digitCount = er.getRate( source, target ) 	if rate then 		return formatNumber( outputFormat( digits ):format( 			round( amount * rate, digitCount ) ):gsub( '%.0*$', '' ) ) 	else 		return nil 	end end  -- converts a single currency amount or an amount range and adding the currency unit function er._convert( source, targets, amount, withUnit, digits, externalFormatter ) 	local amount1, amount2, pos, result 	local results = {}  	if not isSet( targets ) then 		targets = language.defaultUnits 		withUnit = true 	elseif type( targets ) == 'string' then 		targets = { targets } 	end  	amount = amount:gsub( '[ %a%' .. language.thousandsSep .. ']+', '' ):gsub( '-', '–' ) 	if language.decimalSep ~= '.' then 		amount = amount:gsub( language.decimalSep, '.' ) 	end  	for i, target in ipairs( targets ) do 		if target ~= source then 			pos = mw.ustring.find( amount, '[^,%.%d]' ) 			if pos then 				amount1 = mw.ustring.sub( amount, 1, pos - 1 ) 				amount2 = tonumber( mw.ustring.sub( amount, pos + 1 ) ) 			else 				amount1 = amount 			end 			amount1 = tonumber( amount1 ) or 1 			result = convertSingle( source, target, amount1, digits ) 			if pos and result and amount2 then 				amount2 = convertSingle( source, target, amount2, digits ) 				result = amount2 and 					( result .. mw.ustring.sub( amount, pos, pos ) .. amount2 ) 			end 			if result then 				if withUnit then 					result = addUnit( result, target, externalFormatter ) 				end 				table.insert( results, result ) 			end 		end 	end 	result = table.concat( results, language.commaSep ) 	return result ~= '' and result end  -- returns a wrapper format string with tooltip title function er.getWrapper( amount, source, target, digits, externalFormatter, 	withMaintenance) 	local formatStr = getFormatter( source, externalFormatter ) 	local title = er._convert( source, target, amount, true, digits ) 	if title then 		return tostring( mw.html.create( 'abbr' ) 			:attr( 'title', mw.ustring.format( language.convertFormatter, title ) ) 			:addClass( language.wrapperClass ) 			:addClass( language.wrapperClass .. '-' .. source:lower() ) 			:wikitext( formatStr ) 		) 	else 		return formatStr .. ( withMaintenance and messages.wrongParams or '' ) 	end end  -- #invoke function returning the exchange rate function er.rate( frame ) 	local args = frame.args 	local rate, asOf, digitCount = er.getRate( args.source, args.target, true ) 	return rate and formatRate( rate, asOf, args.show, args.digits, args.target ) 		or messages.unknownIsoCode end  -- #invoke function returning the converted amount or amount range function er.convert( frame ) 	local args = frame.args 	if isSet( args.show ) then 		return er.rate( frame ) 	else 		return er._convert( args.source, args.target, 			isSet( args.amount ) and args.amount or '1', ( args.plain or '' ) ~= '1', 			args.digits ) or messages.wrongParams 	end end  -- #invoke function returning exchange-rate information -- returns the formatted amount or amount range with a tooltip containing -- converted values function er.currencyWithConversions( frame ) 	local args = frame.args 	if not isSet( args.amount ) then 		args.amount = '1' 	end 	return mw.ustring.format( 		er.getWrapper( args.amount, args.source, args.target, args.digits, nil, true ), 		args.amount:gsub( '-', '–' ) 	) end  return er