Module:es-common

Hello, you have come here looking for the meaning of the word Module:es-common. In DICTIOUS you will not only get to know all the dictionary meanings for the word Module:es-common, but we will also tell you about its etymology, its characteristics and you will know how to say Module:es-common in singular and plural. Everything you need to know about the word Module:es-common you have here. The definition of the word Module:es-common will help you to be more precise and correct when speaking or writing your texts. Knowing the definition ofModule:es-common, as well as those of other words, enriches your vocabulary and provides you with more and better linguistic resources.

This module contains utility functions used by Module:es-verb and Module:es-headword.


local export = {}

local romut_module = "Module:romance utilities"

local u = require("Module:string/char")
local rsplit = mw.text.split
local rfind = mw.ustring.find
local rmatch = mw.ustring.match
local rsubn = mw.ustring.gsub


local TEMPC1 = u(0xFFF1)
local TEMPC2 = u(0xFFF2)
local TEMPV1 = u(0xFFF3)
local DIV = u(0xFFF4)
local vowel = "aeiouáéíóúý" .. TEMPV1
local V = ""
local AV = "" -- accented vowel
local W = "" -- glide
local C = ""

export.vowel = vowel
export.V = V
export.AV = AV
export.W = W 
export.C = C 

local remove_accent = {
	 = "a",  = "e",  = "i",  = "o",  = "u",  = "y"
}
local add_accent = {
	 = "á",  = "é",  = "í",  = "ó",  = "ú",  = "ý"
}

export.remove_accent = remove_accent
export.add_accent = add_accent


local prepositions = {
	"al? ",
	"del? ",
	"como ",
	"con ",
	"en ",
	"para ",
	"por ",
}


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

export.rsub = rsub

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

export.rsub_repeatedly = rsub_repeatedly


-- Apply vowel alternation to stem.
function export.apply_vowel_alternation(stem, alternation)
	local ret, err
	-- Treat final -gu, -qu as a consonant, so the previous vowel can alternate (e.g. conseguir -> consigo).
	-- This means a verb in -guar can't have a u-ú alternation but I don't think there are any verbs like that.
	stem = rsub(stem, "()u$", "%1" .. TEMPC1)
	local before_last_vowel, last_vowel, after_last_vowel = rmatch(stem, "^(.*)(" .. V .. ")(.-)$")
	if alternation == "ie" then
		if last_vowel == "e" or last_vowel == "i" then
			-- allow i for adquirir -> adquiero, inquirir -> inquiero, etc.
			ret = before_last_vowel .. "ie" .. after_last_vowel
		else
			err = "should have -e- or -i- as the last vowel"
		end
	elseif alternation == "ye" then
		if last_vowel == "e" then
			ret = before_last_vowel .. "ye" .. after_last_vowel
		else
			err = "should have -e- as the last vowel"
		end
	elseif alternation == "ue" then
		if last_vowel == "o" or last_vowel == "u" then
			-- allow u for jugar -> juego; correctly handle avergonzar -> avergüenzo
			ret = (
				last_vowel == "o" and before_last_vowel:find("g$") and before_last_vowel .. "üe" .. after_last_vowel or
				before_last_vowel .. "ue" .. after_last_vowel
			)
		else
			err = "should have -o- or -u- as the last vowel"
		end
	elseif alternation == "hue" then
		if last_vowel == "o" then
			ret = before_last_vowel .. "hue" .. after_last_vowel
		else
			err = "should have -o- as the last vowel"
		end
	elseif alternation == "i" then
		if last_vowel == "e" then
			ret = before_last_vowel .. "i" .. after_last_vowel
		else
			err = "should have -i- as the last vowel"
		end
	elseif alternation == "í" then
		if last_vowel == "e" or last_vowel == "i" then
			-- allow e for reír -> río, sonreír -> sonrío
			ret = before_last_vowel .. "í" .. after_last_vowel
		else
			err = "should have -e- or -i- as the last vowel"
		end
	elseif alternation == "ú" then
		if last_vowel == "u" then
			ret = before_last_vowel .. "ú" .. after_last_vowel
		else
			err = "should have -u- as the last vowel"
		end
	else
		error("Unrecognized vowel alternation '" .. alternation .. "'")
	end
	ret = ret and ret:gsub(TEMPC1, "u") or nil
	return {ret = ret, err = err}
end


