Módulo:generar-pron/nci

La documentación para este módulo puede ser creada en Módulo:generar-pron/nci/doc

-- PRONUNCIACION PARA EL NÁHUATL
-- Este módulo cubre todas las variantes de náhuatl, por lo que todas redirigen acá para generar la pronunciación
-- Por lo tanto, hay un popurrí de los símbolos que se usan en cada región. Por ejemplo, en algunas uasn macrones
-- para alargar vocales. Esto sin embargo no produce ninguna colisión entre ninguna variante.
-- Pero sí que hay algunas incompatibilidades entre las variantes:
-- 1. El saltillo es una glotal en el nahua clásico, en los demás es una /h/
-- 2. Las tildes representan un saltillo en todas las variantes excepto en Mecayapan y Tatahuicapan, en donde se usan para acentuar.
-- Asimismo, supuestamente hay algo así como una corriente "new school" que propone una ortografía nueva,
-- 100% regular https://netza.org/archivo/por-que-la-ortografia-moderna-es-la-mejor/. En base a esto,
-- la ortografía clásica tiene algunas irregularidades en el sentido de que no es 1 letra 1 fonema el mapeo
-- en ciertos casos:
-- la C: mapea como /s/ antes de E o I, mapea como /k/ sino
-- la QU: mapea como /k/, cuidado porque si reemplazo una por una va a mapear como /ku/
-- En los demás casos, se mapean ciertos digrafos calcados del español (gü, rr, etc.) 
--
-- Autor: Tmagc

local export = {}

local insert = table.insert
local concat = table.concat

local m_str = require("Módulo:String")

local u = m_str.char
local strsubn = m_str.gsub
local strsubb = m_str.gsubb
local strsubrep = m_str.gsub_rep
local strlower = m_str.lower
local strstrip = m_str.strip
local strsplit = m_str.split
local strfind = m_str.find
local strnfd = m_str.toNFD
local strnfc = m_str.toNFC
local strhtml = m_str.encode_html

--CONVENCION: mayúscula para patrones encerrados entre corchetes, minúscula para todo lo demás
local ac_primario = u(0x02C8)
local ac_secundario = u(0x02CC)

local acentos_ipa = ac_primario..ac_secundario
local ACENTOS_IPA = "[" .. acentos_ipa .. "]"

local divsil = u(0xFFF0)
local sepsil = "%-.·" .. divsil
local SEPARADORES_SILABICOS = "[" .. sepsil .. "]"
local SALVO_SEPARADORES_SILABICOS = "[^" .. sepsil .. "]"
local seppal = "# "
local separador_excepto_palabras = acentos_ipa .. sepsil
local separador = separador_excepto_palabras .. seppal
local SEPARADOR = "[" .. separador .. "]"

local PUNTUACION = "[%(%)%[%]%{%}¡!¿?.,;:–—]"
local PUNTUACION_EXTRA = "[%(%)%[%]%{%}¡!¿?.,;:–—\"“”„‟‘’«»»«‹››‹]"

-- grafía
local virgulilla = u(0x0303)
local dieresis = u(0x0308)
local cedilla = u(0x0327)
local tildes = u(0x0301) -- puede ser un saltillo o para marcar la acentuación
local apostrofes = "'ʼꞌꞋ"..u(0x0300)..u(0x0302) -- el acento grave y el circunflejo mapea a un saltillo siempre
local macrones = u(0x0304)..u(0x0331)

local vocales = "aeioöAEIOÖ"
local VOCAL_SIN_TILDAR = "["..vocales.."]["..macrones.."]?"
local VOCAL = VOCAL_SIN_TILDAR.."["..tildes.."]?"
local consonantes = "bcdfghjklmnñpqrstuvwxyzçBCDFGHJKLMNÑPQRSTUVWXYZÇüÜ"
local CONS = "["..consonantes.."]"
local CONS_O_TILDE = "["..consonantes..tildes.."]"
local permitido = vocales..consonantes..macrones..apostrofes..tildes.."·|%s"

-- IPA
local vocales_ipa = "aeioɔ"
local VOCAL_IPA = "["..vocales_ipa.."]"
local CONS_IPA = "[^"..vocales_ipa..separador.."]"

local mapeo_fono_1 = {
	["a"] = "a",
	["b"] = "b",
	["c"] = "k",
	["d"] = "d",
	["e"] = "e",
	["f"] = "f",
	["g"] = "g",
	--["h"] = saltillo,
	["i"] = "i",
	--["j"] = saltillo,
	["k"] = "k",
	["l"] = "l",
	["m"] = "m",
	["n"] = "n",
	["ñ"] = "ɲ",
	["o"] = "o",
	["p"] = "p",
	["q"] = "k",
	["r"] = "ɾ",
	["s"] = "s",
	["t"] = "t",
	["u"] = "w",
	["v"] = "b",
	["w"] = "w",
	["x"] = "ʃ",
	["y"] = "j",
	["z"] = "s",
	["ç"] = "s",
	["ö"] = "ɔ",
	["ü"] = "w",
}

