測試樣例

10測試s失敗。 (刷新)

文字 預期 實際
test_all:
Passed нананазад (nananazad) naˈnanazat naˈnanazat
Passed Тласолтеотл (Tlasolteotl) tɫasɔɫˈtɛɔtɫ̩ tɫasɔɫˈtɛɔtɫ̩
Passed њутн (njutn) ˈɲutn̩ ˈɲutn̩
Passed беџ (bedž) bɛt͡ʃ bɛt͡ʃ
Passed правци (pravci) ˈpraft͡si ˈpraft͡si
Passed надежта (nadežta) ˈnadɛʃta ˈnadɛʃta
Passed бели (beli) ˈbɛli ˈbɛli
Passed соседство (sosedstvo) ˈsɔsɛtstvɔ ˈsɔsɛtstvɔ
Passed зима́ва (zimáva) ziˈmava ziˈmava
Passed одва́j (odváj) ɔˈdvaj ɔˈdvaj
Passed Мавританија (Mavritanija) mavriˈtani(j)a mavriˈtani(j)a
Passed ’рѓа (’rǵa) ˈr̩ɟa ˈr̩ɟa
Passed бесчестен (besčesten) ˈbɛʃt͡ʃɛstɛn ˈbɛʃt͡ʃɛstɛn
Passed бара (bara) ˈbaɾa ˈbaɾa
Passed станбен (stanben) ˈstambɛn ˈstambɛn
Passed конфузен (konfuzen) ˈkɔɱfuzɛn ˈkɔɱfuzɛn
Passed рамка (ramka) ˈramka ˈramka
Passed амфора (amfora) ˈaɱfɔɾa ˈaɱfɔɾa
Passed емиграциски (emigraciski) ɛmiˈɡrat͡siski ɛmiˈɡrat͡siski
Passed соучесништво (součesništvo) sɔuˈt͡ʃɛsniʃtvɔ sɔuˈt͡ʃɛsniʃtvɔ
Passed подмножество (podmnožestvo) pɔdˈmnɔʒɛstvɔ pɔdˈmnɔʒɛstvɔ
Passed грнчарство (grnčarstvo) ˈɡr̩nt͡ʃarstvɔ ˈɡr̩nt͡ʃarstvɔ
Passed стокхолмски (stokholmski) ˈstɔkxɔɫmski ˈstɔkxɔɫmski
Passed трамвајскиот (tramvajskiot) traɱˈvajski(j)ɔt traɱˈvajski(j)ɔt
Passed одраниот (odraniot) ɔˈdrani(j)ɔt ɔˈdrani(j)ɔt
Passed позлатува (pozlatuva) pɔˈzɫatuva pɔˈzɫatuva
Passed остварува (ostvaruva) ɔˈstvaɾuva ɔˈstvaɾuva
Passed дошколува (doškoluva) dɔˈʃkɔɫuva dɔˈʃkɔɫuva
Passed основање (osnovanje) ɔˈsnɔvaɲɛ ɔˈsnɔvaɲɛ
Passed потковица (potkovica) pɔtˈkɔvit͡sa pɔtˈkɔvit͡sa
Passed инјекција (injekcija) inˈjɛkt͡si(j)a inˈjɛkt͡si(j)a
Passed отсјаите (otsjaite) ɔtˈsjaitɛ ɔtˈsjaitɛ
Passed подморница (podmornica) pɔdˈmɔrnit͡sa pɔdˈmɔrnit͡sa
Passed полудневниот (poludnevniot) pɔɫuˈdnɛvni(j)ɔt pɔɫuˈdnɛvni(j)ɔt
Passed од играчка плачка (od igračka plačka) ɔd ˈiɡrat͡ʃka ˈpɫat͡ʃka ɔd ˈiɡrat͡ʃka ˈpɫat͡ʃka
Failed од немај-каде (od nemaj-kade) ɔd nɛˈmajkadɛ ɔd ˈnɛmaj ˈkadɛ
Passed од почит кон (od počit kon) ɔt ˈpɔt͡ʃit kɔn ɔt ˈpɔt͡ʃit kɔn
Passed обновува (obnovuva) ɔbˈnɔvuva ɔbˈnɔvuva
Passed облажува (oblažuva) ɔˈbɫaʒuva ɔˈbɫaʒuva
Passed чувствителност (čuvstvitelnost) t͡ʃufˈstvitɛɫnɔst t͡ʃufˈstvitɛɫnɔst
Passed конфли́кт (konflíkt) kɔɱˈflikt kɔɱˈflikt
Passed комфорен (komforen) ˈkɔɱfɔɾɛn ˈkɔɱfɔɾɛn
Failed бара преку леб погача (bara preku leb pogača) ˈbaɾa ˈprɛku ˈlɛp ˈpɔɡat͡ʃa ˈbaɾa ˈprɛku lɛp ˈpɔɡat͡ʃa
Failed сѐ или ништо (sè ili ništo) ˈsɛ ili ˈniʃtɔ sɛ ili ˈniʃtɔ
Failed сѐ уште (sè ušte) ˈsɛ uʃtɛ sɛ ˈuʃtɛ
Passed илјадити (iljaditi) iˈʎaditi iˈʎaditi
Passed Унгарија (Ungarija) uŋˈɡaɾi(j)a uŋˈɡaɾi(j)a
Passed архиепископ (arhiepiskop) arxiˈɛpiskɔp arxiˈɛpiskɔp
Passed комба́јн (kombájn) kɔmˈbajn kɔmˈbajn
Passed мјаука (mjauka) ˈmjauka ˈmjauka
Passed скејтборд (skejtbord) ˈskɛjdbɔrt ˈskɛjdbɔrt
Passed жанр (žanr) ˈʒanr̩ ˈʒanr̩
Failed подредува (podreduva) pɔdˈrɛduva pɔˈdrɛduva
Failed разликува (razlikuva) razˈlikuva raˈzlikuva
Failed растворени (rastvoreni) rasˈtvɔɾɛni raˈstvɔɾɛni
Failed потешкотија (poteškotija) pɔtɛʃˈkɔti(j)a pɔtɛˈʃkɔti(j)a
Failed олеснување (olesnuvanje) ɔlɛsˈnuvaɲɛ ɔlɛˈsnuvaɲɛ
Failed соткаено (sotkaeno) sɔˈtkaɛnɔ sɔtˈkaɛnɔ

