De Muysc cubun - Lengua Muisca

m (Se ha deshecho la revisión 102469 de Diegomez (disc.))
Etiqueta: Deshacer
m
Línea 1: Línea 1:
 +
-- ============================================================
 +
-- Diego F. Gómez -- 2024-2026
 +
-- Módulo de conjugación para verbos muysca en mediawiki
 +
-- ============================================================
 +
 +
 
local p = {}
 
local p = {}
  
-- 1. Limpieza y Normalización
+
-- ============================================================
 +
-- DICCIONARIO DE TEXTOS
 +
-- ============================================================
 +
local TEXTS = {
 +
    ui = {
 +
        expand = "Conjugar",
 +
        collapse = "Ocultar",
 +
        error_root = "Error: No se pudo extraer la raíz de ",
 +
        main_title = "Paradigma verbal: ",
 +
        col_person = "Persona"
 +
    },
 +
    series = {
 +
        s1 = {
 +
            title = "Serie de Flexión Verbal (Independiente)",
 +
            headers = {"Perfectivo", "Imperfectivo", "Irrealis"}
 +
        },
 +
        s2 = {
 +
            title = "Serie de Nominalización",
 +
            headers = {"Resultativa", "Factual", "Irrealis"}
 +
        }
 +
    },
 +
    persons = {
 +
        sg1 = "1.ª sg.", sg2 = "2.ª sg.", sg3 = "3.ª",
 +
        pl1 = "1.ª pl.", pl2 = "2.ª pl."
 +
    }
 +
}
 +
 
 +
-- ============================================================
 +
-- LÓGICA PRIVADA
 +
-- ============================================================
 +
 
 
local function cleanPageName(pageName)
 
local function cleanPageName(pageName)
 +
    if not mw then return pageName:gsub("%s*%b()", ""):gsub("%d+", ""):trim() end
 
     pageName = mw.text.trim(pageName or "")
 
     pageName = mw.text.trim(pageName or "")
 
     pageName = mw.ustring.gsub(pageName, "%s*%b()", "")
 
     pageName = mw.ustring.gsub(pageName, "%s*%b()", "")
Línea 10: Línea 47:
  
 
local function normalizeClass(rawClass)
 
local function normalizeClass(rawClass)
     rawClass = mw.text.trim(rawClass or "")
+
     rawClass = (rawClass or ""):lower()
    rawClass = mw.ustring.lower(rawClass)
+
     if rawClass:find("sq") then return "sq."
     if mw.ustring.find(rawClass, "sq") then return "sq."
+
     elseif rawClass:find("su") then return "su." end
     elseif mw.ustring.find(rawClass, "su") then return "su." end
 
 
     return ""
 
     return ""
 
end
 
end
  
 
local function getRoot(pageName, clase, manualRoot)
 
local function getRoot(pageName, clase, manualRoot)
     manualRoot = mw.text.trim(manualRoot or "")
+
     if manualRoot and manualRoot ~= "" then return manualRoot end
    if manualRoot ~= "" then return manualRoot end
 
 
     local fullVerb = cleanPageName(pageName)
 
     local fullVerb = cleanPageName(pageName)
 
     local root = fullVerb
 
     local root = fullVerb
     if clase == "sq." then root = mw.ustring.gsub(fullVerb, "squa$", "")
+
     if clase == "sq." then root = fullVerb:gsub("squa$", "")
     elseif clase == "su." then root = mw.ustring.gsub(fullVerb, "suca$", "") end
+
     elseif clase == "su." then root = fullVerb:gsub("suca$", "") end
     if root == fullVerb then root = mw.ustring.gsub(fullVerb, "s[uq]ua$", "") end
+
     if root == fullVerb then root = fullVerb:gsub("s[uq]ua$", "") end
 
     return root
 
     return root
 
end
 
end
  
-- 2. Función que genera la tabla con el título ARRIBA
+
-- ============================================================
local function generateTableHtml(title, root, persons, suffixes, applySpecialRule, colNames)
+
-- NUEVA LÓGICA DE CLASE (Parsing)
    local wrapper = mw.html.create("div")
