Module:qhv-pron

From Linguifex
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

This module generates IPA pronunciation for High Valyrian words. Backend to {{qhv-IPA}}.
local sub = mw.ustring.sub
local find = mw.ustring.find
local gmatch = mw.ustring.gmatch
local gsub = mw.ustring.gsub
local match = mw.ustring.match
local u = mw.ustring.char
local split = mw.text.split
local gsplit = mw.text.gsplit

local m_table = require("Module:table")

local export = {}

local palatal = "ɲʎɟj"
local velar = "kɡxɣ"
local uvular = "q"
local consonants = "[mpbvwθntdszlrɾŋɴhɥṛ" .. palatal .. velar .. uvular .. "]"
local NONSYLLABIC = u(0x032F) -- non-syllabic, combining inverted breve below
local DIPHTHONG = u(0x035C) -- double articulation, combining double breve below
local vowels = "[aeiouyáéíóúýàèìòùỳː" .. NONSYLLABIC .. DIPHTHONG .. "]"

local rules = {
	{"rh", "ṛ"}, {"mh", "m"}, {"th", "θ"}, {"lj", "ʎ"}, {"ñ", "ɲ"}, {"kh", "x"}, {"[gɡ]h", "ɣ"}, {"g", "ɡ"},
	
	{"([aāáà][eo])", "%1" .. NONSYLLABIC}, {"([iíuú])([aāeēoōáéóàèò])", "%1" .. DIPHTHONG .. "%2"}, 
	{"ā", "aː"}, {"ē", "eː"}, {"ī", "iː"}, {"ō", "oː"}, {"ū", "uː"}, {"ȳ", "yː"},
	{"à", "áː"}, {"è", "éː"}, {"ì", "íː"}, {"ò", "óː"}, {"ù", "úː"}, {"ỳ", "ýː"},
	
	{"n([" .. palatal .. "])", "ɲ%1"}, {"n([" .. velar .. "])", "ŋ%1"}, {"n([" .. uvular .. "])", "ɴ%1"},
	{"(" .. vowels .. ")r(" .. vowels .. ")", "%1ɾ%2"}, {"ɲi", "ni"}, {"ʎi", "li"},
}

local deacuter = {
	["á"] = "a", ["é"] = "e", ["í"] = "i", ["ó"] = "o", ["ú"] = "u", ["ý"] = "y",
}

function export.write_stress(term, from_module)
	local pattern = "(" .. consonants .. "*".. vowels .. "*" .. consonants .. "-)"
	local weight = {}
	term = gsub(term, pattern, "·%1")
	term = gsub(term, "^·", "")
	term = gsub(term, "·$", "")
	term = gsub(term, "·(" .. consonants .. ")·", "·%1")
	term = gsub(term, "·(" .. consonants .. ")$", "%1")
	term = gsub(term, "·(" .. consonants .. ")(" .. consonants .. ")", "%1·%2")  
	term = gsub(term, "([ptkbdɡ])·([rlṛsz])", "·%1%2")
	term = gsub(term, "·(" .. consonants .. "?" .. consonants .. ")$", "%1")
	
	local syllables = split(term, "·")
	
	if from_module then return #syllables end -- allow other modules to know the number of syllables
	
	if #syllables == 1 then return table.concat(syllables) end -- account for monosyllables
	for i, syllable in ipairs(syllables) do
		if match(syllable, "[áéíóúý]") then -- if the user inputted manual stress, ignore all the rest
			table.insert(syllables, i, "ˈ")
			return table.concat(syllables)
		end	
		if match(syllable, consonants .. "$") or match(syllable, "ː$") then weight[i] = "h"
		elseif match(syllable, NONSYLLABIC .. "$") then weight[i] = "h"
		else weight[i] = "l"
		end
	end
	
	local a, p = weight[#weight-2], weight[#weight-1]
	if p == nil then table.insert(syllables, #syllables, "ˈ")
	elseif a == nil then table.insert(syllables, #syllables-1, "ˈ")
	elseif p == "l" and a == "h" then table.insert(syllables, #syllables-2, "ˈ")
	elseif (p == "l" and a == "l") or (p == "h") then table.insert(syllables, #syllables-1, "ˈ")
	else table.insert(syllables, #syllables-1, "ˈ") end
	
	return table.concat(syllables)
end

function export.crux(term)
	term = mw.ustring.lower(term)
	
	for _, rule in ipairs(rules) do
		term = gsub(term, rule[1], rule[2])
	end
	
	return export.write_stress(term, false)
end	

function export.antique_crux(term)
	local oldrules = {
	{"v([ou])", "w%1"}, {"v([ay])", "ɥ%1"}, {"(" .. vowels .. ")v(ˈ?" .. consonants .. ")", "%1u%2"},
	{"j([iy])", "ɟ%1"}, {"sˈ?ri(".. vowels .. ")", "ˈɟ%1"}, {"sr", "ɟ"}, {"sˈ?r", "ˈɟ"},
	}
	
	term = export.crux(term)
	
	for _, oldrule in ipairs(oldrules) do
		term = gsub(term, oldrule[1], oldrule[2])	
	end
	
	return term
end

local function IPA_span(items)
	local bits = {}
	for _, item in ipairs(items) do
		local bit = "<span style=\"font-size:110%;font-family:Gentium,'DejaVu Sans','Segoe UI',sans-serif>" .. item.pron .. "</span>"
		table.insert(bits, bit)
	end
	return table.concat(bits)
end

local function format_IPA(items)
	return "[[w:IPA chart|IPA]]<sup>([[IPA for High Valyrian|key]])</sup>:&#32;" .. IPA_span(items)
end

function line_format(pronunciation, register)
	local full_pronunciations = {}
	local IPA_args = {{pron = '[' .. pronunciation .. ']'}}
	table.insert(full_pronunciations, format_IPA(IPA_args))
	return "(''" .. table.concat(register, ", ") .. "'')" .. ' ' .. table.concat(full_pronunciations, ' or ')
end

function separate_word(term, b)
	local result = {}
	
	for word in gsplit(term, " ") do
		if b then table.insert(result, export.antique_crux(word))
		else table.insert(result, export.crux(word)) end
	end
	
	return table.concat(result, " ")
end

function export.show(frame)
	local params = {
		[1] = { default = mw.title.getCurrentTitle().nsText == 'Template' and "drakarys" or mw.title.getCurrentTitle().text },
	}
	local args = require("Module:parameters").process(frame:getParent().args, params)
	local term = args[1]
	
	local ipa = "* "
	ipa = ipa .. line_format(separate_word(term, false), {'Post-Classical'})
	if export.crux(term) ~= export.antique_crux(term) then
		ipa = ipa .. "\n* " .. line_format(separate_word(term, true), {'Classical'})
	end	
	
	ipa = gsub(ipa, "ṛ", "r̥")
	ipa = gsub(ipa, "([áéíóú])", function(v) return deacuter[v] end)
	
	return ipa
end	

return export