Mô đun:Nihongo

require('strict');
------------------------------------------------------------------------------
error messaging; keys to this table are the template base names:
	'nihongo', 'nihongo3', 'nihongo krt', 'nihongo foot' → 'nihongo' etc
local err_msg = {
	'nihongo' = 'Yêu cầu văn bản tiếng Nhật hoặc romaji',
	}
local err_cat = {
	'nihongo' = 'Thể loại:Lỗi bản mẫu Nihongo',
	}
--------------------------------------------------------------------------------
configuration setting for the various templates.  keys to this table are the template names without spacing
local cfg = {
	'nihongo' = {
		tag = 'ja',
		system = 'hepburn',
		system_link = 'Hepburn',
		err_msg = err_msg.nihongo,
		err_cat = err_cat.nihongo,
		},
	'nihongo3' = {
		tag = 'ja',
		system = 'hepburn',
		err_msg = err_msg.nihongo,
		err_cat = err_cat.nihongo,
		},
	'nihongo krt' = {
		tag = 'ja',
		system = 'hepburn',
		err_msg = err_msg.nihongo,
		err_cat = err_cat.nihongo,
		},
	'nihongo foot' = {
		tag = 'ja',
		system = 'hepburn',
		system_link = 'Hepburn',
		err_msg = err_msg.nihongo,
		err_cat = err_cat.nihongo,
		},
	}
--------------------------------------------------------------------------------
Creates an error message for , , , and  when these template are missing 
or  inputs; names the offending template, links to template page, and adds article to Category:Nihongo template errors
local function error_message (template)
	local msg = {'error: }: ');
	table.insert (msg, cfgtemplate.err_msg);
	table.insert (msg, ' (trợ giúp)');
	if 0 == mw.title.getCurrentTitle().namespace then
		table.insert (msg, cfgtemplate.err_cat);
	end
	return table.concat (msg);	
end
------------------------------------------------------------------------------------------
Shared support function for nihingo(), nihongo3(), and nihongo_foot().  Calculates an index into formatting{}
from set/unset parameters:
	args1 (english text) has a value of 8 (set) or 0 (unset)
	args2 (native text) has a value of 4
	args3 (romanized text) has a value of 2
	args4 (extra) has a value of 1
index, the sum of these values, gets the appropriate format string from formatting{} table with associated values
from the formattingindex2 table
local function renderer (args, formatting, extra2)
	local output;
	local index = 0;															-- index into formatting{}
	local param_weight = {8, 4, 2, 1};											-- binary parameter weights: 1 = english (8), 2 = japanese (4), 3 = romaji (2), 4 = extra (1)
	for i=1, 5 do																-- spin through args1 – args4
		index = index + (argsi and param_weighti or 0);						-- calculate an index into formatting{}
	end
	output = (0 ~= index) and string.format (formattingindex1 and formattingindex1, formattingindex21, formattingindex22, formattingindex23, formattingindex24) or nil;
	if extra2 then																-- always just attached to the end (if there is an end) so not part of formatting{}
		output = output and (output .. ' ' .. extra2) or  .. extra2;	--  and : place holders for font-weight style spans; akin to stripmarkers, to be replaced
	end																			-- (nihongo and nihongo3) or removed (nihongo foot)
	return output and (output .. ) or ;								-- where there is output, add secret tag close
end
------------------------------------------------------------------------------
Add kerning when first or last character of romanized text contacts adjacent opening or closing paranthesis
In this example, without kerning, the romanized characters 'j' and 'V' are italicized so will contact the parentheses
	(jV)