-- Syllabify a word. This implements the full syllabification algorithm, based on the corresponding code
-- in ]. This is more than is needed for the purpose of this module, which doesn't
-- care so much about syllable boundaries, but won't hurt.
function export.syllabify(word)
	word = DIV .. word .. DIV
	-- gu/qu + front vowel; make sure we treat the u as a consonant; a following
	-- i should not be treated as a consonant (] would become ''álguienes''
	-- if pluralized)
	word = rsub(word, "()u()", "%1" .. TEMPC2 .. "%2")
	local vowel_to_glide = {  = TEMPC1,  = TEMPC2 }
	-- i and u between vowels should behave like consonants (], ], ],
	-- ], ], etc.)
	word = rsub_repeatedly(word, "(" .. V .. ")()(" .. V .. ")",
		function(v1, iu, v2) return v1 .. vowel_to_glide .. v2 end
	)
	-- y between consonants or after a consonant at the end of the word should behave like a vowel
	-- (], ], ], ], etc.)
	word = rsub_repeatedly(word, "(" .. C .. ")y(" .. C .. ")",
		function(c1, c2) return c1 .. TEMPV1 .. c2 end
	)

	word = rsub_repeatedly(word, "(" .. V .. ")(" .. C .. W .. "?" .. V .. ")", "%1.%2")
	word = rsub_repeatedly(word, "(" .. V .. C .. ")(" .. C .. V .. ")", "%1.%2")
	word = rsub_repeatedly(word, "(" .. V .. C .. "+)(" .. C .. C .. V .. ")", "%1.%2")
	word = rsub(word, "()%.()", ".%1%2")
	word = rsub_repeatedly(word, "(" .. C .. ")%.s(" .. C .. ")", "%1s.%2")
	-- Any aeo, or stressed iu, should be syllabically divided from a following aeo or stressed iu.
	word = rsub_repeatedly(word, "()()", "%1.%2")
	word = rsub_repeatedly(word, "()()", "%1.%2")
	word = rsub_repeatedly(word, "()()", "%1.%2")
	word = rsub(word, "()", {
		 = "",
		 = "i",
		 = "u",
		 = "y",
	})
	return rsplit(word, "%.")
end


-- Return the index of the (last) stressed syllable.
function export.stressed_syllable(syllables)
	-- If a syllable is stressed, return it.
	for i = #syllables, 1, -1 do
		if rfind(syllables, AV) then
			return i
		end
	end
	-- Monosyllabic words are stressed on that syllable.
	if #syllables == 1 then
		return 1
	end
	local i = #syllables
	-- Unaccented words ending in a vowel or a vowel + s/n are stressed on the preceding syllable.
	if rfind(syllables, V .. "?$") then
		return i - 1
	end
	-- Remaining words are stressed on the last syllable.
	return i
end


-- Add an accent to the appropriate vowel in a syllable, if not already accented.
function export.add_accent_to_syllable(syllable)
	-- Don't do anything if syllable already stressed.
	if rfind(syllable, AV) then
		return syllable
	end
	-- Prefer to accent an a/e/o in case of a diphthong or triphthong (the first one if for some reason
	-- there are multiple, which should not occur with the standard syllabification algorithm);
	-- otherwise, do the last i or u in case of a diphthong ui or iu.
	if rfind(syllable, "") then
		return rsub(syllable, "^(.-)()", function(prev, v) return prev .. add_accent end)
	end
	return rsub(syllable, "^(.*)()", function(prev, v) return prev .. add_accent end)
end


-- Remove any accent from a syllable.
function export.remove_accent_from_syllable(syllable)
	return rsub(syllable, AV, remove_accent)
end


-- Return true if an accent is needed on syllable number `sylno` if that syllable were to receive the stress,
-- given the syllables of a word. The current accent may be on any syllable.
function export.accent_needed(syllables, sylno)
	-- Diphthongs iu and ui are normally stressed on the second vowel, so if the accent is on the first vowel,
	-- it's needed.
	if rfind(syllables, "íu") or rfind(syllables, "úi") then
		return true
	end
	-- If the default-stressed syllable is different from `sylno`, accent is needed.
	local unaccented_syllables = {}
	for _, syl in ipairs(syllables) do
		table.insert(unaccented_syllables, export.remove_accent_from_syllable(syl))
	end
	local would_be_stressed_syl = export.stressed_syllable(unaccented_syllables)
	if would_be_stressed_syl ~= sylno then
		return true
	end
	-- At this point, we know that the stress would by default go on `sylno`, given the syllabification in
	-- `syllables`. Now we have to check for situations where removing the accent mark would result in a
	-- different syllabification. For example, países -> `pa.i.ses` but removing the accent mark would lead
	-- to `pai.ses`. Similarly, río -> `ri.o` but removing the accent mark would lead to single-syllable `rio`.
	-- We need to check whether (a) the stress falls on an i or u; (b) in the absence of an accent mark, the
	-- i or u would form a diphthong with a preceding or following vowel and the stress would be on that vowel.
	-- The conditions are slightly different when dealing with preceding or following vowels because ui and ui
	-- diphthongs are by default stressed on the second vowel. We also have to ignore h between the vowels.
	local accented_syllable = export.add_accent_to_syllable(unaccented_syllables)
	if sylno > 1 and rfind(unaccented_syllables, "$") and rfind(accented_syllable, "^h?") then
		return true
	end
	if sylno < #syllables then
		if rfind(accented_syllable, "í$") and rfind(unaccented_syllables, "^h?") or
			rfind(accented_syllable, "ú$") and rfind(unaccented_syllables, "^h?") then
			return true
		end
	end
	return false