+
-- ============================================================
        :css("margin-bottom", "1.5em")
 
        :css("font-size", "14px")
 
  
     -- Título encima de la tabla
+
local function parseVerbClass(raw)
     wrapper:tag("div")
+
     raw = (raw or ""):lower()
        :css("font-weight", "bold")
+
    local info = {
        :css("font-size", "1.1em")
+
        type = "",            -- "sq." o "su."
         :css("margin-bottom", "0.4em")
+
        isTransitive = false,
         :css("color", "#202122")
+
        isIntransitive = false,
        :wikitext(title)
+
        isQuy = false,
 +
        raw = raw
 +
    }
 +
   
 +
    if raw:find("sq") then info.type = "sq." end
 +
    if raw:find("su") then info.type = "su." end
 +
     if raw:find("tr%.") then info.isTransitive = true end
 +
    if raw:find("intr%.") then info.isIntransitive = true end
 +
    if raw:find("quy%.") then info.isQuy = true end
 +
   
 +
    return info
 +
end
 +
 
 +
-- ============================================================
 +
-- EL CEREBRO: Lógica Pura
 +
-- ============================================================
 +
 
 +
function p.getConjugations(pageName, claseRaw, manualRoot)
 +
    local classInfo = parseVerbClass(claseRaw)
 +
    local root = getRoot(pageName, classInfo, manualRoot)
 +
   
 +
    local results = { root = root, classInfo = classInfo, series = {} }
 +
 
 +
    -- Configuración de Series
 +
    local config = {
 +
        {
 +
            id = "S1", -- Flexión Verbal
 +
            title = TEXTS.series.s1.title,
 +
            headers = TEXTS.series.s1.headers,
 +
            persons = {{TEXTS.persons.sg1, "z-"}, {TEXTS.persons.sg2, "m-"}, {TEXTS.persons.sg3, "a-"}, {TEXTS.persons.pl1, "chi-"}, {TEXTS.persons.pl2, "mi-"}},
 +
            suffixes = {perf = "", imperf = (classInfo.type == "su." and "-suca" or "-squa"), irreal = "-nga"},
 +
            applyRule = true,
 +
            allowInfix = true  -- <--- Habilitar infijo -b-
 +
         },
 +
        {
 +
            id = "S2", -- Nominalización
 +
            title = TEXTS.series.s2.title,
 +
            headers = TEXTS.series.s2.headers,
 +
            persons = {{TEXTS.persons.sg1, "cha-"}, {TEXTS.persons.sg2, "ma-"}, {TEXTS.persons.sg3, ""}, {TEXTS.persons.pl1, "chi-"}, {TEXTS.persons.pl2, "mi-"}},
 +
            suffixes = {perf = "-ia", imperf = "-sca", irreal = "-nga"},
 +
            applyRule = false,
 +
            allowInfix = false -- <--- Prohibir infijo -b- en esta serie
 +
        }
 +
    }
 +
 
 +
    local firstChar = root:sub(1,1):lower()
 +
    local firstTwo = root:sub(1,2):lower()
 +
 
 +
    for _, s in ipairs(config) do
 +
         local serieData = { title = s.title, headers = s.headers, rows = {} }
 +
       
 +
        for _, pData in ipairs(s.persons) do
 +
            local label, prefix = pData[1], pData[2]
 +
           
 +
            -- 1. Regla Especial de Prefijo (z- -> i-)
 +
            if s.applyRule and label == TEXTS.persons.sg1 then
 +
                if firstChar == "n" or firstChar == "z" or firstChar == "t" or firstTwo == "ch" then
 +
                    prefix = "i-"
 +
                end
 +
            end
 +
 
 +
            -- 2. LÓGICA DEL INFIJO -b- Y CAMBIOS EN LA RAÍZ
 +
            local currentInfix = ""
 +
            local currentRoot = root -- Por defecto, la raíz no cambia
 +
           
 +
            if s.allowInfix and classInfo.isTransitive and not classInfo.isIntransitive then
 +
                if prefix ~= "" then
 +
                    local r1 = firstChar
 +
                    local r2 = firstTwo
 +
                   
 +
                    -- Regla: b + u = g + u (Ej: b-u-squa -> g-u-squa ; g-uity-suca -> g-uity-suca)
 +
                    if r1 == "u" then
 +
                        currentInfix = "g-"
  
    local html = wrapper:tag("table")