is the formatted template output (except that the magic string  has not yet been replaced)
is the return from lang_module._transl() so is not wrapped in parentheses
local function romanized_kern (ret_string, romanized)
	if not romanized or ( == romanized) then									-- if romanized not set
		return ret_string;														-- then we're done
	end
	local romanized_text = romanized:gsub ('%b', ):gsub ('\'\'+', ):gsub ('%%', ):gsub ('%%', );	-- strip html tags
	romanized = romanized:gsub ('(%(%)%.%%%+%-%*%?%%^%$%)', '%%%1');				-- escape lua pattern characters
	local romanized_has_leading_paren = ret_string:match ('%(' .. romanized);			-- has a value if (; nil else
	local romanized_has_trailing_paren = ret_string:match (romanized .. '%)');		-- has a value if ); nil else
	local kern_lead_pattern = '^jpy';											-- list of characters that when italicized contact unitalicized leading parenthesis
	local kern_tail_pattern = 'dfijkltCEFHIJKMNPR-Z\'"%?!%$';				-- list of characters that when italicized contact unitalicized trailing parenthesis
	local kern_right = '(%1';			-- %1 is  capture
	local kern_left = '%1)';				-- %1 is  capture
	if romanized_has_leading_paren and romanized_text:match (kern_lead_pattern) then
		ret_string = ret_string:gsub ('%((' .. romanized .. ')', kern_right);		-- replace plain '(' with kerned '(';  included here to ensure that the correct '(' is kerned
	end
	if romanized_has_trailing_paren and romanized_text:match (kern_tail_pattern) then
		ret_string = ret_string:gsub ('(' .. romanized .. ')%)', kern_left);		-- replace plain ')' with kerned ')';  included here to ensure that the correct ')' is kerned
	end
	return ret_string;															-- done
end
----------------------------------------------------------------------------------------------
Common support for 
render order: is translated (English), native, romanized
is used to select the appropriate cfg table
local function common (frame, template)
	local lang_module = require ('Module:Lang' .. (frame:getTitle():match ('/sandbox') or ));	-- if this module is the sandbox, use Module:lang/sandbox; Module:Lang else
	local args = require ('Module:Arguments').getArgs (frame);
	
	local english, native, romanized, extra, extra2 = args1, args2, args3, args.extra or args4, args.extra2 or args5;	-- meaningful names
	args4 = extra or args4;													-- ensure that extra is 'positional' for use by renderer()
	local lead = 'yes' == args.lead;											-- make boolean
	if not (native or romanized) then											-- not present, return an error message
		return error_message (template);
	end
	if native then
		native = lead and lang_module._langx ({'code'=cfgtemplate.tag, 'text'=native, 'template'=template}) or
			lang_module._lang ({cfgtemplate.tag, native, 'template'=template});	-- add ja script with/without language prefix
	end
	if romanized then
		romanized = (lead and english and (cfgtemplate.system_link .. ': ') or ) .. lang_module._transl ({'ja', cfgtemplate.system, romanized, 'template'=template}) or nil;
	end
	local formatting = {														--  and : place holders for font-weight style spans; akin to stripmarkers, replaced  before function returns
		{'(%s)', {extra}}, 												-- 1 - (extra)
		{'%s', {romanized}},												-- 2 - romanized
		{'%s (%s)', {romanized, extra}},									-- 3 - romanized (extra)
		{'(%s)', {native}},												-- 4 - native
		{'(%s, %s)', {native, extra}},									-- 5 - (native, extra)
		{'%s (%s)', {romanized, native}},									-- 6 - romanized (native)
		{'%s (%s, %s)', {romanized, native, extra}},						-- 7 - romanized (native, extra)
		{'%s', {english}},												-- 8 - english
		{'%s (%s)', {english, extra}},									-- 9 - english (extra)
		{'%s (%s)', {english, romanized}},								-- 10 - english (romanized)
		{'%s (%s, %s)', {english, romanized, extra}},						-- 11 - english (romanized, extra)
		{'%s (%s)', {english, native}},									-- 12 - english (native)
		{'%s (%s, %s)', {english, native, extra}},						-- 13 - english (native, extra)
		{'%s (%s, %s)', {english, native, romanized}},					-- 14 - english (native, romanized)
		{'%s (%s, %s, %s)', {english, native, romanized, extra}},			-- 15 - english (native, romanized, extra)
		}
	local ret_string = renderer (args, formatting, extra2)
	ret_string = romanized_kern (ret_string, romanized);						-- kern romanized text when appropriate
	ret_string = ret_string:gsub (, ):gsub (, );	-- replace 'secret' tags with proper tags
	return ret_string;															-- because gsub returns the number of replacements made as second return value
