Module:User:Babr/fa-IPA

local export = {}

local U = mw.ustring.char local lang = require("Module:languages").getByCode("fa") local m_IPA = require("Module:IPA") local m_romanize = require("Module:User:Sameerhameedy/fa-IPA/romanize") local m_harakat = require("Module:fa-IPA/harakat") local m_table = require("Module:table") local m_qual = require("Module:qualifier") local consonants = "bptTjčhxdDðrzžsšʔʾğGfqkglmnŋhɦwvy'" --needed for syllables local stop_cons = "bptTjčdDðqkg" local non_stopc = "hxrzžsšʔğGflmhɦwvy'"

local rsplit = mw.text.split local rsubn = mw.ustring.gsub local ulen = mw.ustring.len local pitchaccent = U(0x301) local devoice = U(0x325) local dtack = U(0x31E) local gstop = U(0x027) local dental = U(0x32A)

-- version of rsubn that discards all but the first return value local function rsub(term, foo, bar) local retval = rsubn(term, foo, bar) return retval end

export.all_styles = {"cls", "prs", "kbl", "haz", "kbl-Arab", "haz-Arab", "fa", "teh", "tg"} export.all_style_groups = { all = export.all_styles, cls = {"cls"}, dari = {"prs", "kbl", "haz", "kbl-Arab", "haz-Arab"}, ir = {"fa", "teh"}, tg = {"tg"} }

export.all_style_descs = { cls = "Classical Persian", prs = "Dari Persian", kabul = "Kabuli", haz = "Hazaragi", fa = "Iranian Persian", teh = "Tehrani", tg = "Tajik" }

local function flatmap(items, fun) local new = {} for _, item in ipairs(items) do		local results = fun(item) for _, result in ipairs(results) do			table.insert(new, result) end end return new end

local common_consonants = { ["j"] = "d͡ʒ", ["'"] = "ʔ", ["ḍ"] = "z", ["D"] = "d", --these are here for Hazaragi ["T"] = "t", --they are retroflexes in haz ["ğ"] = "ɣ", ["G"] = "ɣ", ["ḥ"] = "h", ["r"] = "ɾ", ["ṣ"] = "s", ["š"] = "ʃ", ["ṯ"] = "s", ["ṭ"] = "t", ["y"] = "j", ["ž"] = "ʒ", ["ẓ"] = "z", ["č"] = "t͡ʃ", ["g"] = "ɡ", ["`"] = "ˈ" }

local iranian_persian_short_vowels = {["a"] = "æ", ["i"] = "e", ["u"] = "o"}

local iranian_persian_long_vowels = { ["ā"] = "ɒː", ["ī"] = "iː", ["ū"] = "uː", ["ō"] = "uː", ["ē"] = "iː" }

local iranian_persian_consonants = {["ḏ"] = "z", ["q"] = "ɢ", ["ğ"] = "ɢ", ["k"] = "c", ["g"] = "ɟ"}

local dari_persian_short_vowels = {["a"] = "ä", ["i"] = "ɪ", ["u"] = "ʊ"}

local dari_persian_long_vowels = { ["ā"] = "ɑː", ["ī"] = "iː", ["ū"] = "uː", ["ō"] = "oː", ["ē"] = "eː" }

local dari_persian_consonants = {["ḏ"] = "z", ["v"] = "w"}

local tajik_short_vowels = {["a"] = "ä", ["i"] = "i", ["u"] = "u"}

local tajik_long_vowels = { ["ā"] = "ɔ", ["ī"] = "i", ["ū"] = "u", ["ō"] = "ɵ", ["ē"] = "e" }

local tajik_vowels = "aieuɵɔ"

local tajik_consonants = {["ḏ"] = "z", ["ɣ"] = "ʁ", ["x"] = "χ"}

local classical_persian_short_vowels = {["a"] = "a", ["i"] = "i", ["u"] = "u"}

local classical_persian_long_vowels = { ["ā"] = "ɑː", ["ī"] = "iː", ["ū"] = "uː", ["ō"] = "oː", ["ē"] = "eː" }

local classical_persian_consonants = {["ḏ"] = "ð", ["v"] = "w"}

