Bengali IPA pronunciation module. See {{bn-IPA}}.

Module:bn-IPA/testcases:

17 tests failed. (refresh)

လိက် ဗွဲမရံၚ်လၟဳ မဇေတ်ဍာံ တၚ်လညာတ်ဂမၠိုၚ်
test_all:
Failed ব্রাহ্মণ (brahmon) bɾamɦón bɾamhón
Failed উত্তর (uttor) ut̪ːóɾ ut̪ːɔɾ
Passed অ্যান্টার্কটিকা (ênṭarkṭika) ænʈaɾkʈika ænʈaɾkʈika
Passed ব্যায়াম (bêẏam) bæam bæam
Passed দেশ (deś) d̪eʃ d̪eʃ
Failed মধু (modhu) mód̪ʱu mɔd̪ʱu
Passed আমার (amar) amaɾ amaɾ
Failed খেলনা (khelna) kʰælna kʰelna
Failed বিবাহ (bibaho) bibaɦó bibahó
Passed গম (gom) ɡɔm ɡɔm
Failed খরগোশ (khorgōś) kʰɔɾɡóʃ kʰɔɾɡoʃ
Passed মুক্ত (mukto) mukt̪ó mukt̪ó
Passed মিঞা (mĩa) mĩa mĩa
Passed শাস্ত্র (śastro) ʃast̪ɾó ʃast̪ɾó
Passed ত্বক (tok) t̪ɔk t̪ɔk
Passed অন্বেষণ (onneśon) ɔnːeʃɔn ɔnːeʃɔn
Passed শ্রাবণ (srabon) sɾabón sɾabón
Passed ভাই (bhai) bʱai̯ bʱai̯
Passed দৃষ্টি (driśṭi) d̪ɾiʃʈi d̪ɾiʃʈi
Failed শক্তি (śokti) ʃokt̪i ʃɔkt̪i
Passed ওস্তাদ (ōstad) ost̪ad̪ ost̪ad̪
Failed পঙ্কজ (poṅkoj) pɔŋkodʒ pɔŋkɔd͡ʒ
Passed দেওয়াল (deōẇal) d̪eo̯al d̪eo̯al
Passed নিবৃত্ত (nibritto) nibɾit̪ːó nibɾit̪ːó
Failed মৃত্যুঞ্জয় (mrittunjoẏ) mɾit̪ːundʒɔe̯ mɾit̪ːund͡ʒɔe̯
Failed গর্ভপাত (gorbhopat) ɡɔɾbʱópat̪ ɡɔɾbʱɔpat̪
Passed গর্ভ (gorbho) ɡɔɾbʱó ɡɔɾbʱó
Failed যক্ষ্মা (jokkha) dʒɔkʰːa d͡ʒɔkʰːa
Failed রক্ষা (rokkha) rókʰːa rɔkʰːa
Passed সংখ্যা (śoṅkha) ʃɔŋkʰa ʃɔŋkʰa
Failed সবজি (śoboji) ʃóbdʒi ʃɔbód͡ʒi
Failed ইনফ্লুয়েঞ্জা (inphluẏenja) influ̯endʒa influ̯end͡ʒa
Failed পশ্চিমবঙ্গ (pościmboṅgo) póʃtʃimbɔŋɡó pɔʃt͡ʃimbɔŋɡó
Failed নয়ন (noẏon) nɔe̯ón nɔe̯on
Failed জিহ্বা (jiubha) dʒiu̯bʱa d͡ʒiu̯bʱa

local export = {}

local lang = require("Module:languages").getByCode("bn")
local sc = require("Module:scripts").getByCode("Beng")
local m_IPA = require("Module:IPA")
local m_a = require("Module:accent qualifier")

local gsub = mw.ustring.gsub
local gmatch = mw.ustring.gmatch
local find = mw.ustring.find

local correspondences = {
	["ṅ"] = "ŋ", ["g"] = "ɡ",
	["c"] = "t͡ʃ", ["j"] = "d͡ʒ",
	["ṭ"] = "ʈ", ["ḍ"] = "ɖ",
	["t"] = "t̪", ["d"] = "d̪",
	["y"] = "e̯", ["r"] = "ɾ", ["l"] = "l",
	["ś"] = "ʃ", ["h"] = "h", ["ḥ"] = "h",
	["ṛ"] = "ɽ",

	["y"] = "e̯", ["w"] = "o̯",

	["o"] = "ɔ", ["ô"] = "ɔ",
	["ī"] = "i", ["ō"] = "o",
	["ū"] = "u", ["ê"] = "æ",

	["õ"] = "ɔ̃", ["ō̃"] = "õ", ["ī̃"] = "ĩ", ["ū̃"] = "ũ", ["ễ"] = "æ̃",
}


local dhaka = {
	["c"] = "ṯɕ",	["ch"] = "ṯɕʰ", ["j"] = "ḏʑ", ["jh"] = "ḏʑʱ", ["r"] = "ɹ", ["ṛ"] = "ɹ", ["ṛh"] = "ɹ",

	["e"] = "e", ["ê"] = "ɛ", ["õ"] = "ɔ", ["ō̃"] = "o", ["ĩ"] = "i", ["ũ"] = "u", ["ẽ"] = "e", ["ễ"] = "ɛ", ["ã"] = "a",
}

local vanga = {
	["c"] = "ts", ["ch"] = "s", ["j"] = "dz", ["jh"] = "z", ["f"] = "ɸ", ["r"] = "ɾ", ["ṛ"] = "ɾ", ["ṛh"] = "ɾ",

	["e"] = "ɛ", ["ê"] = "ɛ", ["õ"] = "ɔ", ["ō̃"] = "o", ["ĩ"] = "i", ["ũ"] = "u", ["ẽ"] = "ɛ", ["ễ"] = "ɛ", ["ã"] = "a",
}

