# Module:Native name

require('strict');  

local getArgs = require ('Module:Arguments').getArgs;  
local lang_module = require ('Module:Lang');  
local yes_no = require('Module:Yesno')  

local defined_values = {  
italic = {['no']='no', ['off']='no'}, -- values accepted by |italic= and |italics=; expects 'no' so 'off' must be translated  
paren = {['no']=true, ['off']=true, ['omit']=true}, -- values accepted by |paren=  
}  

local messages_t = {  
tag_required = 'an IETF language tag as parameter } is required', -- for  
name_required = 'a name as parameter } is required',  

tag_required_idx = 'an IETF language tag in |tag%s= is required', -- for when called from  
name_required_idx = 'a name in |name%s= is required',  

empty_list = 'list is empty', -- for  
positional = 'positional parameters not supported',  

br_list = '&lt;br /> lists not allowed', -- for  
list_markup = 'list markup expected for multiple names',  
malformed_param = 'parameter value is malformed',  
}  

local help_links_t = {  
['native name'] = 'help',  
['native name checker'] = 'help',  
['native name list'] = 'help',  
}  

local error_cats_t = {  
['native name'] = '',  
['native name checker'] = '',  
['native name list'] = '',  
}  

----------------------------< E R R O R _ M S G >------------------------------------------------------------  

returns a formatted error message  

local function error_msg (msg, template, index)  
local cat = ((0 == mw.title.getCurrentTitle.namespace) and error_cats_t[template]) or '';  
if index then  
local message = string.format (msg, index);  
return string.format ('<span>Error : %s (%s)</span>%s', template, message, help_links_t[template], cat)  
end  
return string.format ('<span>Error : %s (%s)</span>%s', template, msg, help_links_t[template], cat)  
end  

--[=[-------------------------< _ N A T I V E _ N A M E >------------------------------------------------------  

implements ; entry point from a module  

<args_t> is a table of parameter name/value pairs. Parameters that are supported are:  
args_t[1] - IETF language tag (required)  
args_t[2] - the native name (required)  
args_t.italic - accepts string values 'no' or 'off'; expects 'no' so 'off' must be translated  
args_t.italics - alias of |italic=  
args_t.paren - accepts 'omit', 'off', or 'no'  
args_t.icon - alias of paren  
args_t.parensize -  
args_t.fontsize - deprecated alias of |parensize=  
args_t.nolink - any value inhibits wikilinking of language name  

args_t.suppress_empty_list_error - when set to 'yes', suppresses an 'empty' error message; mostly for use within another template  

this function calls these functions in Module:lang:  
_is_ietf_tag  
_lang  
_name_from_tag  

TODO:  
add support for romanization and transliteration?  
add support for postfix so that 'mis' can render something like this:  

Chotilapacquen (Coahuiltecan)  

]=]  

local function _native_name (args_t)  
local template = (args_t.template and args_t.template) or 'native name'; -- for error messaging; use 'native name list' when called from native_name_list, etc  

if not (args_t[1] or args_t[2]) and yes_no (args_t.suppress_empty_list_error) then  
return ''; -- if empty list error is suppressed, return empty string  
elseif not args_t[1] then  
return error_msg ((args_t.index and messages_t.tag_required_idx) or messages_t.tag_required, template, args_t.index)  
elseif not args_t[2] then  
return error_msg ((args_t.index and messages_t.name_required_idx) or messages_t.name_required, template, args_t.index)  
end  

args_t.italic = args_t.italics or args_t.italic; -- plural form first in but singular form for  
args_t.italic = defined_values.italic[args_t.italic] or nil; -- translate assigned value  
args_t.italics = nil; -- so unset as unneeded  

args_t.paren = args_t.paren or args_t.icon;  
args_t.icon = nil; -- unset as unneeded  

args_t.parensize = args_t.parensize or args_t.fontsize or '100%';  
args_t.fontsize = nil; -- unset as unneeded  

if not lang_module._is_ietf_tag (args_t[1]) then  
args_t[1] = lang_module._tag_from_name ({args_t[1]});  
if args_t[1]:find ('Error') then  
return error_msg ((args_t.index and messages_t.tag_required_idx) or messages_t.tag_required, template, args_t.index)  
end  
end  

local out_t = {};  

table.insert (out_t, lang_module._lang ({args_t[1], args_t[2], ['italic']=args_t.italic, ['template']=template}));  
if not defined_values.paren[args_t.paren] then  
table.insert (out_t, '&nbsp;');  

table.insert (out_t, table.concat ({  
'<span>'}));  

if args_t.nolink then  
table.insert (out_t, table.concat ({'(', lang_module._name_from_tag ({args_t[1], ['template']=template}), ')'}));  
else  
if lang_module._is_ietf_tag (args_t[1]) then  
table.insert (out_t, table.concat ({'(', lang_module._name_from_tag ({args_t[1], ['link'] ='yes', ['template']=template}), ')'}));  
else  
table.insert (out_t, '(language?)'); -- TODO: any reason to keep this?  
end  
end  

table.insert (out_t, '</span>');  
end  

return table.concat (out_t);  
end  

----------------------------< N A T I V E _ N A M E >--------------------------------------------------------  

implements ; entry point from the template  

