require('strict');  
local getArgs = require ('Module:Arguments').getArgs;
local override_data = mw.loadData ('Module:Language/data/ISO 639 override');
--local override_data = mw.loadData ('Module:Language/data/ISO 639 override/sandbox');
local deprecated_data = mw.loadData ('Module:Language/data/ISO 639 deprecated');
local parts = {
{'Module:Language/data/ISO 639-1', '1'},
{'Module:Language/data/ISO 639-2', '2'},
{'Module:Language/data/ISO 639-2B', '2B'},
{'Module:Language/data/ISO 639-3', '3'},
{'Module:Language/data/ISO 639-5', '5'},
}  
----------------------------< E R R O R _ M E S S A G E S >--------------------------------------------------  
local error_messages = {
['err_msg'] = '<span>error: $1 (help)</span>',
['err_text'] = { -- error messages used only in the code to name functions
['ietf'] = '$1 is an IETF tag', -- $1 is the ietf tag
['required'] = 'ISO 639$1 code is required', -- $1 is the 639 '-1', '-2', '-3', '-5' part suffix; may be empty string  
-- code to name functions and iso_639_name_to_code
['not_found'] = '$1 not found in ISO 639-$2 list', -- $1 is code or language name; $2 is 639 part suffix(es)  
-- iso_639_name_to_code only
['name'] = 'language name required',
['not_part'] = '$1 not an ISO 639 part', -- $1 is invalid 639 suffix (without hyphen)  
['code_name'] = 'language code or name required', -- iso_639 only
}
}  
local error_cat = '';  
----------------------------< S U B S T I T U T E >----------------------------------------------------------  
Populates numbered arguments in a message string using an argument table.  
local function substitute (msg, args)
return args and mw.message.newRawMessage (msg, args):plain or msg;
end  
----------------------------< E R R O R _ M S G >------------------------------------------------------------  
create an error message  
local function error_msg (msg, arg, hide, nocat)
local retval = '';
if not hide then
retval = substitute (error_messages.err_msg, substitute (error_messages.err_text[msg], arg));
retval = nocat and retval or (retval .. error_cat);
end
return retval
end  
----------------------------< I S _ S E T >------------------------------------------------------------------  
Returns true if argument is set; false otherwise. Argument is 'set' when it exists (not nil) or when it is not an empty string.  
local function is_set (var)
return not (var == nil or var == '');
end  
--[=[-------------------------< M A K E _ W I K I L I N K >----------------------------------------------------  
Makes a wikilink; when both link and display text is provided, returns a wikilink in the form D; if only
link is provided, returns a wikilink in the form L; if neither are provided or link is omitted, returns an
empty string.  
]=]  
local function make_wikilink (link, display)
if is_set (link) then
if is_set (display) then
return table.concat ({*, display, *});
else
return table.concat ({*, link, *});
end
else
return '';
end
end  
----------------------------< L A N G _ N A M E _ G E T >----------------------------------------------------  
returns first listed language name for code from data{} table; strips parenthetical disambiguation; wikilinks to
the language article if link is true; returns nil else  
local function lang_name_get (code, data, link, label, raw)
local name;
if data[code] then
-- name = raw and data[code][1] or data[code][1]:gsub ('%s*%b', ''); -- get the name; strip parenthetical disambiguators if any when <raw> is false
if raw then
name = data[code][1];
else
name = data[code][1]:gsub ('%s*%b', ''); -- strip parenthetical disambiguators if any
name = name:gsub ('([^,]-), +(.+)', '%2 %1'); -- if inverted, uninvert
end
if link then -- make a link to the language article?
if name:find ('languages') or name:find ('[Ll]anguage$') then
name = make_wikilink (name, label); -- simple wikilink for collective languages or langauges ending in 'Language' unless there is a label
elseif override_data.article_name[code] then
name = make_wikilink (override_data.article_name[code][1], label or name); -- language name or label with wikilink from override data
else
name = make_wikilink (name .. ' language', label or name); -- name or label
end
end
return name;
end
end  
--hide-err=yes suppresses error message and category
|cat=no supresses category  
local function add_ietf_error_msg (text, ietf_err, hide, nocat)
if hide then
ietf_err = '';
end  
if not nocat then -- |cat= empty or omitted -> nocat=false
nocat = '' == ietf_err; -- spoof; don't add cat when no error
end  
return table.concat ({ -- tack on ietf error message if one exists
text, -- code name, language name, or error message
* ~= ietf_err and ' ' or *, -- needs a space when ietf_err is not empty
ietf_err,
nocat and '' or error_cat, -- add error category when |cat=<aynthing but 'no'>
});
end  
--[[--------------------------< G E T _ P A R T _ I N D E X >--------------------------------------------------  
gets index suitable for parts{} table from ISO 639-<part> (usually args[2])  
return valid index [1] - [5]; nil else
1 <- part ['1']
2 <- part ['2'] -- this is part 2T
3 <- part ['2B']
4 <- part ['3']
nil <- part ['4'] -- there is no part 4
5 <- part ['5']  
local function get_part_index (part)
return ({['1']=1, ['2']=2, ['2B']=3, ['3']=4, ['4']=nil, ['5']=5})[part]
end  
----------------------------< I S O _ 6 3 9 _ C O D E _ T O _ N A M E _ C O M M O N >------------------------  
this is code that is common to all of the iso_639_code_n_to_name functions which serve only as template entry
points to provide the , the name of the appropriate data source, and to identify which 639 part applies.  
this function returns a language name or an error message. data is searched in this order:
part-specific override data -> standard part data -> part-specific deprecated data  
a second retval used by _iso_639_code_to_name is true when a code is found; nil else  
local function iso_639_code_to_name_common (args, source, part)
local hide = 'yes' == args['hide-err']; -- suppress error messages and error categorization
local nocat = 'no' == args.cat; -- suppress error categorization (primarily for demo use)
local raw = 'yes' == args.raw; -- disable override and dab removal
local data; -- one of the override or part tables
local name; -- holds language name from data  
if not args[1] then -- if code not provided in the template call
return error_msg ('required', '-' .. part, hide, nocat); -- abandon
end  
local code; -- used for error messaging
local ietf_err; -- holds an error message when args[1] (language code) is in IETF tag form (may or may not be a valid IETF tag)
code, ietf_err = args[1]:gsub('(.-)%-.*', '%1'); -- strip ietf subtags; ietf_err is non-zero when subtags are stripped
ietf_err = (0 ~= ietf_err) and error_msg ('ietf', args[1], hide, nocat) or ''; -- when tags are stripped create an error message; empty string for concatenation else  
if not raw then -- when raw is true, fetch name as is from part data; ignore override
data = override_data['override_' .. part]; -- get override data for this part
name = lang_name_get (code:lower, data, args.link, args.label, raw); -- get override language name if there is one
end  
if not name then
data = mw.loadData (source); -- get the data for this ISO 639 part
name = lang_name_get (code:lower, data, args.link, args.label, raw); -- get language name if there is one
end  
if not name then -- TODO: do something special to indicate when a name is fetched from deprecated data?
data = deprecated_data['deprecated_' .. part]; -- get deprecated data for this part
name = lang_name_get (code:lower, data, args.link, args.label, raw); -- get deprecated language name if there is one  
if not name then
return error_msg ('not_found', {code, part}, hide, nocat); -- code not found, return error message
end
end
return add_ietf_error_msg (name, ietf_err, hide, nocat), true; -- return language name with ietf error message if any; true because we found a code
end