local eastern_vanga= {
	["c"] = "s", ["ch"] = "s", ["j"] = "z", ["jh"] = "z", ["k"] = "x", ["kh"] = "x", ["p"] = "ɸ", ["f"] = "ɸ", ["r"] = "ɹ", ["ṛ"] = "ɹ", ["ṛh"] = "ɹ",
}

local varendra = {
	["c"] = "s", ["ch"] = "ts", ["j"] = "z", ["jh"] = "dz", ["ṛ"] = "ɾ", ["ṛh"] = "ɾ",
}

local vowels = "aiuoōêɔɔ̃ɛeææ̃ãễẽĩõō̃ũ"
local vowel = "[aiuoōêɔɔ̃ɛeææ̃ãễẽĩõō̃ũ]"
local consonants = "[bcdd̪ḍɖfgjklmnṇprṛɾsṣśs̪ʃɕtt̪ṭʈzz̪ʑ]"
local weak = "([gjdḍbṛʑ])"
local aspirate = "([kctṭpɕ])"

local function find_consonants(text)
	local current = ""
	local cons = {}
	for cc in mw.ustring.gcodepoint(text .. " ") do
		local ch = mw.ustring.char(cc)
		if find(current .. ch, "^[kgṅcjñṭḍṇṁtdnpbmyrlvśṣshṛz]$") or find(current .. ch, "^[kgcjṭḍṇtdpbṛ]h$") then
			current = current .. ch
		else
			table.insert(cons, current)
			current = ch
		end
	end
	return cons
end

local identical = "knlsfz"
for character in gmatch(identical, ".") do
	correspondences[character] = character
end

local function transliterate(text)
	return (lang:transliterate(text))
end

function export.link(term)
	return require("Module:links").full_link{ term = term, lang = lang, sc = sc }
end