local vowels_minus_a = "iuāīūüēōːʷ" local vowels = "aiuāīūüēōeoːʷ" --ʷ and ː are counted as vowels to prevent them from being put in the next syllable local consonant = "[^" .. vowels .. ". -]" local vowel = "[" .. vowels .. "]" local syllabify_pattern = "(" .. vowel .. ")(" .. consonant .. ")(" .. consonant .. "?)(" .. vowel .. ")"

local function syllabify(text) text = rsubn(text, "%-(" .. consonant .. ")%-(" .. consonant .. ")", "%1.%2")	text = rsubn(text, "([" .. consonants .. vowels .. "])`", "%1.`")

-- Add syllable breaks. for _ = 1, 2 do		text = rsubn(			text,			syllabify_pattern,			function(a, b, c, d)				if c == "" and b ~= "" then					c, b = b, ""				end

return a .. b .. "." .. c .. d			end )	end

-- syllable boundry consonants text = rsubn(		text,		"([" .. non_stopc .. "])([" .. stop_cons .. "])([" .. non_stopc .. "]+ʷ?)([" .. consonants .. vowels .. "])",		"%1%2.%3%4"	)	text = rsubn(text, "([" .. consonants .. "])([" .. consonants .. "])([" .. consonants .. "])", "%1%2.%3")	-- ALL syllables are CV- so vowels NEED an intial consonant (ʔ) text = rsubn(text, "([" .. consonants .. "])([.])i#", "%1%2i#") --exclude izafa/ezafe text = rsubn(text, "([.])([" .. vowels .. "])", "%1ʔ%2") text = rsubn(text, "#([" .. vowels .. "])", "#ʔ%1")

return text end

local function con_assimilation(text) --DONT USE THIS ON CLASSICAL -- assimilation/placement of certain consonants text = rsubn(text, "l((%.?)[ʈɖ])", "ɭ%1") --retroflexes are only in hazaragi text = rsubn(text, "([nl])((%.?)[td])", "%1" .. dental .. "%2") text = rsubn(text, "n((%.?)[ʈɖ])", "ɳ%1") text = rsubn(text, "([td])", "%1" .. dental .. "") text = rsubn(text, "n((%.?)[kg])", "ŋ%1") text = rsubn(text, "n((%.?)[cɟy])", "ɲ%1") text = rsubn(text, "n((%.?)[bp])", "m%1") text = rsubn(text, "n((%.?)[qɢ])", "ɴ%1") text = rsubn(text, "([nm])((%.?)[fv])", "ɱ%2") text = rsubn(text, "([āʌɑɒäæeēīioɔōuūʊɪ](%" .. dtack .. "?)(%" .. pitchaccent .. "?)(%ː?)(%.?))([h])", "%1ɦ") text = rsubn(text, "r([tdszšlž])", "ɹ%1") -- formally, f only assimiates in the same syllable text = rsubn(text, "f([bjdžğ])", "v%1") text = rsubn(text, "ɾ(%.?)ɾ", "#r%1r") text = rsubn(text, "ä(" .. pitchaccent .. ")", "æ%1") text = rsubn(text, "([ɦ])#", "ʱ#") text = rsubn(text, "([h])#", "ʰ#") return text end