local function native_name  
return _native_name (getArgs );  
end  

--tag1= required)  
args_t.namen - the native name (|name1= required)  
args_t.italicn - accepts string values 'no' or 'off'  
args_t.italicsn - alias of |italicn=  
args_t.parenn - accepts 'omit', 'off', or 'no'  
args_t.iconn - alias of paren  
args_t.parensizen -  
args_t.fontsizen - deprecated alias of |parensizen=  
args_t.nolinkn - any value inhibits wikilinking of language name  

also supports:  
args_t.postfixn - wikitext to be appended to list item n (references other appropriate text)  
args_t.suppress_empty_list_error - when set to 'yes', suppresses an 'empty list' error message; mostly for use within another template  

local function _native_name_list (args_t)  
if args_t[1] then  
return error_msg (messages_t.positional, 'native name list')  
end  

local unsorted_enumerators_t = {} -- unsorted k/v table of tagn and namen enumerators where k is the enumerator and v is always true  

for param, _ in pairs (args_t) do -- loop through all parameters  
local enumerator = mw.ustring.match (param, "^tag(%d+)$") -- is this a |tagn= parameter? extract enumerator if present  
if enumerator then -- if there is an enumerator  
unsorted_enumerators_t[tonumber(enumerator)] = true -- add enumerator to the table  
else  
local name_match = mw.ustring.match (param, "^name(%d+)$") -- is this a |tagn= parameter? extract enumerator if present  
if name_match then -- if there is an enumerator  
unsorted_enumerators_t[tonumber (name_match)] = true -- add enumerator to the table  
end  
end  
end  

local enumerators_t = {} -- will hold a sorted sequence of enumerators  
for n, _ in pairs (unsorted_enumerators_t) do -- loop through the k/v table of enumerators  
table.insert (enumerators_t, n) -- add the enumerator to the sequence  
end  
table.sort (enumerators_t) -- and ascending sort  

local list_t = {}; -- list of formatted native names goes here  

for _, n in ipairs (enumerators_t) do -- loop through the sorted enumerators  
table.insert (list_t, table.concat ({  
_native_name ({ -- go render the native name  
args_t['tag'..n],  
args_t['name'..n],  
['italic'] = args_t['italic'..n],  
['italics'] = args_t['italics'..n],  
['paren'] = args_t['paren'..n],  
['icon'] = args_t['icon'..n],  
['parensize'] = args_t['parensize'..n],  
['fontsize'] = args_t['fontsize'..n],  
['nolink'] = args_t['nolink'..n],  
['template'] = 'native name list', -- for error messaging  
['index'] = n, -- for error messaging  
}),  
args_t['postfix'..n] or '',  
}));  
end  

if 0 == #list_t then  
return (yes_no (args_t.suppress_empty_list_error) and '') or -- return empty string when error suppressed  
error_msg (messages_t.empty_list, 'native name list'); -- otherwise error  
elseif 1 == #list_t then  
return list_t[1]; -- return the very short list; TODO: add error?  
else  
return require ('Module:List').unbulleted (list_t); -- use unbulleted list from module  
end  
end  

----------------------------< N A T I V E _ N A M E _ L I S T >----------------------------------------------  

implements ; entry point from the template  

local function native_name_list  
return _native_name_list (getArgs );  
end  

--dataxx = }  

inspects rendered content of }:  
expects: at least one lang="<valid IETF tag>" html attribute; tag must begin with 2 or three letters followed  
by a hyphen or double quote character: lang="zh-Hant" or lang="nav" or lang="oj"  
emits error message when 2 or more lang="<valid IETF tag>" html attribute but list markup <li> tag not found  
emits error message if any form of '  
' tag is found per MOS:NOBREAK  

returns:  
nothing when |native_name= is omitted or empty  
assigned value when no error  
error message on error  

local function _native_name_checker (args_t)  
local value = args_t[1];  

if not value then -- if |native_name= is omitted or empty  
return; -- return nothing  
end  

local _, count = value:gsub ('lang="%a%a%a?[%-"]%a*', '%1');  
if 0 == count then  
return table.concat ({value, error_msg (messages_t.malformed_param, 'native name checker')}, ' '); -- no or template  
end  
if 1 < count then  
if not value:find ('<div *>') or not value:find ('</div>$') then -- must be wrapped in 'plainlist' div  
return table.concat ({value, error_msg (messages_t.list_markup, 'native name checker')}, ' ');  
end  
end  

if value:find ('< */? *[Bb][Rr] */? *>') then -- look for something that vaguely resembles a  
tag  
return table.concat ({value, error_msg (messages_t.br_list, 'native name checker')}, ' ');  
end  

return value; -- no failed tests, return the value as is  
end  

----------------------------< N A T I V E _ N A M E _ C H E C K E R >--------------------------------------  

entry point from a module  

implements  

local function native_name_checker  
return _native_name_checker (getArgs );  
end  

----------------------------< E X P O R T S >----------------------------------------------------------------  

return {  
native_name = native_name, -- template interface  
native_name_list = native_name_list,  
native_name_checker = native_name_checker,  

_native_name = _native_name, -- other module interface  
_native_name_list = _native_name_list,  
_native_name_checker = _native_name_checker,  
}