function export.toIPA(text, style)
	local translit = text
	if lang:findBestScript(text):isTransliterated() then
		translit = transliterate(text)
	end
	if not translit then
		error('The term "' .. text .. '" could not be transliterated.')
	end

	-- metathesis (Chatterji, 1921)
	translit = gsub(translit, "(" .. vowel .. ")hl", "%1lh")
	translit = gsub(translit, "(" .. vowel .. ")hm", "%1mh")
	translit = gsub(translit, "(" .. vowel .. ")hn", "%1nh")

	-- suppressing the above metathesis
	translit = gsub(translit, "h'l", "hl")
	translit = gsub(translit, "h'm", "hm")
	translit = gsub(translit, "h'n", "hn")

	-- some workarounds since [[Module:bn-translit]] is locked
	translit = gsub(translit, "ph", "f")
	translit = gsub(translit, "v", "bh")
	translit = gsub(translit, "ẏ", "y")
	translit = gsub(translit, "ẇ", "w")

	-- vowel harmony
	translit = gsub(translit, "o([bd̪hlmnrṛɹt̪])([iu])", "ó%1%2") -- Chatterji, 1926
	translit = gsub(translit, "o([bd̪hlnrṛɹt̪])o", "o%1ó")
	translit = gsub(translit, "ḍḍo", "ḍḍó") 
	translit = gsub(translit, "ṭṭo", "ṭṭó") 
	translit = gsub(translit, "ho$", "hó")
	translit = gsub(translit, "(" .. vowel .. ")h$", "%1")
	translit = gsub(translit, "(" .. vowel .. ")h ", "%1 ")

	translit = gsub(translit, "oi", "ói")
	translit = gsub(translit, "ou", "óu")

	translit = gsub(translit, "^(".. consonants .. ")o$", "%1ô")
	translit = gsub(translit, "o$", "ó")
	translit = gsub(translit, "õ$", "ó̃")

	translit = gsub(translit, "pro", "pró")
	translit = gsub(translit, "(" .. vowel .. ")(" .. consonants .. "h?)om$", "%1%2óm")
	translit = gsub(translit, "bon$", "bón")
	translit = gsub(translit, "ron$", "rón")

	translit = gsub(translit, "^(".. consonants .. ")o ", "%1ô ")
	translit = gsub(translit, " (".. consonants .. ")o$", " %1ô")

	translit = gsub(translit, "o ", "ó ")
	translit = gsub(translit, "õ ", "ó̃ ")

	translit = gsub(translit, "(" .. vowel .. ")(" .. consonants .. "h?)om ", "%1%2óm ")
	translit = gsub(translit, "bon ", "bón ")
	translit = gsub(translit, "ron ", "rón ")

	translit = gsub(translit, "^o", "ô")
	translit = gsub(translit, " o", " ô")

	translit = gsub(translit, "([lmn])ho", "%1hó")

	if style == "formal" then
		translit = gsub(translit, "ó", "ō")
	end

	if style == "desanskritized" then
		translit = gsub(translit, "ó", "ō")
		translit = gsub(translit, "ṛh", "ṛ")
	end

	if style == "colloquial" then
		translit = gsub(translit, "ó", "ō")
		translit = gsub(translit, "lh", "ll") -- Chatterji
		translit = gsub(translit, "mh", "mm") -- Chatterji
		translit = gsub(translit, "nh", "nn") -- Chatterji
		translit = gsub(translit, "ṛ", "r")
		translit = gsub(translit, "ṛh", "r")
		translit = gsub(translit, "śt", "st")
		translit = gsub(translit, "sṭ", "śṭ")
	end

	if style == "dhaka" then
		translit = gsub(translit, "ó", "ō")
		translit = gsub(translit, "([cjrṛ]h?)", dhaka)
		translit = gsub(translit, "(" .. vowel .. ")", dhaka)
		translit = gsub(translit, "ó̃", "ō")
	end

	if style == "dhaka_colloquial" then
		translit = gsub(translit, "ó", "ō")
		translit = gsub(translit, "lh", "ll")
		translit = gsub(translit, "mh", "mm")
		translit = gsub(translit, "nh", "nn")
		translit = gsub(translit, "śt", "st")
		translit = gsub(translit, "sṭ", "śṭ")

		translit = gsub(translit, "([cjprṛ]h?)", dhaka)
		translit = gsub(translit, "(" .. vowel .. ")", dhaka)
		translit = gsub(translit, "ō̃", "ō")
	end

	if style == "vanga" then
		translit = gsub(translit, "ó", "ô")
		translit = gsub(translit, "([cfjprṛ]h?)", vanga)
		translit = gsub(translit, "(" .. vowel .. ")", vanga)
		translit = gsub(translit, "śt", "st")
		translit = gsub(translit, "sṭ", "śṭ")
	end

	if style == "eastern_vanga" then
		translit = gsub(translit, "ó", "ô")
		translit = gsub(translit, "([cfjkprṛ]h?)", eastern_vanga)
		translit = gsub(translit, "(" .. vowel .. ")", vanga)
		translit = gsub(translit, "śt", "st")
		translit = gsub(translit, "sṭ", "śṭ")
	end

	if style == "varendra" then
		translit = gsub(translit, "ó", "ô")
		translit = gsub(translit, "śt", "st")
		translit = gsub(translit, "sṭ", "śṭ")
		translit = gsub(translit, "([cjṛ]h?)", varendra)
	end

	-- vowels
	translit = gsub(translit, "%-$", "")
	translit = gsub(translit, "^%-", "")
	translit = gsub(translit, ",", "")
	translit = gsub(translit, " ", "..")
	translit = gsub(translit, "%.ː", "ː.")
	translit = gsub(translit, "%.̃", "̃")

	translit = gsub(translit, "ay([eiu])", "a%1")
	translit = gsub(translit, "ey([aioōu])", "e%1")
	translit = gsub(translit, "êy([aeioōu])", "ê%1")
	translit = gsub(translit, "iy([aeoōu])", "i%1")
	translit = gsub(translit, "ĩy([aeoōu])", "ĩ%1")
	translit = gsub(translit, "ito$", "itō")
	translit = gsub(translit, "oy([eiōu])", "o%1")
	translit = gsub(translit, "õy([eiōu])", "õ%1")
	translit = gsub(translit, "ōw([aeoōu])", "ō%1")
	translit = gsub(translit, "ō̃w([aeoōu])", "ō̃%1")
	translit = gsub(translit, "uy([aeioō])", "u%1")
	translit = gsub(translit, "ũy([aeioō])", "ũ%1")

	local consonants_no_h = "[b-df-gj-np-tv-zśṣʃʒ]"

	translit = gsub(translit, aspirate .. "h", '%1ʰ')
	translit = gsub(translit, weak .. "h", '%1ʱ')

	translit = gsub(translit, "([kgcjṭḍtdpb])'h", "%1h")

	if style == "colloquial" then
		translit = gsub(translit, aspirate .. "h", '%1ʰ')
		translit = gsub(translit, weak .. "h", '%1ʱ')
	end

	local result = gsub(translit, ".", correspondences)

	result = gsub(result, "%.?%-", ".")

	result = gsub(result, "%.%.", "‿")

	if style == "dhaka" then
		result = gsub(result, "ḏʑ", "dʑ") 
		result = gsub(result, "ɖ", "d") -- Khan, 2010
		result = gsub(result, "ṯɕ", "tɕ")
		result = gsub(result, "ʈ", "t") -- Khan, 2010
	end

	if style == "dhaka_colloquial" then
		result = gsub(result, "ḏʑ", "dʑ") 
		result = gsub(result, "ɖ", "d") -- Khan, 2010
		result = gsub(result, "ṯɕ", "tɕ")
		result = gsub(result, "ʈ", "t") -- Khan, 2010
	end

	if style == "vanga" then
		result = gsub(result, "ɖ", "d")
		result = gsub(result, "ʈ", "t")
	end

	if style == "vanga_colloquial" then
		result = gsub(result, "ɖ", "d")
		result = gsub(result, "ʈ", "t")
	end

	if style == "eastern_vanga" then
		result = gsub(result, "ɖ", "d")
		result = gsub(result, "ʈ", "t")
	end

	if style == "eastern_vanga_colloquial" then
		result = gsub(result, "ɖ", "d")
		result = gsub(result, "ʈ", "t")
	end

	-- formatting
	result = gsub(result, "ː̃", "̃ː")
	result = gsub(result, "ː%.̃", "̃ː.")
	result = gsub(result, "%.$", "")

	result = gsub(result, "^ɾ", "r")

	-- force final ɔe̯
	result = gsub(result, "([ʒm])oe̯$", "%1ɔe̯")

	result = gsub(result, "d̪ʑ", "dʑ")
	result = gsub(result, "t̪ɕ", "tɕ")

	-- gemination
	result = gsub(result, "bb(ʱ?)", "b%1ː")
	result = gsub(result, "dd(ʱ?)", "d%1ː")
	result = gsub(result, "d͡d͡ʒʒ(ʱ?)", "d͡ʒ%1ː")
	result = gsub(result, "dʑdʑ(ʱ?)", "dʑ%1ː")
	result = gsub(result, "d̪d̪(ʱ?)", "d̪%1ː")
	result = gsub(result, "ɖɖ(ʱ?)", "ɖ%1ː")

	result = gsub(result, "ff", "fː")
	result = gsub(result, "ɡɡ(ʱ?)", "ɡ%1ː")

	result = gsub(result, "kk(ʰ?)", "k%1ː")
	result = gsub(result, "ll", "lː")

	result = gsub(result, "mm", "mː")
	result = gsub(result, "nn", "nː")

	result = gsub(result, "nd(ʱ?)ː", "nd%1")
	result = gsub(result, "nd͡ʒ(ʱ?)ː", "nd͡ʒ%1")
	result = gsub(result, "nd̪(ʱ?)ː", "nd̪%1")
	result = gsub(result, "nɖ(ʱ?)ː", "nɖ%1")
	result = gsub(result, "nt(ʰ?)ː", "nt%1")
	result = gsub(result, "nt͡ʃ(ʰ?)ː", "nt͡ʃ%1")
	result = gsub(result, "nt̪(ʰ?)ː", "nt̪%1")
	result = gsub(result, "nʈ(ʰ?)ː", "nʈ%1")
	result = gsub(result, "ŋɡ(ʱ?)ː", "ŋɡ%1")
	result = gsub(result, "ŋɡ$", "ŋ")
	result = gsub(result, "ŋɡ ", "ŋ ")
	result = gsub(result, "ŋk(ʰ?)ː", "ŋk%1")

	result = gsub(result, "pp(ʰ?)", "p%1ː")

	result = gsub(result, "ɾɾ", "ɾ")
	result = gsub(result, "ɹɹ", "ɹ")

	result = gsub(result, "ʃʃ", "ʃː")
	result = gsub(result, "ss", "sː")
	result = gsub(result, "tt(ʰ?)", "t%1ː")
	result = gsub(result, "t͡ʃt͡ʃ(ʰ?)", "t͡ʃ%1ː")
	result = gsub(result, "tɕtɕ(ʰ?)", "tɕ%1ː")
	result = gsub(result, "t̪t̪(ʰ?)", "t̪%1ː")
	result = gsub(result, "ʈʈ(ʰ?)", "ʈ%1ː")

	result = gsub(result, "a([eou])", "a%1̯")
	result = gsub(result, "iu", "iu̯")
	result = gsub(result, "i(" .. vowel .. ")", "i̯%1")
	result = gsub(result, "i̯u̯", "iu̯")
	result = gsub(result, "oa", "o̯a")
	result = gsub(result, "ɔe̯ɔ", "ɔe̯o")
	result = gsub(result, "ɔo", "ɔo̯")
	result = gsub(result, "o([iu])", "o%1̯")
	result = gsub(result, "u(" .. vowel .. ")", "u̯%1")

	result = gsub(result, "([aeou])i", "%1i̯")

	result = gsub(result, "^ui̯", "u̯i")

	result = gsub(result, "([eiou])̯̯", "%1̯")

	return result