local mapeo_fono_2 = {
	["ce"] = "se",
	["ch"] = "t͡ʃ",
	["ci"] = "si",
	["cu"] = "kʷ",
	["gü"] = "w",
	["hu"] = "w",
	["ku"] = "kʷ",
	["lh"] = "l",
	--["ll"] = "j", debería hacer esto? NO, la doble l es para forzar una separación de sílaba
	["qu"] = "k",
	["tl"] = "t͡ɬ",
	["ts"] = "t͡s",
	["tz"] = "t͡s",
	--["uh"] = "w", esto no sé cómo tratarlo, supuestamente es de las terminaciones -uhua, pero provocará un loop infinito cuando intente juntar la hu también. No es más fácil silabear u-hua y ya?
	["iy"] = "j",
	["yi"] = "j", -- yi después de vocal e iy después de consonante son como una y simple [j]. Ēyi "tres" [eːj] y Quiyahuitl "lluvia" [ˈkja.witɬ]
}

local function aislar_diacriticos(texto)
	texto = strnfd(texto)
	texto = strsubrep(texto, "(["..tildes.."])([".. virgulilla .. dieresis .. cedilla .. macrones .."]+)", "%2%1")
	texto = strsubrep(texto, "(["..macrones.."])([".. virgulilla .. dieresis .. cedilla .."]+)", "%2%1")
	texto = strsubn(texto, ".[" .. virgulilla .. dieresis .. cedilla .. "]", {
		["n" .. virgulilla] = "ñ",
		["N" .. virgulilla] = "Ñ",
		["o" .. dieresis] = "ö",
		["O" .. dieresis] = "Ö",
		["u" .. dieresis] = "ü",
		["U" .. dieresis] = "Ü",
		["c" .. cedilla] = "ç",
		["C" .. cedilla] = "Ç",
	})
	return texto
end

local function recomponer_diacriticos(texto)
	return strnfc(texto)
end

local function normalizar(texto)
	texto = strlower(texto)
	texto = aislar_diacriticos(texto)

	texto = strsubrep(texto, PUNTUACION, " | ") -- convierto lo que delimite fragmentos a los IPA foot boundaries |
	texto = strsubrep(texto, PUNTUACION_EXTRA, "") -- elimino la puntuación restante que haya quedado
	texto = strsubrep(texto, "[%-‐]", " ") --los guiones pasan a ser espacios (austro-húngaro, franco-italiano)

	if strfind(texto, "[^"..permitido.."]") then
		error("caracteres no permitidos en el título")
	end

    texto = strsubrep(texto, "%s*|%s*|%s*", " | ") --finalmente, elimino las barras y espacios de más
    texto = strsubrep(texto, "%s+", " ")
	texto = strstrip(texto, "[%s|]+")

	return texto
end

local function separar_en_silabas(p, acentuacion_lr)
	p = aislar_diacriticos(p)

	p = divsil..p..divsil

	local C_VOCAL = acentuacion_lr and VOCAL or VOCAL_SIN_TILDAR
	local C_CONS = acentuacion_lr and CONS or CONS_O_TILDE

	-- Primero: las sílabas son todas del estilo CVC, el punto es que no puede haber dos vocales seguidas o dos consonantes seguidas en una misma sílaba
	p = strsubrep(p, "(" .. C_VOCAL .. C_CONS .. "?" .. ")(" .. C_CONS .. "+" .. C_VOCAL .. C_CONS .. "?" .. ")", "%1"..divsil.."%2")
	p = strsubrep(p, "(" .. C_VOCAL .. ")(" .. C_VOCAL .. ")", "%1"..divsil.."%2")
	p = strsubrep(p, "ll", "l"..divsil.."l")

	--Segundo, eximo de la regla anterior los digrafos
	for cc, fono in pairs(mapeo_fono_2) do
		local a, b = cc:sub(1,1), cc:sub(2)
		local A, B = a:upper(), b == "ü" and "Ü" or b:upper()
		p = strsubrep(p, "(["..a..A.."])"..divsil.."(["..b..B.."]"..C_VOCAL..")", divsil.."%1%2")
		p = strsubrep(p, "(["..a..A.."]["..b..B.."])"..divsil.."("..C_VOCAL..")", divsil.."%1%2")
		p = strsubrep(p, "(["..a..A.."])"..divsil.."(["..b..B.."])("..C_CONS..")", "%1%2"..divsil.."%3")
	end

	-- correcciones finales
	p = strsubn(p, "["..divsil.."]+", divsil)
	p = strsubrep(p, SEPARADORES_SILABICOS.."("..C_CONS.."+)"..SEPARADORES_SILABICOS.."("..SALVO_SEPARADORES_SILABICOS.."-"..C_VOCAL..")", divsil.."%1%2")
	p = strsubrep(p, SEPARADORES_SILABICOS.."("..SALVO_SEPARADORES_SILABICOS.."-)"..SEPARADORES_SILABICOS.."("..C_CONS.."+)"..SEPARADORES_SILABICOS, divsil.."%1%2"..divsil)

	p = strsubn(p, "["..divsil.."]+", divsil)
	p = strstrip(p, "["..divsil.." ]+")
	p = recomponer_diacriticos(p)

	return p
