text:
Module:User:Benwing2/ca-IPA

local export = {}

local lang = require("Module:languages").getByCode("ca")

local m_IPA = require("Module:IPA") local m_a = require("Module:accent qualifier") local m_table = require("Module:table")

local parse_utilities_module = "Module:parse utilities" local patut_module = "Module:pattern utilities"

local listToSet = require("Module:table").listToSet

--[=[ FIXME:

1. [zʒ] should reduce to [ʒ] in Central and Balearic (disjunt, disjuntor). Similar for [sʃ] (desxifrar). 2. There needs to be a way of forcing [ʃ]. (Maybe just ʃ?) [DONE] 3. Make sure manual dot for syllable break works, cf. best-seller respelled `bèst.sèlerr'. [DONE] 4. Explicit accents on a/i/u should be removed in split_syllables. 5. Compress double schwa in Central/Balearic in e.g. sobreescalfament, centreafricà, contraatac, contraescarpa; seems not to operate in Valencian. 6. Compress unstressed  and  followed by coda consonant -> [u] in Central/Balearic in e.g. aeroespacial, autoescola, antiespasmòdic, but not autoerotisme, antiemètic; seems not to operate in Valencian. NOTE: It does operate in an open syllable in fotoelèctric, fotoelectricitat, macroeconomia; not sure why. 7. Compress unstressed  followed by a coda consonant -> [u] in Central/Balearic in e.g. microorganisme. Seems not to operate in Valencian. 8. bm -> [mm] e.g. subministrament; seems not to operate in Valencian. 9. ë (and presumably ê) doesn't work in secondary stress, always becomes /ɛ/ (e.g. in extrajudicial respelled  'ëxtrajudiciàl'; this seems to be because the handling of ë goes through mid_vowel_hint, which doesn't work for   secondary stress. [DONE] 10. Respect ʃ at beginning of word in Valencian. [DONE] 11. [ʃ] in single substitution specs should match against written x. [DONE] 12. Prefixes e.g. xilo- should not have stress by default, and written primary stresses should be converted to    secondary. [DONE] 13. Convert apostrophe near beginning to tie (‿) and make sure we take account of it later, so that words like	captindre's and phrases like dona d'aigua work correctly. [DONE] 14. Correctly handle -bl and -gl in respelling, generating [bl] and [gl]. 15. Correctly handle [βðɣ] in respelling forcing fricatives; should not be fortitioned. 16. [βðɣ] in single substitution specs should match against b/d/g. [DONE] 17. [ss] in single substitution specs should match against ss?; used to force a pronounced [s]. [DONE] 18. [dm] in single substitution specs should match against [td]m. 19. Correctly handle written -dg- after [rz]: fricatives in Valencian, stops in Central (and Balearic?). [DONE] 20. Correctly handle lenition of written -bdg-: (1) -b- not lenited in Valencian or Balearic, lenited to [β] in   Central Catalan after vowels and consonants except nasals and [rz]; (2) -g- not lenited after nasals, also not after [rz] in Central Catalan (and maybe Balearic?), otherwise yes except utterance initial; (3) -d- not lenited after nasals or laterals, also not after [rz] in Central Catalan (and maybe Balearic?), otherwise yes except utterance initial. Verify against ca-IPA equivalent on cawikt and also based on and the IEC grammar that Vriullop linked. [DONE] 21. Finish rewriting do_dialect_specific to operate on whole word using Lua patterns. [DONE] 22. Implement multiword handling. [DONE] 23. Make sure suffix handling works correctly. [DONE] 24. Add many more test cases and redo test harness ala the German test harness. [DONE] 25. Redo handling of mid-vowel hints so it gets done early and in one place. [DONE] 26. Think about how to solve the issue of mid-vowel hints along with secondary stress marks in substitution specs. Maybe a single mid-vowel spec should be rewritten to be a single substitution spec and the insertion of the mid-vowel spec should happen during resolution of substitution specs. [DONE] 27.  should default to [dm] not [mm]. 28. Fix handling of mid vowel default in -è/-ès/-esa so it doesn't affect tèbia etc. [DONE] 29. x- after hyphen should probably become tx- in Valencian, cf. para-xocs. 30. Implement DOTOVER to indicate lack of stress in a word, e.g. in a suffix. [DONE] 31. Handle words without vowels. [DONE] 32. Finish reviewing places where we may need to check for tie symbols. 33. Handle tie indicating liaison in e.g. Sant Antoni de Portmany. [DONE] 34. Handle pronunciation of amb correctly. [DONE] 35. Handle tie indicating liaison before h- correctly, e.g. Sant Hipòlit. [DONE] 36. Lenition should happen in Valencian in regla whether respelled 'réggla', 'régla' or 'rég_la'. [DONE] 37. Syllabification should happen correctly when underscore is used in 'bíb_lia' to block doubling of . [DONE] 38.  should show up as [ŋn]. [DONE] 39. Delete [t] after [s] before anything but [s] (best-seller) or [ɾ] (postrem). [DONE] 40. Delete  after  before consonant even in Valencian; likewise for  after ,  after . [DONE] 41. DOTOVER in single substitution specs should work. [DONE] 42. Underline in single substitution specs should work. [DONE] 43. LINEUNDER should work to indicate secondary stress after the primary stress, including in single substitution specs. [DONE] ]=]

local usub = mw.ustring.sub local rfind = mw.ustring.find local rmatch = mw.ustring.match local rsplit = mw.text.split local rsubn = mw.ustring.gsub local ulower = mw.ustring.lower local u = mw.ustring.char local ugcodepoint = mw.ustring.gcodepoint

export.dialects = {"bal", "cen", "val"} export.dialects_to_names = { bal = "Balearic", cen = "Central Catalan", val = "Valencian", } export.dialect_groups = { east = {"bal", "cen"}, }

local written_unaccented_vowel_l = "aeiouyAEIOUY" local written_stressed_vowel_l = "àèéêëíòóôúýÀÈÉÊËÍÒÓÔÚÝ" local written_accented_not_stressed_vowel_l = "ïüÏÜ" local written_accented_vowel_l = written_stressed_vowel_l .. written_accented_not_stressed_vowel_l local ipa_vowel_l = "ɔɛə" local written_vowel_l = written_unaccented_vowel_l .. written_accented_vowel_l local vowel_l = written_vowel_l .. ipa_vowel_l local V = "[" .. vowel_l .. "]" local written_accented_to_plain_vowel = { ["à"] = "a", ["è"] = "e", ["é"] = "e", ["ê"] = "e", ["ë"] = "e", ["í"] = "i", ["ï"] = "i", ["ò"] = "o", ["ó"] = "o", ["ô"] = "o", ["ú"] = "u", ["ü"] = "u", ["ý"] = "y", ["À"] = "A", ["È"] = "E", ["É"] = "E", ["Ê"] = "E", ["Ë"] = "E", ["Í"] = "I", ["Ï"] = "I", ["Ò"] = "O", ["Ó"] = "O", ["Ô"] = "O", ["Ú"] = "U", ["Ü"] = "U", ["Ý"] = "Y", }

local AC = u(0x0301) -- acute = ́ local GR = u(0x0300) -- grave = ̀ local CFLEX = u(0x0302) -- circumflex = ̂ local DOTOVER = u(0x0307) -- dot over = ̇ local DIA = u(0x0308) -- diaeresis = ̈ local LINEUNDER = u(0x0331) -- lineunder = ̱

local stress_l = AC .. GR local stress_c = "[" .. stress_l .. "]" local ipa_stress_l = "ˈˌ" local ipa_stress_c = "[" .. ipa_stress_l .. "]" local sylsep_l = "%-." -- hyphen included for syllabifying from spelling; FIXME: formerly included SYLDIV local sylsep_c = "[" .. sylsep_l .. "]" local tie_l = "‿'" local tie_c = "[" .. tie_l .. "]" local charsep_l = sylsep_l .. tie_l .. stress_l .. ipa_stress_l local charsep_c = "[" .. charsep_l .. "]" local wordsep_l = "# " local wordsep_c = "[" .. wordsep_l .. "]" local separator_l = charsep_l .. wordsep_l local separator_c = "[" .. separator_l .. "]" local neg_guts_of_cons = vowel_l .. separator_l local C = "[^" .. neg_guts_of_cons .. "]" -- consonant class including h

export.mid_vowel_hints = "éèêëóòô" export.mid_vowel_hint_c = "[" .. export.mid_vowel_hints .. "]"

local TEMP_PAREN_R = u(0xFFF1) local TEMP_PAREN_RR = u(0xFFF2) -- Pseudo-consonant at the edge of prefixes ending in a vowel and suffixes beginning with a vowel; FIXME: not currently -- used. local PSEUDOCONS = u(0xFFF3) -- local PREFIX_MARKER = u(0xFFF4) -- marker indicating a prefix so we can convert primary to secondary accents

local valid_onsets = listToSet { "b", "bl", "br", "c", "cl", "cr", "ç", "d", "dj", "dr", "f", "fl", "fr", "g", "gl", "gr", "gu", "gü", "h", "i", "j", "k", "kl", "kr", "l", "ll", "m", "n", "ny", "ñ", "p", "pl", "pr", "qu", "qü", "r", "rr", "s", "ss", "t", "tg", "tj", "tr", "tx", "tz", "u", "v", "vl", "w", "x", "y", "z", }

local decompose_dotover = { -- No composed i, u or U with DOTOVER. ["ȧ"] = "a" .. DOTOVER, ["ė"] = "e" .. DOTOVER, ["ȯ"] = "o" .. DOTOVER, ["ẏ"] = "y" .. DOTOVER, ["Ȧ"] = "A" .. DOTOVER, ["Ė"] = "E" .. DOTOVER, ["İ"] = "I" .. DOTOVER, ["Ȯ"] = "O" .. DOTOVER, ["Ẏ"] = "Y" .. DOTOVER, }

local unstressed_words = listToSet { -- proclitic object pronouns "em", "et", "es", "el", "la", "els", "les", "li", "ens", "us", "ho", "hi", "en", -- enclitic object pronouns usually attach with hyphen to preceding verb but not always, cf. tant me fa "me", "te", "se", "lo", "los", "nos", "vos", "ne", -- contracted object pronouns and articles attached with apostrophe so no need to include -- unstressed possessives "mon", "ma", "mos", "mes", "ton", "ta", "tos", "tes", "son", "sa", "sos", "ses", -- prepositions "a", "de", "per", "amb", "ab", -- 'en' already included as proclitic object pronouns -- prepositional contractions "al", "als", "del", "dels", "pel", "pels", -- articles 'el', 'la', 'els', 'les' already included as proclitic pronouns -- personal articles "na", -- 'en' already included above -- indefinite articles "un", "uns", -- salat articles "ets", "so", -- 'es' already included as proclitic object pronouns and 'ses', 'sa', 'sos' as possessives -- conjunctions "i", "o", "si", "ni", "que", }

-- 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

-- Version of rsubn that returns a 2nd argument boolean indicating whether a substitution was made. local function rsubb(term, foo, bar) local retval, nsubs = rsubn(term, foo, bar) return retval, nsubs > 0 end

-- Apply rsub repeatedly until no change. local function rsub_repeatedly(term, foo, bar) while true do		local new_term = rsub(term, foo, bar) if new_term == term then return term end term = new_term end end

local function split_into_chars(text) local chars = {} for codepoint in ugcodepoint(text) do		table.insert(chars, u(codepoint)) end return chars end

local function split_on_comma(term) if term:find(",%s") or term:find("\\") then return require(parse_utilities_module).split_on_comma(term) else return rsplit(term, ",") end end

local function concat_keys(tab) local res = {} for k, _ in pairs(tab) do		table.insert(res, k)	end return table.concat(res) end

local function handle_unstressed_words(words) words = m_table.deepcopy(words)

-- Lowercase all words for ease in further processing. for i, wordobj in ipairs(words) do		wordobj.term = ulower(wordobj.term) end

-- Check if the word at index `i` in `words` is "amb" and the following word begins with a vowel. local function is_amb_to_join(words, i) return i < #words and words[i].term == "a" .. DOTOVER .. "mb" and rfind(words[i + 1].term, "^h?" .. V)	end local saw_amb_to_join = true

-- Mark all unstressed words with DOTOVER, so that split_syllables doesn't assign stress. We need to do this -- before special handling for amb, because amb may join to another unstressed word like el, in the -- process losing the identity of the two words. In the process, see if amb occurs before a following -- vowel-initial word (which may begin with h-). for i, wordobj in ipairs(words) do -- Put DOTOVER after the last vowel (to handle the case of que). It doesn't actually matter where we put -- it, because split_syllables just looks for DOTOVER anywhere in the word. if unstressed_words[wordobj.term] then wordobj.term = rsub(wordobj.term, "^(.*" .. V .. ")", "%1" .. DOTOVER) end if is_amb_to_join(words, i) then saw_amb_to_join = true end end

-- Join amb before vowel-initial word with following word. if saw_amb_to_join then local new_words = {} local i = 1 while i <= #words do			if is_amb_to_join(words, i) then table.insert(new_words, {term = words[i].term .. "‿" .. words[i + 1].term, pos = words[i + 1].pos}) i = i + 2 else table.insert(new_words, words[i]) i = i + 1 end end words = new_words end

-- Finally, rewrite some unstressed words to get the right pronunciation. Any remaining amb not before a	-- vowel-initial word is pronounced [am] even in Valencian (where [amp]/[amb] would be expected), and per always -- has a pronounced . local unstressed_word_replacement = { ["a" .. DOTOVER .. "mb"] = "a" .. DOTOVER .. "m", ["pe" .. DOTOVER .. "r"] = "pe" .. DOTOVER .. "rr", }

for i, wordobj in ipairs(words) do		wordobj.term = unstressed_word_replacement[wordobj.term] or wordobj.term end

return words end

local function fix_prefixes(word) -- Orthographic fixes for unassimilated prefixes local prefix = { "a[eè]ro", "ànte", "[aà]nti", "[aà]rxi", "[aà]uto", -- a- is ambiguous as prefix "bi", "b[ií]li", "bio", "c[oò]ntra", -- ambiguous co- "dia", "dodeca", "[eé]ntre", "equi", "estereo", -- ambiguous e-(radic) "f[oó]to", "g[aà]stro", "gr[eé]co", "hendeca", "hepta", "hexa", "h[oò]mo", "[ií]nfra", "[ií]ntra", "m[aà]cro", "m[ií]cro", "mono", "morfo", "m[uú]lti", "n[eé]o", "octo", "orto", "penta", "p[oòô]li", "pol[ií]tico", "pr[oòô]to", "ps[eèêë]udo", "psico", -- ambiguous pre-(s), pro- "qu[aà]si", "qu[ií]mio", "r[aà]dio", -- ambiguous re- "s[eèêë]mi", "s[oó]bre", "s[uú]pra", "termo", "tetra", "tri", -- ambiguous tele-(r) "[uú]ltra", "[uu]n[ií]", "v[ií]ce" }	local prefix_r = {"[eèéêë]xtra", "pr[eé]"} local prefix_s = {"antropo", "centro", "deca", "d[ií]no", "eco", "[eèéêë]xtra", "hetero", "p[aà]ra", "post", "pré", "s[oó]ta", "tele"} local prefix_i = {"pr[eé]", "pr[ií]mo", "pro", "tele"} local no_prefix = {"autoic", "autori", "biret", "biri", "bisa", "bisell", "bisó", "biur", "contrari", "contrau", "diari", "equise", "heterosi", "monoi", "parasa", "parasit", "preix", "psicosi", "sobrera", "sobreri"}

-- False prefixes for _, pr in ipairs(no_prefix) do if rfind(word, "^" .. pr) then return word end end

-- Double r in prefix + r + vowel for _, pr in ipairs(prefix_r) do word = rsub(word, "^(" .. pr .. ")r([aàeèéiíïoòóuúü])", "%1rr%2") end word = rsub(word, "^eradic", "erradic")

-- Double s in prefix + s + vowel for _, pr in ipairs(prefix_s) do word = rsub(word, "^(" .. pr .. ")s([aàeèéiíïoòóuúü])", "%1ss%2") end

-- Hiatus in prefix + i	for _, pr in ipairs(prefix_i) do word = rsub(word, "^(" .. pr .. ")i(.)", "%1ï%2") end

-- Both prefix + r/s or i/u for _, pr in ipairs(prefix) do word = rsub(word, "^(" .. pr .. ")([rs])([aàeèéiíïoòóuúü])", "%1%2%2%3") word = rsub(word, "^(" .. pr .. ")i(.)", "%1ï%2") word = rsub(word, "^(" .. pr .. ")u(.)", "%1ü%2") end

-- Voiced s in prefix roots -fons-, -dins-, -trans- word = rsub(word, "^enfons([aàeèéiíoòóuú])", "enfonz%1") word = rsub(word, "^endins([aàeèéiíoòóuú])", "endinz%1") word = rsub(word, "tr([aà])ns([aàeèéiíoòóuúbdghlmv])", "tr%1nz%2")

-- in + ex > ineks/inegz word = rsub(word, "^inex", "inhex")

return word end

local function restore_diaereses(word) -- Some structural forms do not have diaeresis per diacritic savings, let's restore it to identify hiatus

word = rsub(word, "([iu])um(s?)$", "%1üm%2") -- Latinisms (-ius is ambiguous but rare)

word = rsub(word, "([aeiou])isme(s?)$", "%1ísme%2") -- suffix -isme word = rsub(word, "([aeiou])ist([ae]s?)$", "%1íst%2") -- suffix -ista

word = rsub(word, "([aeou])ir$", "%1ír") -- verbs -ir word = rsub(word, "([aeou])int$", "%1ínt") -- present participle word = rsub(word, "([aeo])ir([éà])$", "%1ïr%2") -- future word = rsub(word, "([^gq]u)ir([éà])$", "%1ïr%2") word = rsub(word, "([aeo])iràs$", "%1ïràs") word = rsub(word, "([^gq]u)iràs$", "%1ïràs") word = rsub(word, "([aeo])ir(e[mu])$", "%1ïr%2") word = rsub(word, "([^gq]u)ir(e[mu])$", "%1ïr%2") word = rsub(word, "([aeo])iran$", "%1ïran") word = rsub(word, "([^gq]u)iran$", "%1ïran") word = rsub(word, "([aeo])iria$", "%1ïria") -- conditional word = rsub(word, "([^gq]u)iria$", "%1ïria") word = rsub(word, "([aeo])ir(ie[sn])$", "%1ïr%2") word = rsub(word, "([^gq]u)ir(ie[sn])$", "%1ïr%2")

return word end

local function fix_y(word) -- y > vowel i else consonant /j/, except ny

word = rsub(word, "ny", "ñ")

word = rsub(word, "y([^aeiouàèéêëíòóôúïü])", "i%1") -- vowel if not next to another vowel word = rsub(word, "([^aeiouàèéêëíòóôúïü·%-%.])y", "%1i") -- excluding also syllables separators

return word end

local function mid_vowel_fixes(word) local function track_mid_vowel(vowel, cont) require("Module:debug/track"){"ca-IPA/" .. vowel, "ca-IPA/" .. vowel .. "/" .. cont} return true end local changed -- final -el (not -ell) usually è but not too many cases word, changed = rsubb(word, "e(nts?)$", "é%1") if changed then track_mid_vowel("e", "nt-nts") end word, changed = rsubb(word, "e(rs?)$", "é%1") if changed then track_mid_vowel("e", "r-rs") end word, changed = rsubb(word, "o(rs?)$", "ó%1") if changed then track_mid_vowel("o", "r-rs") end word, changed = rsubb(word, "è(s?)$", "ê%1") if changed then track_mid_vowel("è", "s-blank") end word, changed = rsubb(word, "e(s[oe]s)$", "ê%1") if changed then track_mid_vowel("e", "sos-sa-ses") end word, changed = rsubb(word, "e(sa)$", "ê%1") if changed then track_mid_vowel("e", "sos-sa-ses") end return word end

local function word_fixes(word) word = rsub(word, "%(rr%)", TEMP_PAREN_RR) word = rsub(word, "%(r%)", TEMP_PAREN_R) word = rsub(word, "%-([rs]?)", "-%1%1") word = rsub(word, "rç$", "rrs") -- silent r only in plurals -rs word = fix_prefixes(word) -- internal pause after a prefix word = restore_diaereses(word) -- no diaeresis saving word = fix_y(word) -- ny > ñ else y > i vowel or consonant word = mid_vowel_fixes(word) -- all words in pn- (e.g. pneumotòrax and mn- (e.g. mnemònic) have silent p/m in both Central and Valencian	word = rsub(word, "^[pm]n", "n")

return word end

local function split_vowels(vowels, saw_dotover, saw_lineunder) local syllables = vowels = usub(vowels, 2)

while vowels ~= "" do		local syll = {onset = "", vowel = "", coda = ""} syll.onset, syll.vowel, vowels = rmatch(vowels, "^([iu]?)(.)(.-)$") table.insert(syllables, syll) end

local count = #syllables

if count >= 2 and (syllables[count].vowel == "i" or syllables[count].vowel == "u") then syllables[count - 1].coda = syllables[count].vowel syllables[count] = nil end

return syllables end

-- Split the word into syllables. Return a list of syllable objects, each of which contains fields `onset`, `vowel`, -- `coda`, `separator` (a user-specified syllable divider that goes before the syllable; one of '·', '-' or '.') and -- `stressed` (a boolean indicating that the syllable is stressed). In addition, the list has fields `stress` (the -- index of the syllable with primary stress) and `is_prefix` (true if the word is a prefix, i.e. it ends in '-'). -- Normally, prefixes are treated as unstressed if a stressed syllable isn't explicitly marked, but this can be -- overridden with `stress_prefixes`, which causes the automatic stress-assignment algorithm to run for these terms. local function split_syllables(word, stress_prefixes, may_be_uppercase) local syllables = {} local saw_dotover = false

local remainder = word local is_prefix = false if remainder:find("%-$") then -- prefix is_prefix = true remainder = remainder:gsub("%-$", "") end local is_suffix = false if remainder:find("^%-") then -- suffix is_suffix = true remainder = remainder:gsub("^%-", "") end

while remainder ~= "" do		local consonants, vowels

-- FIXME: Using C and V below instead of the existing patterns slows things down TREMENDOUSLY. -- Not sure why. local vowel_list = may_be_uppercase and "aeiouàèéêëíòóôúïüAEIOUÀÈÉÊËÍÒÓÔÚÏÜ" .. DOTOVER .. LINEUNDER or "aeiouàèéêëíòóôúïü" .. DOTOVER .. LINEUNDER consonants, remainder = rmatch(remainder, "^([^" .. vowel_list .. "]*)(.-)$")		vowels, remainder = rmatch(remainder, "^([" .. vowel_list .. "]*)(.-)$")		local this_saw_dotover = not not rfind(vowels, DOTOVER) if this_saw_dotover then saw_dotover = true vowels = vowels:gsub(DOTOVER, "") end local this_saw_lineunder = not not rfind(vowels, LINEUNDER) if this_saw_lineunder then vowels = vowels:gsub(LINEUNDER, "") end

if vowels == "" then if #syllables > 0 then syllables[#syllables].coda = syllables[#syllables].coda .. consonants else -- word without vowels, e.g. foot boundary | table.insert(syllables, {onset = consonants, vowel = "", coda = "", separator = ""}) end else local onset = consonants local first_vowel = usub(vowels, 1, 1)

if (rfind(onset, "[gqGQ]$") and (first_vowel == "ü" or (first_vowel == "u" and vowels ~= "u"))) or ((onset == "" or onset == "h" or onset == "H") and #syllables == 0 and				(first_vowel == "i" or first_vowel == "I") and (vowels ~= "i" and vowels ~= "I")) then onset = onset .. usub(vowels, 1, 1) vowels = usub(vowels, 2) end

local vsyllables = split_vowels(vowels, this_saw_dotover, this_saw_lineunder) vsyllables[1].onset = onset .. vsyllables[1].onset

for _, s in ipairs(vsyllables) do				table.insert(syllables, s)			end end end

-- Shift over consonants from the onset to the preceding coda, until the syllable onset is valid for i = 2, #syllables do		local current = syllables[i] local previous = syllables[i-1]

while not (current.onset == "" or valid_onsets[rsub(rsub(current.onset, tie_c .. "[hH]?$", ""), "_", "")]) do			local letter = usub(current.onset, 1, 1) current.onset = usub(current.onset, 2) if rfind(letter, "[·%-%.]") then -- syllable separators current.separator = letter break else previous.coda = previous.coda .. letter if rfind(letter, tie_c) then break end end end end

-- Detect stress for i, syll in ipairs(syllables) do if rfind(syll.vowel, "^[" .. written_stressed_vowel_l .. "]$") then syll.stressed = true -- primary stress: the last one stressed without LINEUNDER if not syll.has_lineunder then syllables.stress = i			end end end

-- Assign default stress if not syllables.stress and not saw_dotover and (stress_prefixes or not is_prefix) then local count = #syllables

if count == 1 then if syllables[1].vowel ~= "" then -- vowel-less words don't get stress syllables.stress = 1 end else local final = syllables[count]

-- Take account of tie symbols (apostrophes and ‿). if rfind(final.coda, "^[s" .. tie_l .. "]*$") or (rfind(final.coda, "^" .. tie_c .. "*n" .. tie_c .. "*$") and ( final.vowel == "e" or final.vowel == "i" or final.vowel == "ï")) then syllables.stress = count - 1 else syllables.stress = count end end if syllables.stress then syllables[syllables.stress].stressed = true end end

syllables.is_prefix = is_prefix syllables.is_suffix = is_suffix return syllables end

local function reconstitute_word_from_syllables(syllables) local parts = {} local function ins(txt) table.insert(parts, txt) end if syllables.is_suffix then ins("-") end for _, syl in ipairs(syllables) do		ins(syl.separator) ins(syl.onset) ins(syl.vowel) if syl.has_dotover then ins(DOTOVER) end if syl.has_lineunder then ins(LINEUNDER) end ins(syl.coda) end if syllables.is_prefix then ins("-") end return table.concat(parts) end

local function decompose_respelling(text) local dotover_keys = concat_keys(decompose_dotover) return rsub(text, "[" .. dotover_keys .. "]", decompose_dotover) end

local function canon_respelling(text) local function canon_spaces(text) text = rsub(text, "%s+", " ") text = rsub(text, "^ ", "") text = rsub(text, " $", "") return text end

text = canon_spaces(text) -- eliminate upside down punctuation text = rsub(text, "[¡¿]", "") -- eliminate utterance-final punctuation text = rsub(text, "[!?.]$", "") -- eliminate double and triple quotes text = rsub(text, "''+", "") -- Convert commas and em/en dashes to IPA foot boundaries; require a space after commas and en dashes (for the	-- latter, in particular, to avoid treating the en dash in 'Bose–Einstein condensate' as a foot boundary.	text = rsub(text, " *[,–] ", " | ")	text = rsub(text, " *[—] *", " | ")	-- ... in phrases like com es diu...en català and necessito ... become foot boundaries	text = rsub(text, " *%.%.%. *", " | ")	-- remaining commas and en dashes become spaces	text = rsub(text, "[,–]", " ")	-- may need to eliminate extraneous spaces again, e.g. if there was a space before or after an eliminated	-- punctuation mark	text = canon_spaces(text)	-- question mark or exclamation point in the middle of a sentence -> IPA foot boundary	text = rsub(text, "([^ ]) *[!?] *([^ ])", "%1 | %2")	return text end

local IPA_vowels_central = { ["ê"] = "ɛ", ["ë"] = "ɛ", ["ô"] = "ɔ", } local IPA_vowels_balearic = { ["ê"] = "ə", ["ë"] = "ɛ", ["ô"] = "ɔ", } local IPA_vowels_valencian = { ["ê"] = "e", ["ë"] = "e", ["ô"] = "o", }

local IPA_vowels = { ["à"] = "a", ["è"] = "ɛ", ["ê"] = "ɛ", ["ë"] = "ɛ", ["é"] = "e", ["í"] = "i", ["ï"] = "i", ["ò"] = "ɔ", ["ô"] = "ɔ", ["ó"] = "o", ["ú"] = "u", ["ü"] = "u", }

local function replace_context_free(cons) cons = rsub(cons, "ŀ", "l")

cons = rsub(cons, "r", "ɾ") cons = rsub(cons, "ɾɾ", "r") cons = rsub(cons, "ss", "s") cons = rsub(cons, "ll", "ʎ") cons = rsub(cons, "ñ", "ɲ") -- hint ny > ñ

-- NOTE: We use single-character affricate symbols during processing for ease in handling, and convert them -- to tied multi-character affricates at the end of join_syllables. cons = rsub(cons, "[dt]j", "ʤ") cons = rsub(cons, "tx", "ʧ") cons = rsub(cons, "[dt]z", "ʣ")

cons = rsub(cons, "ç", "s") cons = rsub(cons, "[cq]", "k") cons = rsub(cons, "h", "") cons = rsub(cons, "j", "ʒ") -- Don't replace x -> ʃ yet so we can distinguish x from manually specified ʃ.

cons = rsub(cons, "i", "j") -- must be after j > ʒ cons = rsub(cons, "y", "j") -- must be after j > ʒ and fix_y cons = rsub(cons, "[uü]", "w") cons = rsub(cons, "'", "‿")

return cons end

-- Do context-sensitive phonological changes. Formerly this was all done syllable-by-syllable but that made the code -- tricky (since it often had to look at adjacent syllables) and full of subtle bugs. Now we first concatenate the -- syllables back to words and the words to the combined text and work on the text as a whole. FIXME: We should move -- more of the work done in preprocess_word, e.g. most of replace_context_free, here. local function postprocess_general(text, dialect) local function verify(cond, msg) if not cond then error(("Internal error: %s; processed respelling at this point is '%s'"):format(msg, text)) end return true end

local voiced = listToSet {"b", "ð", "d", "g", "m", "n", "ɲ", "l", "ʎ", "r", "ɾ", "v", "z", "ʒ", "ʣ", "ʤ"} local voiced_keys = concat_keys(voiced) local voiceless = listToSet {"p", "t", "k", "f", "s", "ʃ", "ʦ", "ʧ"} local voiceless_keys = concat_keys(voiceless) local voicing = {["p"] = "b", ["t"] = "d", ["k"] = "g", ["f"] = "v", ["s"] = "z", ["ʃ"] = "ʒ", ["ʦ"] = "ʤ", ["ʧ"] = "ʤ"} local voicing_keys = concat_keys(voicing) local devoicing = {} for k, v in pairs(voicing) do		devoicing[v] = k	end local devoicing_keys = concat_keys(devoicing)

-- Handle

-- Handle ex(h)- + vowel > -egz-. We handle -x- on either side of the syllable boundary (ex- vs. exh-). Note that -- this also handles inex(h)- + vowel because in fix_prefixes we respell inex- as inhex-, which ends up at this -- stage as in.e.xV, or as in.ex.V in the case of inexh-. text = rsub_repeatedly(text, "([.#][eɛ]" .. stress_c .. "*)(" .. charsep_c .. "*)x(" .. charsep_c .. "*" .. V .. ")", function(e, pre, post)			-- Preserve other character separators (especially the tie character ‿).			pre = pre:gsub("%.", "")			post = post:gsub("%.", "")			return e .. pre .. "g.z" .. post		end) -- -x- at the beginning of a coda becomes [ks], e.g. annex, apèndix, extracció; but not elsewhere in -- the coda, e.g. in romanx, ponx; words with [ks] in -nx such as esfinx, linx, manx need -- respelling with [ks]; words ending in vowel + x like ídix need respelling with [ʃ] text = rsub(text, "(" .. V .. charsep_c .. "*)x", "%1ks") if dialect == "val" then -- Word-initial  as well as  after a consonant other than /j/ (including in the coda, e.g. ponx) -- becomes [t͡ʃ]. text = rsub(text, "#x", "#ʧ") text = rsub(text, "([^" .. vowel_l .. separator_l .. "j]" .. charsep_c .. "*)x", "%1ʧ") end -- Other x becomes [ʃ] text = rsub(text, "x", "ʃ")

-- Doubled ss -> s e.g. in exs-, exc(e/i)-, sc(e/i)-; FIXME: should this apply across word boundaries? text = rsub(text, "s(" .. charsep_c .. "*)s", "%1s")

-- Coda consonant losses; in Central Catalan, they happen everywhere, but otherwise they don't happen when -- absolutely word-finally before a vowel or end of utterance (e.g. blanc has /k/ in Balearic and	-- Valencian but not blancs). Must precede consonant assimilations. local boundary = dialect == "cen" and "(.)" or "([^#])" text = rsub(text, "m[pb]" .. boundary, "m%1") text = rsub(text, "([ln])[td]" .. boundary, "%1%2") text = rsub(text, "[nŋ][kg]" .. boundary, "ŋ%1") if dialect == "val" or dialect == "bal" then local before_cons = "(" .. separator_c .. "*" .. C .. ")" text = rsub(text, "m[pb]" .. before_cons, "m%1") text = rsub(text, "([ln])[td]" .. before_cons, "%1%2") text = rsub(text, "[nŋ][kg]" .. before_cons, "ŋ%1") end

-- Delete /t/ between /s/ and any consonant other than /s/ or /ɾ/. Must precede voicing assimilation and -- t + lateral/nasal assimilation. text = rsub(text, "st(" .. sylsep_c .. "*[^" .. neg_guts_of_cons .. "sɾ])", "s%1") -- Consonant assimilations

if dialect == "cen" then -- v > b in onsets (not in codas, e.g. ovni [ɔ́vni] and hafni [ávni]). This needs to precede -- assimilation of nb -> mb. text = rsub(text, "v(" .. C .. "*" .. V ..")", "b%1") end

-- t + lateral/nasal assimilation -> geminate across syllable boundary; FIXME: this doesn't always happen in -tl-, -- -tm-, e.g. atmosfèric [ədmusfɛ́ɾik] in GDLC along with tmesi [dmɛ́zi]; atlàntic has [əllántik] in GDLC -- but [adlántik] in DNV. -- FIXME: Clean this up, maybe move below voicing assimilation, investigate whether it operates across words. text = rsub(text, "t(" .. sylsep_c .. ")([lʎmn])", "%2%1%2")

-- n + labial > labialized assimilation text = rsub(text, "n(" .. separator_c .. "*[mbp])", "m%1") text = rsub(text, "n(" .. separator_c .. "*[fv])", "ɱ%1")

-- n + velar > velarized assimilation text = rsub(text, "n(" .. separator_c .. "*[kg])", "ŋ%1")

-- l/n + palatal > palatalized assimilation text = rsub(text, "([ln])(" .. separator_c .. "*[ʎɲʃʒʧʤ])", function(ln, palatal)		ln = ({["l"] = "ʎ", ["n"] = "ɲ"})[ln]		return ln .. palatal	end)

-- ɲs > ɲʃ; FIXME: not sure the purpose of this; it doesn't apply in menys or derived terms like menyspreu -- NOTE: Per, it does apply in these scenarios but the result is -- somewhere between [s] and [ʃ], which is why it isn't shown in GDLC. -- text = rsub(text, "ɲs", "%1ʃ")

-- ɾ -> r word-initially or after [lns]; needs to precede voicing assimilation as will be voiced to [z] before -- /ɾ/. text = rsub(text, "([#lns]" .. sylsep_c .. "*)ɾ", "%1r")

-- Voicing or devoicing; we want to proceed from right to left, and due to the limitations of patterns (in	-- particular, the lack of support for alternations), it's difficult to do this cleanly using Lua patterns, so we -- do it character by character. local chars = split_into_chars(text) -- We need to look two characters ahead in some cases, so start two characters from the end. This is safe because -- the overall respelling ends in "##". (Similarly, as an optimization, don't check the first two characters, which	-- are always "##".) for i = #chars - 2, 3, -1 do -- We are looking for two consonants next to each other, possibly separated by a syllable or word divider. -- We also handle a consonant followed by a syllable divider then a vowel, and a consonant word-finally. -- Note that only coda consonants can change voicing, so we need to check to make sure we're in the coda. local first = chars[i] -- If `second` is nil, no assimilation occurs. Otherwise, `second` should be a consonant or empty string (which		-- represents a syllable or word boundary followed by a vowel or end of string), and we assimilate to that -- consonant (empty string forces devoicing). local second -- If set to true, we're processing a consonant directly before a word boundary followed by a word beginning -- with a vowel. In this context, voiceless sibilants voice. Note that we handle voicing of word-internally -- separately, in preprocess_word [FIXME: maybe move much of the processing in preprocess_word into this -- function]. local word_boundary_before_vowel if not rfind(first, C) then -- leave `second` at nil; no assimilation elseif chars[i + 1] == "#" then -- word boundary if chars[i + 2] == " " then -- chars[i + 3] should always be "#" verify(chars[i + 3] == "#", "Word boundary followed by space but not #") if rfind(chars[i + 4], C) then second = chars[i + 4] else second = "" word_boundary_before_vowel = true end else second = "" end elseif rfind(chars[i + 1], sylsep_c) then -- syllable boundary if rfind(chars[i + 2], C) then second = chars[i + 2] else second = "" end elseif rfind(chars[i + 1], C) then second = chars[i + 1] else -- followed by a vowel not across a syllable or word boundary; leave `second` as nil, no assimilation end if second then -- Make sure we're in the coda. We have to look backwards until we find a vowel or syllable/word boundary. local in_coda = false local j = i - 1 while true do				verify(j > 0, "Missing word boundary at beginning of overall respelling") if rfind(chars[j], "[" .. sylsep_l .. wordsep_l .. "]") then break elseif rfind(chars[j], V) then in_coda = true break end j = j - 1 end if in_coda then if word_boundary_before_vowel and rfind(first, "[zʒʣʤ]") then -- leave alone elseif voiced[second] and voicing[first] or word_boundary_before_vowel and rfind(first, "[sʃʦʧ]") then chars[i] = voicing[first] elseif (voiceless[second] or second == "") and devoicing[first] then chars[i] = devoicing[first] end end end end text = table.concat(chars)

-- gn -> ŋn e.g. regnar (including word-initial gn- e.g. gnòmic, gneis) -- FIXME: This should be moved below voicing assimilation, and we need to investigate if it operates across words -- (here I'm guessing yes). text = rsub(text, "g(" .. separator_c .. "*n)", "ŋ%1")

-- gʒ > d͡ʒ -- FIXME: This should be moved below voicing assimilation, and we need to investigate if it operates across words text = rsub(text, "g(" .. sylsep_c .. "*)ʒ", "%1ʤ")

if dialect ~= "val" then -- bl -> bbl, gl -> ggl after the stress when following a vowel; to avoid this, use <b_l> or <g_l>. FIXME: We -- need a way of forcing a hard ungeminated [b] or [g]. This must follow v > b above. text = rsub(text, "(" .. stress_c .. ")(" .. sylsep_c .. ")([bg])l", "%1%3%2%3l") else -- Valencian; undo manually written 'bbl', 'ggl' in words like poblar, reglament text = rsub(text, "([bg])(" .. sylsep_c .. ")%1l", "%2%1l") end

-- In Central Catalan, b/d/g become fricatives (actually approximants, like in Spanish) in the onset following a	-- vowel and (except for <d>) after <l> and <ll> (cf. GDLC cabellblanc [kəβɛ̀ʎβláŋ]). This also happens across -- word boundaries but doesn't happen after stops, nor in Central Catalan after [r], [ɾ] or [z] (and hence probably	-- not after [ʒ] either, although I can't find any examples in GDLC). --	-- In Valencian, <b> doesn't lenite (at least formally?), but <d> and <g> do lenite after [r], [ɾ] or [z]. --	-- Balearic is like Valencian in not leniting <b>, and probably like Central Catalan otherwise. local lenite_bdg = {["b"] = "β", ["d"] = "ð", ["g"] = "ɣ"} if dialect == "cen" then text = rsub(text, "([" .. vowel_l .. "jwlʎv]" .. separator_c .. "*[.#]" .. separator_c .. "*)([bdg])",			function(before, bdg) return before .. lenite_bdg[bdg] end) elseif dialect == "val" then text = rsub(text, "([" .. vowel_l .. "jwlʎvrɾzʣ]" .. separator_c .. "*[.#]" .. separator_c .. "*)([dg])",			function(before, dg) return before .. lenite_bdg[dg] end) else verify(dialect == "bal", ("Unrecognized dialect '%s'"):format(dialect)) text = rsub(text, "([" .. vowel_l .. "jwlʎv]" .. separator_c .. "*[.#]" .. separator_c .. "*)([dg])",			function(before, dg) return before .. lenite_bdg[dg] end) end

-- Final losses. text = rsub(text, "j(ʧs?#)", "%1") -- boigs /bɔt͡ʃ/ text = rsub(text, "([ʃʧs])s#", "%1#") -- homophone plurals -xs, -igs, -çs

-- Reduction of unstressed a,e in Central and Balearic (Eastern Catalan). if dialect ~= "val" then -- The following rules seem to apply, based on the old code: -- (1) Stressed a and e are never reduced. -- (2) Unstressed e directly following ə/o/ɔ is not reduced. -- (3) Unstressed e directly before written <a> or before /ɔ/ is not reduced. -- (4) Written <ee> when both vowels precede the primary stress is reduced to [əə]. (This rule preempts #2.) -- (5) Written <ee> when both vowels follow the primary stress isn't reduced at all. -- Rule #2 in particular seems to require that we proceed left to right, which is how the old code was -- implemented. -- FIXME: These rules seem overly complex and may produce incorrect results in some circumstances. local words = rsplit(text, " ") for j, word in ipairs(words) do			local chars = split_into_chars(word) -- See above where voicing assimilation is handled. The overall respelling begins and ends in #, which we -- can ignore. We need to look ahead three chars in some circumstances, but in all those circumstances we -- shoudn't run off the end (and have assertions to check this). local seen_primary_stress = false for i = 2, #chars - 1 do				local this = chars[i] if chars[i] == AC then seen_primary_stress = true end if (this ~= "a" and this ~= "e") or rfind(chars[i + 1], stress_c) then -- Not a/e, or a stressed vowel; continue else local reduction = true local prev, prev_stress, nxt, nxt_stress if not rfind(chars[i - 1], sylsep_c) then prev = "" else prev = chars[i - 2] -- this should be non-nil as chars[i - 1] is a syllable separator (not #) verify(prev, "Missing # at word boundary") prev_stress = "" if rfind(prev, stress_c) then prev_stress = prev prev = chars[i - 3] -- As above; chars[i - 2] is a stress indicator (not #). verify(prev, "Missing # at word boundary") end end if not rfind(chars[i + 1], sylsep_c) then nxt = "" -- leave nxt at nil else nxt = chars[i + 2] nxt_stress = chars[i + 3] -- chars[i + 1] is a syllable separator, so chars[i + 2] should not be a word boundary, so -- chars[i + 3] should exist. verify(nxt and nxt_stress, "Syllable separator at word boundary or missing # at word boundary") end if this == "e" and rfind(prev, "[əoɔ]") then reduction = false elseif this == "e" and rfind(nxt, "[aɔ]") then reduction = false elseif this == "e" and nxt == "e" and not rfind(nxt_stress, AC) then -- FIXME: Check specifically for AC duplicates previous logic but is probably wrong or unnecessary. if not seen_primary_stress then chars[i + 2] = "ə" else reduction = false end end if reduction then chars[i] = "ə" end end end words[j] = table.concat(chars) end text = table.concat(words, " ") end

-- Handle variable r. In replace_context_free, we converted single r to ɾ and double rr to r. -- FIXME: For some reason, Central and Balearic final -r renders as /r/ but Valencian final -r renders as /ɾ/. -- This is inherited from the older code. Correct? if dialect == "cen" then text = rsub(text, TEMP_PAREN_R, "") text = rsub(text, TEMP_PAREN_RR, "r") elseif dialect == "bal" then text = rsub(text, TEMP_PAREN_R, "") text = rsub(text, TEMP_PAREN_RR, "") else verify(dialect == "val", ("Unrecognized dialect '%s'"):format(dialect)) text = rsub(text, TEMP_PAREN_R, "ɾ") text = rsub(text, TEMP_PAREN_RR, "ɾ") -- Coda /r/ -> /ɾ/ text = rsub(text, "(" .. V .. stress_c .. "*" .. C .. "*)r", "%1ɾ") end

if dialect == "cen" then -- Reduction of unstressed o (not before w) text = rsub(text, "o([^" .. stress_l .. "w])", "u%1") elseif dialect == "bal" then -- Reduction of unstressed o per vowel harmony: unstressed /o/ -> /u/ directly before stressed /i/ or /u/; -- as a Lua pattern, o can be followed only by consonants and/or syllable separators (no vowels, stress marks		-- or word separators). text = rsub(text, "o([^" .. vowel_l .. stress_l .. wordsep_l .. "]*[iu]" .. stress_c .. ")", "u%1") end

if dialect ~= "val" then -- Remove j before palatal obstruents text = rsub(text, "j(" .. sylsep_c .. "*[ʃʒʧʤ])", "%1") else -- Valencian -- Fortition of palatal fricatives text = rsub(text, "ʒ", "ʤ") text = rsub(text, "(i" .. stress_c .. "*" .. sylsep_c .. ")ʣ", "%1z") end

if dialect ~= "cen" then -- No palatal gemination ʎʎ > ll or ʎ, in Valencian and Balearic. -- FIXME: These conditions seem to be targeting specific words and should probably be fixed using respelling -- instead. text = rsub(text, "([bpw]a" .. stress_c .. "*)ʎ(" .. sylsep_c .. "*)ʎ", "%1l%2l") text = rsub(text, "([mv]e" .. stress_c .. "*)ʎ(" .. sylsep_c .. "*)ʎ", "%1l%2l") text = rsub(text, "(ti" .. stress_c .. "*)ʎ(" .. sylsep_c .. "*)ʎ", "%1l%2l") text = rsub(text, "(m[oɔ]" .. stress_c .. "*)ʎ(" .. sylsep_c .. "*)ʎ", "%1l%2l") text = rsub(text, "(u" .. stress_c .. "*)ʎ(" .. sylsep_c .. "*)ʎ", "%1l%2l") text = rsub(text, "ʎ(" .. sylsep_c .. "*ʎ)", "%1") end

-- Convert pseudo-symbols to real ones.

-- Convert g to IPA ɡ. text = rsub(text, "g", "ɡ")

-- Convert pseudo-afficate symbols to full affricates. local full_affricates = { ["ʦ"] = "t͡s", ["ʣ"] = "d͡z", ["ʧ"] = "t͡ʃ", ["ʤ"] = "d͡ʒ" } text = rsub(text, "([ʦʣʧʤ])", full_affricates)

-- Generate IPA stress marks.

-- Convert acute and grave to IPA stress marks. text = rsub(text, AC, "ˈ") text = rsub(text, GR, "ˌ") -- Move IPA stress marks to the beginning of the syllable. text = rsub_repeatedly(text, "([#.])([^#.]*)(" .. ipa_stress_c .. ")", "%1%3%2")	-- Suppress syllable divider before IPA stress indicator. text = rsub(text, "%.(#?" .. ipa_stress_c .. ")", "%1")	-- Make all primary stresses but the last one in a given word be secondary. May be fed by the first rule above. -- FIXME: Currently this is handled earlier, but we might want to move it here, as is done in Module:pt-pronunc. -- text = rsub_repeatedly(text, "ˈ([^ ]+)ˈ", "ˌ%1ˈ") -- Make primary stresses in prefixes become secondary. (FIXME: Handled earlier now.) -- text = rsub_repeatedly(text, "ˈ([^#]*#" .. PREFIX_MARKER .. ")", "ˌ%1")

-- Remove # symbols at word/text boundaries, as well as _ (which forces separate interpretation), pseudo-consonant -- markers (at edges of some prefixes/suffixes), and prefix markers, and recompose. text = rsub(text, "[#_" .. PSEUDOCONS .. "]", "") text = mw.ustring.toNFC(text)

return text end

local function preprocess_word(syllables, suffix_syllables, dialect, pos, orig_word) -- Stressed vowel is ambiguous if syllables.stress then local stressed_vowel = syllables[syllables.stress].vowel if rfind(stressed_vowel, "[eo]") then local marks = {["e"] = {AC, GR, CFLEX, DIA}, ["o"] = {AC, GR, CFLEX}} local marked_vowels = {} for _, mark in ipairs(marks[stressed_vowel]) do table.insert(marked_vowels, stressed_vowel .. mark) end

error(("In respelling '%s', the stressed vowel '%s' is ambiguous. Please mark it with an acute, " .. "grave, or combined accent: %s."):format(orig_word, stressed_vowel, m_table.serialCommaJoin(marked_vowels, {dontTag = true, conj = "or"}))) end end

-- Final -r is ambiguous in many cases. local final = syllables[#syllables] -- Stressed final r after a or i in non-monosyllables is treated as (r), i.e. verbal infinitives are assumed (NOTE:	-- not always the case, e.g. there are many adjectives and nouns in -ar that should be marked as '(rr)', and	-- several loanword nouns in -ir that should be marked as 'rr'). Likewise for stressed final r or rs after é in	-- non-monosyllables (which are usually adjectives or nouns with the -er ending, but may be verbal infinitives,	-- which should be marked as 'ê(r)'). That is, it disappears other than in Valencian. All other final r and final -- rs are considered ambiguous and need to be rewritten using rr, (rr) or (r). if #syllables > 1 and final.stressed then if final.coda == "r" and rfind(final.vowel, "[aàiíé]") or final.coda == "rs" and final.vowel == "é" or			final.vowel == "ó" and rfind(final.coda, "^rs?$") and rfind(final.onset, "[stdç]") then final.coda = TEMP_PAREN_R end end if rfind(final.coda, "^rs?$") or rfind(final.coda, "[^r]rs?$") then error(("In respelling '%s', final -r by itself or in -rs is ambiguous except in the verbal endings -ar or " .. "-ir, in the nominal or adjectival endings -er(s) and -[dtsç]or(s). In all other cases it needs to be " .. "rewritten using one of 'rr' (pronounced everywhere), '(rr)' (pronounced everywhere but Balearic) or " .. "'(r)' (pronounced only in Valencian). Note that adjectives in -ar usually need rewriting using '(rr)'; " .. "nouns in -ar referring to places should be rewritten using '(r)'; and loanword nouns in -ir usually " .. "need rewriting using 'rr'."):format(orig_word)) end

local syllables_IPA = {stress = syllables.stress, is_prefix = syllables.is_prefix, is_suffix = syllables.is_suffix}

for key, val in ipairs(syllables) do		syllables_IPA[key] = {onset = val.onset, vowel = val.vowel, coda = val.coda, stressed = val.stressed} end

-- Replace letters with IPA equivalents for i, syll in ipairs(syllables_IPA) do		-- Voicing of s		if syll.onset == "s" and i > 1 and rfind(syllables[i - 1].coda, "^[iu]?$") then syll.onset = "z" end

if rfind(syll.vowel, "^[eèéêëií]$") then syll.onset = rsub(syll.onset, "tg$", "ʤ") syll.onset = rsub(syll.onset, "[cg]$", {["c"] = "s", ["g"] = "ʒ"}) syll.onset = rsub(syll.onset, "[qg]u$", {["qu"] = "k", ["gu"] = "g"}) end

syll.coda = rsub(syll.coda, "igs?$", "iʤ")

syll.onset = replace_context_free(syll.onset) syll.coda = replace_context_free(syll.coda)

syll.vowel = rsub(syll.vowel, ".",			dialect == "cen" and IPA_vowels_central or			dialect == "bal" and IPA_vowels_balearic or			IPA_vowels_valencian		) syll.vowel = rsub(syll.vowel, ".", IPA_vowels) end

for _, suffix_syl in ipairs(suffix_syllables) do		table.insert(syllables_IPA, suffix_syl) end

return syllables_IPA end

-- Given a single substitution spec, `to`, figure out the corresponding value of `from` used in a complete -- substitution spec. `pagename` is the name of the page, either the actual one or taken from the `pagename` param. -- `whole_word`, if set, indicates that the match must be to a whole word (it was preceded by ~). local function convert_single_substitution_to_original(to, pagename, whole_word) -- Replace specially-handled characters with a class matching the character and possible replacements. local escaped_from = to	-- Handling of '(rr)', '(r)', '.' and '-' needs to be done before calling pattern_escape; otherwise they will be -- escaped. escaped_from = escaped_from:gsub("%(rr%)", "r") escaped_from = escaped_from:gsub("%(r%)", "r") escaped_from = escaped_from:gsub("ks", "x"):gsub("Ks", "X"):gsub("gz", "x"):gsub("([bg])%1l", "%1l"):gsub("[.%-_]", "") escaped_from = require(patut_module).pattern_escape(escaped_from) escaped_from = escaped_from:gsub("rr", "rr?") escaped_from = escaped_from:gsub("ss", "ss?") escaped_from = escaped_from:gsub("ʃ", "[xX]") escaped_from = escaped_from:gsub("β", "b") escaped_from = escaped_from:gsub("ð", "d") escaped_from = escaped_from:gsub("ɣ", "g") escaped_from = rsub(escaped_from, "[" .. written_accented_vowel_l .. "]",		function(v) return "[" .. v .. written_accented_to_plain_vowel[v] .. "]" end) escaped_from = escaped_from:gsub(DOTOVER, DOTOVER .. "?"):gsub(LINEUNDER, LINEUNDER .. "?") escaped_from = "(" .. escaped_from .. ")" if whole_word then escaped_from = "%f[%a]" .. escaped_from .. "%f[%A]" end local match = rmatch(pagename, escaped_from) if match then if match == to then error(("Single substitution spec '%s' found in pagename '%s', replacement would have no effect"):				format(to, pagename)) end return match end error(("Single substitution spec '%s' couldn't be matched to pagename '%s'"):format(to, pagename)) end

local function apply_substitution_spec(respelling, pagename, pos, allow_mid_vowel_hints, parse_err) local subs = split_on_comma(rmatch(respelling, "^%[(.*)%]$")) respelling = pagename local mid_vowel_hint local regular_subs = {} for _, sub in ipairs(subs) do if rfind(sub, "^" .. export.mid_vowel_hint_c .. "$") then if mid_vowel_hint then parse_err(("Specified mid vowel hint twice, '%s' and '%s'"):format( mid_vowel_hint, sub)) end mid_vowel_hint = sub else table.insert(regular_subs, sub) end end if mid_vowel_hint then if not allow_mid_vowel_hints then parse_err(("Mid vowel hint '%s' not allowed when apply one substitution spec to multiple words"):format( mid_vowel_hint)) end local suffix = "" -- FIXME: This duplicates logic in to_IPA. if not pos or pos == "adverb" then local part_before_ment, ment = rmatch(respelling, "^(.*)(m[eé]nt)$") if part_before_ment and (pos == "adverb" or not rfind(part_before_ment, "[iï]$") and				rfind(part_before_ment, V .. ".*" .. V)) then suffix = ment respelling = part_before_ment end end local syllables = split_syllables(respelling, "stress prefixes", "may be uppercase") local stressed_vowel = syllables[syllables.stress].vowel if stressed_vowel == mid_vowel_hint then -- do nothing elseif rfind(mid_vowel_hint, "[èéêë]") and rfind(stressed_vowel, "[eEèÈ]") or			rfind(mid_vowel_hint, "[òóô]") and rfind(stressed_vowel, "[oO]") then syllables[syllables.stress].vowel = mid_vowel_hint else parse_err(("Stressed vowel '%s' not compatible with mid vowel hint '%s'"):format( stressed_vowel, mid_vowel_hint)) end respelling = reconstitute_word_from_syllables(syllables) .. suffix end

for _, sub in ipairs(regular_subs) do		local from, escaped_from, to, escaped_to, whole_word if rfind(sub, "^~") then -- whole-word match sub = rmatch(sub, "^~(.*)$") whole_word = true end if sub:find(":") then from, to = rmatch(sub, "^(.-):(.*)$") else to = sub from = convert_single_substitution_to_original(to, pagename, whole_word) end if from then local patut = require(patut_module) escaped_from = patut.pattern_escape(from) if whole_word then escaped_from = "%f[%a]" .. escaped_from .. "%f[%A]" end escaped_to = patut.replacement_escape(to) local subbed_respelling, nsubs = rsubn(respelling, escaped_from, escaped_to) if nsubs == 0 then parse_err(("Substitution spec %s -> %s didn't match processed pagename '%s'"):format( from, to, respelling)) elseif nsubs > 1 then parse_err(("Substitution spec %s -> %s matched multiple substrings in processed pagename '%s', add " .. "more context"):format(from, to, respelling)) else respelling = subbed_respelling end end end

return respelling end

local canonicalize_pos = { n = "noun", noun = "noun", v = "verb", vb = "verb", verb = "verb", a = "adjective", adj = "adjective", adjective = "adjective", av = "adverb", adv = "adverb", adverb = "adverb", o = "other", other = "other", }

local function parse_off_pos(respelling, parse_err) local pos, rest = respelling:match("^([a-z]+)/(.*)$") if pos then if not canonicalize_pos[pos] then local valid_pos = {} for vp, _ in pairs(canonicalize_pos) do				table.insert(valid_pos, vp) end table.sort(valid_pos) parse_err(("Unrecognized part of speech '%s', should be one of %s"):format(pos, table.concat(valid_pos, ", "))) end pos = canonicalize_pos[pos] respelling = rest if respelling == "" then respelling = "+" end end return pos, respelling end

-- Parse a respelling given by the user, allowing for '+' for pagename, mid vowel hints in place of a respelling and -- substitution specs like '[ks]' or [val:vol,ê,ks]. In general, return an object {words = {WORD, WORD, ...}} where -- WORD is of the form {term = PARSED_RESPELLING, pos = POS}. Other fields are set in special cases: If a raw respelling -- was seen, the fields `raw_phonemic` and/or `raw_phonetic` are set; if '?' is seen, the field `unknown` is set; and if -- '-' is seen, the field `omitted` is set. local function parse_respelling(respelling, pagename, parse_err) if respelling == "?" then return { unknown = true }	end if respelling == "-" then return { omitted = true }	end local saw_raw local remaining_respelling = respelling:match("^raw:(.*)$") if remaining_respelling then saw_raw = true respelling = remaining_respelling end local raw_phonemic, raw_phonetic = respelling:match("^/(.*)/ %[(.*)%]$") if not raw_phonemic then raw_phonemic = respelling:match("^/(.*)/$") end if not raw_phonemic and saw_raw then raw_phonetic = respelling:match("^%[(.*)%]$") end if raw_phonemic or raw_phonetic then return { raw_phonemic = raw_phonemic, raw_phonetic = raw_phonetic, }	end

pagename = decompose_respelling(pagename) respelling = decompose_respelling(respelling)

local function split_respelling_into_words(respelling, parse_pos) respelling = canon_respelling(respelling) local word_objs = {} local respelling_words = rsplit(respelling, " ") for _, word in ipairs(respelling_words) do			local pos if parse_pos then pos, word = parse_off_pos(word, parse_err) end table.insert(word_objs, {term = word, pos = pos}) end return {words = word_objs} end

local function substitute_respelling_word(respelling_word, pagename_word) local pos pos, respelling_word = parse_off_pos(respelling_word, parse_err) if respelling_word == "+" then respelling_word = pagename_word else if rfind(respelling_word, "^" .. export.mid_vowel_hint_c .. "$") then respelling_word = "[" .. respelling_word .. "]"			end if rfind(respelling_word, "^%[.*%]$") then respelling_word = apply_substitution_spec(respelling_word, pagename_word, pos,					"allow mid vowel hint", parse_err) end end return {term = respelling_word, pos = pos} end

-- At this point, if there are multiple words in the pagename, there are three syntaxes allowed: all-at-once, -- replacement or word-by-word. All-at-once syntax involves either a + representing the entire pagename, or a	-- substitution spec that applies to all words in the pagename. This syntax cannot have a prefixed part of speech -- because it wouldn't be clear which word to apply the part of speech to. Replacement syntax simply spells out the -- respelling without any substitution specs or +'s (but possibly with parts of speech prefixed to individual	-- words), and can have a different number of words than the pagename (essentially, the pagename is disregarded). -- Word-by-word syntax involves a combination of respelled words, per-word substitution specs and/or a + -- representing an individual word, and must have the same number of words as the pagename so that substitution -- specs and +'s can be lined up with words in the pagename. In all cases, the return value is in the same format; -- see comment at top of function. if pagename:find(" ") or respelling:find(" ") then if respelling == "+" then return split_respelling_into_words(pagename) elseif rfind(respelling, "^%[.*%]$") then -- all-at-once syntax with substitution spec return split_respelling_into_words(apply_substitution_spec(respelling, pagename, nil, false, parse_err)) elseif rfind(respelling, "^([a-z]+)/$") or rfind(respelling, "^([a-z]+)/%^%[%*%]$") then -- attempt to include a part of speech in all-at-once syntax parse_err(("Part of speech not allowed when pagename is multiword and all-at-once syntax is used in " .. "the respelling, but saw '%s'"):format(respelling)) elseif rfind(respelling, "^" .. export.mid_vowel_hint_c .. "$") then -- attempt to use a mid-vowel hint in all-at-once syntax parse_err(("Single mid-vowel hint not allowed when pagename is multiword because it's not clear which " .. "word to apply it to, but saw '%s'"):format(respelling)) elseif rfind(respelling, "[+%[%]]") or rfind(respelling, "^" .. export.mid_vowel_hint_c .. " ") or rfind(respelling, " " .. export.mid_vowel_hint_c .. " ") or rfind(respelling, " " .. export.mid_vowel_hint_c .. "$") then -- word-by-word syntax local sub_with_space = rmatch(respelling, "%^%[%* [^%[%]]*%]") if sub_with_space then parse_err(("When using word-by-word syntax with a multiword pagename, saw substitution spec '%s' " .. "with spaces, which is not allowed because it must match a single word"):format(sub_with_space)) end pagename = canon_respelling(pagename) respelling = canon_respelling(respelling) local pagename_words = rsplit(pagename, " ") local respelling_words = rsplit(respelling, " ") if #pagename_words ~= #respelling_words then parse_err(("When using word-by-word syntax with a multiword pagename, saw %s words in pagename but " .. "%s word%s in respelling; they need to match"):format(#pagename_words, #respelling_words, #respelling_words > 1 and "s" or "")) end local word_objs = {} for i = 1, #pagename_words do				table.insert(word_objs, substitute_respelling_word(respelling_words[i], pagename_words[i])) end return {words = word_objs} else -- replacement syntax; pagename ignored return split_respelling_into_words(respelling, "parse pos") end else local word_obj = substitute_respelling_word(respelling, pagename) word_obj.term = canon_respelling(word_obj.term) return {words = {word_obj}} end end

-- Parse a list of comma-split runs containing one or more respellings, i.e. after calling parse_balanced_segment_run -- or the like followed by split_alternating_runs or the like (see Module:parse utilities). `pagename` is the -- pagename, for use when a respelling is just '+', a mid-vowel hint like 'ê' or a substitution spec like '[ks]'. -- `original_input` is the raw input and `input_param` the name of the param containing the raw input; both are used -- only in error messages. Return an object specifying the respellings, currently with a single field 'terms' (this -- format is used in case other outer properties exist in the future), where 'terms' is a list of term objects. Each -- term object contains either a field `term` with the respelling and an optional part of speech `pos`, or fields -- `raw_phonemic` and/or `raw_phonetic` (if the user specified raw IPA using "/.../" or "/.../ [...]" or "raw:[...]"), -- `unknown` (if the user specified "?"), or `omitted` (if the user specified "-"). In addition, there may be fields -- `q`, `qq`, `a`, `aa`, and/or `ref` corresponding to inline modifiers. Each such field is a list; all are lists of -- strings except for `ref`, which is a list of objects as returned by parse_references in Module:references. function export.parse_comma_separated_groups(comma_separated_groups, pagename, original_input, input_param) local function generate_obj(respelling, parse_err) return parse_respelling(respelling, pagename == true and respelling or pagename, parse_err) end local put = require(parse_utilities_module)

local outer_container = {terms = {}} for _, group in ipairs(comma_separated_groups) do -- Rejoin runs that don't involve <...>. local j = 2 while j <= #group do			if not group[j]:find("^<.*>$") then group[j - 1] = group[j - 1] .. group[j] .. group[j + 1] table.remove(group, j)				table.remove(group, j)			else j = j + 2 end end

local param_mods = { -- pre = { overall = true }, -- post = { overall = true }, ref = { store = "insert", convert = function(arg, parse_err) return require("Module:references").parse_references(arg) end }, q = { store = "insert" }, qq = { store = "insert" }, a = { store = "insert" }, aa = { store = "insert" }, }

table.insert(outer_container.terms, put.parse_inline_modifiers_from_segments {			group = group,			arg = original_input,			props = {				paramname = input_param,				param_mods = param_mods,				generate_obj = generate_obj,				splitchar = ",",				outer_container = outer_container,			},		}) end

return outer_container end

-- Generate the pronunciation of `words` (a list of word objects representing respellings, each of which is an object -- of the form {term = RESPELLING, pos = PART_OF_SPEECH} in `dialect` ("cen", "bal" or "val"). local function to_IPA(words, dialect)	local pronuns = {}

words = handle_unstressed_words(words) for _, wordobj in ipairs(words) do		local word = wordobj.term local pos = wordobj.pos local suffix_syllables = {} local orig_word = word

word = ulower(word) if not pos or pos == "adverb" then local word_before_ment, ment = rmatch(word, "^(.*)(m[eé]nt)$") if word_before_ment and (pos == "adverb" or not rfind(word_before_ment, "[iï]$") and				rfind(word_before_ment, V .. ".*" .. V)) then suffix_syllables = pos = "adjective" word = word_before_ment end end

word = word_fixes(word) local syllables = split_syllables(word) syllables = preprocess_word(syllables, suffix_syllables, dialect, pos, orig_word) -- Combine syllables. local combined = {} local has_ment = #suffix_syllables > 0 for i, syll in ipairs(syllables) do			local ac = (i == syllables.stress and not syllables.is_prefix and not has_ment or				has_ment and i == #syllables) and AC or -- primary stress syllables[i].stressed and GR or -- secondary stress ""			table.insert(combined, syll.onset .. syll.vowel .. ac .. syll.coda) end table.insert(pronuns, table.concat(combined, ".")) end

-- Put double ## at utterance boundaries (beginning/end of string) and at foot boundaries (marked with |). -- Note that if the string without pound signs is 'foo bar baz | bat quux', the final string will be -- '##foo# #bar# #baz## #|# ##bat# #quux##'. local text = "##" .. table.concat(pronuns, " ") .. "##"	text = rsub(text, " | ", "# | #") text = rsub(text, " ", "# #") return postprocess_general(text, dialect) end

-- Generate the phonemic and phonetic pronunciations of the respellings in `parsed_respellings`, which is a table whose -- keys are dialect identifiers (e.g. "cen" for Central Catalan, "val" for Valencian) and whose values are objects of -- the format returned by parse_comma_separated_groups (see comment above that function). This destructively modifies -- `parsed_respellings`, adding fields `phonemic` and `phonetic` containing the generated pronunciations and removing -- the input fields used to generate those output fields. (FIXME: Currently only phonetic pronunciation is generated.) function export.generate_phonemic_phonetic(parsed_respellings) -- Convert each canonicalized respelling to phonemic/phonetic IPA. for dialect, respelling_spec in pairs(parsed_respellings) do		for _, termobj in ipairs(respelling_spec.terms) do			if termobj.unknown or termobj.omitted then -- leave alone, will handle later elseif termobj.raw_phonemic or termobj.raw_phonetic then termobj.phonemic = termobj.raw_phonemic termobj.phonetic = termobj.raw_phonetic -- set to nil so by-value comparisons respect only the resulting phonemic/phonetic and qualifiers termobj.raw_phonemic = nil termobj.raw_phonetic = nil else termobj.phonetic = to_IPA(termobj.words, dialect) -- set to nil so by-value comparisons respect only the resulting phonemic/phonetic and qualifiers termobj.words = nil end end end end

-- Group pronunciations by dialect, i.e. grouping pronunciations that are identical in every way (including both the -- pronunciation(s) and any qualifiers and other inline modifiers). `parsed_respellings` contains the output from -- generate_phonemic_phonetic, and the return value is a list of grouped pronunciations, where each object in the list -- contains fields `dialects` (a list of dialects containing the pronunciations) and `pronuns` (a list of -- pronunciations, where each pronunciation is specified by an object containing fields `phonemic` and `phonetic`, as -- generated by generate_phonemic_phonetic, along with any inline modifier fields `q`, `qq`, `a`, `aa` and/or `ref`). function export.group_pronuns_by_dialect(parsed_respellings) local grouped_pronuns = {} for dialect, pronun_spec in pairs(parsed_respellings) do		local saw_omitted = false for _, termobj in ipairs(pronun_spec.terms) do			if termobj.omitted then saw_omitted = true break end end if not saw_omitted then local saw_existing = false for _, group in ipairs(grouped_pronuns) do				if m_table.deepEquals(group.pronuns, pronun_spec.terms) then table.insert(group.dialects, dialect) saw_existing = true break end end if not saw_existing then table.insert(grouped_pronuns, {dialects = {dialect}, pronuns = pronun_spec.terms}) end end end return grouped_pronuns end

-- Format pronunciations grouped by dialect. `grouped_pronuns` contains the output of group_pronuns_by_dialect. -- This destructively modifies `grouped_pronuns`, adding a field 'formatted' to the first-level values of -- `grouped_pronuns` containing the formatted pronunciation(s) for a given set of dialects. function export.format_grouped_pronunciations(grouped_pronuns) for _, grouped_pronun_spec in pairs(grouped_pronuns) do		local pronunciations = {}

-- Loop through each pronunciation. For each one, add the phonemic and phonetic versions to `pronunciations`, -- for formatting by Module:IPA or raw (for use in Module:ca-headword). for j, pronun in ipairs(grouped_pronun_spec.pronuns) do			-- Add dialect tags to left accent qualifiers if first one local as = pronun.a			if j == 1 then if as then as = m_table.deepcopy(as) else as = {} end for _, dialect in ipairs(grouped_pronun_spec.dialects) do					table.insert(as, export.dialects_to_names[dialect]) end end

local first_pronun = #pronunciations + 1

if pronun.unknown then -- FIXME: This is a massive hack but it works for now. table.insert(pronunciations, { pron = "", pretext = "unknown" }) else if not pronun.phonemic and not pronun.phonetic then error("Internal error: Saw neither phonemic nor phonetic pronunciation") end

if pronun.phonemic then -- missing if 'raw:[...]' given local slash_pron = "/" .. pronun.phonemic .. "/"					table.insert(pronunciations, {						pron = slash_pron,					}) end

if pronun.phonetic then -- missing if '/.../' given local bracket_pron = "[" .. pronun.phonetic .. "]"					table.insert(pronunciations, {						pron = bracket_pron,					}) end end

local last_pronun = #pronunciations

if pronun.q then pronunciations[first_pronun].q = pronun.q			end if as then pronunciations[first_pronun].a = as			end if j > 1 then pronunciations[first_pronun].separator = ", " end if pronun.qq then pronunciations[last_pronun].qq = pronun.qq			end if pronun.aa then pronunciations[last_pronun].aa = pronun.aa			end if pronun.refs then pronunciations[last_pronun].refs = pronun.refs end if first_pronun ~= last_pronun then pronunciations[last_pronun].separator = " " end end

grouped_pronun_spec.formatted = m_IPA.format_IPA_full { lang = lang, items = pronunciations, separator = "" } end end

function export.show(frame) local params = { [1] = {},		indent = {}, pagename = {} -- for testing or documentation pages }

for _, dialect in ipairs(export.dialects) do		params[dialect] = {} end for dialect_group, _ in pairs(export.dialect_groups) do		params[dialect_group] = {} end

local args = require("Module:parameters").process(frame:getParent.args, params) local pagename = args.pagename or mw.title.getCurrentTitle.subpageText

-- Set inputs local inputs = {} -- If 1= specified, do all dialects. if args[1] then for _, dialect in ipairs(export.dialects) do			inputs[dialect] = {input = args[1], param = 1} end end -- Then do dialect groups. for dialect_group, group_dialects in pairs(export.dialect_groups) do		if args[dialect_group] then for _, dialect in ipairs(group_dialects) do				inputs[dialect] = {input = args[dialect_group], param = dialect_group} end end end -- Then do individual dialect settings. for _, dialect in ipairs(export.dialects) do		if args[dialect] then inputs[dialect] = {input = args[dialect], param = dialect} end end -- If no inputs given, set all dialects based on current pagename. if not next(inputs) then for _, dialect in ipairs(export.dialects) do			inputs[dialect] = {input = "+", param = "(pagename)"} end end

-- Parse the arguments. local parsed_respellings = {} for dialect, inputspec in pairs(inputs) do		local function generate_obj(respelling, parse_err) return parse_respelling(respelling, pagename, parse_err) end

if inputspec.input:find("[<%[]") then local put = require(parse_utilities_module) -- Parse balanced segment runs involving either [...] (substitution notation) or <...> (inline modifiers). -- We do this because we don't want commas inside of square or angle brackets to count as respelling -- delimiters. However, we need to rejoin square-bracketed segments with nearby ones after splitting -- alternating runs on comma. For example, if we are given -- "a[x]a<q:learned>,[vol:vôl,ks]<q:nonstandard>", after calling -- parse_multi_delimiter_balanced_segment_run we get the following output: --			-- {"a", "[x]", "a", "<q:learned>", ",", "[vol:vôl,ks]", "", "<q:nonstandard>", ""} --			-- After calling split_alternating_runs, we get the following: --			-- {{"a", "[x]", "a", "<q:learned>", ""}, {"", "[vol:vôl,ks]", "", "<q:nonstandard>", ""}} --			-- We need to rejoin stuff on either side of the square-bracketed portions. local segments = put.parse_multi_delimiter_balanced_segment_run(inputspec.input, {{"<", ">"}, {"[", "]"}})

local comma_separated_groups = put.split_alternating_runs_on_comma(segments)

-- Process each value. local outer_container = export.parse_comma_separated_groups(comma_separated_groups, pagename,				inputspec.input, inputspec.param) parsed_respellings[dialect] = outer_container else local termobjs = {} local function parse_err(msg) error(msg .. ": " .. inputspec.param .. "=" .. inputspec.input) end for _, term in ipairs(split_on_comma(inputspec.input)) do				table.insert(termobjs, generate_obj(term, parse_err)) end parsed_respellings[dialect] = { terms = termobjs, }		end end

-- Convert each canonicalized respelling to phonemic/phonetic IPA. export.generate_phonemic_phonetic(parsed_respellings)

-- Group the results. local grouped_pronuns = export.group_pronuns_by_dialect(parsed_respellings)

-- Format the results. export.format_grouped_pronunciations(grouped_pronuns)

-- Concatenate formatted results. local formatted = {} for _, grouped_pronun_spec in ipairs(grouped_pronuns) do		table.insert(formatted, grouped_pronun_spec.formatted) end local indent = (args.indent or "*") .. " "	local out = table.concat(formatted, "\n" .. indent) if args.indent then out = indent .. out end

return out end

-- Used by Module:ca-IPA/testcases. function export.test(pagename, respelling, dialect) local function parse_err(msg) error(msg) end local parsed = parse_respelling(respelling, pagename, parse_err) return to_IPA(parsed.words, dialect) end

return export

title: Module:User:Benwing2/ca-IPA


text:
Template:myv-noun-def-2/documentation

Use sg=1 for terms that don't have plural (e.g., proper nouns.)

See also: Appendix:Erzya declension.

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

title: Template:myv-noun-def-2/documentation


title: Template:R:lud:Pahomov:2022


title: User:Benwing2/ca-IPA


text: self-contradicts

title: self-contradicts


text: self-contradicting

title: self-contradicting


text: self-contradicted

title: self-contradicted


text: self-contains

title: self-contains


text: self-containing

title: self-containing


title: Template:R:lud:Kujola:1944


text:
chappish

Etymology
From.

Adjective

 * 1) Like a chap; mannish, blokey.

title: chappish


text:
lleisiad

Etymology
From.

Noun

 * 1) vocalisation

title: lleisiad


text:
ଖଣ୍ଡ

Etymology
.

Noun

 * 1) small piece; tiny portion; bit
 * 2) slice; fragment; cut piece
 * 3) a part cut or taken out from a whole thing
 * 4) a copy; piece or number
 * 5) candied sugar
 * 6) one part or volume of a book (of many volumes)
 * 7) chapter or section of a book
 * 8) powder prepared from treacle; molasses partially dried by heat
 * 9) group; assemblage; multitude
 * 10) chasm
 * 11) fissure
 * 12) a flaw or defect in a jewel
 * 13) a kind of sugarcane
 * 14) black salt
 * 15) a break in continuity
 * 16) gap
 * 17)  one of the terms in equation
 * 18) a calf with horns half-grown
 * 19) nine
 * 20) direction; quarter of the globe
 * 21) a kind of measure in music
 * 1) a break in continuity
 * 2) gap
 * 3)  one of the terms in equation
 * 4) a calf with horns half-grown
 * 5) nine
 * 6) direction; quarter of the globe
 * 7) a kind of measure in music
 * 1) direction; quarter of the globe
 * 2) a kind of measure in music
 * 1) a kind of measure in music
 * 1) a kind of measure in music

Adjective

 * 1) sliced, broken
 * 2) divided
 * 3) small
 * 4) defective
 * 5) not full
 * 6) crippled
 * 7) deficient
 * 8) incomplete
 * 1) crippled
 * 2) deficient
 * 3) incomplete
 * 1) deficient
 * 2) incomplete

title: ଖଣ୍ଡ


text: Citations:yuhs

title: Citations:yuhs


text:
lleisiol

Etymology
From.

Adjective

 * 1) vocal

title: lleisiol


text:
آزیلی

Etymology
From.

Adjective

 * 1) (of animals) savage.

title: آزیلی


text:
କନ୍ଧ

Etymology 1
. Compare 🇨🇬.

Proper noun

 * 1) a member of the Khonds (Kuis and Kuvis), an aboriginal tribe in the Indian states of Odisha and Andhra Pradesh

Etymology 2
. Compare 🇨🇬, 🇨🇬.

Noun

 * 1) the shoulders

title: କନ୍ଧ


text:
User talk:139.130.241.224

Appeal Block
139.130.241.224 22:21, 4 January 2024 (UTC)

title: User talk:139.130.241.224


text: Category:sv:Animation

title: Category:sv:Animation


text:
𑀧𑀸𑀮𑀓𑁆𑀓𑀸

Etymology
.

Noun

 * 1) Indian spinach

Related terms

 * 𑀧𑀸𑀮𑀁𑀕

Descendants

 * Hindustani: pālak
 * Hindustani: pālak
 * Hindustani: pālak
 * Hindustani: pālak

title: 𑀧𑀸𑀮𑀓𑁆𑀓𑀸


text:
cawell

Etymology
Borrowed from.

Noun

 * 1) basket, pannier
 * 2) cradle
 * 3) creel, fish trap, cage
 * 4)  quiver
 * 5)  belly, breast, torso
 * 1)  quiver
 * 2)  belly, breast, torso
 * 1)  belly, breast, torso

title: cawell


text: 曼達維

title: 曼達維


text: Category:en:Davao City

title: Category:en:Davao City


text:
pixilinga

Noun

 * 1)  chicken lice
 * 2)  anything small in size

title: pixilinga


text:
여하튼

Etymology
🇰🇲.

Adverb

 * 1) anyway, anyhow

title: 여하튼


text: corns on the cob

title: corns on the cob


text: corn-on-the-cob

title: corn-on-the-cob


text: Category:es:Davao City

title: Category:es:Davao City


text:
Dmitriev

Etymology
.

title: Dmitriev


text: Category:es:Davao del Sur, Philippines

title: Category:es:Davao del Sur, Philippines


text:
سونمك

Etymology
. See it for cognates.

Verb

 * 1) to rejoice, to be happy

title: سونمك


text: 曼达维

title: 曼达维


text:
பயறு

Etymology
From. Cognate to 🇨🇬 and 🇨🇬.

Noun

 * 1) cereals, pulse of various kinds
 * 2) green gram

title: பயறு


text:
どうしても

Adverb

 * 1) no matter what

title: どうしても


text:
തങ്ക

Etymology
.

Noun

 * 1)  younger sister

title: തങ്ക


text: 왜냐면

title: 왜냐면


text: Bolham

title: Bolham


text:
伯樂一顧

Etymology
From the :

Idiom

 * 1) To instantly raise the ask price of something

title: 伯樂一顧


text: 萬那威

title: 萬那威


text: stirfrys

title: stirfrys


text: 万那威

title: 万那威


text: 伯乐一顾

title: 伯乐一顾


text: 曼達威

title: 曼達威


text:
ngemata

Verb

 * 1) look after, keep an eye on.

title: ngemata


text: 彳む

title: 彳む


text: 曼达威

title: 曼达威


text: Wiktionary:Foreign Word of the Day/2024/January 5


text:
sikỳi

Etymology
Compare 🇨🇬, 🇨🇬, 🇨🇬, 🇨🇬, 🇨🇬.

Noun

 * 1) smallness

title: sikỳi


text: Category:English terms prefixed with corp-


text:
ܚܣܟ

Etymology
Cognate to 🇨🇬.

Verb

 * 1)  to refrain, hold back, restrain, curb
 * 2)  to spare, exempt, deprive
 * 3)  to save
 * 1)  to save
 * 1)  to save
 * 1)  to save

title: ܚܣܟ


text:
apotheke

Etymology 1
From. .

Noun

 * 1) A Greek storeroom or warehouse.

Etymology 2
From. .

Noun

 * 1) A European, especially German, pharmacy.

title: apotheke


text: apothekes

title: apothekes


text: cafenion

title: cafenion


text: cafenions

title: cafenions


text: 艾伯尼港

title: 艾伯尼港


text:
kielʹ

Etymology
From. Cognates include 🇨🇬 and 🇨🇬.

Noun

 * 1) tongue
 * 2) language
 * 3) string

title: kielʹ


text:
آسوده

Etymology
.

Adjective

 * 1) tranquil, comfortable, peaceful
 * 2) quiet

title: آسوده


text:
Barle

Proper noun

 * 1)  at  on the Devon border.

title: Barle


text:
食器洗い機

Noun

 * 1) dishwasher

title: 食器洗い機


text: ascensións

title: ascensións


text:
Port Alberni

Etymology
who commanded at Nootka Sound on Vancouver Island's west coast.

Translations

 * Chinese:
 * Cantonese: 艾伯尼港
 * Mandarin: 艾伯尼港
 * Marathi: पोर्ट अ‍ॅलबर्नी

title: Port Alberni


text:
Talk:niederrheinisch

niederrheinisch/Niederrheinisch
Dialectal senses:
 * 1) Low Franconian in Germany

title: Talk:niederrheinisch


text: celebracións

title: celebracións


text:
ઉપનિષદ

Etymology
.

Noun

 * 1)  Upanishad

title: ઉપનિષદ


text: descontaminacións

title: descontaminacións


text:
ماشین ظرف‌شویی

Noun

 * 1) dishwasher

title: ماشین ظرف‌شویی


text:
Template:lud-decl/uni

3

title: Template:lud-decl/uni


text:
corpography

Etymology
From.

Noun

 * 1) a means of conceptualizing a battlefield or war through the physical forms of soldiers
 * 2) the study of the experience of living in a body
 * 1) the study of the experience of living in a body
 * 1) the study of the experience of living in a body

title: corpography


text: Citations:Pago Pago

title: Citations:Pago Pago


text:
corpographies

Noun

 * 1) NaN corpographies

title: corpographies


text:
Appendix:Variations of "rea"

The word “rea” appears in many languages with many variations in the use of capitalization, punctuation, and diacritics.

Capitalization and punctuation

 * rea
 * Rea
 * REA
 * ReA
 * rea-
 * re'a
 * reʻa
 * re·a
 * -rea

Diacritics

 * reá
 * reà
 * Reā
 * réa

Other scripts

 * Cyrillic
 * реа (rea)
 * Реа (Rea)

 * Greek
 * Ρέα (Réa)

 * Katakana
 * レア (rea, Rea)
 * レアー (Reā)

title: Appendix:Variations of "rea"


text:
Template:lud-decl/vezi

3

title: Template:lud-decl/vezi


text:
sinuman

Etymology
From.

Pronoun

 * 1) whoever

title: sinuman


text:
Template:lud-decl/kana

1

title: Template:lud-decl/kana


text:
તવો

Etymology
, from a variant of, from , from.

Cognates include 🇨🇬, 🇨🇬, 🇨🇬 /, 🇨🇬, 🇨🇬, 🇨🇬 / 🇨🇬, 🇨🇬, and 🇨🇬

Noun

 * 1) tawa, pan, griddle

title: તવો


text:
𑀚𑀮

Etymology
.

Noun

 * 1) water

Descendants

 * Dardic:
 * Hindustani:
 * Punjabi:
 * Hindustani:
 * Punjabi:
 * Punjabi:
 * Punjabi:
 * Punjabi:
 * Punjabi:
 * Punjabi:
 * Punjabi:

title: 𑀚𑀮


text: autonaprawy

title: autonaprawy


text: autonaprawie

title: autonaprawie


text: autonaprawę

title: autonaprawę


text: autonaprawą

title: autonaprawą


text: autonaprawo

title: autonaprawo


text: Template:ja-etym-theory

title: Template:ja-etym-theory


text:
sintunis

Etymology
Early from  with.

Noun

 * 1) calamansi; calamondin (, ×Citrofortunella mitis)

title: sintunis


text: autoserwisy

title: autoserwisy


text: autoserwisu

title: autoserwisu


text: autoserwisów

title: autoserwisów


text: autoserwisowi

title: autoserwisowi


text: autoserwisom

title: autoserwisom


text: autoserwisem

title: autoserwisem


text: autoserwisami

title: autoserwisami


text: autoserwisie

title: autoserwisie


text: autoserwisach

title: autoserwisach


text: trzciny

title: trzciny


text: trzcin

title: trzcin


text: trzcinie

title: trzcinie


text: trzcinom

title: trzcinom


text: trzcinę

title: trzcinę


text: trzciną

title: trzciną


text: trzcinami

title: trzcinami


text: trzcinach

title: trzcinach


text: trzcino

title: trzcino


text: serwisy

title: serwisy


text: serwisu

title: serwisu


text: serwisów

title: serwisów


text: serwisowi

title: serwisowi


text: serwisom

title: serwisom


text: serwisem

title: serwisem


text: serwisami

title: serwisami


text: serwisie

title: serwisie


text: serwisach

title: serwisach


text: oczerety

title: oczerety


text: oczeretu

title: oczeretu


text: oczeretów

title: oczeretów


text: oczeretowi

title: oczeretowi


text: oczeretom

title: oczeretom


text: oczeretem

title: oczeretem


text: oczeretami

title: oczeretami


text: oczerecie

title: oczerecie


text: oczeretach

title: oczeretach


text: serwy

title: serwy


text: serwu

title: serwu


text: serwów

title: serwów


text: serwowi

title: serwowi


text: serwom

title: serwom


text: serwem

title: serwem


text: serwami

title: serwami


text: serwie

title: serwie


text: serwach

title: serwach


text: zagrywki

title: zagrywki


text: zagrywek

title: zagrywek


text: zagrywce

title: zagrywce


text: zagrywkom

title: zagrywkom


text: zagrywkę

title: zagrywkę


text: zagrywką

title: zagrywką


text: zagrywkami

title: zagrywkami


text: zagrywkach

title: zagrywkach


text: zagrywko

title: zagrywko


text: zagrania

title: zagrania


text: zagrań

title: zagrań


text: zagraniu

title: zagraniu


text: zagraniom

title: zagraniom


text: zagraniem

title: zagraniem


text: zagraniami

title: zagraniami


text: zagraniach

title: zagraniach


text: bezruchu

title: bezruchu


text: bezruchowi

title: bezruchowi


text: bezruchem

title: bezruchem


text: sintonis

title: sintonis


text: ruchomości

title: ruchomości


text: ruchomościom

title: ruchomościom


text: ruchomością

title: ruchomością


text: ruchomościami

title: ruchomościami


text: ruchomościach

title: ruchomościach


text: przynależności

title: przynależności


text: przynależnościom

title: przynależnościom


text: przynależnością

title: przynależnością


text: przynależnościami

title: przynależnościami


text: przynależnościach

title: przynależnościach


text: areligijności

title: areligijności


text: areligijnością

title: areligijnością


text: niereligijności

title: niereligijności


text: niereligijnością

title: niereligijnością


text: niewiary

title: niewiary


text: niewiarze

title: niewiarze


text: niewiarę

title: niewiarę


text: niewiarą

title: niewiarą


text: niewiaro

title: niewiaro


text: pobożności

title: pobożności


text: pobożnościom

title: pobożnościom


text: pobożnością

title: pobożnością


text: pobożnościami

title: pobożnościami


text: pobożnościach

title: pobożnościach


text: bogobojności

title: bogobojności


text: bogobojnością

title: bogobojnością


text: bogoburstwa

title: bogoburstwa


text: bogoburstw

title: bogoburstw


text: bogoburstwu

title: bogoburstwu


text: bogoburstwom

title: bogoburstwom


text: bogoburstwem

title: bogoburstwem


text: bogoburstwami

title: bogoburstwami


text: bogoburstwie

title: bogoburstwie


text: bogoburstwach

title: bogoburstwach


text: herezje

title: herezje


text: herezji

title: herezji


text: herezyj

title: herezyj


text: herezjom

title: herezjom


text: herezję

title: herezję


text: herezją

title: herezją


text: herezjami

title: herezjami


text: herezjach

title: herezjach


text: herezjo

title: herezjo


text:
сёлыӈ

Etymology
From.

Adjective

 * 1) rich

title: сёлыӈ


text:
Template:ja-etym-theory/documentation

This template allows etymological theories from the Nihon Kokugo Daijiten (second edition), as well as other etymological theory dictionaries, such as the Gogen Yurai Jiten.

Example
text

The following code gives this:

title: Template:ja-etym-theory/documentation


text: artystyczności

title: artystyczności


text: artystycznością

title: artystycznością


text: abecadłowości

title: abecadłowości


text: abecadłowością

title: abecadłowością


text: aberracyjności

title: aberracyjności


text: aberracyjnością

title: aberracyjnością


text: ablatywności

title: ablatywności


text: ablatywnością

title: ablatywnością


text: abrazyjności

title: abrazyjności


text: abrazyjnością

title: abrazyjnością


text: absencyjności

title: absencyjności


text: absencyjnością

title: absencyjnością


text: abstrakcyjności

title: abstrakcyjności


text: abstrakcyjnościom

title: abstrakcyjnościom


text: abstrakcyjnością

title: abstrakcyjnością


text: abstrakcyjnościami

title: abstrakcyjnościami


text: abstrakcyjnościach

title: abstrakcyjnościach


text: abuzywności

title: abuzywności


text: abuzywnością

title: abuzywnością


text: achromatyczności

title: achromatyczności


text: achromatycznością

title: achromatycznością


text: achroniczności

title: achroniczności


text: achronicznością

title: achronicznością


text: acydofilności

title: acydofilności


text: acydofilnością

title: acydofilnością


text: acykliczności

title: acykliczności


text: acyklicznością

title: acyklicznością


text: aczasowości

title: aczasowości


text: aczasowością

title: aczasowością


text: adaptabilności

title: adaptabilności


text: adaptabilnością

title: adaptabilnością


text: adaptacyjności

title: adaptacyjności


text: adaptacyjnością

title: adaptacyjnością


text: adaptatywności

title: adaptatywności


text: adaptatywnością

title: adaptatywnością


text: adaptowalności

title: adaptowalności


text: adaptowalnością

title: adaptowalnością


text: addycyjności

title: addycyjności


text: addycyjnością

title: addycyjnością


text: addytywności

title: addytywności


text: addytywnością

title: addytywnością


text: adekwatności

title: adekwatności


text: adekwatnością

title: adekwatnością


text: adhezyjności

title: adhezyjności


text: adhezyjnością

title: adhezyjnością


text: adiabatyczności

title: adiabatyczności


text: adiabatycznością

title: adiabatycznością


text: adiektywności

title: adiektywności


text: adiektywnością

title: adiektywnością


text: administracyjności

title: administracyjności


text: administracyjnością

title: administracyjnością


text: adnominalności

title: adnominalności


text: adnominalnością

title: adnominalnością


text: adoracyjności

title: adoracyjności


text: adoracyjnością

title: adoracyjnością


text: honetatik

title: honetatik


text:
ligatinë

Etymology
From. See for more.

Noun

 * 1) swamp
 * 2) marsh

title: ligatinë


text: sintores

title: sintores


text:
ligatishtë

Etymology
From

Noun

 * 1) swamp
 * 2) marsh

title: ligatishtë


text:
vatnyk

Etymology
From.

title: vatnyk


text: Lìbǐlǐyà

title: Lìbǐlǐyà


text: vatnyks

title: vatnyks


text:
सैलून

Etymology
, from, from , ultimately from. Cognate with 🇨🇬.

Noun

 * 1) saloon, barbershop, hairdresser's
 * 2) saloon car, sedan

title: सैलून


text: adresowalności

title: adresowalności


text: adresowalnością

title: adresowalnością


text: adsorpcyjności

title: adsorpcyjności


text: adsorpcyjnością

title: adsorpcyjnością


text: honetara

title: honetara


text: adsorbaty

title: adsorbaty


text: adsorbatu

title: adsorbatu


text: adsorbatów

title: adsorbatów


text: adsorbatowi

title: adsorbatowi


text: adsorbatom

title: adsorbatom


text: adsorbatem

title: adsorbatem


text: adsorbatami

title: adsorbatami


text: adsorbacie

title: adsorbacie


text: adsorbatach

title: adsorbatach


text: adsorbenty

title: adsorbenty


text: adsorbentu

title: adsorbentu


text: adsorbentów

title: adsorbentów


text: adsorbentowi

title: adsorbentowi


text: adsorbentom

title: adsorbentom


text: adsorbentem

title: adsorbentem


text: adsorbentami

title: adsorbentami


text: adsorbencie

title: adsorbencie


text: adsorbentach

title: adsorbentach


text: adsorpcji

title: adsorpcji


text: adsorpcję

title: adsorpcję


text: adsorpcją

title: adsorpcją


text: adsorpcjo

title: adsorpcjo


text: adwentowości

title: adwentowości


text: adwentowością

title: adwentowością


text: adwerbalności

title: adwerbalności


text: adwerbalnością

title: adwerbalnością


text: adwerbialności

title: adwerbialności


text: adwerbialnością

title: adwerbialnością


text: aerobowości

title: aerobowości


text: aerobowością

title: aerobowością


text: aerodynamiczności

title: aerodynamiczności


text: aerodynamicznością

title: aerodynamicznością


text: aeroelastyczności

title: aeroelastyczności


text: aeroelastycznością

title: aeroelastycznością


text: aerosprężystości

title: aerosprężystości


text: aerosprężystością

title: aerosprężystością


text: honetan

title: honetan


text: aestetyczności

title: aestetyczności


text: aestetycznością

title: aestetycznością


text: afabularności

title: afabularności


text: afabularnością

title: afabularnością


text: afektywności

title: afektywności


text: afektywnością

title: afektywnością


text: afleksyjności

title: afleksyjności


text: afleksyjnością

title: afleksyjnością


text: aforystyczności

title: aforystyczności


text: aforystycznością

title: aforystycznością


text: aglutynacyjności

title: aglutynacyjności


text: aglutynacyjnością

title: aglutynacyjnością


text: agresywności

title: agresywności


text: agresywnością

title: agresywnością


text: ahistoryczności

title: ahistoryczności


text: ahistorycznością

title: ahistorycznością


text: akademickości

title: akademickości


text: akademickością

title: akademickością


text: honetako

title: honetako


text: hauetako

title: hauetako


text: hauetan

title: hauetan


text: hauetara

title: hauetara


text: akademiczności

title: akademiczności


text: akademicznością

title: akademicznością


text: afektowności

title: afektowności


text: afektownością

title: afektownością


text: Category:Rhymes:Portuguese/idɐ/4 syllables


text: afekciki

title: afekciki


text: afekcika

title: afekcika


text: afekcików

title: afekcików


text: afekcikowi

title: afekcikowi


text: afekcikom

title: afekcikom


text: afekcikiem

title: afekcikiem


text: afekcikami

title: afekcikami


text: afekciku

title: afekciku


text: afekcikach

title: afekcikach


text: afektoterapii

title: afektoterapii


text: afektoterapię

title: afektoterapię


text: afektoterapią

title: afektoterapią


text: afektoterapio

title: afektoterapio


text: afektacji

title: afektacji


text: afektację

title: afektację


text: afektacją

title: afektacją


text: afektacjo

title: afektacjo


text: afektonimy

title: afektonimy


text: afektonimu

title: afektonimu


text: afektonimów

title: afektonimów


text: afektonimowi

title: afektonimowi


text: afektonimom

title: afektonimom


text: afektonimem

title: afektonimem


text: afektonimami

title: afektonimami


text: afektonimie

title: afektonimie


text: afektonimach

title: afektonimach


text:
somniferosity

Etymology
From.

Noun

 * 1) The property of being somniferous.

title: somniferosity


text:
蚵乾

Noun

 * 1)  dried oyster

title: 蚵乾


text: Barbe-Bleue

title: Barbe-Bleue


text: 蚵干

title: 蚵干


text:
User talk:ZW1996

Ha

title: User talk:ZW1996


text: afekcje

title: afekcje


text: afekcji

title: afekcji


text: afekcyj

title: afekcyj


text: afekcjom

title: afekcjom


text: afekcję

title: afekcję


text: afekcją

title: afekcją


text: afekcjami

title: afekcjami


text: afekcjach

title: afekcjach


text: afekcjo

title: afekcjo


text: kacerstwa

title: kacerstwa


text: kacerstw

title: kacerstw


text: kacerstwu

title: kacerstwu


text: kacerstwom

title: kacerstwom


text: kacerstwem

title: kacerstwem


text: kacerstwami

title: kacerstwami


text: kacerstwie

title: kacerstwie


text: kacerstwach

title: kacerstwach


text: heretycy

title: heretycy


text: heretyki

title: heretyki


text: heretyka

title: heretyka


text: heretyków

title: heretyków


text: heretykowi

title: heretykowi


text: heretykom

title: heretykom


text: heretykiem

title: heretykiem


text: heretykami

title: heretykami


text: heretyku

title: heretyku


text: heretykach

title: heretykach


text: kacerze

title: kacerze


text: kacerza

title: kacerza


text: kacerzy

title: kacerzy


text: kacerzów

title: kacerzów


text: kacerzowi

title: kacerzowi


text: kacerzom

title: kacerzom


text: kacerzem

title: kacerzem


text: kacerzami

title: kacerzami


text: kacerzu

title: kacerzu


text: kacerzach

title: kacerzach


text: akademiczki

title: akademiczki


text: akademiczek

title: akademiczek


text: akademiczce

title: akademiczce


text: akademiczkom

title: akademiczkom


text: akademiczkę

title: akademiczkę


text: akademiczką

title: akademiczką


text: akademiczkami

title: akademiczkami


text: akademiczkach

title: akademiczkach


text: akademiczko

title: akademiczko


text:
doaudoau

Verb

 * 1) to fill

title: doaudoau


text:
Talk:鎖管

Integrating into the Dialectal Synonym Chart of 魷魚
I'm thinking of integrating all the terms for "small squid" in Hokkien into the dialectal synonym chart for. Since it's just a small 魷魚, so we can just label them as such. What do you think? Mar vin kaiser (talk) 01:14, 5 January 2024 (UTC)

title: Talk:鎖管


text:
monosialotetrahexosylganglioside

Noun

 * 1)  A glycosphingolipid found in high concentrations in nerve cell membranes.

Synonyms

 * GM1

title: monosialotetrahexosylganglioside


text:
호가호위

Etymology
.

Noun

 * 1)  using powerful connections to intimidate people

title: 호가호위


text:
microoptoelectromechanical

Adjective

 * 1) Very small, optical, electrical, and mechanical.

title: microoptoelectromechanical


text:
User talk:SwordofStorms

Welcome
Hello, welcome to Wiktionary, and thank you for your contributions so far.

If you are unfamiliar with wiki-editing, take a look at Help:How to edit a page. It is a concise list of technical guidelines to the wiki format we use here: how to, for example, make text boldfaced or create hyperlinks. Feel free to practice in the sandbox. If you would like a slower introduction we have a short tutorial.

These links may help you familiarize yourself with Wiktionary:

 * Entry layout (EL) is a detailed policy on Wiktionary's page formatting; all entries must conform to it. The easiest way to start off is to copy the contents of an existing same-language entry, and then adapt it to fit the entry you are creating.
 * Check out Language considerations to find out more about how to edit for a particular language.
 * Our Criteria for Inclusion (CFI) defines exactly which words can be added to Wiktionary; the most important part is that Wiktionary only accepts words that have been in somewhat widespread use over the course of at least a year, and citations that demonstrate usage can be asked for when there is doubt.
 * If you already have some experience with editing our sister project Wikipedia, then you may find our guide for Wikipedia users useful.
 * If you have any questions, bring them to Information desk or ask me on my talk page.
 * Whenever commenting on any discussion page, please sign your posts with four tildes which automatically produces your username and timestamp.
 * You are encouraged to add a BabelBox to your userpage to indicate your self-assessed knowledge of languages.

Enjoy your stay at Wiktionary! —Justin ( koavf ) ❤T☮C☺M☯ 01:24, 5 January 2024 (UTC)

Context labels
Hi, be aware that a context label usually indicates restricted usage: you might add "Louisiana" or "New York City" to an entry if it is only used or understood in these regions. See Context labels. Jberkel 08:19, 8 February 2024 (UTC)

 * But don't misuse them just to indicate where the defined object comes from. If a Lane cake is truly only called "Lane cake" in the South US, what would it be called elsewhere in the world? Equinox ◑ 20:04, 11 February 2024 (UTC)
 * It's not found in the rest of the world, hence my adding. The edits I'm making are largely to expand/pad out the library of US regionalisms. There were many other dishes that are only regionally available before I started editing here that were given such context labels. "Cincinnati chili" had a "Cincinnati" context label, "hushpuppy" had a "Southern US" context label, etc. Each of the food items I've added, as far as I'm aware, only exist in the regions I described. Someone from outside the South would likely simply refer to a hushpuppy as 'deep fried corn meal' when encountering it for the first time. Also I've been cross-referencing to Wikipedia for literally every entry I've made. SwordofStorms (talk) 20:14, 11 February 2024 (UTC)

 * I disagree. An English speaker from the USA, Canada, Trinidad, Jamaica or elsewhere who comes to Scotland and encounters haggis will call it haggis. They might have to be taught the word but it's still haggis. The referent being exotic is very different from something being a local, different word for an everyday thing (e.g. "sidewalk" vs "pavement"). Equinox ◑ 20:37, 13 February 2024 (UTC)
 * Okay well then you don't disagree with me, you disagree with the precedent set by entries before me. I've just made things consistent. SwordofStorms (talk) 20:39, 13 February 2024 (UTC)
 * Is there? I thought it was said that "lb|xx|PLACENAME" was only to be used if a term is used in PLACENAME only. (You could add a category like en:Southern US to place the terms whose referents only exist in the Southern US, as well.) CitationsFreak (talk) 21:26, 17 February 2024 (UTC)
 * Yes that's exactly what I'm doing, adding terms whose referents only exist regionally. SwordofStorms (talk) 21:28, 17 February 2024 (UTC)

 * The Eiffel Tower only exists in Paris but that doesn't make it "Eiffel Tower" Parisian French. Equinox ◑ 21:30, 17 February 2024 (UTC)

 * SwordofStorms, I see where you're coming from, in thinking "It's not found in the rest of the world", but that's not correct and it is not how labels are used (despite your claims above). Compare Wenksville: few if any people outside Pennsylvania ever discuss the place, but that doesn't mean the placename is specific to dialect; anyone speaking any dialect would call the place that if discussing it. You need to distinguish between when a term is regional and when the referent is discussed elsewhere it is called by other terms (like toboggan for a particular kind of hat), vs when the referent itself is just not much discussed outside of a particular place, but when it is discussed (anywhere) it is by the given term. I sympathize that this is not always an easy distinction to make, but you need to make the distinction, and add labels only when the term (not the referent) is regional; if you are not sure about a particular word, you should ask for input in e.g. the WT:Tea Room. (Please join Beer_parlour/2024/February.) PS, cheesesteak is made and sold all over the US, so nothing about it is restricted, neither the term nor even the referent. - -sche (discuss) 21:56, 17 February 2024 (UTC)
 * People do think of cheesesteak as a regional dish (Philadelphia, not just any part of Pennsylvania). A better example is Waldorf salad. People make, eat and talk about Waldorf salads all over the US, at the very least, and a lot of them don't know anything about any connection to New York. That's just part of the history of the recipe- something to mention in the etymology or in an encyclopedia article. There are all kinds of foods that came from a specific place, but we don't want them in the regional categories for those places- French fries don't belong in Category:French English (especially since they didn't come from France). Chuck Entz (talk) 22:36, 17 February 2024 (UTC)
 * As I've said, there were a multitude of entries with labels in this vain well before I started editing. I'm sorry if these were in themselves mistakes but I can tell you there were dozens of entries labeled this way. Feel free do undo any mistakes you think I've made, I would hope that people would do that, I'm no oracle. It's not everything I've done though I've also added countless non-cuisine related lexical items to the American English category. SwordofStorms (talk) 23:37, 17 February 2024 (UTC)
 * Okay well then I hope you enjoy removing the "Southern US" context label from 'sweet tea,' the "South Africa" context label from 'bunny chow,' the "British/New Zealand" context label from 'bangers and mash' and all other such entries. SwordofStorms (talk) 23:26, 17 February 2024 (UTC)
 * What is your source of regional usage information? DCDuring (talk) 15:27, 18 February 2024 (UTC)

title: User talk:SwordofStorms