end

function export.narrow_IPA(ipa)
	local vowel = "[aiuoêɔɔ̃ɛeææ̃ãẽĩõũ]"
	local consonants = "[bβcdd̪ɖfɸgɦjklmnprṛɾsśs̪ʃɕtt̪ʈvzz̪ʑ]"

	-- word-final deaspiration
	ipa = gsub(ipa, "bʱ$", "b")
	ipa = gsub(ipa, "ɖʱ$", "ɖ")
	ipa = gsub(ipa, "d͡ʒʱ$", "d͡ʒ")
	ipa = gsub(ipa, "dʑʱ$", "dʑ")
	ipa = gsub(ipa, "d̪ʱ$", "d̪")
	ipa = gsub(ipa, "ɡʱ$", "ɡ")
	ipa = gsub(ipa, "kʰ$", "k")
	ipa = gsub(ipa, "pʰ$", "p")
	ipa = gsub(ipa, "ʈʰ$", "ʈ")
	ipa = gsub(ipa, "t͡ʃʰ$", "t͡ʃ")
	ipa = gsub(ipa, "tɕʰ$", "tɕ")
	ipa = gsub(ipa, "t̪ʰ$", "t̪")

	-- deaspiration before t̪
	ipa = gsub(ipa, "kʰt̪", "kt̪")
	ipa = gsub(ipa, "pʰt̪", "pt̪")

	-- regressive assimilation
	ipa = gsub(ipa, "kz", "ɡz")
	ipa = gsub(ipa, "kd͡ʒ", "ɡd͡ʒ")
	ipa = gsub(ipa, "kdʑ", "ɡdʑ")

	ipa = gsub(ipa, "b‿p", "pː")
	ipa = gsub(ipa, "d‿t", "tː")
	ipa = gsub(ipa, "d͡ʒ‿t͡ʃ", "t͡ʃː")
	ipa = gsub(ipa, "d̪‿t̪", "t̪ː")
	ipa = gsub(ipa, "f‿b", "bː")
	ipa = gsub(ipa, "ɡ‿k", "kː")
	ipa = gsub(ipa, "k‿ɡ", "ɡː")
	ipa = gsub(ipa, "p‿b", "bː")
	ipa = gsub(ipa, "t‿d", "dː")
	ipa = gsub(ipa, "t͡ʃ‿d͡ʒ", "d͡ʒː")
	ipa = gsub(ipa, "t̪‿d̪", "d̪ː")
	ipa = gsub(ipa, "sː([t̪d̪])", "s̪%1")

	ipa = gsub(ipa, "d͡ʒ(‿?)([d̪t̪])", "z̪%2")
	ipa = gsub(ipa, "d͡ʒʱ(‿?)([d̪t̪])", "z̪%2")
	ipa = gsub(ipa, "dʑ(‿?)([d̪t̪])", "z̪%2")
	ipa = gsub(ipa, "dʑʱ(‿?)([d̪t̪])", "z̪%2")

	ipa = gsub(ipa, "^(" .. consonants .. ")ɾ(" .. vowel .. ")(" .. consonants .. ")ɾ", "%1ɾ%2%3ː") -- R syncope
	ipa = gsub(ipa, "([ɖd̪ʈt̪])([lɾɹ])", "%1ː%2")

	-- intervocalic e̯
	ipa = gsub(ipa, "(" .. vowel .. ")‿(" .. vowel .. ")", "%1e̯%2")

	ipa = gsub(ipa, "‿", "")

	-- long vowels
	ipa = gsub(ipa, "^(" .. vowel .. ")(" .. consonants .. ")$", "%1ː%2")
	ipa = gsub(ipa, "^(" .. consonants .. "ʰ?)(" .. vowel .. ")$", "%1%2ː")
	ipa = gsub(ipa, "^(" .. consonants .. "ʱ)(" .. vowel .. ")$", "%1%2ː")
	ipa = gsub(ipa, "^(" .. consonants .. ")(" .. consonants .. "ʰ?)(" .. vowel .. ")$", "%1%2%3ː")
	ipa = gsub(ipa, "^(" .. consonants .. ")(" .. consonants .. "ʱ)(" .. vowel .. ")$", "%1%2%3ː")
	ipa = gsub(ipa, "^(" .. consonants .. ")(" .. consonants .. ")(" .. consonants .. "ʰ?)(" .. vowel .. ")$", "%1%2%3%4ː")
	ipa = gsub(ipa, "^(" .. consonants .. ")(" .. consonants .. ")(" .. consonants .. "ʱ)(" .. vowel .. ")$", "%1%2%3%4ː")
	ipa = gsub(ipa, "^(" .. consonants .. "ʰ?)(" .. vowel .. ")(" .. consonants .. ")$", "%1%2ː%3")
	ipa = gsub(ipa, "^(" .. consonants .. "ʱ)(" .. vowel .. ")(" .. consonants .. ")$", "%1%2ː%3")
	ipa = gsub(ipa, "^(" .. consonants .. ")(" .. consonants .. "ʰ?)(" .. vowel .. ")(" .. consonants .. ")$", "%1%2%3ː%4")

	-- half-long vowels
	ipa = gsub(ipa, "(" .. vowel .. ")$", "%1ˑ")
	ipa = gsub(ipa, "(" .. vowel .. ") ", "%1ˑ ")

	-- dental and retroflex laterals
	ipa = gsub(ipa, "l([t̪d̪])", "l̪%1")
	ipa = gsub(ipa, "l([ʈɖ])", "ɭ%1")

	-- dental and retroflex nasals
	ipa = gsub(ipa, "n([t̪d̪])", "n̪%1")
	ipa = gsub(ipa, "n̪([td])", "n%1")
	ipa = gsub(ipa, "n([ʈɖ])", "ɳ%1")

	-- dental and retroflex sibilants
	ipa = gsub(ipa, "s([t̪d̪])", "s̪%1")
	ipa = gsub(ipa, "([t̪d̪])s", "%1s̪")
	ipa = gsub(ipa, "s̪([td])", "s%1")
	ipa = gsub(ipa, "([td])s̪", "%1s")

	ipa = gsub(ipa, "z([t̪d̪])", "z̪%1")
	ipa = gsub(ipa, "([t̪d̪])z", "%1z̪")
	ipa = gsub(ipa, "z̪([td])", "z%1")
	ipa = gsub(ipa, "([td])z̪", "%1z")
	ipa = gsub(ipa, "ʃ([ʈɖ])", "ʂ%1")

	-- initial stress
	ipa = gsub(ipa, "^(" .. vowel .. ")", "ˈ%1")
	ipa = gsub(ipa, "^(" .. consonants .. ")", "ˈ%1")

	return ipa