end
--------------------------------------
Common support for 
render order: is romanized, native, translated (English)
is used to select the appropriate cfg table
local function common_romanized_native_translated (frame, template)
	local lang_module = require ('Module:Lang' .. (frame:getTitle():match ('/sandbox') or ));	-- if this module is the sandbox, use Module:lang/sandbox; Module:Lang else
	local args = require ('Module:Arguments').getArgs (frame);
	
	local english, native, romanized, extra, extra2 = args1, args2, args3, args.extra or args4, args.extra2 or args5;	-- meaningful names
	args4 = extra or args4;													-- ensure that extra is 'positional' for use by renderer()
	if not (native or romanized) then											-- not present, return an error message
		return error_message (template);
	end
	native = native and lang_module._lang ({cfgtemplate.tag, native, 'template'=template}) or nil;
	romanized = romanized and lang_module._transl ({cfgtemplate.tag, cfgtemplate.system, romanized, 'template'=template}) or nil;
	
	local formatting = {														--  and : place holders for font-weight style spans; akin to stripmarkers, replaced  before function returns
		{'(%s)', {extra}}, 												-- 1 - (extra)
		{'%s', {romanized}},												-- 2 - romanized
		{'%s (%s)', {romanized, extra}},									-- 3 - romanized (extra)
		{'(%s)', {native}},												-- 4 - native
		{'(%s, %s)', {native, extra}},									-- 5 - (native, extra)
		{'%s (%s)', {romanized, native}},									-- 6 - romanized (native)
		{'%s (%s, %s)', {romanized, native, extra}},						-- 7 - romanized (native, extra)
		{'%s', {english}},												-- 8 - english
		{'%s (%s)', {english, extra}},									-- 9 - english (extra)
		{'%s (%s)', {romanized, english}},								-- 10 - romanized (english)
		{'%s (%s, %s)', {romanized, english, extra}},						-- 11 - romanized (english, extra)
		{'%s (%s)', {english, native}},									-- 12 - english (native)
		{'%s (%s, %s)', {english, native, extra}},						-- 13 - english (native, extra)
		{'%s (%s, %s)', {romanized, native, english}},					-- 14 - romanized (native, english)
		{'%s (%s, %s, %s)', {romanized, native, english, extra}},			-- 15 - romanized (native, english, extra)
		}
	local ret_string = renderer (args, formatting, extra2)
	ret_string = ret_string:gsub (, ):gsub (, );	-- replace 'secret' tags with proper tags
	return ret_string;															-- because gsub returns the number of replacements made as second return value
