Module:jje-pron

Hello, you have come here looking for the meaning of the word Module:jje-pron. In DICTIOUS you will not only get to know all the dictionary meanings for the word Module:jje-pron, but we will also tell you about its etymology, its characteristics and you will know how to say Module:jje-pron in singular and plural. Everything you need to know about the word Module:jje-pron you have here. The definition of the word Module:jje-pron will help you to be more precise and correct when speaking or writing your texts. Knowing the definition ofModule:jje-pron, as well as those of other words, enriches your vocabulary and provides you with more and better linguistic resources.

This module is in beta stage.
Its interface has been stabilised, but the module may still contain errors. Do not deploy widely until the module has been tested.

Korean pronunciation and romanisation module. Generates Revised Romanisation (RR), phonetic hangul (ph), Yale romanisation (yr), WT-revised Revised Romanisation (rrr) and IPA phonemic (ipa-p) & IPA phonetic (ipa) for now.

Data is stored at Module:jje-pron/data.

See {{jje-IPA}}.


local export = {}

local m_data = mw.loadData("Module:jje-pron/data")
local m_jje_utilities = require("Module:jje")
local m_str_utils = require("Module:string utilities")

-- Created from Module:ko.pron 

local codepoint = m_str_utils.codepoint
local concat = table.concat
local floor = math.floor
local gmatch = m_str_utils.gmatch
local gsub = m_str_utils.gsub
local insert = table.insert
local len = m_str_utils.len
local match = m_str_utils.match
local pattern_escape = m_str_utils.pattern_escape
local remove = table.remove
local sub = m_str_utils.sub
local toNFC = mw.ustring.toNFC
local u = m_str_utils.char
local upper = m_str_utils.upper

local trackfn = require("Module:debug").track

local function track(page)
	trackfn("jje-pron/" .. page)
	return true
end

local PAGENAME = mw.loadData("Module:headword/data").pagename

local system_lookup = {
	 = 1,  = 2,  = 3,
	 = 4,  = 5,  = 6,
}

local question_mark = "<sup><small>]</small></sup>"

local system_list = {
	{ 
		abbreviation = "ph", 
		display = "Phonetic hangul: ", 
		separator = "/",
	},
	{ 
		abbreviation = "rr", 
		display = "Revised Romanization" .. question_mark, 
		separator = "/",
	},
	{ 
		abbreviation = "rrr", 
		display = "Revised Romanization (translit.)" .. question_mark, 
		separator = "/"
	},
	{ 
		abbreviation = "yr", 
		display = "Yale Romanization" .. question_mark,
		separator = "/"
	},
	{
		abbreviation = "ipa-p",
		display = "(<i>Morphophonemic</i>) ]<sup>(])</sup>: ", 
		separator = " ~ "
	},
	{ 
		abbreviation = "ipa", 
		display = "(<i>]</i>) ]<sup>(])</sup>: ", 
		separator = " ~ "
	}
}

--[[

vowel_variation:
	rules for vowel transformation.
	key:
		the number of a syllable's vowel (vowel_id):
			floor(((codepoint('가') - 0xAC00) % 588) / 28) = 0
			floor(((codepoint('개') - 0xAC00) % 588) / 28) = 1
	value:
		an integer that is added to the decimal codepoint of the syllable
				u(codepoint('개') + 112) = '게'

allowed_vowel_scheme:
	a list of which systems vowel transformation is reflected in.
	key:
		vowel_id .. "-" .. system_index
		system_index: see system_list above. IPA is #6
	value:
		1, representing true

]]

local final_syllable_conversion = {  = "Ø",  = "" }
local com_mc = {  = "k",  = "t",  = "p",  = "ch",  = "s",  = "ss" }
local com_ph = {  = "ᄁ",  = "ᄄ",  = "ᄈ",  = "ᄊ",  = "ᄍ" }
local vowel_variation = {
	 = 112,  -- 개→게

	 = -56,  -- 계→게
}
local allowed_vowel_scheme = {
	 = 1,
	 = 1,

	 = 1,
	 = 1,
}
local ambiguous_intersyllabic_rr = {  = 1,  = 1,  = 1,  = 1,  = 1 }
local ambiguous_intersyllabic_mr = {  = 1,  = 1 }

