Module:User:Mr. Stradivarius/Check ISO 639-1

From Omniversalis

Documentation for this module may be created at Module:User:Mr. Stradivarius/Check ISO 639-1/doc

--[[
-- This module detects whether the first positional parameter is a valid ISO 639-1 language code.
-- If it is, it returns the code. If not, it returns an error and a tracking category. For blank
-- or non-string input, the returns a blank string. The tracking category is sorted by the language
-- code, rather than by the page name.
--]]

--[[
-----------------------------------------------------------------------------
--                             Configuration
--
-- Values that vary between languages are stored here, to enable easy
-- porting between wikis.
-----------------------------------------------------------------------------
--]]

local cfg = {}

-- Error message on receiving invalid input. %s is the input passed to the module, and should be included in the message exactly once.
cfg.errorMessage = 'Error: invalid input "%s"; please use an [[List of ISO 639-1 codes|ISO 639-1 code]]'
cfg.errorClass = 'error' -- The CSS class used in error messages on the local wiki.
cfg.errorCategory = 'Pages with invalid ISO 639-1 language codes' -- The name of the error category to display.

--[[
-----------------------------------------------------------------------------
-- End configuration
-----------------------------------------------------------------------------
--]]

-- Define constants.
local categoryNsText = mw.site.namespaces[14].name
local currentLanguageCode = mw.language.getContentLanguage():getCode()

-- Load dependent modules.
local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')

local p = {}

local codes = {
	['aa'] = true, ['ab'] = true, ['ae'] = true, ['af'] = true, ['ak'] = true,
	['am'] = true, ['an'] = true, ['ar'] = true, ['as'] = true, ['av'] = true,
	['ay'] = true, ['az'] = true, ['ba'] = true, ['be'] = true, ['bg'] = true,
	['bh'] = true, ['bi'] = true, ['bn'] = true, ['bo'] = true, ['br'] = true,
	['bs'] = true, ['ca'] = true, ['ce'] = true, ['ch'] = true, ['co'] = true,
	['cr'] = true, ['cs'] = true, ['cu'] = true, ['cv'] = true, ['cy'] = true,
	['da'] = true, ['de'] = true, ['dv'] = true, ['dz'] = true, ['ee'] = true,
	['el'] = true, ['en'] = true, ['eo'] = true, ['es'] = true, ['et'] = true,
	['eu'] = true, ['fa'] = true, ['ff'] = true, ['fi'] = true, ['fj'] = true,
	['fo'] = true, ['fr'] = true, ['fy'] = true, ['ga'] = true, ['gd'] = true,
	['gl'] = true, ['gn'] = true, ['gu'] = true, ['gv'] = true, ['ha'] = true,
	['he'] = true, ['hi'] = true, ['ho'] = true, ['hr'] = true, ['ht'] = true,
	['hu'] = true, ['hy'] = true, ['ia'] = true, ['id'] = true, ['ie'] = true,
	['ig'] = true, ['ii'] = true, ['ik'] = true, ['io'] = true, ['is'] = true,
	['it'] = true, ['iu'] = true, ['ja'] = true, ['jv'] = true, ['ka'] = true,
	['kg'] = true, ['ki'] = true, ['kj'] = true, ['kk'] = true, ['kl'] = true,
	['km'] = true, ['kn'] = true, ['ko'] = true, ['kr'] = true, ['ks'] = true,
	['ku'] = true, ['kv'] = true, ['kw'] = true, ['ky'] = true, ['la'] = true,
	['lb'] = true, ['lg'] = true, ['li'] = true, ['ln'] = true, ['lo'] = true,
	['lt'] = true, ['lu'] = true, ['lv'] = true, ['mg'] = true, ['mh'] = true,
	['mi'] = true, ['mk'] = true, ['ml'] = true, ['mn'] = true, ['mr'] = true,
	['ms'] = true, ['mt'] = true, ['my'] = true, ['na'] = true, ['nb'] = true,
	['nd'] = true, ['ng'] = true, ['ne'] = true, ['nl'] = true, ['nn'] = true,
	['no'] = true, ['nr'] = true, ['nv'] = true, ['ny'] = true, ['oc'] = true,
	['om'] = true, ['or'] = true, ['os'] = true, ['pa'] = true, ['pi'] = true,
	['pl'] = true, ['ps'] = true, ['pt'] = true, ['qu'] = true, ['rm'] = true,
	['rn'] = true, ['ro'] = true, ['ru'] = true, ['rw'] = true, ['sa'] = true,
	['sc'] = true, ['sd'] = true, ['se'] = true, ['sk'] = true, ['sl'] = true,
	['sm'] = true, ['sn'] = true, ['so'] = true, ['sq'] = true, ['sr'] = true,
	['ss'] = true, ['st'] = true, ['su'] = true, ['sv'] = true, ['sw'] = true,
	['ta'] = true, ['te'] = true, ['tg'] = true, ['th'] = true, ['ti'] = true,
	['tk'] = true, ['tl'] = true, ['tn'] = true, ['tr'] = true, ['ts'] = true,
	['tt'] = true, ['tw'] = true, ['ty'] = true, ['ug'] = true, ['uk'] = true,
	['ur'] = true, ['uz'] = true, ['ve'] = true, ['vi'] = true, ['vo'] = true,
	['yi'] = true, ['yo'] = true, ['za'] = true, ['zh'] = true, ['za'] = true
}

function p.main(frame)
	local args = getArgs(frame)
	return p._main(args)
end

function p._main(args)
	local input = args[1]
	if type(input) ~= 'string' then
		return '' -- input is either not a string or is a blank string that was removed by getArgs.
	end
	local inputLower = mw.ustring.lower(input)
	local ret
	if codes[inputLower] then
		ret = inputLower
	else
		local code = p.getCodeFromLanguageName(inputLower)
		if code and codes[code] then -- MediaWiki language codes might not be valid ISO 639-1 codes, so we need to check the codes table too.
			ret = code
		else
			ret = mw.ustring.format('<strong class="%s">' .. cfg.errorMessage .. '</strong>', cfg.errorClass, input)
			if not yesno(args.nocat) then
				ret = mw.ustring.format('%s[[%s:%s|%s]]', ret, categoryNsText, cfg.errorCategory, input)
			end
		end
	end
	return ret
end

function p.getCodeFromLanguageName(s)
	-- Gets an ISO 639-1 code from a language name, or returns nil if none can be found.
	local languages = mw.language.fetchLanguageNames(currentLanguageCode)
	for code, name in pairs(languages) do
		if s == mw.ustring.lower(name) then -- s has already been converted to lower case
			return code
		end
	end
	return nil
end

return p