end
--------------------------------------
Common support for 
render order: is native, romanized, translated (English)
is used to select the appropriate cfg table
local function common_native_romanized_translated (frame, template)
	local lang_module = require ('Module:Lang' .. (frame:getTitle():match ('/sandbox') or ));	-- if this module is the sandbox, use Module:lang/sandbox; Module:Lang else
	local args = require ('Module:Arguments').getArgs (frame);
	
	local english, native, romanized, extra, extra2 = args1, args2, args3, args.extra or args4, args.extra2 or args5;	-- meaningful names
	args4 = extra or args4;													-- ensure that extra is 'positional' for use by renderer()
	if not (native or romanized) then											-- not present, return an error message
		return error_message (template);
	end
	native = native and lang_module._lang ({cfgtemplate.tag, native, 'template'=template}) or nil;
	romanized = romanized and lang_module._transl ({cfgtemplate.tag, cfgtemplate.system, romanized, 'template'=template}) or nil;
	
	local formatting = {														--  and : place holders for font-weight style spans; akin to stripmarkers, replaced  before function returns
		{'(%s)', {extra}}, 												-- 1 - (extra)
		{'%s', {romanized}},												-- 2 - romanized
		{'%s (%s)', {romanized, extra}},									-- 3 - romanized (extra)
		{'%s', {native}},													-- 4 - native
		{'%s (%s)', {native, extra}},										-- 5 - native (extra)
		{'%s (%s)', {native, romanized}},									-- 6 - native (romanized)
		{'%s (%s, %s)', {native, romanized, extra}},						-- 7 - native (romanized, extra)
		{'%s', {english}},												-- 8 - english
		{'%s (%s)', {english, extra}},									-- 9 - english (extra)
		{'%s (%s)', {romanized, english}},								-- 10 - romanized (english)
		{'%s (%s, %s)', {romanized, english, extra}},						-- 11 - romanized (english, extra)
		{'%s (%s)', {native, english}},									-- 12 - native (english)
		{'%s (%s, %s)', {native, english, extra}},						-- 13 - native (english, extra)
		{'%s (%s, %s)', {native, romanized, english}},						-- 14 - native (romanized, english)
		{'%s (%s, %s, %s)', {native, romanized, english, extra}},			-- 15 - native (romanized, english, extra)
		}
	local ret_string = renderer (args, formatting, extra2)
	ret_string = romanized_kern (ret_string, romanized);						-- kern romanized text when appropriate
	ret_string = ret_string:gsub (, ):gsub (, );	-- replace 'secret' tags with proper tags
	return ret_string;															-- because gsub returns the number of replacements made as second return value
end
------------------------------------------------------------------------------------
Common support for 
render order: is English
is used to select the appropriate cfg table
local function common_foot (frame, template)
	local lang_module = require ('Module:Lang' .. (frame:getTitle():match ('/sandbox') or ));	-- if this module is the sandbox, use Module:lang/sandbox; Module:Lang else
	local args = require ('Module:Arguments').getArgs (frame);
	
	local english, native, romanized, extra, extra2 = args1, args2, args3, args.extra or args4, args.extra2 or args5;	-- meaningful names
	args4 = extra or args4;													-- ensure that extra is 'positional' for use by renderer()
	local post = args6 or args.post;
	local group = args.group;
	local ref_name = args.ref_name
	local lead = 'yes' == args.lead;											-- make boolean
	if not (native or romanized) then											-- not present, return an error message
		return error_message (template);
	end
	if native then
		native = lead and lang_module._langx ({'code'=cfgtemplate.tag, 'text'=native, 'template'=template}) or
			lang_module._lang ({cfgtemplate.tag, native, 'template'=template});	-- add ja script with/without language prefix
	end
	if romanized then
		romanized = (lead and (cfgtemplate.system_link .. ': ') or ) .. lang_module._transl ({'ja', cfgtemplate.system, romanized, 'template'=template}) or nil;
	end
	
	local formatting = {
		{'%s', {extra}}, 														-- 1 - extra
		{'%s', {romanized}},													-- 2 - romanized
		{'%s, %s', {romanized, extra}},											-- 3 - romanized, extra
		{'%s', {native}},														-- 4 - native
		{'%s, %s', {native, extra}},											-- 5 - native, extra
		{'%s, %s', {native, romanized}},										-- 6 - native romanized
		{'%s, %s, %s', {native, romanized, extra}},								-- 7 - native romanized, extra
																				-- from here english is used in the mapping but not rendered by renderer so not included in the table
		{, {}},																-- 8 - english
		{'%s', {extra}},														-- 9 - extra
		{'%s', {romanized}},													-- 10 - romanized
		{'%s, %s', {romanized, extra}},											-- 11 - romanized, extra
		{'%s', {native}},														-- 12 - native
		{'%s, %s', {native, extra}},											-- 13 - native, extra
		{'%s, %s', {native, romanized}},										-- 14 - native romanized
		{'%s, %s, %s', {native, romanized, extra}},								-- 15 - native romanized, extra
		}
	if english and post then													-- rewrite english to include |post=
		english = english .. post;												-- if english has a value append post else just post
	elseif post then
		english = post;															-- english not set, use post
	elseif not english then														-- neither are set
		english = ;															-- make english an empty string for concatenation
	end
	if native or romanized or extra or extra2 then								-- no ref tag when none of these are set (it would be empty)
		local content = renderer (args, formatting, extra2);
		content = content:gsub (, ):gsub ('$', , 1);			-- strip secret  and  tags added by renderer(); spans not used by this template
		if english:match ('\'\'+$') then										-- if  is italic, bold, or both
			local text = english:gsub ('%b', ):gsub ('\'\'+', ):gsub ('%%', ):gsub ('%%', );	-- strip markup
			if text:match ('dfijkltCEFHIJKMNPR-Z\'"%?!%$') then				-- when  ends with one of these characters
				english =   .. english .. ;	-- add kerning
			end
		end
		return english .. frame:extensionTag ({name='ref', args={group=group, name=ref_name}, content=content});	-- english with attached reference tag
	else
		return english;															-- nothing to be inside ref tag so just return english
	end