local export = {}

local u = mw.ustring.char
local rsubn = mw.ustring.gsub
local ulower = mw.ustring.lower

local m_syllables = require("Module:syllables")
local m_utils = require("Module:utilities")
local lang = require("Module:languages").getByCode("mk")

local AC = u(0x301)
local SYLLABIC = u(0x329)
local TIE = u(0x361)

local phonetic_chars_map = {
	["а"] = "a",
	["е"] = "ɛ", ["ѐ"] = "ɛ",
	["и"] = "i", ["ѝ"] = "i",
	["о"] = "ɔ",
	["у"] = "u",
	
	["б"] = "b",
	["в"] = "v",
	["г"] = "ɡ",
	["д"] = "d",
	["ѓ"] = "ɟ",
	["ж"] = "ʒ",
	["з"] = "z",
	["ѕ"] = "d" .. TIE .. "z",
	["ј"] = "j",
	["к"] = "k",
	["л"] = "ɫ",
	["љ"] = "ʎ",
	["м"] = "m",
	["н"] = "n",
	["њ"] = "ɲ",
	["п"] = "p",
	["р"] = "r",
	["с"] = "s",
	["т"] = "t",
	["ќ"] = "c",
	["ф"] = "f",
	["х"] = "x",
	["ц"] = "t" .. TIE .. "s",
	["ч"] = "t" .. TIE .. "ʃ",
	["џ"] = "d" .. TIE .. "ʒ",
	["ш"] = "ʃ",

	["’"] = "ə",
	["‘"] = "ə",
	[AC] = "ˈ",
	["`"] = "ˈ",
	["/"] = "ˈ",
}

local devoicing = {
	['b'] = 'p', ['d'] = 't', ['ɟ'] = 'c', ['ɡ'] = 'k',
	['z'] = 's', ['ʒ'] = 'ʃ',
	['v'] = 'f', [TIE] = TIE
}

local vowel = "aɛiɔuə"
local vocalic = vowel .. SYLLABIC
local vocalic_c = "[" .. vocalic .. "]"

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

