Module:User:RichardW57/nod-pron

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

Pronunciation/transcription module for Northern Thai. See {{nod-pron}} for usage.

Testcases: Module:User:RichardW57/nod-translit/testcases.


local export = {}

local gsub = mw.ustring.gsub
local sub = mw.ustring.sub
local match = mw.ustring.match
local find = mw.ustring.find

local failed_cat = "]"
local namespace = mw.title.getCurrentTitle().nsText
local thai_range = "" -- Thai scripts character plus extras for respelling, includinɡ the diacritic macron.
local categories = {}

local function dc(x) return gsub(x, "ก", "") end -- Use this to make Thai marks legible.  The name 'dc' means 'drop carrier'.
local function dq(x) return gsub(x, "q", "") end -- Use this to make Roman script marks legible.  The name 'dq' means 'drop e'.

local systems = {
	 = 1,
	 = 2,
	 = 3,
	 = 4,
	 = 5,
	 = 6,
	 = 7
}

local function clone_lookup(lookup, src, dst)
	local s = systems
	local d = systems
	for i, v in pairs(lookup) do
		lookup = lookup
	end
end

local initial = {
	 = { "g", "k", "k", class = "mid" },
	 = { "j", "ch", "t͡ɕ", class = "mid" },
	 = { "d", "d", "d", class = "mid" },
	 = { "d", "d", "d", class = "mid" },
	 = { "dt", "t", "t", class = "mid" },
	 = { "dt", "t", "t", class = "mid" },
	 = { "b", "b", "b", class = "mid" },
	 = { "bp", "p", "p", class = "mid" },
	 = { "", "@", "ʔ", class = "mid" },
	
	 = { "ng", "$ng", "ŋ", class = "low" },
	 = { "n", "n", "n", class = "low" },
	 = { "n", "n", "n", class = "low" },
	 = { "m", "m", "m", class = "low" },
	 = { "ny", "ny", "ɲ", class = "low" },
	 = { "y", "y", "j", class = "low" },
	 = { "r", "r", "r", class = "low" },
	 = { "l", "l", "l", class = "low" },
	 = { "l", "l", "l", class = "low" },
	 = { "w", "w", "w", class = "low" },
	
	 = { "k", "kh", "x", class = "low" }, 
	 = { "k", "kh", "x", class = "low" },
	 = { "k", "kh", "x", class = "low" },
	 = { "k", "kh", "x", class = "high" },
	 = { "k", "kh", "x", class = "high" },
	 = { "ch", "ch", "t͡ɕʰ", class = "low" },
	 = { "ch", "ch", "t͡ɕʰ", class = "low" },
	 = { "ch", "ch", "t͡ɕʰ", class = "high" },
	 = { "t", "th", "tʰ", class = "low" },
	 = { "t", "th", "tʰ", class = "low" },
	 = { "t", "th", "tʰ", class = "low" },
	 = { "t", "th", "tʰ", class = "low" },
	 = { "t", "th", "tʰ", class = "high" },
	 = { "t", "th", "tʰ", class = "high" },
	 = { "p", "ph", "pʰ", class = "low" },
	 = { "p", "ph", "pʰ", class = "low" },
	 = { "p", "ph", "pʰ", class = "high" },
	 = { "f", "f", "f", class = "low" },
	 = { "f", "f", "f", class = "high" },
	 = { "s", "s", "s", class = "low" },
	 = { "s", "s", "s", class = "high" },
	 = { "s", "s", "s", class = "high" },
	 = { "s", "s", "s", class = "high" },
	 = { "h", "h", "h", class = "low" },
	 = { "h", "h", "h", class = "high" },
	
	 = { "ng", "$ng", "ŋ", class = "high" },
	 = { "n", "n", "n", class = "high" },
	 = { "m", "m", "m", class = "high" },
	 = { "y", "y", "j", class = "high" },
	 = { "y", "y", "j", class = "high" },
	 = { "r", "r", "r", class = "high" },
	 = { "l", "l", "l", class = "high" },
	 = { "w", "w", "w", class = "high" },
		
	 = { "…", "…", "…", class = "" },
	 = { failed_cat, failed_cat, "", class = "" },
}

clone_lookup(initial, "ipa_CM", "ipa_CR")
for _, kh in ipairs({"ค", "ฅ", "ฆ", "ข", "ฃ"}) do
	initial] = "kʰ"
end