+
                    --NO BORRAR: Falta aquí una regla relacionada con la existencia de raices con vocales altas u, i, ɨ.
        :addClass("wikitable")
+
                   
        :css("width", "100%")
+
                    -- Regla: b + n = m + n
        :css("max-width", "600px")
+
                    elseif r1 == "n" then
        :css("margin", "0") -- Reset para que pegue al título
+
                        currentInfix = "m-"
 +
                       
 +
                    -- Regla: b + hV = mV + h (Ej: b-hize-suca -> mi-hize-suca)
 +
                    elseif r1 == "h" then
 +
                        local vocal = root:sub(2,2)
 +
                        currentInfix = "m" .. vocal .. "-"
 +
                        currentRoot = "h" .. root:sub(3)
 +
                       
 +
                    -- Regla: b + b = m + m (Ej: b-bahasy-suca -> m-mahasy-suca)
 +
                    elseif r1 == "b" then
 +
                        currentInfix = "m-"
 +
                        currentRoot = "m" .. root:sub(2)
  
    local header = html:tag("tr")
+
                    -- Reglas por defecto y asimilación por prefijo m-
    header:tag("th"):wikitext("Persona")
+
                    else
    header:tag("th"):wikitext(colNames[1])
+
                        if prefix == "m-" then
    header:tag("th"):wikitext(colNames[2])
+
                            currentInfix = "m-"
    header:tag("th"):wikitext(colNames[3])
+
                        else
 +
                            currentInfix = "b-"
 +
                        end
 +
                    end
 +
                end
 +
            end
  
    local firstChar = mw.ustring.lower(mw.ustring.sub(root, 1, 1))
+
            -- 3. LÓGICA DE VERBOS CON RAÍZ HISTÓRICA EN IQUY (-quy / -z / -i)
    local firstTwo = mw.ustring.lower(mw.ustring.sub(root, 1, 2))
+
            local perfSuffix = s.suffixes.perf
 +
            local imperfSuffix = s.suffixes.imperf
 +
            local irrealSuffix = s.suffixes.irreal
 +
           
 +
            local rootPerf = currentRoot
 +
            local rootImperf = currentRoot
 +
            local rootIrreal = currentRoot
  
    for _, personData in ipairs(persons) do
+
            if classInfo.isQuy then
        local label, prefix = personData[1], personData[2]
+
                if s.id == "S1" then
        if applySpecialRule and label == "1.ª sg." then
+
                    -- Serie de Flexión: Mantiene raíz u + sufijo quy
            if firstChar == "n" or firstChar == "z" or firstChar == "t" or firstTwo == "ch" then
+
                    perfSuffix = "quy"
                prefix = "i-"
+
                elseif s.id == "S2" then
 +
                    -- Serie de Nominalización: Preserva rasgos históricos
 +
                   
 +
                    -- A. Resultativa: Palatalización histórica (u -> uz) + alomorfo -a
 +
                    rootPerf = currentRoot .. "z"
 +
                    perfSuffix = "-a"
 +
                   
 +
                    -- B. Factual e Irrealis: Preserva la -i histórica (u -> ui)
 +
                    rootImperf = currentRoot .. "i"
 +
                    rootIrreal = currentRoot .. "i"
 +
                end
 
             end
 
             end
 +
 +
            table.insert(serieData.rows, {
 +
                label = label,
 +
                perf = prefix .. currentInfix .. rootPerf .. perfSuffix,
 +
                imperf = prefix .. currentInfix .. rootImperf .. imperfSuffix,
 +
                irreal = prefix .. currentInfix .. rootIrreal .. irrealSuffix
 +
            })
 +
 
         end
 
         end
         local row = html:tag("tr")
+
         table.insert(results.series, serieData)
        row:tag("td"):css("font-weight", "bold"):wikitext(label)
 
        row:tag("td"):wikitext(prefix .. root .. (suffixes.perf or ""))
 
        row:tag("td"):wikitext(prefix .. root .. (suffixes.imperf or ""))
 
        row:tag("td"):wikitext(prefix .. root .. (suffixes.irreal or ""))
 
 
     end
 
     end
 +
 +
    return results
 +
