Module:Translator

Module documentation
local p = {}

-- Dependencies.
local getArgs = require('Module:Arguments').getArgs
local iso639 = require('Module:ISO 639 name')
local ctn = function(code)
	if not code then
		return nil
	elseif code ~= 'simple' then
		return iso639['iso_639_code_to_name']({code})
	else
		return 'Simple English'
	end
end
local to639_3 = function(code)
	if not code then
		return nil
	elseif code == 'simple' or code == 'hin' or code == 'msa' or code == 'nep' or code == 'swa' then
		return code
	else
		return iso639['iso_639_name_to_code']({ctn(code), '3'})
	end
end
local exc = function(code)
	if not code then
		return nil
	elseif code == 'simple' or code == 'hin' or code == 'msa' or code == 'nep' or code == 'swa' then
		return true
	else
		return iso639['iso_639_code_exists']({code})
	end
end
local ubx = require('Module:Userbox').userbox

-- Main function.
function p.main(frame)
	local args = getArgs(frame, {
		trim = true,
		removeBlanks = true
	})
	local skipcat = args['skipcat'] or args['nocat']
	local plain = args['plain'] and args['plain'] ~= ''
	if plain then
		if not args[1] then
			return ''
		end
		local lang = mw.text.split(args[1], '%s*-%s*')
		if #lang == 2 then
			for i = 1, 2 do
				lang[i] = mw.text.split(lang[i], '%s*,%s*')
				for j = 1, #lang[i] do
					lang[i][j] = lang[i][j]:lower()
				end
			end
			return p.transbabel(p.filter(lang[1]), p.filter(lang[2]), skipcat)
		else
			return p.throw('Bad syntax. See [[Template:Translator]] for information.', skipcat)
		end
	end
	local t = {
		'{| name="userboxes" class="translator-userboxes" style="' ..
			'clear: right; float: right; margin-left: 1ex; margin-bottom: 1ex; ' ..
			'border: 1px solid #808080; width: 242px;"',
		'|-',
		'! [[:m:Translator in the following language combinations|' ..
			'Translator in the following language combinations]]'
	}
	
	for i = 1, 100 do
		if args[i] then
			local lang = mw.text.split(args[i], '%s*-%s*')
			local skipcati = args['skipcat' .. i] or args['nocat' .. i]
			if #lang == 2 then
				for i = 1, 2 do
					lang[i] = mw.text.split(lang[i], '%s*,%s*')
					for j = 1, #lang[i] do
						lang[i][j] = lang[i][j]:lower()
					end
				end
				t = p.ins(t, {
					'|-',
					'| ',
					p.transbabel(lang[1], lang[2], skipcat or skipcati)
				})
			else
				t = p.ins(t, {
					'|-',
					'| ' .. p.throw('Bad syntax. See [[Template:Translator]] for information.', skipcat or skipcati)
				})
			end
		end
	end
	
	t = p.ins(t, {
		'|-', 
		'| style="text-align: center;" | [[:m:Category:Translator\'s Templates|Search translators]]',
		'|}'
	})
	
	return table.concat(t, '\n')
end