end

local function acentuar(p, acentuacion_lr)
	p = aislar_diacriticos(p)
	
	if not acentuacion_lr then -- reglas normales
		--Si la palabra termina en E, es aguda. Ejemplo: TEOTLÉ, NOPILTSINÉ, KETSALKOATLÉ. En cualquier otro caso es llana.
		if strfind(p, "e$") or not strfind(p, SEPARADORES_SILABICOS) then
			return strsubn(p, SEPARADORES_SILABICOS.."?".."("..SALVO_SEPARADORES_SILABICOS.."+)$", ac_primario.."%1")
		end

		return strsubn(p, SEPARADORES_SILABICOS.."?".."("..SALVO_SEPARADORES_SILABICOS.."+"..SEPARADORES_SILABICOS..SALVO_SEPARADORES_SILABICOS.."+)$", ac_primario.."%1")
	else -- reglas para Mecayapan y Tatahuicapan: la tilde marca la acentuación
		local encontrado
		p, encontrado = strsubb(p, SEPARADORES_SILABICOS.."?".."("..SALVO_SEPARADORES_SILABICOS.."+".."["..tildes.."]"..")", ac_primario.."%1")
		if not encontrado then
			if strfind(p, "[lLrR]$") or not strfind(p, SEPARADORES_SILABICOS) then --termina en -l, -r o es una única sílaba: mono o aguda
				p = strsubn(p, SEPARADORES_SILABICOS.."?".."("..SALVO_SEPARADORES_SILABICOS.."+)$", ac_primario.."%1")
			else -- varias sílabas y no termina en -l -r --> es LLANA
				p = strsubn(p, SEPARADORES_SILABICOS.."?".."("..SALVO_SEPARADORES_SILABICOS.."+"..SEPARADORES_SILABICOS..SALVO_SEPARADORES_SILABICOS.."+)$", ac_primario.."%1")
			end
		end
		return p
	end
end

local function generar_pron(texto, fone, saltillo_es_h, acentuacion_lr)
	texto = normalizar(texto)
	local convertido = {}
	local fragmentos = strsplit(texto, "%s*|%s*")

	for _,fragmento in ipairs(fragmentos) do
	    local palabras = strsplit(fragmento, "%s")
		local palabras_convertidas = {}
	    for _,p in ipairs(palabras) do
	    	p = separar_en_silabas(p, acentuacion_lr)
            p = strsubn(p, SEPARADORES_SILABICOS, ".")
			p = acentuar(p, acentuacion_lr) -- ya la deja descompuesta

	    	-- mapeo fonológico
	    	for a,b in pairs(mapeo_fono_2) do
	    		p = strsubn(p, a, b)
	    	end
	    	if not acentuacion_lr then
            	p = strsubn(p, "["..tildes.."]", saltillo_es_h and "h" or "Ɂ")
            else
            	p = strsubn(p, "["..tildes.."]", "")
            end
            p = strsubn(p, "[jh]", saltillo_es_h and "h" or "Ɂ")
	    	p = strsubn(p, ".", mapeo_fono_1)
	    	p = strsubn(p, "["..apostrofes.."]", "Ɂ")
	    	p = strsubn(p, "["..macrones.."]", "ː")
	    	p = strsubn(p, "i([aeo])", "j%1")
	    	p = strsubrep(p, "ɾɾ", "r")
	    	p = strsubrep(p, "^ɾ", "r")
	    	
	    	insert(palabras_convertidas, p)
	    end
	    insert(convertido, concat(palabras_convertidas, " "))
	end

    return {{strhtml(concat(convertido, " | "))}}
end

-- Punto de entrada externo, recibe el título de página y los argumentos de plantilla
function export.procesar_pron_args(titulo, args, saltillo_es_h, acentuacion_lr)
	if #args["ayuda"] < 1 then
		args["ayuda"][1] = titulo
	end

	if #args["fone"] < 1 and #args["fono"] < 1 then
		--local x = pron_abc[args["ayuda"][1]]
		--if x then
		--	args["tl"] = x
		--	args["ayuda"][1] = x
		--end
		local A = #args["ayuda"]
		local j = 1 -- indice de la ayuda
		local k = 1 -- cantidad de pronunciaciones insertadas (máximo 9)
		while k <= 9 and j <= A do
			local fono = generar_pron(args["ayuda"][j], saltillo_es_h, acentuacion_lr)
			for i,_ in ipairs(fono) do
				insert(args["fono"], fono[i])
				k = k + 1
				if k > 9 then
					break
				end
			end
			j = j + 1
		end

		local tiene_espacios = strfind(titulo, " ")

		if not tiene_espacios then
			if not args["d"][1] then
				local aux = separar_en_silabas(args["ayuda"][1], acentuacion_lr)
				args["d"][1] = strsubn(aux, SEPARADORES_SILABICOS, "-")
			end
		end

		local rim = args["fono"][1][1]
		rim = strsubn(rim, "^.*ˈ(.-)$", "%1")
		args["rima"][1] = strsubn(rim, ".-".."("..VOCAL_IPA..".*"..")".."$", "%1")

	end

	return args

end
 
return export