local vowel = {
	 = {
		 = { "a", "a", "a" },
		 = { "a", "a", "a" },
		 = { "i", "i", "i" },
		 = { "ʉ", "ue", "ɯ" },
		 = { "u", "u", "u" },
		 = { "e", "e", "eʔ" },
		 = { "ɛ", "ae", "ɛʔ" },
		 = { "o", "o", "oʔ" },
		 = { "ɔ", "o", "ɔʔ" },
		 = { "ɔ", "o", "ɔ" },
		 = { "ə", "oe", "ɤ" },
		 = { "ə", "oe", "ɤʔ" },
		 = { "aa", "a", "aː" },
		 = { "ii", "i", "iː" },
		 = { "uu", "u", "uː" },
		 = { "ʉʉ", "ue", "ɯː" },
		 = { "ee", "e", "eː" },
		 = { "ɛɛ", "ae", "ɛː" },
		 = { "oo", "o", "oː" },
		 = { "ɔɔ", "o", "ɔː" },
		 = { "ɔɔ", "on", "ɔːn" },
		 = { "əə", "oe", "ɤː" },
		 = { "ia", "ia", "ia̯ʔ" },
		 = { "ʉa", "uea", "ɯa̯ʔ" },
		 = { "ua", "ua", "ua̯ʔ" },
		 = { "iia", "ia", "ia̯" },
		 = { "ʉʉa", "uea", "ɯa̯" },
		 = { "uua", "ua", "ua̯" },
		 = { "iu", "io", "iw" },
		 = { "iiu", "io", "iːw" },
		 = { "eo", "eo", "ew" },
		 = { "ɛo", "aeo", "ɛw" },
		 = { "ao", "ao", "aw" },
		 = { "eeo", "eo", "eːw" },
		 = { "ɛɛo", "aeo", "ɛːw" },
		 = { "aao", "ao", "aːw" },
		 = { "əəo", "oeu", "ɤːw" }, --royin inferred
		 = { "oow", "ou", "oːw" }, --royin inferred
		 = { "iao", "iao", "ia̯w" },
		 = { "ai", "ai", "aj" },
		 = { "ai", "ai", "aj" },
		 = { "ai", "ai", "aj" },
		 = { "ai", "ai", "aj" },
		 = { "ʉi", "uei", "ɯj" },
		 = { "ɔi", "oi", "ɔj" },
		 = { "əi", "oei", "ɤj" },
		 = { "ui", "ui", "uj" },
		 = { "aai", "ai", "aːj" },
		 = { "ɔɔi", "oi", "ɔːj" },
		 = { "ooi", "oi", "oːj" },
		 = { "əəi", "oei", "ɤːj" },
		 = { "əəi", "oei", "ɤːj" }, -- Certainly occurs in rup pariwat.
		 = { "uui", "ui", "uːj" },
		 = { "uai", "uai", "ua̯j" },
		 = { "ʉai", "ueai", "ɯa̯j" },
		 = { "am", "am", "am" },
		M = { "m", "m", "m̩" },
		N = { "n", "n", "n̩̩" },
		NG = { "ng", "ng$", "ŋ̩̩" },
	},
	 = {
		 = { "a", "a", "a" },
		 = { "a", "a", "a" },
		 = { "i", "i", "i" },
		 = { "ʉ", "ue", "ɯ" },
		 = { "u", "u", "u" },
		 = { "ee", "e", "eː" },
		 = { "e", "e", "e" },
		 = { "ɛ", "ae", "ɛ" },
		 = { "ɛɛ", "ae", "ɛː" },
		 = { "o", "o", "o" },
		 = { "ɔ", "o", "ɔ" },
		 = { "ə", "oe", "ɤ" },
		 = { "aa", "a", "aː" },
		 = { "ii", "i", "iː" },
		 = { "ʉʉ", "ue", "ɯː" },
		 = { "uu", "u", "uː" },
		 = { "oo", "o", "oː" },
		 = { "ɔɔ", "o", "ɔː" },
		 = { "əə", "oe", "ɤː" },
		 = { "əə", "oe", "ɤː" },
		 = { "iia", "ia", "ia̯" },
		 = { "ʉʉa", "uea", "ɯa̯" },
		 = { "uua", "ua", "ua̯" },
		 = { "ai", "ai", "aj" },
		 = { "ao", "ao", "aw" },
		 = { "ɔi", "oi", "ɔj" },
	}
}
clone_lookup(vowel,   "ipa_CM", "ipa_CR")
clone_lookup(vowel, "ipa_CM", "ipa_CR")