end
 +
 +
 +
-- ============================================================
 +
-- LA VISTA: Usado por la Wiki
 +
-- ============================================================
 +
 +
local function drawTable(serie)
 +
    local wrapper = mw.html.create("div"):css("margin-bottom", "1.5em"):css("font-size", "14px")
 +
 +
    wrapper:tag("div")
 +
        :css("font-weight", "bold"):css("font-size", "1.1em")
 +
        :css("margin-bottom", "0.4em"):css("color", "#202122")
 +
        :wikitext(serie.title)
 +
 +
    local tableHtml = wrapper:tag("table"):addClass("wikitable")
 +
        :css("width", "100%"):css("max-width", "600px"):css("margin", "0")
 +
 +
    local headerRow = tableHtml:tag("tr")
 +
    headerRow:tag("th"):wikitext(TEXTS.ui.col_person)
 +
    for _, hName in ipairs(serie.headers) do
 +
        headerRow:tag("th"):wikitext(hName)
 +
    end
 +
 +
    for _, row in ipairs(serie.rows) do
 +
        local tr = tableHtml:tag("tr")
 +
        tr:tag("td"):css("font-weight", "bold"):wikitext(row.label)
 +
        tr:tag("td"):wikitext(row.perf)
 +
        tr:tag("td"):wikitext(row.imperf)
 +
        tr:tag("td"):wikitext(row.irreal)
 +
    end
 +
 
     return wrapper
 
     return wrapper
 
end
 
end
  
-- FUNCIÓN PRINCIPAL
 
 
function p.render(frame)
 
function p.render(frame)
 
     local args = frame:getParent().args
 
     local args = frame:getParent().args
    local clase = normalizeClass(args.clase or args.tipo or "")
 
 
     local pageName = mw.title.getCurrentTitle().text
 
     local pageName = mw.title.getCurrentTitle().text
     local root = getRoot(pageName, clase, args.raiz or "")
+
     local data = p.getConjugations(pageName, args.clase or args.tipo, args.raiz)
  
     if root == "" or root == pageName then
+
     if data.root == "" or data.root == pageName then
         return "<span style='color:red;'>Error: No se pudo extraer la raíz.</span>"
+
         return "<span style='color:red;'>" .. TEXTS.ui.error_root .. pageName .. ".</span>"
 
     end
 
     end
  
    -- Definición de Series con tus traducciones
 
    local serie1 = {
 
        title = "Serie de Flexión Verbal (Independiente)",
 
        persons = {{"1.ª sg.", "z-"}, {"2.ª sg.", "m-"}, {"3.ª", "a-"}, {"1.ª pl.", "chi-"}, {"2.ª pl.", "mi-"}},
 
        suffixes = {perf = "", imperf = (clase == "su." and "-suca" or "-squa"), irreal = "-nga"},
 
        rule = true,
 
        cols = {"Perfectivo", "Imperfectivo", "Irrealis"}
 
    }
 
 
    local serie2 = {
 
        title = "Serie de Nominalización",
 
        persons = {{"1.ª sg.", "cha-"}, {"2.ª sg.", "ma-"}, {"3.ª", ""}, {"1.ª pl.", "chi-"}, {"2.ª pl.", "mi-"}},
 
        suffixes = {perf = "-ia", imperf = "-sca", irreal = "-nga"},
 
        rule = false,
 
        cols = {"Nominalización Resultativa", "Nominalización Factual", "Nominalización Irrealis"}
 
    }
 
 
    --- CONSTRUCCIÓN DEL CONTENEDOR COLAPSABLE ---
 
 
     local mainDiv = mw.html.create("div")
 
     local mainDiv = mw.html.create("div")
         :addClass("mw-collapsible")
+
         :addClass("mw-collapsible"):addClass("mw-collapsed")
        :addClass("mw-collapsed")