function export.fa_IPA(text) text = m_romanize.romanize_ira(text) text = rsubn(text, " | ", "# | #") text = "##" .. rsubn(text, " ", "# #") .. "##"	text = rsubn(text, "i", "ī") text = rsubn(text, "e", "i") text = rsubn(text, "u", "ū") text = rsubn(text, "o", "u") text = rsubn(text, "â", "ā") text = rsubn(text, "a%-", "e-") text = rsubn(text, "%-i#", "i#") text = rsubn(text, "[-]", ".") text = rsubn(text, "v", "w") --automatically denote syllables text = syllabify(text) -- then do pitch accent mark text = rsubn(text, "`([" .. consonants .. "])([" .. vowels .. "])", "%1%2" .. pitchaccent .. "") text = rsubn(text, "([ptkč](%" .. dental .. "?))([" .. vowels .. "])", "%1ʰ%3") text = rsubn(text, "([" .. vowels .. "](%.?))q", "%1ʁ") -- Replace final a with e (can be overwritten by entering æ) text = rsubn(text, "([a])(%" .. pitchaccent .. "?)#", "e%2#") -- Replace short vowels text = rsubn(text, ".", iranian_persian_short_vowels) -- Replace long vowels text = rsubn(text, ".", iranian_persian_long_vowels) text = rsubn(text, "E(" .. pitchaccent .. "?)(%.?)y", "i%1%2y") -- Replace jj with dj	text = rsubn(text, "jj", "dj") -- Replace čč with tč	text = rsubn(text, "čč", "tč") -- Allephones text = rsubn(text, "([gbdjl](%" .. dental .. "?))#", "%1" .. devoice .. "#") -- Replace consonants text = rsubn(text, ".", iranian_persian_consonants) text = rsubn(text, "cʰ([ɒuo])", "kʰ%1") text = rsubn(text, "ɟ(%" .. devoice .. "?)([ɒuo])", "g%1%2") text = con_assimilation(text) text = rsubn(text, "#(g)", "%1" .. devoice .. "") text = rsubn(text, ".", common_consonants) text = rsubn(text, "ɾ", "ɹ") --fix the pitch accent on long vowels text = rsubn(text, "([ɒiu])ː" .. pitchaccent .. "", "%1" .. pitchaccent .. "ː") text = rsubn(text, "([ɢʁ])(%.?)t", "x%2t") text = rsubn(text, "([ʁɢ])#", "ɢ" .. devoice .. "#") text = rsubn(text, "#([ʁɢ])", "#q") text = rsubn(text, "ʁɢ", "ɢɢ") text = rsubn(text, "#g", "#k") text = rsubn(text, "c", "kʲ") text = rsubn(text, "ɟ", "ɡʲ") text = rsubn(text, "ʲʰ", "ʰʲ")

text = rsubn(text, "#", "")

text = mw.ustring.toNFC(text) return text end

function export.prs_IPA(text) --based on formal speech URBAN kabul text = m_romanize.romanize_prs(text) text = rsubn(text, "ˈ", "`") text = rsubn(text, " | ", "# | #") text = "##" .. rsubn(text, " ", "# #") .. "##"	text = rsubn(text, "%-i#", "i#") text = rsubn(text, "[-]", ".") text = rsubn(text, "v", "w") text = rsubn(text, "([iī](%`?))(%.?)y", "i%2y")

--automatically denote syllables text = syllabify(text) --pitch accent mark text = rsubn(text, "`([" .. consonants .. "])([ʷ]?)([" .. vowels .. "])", "%1%2%3" .. pitchaccent .. "") text = rsubn(text, "([ptkč])([" .. vowels .. "])", "%1ʰ%2") -- Replace short vowels text = rsubn(text, ".", dari_persian_short_vowels) text = rsubn(text, "e", "e" .. dtack ) text = rsubn(text, "o", "o" .. dtack ) -- Replace long vowels text = rsubn(text, ".", dari_persian_long_vowels) -- Replace jj with dj	text = rsubn(text, "jj", "dj") -- Replace čč with tč	text = rsubn(text, "čč", "tč") --fix the pitch accent on long vowels text = rsubn(text, "([ʌɑeiou])ː" .. pitchaccent .. "", "%1" .. pitchaccent .. "ː") -- Allephones text = con_assimilation(text) -- Replace consonants text = rsubn(text, ".", common_consonants) text = rsubn(text, "f([bjdžğ])", "v%1") text = rsubn(text, ".", dari_persian_consonants) text = rsubn(text, "ɾ(%.?)ɾ", "r%1r") text = rsubn(text, "ɪ(" .. pitchaccent .. "?)(%.?)j", "i%1%2j") text = rsubn(text, "#ɾ", "#r")

text = rsubn(text, "#", "")

text = mw.ustring.toNFC(text)

return text end