local unromLong = {
	 = true,  = true,  = true,  = true,
	 = true,  = true,  = true,
	 = true,
}

local liveExc = {
	 = true,  = true,  = true,  = true,
	 = true,  = true,  = true,  = true,
	 = true,  = true,  = true,  = true,
	 = true,
}

-- ย,ว are not included.
-- ช,ซ,ส,ฟ,ล are changed for loanwords.
-- ห,อ,ฮ can never be c2s.
local coda = {
	 = { "k", "k", "k̚" },
	 = { "k", "k", "k̚" },
	 = { "k", "k", "k̚" },
	 = { "k", "k", "k̚" },
	 = { "k", "k", "k̚" },
	 = { "k", "k", "k̚" },
	 = { "t", "t", "t̚" },
	 = { "t", "t", "t̚" },
	 = { "ch", "ch", "t͡ɕʰ" },
	 = { "s", "s", "s" },
	 = { "t", "t", "t̚" },
	 = { "t", "t", "t̚" },
	 = { "t", "t", "t̚" },
	 = { "t", "t", "t̚" },
	 = { "t", "t", "t̚" },
	 = { "t", "t", "t̚" },
	 = { "t", "t", "t̚" },
	 = { "t", "t", "t̚" },
	 = { "t", "t", "t̚" },
	 = { "t", "t", "t̚" },
	 = { "t", "t", "t̚" },
	 = { "t", "t", "t̚" },
	 = { "t", "t", "t̚" },
	 = { "s", "s", "s" },
	 = { "p", "p", "p̚" },
	 = { "p", "p", "p̚" },
	 = { "p", "p", "p̚" },
	 = { "p", "p", "p̚" },
	 = { "p", "p", "p̚" },
	 = { "f", "f", "f" },
	 = { "p", "p", "p̚" },
	 = { "ng", "ng$", "ŋ" },
	 = { "n", "n", "n" },
	 = { "n", "n", "n" },
	 = { "n", "n", "n" },
	 = { "n", "n", "n" },
	 = { "l", "l", "l" },
	 = { "n", "n", "n" },
	 = { "m", "m", "m" },
}
clone_lookup(coda, "ipa_CM", "ipa_CR")

--[[
Notate tones on live syllables and long syllables by names for Chiang Mai tones.
Short dead syllables' tones are designated by D1S for high and mid class initials,
and D4S for low initials.  D1S is also used for D2S and D3S, for we have no
evidence that the difference matters for Northern Thai.
]]
local tmarks = dc("") -- Includes macron.
local tFromMark = {
	-- common
	 = {  = "low",      = "low",      = "falling" },
	 = {  = "special",  = "special",  = "high" },
	 = {  = "high",     = "high",     = "high" },
	 = {  = "rising",   = "rising",   = "rising" },
	-- forced mid tone
	 = {  = "mid",      = "mid",      = "mid" },-- Macron
}

local tNoMark = {
	 = {  = "D1S",     = "D1S",     = "D4S" },
	  = {  = "low",     = "low",     = "falling" },
	       = {  = "rising",  = "mid",     = "mid" },
}

local tRomMarks = {
	 = dq("q́"),  = "",  = dq("q̀"),
	 = dq("q̌"),  = dq("q̂"),  = dq("q᷆"),
	 = dq("q̌"),  = dq("q́")
}

local tLevels = {}
tLevels = {
	 = "˦˥",  = "˧",  = "˨˩",
	 = "˩˩˦",  = "˦˩",  = "˥˥˨", -- More work needed!
	 = "˦˦˥",  = "˥",
}
tLevels = {
	 = "˥˥˧",  = "˧˧˦",  = "˩˩",
	 = "˩˩˧",  = "˧˧˩",  = "˥˥",
	 = "˦˦˥",  = "˥˥˦",
}
local symbols = {
	 = 0,  = 1,  = 2,  = 3,  = 4,
	 = 5,  = 6,  = 7,  = 8,  = 9,
}

local permitted_cluster = {
	 = 1,  = 1,  = 1,  = 1,  = 1,
}