+
         :css("border", "1px solid #a2a9b1"):css("padding", "15px")
         :css("border", "1px solid #a2a9b1")
 
        :css("padding", "15px")
 
 
         :css("background-color", "#fcfcfc")
 
         :css("background-color", "#fcfcfc")
         :attr("data-expandtext", "Conjugar")
+
         :attr("data-expandtext", TEXTS.ui.expand)
         :attr("data-collapsetext", "Ocultar")
+
         :attr("data-collapsetext", TEXTS.ui.collapse)
  
    -- Encabezado del bloque colapsable (Título del verbo)
 
 
     mainDiv:tag("div")
 
     mainDiv:tag("div")
         :css("font-weight", "bold")
+
         :css("font-weight", "bold"):css("border-bottom", "1px solid #a2a9b1")
        :css("border-bottom", "1px solid #a2a9b1")
+
         :css("margin-bottom", "15px"):css("padding-bottom", "5px")
         :css("margin-bottom", "15px")
+
         :wikitext(TEXTS.ui.main_title .. data.root .. " (" .. data.clase .. ")")
        :css("padding-bottom", "5px")
 
         -- :wikitext("Paradigma de " .. root)
 
  
     local contentDiv = mainDiv:tag("div")
+
     local contentDiv = mainDiv:tag("div"):addClass("mw-collapsible-content")
        :addClass("mw-collapsible-content")
 
  
     -- Añadimos las tablas con los títulos arriba
+
     for _, serie in ipairs(data.series) do
    contentDiv:node(generateTableHtml(serie1.title, root, serie1.persons, serie1.suffixes, serie1.rule, serie1.cols))
+
        contentDiv:node(drawTable(serie))
    contentDiv:node(generateTableHtml(serie2.title, root, serie2.persons, serie2.suffixes, serie2.rule, serie2.cols))
+
    end
  
 
     return tostring(mainDiv)
 
     return tostring(mainDiv)

Revisión del 09:51 29 mar 2026

La documentación para este módulo puede ser creada en Módulo:Conjugador/doc

-- ============================================================
-- Diego F. Gómez -- 2024-2026
-- Módulo de conjugación para verbos muysca en mediawiki
-- ============================================================


local p = {}

-- ============================================================
-- DICCIONARIO DE TEXTOS 
-- ============================================================
local TEXTS = {
    ui = {
        expand = "Conjugar",
        collapse = "Ocultar",
        error_root = "Error: No se pudo extraer la raíz de ",
        main_title = "Paradigma verbal: ",
        col_person = "Persona"
    },
    series = {
        s1 = {
            title = "Serie de Flexión Verbal (Independiente)",
            headers = {"Perfectivo", "Imperfectivo", "Irrealis"}
        },
        s2 = {
            title = "Serie de Nominalización",
            headers = {"Resultativa", "Factual", "Irrealis"}
        }
    },
    persons = {
        sg1 = "1.ª sg.", sg2 = "2.ª sg.", sg3 = "3.ª",
        pl1 = "1.ª pl.", pl2 = "2.ª pl."
    }
}

-- ============================================================
-- LÓGICA PRIVADA
-- ============================================================

local function cleanPageName(pageName)
    if not mw then return pageName:gsub("%s*%b()", ""):gsub("%d+", ""):trim() end
    pageName = mw.text.trim(pageName or "")
    pageName = mw.ustring.gsub(pageName, "%s*%b()", "")
    pageName = mw.ustring.gsub(pageName, "%d+", "")
    return mw.text.trim(pageName)
end

local function normalizeClass(rawClass)
    rawClass = (rawClass or ""):lower()
    if rawClass:find("sq") then return "sq."
    elseif rawClass:find("su") then return "su." end
    return ""
end

local function getRoot(pageName, clase, manualRoot)
    if manualRoot and manualRoot ~= "" then return manualRoot end
    local fullVerb = cleanPageName(pageName)
    local root = fullVerb
    if clase == "sq." then root = fullVerb:gsub("squa$", "")
    elseif clase == "su." then root = fullVerb:gsub("suca$", "") end
    if root == fullVerb then root = fullVerb:gsub("s[uq]ua$", "") end
    return root
end

-- ============================================================
-- NUEVA LÓGICA DE CLASE (Parsing)
-- ============================================================