function export.prs_kbl_IPA(text) --Colloquial dialect of Kabul text = m_romanize.romanize_kbl(text) text = rsubn(text, "ˈ", "`") text = rsubn(text, " | ", "# | #") text = "##" .. rsubn(text, " ", "# #") .. "##"	text = rsubn(text, "%-i#", "i#") text = rsubn(text, "%-i%-", "i-") text = rsubn(text, "[-]", ".") --automatically denote syllables text = syllabify(text) -- universal aspiration text = rsubn(text, "([ptkč])([" .. vowels .. "])", "%1ʰ%2") -- Replace short vowels text = rsubn(text, ".", dari_persian_short_vowels) -- Replace long vowels text = rsubn(text, ".", dari_persian_long_vowels) -- Replace jj with dj	text = rsubn(text, "jj", "dj") text = rsubn(text, "āw", "aw") -- lost colloquially -- Replace čč with tč	text = rsubn(text, "čč", "tč") -- Allephones text = con_assimilation(text) -- Replace consonants text = rsubn(text, ".", dari_persian_consonants) text = rsubn(text, "f((%.?)[bjdžğ])", "v%1") text = rsubn(text, ".", common_consonants) --fix the pitch accent on long vowels text = rsubn(text, "([ʌɑeiou])ː" .. pitchaccent .. "", "%1" .. pitchaccent .. "ː") text = rsubn(text, "ɾ(%.?)ɾ", "#r%1r") text = rsubn(text, "ɪ(" .. pitchaccent .. "?)(%.?)j", "i%1%2j") text = rsubn(text, "#ɾ", "#r")

text = rsubn(text, "#", "")

text = mw.ustring.toNFC(text)

return text end

function export.prs_haz_IPA(text) --Hazaragi text = m_romanize.romanize_haz(text) text = rsubn(text, "ˈ", "`") text = rsubn(text, " | ", "# | #") text = "##" .. rsubn(text, " ", "# #") .. "##"	text = rsubn(text, "%-i#", "i#") text = rsubn(text, "%-i%-", "i-") text = rsubn(text, "[-]", ".") text = rsubn(text, "([iī](%`?))(%.?)y", "i%2y") --automatically denote syllables text = syllabify(text) -- universal aspiration text = rsubn(text, "([ptkč])([" .. vowels .. "])", "%1ʰ%2") --delete certain consonant clusters and dipthongs text = rsubn(text, "āy", "ay") text = rsubn(text, "āw", "aw") --retroflex consonants text = rsubn(text, "ḍ", "ɖ") text = rsubn(text, "ṭ", "ʈ") -- Replace short vowels text = rsubn(text, ".", classical_persian_short_vowels) --approximate vowels text = rsubn(text, "ā", "ɔː") text = rsubn(text, "ō", "ʊː") text = rsubn(text, "a", "ä") -- Replace long vowels text = rsubn(text, ".", dari_persian_long_vowels) --fix the pitch accent on long vowels text = rsubn(text, "([ɔeiʊu])ː" .. pitchaccent .. "", "%1" .. pitchaccent .. "ː") -- Replace jj with dj	text = rsubn(text, "jj", "dj") -- Replace čč with tč	text = rsubn(text, "čč", "tč") --allophones text = con_assimilation(text) text = rsubn(text, "([gbdjl](%" .. dental .. "?))#", "%1" .. devoice .. "#") --Terminal voicing in not phonetic text = rsubn(text, "([gbdj])#", "%1" .. devoice .. "#") -- Replace consonants text = rsubn(text, ".", dari_persian_consonants) text = rsubn(text, "f((%.?)[bjdžğ])", "v%1") text = rsubn(text, ".", common_consonants) text = rsubn(text, "ɾ(%.?)ɾ", "#r%1r") text = rsubn(text, "#ɾ", "#r") text = rsubn(text, "#", "")

text = mw.ustring.toNFC(text)

return text end

function export.tg_IPA(text) text = m_romanize.romanize_tg(text) text = rsubn(text, "ˈ", "`") text = rsubn(text, " | ", "# | #") text = "##" .. rsubn(text, " ", "# #") .. "##"	text = rsubn(text, "%-i#", "i#") text = rsubn(text, "[-]", ".")