-- modified ISO 11940 (to make sound values are more apparent), uses spacing marks for signs
local char_table = {
	 = "k",  = "kʰ",  = "x",  = "g",  = "ɣ",  = "gʰ",  = "ŋ",
	 = "t͡ɕ",  = "t͡ɕʰ",  = "d͡ʑ",  = "z",  = "d͡ʑʰ",  = "ɲ", 
	 = "ᶑ",  = "ʈ",  = "ʈʰ",  = "ɖ",  = "ɖʰ",  = "ɳ",
	 = "ɗ",  = "t",  = "tʰ",  = "d",  = "dʰ",  = "n",
	 = "ɓ",  = "p",  = "pʰ",  = "v",  = "b",  = "f",  = "bʰ",  = "m",
	 = "y",  = "r",  = "ṛ",  = "l",  = "ḷ",  = "w",
	 = "ɕ",  = "ʂ",  = "s",  = "h",  = "ɭ",  = "ɒ",  = "ɦ",
	
	 = "a",  = "ạ",  = "ā",  = "å",  = "i",  = "ī",
	 = "ụ",  = "ụ̄",  = "u",  = "ū",  = "ɨ",  = "̥",  = "฿",
	
	 = "e",  = "æ",  = "o",  = "au",  = "ai", 
	
	 = "ˋ",  = "ˆ",  = "ˊ",  = "ˇ",
	
	 = "ǂ",  = "«",  = "˘",
	 = "ʻ",  = "˚",  = "~",  = "§",
	 = "ǁ",  = "»",
	
	 = "0",  = "1",  = "2",  = "3",  = "4", 
	 = "5",  = "6",  = "7",  = "8",  = "9", 
	
	 = "  ",  = "–",  = "…",
}

local prevowels = "?"
local onset = ""
local red_medials = "?"
local medials = dc("กฺ?"..red_medials)
local nucleus
	  nucleus = dc("?ก็?"..tmarks.."???ะ?")-- Old
	  nucleus = dc("?ก็?"..tmarks.."???ะ?")-- Old
local red_nucleus = dc("???ะ?")
--      red_nucleus = dc("?")
local final = "?"
local final2 = final..final
local mgvc_pattern = "^("..red_medials..")("..red_nucleus..")("..final..")$"
--      mgvc_pattern = "^("..red_medials..")("..red_nucleus..")"
-- partial_pattern is pattern for syllables without tone-shifting ho hip.
-- full_pattern is pattern for syllables with it.
local partial_pattern = "^("..prevowels..")("..onset..")("..medials..")("..nucleus..")("..final2..")$"
local full_pattern = "^("..prevowels..")(หฺ"..onset..")("..medials..")("..nucleus..")("..final2..")$"
local old_mgvc_pattern = "^(?)(???ะ?)(?)$"
--      old_mgvc_pattern = "^(?)(?)"
local old_full_pattern = "^(?)(หฺ)(ฺ??)(?็????ะ?)(??)$"
local old_partial_pattern = "^(?)()(ฺ??)(?็????ะ?)(??)$"

if mgvc_pattern ~= old_mvgc_pattern then
	mw.addWarning("mgvc_pattern accidentally_changed from "..old_mgvc_pattern.." to "..mgvc_pattern)
    local l1 = mw.ustring.len(old_mgvc_pattern)
    local l2 = mw.ustring.len(mgvc_pattern)
    if l1 ~= l2 then
		mw.addWarning('Lengths are '.. tostring(l1)..' and '..tostring(l2))
	else
		for i = 1, l1 do
			local c1 = mw.ustring.codepoint(old_mgvc_pattern, i, i)
			local c2 = mw.ustring.codepoint(mgvc_pattern, i, i)
			if c1 == c2 then
				mw.addWarning('Characters '..tostring(i)..' are '..
				string.format('%x', c1))
			else
				mw.addWarning('Characters '..tostring(i)..' differ, being '..
				string.format('%x', c1)..' and '..string.format('%x', c2))
			end
		end
	end
end
--[[ Comparison testing donefor these two - no problems were found, but will now differ.
if full_pattern ~= old_full_pattern then
	mw.addWarning("full_pattern accidentally_changed from "..old_full_pattern.." to "..full_pattern)
end
if partial_pattern ~= old_partial_pattern then
	mw.addWarning("partial_pattern accidentally_changed from "..old_partial_pattern.." to "..partial_pattern)
end
]]
function export.translit(text, lang, sc, mode, source)
	local seq = systems
	local poly_evidence = tmarks..".?"..tmarks
	for word in mw.ustring.gmatch(text, thai_range .. "+") do
		local orig_word, class, tMark, tone, long, c2 = word, "", false, false, false, false