-- Internal functions.
function p.transbabel(from, to, skipcat)
	if p.validate({from, to}) then
		return p.throw('Incorrect ISO 639 code: ' .. p.validate({from, to}), skipcat)
	elseif p.overlap(from, to) then
		return p.throw('Bad syntax. See [[Template:Translator]] for information.', skipcat)
	end
	
	local userbox
	local text1 = 'This translator translates from' .. '<br>'
	local text = {}
	local err = ''
	
	from, to = p.normalize(from), p.normalize(to)
	
	if #from > 1 and #to > 1 then
		local f = {}
		local t = {}
		for i = 1, (#from > #to and #from or #to) do
			f[i] = ctn(from[i])
			t[i] = ctn(to[i])
		end
		text = p.ins(text, {
			mw.text.listToText(f) .. ' to ' .. mw.text.listToText(t)
		})
	elseif #from > 1 then
		for i = 1, #from do
			if from[i] ~= to[1] then
				if i ~= #from then
					text = p.ins(text, {
						'[[:Category:Translators ' .. from[i] .. '-' .. to[1] .. '|' ..
						ctn(from[i]) .. ']]'
					})
				else
					text = p.ins(text, {
						'[[:Category:Translators ' .. from[i] .. '-' .. to[1] .. '|' ..
						ctn(from[i]) .. ' to ' .. ctn(to[1]) .. ']]'
					})
				end
			end
		end
	elseif #to > 1 then
		for j = 1, #to do
			if from[1] ~= to[j] then
				if j == 1 then
					text = p.ins(text, {
						'[[:Category:Translators ' .. from[1] .. '-' .. to[j] .. '|' ..
						ctn(from[1]) .. ' to ' .. ctn(to[j]) .. ']]'
					})
				else
					text = p.ins(text, {
						'[[:Category:Translators ' .. from[1] .. '-' .. to[j] .. '|' ..
						ctn(to[j]) .. ']]'
					})
				end
			end
		end
	else
		if from[1] ~= to[1] then
			text = p.ins(text, {
				'[[:Category:Translators ' .. from[1] .. '-' .. to[1] .. '|' ..
				ctn(from[1]) .. ' to ' .. ctn(to[1]) .. ']]'
			})
		else
			err = 'Bad syntax. See [[Template:Translator]] for information.'
		end
	end
	
	if #text ~= 0 then
		userbox = ubx({
			['border-c']	= '#708090',
			['id']			= '[[File:Icono de traducción.svg|33px|A loop consists of a Latin A, ' ..
								'a Hiragana a and two blue arrows lying between them]]',
			['id-c']		= '#FFFFFF',
			['id-p']		= '1px',
			['info']		= text1 .. '<b>' .. mw.text.listToText(text) .. '</b>.' ..
								(skipcat and '' or p.cat(from, to)),
			['info-c']		= '#DCDCDC',
			['info-p']		= '0 0.5em'
		})
	else
		err = 'Bad syntax. See [[Template:Translator]] for information.'
	end
	
	if err ~= '' then
		return p.throw(err, skipcat)
	else
		return userbox
	end
end

function p.cat(from, to)
	local ret = {}
	
	for i = 1, #from do
		for j = 1, #to do
			if from[i] ~= to[j] and exc(from[i]) and exc(to[j]) then
				ret = p.ins(ret, {'[[Category:Translators ' .. from[i] .. '-' .. to[j] .. ']]'})
			end
		end
	end
	
	return table.concat(ret, '')
end

function p.ins(array, elements)
	for i = 1, #elements do
		array[#array + 1] = elements[i]
	end
	return array
end

function p.validate(array)
	local t = p.merge(array)
	for i = 1, #t do
		if t[i] == '' then
			return 'No code provided.'
		elseif not exc(t[i]) then
			return t[i]
		end
	end
	return nil
end

function p.overlap(array1, array2)
	for i = 1, #array1 do
		for j = 1, #array2 do
			if array1[i] == array2[j] then
				return true
			end
		end
	end
	return false
end

function p.merge(array)
	local ret = {}
	for i = 0, 1 do
		for j = 1, #array do
			if i == 0 then
				if type(array[j]) == 'table' then
					ret = p.ins(ret, array[j])
				else
					ret[#ret + 1] = array[j]
				end
			else
				if type(array[j]) == 'table' then
					return p.merge(ret)
				end
			end
		end
	end
	return ret
end

function p.filter(t)
	local ret = {}
	for k, v in pairs(t) do
		if mw.text.trim(v) ~= '' then
			ret[k] = v
		end
	end
	return ret
end

function p.normalize(codes)
	for k, v in ipairs(codes) do
		codes[k] = to639_3(v)
	end
	return codes
end

function p.throw(err, skipcat)
	return tostring(
		mw.html.create('strong')
			:attr('class', 'error')
			:wikitext('Error: ' .. err)
	) .. (skipcat and '' or '[[Category:Translator module errors]]')
end

return p