text = rsubn(text, "v", "w") text = rsubn(text, "o", "ā") text = rsubn(text, "ü", "ō") text = rsubn(text, "e", "ē") text = rsubn(text, "xwē", "xē") --automatically denote syllables text = syllabify(text) -- Replace jj with dj	text = rsubn(text, "jj", "dj") -- Replace čč with tč	text = rsubn(text, "čč", "tč") text = rsubn(text, "w([" .. vowels .. "])", "v%1") -- universal aspiration text = rsubn(text, "([ptkč])([" .. vowels .. "])", "%1ʰ%2") --aspiration text = rsubn(text, "([ptkč](%" .. dental .. "?))([" .. vowels .. "])", "%1ʰ%3") -- Replace short vowels text = rsubn(text, ".", tajik_short_vowels) -- Replace long vowels text = rsubn(text, ".", tajik_long_vowels) --allophones text = con_assimilation(text) -- Replace consonants text = rsubn(text, ".", common_consonants) text = rsubn(text, ".", tajik_consonants) text = rsubn(text, "([aä])(" .. pitchaccent .. ")", "æ%2") text = rsubn(text, "#", "")

text = mw.ustring.toNFC(text)

return text end

function export.fa_cls_IPA(text) text = m_romanize.romanize_fa_cls(text) text = rsubn(text, "ˈ", "`") text = rsubn(text, " | ", "# | #") text = "##" .. rsubn(text, " ", "# #") .. "##"	text = rsubn(text, "([iī](%`?))(%.?)y", "i%2y") text = rsubn(text, "%-i#", "i#") text = rsubn(text, "[-]", ".")

text = rsubn(text, "v", "w") -- Replace xwa with xʷa text = rsubn(text, "xwa", "xʷa") -- Replace xwā with xʷā text = rsubn(text, "xwā", "xʷā") -- Replace xwē with xʷē text = rsubn(text, "xwē", "xʷē") --automatically denote syllables text = syllabify(text) -- Replace short vowels text = rsubn(text, ".", classical_persian_short_vowels) -- Replace d with ḏ after vowels text = rsubn(text, "ḏ", "ð") text = rsubn(text, "ḇ", "β") -- Replace long vowels text = rsubn(text, ".", classical_persian_long_vowels) -- Replace jj with dj	text = rsubn(text, "jj", "dj") -- Replace čč with tč	text = rsubn(text, "čč", "tč") -- Replace consonants text = rsubn(text, ".", common_consonants) text = rsubn(text, ".", classical_persian_consonants) text = rsubn(text, "#", "")

text = mw.ustring.toNFC(text)

return text end

--- Arabic spellings function export.cls_Arab(text) text = m_romanize.romanize_fa_cls(text) text = m_harakat.tr(text) return text end

function export.prs_Arab(text) text = m_romanize.romanize_prs(text) text = m_harakat.tr(text) return text end

function export.ira_Arab(text) text = m_romanize.romanize_ira(text) text = rsubn(text, "i", "ē") text = rsubn(text, "u", "ō") text = rsubn(text, "ey", "ay") text = rsubn(text, "ow", "aw") text = rsubn(text, "v", "w") text = rsubn(text, "o", "u") text = rsubn(text, "e", "i") text = rsubn(text, "â", "ā") text = m_harakat.tr(text) return text end

function export.haz_Arab(text) text = m_romanize.romanize_haz(text) text = m_harakat.tr(text) return text end

function export.kbl_Arab(text) text = m_romanize.romanize_kbl(text) text = m_harakat.tr(text) return text end

local function one_term_ipa(text, style) if style == "cls" then text = export.fa_cls_IPA(text) elseif style == "prs" then text = export.prs_IPA(text) elseif style == "kbl" then text = export.prs_kbl_IPA(text) elseif style == "haz" then text = export.prs_haz_IPA(text) -- elseif style == "kbl-Arab" then --	text = export.kbl_Arab(text) --elseif style == "haz-Arab" then --	text = export.haz_Arab(text) elseif style == "fa" then text = export.fa_IPA(text) elseif style == "teh" then text = export.fa_IPA(text) elseif style == "tg" then text = export.tg_IPA(text) end

return text end

-- style == one of the following: -- "cls": Classical Persian -- "prs": Dari Persian -- "kbl": Kabuli -- "haz": Hazaragi -- "fa": Iranian Persian -- "teh": Tehrani -- "tg": Tajik function export.IPA(text, style) local variants = {text}