local function parseVerbClass(raw)
    raw = (raw or ""):lower()
    local info = {
        type = "",             -- "sq." o "su."
        isTransitive = false,
        isIntransitive = false,
        isQuy = false,
        raw = raw
    }
    
    if raw:find("sq") then info.type = "sq." end
    if raw:find("su") then info.type = "su." end
    if raw:find("tr%.") then info.isTransitive = true end
    if raw:find("intr%.") then info.isIntransitive = true end
    if raw:find("quy%.") then info.isQuy = true end
    
    return info
end

-- ============================================================
-- EL CEREBRO: Lógica Pura
-- ============================================================

function p.getConjugations(pageName, claseRaw, manualRoot)
    local classInfo = parseVerbClass(claseRaw)
    local root = getRoot(pageName, classInfo, manualRoot)
    
    local results = { root = root, classInfo = classInfo, series = {} }

    -- Configuración de Series
    local config = {
        {
            id = "S1", -- Flexión Verbal
            title = TEXTS.series.s1.title, 
            headers = TEXTS.series.s1.headers,
            persons = {{TEXTS.persons.sg1, "z-"}, {TEXTS.persons.sg2, "m-"}, {TEXTS.persons.sg3, "a-"}, {TEXTS.persons.pl1, "chi-"}, {TEXTS.persons.pl2, "mi-"}},
            suffixes = {perf = "", imperf = (classInfo.type == "su." and "-suca" or "-squa"), irreal = "-nga"},
            applyRule = true,
            allowInfix = true  -- <--- Habilitar infijo -b-
        },
        {
            id = "S2", -- Nominalización
            title = TEXTS.series.s2.title, 
            headers = TEXTS.series.s2.headers,
            persons = {{TEXTS.persons.sg1, "cha-"}, {TEXTS.persons.sg2, "ma-"}, {TEXTS.persons.sg3, ""}, {TEXTS.persons.pl1, "chi-"}, {TEXTS.persons.pl2, "mi-"}},
            suffixes = {perf = "-ia", imperf = "-sca", irreal = "-nga"},
            applyRule = false,
            allowInfix = false -- <--- Prohibir infijo -b- en esta serie
        }
    }

    local firstChar = root:sub(1,1):lower()
    local firstTwo = root:sub(1,2):lower()

    for _, s in ipairs(config) do
        local serieData = { title = s.title, headers = s.headers, rows = {} }
        
        for _, pData in ipairs(s.persons) do
            local label, prefix = pData[1], pData[2]
            
            -- 1. Regla Especial de Prefijo (z- -> i-)
            if s.applyRule and label == TEXTS.persons.sg1 then
                if firstChar == "n" or firstChar == "z" or firstChar == "t" or firstTwo == "ch" then
                    prefix = "i-"
                end
            end

            -- 2. LÓGICA DEL INFIJO -b- Y CAMBIOS EN LA RAÍZ
            local currentInfix = ""
            local currentRoot = root -- Por defecto, la raíz no cambia
            
            if s.allowInfix and classInfo.isTransitive and not classInfo.isIntransitive then
                if prefix ~= "" then
                    local r1 = firstChar
                    local r2 = firstTwo
                    
                    -- Regla: b + u = g + u (Ej: b-u-squa -> g-u-squa ; g-uity-suca -> g-uity-suca)
                    if r1 == "u" then
                        currentInfix = "g-"

                    --NO BORRAR: Falta aquí una regla relacionada con la existencia de raices con vocales altas u, i, ɨ.
                    
                    -- Regla: b + n = m + n
                    elseif r1 == "n" then
                        currentInfix = "m-"
                        
                    -- Regla: b + hV = mV + h (Ej: b-hize-suca -> mi-hize-suca)
                    elseif r1 == "h" then
                        local vocal = root:sub(2,2)
                        currentInfix = "m" .. vocal .. "-"
                        currentRoot = "h" .. root:sub(3)
                        
                    -- Regla: b + b = m + m (Ej: b-bahasy-suca -> m-mahasy-suca)
                    elseif r1 == "b" then
                        currentInfix = "m-"
                        currentRoot = "m" .. root:sub(2)

                    -- Reglas por defecto y asimilación por prefijo m-
                    else
                        if prefix == "m-" then
                            currentInfix = "m-"
                        else
                            currentInfix = "b-"
                        end
                    end
                end
            end

            -- 3. LÓGICA DE VERBOS CON RAÍZ HISTÓRICA EN IQUY (-quy / -z / -i)
            local perfSuffix = s.suffixes.perf
            local imperfSuffix = s.suffixes.imperf
            local irrealSuffix = s.suffixes.irreal
            
            local rootPerf = currentRoot
            local rootImperf = currentRoot
            local rootIrreal = currentRoot

            if classInfo.isQuy then
                if s.id == "S1" then
                    -- Serie de Flexión: Mantiene raíz u + sufijo quy
                    perfSuffix = "quy"
                elseif s.id == "S2" then
                    -- Serie de Nominalización: Preserva rasgos históricos
                    
                    -- A. Resultativa: Palatalización histórica (u -> uz) + alomorfo -a
                    rootPerf = currentRoot .. "z"
                    perfSuffix = "-a"
                    
                    -- B. Factual e Irrealis: Preserva la -i histórica (u -> ui)
                    rootImperf = currentRoot .. "i"
                    rootIrreal = currentRoot .. "i"
                end
            end

            table.insert(serieData.rows, {
                label = label,
                perf = prefix .. currentInfix .. rootPerf .. perfSuffix,
                imperf = prefix .. currentInfix .. rootImperf .. imperfSuffix,
                irreal = prefix .. currentInfix .. rootIrreal .. irrealSuffix
            })

        end
        table.insert(results.series, serieData)
    end

    return results