local function decompose_syllable(word)
	local decomposed_syllables = {}
	for syllable in mw.text.gsplit(word, "") do
		insert(decomposed_syllables, m_jje_utilities.decompose_jamo(syllable))
	end
	return decomposed_syllables
end

local function tidy_phonetic(original, romanised)
	local ori_index, rom_index, result = 1, 1, {}
	for i = 1, len(romanised) do
		local romanised_syllable = sub(romanised, rom_index, rom_index)
		local original_syllable = sub(original, ori_index, ori_index)
		if romanised_syllable ~= original_syllable then
			-- Handle cases of non-precomposed choseong character changing
			if match(romanised_syllable, "") then 
				-- Insert choseong
				insert(result, '<b>'..romanised_syllable..'</b>')
				
				-- Insert jungseong
				romanised_syllable = sub(romanised, rom_index + 1, rom_index + 1)
				insert(result, '<b>'..romanised_syllable..'</b>')
				
				-- Check if next character is jongseong; if so, insert, if not end iteration
				-- and continue accoringly
				romanised_syllable = sub(romanised, rom_index + 2, rom_index + 2)
				if match(romanised_syllable, "") then 
					insert(result, '<b>'..romanised_syllable..'</b>')
					ori_index, rom_index = ori_index + 2, rom_index + 2
					if match(original_syllable, "") then rom_index = rom_index + 1 end
					if match(romanised_syllable, "") then ori_index = ori_index + 1 end
				else
					ori_index, rom_index = ori_index + 1, rom_index + 1
					if match(original_syllable, "") then rom_index = rom_index + 1 end
					if match(romanised_syllable, "") then ori_index = ori_index + 1 end
				end
				
			-- Handle cases of non-precomposed jongseong character changing
			elseif match(romanised_syllable, "") then 
			-- 	-- Remove previous non-bold choseong & jungseong
				remove(result, #result - 1)
				remove(result, #result)
				
			-- 	-- Insert choseong character
				romanised_syllable_cho = sub(romanised, rom_index - 2, rom_index - 2)
				insert(result, '<b>'..romanised_syllable_cho..'</b>')
				
			-- 	-- Insert jungseong character
				romanised_syllable_jung = sub(romanised, rom_index - 1, rom_index - 1)
				insert(result, '<b>'..romanised_syllable_jung..'</b>')
				
			-- 	-- Insert jongseong character
				insert(result, '<b>'..romanised_syllable..'</b>')
				if match(original_syllable, "") then rom_index = rom_index + 1 end
				if match(romanised_syllable, "") then ori_index = ori_index + 1 end
				
			-- Handle precomposed characters per typical method
			else
				insert(result, '<b>'..romanised_syllable..'</b>')
				if match(original_syllable, "") then rom_index = rom_index + 1 end
				if match(romanised_syllable, "") then ori_index = ori_index + 1 end
			end
		else
			insert(result, '<span>'..romanised_syllable..'</span>')
			ori_index, rom_index = ori_index + 1, rom_index + 1
		end
	end
	return concat(result)
end

local function tidy_ipa(ipa)
	ipa = gsub(ipa, "ʌ̹ː", "ɘː")
	ipa = gsub(ipa, "ɭɭ()", "ʎʎ%1")
	ipa = gsub(ipa, "s()ɥi" ,"ʃ%1ɥi")
	ipa = gsub(ipa, "ss͈()" ,"ɕɕ͈%1")
	ipa = gsub(ipa, "s()()" ,"ɕ%1%2")
	ipa = gsub(ipa, "nj", "ɲj")
	ipa = gsub(ipa, "()(?)j", "%1%2")
	
	ipa = gsub(ipa, "kʰ", { 
		 = "kçi", 
		 = "kçj", 
		 = "kxɯ" }
	)
	ipa = gsub(ipa, "", {
		 = "çi",
		 = "çj",
		 = "xɯ",
		 = "ɸʷo",
		 = "ɸʷu",
		 = "ɸw",
		 = "ʝi",
		 = "ʝj",
		 = "ɣɯ",
		 = "βo",
		 = "βu",
		 = "βw" }
	)
	
	if match(ipa, "ɥi") then
		local midpoint = floor(len(ipa) / 2)
		ipa = sub(ipa, 1, midpoint) .. gsub(sub(ipa, midpoint+1, -1), "ɥi", "y")
	end
	
	return ipa
end

function export.romanise(text_param, system_index, args)
	if type(text_param) == "table" then
		args = text_param:getParent().args
		system_index = args or 2
		text_param = args
	end
	local p, optional_params = {}, { "nn", "l", "com", "cap", "ni" }
	for _, pm in ipairs(optional_params) do
		p = { }
		if args then
			for pp in mw.text.gsplit(args, ",") do p = 1 end
		end
	end
		
	local vowel_ui_i, vowel_ui_e, no_batchim, batchim_reduce, s_variation, iotation, yeo_reduce = 
		args.ui, args.uie, args.nobc, args.bcred, args.svar, args.iot, args.yeored
	
	system_index = system_lookup or system_index
	text_param = gsub(text_param, '(.)', "%1")
	
	for primitive_word in gmatch(text_param, "+") do
		local the_original = primitive_word
		primitive_word = gsub(primitive_word, "'''", "ß")
		local formatting_position, formatting_count = {}, 0
		primitive_word = gsub(primitive_word, "()()", function(m1, m2)
			formatting_position = m2 == "ß" and "'''" or m2
			return ""
		end)
		
		local has_vowel = {}
		for ch in gmatch(primitive_word, ".") do
			local jungseong = floor(((codepoint(ch) - 0xAC00) % 588) / 28)
			if not match(ch, "") and match(ch, "") then has_vowel = true end
		end
		local word_set = { primitive_word }
		
		local function add_respelling(variable, modification, modification2)
			modification2 = modification2 or function(x) return x end
			if variable and match(system_index, "") then
				variable = tonumber(variable)
				local pre_length = #word_set
				for i = 1, pre_length do
					local item = mw.text.split(word_set, "")
					item = modification(item)
					item = modification2(item)
					word_set = concat(item)
				end
			end
		end
		add_respelling(vowel_ui_i, function(x) return "이" end)
		add_respelling(vowel_ui_e, function(x) return "에" end)
		
		add_respelling(no_batchim, 
			function(x) return u(codepoint(x) - (codepoint(x) - 0xAC00) % 28) end, 
			function(y) return u(codepoint(y) + 588) end)
		
		add_respelling(s_variation, function(x) return u(codepoint(x) - 12) end)
		add_respelling(iotation, function(x) return u(codepoint(x) + 56) end)
		add_respelling(yeo_reduce, function(x) return u(codepoint(x) - 56) end)
		
		for vowel_id, vowel_variation_increment in pairs(vowel_variation) do
			if has_vowel and allowed_vowel_scheme then
				local pre_length = #word_set
				for i = 1, pre_length do
					local item = mw.text.split(word_set, "")
					for num, it in ipairs(item) do
						if floor(((codepoint(it) - 0xAC00) % 588) / 28) == vowel_id then
							item = u(codepoint(it) + vowel_variation_increment)
						end
					end
					if vowel_id == 11 then
						insert(word_set, i, concat(item))
					else
						insert(word_set, concat(item))
					end
				end
			end
		end
		
		local word_set_romanisations = {}
		for _, respelling in ipairs(word_set) do
			local decomposed_syllables = decompose_syllable(respelling)
			local romanisation = {}
			local formatting_insert_count = 0
			for index = 0, #decomposed_syllables, 1 do
				local this_syllable_text = index ~= 0 and sub(respelling, index, index) or ""
				if this_syllable_text == "-" then
					-- skip it, it will be handled below
				else
					local syllable = decomposed_syllables or { initial = "Ø", vowel = "Ø", final = "X" }
					local next_index = index
					local next_syllable_text
					local saw_hyphen_after = false
					while true do
						next_index = next_index + 1
						next_syllable_text = next_index > #decomposed_syllables and "" or sub(respelling, next_index, next_index)
						if next_syllable_text ~= "-" then
							break
						end
						saw_hyphen_after = true
					end
					local next_syllable = decomposed_syllables or { initial = "Ø", vowel = "Ø", final = "Ø" }
					syllable.final = final_syllable_conversion or syllable.final
					
					if system_index == 4 and syllable.vowel == "ᅮ" and match(syllable.initial, "") then
						syllable.vowel = "ᅳ"
					end
					
					if match(system_index, "") then
						if match(syllable.initial, "") then
							if syllable.vowel == "ᅣ" then
								syllable.vowel = "ᅡ"
							elseif syllable.vowel == "ᅤ" then
								syllable.vowel = "ᅢ"
							elseif syllable.vowel == "ᅧ" then
								syllable.vowel = "ᅥ"
							elseif syllable.vowel == "ᅨ" then
								syllable.vowel = "ᅦ"
							elseif syllable.vowel == "ᅭ" then
								syllable.vowel = "ᅩ"
							elseif syllable.vowel == "ᅲ" then
								syllable.vowel = "ᅮ"
							elseif syllable.vowel == "ᆢ" then
								syllable.vowel = "ᆞ"
							end
						end
					end
					
					if match(system_index, "") then
						if syllable.vowel == "ᅴ" and this_syllable_text ~= "의" then
							syllable.vowel = "ᅵ"
						end
					end
					if match(system_index, "") then
						if this_syllable_text == "넓" then
							if match(next_syllable.initial, "") then
								syllable.final = "ᆸ"
								
							elseif next_syllable.initial == "ᄃ" then
								if match(next_syllable.vowel, "") then
									syllable.final = "ᆸ"
								end
							end
						end
					end
					
					local vowel = m_data.vowels

					if p.nn then
						next_syllable.initial = "ᄂ"
					end
					if p.com and match(system_index, "") then
						next_syllable.initial = com_ph or next_syllable.initial
					end
					
					if p.ni and system_index ~= 3 then
						next_syllable.initial = (system_index == 4 and syllable.final == "ᆯ") and "ᄅ" or "ᄂ"
					end
					
					if match(system_index, "") then
						if tonumber(batchim_reduce or -1) == index then
							syllable.final = m_data.boundary
						end
					
						if index ~= 0 and this_syllable_text == "밟" then
							syllable.final = "ᆸ"
						end
						
						-- if match(syllable.final .. next_syllable.initial .. next_syllable.vowel, "ᅵ") then
						-- 	syllable.final = "ᆾ"
						
						-- elseif match(syllable.final .. next_syllable.initial .. next_syllable.vowel, "ᆮ이") then
						-- 	syllable.final = "ᆽ"
						
						-- elseif match(syllable.final .. next_syllable.initial .. next_syllable.vowel, "ᆮ히") then
						-- 	syllable.final = "ᆾ"
							
						-- elseif match(syllable.final .. next_syllable.initial .. next_syllable.vowel, "ㅣ") then
						-- 	syllable.final = "ퟹ"
						
						-- elseif syllable.final .. next_syllable.initial == "ᆺᄋ" and not
						-- 	match(next_syllable_text, "") then
						-- 		syllable.final = "ᆮ"
						-- end
						if match(syllable.final .. next_syllable.initial, "ᇀᄋ") then
								if next_syllable.vowel == "ᅵ" then
									syllable.final = "ᆾ"
								elseif next_syllable.vowel == "ᅧ" then
									syllable.final = "ᆾ"
									next_syllable.vowel = "ᅥ"
								end
							
							elseif match(syllable.final .. next_syllable.initial, "ᆴᄋ") then
								if next_syllable.vowel == "ᅵ" then
									syllable.final = "ᆯ"
									next_syllable.initial = "ᄎ"
								elseif next_syllable.vowel == "ᅧ" then
									syllable.final = "ᆯ"
									next_syllable.initial = "ᄎ"
									next_syllable.vowel = "ᅥ"
								end
							
							elseif match(syllable.final .. next_syllable.initial, "ᆮᄋ") and tonumber(s_variation or -1) ~= index then
								if next_syllable.vowel == "ᅵ" then
									syllable.final = "ᆽ"
								elseif next_syllable.vowel == "ᅧ" then
									syllable.final = "ᆽ"
									next_syllable.vowel = "ᅥ"
								end
							
							elseif match(syllable.final .. next_syllable.initial, "ᆮᄒ") then
								if next_syllable.vowel == "ᅵ" then
									syllable.final = "ᆾ"
									next_syllable.initial = "ᄋ"
								elseif next_syllable.vowel == "ᅧ" then
									syllable.final = "ᆾ"
									next_syllable.initial = "ᄋ"
									next_syllable.vowel = "ᅥ"
								end
								
							elseif match(syllable.final .. next_syllable.initial, "ퟍᄋ") then
								if next_syllable.vowel == "ᅵ" then
									syllable.final = "ퟹ"
								elseif next_syllable.vowel == "ᅧ" then
									syllable.final = "ퟹ"
									next_syllable.vowel = "ᅥ"
								end
						
							elseif syllable.final .. next_syllable.initial == "ᆺᄋ" and not
								match(next_syllable_text, "") then
									syllable.final = "ᆮ"
							end
					end
					
					local bound = syllable.final .. "-" .. next_syllable.initial
					if not m_data.boundary then
						track("no boundary data")
						mw.log("No boundary data for " .. bound .. ".")
						return nil
					end
					local junction = m_data.boundary
					
					if formatting_position and system_index == 2 then
						junction = gsub(junction, "^.*$", function(matched)
							local a, b = match(matched, "^(ng%-?)(.?)$")
							if not a or not b then a, b = match(matched, "^(.?%-?)(.*)$") end
							return match(syllable.final .. next_syllable.initial, "^Ø?$")
								and formatting_position .. (a or "") .. (b or "")
								or (a or "") .. formatting_position .. (b or "") end)
							
						formatting_insert_count = formatting_insert_count + 1
					end
					
					if p.l or (p.l and index == 1) then
						-- FIXME, verify this code still works with final/initial cons changes
						if system_index == 1 then
							if #junction == 0 then
								junction = junction .. "ː"
							else
								junction = gsub(junction, "^(.)(.?)$", function(a, b)
									return match(a, "") and a .. "ː" .. b or "ː" .. a .. b end)
							end
							
						elseif system_index == 5 then
							vowel = gsub(vowel, "()", "%1̄")
							
						elseif system_index == 6 then
							vowel = vowel .. "ː]"
						end
					end
					
					if (p.l or p.l) and index == 0 and system_index == 6 and #decomposed_syllables > 1 then
						vowel = vowel .. "ˈ"
					end
				
					if p.com then
						-- FIXME, verify this code still works with final/initial cons changes
						junction = gsub(junction, "(.)$", function(next_letter)
							return 
								(system_index == 5 and "q" or "") .. 
								(system_index == 4
									and (com_mc or "")] or com_mc or next_letter)
									or next_letter) end)
					end
					
					if p.ni and system_index == 4 then
						-- FIXME, verify this code still works with final/initial cons changes
						junction = gsub(junction, "()$", "<sup>%1</sup>")
					end

					local final_cons, initial_cons = match(junction, "^(.*);(.*)$")
					if not final_cons then
						if system_index == 2 then
							error("Need a semicolon in the boundary value for " .. bound)
						end
						-- FIXME, throw an error for all systems once we've added semicolons everywhere
						final_cons = junction
						initial_cons = ""
					end

					if system_index == 2 then
						insert(romanisation, vowel .. final_cons .. (saw_hyphen_after and "-" or "") .. initial_cons)
					else
						insert(romanisation, vowel .. junction)
					end
				end
			end
			
			local temp_romanisation = concat(romanisation)
			if p.cap and match(system_index, "") then
				temp_romanisation = upper(sub(temp_romanisation, 1, 1)) .. sub(temp_romanisation, 2, -1)
			end
			
			if system_index == 1 then
				temp_romanisation = tidy_phonetic(primitive_word, toNFC(temp_romanisation))
			
			elseif match(system_index, "") then
				for i = 1, 2 do
					temp_romanisation = gsub(temp_romanisation, "(.)…(.)", function(a, b)
						return a .. (ambiguous_intersyllabic_rr and "'" or "") .. b end)
					temp_romanisation = gsub(temp_romanisation, "wo'e", "woe")
					temp_romanisation = gsub(temp_romanisation, "yo'e", "yoe")
					temp_romanisation = gsub(temp_romanisation, "we'o", "weo")
					temp_romanisation = gsub(temp_romanisation, "we'u", "weu")
					temp_romanisation = gsub(temp_romanisation, "ye'u", "yeu")
					temp_romanisation = gsub(temp_romanisation, "yu'i", "yui")
				end

			elseif system_index == 5 then
				temp_romanisation = "⫽" .. temp_romanisation .. "⫽"
			
			elseif system_index == 6 then
				temp_romanisation = ""
			end

			insert(word_set_romanisations, temp_romanisation)
		end

		text_param = gsub(
			text_param,
			pattern_escape(the_original),
			concat(word_set_romanisations, system_list.separator),
			1
		)
	end

	if system_index == 6 then
		text_param = tidy_ipa(text_param)
	end
	
	return text_param