end

local function colloquial_narrow_IPA(ipa)
	local vowel = "[aiuoêɔɔ̃ɛeææ̃ãẽĩõũ]"
	local consonants = "[bβcdd̪ɖfɸgɦjklmnprṛɾsśs̪ʃɕtt̪ʈvzz̪ʑ]"

	-- initial stress
	ipa = gsub(ipa, "^(" .. vowel .. ")", "ˈ%1")
	ipa = gsub(ipa, "^(" .. consonants .. ")", "ˈ%1")

	ipa = gsub(ipa, "bʱ", "v")
	ipa = gsub(ipa, "^v", "bʱ")
	ipa = gsub(ipa, " v", " bʱ")

	-- word-final deaspiration
	ipa = gsub(ipa, "ɖʱ$", "ɖ")
	ipa = gsub(ipa, "d͡ʒʱ$", "d͡ʒ")
	ipa = gsub(ipa, "dʑʱ$", "dʑ")
	ipa = gsub(ipa, "d̪ʱ$", "d̪")
	ipa = gsub(ipa, "ɡʱ$", "ɡ")
	ipa = gsub(ipa, "kʰ$", "x")
	ipa = gsub(ipa, "ʈʰ$", "ʈ")
	ipa = gsub(ipa, "t͡ʃʰ$", "t͡ʃ")
	ipa = gsub(ipa, "tɕʰ$", "tɕ")
	ipa = gsub(ipa, "t̪ʰ$", "t̪")

	-- deaspiration before t̪
	ipa = gsub(ipa, "kʰt̪", "xt̪")

	-- regressive assimilation
	ipa = gsub(ipa, "kd͡ʒ", "ɡd͡ʒ")
	ipa = gsub(ipa, "kdʑ", "ɡdʑ")

	ipa = gsub(ipa, "b‿p", "pː")
	ipa = gsub(ipa, "d([ʱ?])‿t", "tː")
	ipa = gsub(ipa, "d͡ʒ([ʱ?])‿t͡ʃ", "t͡ʃː")
	ipa = gsub(ipa, "d̪([ʱ?])‿t̪", "t̪ː")
	ipa = gsub(ipa, "f‿b", "bː")
	ipa = gsub(ipa, "ɡ([ʱ?])‿k", "kː")
	ipa = gsub(ipa, "k([ʰ?])‿ɡ", "ɡː")
	ipa = gsub(ipa, "p‿b", "bː")
	ipa = gsub(ipa, "t([ʰ?])‿d", "dː")
	ipa = gsub(ipa, "t͡ʃ([ʰ?])‿dʒ", "dʒː")
	ipa = gsub(ipa, "t̪([ʰ?])‿d̪", "d̪ː")
	ipa = gsub(ipa, "v‿p", "pː")
	ipa = gsub(ipa, "sː([t̪d̪])", "s̪%1")

	ipa = gsub(ipa, "dʒ(‿?)([d̪t̪])", "z̪%2")
	ipa = gsub(ipa, "dʒʱ(‿?)([d̪t̪])", "z̪%2")
	ipa = gsub(ipa, "dʑ(‿?)([d̪t̪])", "z̪%2")
	ipa = gsub(ipa, "dʑʱ(‿?)([d̪t̪])", "z̪%2")

	ipa = gsub(ipa, "^(" .. consonants .. ")ɾ(" .. vowel .. ")(" .. consonants .. ")ɾ", "%1ɾ%2%3ː") -- R syncope
	ipa = gsub(ipa, "([ɖd̪ʈt̪])([lɾɹ])", "%1ː%2")

	-- intervocalic e̯
	ipa = gsub(ipa, "(" .. vowel .. ")‿(" .. vowel .. ")", "%1e̯%2")

	ipa = gsub(ipa, "‿", "")

	-- long vowels
	ipa = gsub(ipa, "^(" .. vowel .. ")(" .. consonants .. ")$", "%1ː%2")
	ipa = gsub(ipa, "^(" .. consonants .. "ʰ?)(" .. vowel .. ")$", "%1%2ː")
	ipa = gsub(ipa, "^(" .. consonants .. "ʱ)(" .. vowel .. ")$", "%1%2ː")
	ipa = gsub(ipa, "^(" .. consonants .. ")(" .. consonants .. "ʰ?)(" .. vowel .. ")$", "%1%2%3ː")
	ipa = gsub(ipa, "^(" .. consonants .. ")(" .. consonants .. "ʱ)(" .. vowel .. ")$", "%1%2%3ː")
	ipa = gsub(ipa, "^(" .. consonants .. ")(" .. consonants .. ")(" .. consonants .. "ʰ?)(" .. vowel .. ")$", "%1%2%3%4ː")
	ipa = gsub(ipa, "^(" .. consonants .. ")(" .. consonants .. ")(" .. consonants .. "ʱ)(" .. vowel .. ")$", "%1%2%3%4ː")
	ipa = gsub(ipa, "^(" .. consonants .. "ʰ?)(" .. vowel .. ")(" .. consonants .. ")$", "%1%2ː%3")
	ipa = gsub(ipa, "^(" .. consonants .. "ʱ)(" .. vowel .. ")(" .. consonants .. ")$", "%1%2ː%3")
	ipa = gsub(ipa, "^(" .. consonants .. ")(" .. consonants .. "ʰ?)(" .. vowel .. ")(" .. consonants .. ")$", "%1%2%3ː%4")

	-- half-long vowels
	ipa = gsub(ipa, "(" .. vowel .. ")$", "%1ˑ")
	ipa = gsub(ipa, "(" .. vowel .. ") ", "%1ˑ ")

	-- dental and retroflex laterals
	ipa = gsub(ipa, "l([t̪d̪])", "l̪%1")
	ipa = gsub(ipa, "l([ʈɖ])", "ɭ%1")

	-- dental and retroflex nasals
	ipa = gsub(ipa, "n([t̪d̪])", "n̪%1")
	ipa = gsub(ipa, "n̪([td])", "n%1")
	ipa = gsub(ipa, "n([ʈɖ])", "ɳ%1")

	-- dental and retroflex sibilants
	ipa = gsub(ipa, "s([t̪d̪])", "s̪%1")
	ipa = gsub(ipa, "([t̪d̪])s", "%1s̪")
	ipa = gsub(ipa, "s̪([td])", "s%1")
	ipa = gsub(ipa, "([td])s̪", "%1s")

	ipa = gsub(ipa, "z([t̪d̪])", "z̪%1")
	ipa = gsub(ipa, "([t̪d̪])z", "%1z̪")
	ipa = gsub(ipa, "z̪([td])", "z%1")
	ipa = gsub(ipa, "([td])z̪", "%1z")

	ipa = gsub(ipa, "ʃ([td])", "s%1")
	ipa = gsub(ipa, "ʃ([ʈɖ])", "ʂ%1")

	-- initial stress
	ipa = gsub(ipa, "^(" .. vowel .. ")", "ˈ%1")
	ipa = gsub(ipa, "^(" .. consonants .. ")", "ˈ%1")

	return ipa