end


-- ============================================================
-- LA VISTA: Usado por la Wiki
-- ============================================================

local function drawTable(serie)
    local wrapper = mw.html.create("div"):css("margin-bottom", "1.5em"):css("font-size", "14px")

    wrapper:tag("div")
        :css("font-weight", "bold"):css("font-size", "1.1em")
        :css("margin-bottom", "0.4em"):css("color", "#202122")
        :wikitext(serie.title)

    local tableHtml = wrapper:tag("table"):addClass("wikitable")
        :css("width", "100%"):css("max-width", "600px"):css("margin", "0")

    local headerRow = tableHtml:tag("tr")
    headerRow:tag("th"):wikitext(TEXTS.ui.col_person)
    for _, hName in ipairs(serie.headers) do
        headerRow:tag("th"):wikitext(hName)
    end

    for _, row in ipairs(serie.rows) do
        local tr = tableHtml:tag("tr")
        tr:tag("td"):css("font-weight", "bold"):wikitext(row.label)
        tr:tag("td"):wikitext(row.perf)
        tr:tag("td"):wikitext(row.imperf)
        tr:tag("td"):wikitext(row.irreal)
    end

    return wrapper
end

function p.render(frame)
    local args = frame:getParent().args
    local pageName = mw.title.getCurrentTitle().text
    local data = p.getConjugations(pageName, args.clase or args.tipo, args.raiz)

    if data.root == "" or data.root == pageName then
        return "<span style='color:red;'>" .. TEXTS.ui.error_root .. pageName .. ".</span>"
    end

    local mainDiv = mw.html.create("div")
        :addClass("mw-collapsible"):addClass("mw-collapsed")
        :css("border", "1px solid #a2a9b1"):css("padding", "15px")
        :css("background-color", "#fcfcfc")
        :attr("data-expandtext", TEXTS.ui.expand)
        :attr("data-collapsetext", TEXTS.ui.collapse)

    mainDiv:tag("div")
        :css("font-weight", "bold"):css("border-bottom", "1px solid #a2a9b1")
        :css("margin-bottom", "15px"):css("padding-bottom", "5px")
        :wikitext(TEXTS.ui.main_title .. data.root .. " (" .. data.clase .. ")")

    local contentDiv = mainDiv:tag("div"):addClass("mw-collapsible-content")

    for _, serie in ipairs(data.series) do
        contentDiv:node(drawTable(serie))
    end

    return tostring(mainDiv)
end

return p