end

function export.make(frame, scheme)
	local params = {
		 = { default = PAGENAME, list = true },
		
		 = {},
		 = { alias_of = "a" },
		
		 = {},
		 = {},
		 = {},
		 = {},
		 = {},
		 = {},
		 = {},
		 = {},
		 = {},
		 = {},
		 = {},
		 = {},
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local results = {}
	for _, text_param in ipairs(args) do
		local current_word_dataset = {}
		for system_index, system in pairs(system_list) do
			local romanised = export.romanise(text_param, system_index, args)
			insert(current_word_dataset, romanised)
		end
		insert(results, current_word_dataset)
	end
	
	local output_result = {  = {},  = {},  = {},  = {},  = {},  = {} }
	for _, result in ipairs(results) do
		for result_index, value in ipairs(result) do
			insert(output_result, value)
		end
	end

	local html_ul = mw.html.create( "ul" )
	:done()
	local html_li_ipa_p = mw.html.create( "li" )
		:wikitext( system_list.display )
		:tag( "span" )
			:addClass( "IPA" )
			:wikitext( concat(output_result, system_list.separator) )
		:done()
	:done()
	local html_li_ipa = mw.html.create( "li" )
		:wikitext( system_list.display )
		:tag( "span" )
			:addClass( "IPA" )
			:wikitext( concat(output_result, system_list.separator) )
		:done()
	:done()
	local html_li_ph = mw.html.create( "li" )
		:addClass( "jje-pron__ph" )
		:wikitext( system_list.display )
		:tag( "span" )
			:addClass( "Kore" )
			:attr( "lang", "jje" )
			:wikitext( ", system_list.separator) .. "]" )
		:done()
	:done()

	if args.a then
		html_li_ipa
			:tag( "ul" )
				:tag( "li" )
					:wikitext( require("Module:audio").format_audio {
						lang = require("Module:languages").getByCode("jje"),
						file = args.a == "y" and "Jje-" .. PAGENAME .. ".ogg" or args.a,
					})
				:done()
			:done()
		:done()
	end

	html_ul
		:node( html_li_ipa_p )
		:node( html_li_ipa )
		:node( html_li_ph )
	:done()

	local html_table = mw.html.create( "table" )
		:addClass( "jje-pron" )
		:addClass( "mw-collapsible" )
		:addClass( "mw-collapsed" )
		:tag( "tr" )
			:tag( "th" )
				:attr( "colspan", 2 )
				:wikitext( "Romanizations" )
			:done()
		:done()
	:done()
		
	for roman_index = 2, 4 do
		html_table
			:tag( "tr" )
				:tag( "th" )
					:wikitext( system_list.display )
				:done()
				:tag( "td" )
					:addClass( "IPA" )
					:wikitext( concat(output_result, system_list.separator) )
				:done()
			:done()
		:done()
	end
		
	return tostring(html_ul) .. tostring(html_table) .. require("Module:TemplateStyles")("Template:jje-IPA/style.css")
end

return export