end
--=-----------------------------------------------------------------------------------------
Implement  using Module:Lang for language and transliteration markup
, , and  are positional parameters
	: rendered as presented; purports to be English translation of 
	: Japanese language text using Japanese script; TODO: require?
	: Hepburn romanization (transliteration); TODO: in Module:Lang/data change tooltip text to 'Hepburn romanization'?
and  are positional or named: |extra= and |extra2=; mixing can be problematic
	 is rendered as presented preceeded with 
	 is rendered as presented preceeded with 
lead=: takes one value 'yes'; renders language name same as ja but also adds Hepburn: ahead of the romanization; TODO: in Module:Lang, turnoff tooltip for transl when |lead=yes
**
local function nihongo (frame)
	return common (frame, 'nihongo')
end
--=extra2=; mixing can be problematic
	 is rendered as presented preceeded with 
	 is rendered as presented preceeded with 
**
local function nihongo3 (frame)
	return common_romanized_native_translated (frame, 'nihongo3')
end
--=extra2=; mixing can be problematic
	 is rendered as presented preceeded with 
	 is rendered as presented preceeded with 
**
local function nihongo_krt (frame)
	return common_native_romanized_translated (frame, 'nihongo krt')
end
--=-------------------------------------------------------------------------------
Implement  using Module:Lang for language and transliteration markup
, , and  are positional parameters
	: rendered as presented; purports to be English translation of 
	: Japanese language text using Japanese script; TODO: require?
	: Hepburn romanization (transliteration); TODO: in Module:Lang/data change tooltip text to 'Hepburn romanization'?
and  are positional or named: |extra= and |extra2=; mixing can be problematic
	 is rendered as presented preceeded with 
	 is rendered as presented preceeded with 
is positional or named: |post= is a postscript character preceding the  tag (after )
lead=: takes one value 'yes'; renders language name same as ja but also adds Hepburn: ahead of the romanization;
	TODO: in Module:Lang, turnoff tooltip for transl when |lead=yes
	in the live template |lead= also adds the Help:Installing Japanese character sets link; this is not supported in this code (nihongo nor nihongo3 have this support)
group=: the group attribute in  and in 
**
local function nihongo_foot (frame)
	return common_foot (frame, 'nihongo foot')
end
----------------------------------------------------------------------
return {
	nihongo = nihongo,
	nihongo3 = nihongo3,
	nihongo_krt = nihongo_krt,
	nihongo_foot = nihongo_foot,
	}