end

local function vanga_narrow_IPA(ipa)
	local vowel = "[aiuoêɔɔ̃ɛeææ̃ãẽĩõũ]"
	local consonants = "[bβcdd̪ɸgɦjklmnprṛɾsśs̪ʃtt̪zz̪]"
	local implosives = {
	["bʱ"] = "ɓ", ["d̪ʱ"] = "ɗ̪", ["dʱ"] = "ɗ", ["dʒʱ"] = "ɗʒ", ["ɡʱ"] = "ɠ",
}

	ipa = gsub(ipa, "bʱ", "β")
	ipa = gsub(ipa, "^β", "bʱ")
	ipa = gsub(ipa, " β", " bʱ")

	-- lenition before dental
	ipa = gsub(ipa, "dʒ([d̪t̪])", "z̪%1")
	ipa = gsub(ipa, "dʒʱ([d̪t̪])", "z̪%1")

	-- word-final deaspiration
	ipa = gsub(ipa, "bʱ$", "b")
	ipa = gsub(ipa, "ɖʱ$", "ɖ")
	ipa = gsub(ipa, "dʒʱ$", "dʒ")
	ipa = gsub(ipa, "dʑʱ$", "dʑ")
	ipa = gsub(ipa, "d̪ʱ$", "d̪")
	ipa = gsub(ipa, "ɡʱ$", "ɡ")
	ipa = gsub(ipa, "kʰ$", "k")
	ipa = gsub(ipa, "pʰ$", "p")
	ipa = gsub(ipa, "ʈʰ$", "ʈ")
	ipa = gsub(ipa, "t͡ʃʰ$", "t͡ʃ")
	ipa = gsub(ipa, "tɕʰ$", "tɕ")
	ipa = gsub(ipa, "t̪ʰ$", "t̪")

	-- half-long vowels
	ipa = gsub(ipa, "(" .. vowel .. ")$", "%1ˑ")
	ipa = gsub(ipa, "(" .. vowel .. ") ", "%1ˑ ")

	-- replacing voiced aspirates with implosives
	ipa = gsub(ipa, "([bd̪dʒɡ]ʱ)", implosives)

	-- initial stress
	ipa = gsub(ipa, "^(" .. vowel .. ")", "ˈ%1")
	ipa = gsub(ipa, "^(" .. consonants .. ")", "ˈ%1")

	return ipa