-- Reject obvious polysyllables
		if match(word, poly_evidence) then
			return nil
		end

		local function c2_decomp(c2_char, seq, source)
			local converted_c2 = {}
			for character in mw.text.gsplit(c2_char, "") do
				table.insert(converted_c2, coda and coda or nil)
			end
			local cluster = table.concat(converted_c2)
			if source == "translit-module" and not permitted_cluster then
				return c2_char
			else
				return cluster
			end
		end
		
		local function syllable(v1, c1, g, v2, c2)
			
			tMark = match(v2, tmarks)
			v2 = gsub(v2, tmarks, "")

			if match(c1, "^ห.$") then
				if match(sub(c1, 2, 2) .. g .. v2 .. c2, mgvc_pattern) then
					c1, g, v2, c2 = "ห", match(sub(c1, 2, 2) .. g .. v2 .. c2, mgvc_pattern)
					if g ~= "" and not v2 == "ย" then c1, g = c1 .. g, "" end
				end
			end
			
			if g == "ล" and v2 .. c2 == "" then
				c2 = g
				g = ""
			end
			
			openness = c2 ~= "" and "closed" or "open"
			
			if source == "pron-module"
				and (mw.ustring.len(c1) > 1 or match(g, ""))
				and not match(c1 .. g, "ฺ") then
					
				error("Please replace " ..  c1 .. g .. " in the respelling with " .. 
					sub(c1, 1, 1) .. "ฺ" .. (sub(c1, 2, -1) or "") .. g .. ".")
			end
			
			if vowel then
				orig_v = v1 .. g .. v2
				v, g = vowel, ""
			else
				orig_v = v1 .. v2
				v = vowel and vowel or (v1 .. v2)
				g = (initial or initial)
			end
			
			c1 = gsub(c1, "ฺ", "")
			ini, class = "", ""
			
			if initial then
				ini, class = initial, initial.class
			else
				return nil
			end
			
			length = (match(v, "()%1") or match(v, "ː") or unromLong) and "long" or "short"
			life = (match(c2, "") or (match(orig_v, "ย$") and match(v, "i$")) or
				c2..length == "long" or liveExc) and "live" or "dead"
			c2 = coda and coda or c2_decomp(c2, seq, source)

			-- note: Do not add tone for royin
			tone = tMark and tFromMark or (tNoMark or tNoMark)
			if mode == "paiboon" then
				v = gsub(v, "^(*)()", "%1%2" .. tRomMarks)
			elseif mode == "ipa_CM" or mode == "ipa_CR" then
				c2 = c2 .. tLevels
			end
			
			return ini .. g .. v .. c2
		end
		
		word = gsub(word, full_pattern, syllable)

		word = gsub(word, partial_pattern, syllable)

		text = gsub(text, orig_word, word, 1)
	end

	text = gsub(text, "", symbols)

	-- postprocessing
	if mode == "royin" then
		-- initial อ
		text = gsub(text, "^@", "")
		text = gsub(text, "()@", "%1")
		text = gsub(text, "@", "-")
		-- initial ง
		text = gsub(text, "^%$ng", "ng")          
		text = gsub(text, "()%$ng", "%1ng")
		text = gsub(text, "()%$ng", "%1-ng")
		text = gsub(text, "%$ng", "ng")
		-- final ง
		text = gsub(text, "ng%$$", "ng")          
		text = gsub(text, "ng%$()", "ng%1") -- includes hyphen
		text = gsub(text, "ng%$", "ng")
	end

	local count_syl = 0
	if mode == "ipa_CM" or mode == "ipa_CR" then
		text, count_syl = gsub(text, "", ".") -- space, common hyphen, en dash
		if not match(text, "%.$") then
			count_syl = count_syl + 1
		end
		text = gsub(text, "()(+)$", "%1ʔ%2") -- add ʔ if last syllable ends with 
	end

	if match(text, thai_range) then
		if source == "translit-module" or namespace ~= "" then
			return nil
		else
			return failed_cat
		end
	else
		table.insert(categories, count_syl > 0 and "]" or "")
		return mw.ustring.toNFC(text)
	end
end

function annotate(c1_text, annotation)
	if not annotation then return c1_text end
	return tostring( mw.html.create( "span" )
		:css( "border-bottom", "1px dotted #000" )
		:css( "cursor", "help" )
		:attr( "title", annotation )
		:wikitext( c1_text ))