local function apply_sub(from, to1, to2) return function(item) if rfind(item, from) then if to2 then return {rsub(item, from, to1), rsub(item, from, to2)} else return {rsub(item, from, to1)} end else return {item} end end end

local function call_one_term_ipa(variant) local result = { {				phonemic = one_term_ipa(variant, style, false, err) }		}		local function apply_sub(item, from, to1, qual1, to2, qual2) if rfind(item.phonemic, from) or rfind(item.phonetic, from) then return { {						phonemic = rsub(item.phonemic, from, to1), qualifiers = qual1 },					{						phonemic = rsub(item.phonemic, from, to2), qualifiers = qual2 }				}			else return {item} end end

return result end

return flatmap(variants, call_one_term_ipa) end

function export.express_styles(inputs, args_style) local pronuns_by_style = {} local expressed_styles = {}

local function dostyle(style) pronuns_by_style[style] = {} for _, val in ipairs(inputs[style]) do			local pronuns = export.IPA(val, style) for _, pronun in ipairs(pronuns) do				table.insert(pronuns_by_style[style], pronun) end end end

local function all_available(styles) local available_styles = {} for _, style in ipairs(styles) do			if pronuns_by_style[style] then table.insert(available_styles, style) end end return available_styles end

local function express_style(hidden_tag, tag, styles, indent) indent = indent or 1 if hidden_tag == true then hidden_tag = tag end if type(styles) == "string" then styles = {styles} end styles = all_available(styles) if #styles == 0 then return end local style = styles[1]

-- If style specified, make sure it matches the requested style. local style_matches if not args_style then style_matches = true else local or_styles = rsplit(args_style, "%s*,%s*") for _, or_style in ipairs(or_styles) do				local and_styles = rsplit(or_style, "%s*%+%s*") local and_matches = true for _, and_style in ipairs(and_styles) do					local negate if and_style:find("^%-") then and_style = and_style:gsub("^%-", "") negate = true end local this_style_matches = false for _, part in ipairs(styles) do						if part == and_style then this_style_matches = true break end end if negate then this_style_matches = not this_style_matches end if not this_style_matches then and_matches = false end end if and_matches then style_matches = true break end end end if not style_matches then return end

local new_style = { tag = tag, represented_styles = styles, pronuns = pronuns_by_style[style], indent = indent }		for _, hidden_tag_style in ipairs(expressed_styles) do			if hidden_tag_style.tag == hidden_tag then table.insert(hidden_tag_style.styles, new_style) return end end table.insert(			expressed_styles,			{				tag = hidden_tag,				styles = {new_style}			}		) end

for style, _ in pairs(inputs) do		dostyle(style) end

local function diff(style1, style2) if not pronuns_by_style[style1] or not pronuns_by_style[style2] then return true end return not m_table.deepEquals(pronuns_by_style[style1], pronuns_by_style[style2]) end

local fa_teh_different = diff("fa", "teh") local prs_kbl_different = diff("prs", "kbl") local prs_haz_different = diff("prs", "haz")

-- Classical Persian express_style("Classical Persian", "Classical Persian", "cls")

-- Dari Persian express_style(		"Dari, formal",		"Dari, formal",		"prs"	) express_style("Dari, formal", "Kabuli", "kbl", 2) --express_style("Dari, formal", "Persian", "kbl-Arab", 3) express_style("Dari, formal", "Hazaragi", "haz", 2) --express_style("Dari, formal", "Persian", "haz-Arab", 3)

-- Iranian Persian express_style(		"Iran, formal",		"Iran, formal",		"fa"	) if fa_teh_different then express_style("Iran, formal", "Tehrani", "teh", 2) end

-- Tajik express_style(		"Tajik, formal",		"Tajik, formal",		"tg"	)

return expressed_styles end

function export.show(frame) -- Create parameter specs local params = { [1] = {}, -- this replaces style group 'all' ["pre"] = {}, ["post"] = {}, ["ref"] = {}, ["style"] = {}, ["bullets"] = {type = "number", default = 1} }	for group, _ in pairs(export.all_style_groups) do		if group ~= "all" then params[group] = {} end end for _, style in ipairs(export.all_styles) do		params[style] = {} end