end

local function eastern_vanga_narrow_IPA(ipa)
	local vowel = "[aiuoêɔɔ̃ɛeææ̃ãẽĩõũ]"
	local consonants = "[bβcdd̪fɸgɦjklmnprṛɾsśs̪ʃtt̪zz̪]"

	ipa = gsub(ipa, "bʱ", "β")
	ipa = gsub(ipa, "^β", "bʱ")
	ipa = gsub(ipa, " β", " bʱ")

	-- lenition before dental
	ipa = gsub(ipa, "dʒ([d̪t̪])", "z̪%1")
	ipa = gsub(ipa, "dʒʱ([d̪t̪])", "z̪%1")

	-- half-long vowels
	ipa = gsub(ipa, "(" .. vowel .. ")$", "%1ˑ")
	ipa = gsub(ipa, "(" .. vowel .. ") ", "%1ˑ ")

	-- replacing aspiration with tones
	ipa = gsub(ipa, "(" .. consonants .. ")ʰ(ː?)a", "%1%2á")
	ipa = gsub(ipa, "(" .. consonants .. ")ʰ(ː?)i", "%1%2í")
	ipa = gsub(ipa, "(" .. consonants .. ")ʰ(ː?)u", "%1%2ú")
	ipa = gsub(ipa, "(" .. consonants .. ")ʰ(ː?)o", "%1%2ó")
	ipa = gsub(ipa, "(" .. consonants .. ")ʰ(ː?)ɔ", "%1%2ɔ́")
	ipa = gsub(ipa, "(" .. consonants .. ")ʰ(ː?)ɛ", "%1%2ɛ́")
	ipa = gsub(ipa, "(" .. consonants .. ")ʰ(ː?)e", "%1%2é")

	ipa = gsub(ipa, "(" .. consonants .. ")ʱ(ː?)a", "%1%2á")
	ipa = gsub(ipa, "(" .. consonants .. ")ʱ(ː?)i", "%1%2í")
	ipa = gsub(ipa, "(" .. consonants .. ")ʱ(ː?)u", "%1%2ú")
	ipa = gsub(ipa, "(" .. consonants .. ")ʱ(ː?)o", "%1%2ó")
	ipa = gsub(ipa, "(" .. consonants .. ")ʱ(ː?)ɔ", "%1%2ɔ́")
	ipa = gsub(ipa, "(" .. consonants .. ")ʱ(ː?)ɛ", "%1%2ɛ́")
	ipa = gsub(ipa, "(" .. consonants .. ")ʱ(ː?)e", "%1%2é")

	-- initial stress
	ipa = gsub(ipa, "^(" .. vowel .. ")", "ˈ%1")
	ipa = gsub(ipa, "^(" .. consonants .. ")", "ˈ%1")

	return ipa
end

