--[=[  
Lua support for the , , , and templates and replacement of various supporting templates.  
]=]  
require('strict');  
local getArgs = require ('Module:Arguments').getArgs;
local unicode = require ("Module:Unicode data"); -- for is_Latin and is_rtl
local yesno = require ('Module:Yesno');  
local lang_data = mw.loadData ('Module:Lang/data'); -- language name override and transliteration tool-tip tables
local lang_name_table = lang_data.lang_name_table; -- language codes, names, regions, scripts, suppressed scripts
local lang_table = lang_data.lang_name_table.lang;
local lang_dep_table = lang_data.lang_name_table.lang_dep;
local script_table = lang_data.lang_name_table.script;
local region_table = lang_data.lang_name_table.region;
local variant_table = lang_data.lang_name_table.variant;
local suppressed_table = lang_data.lang_name_table.suppressed;
local override_table = lang_data.override;  
local synonym_table = mw.loadData ('Module:Lang/ISO 639 synonyms'); -- ISO 639-2/639-2T code translation to 639-1 code  
local cfg = mw.loadData ('Module:Lang/configuration' .. (mw.getCurrentFrame:getTitle:match ('/sandbox') or '')); -- for internationalization  
local is_latn_data = mw.loadData ('Module:Lang/data/is latn data');
local sizeof_ranges_t = is_latn_data.sizeof_ranges_t;  
local namespace = mw.title.getCurrentTitle.namespace; -- used for categorization  
local content_lang = mw.language.getContentLanguage;
local this_wiki_lang_tag = content_lang.code; -- get this wiki's language tag
local this_wiki_lang_dir = content_lang:getDir; -- get this wiki's language direction  
local initial_style_state; -- set by lang_xx_normal and lang_xx_italic  
local maint_cats = {}; -- maintenance categories go here
local maint_msgs = {}; -- and their messages go here  
----------------------------< M A K E _ E R R O R _ S P A N >--------------------------------------------------  
local function make_error_span (template, msg)
return table.concat ({'<span>', cfg.misc_text_t.error, ': ', template, msg, '</span>'})
end  
----------------------------< S U B S T I T U T E >----------------------------------------------------------  
Substitutes $1, $2, etc in <message> with data from <data_t>. Returns plain-text substituted string when
<data_t> not nil; returns <message> else.  
local function substitute (message, data_t)
return data_t and mw.message.newRawMessage (message, data_t):plain or message;
end  
----------------------------< M A K E _ E R R O R _ M S G >--------------------------------------------------  
Assembles an error message from template name, message text, help link, and error category.  
local function make_error_msg (msg, args_t, template)
local category;
local text; -- handle the oddity that is
if cfg.templates_t.langxx == template then
text = args_t.text or args_t[1]; -- for
else
text = args_t.text or args_t[2]; -- for , , and
end  
if cfg.templates_t.transliteration == template then
category = cfg.make_error_msg_t.xlit_err_cat;
else
category = cfg.make_error_msg_t.lang_err_cat;
end  
local category_link = ((0 == namespace or 10 == namespace) and not args_t.nocat) and substitute (*, {category}) or *;
return substitute ('[$1] <span>$2: : $4 ($6)</span>$7',
{
text or cfg.make_error_msg_t.undefined,
cfg.misc_text_t.error,
template,
msg,
category,
cfg.misc_text_t.help,
category_link
})
end  
----------------------------< P A R A M E T E R _ V A L I D A T E >------------------------------------------  
local function parameter_validate (args_t, template)
local err_msg = cfg.parameter_validate_t.invalid_param;  
if cfg.templates_t.lang == template then -- for
for param, _ in pairs (args_t) do
if not cfg.known_params_t.params_lang_t[param] and -- unique parameters
not cfg.known_params_t.common_params_all_t[param] then -- common to all
return substitute (err_msg, {param}); -- <param> not found so abandon
end
end
elseif cfg.templates_t.langx == template then -- for
for param, _ in pairs (args_t) do
if not cfg.known_params_t.params_langx_t[param] and -- unique parameters
not cfg.known_params_t.params_x_t[param] and -- common to and
not cfg.known_params_t.common_params_all_t[param] then -- common to all
return substitute (err_msg, {param}); -- <param> not found so abandon
end
end
elseif cfg.templates_t.langxx == template then -- for
for param, _ in pairs (args_t) do
if not cfg.known_params_t.params_lang_xx_t[param] and -- unique parameters
not cfg.known_params_t.params_x_t[param] and -- common to and
not cfg.known_params_t.common_params_all_t[param] then -- common to all
return substitute (err_msg, {param}); -- <param> not found so abandon
end
end
end
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  
--italic=unset, |italic=invert disables automatic italic markup. Individual leading/trailing
apostrophes are converted to their html numeric entity equivalent so that the new italic markup doesn't become
bold markup inadvertently.  
Leading and trailing wiki markup is extracted from args.text into separate table elements. Addition, removal,
replacement of wiki markup is handled by a string.gsub replacement table operating only on these separate elements.
In the string.gsub matching pattern, '.*' matches empty string as well as the three expected wiki markup patterns.  
This function expects that markup in args.text is complete and correct; if it is not, oddness may result.  
local function invert_italics (source)
local invert_pattern_table = { -- leading/trailing markup add/remove/replace patterns
[""]="\'\'", -- empty string becomes italic markup
["\'\'"]="", -- italic markup becomes empty string
["\'\'\'"]="\'\'\'\'\'", -- bold becomes bold italic
["\'\'\'\'\'"]="\'\'\'", -- bold italic become bold
};
local seg = {};  
source = source:gsub ("%f[\']\'%f[^\']", '&#39;'); -- protect single quote marks from being interpreted as bold markup  
seg[1] = source:match ('^(\'\'+%f[^\']).+') or ''; -- get leading markup, if any; ignore single quote
seg[3] = source:match ('.+(%f[\']\'\'+)$') or ''; -- get trailing markup, if any; ignore single quote  
if * ~= seg[1] and * ~= seg[3] then -- extract the 'text'
seg[2] = source:match ('^\'\'+%f[^\'](.+)%f[\']\'\'+$') -- from between leading and trailing markup
elseif '' ~= seg[1] then
seg[2] = source:match ('^\'\'+%f[^\'](.+)') -- following leading markup
elseif '' ~= seg[3] then
seg[2] = source:match ('(.+)%f[\']\'\'+$') -- preceding trailing markup
else
seg[2] = source -- when there is no markup
end  
seg[1] = invert_pattern_table[seg[1]] or seg[1]; -- replace leading markup according to pattern table
seg[3] = invert_pattern_table[seg[3]] or seg[3]; -- replace leading markup according to pattern table  
return table.concat (seg); -- put it all back together and done
end  
--italic= or |italics= assigned values.  
When |italic= is set and has an acceptible assigned value, return the matching css font-style property value or,
for the special case 'default', return nil.  
When |italic= is not set, or has an unacceptible assigned value, return nil and a nil error message.  
When both |italic= and |italics= are set, returns nil and a 'conflicting' error message.  
The return value nil causes the calling lang, lang_xx, or transl function to set args.italic according to the template's
defined default ('inherit' for , 'inherit' or 'italic' for depending on
the individual template's requirements, 'italic' for ) or to the value appropriate to |script=, if set (
and only).  
Accepted values and the values that this function returns are are:
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'