end

local front_v = ""
local char_annotation = {
	 = "CANCEL"
}

function export.getCharSeqTbl(text)
	local result = {}
	for character in mw.text.gsplit(text, "") do
		local charDetail = char_table or nil
		
		if find(character, front_v) then
			table.insert(result, tostring( mw.html.create( "span" )
				:css( "border", "1px dotted gray" )
				:css( "border-radius", "50%" )
				:css( "cursor", "help" )
				:attr( "title", "Vowel sign appearing in front of the initial consonant." )
				:wikitext( charDetail )))
		else
			table.insert(result, annotate(charDetail, char_annotation))
		end
	end
	return result
end

function getCharSeq(text)
	return "<br><small>" .. 
		table.concat(export.getCharSeqTbl(text), "&thinsp;") .. 
		"</small>"
end

local note_set = {
	 = annotate(
		"-ɔɔ r-", 
		"In this word, the double consonant combinations กร, ทร, ธร, มร, and หร are pronounced 'gaaw ra', 'thaaw ra', 'maaw ra' and 'haaw ra', respectively."
	),
	 = annotate(
		"Reduplication", 
		"This word exhibits reduplication in pronunciation, i.e. one written consonant is used as the final consonant of a syllable as well as the initial consonant of the next syllable."
	),
	 = annotate(
		"Short", 
		"The vowel in this word is pronounced irregularly short."
	),
	 = annotate(
		"Unorthographical", 
		"This phonetic respelling violates Thai alphabet rules to indicate an irregular pronunciation."
	),
}