-- Rarh
function export.make(frame)
	local args = frame:getParent().args
	local pagetitle = mw.title.getCurrentTitle().text

	local p, results = {}, {}, {}

	if args[1] then
		for index, item in ipairs(args) do
			table.insert(p, (item ~= "") and item or nil)
		end
	else
		p = { pagetitle }
	end

	for _, Bengali in ipairs(p) do
		local formal = export.toIPA(Bengali, "formal")
		local desanskritized = export.toIPA(Bengali, "desanskritized")
		local colloquial = export.toIPA(Bengali, "colloquial")
		table.insert(results, { pron = "/" .. formal .. "/" })
		local narrow = export.narrow_IPA(formal)
		table.insert(results, { pron = "[" .. narrow .. "]" })
		-- desanskritized
		if colloquial ~= desanskritized then if formal ~= desanskritized then table.insert(results, { pron = "/" .. desanskritized .. "/" })
			local desa_narrow = export.narrow_IPA(desanskritized)
			if desanskritized ~= desa_narrow then table.insert(results, { pron = "[" .. desa_narrow .. "]" }) end
		end end
		-- colloquial
		local col_narrow = colloquial_narrow_IPA(colloquial)
		if formal ~= colloquial then table.insert(results, { pron = "/" .. colloquial .. "/" })
			if colloquial ~= col_narrow then table.insert(results, { pron = "[" .. col_narrow .. "]" }) end
		else
			if narrow ~= col_narrow then table.insert(results, { pron = "[" .. col_narrow .. "]" }) end
		end
	end

	return  "* " ..  m_a.format_qualifiers(lang, {"Rarh"}) .. " " .. m_IPA.format_IPA_full { lang = lang, items = results }
end

-- Dhaka
function export.make_dhaka(frame)
	local args = frame:getParent().args
	local pagetitle = mw.title.getCurrentTitle().text

	local p, results = {}, {}, {}

	if args[1] then
		for index, item in ipairs(args) do
			table.insert(p, (item ~= "") and item or nil)
		end
	else
		p = { pagetitle }
	end

	for _, Bengali in ipairs(p) do
		local dhaka = export.toIPA(Bengali, "dhaka")
		local colloquial = export.toIPA(Bengali, "dhaka_colloquial")
		table.insert(results, { pron = "/" .. dhaka .. "/" })
		local narrow = export.narrow_IPA(dhaka)
		table.insert(results, { pron = "[" .. narrow .. "]" })
		-- colloquial
		local col_narrow = colloquial_narrow_IPA(colloquial)
		if dhaka ~= colloquial then table.insert(results, { pron = "/" .. colloquial .. "/" })
			if colloquial ~= col_narrow then table.insert(results, { pron = "[" .. col_narrow .. "]" }) end
		else
			if narrow ~= col_narrow then table.insert(results, { pron = "[" .. col_narrow .. "]" }) end
		end
	end

	return m_a.format_qualifiers(lang, {"Dhaka"}) .. " " ..  m_IPA.format_IPA_full { lang = lang, items = results }
end

-- Vanga
function export.make_vanga(frame)
	local args = frame:getParent().args
	local pagetitle = mw.title.getCurrentTitle().text

	local p, results = {}, {}, {}

	if args[1] then
		for index, item in ipairs(args) do
			table.insert(p, (item ~= "") and item or nil)
		end
	else
		p = { pagetitle }
	end

	for _, Bengali in ipairs(p) do
		local vanga = export.toIPA(Bengali, "vanga")
		local eastern_vanga = export.toIPA(Bengali, "eastern_vanga")
		table.insert(results, { pron = "/" .. vanga .. "/" })
		local narrow = vanga_narrow_IPA(vanga)
		table.insert(results, { pron = "[" .. narrow .. "]" })
		local eastern_narrow = eastern_vanga_narrow_IPA(eastern_vanga)
		table.insert(results, { pron = "[" .. eastern_narrow .. "]" })
	end

	return m_a.format_qualifiers(lang, {"Vanga"}) .. " " ..  m_IPA.format_IPA_full { lang = lang, items = results }
end

-- Eastern Vanga
function export.make_eastern_vanga(frame)
	local args = frame:getParent().args
	local pagetitle = mw.title.getCurrentTitle().text

	local p, results = {}, {}, {}

	if args[1] then
		for index, item in ipairs(args) do
			table.insert(p, (item ~= "") and item or nil)
		end
	else
		p = { pagetitle }
	end

	for _, Bengali in ipairs(p) do
		local vanga = export.toIPA(Bengali, "vanga")
		local eastern_vanga = export.toIPA(Bengali, "eastern_vanga")
		table.insert(results, { pron = "/" .. vanga .. "/" })
		local narrow = eastern_vanga_narrow_IPA(eastern_vanga)
		table.insert(results, { pron = "[" .. narrow .. "]" })
	end

	return m_a.format_qualifiers(lang, {"Eastern Vanga"}) .. " " ..  m_IPA.format_IPA_full { lang = lang, items = results }
end

-- Varendra
function export.make_varendra(frame)
	local args = frame:getParent().args
	local pagetitle = mw.title.getCurrentTitle().text

	local p, results = {}, {}, {}

	if args[1] then
		for index, item in ipairs(args) do
			table.insert(p, (item ~= "") and item or nil)
		end
	else
		p = { pagetitle }
	end

	for _, Bengali in ipairs(p) do
		local varendra = export.toIPA(Bengali, "varendra")
		table.insert(results, { pron = "/" .. varendra .. "/" })
		local narrow = export.narrow_IPA(varendra)
		table.insert(results, { pron = "[" .. narrow .. "]" })
	end

	return m_a.format_qualifiers(lang, {"Varendra"}) .. " " ..  m_IPA.format_IPA_full { lang = lang, items = results }
end

return export