end


function export.make_plural(form, gender, special)
	local retval = require(romut_module).handle_multiword(form, special,
		function(term) return export.make_plural(term, gender) end, prepositions)
	if retval then
		return retval
	end

	if gender == "gneut" and rfind(form, "$") then
		return {form .. "s"}
	end

	-- ends in unstressed vowel or á, é, ó
	if rfind(form, "$") then return {form .. "s"} end

	-- ends in í or ú
	if rfind(form, "$") then
		return {form .. "s", form .. "es"}
	end

	-- ends in a vowel + z
	if rfind(form, V .. "z$") then
		return {rsub(form, "z$", "ces")}
	end

	-- ends in tz
	if rfind(form, "tz$") then return {form} end

	local syllables = export.syllabify(form)

	-- ends in s or x with more than 1 syllable, last syllable unstressed
	if syllables and rfind(form, "$") and not rfind(syllables, AV) then
		return {form}
	end

	-- ends in l, r, n, d, z, or j with 3 or more syllables, stressed on third to last syllable
	if syllables and rfind(form, "$") and rfind(syllables, AV) then
		return {form}
	end

	-- ends in an accented vowel + consonant
	if rfind(form, AV .. C .. "$") then
		return {rsub(form, "(.)(.)$", function(vowel, consonant)
			return export.remove_accent .. consonant .. "es"
		end)}
	end

	-- ends in a vowel + y, l, r, n, d, j, s, x
	if rfind(form, "$") then
		-- two or more syllables: add stress mark to plural; e.g. joven -> jóvenes
		if syllables and rfind(form, "n$") then
			syllables = export.add_accent_to_syllable(syllables)
			return {table.concat(syllables, "") .. "es"}
		end

		return {form .. "es"}
	end

	-- ends in a vowel + ch
	if rfind(form, "ch$") then return {form .. "es"} end

	-- ends in two consonants
	if rfind(form, C .. C .. "$") then return {form .. "s"} end

	-- ends in a vowel + consonant other than l, r, n, d, z, j, s, or x
	if rfind(form, "$") then return {form .. "s"} end

	return nil
end

function export.make_feminine(form, special)
	local retval = require(romut_module).handle_multiword(form, special, export.make_feminine, prepositions)
	if retval then
		if #retval ~= 1 then
			error("Internal error: Should have one return value for make_feminine: " .. table.concat(retval, ","))
		end
		return retval
	end

	if form:find("o$") then
		local retval = form:gsub("o$", "a") -- discard second retval
		return retval
	end

	local function make_stem(form)
		return rsub(
			form,
			"^(.+)(.)(.)$",
			function (before_stress, stressed_vowel, after_stress)
				return before_stress .. (export.remove_accent or stressed_vowel) .. after_stress
			end)
	end

	if rfind(form, "n$") or rfind(form, "s$") or rfind(form, "or$") or rfind(form, "ol$") then
		-- holgazán, comodín, bretón (not común); francés, kirguís (not mandamás);
		-- volador, agricultor, defensor, avizor, flexor, señor (not posterior, bicolor, mayor, mejor, menor, peor);
		-- español, mongol
		return make_stem(form) .. "a"
	end

	return form
end

function export.make_masculine(form, special)
	local retval = require(romut_module).handle_multiword(form, special, export.make_masculine, prepositions)
	if retval then
		if #retval ~= 1 then
			error("Internal error: Should have one return value for make_masculine: " .. table.concat(retval, ","))
		end
		return retval
	end

	if form:find("dora$") then
		local retval = form:gsub("a$", "") -- discard second retval
		return retval
	end

	if form:find("a$") then
		local retval = form:gsub("a$", "o") -- discard second retval
		return retval
	end

	return form
end

return export