nil - when |italic= absent or not set; returns nil
default - for completeness, should rarely if ever be used; returns nil
yes - force args.text to be rendered in italic font; returns 'italic'
no - force args.text to be rendered in normal font; returns 'normal'
unset - disables font control so that font-style applied to text is dictated by markup inside or outside the template; returns 'inherit'
invert - disables font control so that font-style applied to text is dictated by markup outside or inverted inside the template; returns 'invert'  
local function validate_italic (args)
local properties = {[cfg.keywords_t.affirmative] = 'italic', [cfg.keywords_t.negative] = 'normal', [cfg.keywords_t.unset] = 'inherit', [cfg.keywords_t.invert] = 'invert', [cfg.keywords_t.default] = nil};  
local count = 0
for _, arg in pairs {'italic', 'italics', 'i'} do
if args[arg] then
count = count + 1
end
end  
if count > 1 then -- return nil and an error message if more than one is set
return nil, cfg.validate_italic_t.multi_italic;
end  
return properties[args.italic or args.italics or args.i], nil; -- return an appropriate value and a nil error message
end  
--[=[--------------------------< V A L I D A T E _ C A T _ A R G S >----------------------------------------------------------  
Default behavior of the and templates is to add categorization when the templates are used in mainspace.
This default functionality may be suppressed by setting |nocat=yes or |cat=no. This function selects one of these two parameters
to control categorization.  
Because having two parameters with 'opposite' names and 'opposite' values is confusing, this function accepts only affirmative
values for |nocat= and only negative values for |cat=; in both cases the 'other' sense (and non-sense) is not accepted and the
parameter is treated as if it were not set in the template.  
Sets args.nocat to true if categorization is to be turned off; to nil if the default behavior should apply.  
Accepted values for |nocat= are the text strings:
'yes', 'y', 'true', 't', on, '1' -- Module:Yesno returns logical true for all of these; false or nil else
for |cat=
'no', 'n', 'false', 'f', 'off', '0' -- Module:Yesno returns logical false for all of these; true or nil else  
]=]  
local function validate_cat_args (args)
if not (args.nocat or args.cat) then -- both are nil, so categorize
return;
end  
if false == yesno (args.cat) or true == yesno (args.nocat) then
args.nocat = true; -- set to true when args.nocat is affirmative; nil else (as if the parameter were not set in the template)
else -- args.nocat is the parameter actually used.
args.nocat = nil;
end
end  
----------------------------< I N _ A R R A Y >--------------------------------------------------------------  
Whether needle is in haystack.  
local function in_array (needle, haystack)
if needle == nil then
return false;
end
for n,v in ipairs (haystack) do
if v == needle then
return n;
end
end
return false;
end  
----------------------------< F O R M A T _ I E T F _ T A G >------------------------------------------------  
Prettify ietf tags to use recommended subtag formats:
code: lower case
script: sentence case
region: upper case
variant: lower case
private: lower case prefixed with -x-  
local function format_ietf_tag (code, script, region, variant, private)
local out = {};  
if is_set (private) then
return table.concat ({code:lower, 'x', private:lower}, '-'); -- if private, all other tags ignored
end  
table.insert (out, code:lower);
if is_set (script) then
script = script:lower:gsub ('^%a', string.upper);
table.insert (out, script);
end  
if is_set (region) then
table.insert (out, region:upper);
end  
if is_set (variant) then
table.insert (out, variant:lower);
end  
return table.concat (out, '-');
end  
--script=, |region=, and |variant= are supported (not supported in
because those parameters are superfluous to the IETF subtags in |code=).  
Returns six values; all lower case. Valid parts are returned as themselves; omitted parts are returned as empty strings, invalid
parts are returned as nil; the sixth returned item is an error message (if an error detected) or nil.  
See http://www.rfc-editor.org/rfc/bcp/bcp47.txt section 2.1.  
local function get_ietf_parts (source, args_script, args_region, args_variant)
local code, script, region, variant, private; -- ietf tag parts  
if not is_set (source) then
return nil, nil, nil, nil, nil, cfg.get_ietf_parts_t.missing_lang_tag;
end  
local pattern = { -- table of tables holding acceptibe ietf tag patterns and short names of the ietf part captured by the pattern
{'^(%a%a%a?)%-(%a%a%a%a)%-(%a%a)%-(%d%d%d%d)$', 's', 'r', 'v'}, -- 1 - ll-Ssss-RR-variant (where variant is 4 digits)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d)%-(%d%d%d%d)$', 's', 'r', 'v'}, -- 2 - ll-Ssss-DDD-variant (where region is 3 digits; variant is 4 digits)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%a%a)%-(%w%w%w%w%w%w?%w?%w?)$', 's', 'r', 'v'}, -- 3 - ll-Ssss-RR-variant (where variant is 5-8 alnum characters)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d)%-(%w%w%w%w%w%w?%w?%w?)$', 's', 'r', 'v'}, -- 4 - ll-Ssss-DDD-variant (where region is 3 digits; variant is 5-8 alnum characters)  
{'^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d%d)$', 's', 'v'}, -- 5 - ll-Ssss-variant (where variant is 4 digits)
{'^(%a%a%a?)%-(%a%a%a%a)%-(%w%w%w%w%w%w?%w?%w?)$', 's', 'v'}, -- 6 - ll-Ssss-variant (where variant is 5-8 alnum characters)  
{'^(%a%a%a?)%-(%a%a)%-(%d%d%d%d)$', 'r', 'v'}, -- 7 - ll-RR-variant (where variant is 4 digits)
{'^(%a%a%a?)%-(%d%d%d)%-(%d%d%d%d)$', 'r', 'v'}, -- 8 - ll-DDD-variant (where region is 3 digits; variant is 4 digits)
{'^(%a%a%a?)%-(%a%a)%-(%w%w%w%w%w%w?%w?%w?)$', 'r', 'v'}, -- 9 - ll-RR-variant (where variant is 5-8 alnum characters)
{'^(%a%a%a?)%-(%d%d%d)%-(%w%w%w%w%w%w?%w?%w?)$', 'r', 'v'}, -- 10 - ll-DDD-variant (where region is 3 digits; variant is 5-8 alnum characters)  
{'^(%a%a%a?)%-(%d%d%d%d)$', 'v'}, -- 11 - ll-variant (where variant is 4 digits)
{'^(%a%a%a?)%-(%w%w%w%w%w%w?%w?%w?)$', 'v'}, -- 12 - ll-variant (where variant is 5-8 alnum characters)  
{'^(%a%a%a?)%-(%a%a%a%a)%-(%a%a)$', 's', 'r'}, -- 13 - ll-Ssss-RR
{'^(%a%a%a?)%-(%a%a%a%a)%-(%d%d%d)$', 's', 'r'}, -- 14 - ll-Ssss-DDD (region is 3 digits)  
{'^(%a%a%a?)%-(%a%a%a%a)$', 's'}, -- 15 - ll-Ssss  
{'^(%a%a%a?)%-(%a%a)$', 'r'}, -- 16 - ll-RR
{'^(%a%a%a?)%-(%d%d%d)$', 'r'}, -- 17 - ll-DDD (region is 3 digits)  
{'^(%a%a%a?)$'}, -- 18 - ll  
{'^(%a%a%a?)%-x%-(%w%w?%w?%w?%w?%w?%w?%w?)$', 'p'}, -- 19 - ll-x-pppppppp (private is 1-8 alnum characters)
}  
local t = {}; -- table of captures; serves as a translator between captured ietf tag parts and named variables  
for i, v in ipairs (pattern) do -- spin through the pattern table looking for a match
local c1, c2, c3, c4; -- captures in the 'pattern' from the pattern table go here  
c1, c2, c3, c4 = source:match (pattern[i][1]); -- one or more captures set if source matches pattern[i])
if c1 then -- c1 always set on match
code = c1; -- first capture is always code
t = {
[pattern[i][2] or 'x'] = c2, -- fill the table of captures with the rest of the captures
[pattern[i][3] or 'x'] = c3, -- take index names from pattern table and assign sequential captures
[pattern[i][4] or 'x'] = c4, -- index name may be nil in pattern[i] table so "or 'x'" spoofs a name for this index in this table
};
script = t.s or ''; -- translate table contents to named variables;
region = t.r or ''; -- absent table entries are nil so set named ietf parts to empty string for concatenation
variant= t.v or '';
private = t.p or '';
break; -- and done
end
end  
if not code then
return nil, nil, nil, nil, nil, substitute (cfg.get_ietf_parts_t.unrecog_tag, {source}); -- don't know what we got but it is malformed
end  
code = code:lower; -- ensure that we use and return lower case version of this  
if not (override_table[code] or lang_table[code] or synonym_table[code] or lang_dep_table[code]) then