-- Parse arguments local parargs = frame:getParent.args local args = require("Module:parameters").process(parargs, params)

-- Set inputs local inputs = {} -- If 1= specified, do all styles. if args[1] then for _, style in ipairs(export.all_styles) do			inputs[style] = args[1] end end -- Then do remaining style groups other than 'all', overriding 1= if given. for group, styles in pairs(export.all_style_groups) do		if group ~= "all" and args[group] then for _, style in ipairs(styles) do				inputs[style] = args[group] end end end -- Then do individual style settings. for _, style in ipairs(export.all_styles) do		if args[style] then inputs[style] = args[style] end end -- If no inputs given, set all styles based on current pagename. if not next(inputs) then local text = mw.title.getCurrentTitle.text for _, style in ipairs(export.all_styles) do			inputs[style] = text end end

for style, input in pairs(inputs) do		inputs[style] = rsplit(input, ",") end local expressed_styles = export.express_styles(inputs, args.style)

local lines = {}

local function format_style(tag, expressed_style, is_first) local pronunciations = {} local formatted_pronuns = {} for _, pronun in ipairs(expressed_style.pronuns) do			table.insert(				pronunciations,				{					pron = "[" .. pronun.phonemic .. "]",					qualifiers = pronun.qualifiers				}			) local formatted_phonemic = "[" .. pronun.phonemic .. "]"			if pronun.qualifiers then formatted_phonemic = "(" .. table.concat(pronun.qualifiers, ", ") .. ") " .. formatted_phonemic end table.insert(formatted_pronuns, formatted_phonemic) end -- Number of bullets: When indent = 1, we want the number of bullets given by `args.bullets`, -- and when indent = 2, we want `args.bullets + 1`, hence we subtract 1. local bullet = string.rep("*", args.bullets + expressed_style.indent - 1) .. " "		-- Here we construct the formatted line in `formatted`, and also try to construct the equivalent without HTML -- and wiki markup in `formatted_for_len`, so we can compute the approximate textual length for use in sizing -- the toggle box with the "more" button on the right. local pre = is_first and args.pre and args.pre .. " " or "" local pre_for_len = pre .. (tag and "(" .. tag .. ") " or "") pre = pre .. (tag and m_qual.format_qualifier(tag) .. " " or "") local post = is_first and (args.ref or "") .. (args.post and " " .. args.post or "") or "" local formatted = bullet .. pre .. m_IPA.format_IPA_full { lang = lang, items = pronunciations } .. post local formatted_for_len = bullet .. pre .. "IPA(key): " .. table.concat(formatted_pronuns, ", ") .. post return formatted, formatted_for_len end

for i, style_group in ipairs(expressed_styles) do		if #style_group.styles == 1 then style_group.formatted, style_group.formatted_for_len = format_style(style_group.styles[1].tag, style_group.styles[1], i == 1) else style_group.formatted, style_group.formatted_for_len = format_style(style_group.tag, style_group.styles[1], i == 1) for j, style in ipairs(style_group.styles) do				style.formatted, style.formatted_for_len = format_style(style.tag, style, i == 1 and j == 1) end end end

local function textual_len(text) text = rsub(text, "<.->", "") return ulen(text) end

local maxlen = 0 for i, style_group in ipairs(expressed_styles) do		local this_len = textual_len(style_group.formatted_for_len) if #style_group.styles > 1 then for _, style in ipairs(style_group.styles) do				this_len = math.max(this_len, textual_len(style.formatted_for_len)) end end maxlen = math.max(maxlen, this_len) end

for i, style_group in ipairs(expressed_styles) do		if #style_group.styles == 1 then table.insert(lines, " \n" .. style_group.formatted .. " ") else local inline = '\n \n' .. style_group.formatted .. " "			local full_prons = {} for _, style in ipairs(style_group.styles) do				table.insert(full_prons, style.formatted) end local full = '\n \n' .. table.concat(full_prons, "\n") .. " "			local em_length = math.floor(maxlen * 0.68) -- from Module:grc-pronunciation table.insert(				lines,				' ' ..							inline .. full .. " "			) end end

-- major hack to get bullets working on the next line return table.concat(lines, "\n") .. "\n " end return export