function export.show(frame)
	local lang, sc = "th", "Thai"
	local args = frame:getParent().args
	local pagename = args.pagename or mw.title.getCurrentTitle().text
	local p, note = {}, {}
	
	if args then
		for ind_note in mw.text.gsplit(args, ",") do
			table.insert(note, note_set)
		end
	end

	if args then
		for index, item in ipairs(args) do
			table.insert(p, (item ~= "") and item or nil)
		end
	else
		table.insert(p, pagename)
	end
	
	local p_concatenated = table.concat(p, "/")
	if match(p_concatenated, "็" .. thai_range .. "*")
		or match(p_concatenated, "" .. thai_range .. "*็") 
		or match(p_concatenated, "ิ็") then
			
		table.insert(note, note_set)
		if not match(args or "", "short") then
			table.insert(note, note_set)
		end
		
	elseif match(p_concatenated, "็")
		and not match(pagename, "็")
		and not match(args or "", "short") then
		table.insert(note, note_set)
	end
	
	homEdit = tostring( mw.html.create( "div" )
		:css( "float", "right" )
		:css( "clear", "right" )
		:css( "font-size", "60%" )
		:wikitext( tostring( mw.html.create( "span" )
			:attr( "class", "plainlinks" )
			:wikitext( "[" .. tostring( mw.uri.fullUrl( 
				"Module:nod-hom/data", 
				{  = "edit" }
				)) .." edit]" ))))
	
	function formatThai(text, pron, qualifiers)
		local readclass = ''
		if pron == true then
			readclass = 'th-reading'
			end
		return ((qualifiers and table.concat(qualifiers) ~= "")
			and '<span style="background-color:#ffffe6"><small>[' .. 
				table.concat(qualifiers, ", ") .. ']</small></span><br>'
			or '') .. '<span lang="th" class="Thai ' .. readclass .. '">' .. text .. '</span>'
	end
	
	local result = { 
		 = {}, 
		 = {}, 
		 = {}, 
		 = {}, 
		 = {}, 
		 = {}, 
		 = {}
	}
	
	table.insert(categories, "]")
	
	local m_hom_data = require("Module:User:RichardW57/nod-hom/data")
	local m_hom = require("Module:User:RichardW57/nod-hom").makeList
	local m_fileData = require("Module:User:RichardW57/nod-pron/files")
	local qualifiers = {}
	
	for system, _ in pairs(systems) do
		
		local function f(text, system)
			if system == "paiboon" or system == "royin" then
				return '<span class="tr">' .. text .. '</span>'
				
			elseif system == "ipa_CM" or system == "ipa_CR" then
				return '<span class="IPA">/' .. text .. '/</span>'
				
			elseif system == "file" then
				local length = ((mw.ustring.len(gsub(text, "", "")) + 1) * 25 + 50)
				if m_fileData then
					table.insert(categories, "]")
					return "[[File:" .. 
						m_fileData .. 
						"|" .. (length > 200 and 200 or length) .. 
						"px|center]]"
				else
					return ""
				end
			
			else
				return m_hom_data
					and (#m_hom_data > 3 
						and tostring( mw.html.create( "div" )
							:attr {
								 = "vsSwitcher",
								 = "homophones",
							}
							:wikitext( 
								tostring( mw.html.create( "span" )
									:attr( "class", "vsToggleElement" )
									:wikitext( "&nbsp;" )) .. 
								tostring( mw.html.create( "div" )
									:attr( "class", "vsShow" )
									:css( "display", "none" )) ..
								tostring( mw.html.create( "div" )
									:attr( "class", "vsHide" )
									:wikitext(( gsub(m_hom(text), ", ", "<br>" ))))))
						or gsub(m_hom(text), ", ", "<br>"))
					or ""
			end
		end
		
		for i, spelling in ipairs(p) do
			if system == "charPhon" then
				qualifiers = {}
				if match(spelling, "%:") then
					table.insert(qualifiers, match(spelling, "%:(.+)"))
					spelling = match(spelling, "(+)")
				end
				if match(spelling, "-$") then
					table.insert(qualifiers, "bound form")
				end
			else
				spelling = match(spelling, "(+)")
			end
			table.insert(result, tostring( mw.html.create( "td" )
				:css( "border-right", i < #p and "1px solid lightgray" or "0px" )
				:wikitext( 
					(system == "charPhon"
					and formatThai(spelling, false, qualifiers) .. getCharSeq(spelling)
					or f(find(system, "^")
						and export.translit(spelling, lang, sc, system, "pron-module")
						or spelling, system)))))
		end
	end
	
	has_hom = match(table.concat(result), "Northern Thai") or false
	has_file = match(table.concat(result), "File") or false
	notes = (#note > 0 and "<br><small>{" .. table.concat(note, "; ") .. "}</small>" or "")

	local function row(a, b, o)
		return ((o and o) and "" or "\n<tr>") ..
		tostring( mw.html.create( "td" )
			:attr( "bgcolor", "fafeff" )
			:attr( (o and o) and "rowspan" or "colspan", (o and o) and 1 or 2 )
			:css( "border-bottom", (o and o) and "0px" or "1px solid lightgray" )
			:css( "border-right", "1px solid lightgray" )
			:css( "font-weight", "bold" )
			:wikitext(a)) ..
		
		((o and o) and "" or 
			((o and o)
				and tostring(mw.html.create( "td" )
					:attr( "colspan", #p )
					:css( "border-bottom", "1px solid lightgray" )
					:wikitext(b))
				or b) ..
			
			"</tr>")
	end
	
	if find(pagename, "ทร") and find(table.concat(result), "ซ") then
		table.insert(categories, "]")
	end
	
	return
	'<table cellpadding=10 style="border-spacing: 2px; border: 1px solid darkgray; text-align:center">' ..
	
	((namespace ~= "" and not args.pagename)
		
		and row(
			"'']''" .. notes,
			'<div class="th-reading">' .. table.concat(result)) .. '</div>'
		
		or (pagename == table.concat(p)
			and row(
				"'']''",
				formatThai(pagename,true) .. getCharSeq(pagename),
				{  = true })
		
			or row(
				"'']''",
				formatThai(pagename,true) .. getCharSeq(pagename),
				{  = true }) ..
			
				row(
				"'']''" .. notes,
				'<div class="th-reading">' .. table.concat(result)))) .. '</div>' ..
	
	row("'']''", nil, {  = true }) ..
	
	row(
		"'']''",
		table.concat(result),
		{  = true }) ..
	
	row(
		"'']''",
		table.concat(result),
		{  = true }) ..
	
	row(
		"('']'') " ..
		"]" ..
		"<sup>(])</sup>",
		
		table.concat(result),
		{  = false }) ..
	
	row(
		"('']'') " ..
		"]" ..
		"<sup>(])</sup>",
		
		table.concat(result),
		{  = not has_hom and not has_file }) ..
	(has_hom
		and row(
			"''Homophones''" .. homEdit,
			table.concat(result) or "",
			{  = not has_file })
		or "") ..
	
	(has_file
		and row(
			"''Audio''",
			table.concat(result) or "",
			{  = true })
		or "") ..
	
	"\n</table>" .. (namespace == "" and table.concat(categories) or "")
end

return export