function export.toIPA(text)
	text = mw.ustring.toNFC(ulower(text))

	-- convert commas and en/en dashes to text foot boundaries
	text = rsub(text, "%s*[,–—]%s*", " | ")
	-- question mark or exclamation point in the middle of a sentence -> text foot boundary
	text = rsub(text, "([^%s])%s*[!?]%s*([^%s])", "%1 | %2")
	text = rsub(text, "[!?]", "") -- eliminate remaining punctuation

	-- canonicalize multiple spaces and remove leading and trailing spaces
	local function canon_spaces(text)
		text = rsub(text, "%s+", " ")
		text = rsub(text, "^ ", "")
		text = rsub(text, " $", "")
		return text
	end

	-- Convert hyphens to spaces. FIXME: Prefixes and suffixes should be unstressed unless explicitly marked for stress.
	text = rsub(text, "%-", " ")
	-- canonicalize multiple spaces, which may have been introduced by hyphens.
	text = canon_spaces(text)
	-- Put # at word beginning and end and double ## at text/foot boundary beginning/end.
	text = rsub(text, " | ", "# | #")
	text = "##" .. rsub(text, " ", "# #") .. "##"

	text = rsub(text, ".", phonetic_chars_map)

	-- Syllabic sonorants
	text = rsub(text, "# #m#", "# #mə#")
	text = rsub(text, "#m# #", "#mə# #")
	text = rsub(text, "# #n#", "# #nə#")
	text = rsub(text, "#n# #", "#nə# #")
	text = rsub(text, "# #ɲ#", "# #ɲə#")
	text = rsub(text, "#ɲ# #", "#ɲə# #")
	text = rsub(text, "# #r#", "# #rə#")
	text = rsub(text, "#r# #", "#rə# #")
	text = rsub(text, "# #ɫ#", "# #ɫə#")
	text = rsub(text, "#ɫ# $", "#ɫə# #")
	text = rsub(text, "# #l#", "# #lə#")
	text = rsub(text, "#l# #", "#lə# #")
	text = rsub(text, "# #ʎ#", "# #ʎə#")
	text = rsub(text, "#ʎ# #", "#ʎə# #")
	text = rsub(text, "# #j#", "# #jə#")
	text = rsub(text, "#j# #", "#jə# #")
	text = rsub_repeatedly(text, "([^" .. vocalic .. "ˈ])([rɫlʎj])([^" .. vocalic .. "])", "%1%2" .. SYLLABIC .. "%3")
	text = rsub_repeatedly(text, "([^" .. vocalic .. "rɫlʎjˈ])([mnɲ])([^" .. vocalic .. "rɫlʎmnɲj])", "%1%2" .. SYLLABIC .. "%3")
	text = rsub(text, "ər", "r" .. SYLLABIC)

	-- Mark stress
	text = rsub(text, "(#[^#ˈ ]*" .. vocalic_c .. ")([^#ˈ ]*" .. vocalic_c .. "[^#ˈ ]*" .. vocalic_c .. "[^#ˈ ]*#)", "%1ˈ%2")
	text = rsub(text, "(#[^#ˈ ]*" .. vocalic_c .. ")([^#ˈ ]*" .. vocalic_c .. "[^#ˈ ]*#)", "%1ˈ%2")
	text = rsub(text, "([szʃʒ]?[ptckbdɟɡfxmɱnɲ]?[mɱnɲv]?[rɫljʎ]?" .. vocalic_c .. ")ˈ", "ˈ%1")
	text = rsub(text, "([td]" .. TIE .. "[szʃʒ]?)ˈ", "ˈ%1")
	text = rsub(text, "#([^#aɛiɔuə" .. SYLLABIC .. " ]*)ˈ", "#ˈ%1")
	text = rsub(text, "ˈbm", "bˈm")
	text = rsub(text, "ˈbn", "bˈn")
	text = rsub(text, "ˈbv", "bˈv")
	text = rsub(text, "ˈdm", "dˈm")
	text = rsub(text, "ˈdɲ", "dˈɲ")
	text = rsub(text, "ˈdvr", "dˈvr")
	text = rsub(text, "ˈdvɫ", "dˈvɫ")
	text = rsub(text, "ˈstm", "stˈm")
	text = rsub(text, "ˈfn", "fˈn")
	text = rsub(text, "ˈ[mɱn]v", "ɱˈv")
	text = rsub(text, "[ɫl]ˈj", "ˈʎ")
	text = rsub(text, "ˈzʎ", "zˈʎ")
	text = rsub(text, "ˈbj", "bˈj")
	text = rsub(text, "ˈdj", "dˈj")
	text = rsub(text, "ˈnj", "nˈj")
	text = rsub(text, "ˈnɫ", "nˈɫ")
	text = rsub(text, "ˈnr", "nˈr")
	text = rsub(text, "ˈzmj", "zˈmj")
	text = rsub(text, "ˈzmr", "zˈmr")
	text = rsub(text, "ˈzvr", "zˈvr")
	text = rsub(text, "ˈsfr", "sˈfr")
	text = rsub(text, "ˈʃx", "ʃˈx")
	text = rsub(text, "#ˈiɫi#", "#ili#")
	text = rsub(text, "#p#", "#pə#")
	text = rsub(text, "#b#", "#bə#")
	text = rsub(text, "#t#", "#tə#")
	text = rsub(text, "#d#", "#də#")
	text = rsub(text, "#c#", "#cə#")
	text = rsub(text, "#ɟ#", "#ɟə#")
	text = rsub(text, "#k#", "#kə#")
	text = rsub(text, "#ɡ#", "#ɡə#")
	text = rsub(text, "#f#", "#fə#")
	text = rsub(text, "#v#", "#və#")
	text = rsub(text, "#s#", "#sə#")
	text = rsub(text, "#z#", "#zə#")
	text = rsub(text, "#ʃ#", "#ʃə#")
	text = rsub(text, "#ʒ#", "#ʒə#")
	text = rsub(text, "#x#", "#xə#")
	text = rsub(text, "#t͡s#", "#t͡sə#")
	text = rsub(text, "#d͡z#", "#d͡zə#")
	text = rsub(text, "#t͡ʃ#", "#t͡ʃə#")
	text = rsub(text, "#d͡ʒ#", "#d͡ʒə#")
	
	-- Palatalisation
	text = rsub(text, "ɫ([iɛ])", "l%1")
	text = rsub(text, "ɫ([j])", "ʎ")

	-- Voicing assimilation
	text = rsub(text, "([bdɟɡzʒv" .. TIE .. "]*)(ˈ?[ptcksʃfx])", function(a, b)
		return rsub(a, '.', devoicing) .. b end)
	text = rsub(text, "b##", "p##")
	text = rsub(text, "d##", "t##")
	text = rsub(text, "ɟ##", "c##")
	text = rsub(text, "ɡ##", "k##")
	text = rsub(text, "z##", "s##")
	text = rsub(text, "ʒ##", "ʃ##")
	text = rsub(text, "v##", "f##")
	text = rsub(text, "b# #(ˈ?)([ptcksʃfx])", "p# #%1%2")
	text = rsub(text, "b# #(ˈ?)([bdɟɡzʒvmɱnɲvrɫljʎ])", "b# #%1%2")
	text = rsub(text, "d# #(ˈ?)([ptcksʃfx])", "t# #%1%2")
	text = rsub(text, "d# #(ˈ?)([bdɟɡzʒvmɱnɲvrɫljʎ])", "d# #%1%2")
	text = rsub(text, "ɟ# #(ˈ?)([ptcksʃfx])", "c# #%1%2")
	text = rsub(text, "ɟ# #(ˈ?)([bdɟɡzʒvmɱnɲvrɫljʎ])", "ɟ# #%1%2")
	text = rsub(text, "ɡ# #(ˈ?)([ptcksʃfx])", "k# #%1%2")
	text = rsub(text, "ɡ# #(ˈ?)([bdɟɡzʒvmɱnɲvrɫljʎ])", "ɡ# #%1%2")
	text = rsub(text, "z# #(ˈ?)([ptcksʃfx])", "s# #%1%2")
	text = rsub(text, "z# #(ˈ?)([bdɟɡzʒvmɱnɲvrɫljʎ])", "z# #%1%2")
	text = rsub(text, "ʒ# #(ˈ?)([ptcksʃfx])", "ʃ# #%1%2")
	text = rsub(text, "ʒ#(ˈ?)([ptcksʃfx])", "ʃ#%1%2")
	text = rsub(text, "ʒ# #(ˈ?)([bdɟɡzʒvmɱnɲvrɫljʎ])", "ʒ# #%1%2")
	text = rsub(text, "v# #(ˈ?)([ptcksʃfx])", "f# #%1%2")
	text = rsub(text, "v# #(ˈ?)([bdɟɡzʒvmɱnɲvrɫljʎ])", "v# #%1%2")
	text = rsub(text, "(p)(ˈ?)([bdɟɡzʒ])", "b%2%3")
	text = rsub(text, "(t)(ˈ?)([bdɟɡzʒ])", "d%2%3")
	text = rsub(text, "(c)(ˈ?)([bdɟɡzʒ])", "ɟ%2%3")
	text = rsub(text, "(k)(ˈ?)([bdɟɡzʒ])", "ɡ%2%3")
	text = rsub(text, "(s)(ˈ?)([bdɟɡzʒ])", "z%2%3")
	text = rsub(text, "(ʃ)(ˈ?)([bdɟɡzʒ])", "ʒ%2%3")
	text = rsub(text, "zt##", "st##")
	text = rsub(text, "ʒt##", "ʃt##")
	text = rsub(text, "d͡ʃ", "t͡ʃ")
	text = rsub(text, "t͡ʒ", "d͡ʒ")

	-- Sibilant assimilation
	text = rsub(text, "[sz](ˈ?[td]?" .. TIE .. "?)([ʃʒ])", "%2%1%2")

	-- Nasal assimilation
	text = rsub(text, "n([ɡkx]+)", "ŋ%1")
	text = rsub(text, "nˈ([ɡkx]+)", "ŋˈ%1")
	text = rsub(text, "n̩([ɡkx]+)", "ŋ̩%1")
	text = rsub(text, "n̩ˈ([ɡkx]+)", "ŋ̩ˈ%1")
	text = rsub(text, "n([bp]+)", "m%1")
	text = rsub(text, "nˈ([bp]+)", "mˈ%1")
	text = rsub(text, "n([cɟ]+)", "ɲ%1")
	text = rsub(text, "nˈ([cɟ]+)", "ɲˈ%1")
	text = rsub(text, "[nm]([fv]+)", "ɱ%1")
	text = rsub(text, "[nm]ˈ([fv]+)", "ɱˈ%1")

	-- Epenthesis
	text = rsub(text, "(i)j([aɛɔu])", "%1(j)%2")
	text = rsub(text, "(i)([aɛɔu])", "%1(j)%2")
	text = rsub(text, "(iˈ)j([aɛɔu])", "%1j%2")
	text = rsub(text, "(iˈ)([aɛɔu])", "%1%2")

	-- /r/ allophony
	text = rsub(text, "([aɛiɔuə])r", "%1ɾ")
	text = rsub(text, "ɾ([^aɛiɔuə])", "r%1")
	
	-- Strip hashes
	text = rsub(text, "#", "")

	return text
end

function assign_stresscats(syllables)
	syllables = mw.ustring.gsub(syllables, ".*ˈ", "")
	syllables = m_syllables.getVowels(syllables, lang)
	if syllables == 1 then 
		table.insert(syllable_cats, "重音在最後一個音節的馬其頓語詞")
	elseif syllables == 2 then 
		table.insert(syllable_cats, "重音在倒數第二個音節的馬其頓語詞")
	elseif syllables == 3 then 
		table.insert(syllable_cats, "重音在倒數第三個音節的馬其頓語詞")
	end
end

function export.show(frame)
	local params = {
		[1] = {},
		["no_stress"] = {type = "boolean", default = false},
	}
	
	local title = mw.title.getCurrentTitle()
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	local term = args[1] or title.nsText == "Template" and "пример" or title.text

	local IPA = export.toIPA(term)
	
	syllable_cats = {}
	
	if mw.ustring.find(IPA, " ") == nil and args.no_stress == false then 
		assign_stresscats(IPA)
	end

	IPA = "[" .. IPA .. "]"
	IPA = require("Module:IPA").format_IPA_full(lang, { { pron = IPA } } )
	
	return IPA .. m_utils.format_categories(syllable_cats, lang)
end

return export