Module:User:Saam-andar/fa-headword

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


-- Credit: Fenakhay for base of the module, adjectives, and verb functions
-- Saam-andar for nouns function and expansion of adjectives and verbs
-- Also Theknightwho and Benwing2

local lang = require("Module:languages").getByCode("fa")
local fa_cls = require("Module:fa-cls-translit")
local fa_ira = require("Module:fa-translit")
local m_parameters = require("Module:parameters")

local export = {}
local pos_functions = {}

local u = mw.ustring.char
local unpack = unpack or table.unpack -- Lua 5.2 compatibility

-- Diacritics
local A = u(0x064E) -- fatha/fathe
local AN = u(0x064B) -- fatHatan (tanwīn-i fatha or nasb/tanvin-e fathe or nasb)
local U = u(0x064F) -- zamma/zamme
local I = u(0x0650) -- kasra/kasre
local SK = u(0x0652) -- sukūn/sokun
local SH = u(0x0651) -- šadda/tašdid

-----------------------
-- Utility functions --
-----------------------

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

-- Tracking functions
local trackfn = require("Module:debug/track")

local function track(page)
    trackfn("fa-headword/" .. page)
    return true
end

-- Clean up translit strings by removing HTML spans and normalizing
local function clean_translit(tr)
    if not tr then return nil end
    -- Remove HTML spans that might be added by {{fa-xlit}}
    tr = rsub(tr, "</?span*>", "")
    -- Normalize whitespace around separators
    tr = rsub(tr, "%s*/%s*", " / ")
    tr = rsub(tr, "%s*<i>or</i>%s*", " <i>or</i> ")
    tr = mw.text.trim(tr)
    return tr ~= "" and tr or nil
end

-- Check if a parameter is disabled (set to "-" or similar)
local function is_disabled(param)
    return param == "-" or param == "—" or param == "–"
end

function export.ZWNJ(word)
    word = mw.ustring.gsub(word, "+$", "")
    if mw.ustring.match(word, "", -1) then
        return "\226\128\140" -- U+200C
    end
    return ""
end

-- Define parameter specifications
local function get_param_spec(poscat)
    local base_params = {
         = {},
         = {list = true, allow_holes = true},
         = {},
         = {},
         = {list = true, allow_holes = true},
         = {list = true, allow_holes = true},
         = {list = true, allow_holes = true},
         = {list = true, allow_holes = true},
         = {list = true, allow_holes = true},
         = {type = "boolean"},
    }
    
    -- Add qualifier parameters for Tajik forms
    for i = 1, 4 do
        base_params = {}
    end
    
    if poscat == "nouns" then
        base_params = {list = true, allow_holes = true}
        base_params = {list = true, allow_holes = true}
        
        for i = 1, 4 do
            local base_key = "pl" .. (i == 1 and "" or tostring(i))
            base_params = {}
            base_params = {}
            for j = 2, 3 do
                base_params = {}
            end
        end
        
    elseif poscat == "verbs" then
        base_params = {list = true, allow_holes = true}
        base_params = {list = true, allow_holes = true}
        base_params = {list = true, allow_holes = true}
        
        for i = 1, 3 do
            local stem_key = "prstem" .. tostring(i)
            base_params = {}
            base_params = {}
            base_params = {}
        end
        
    elseif poscat == "adjectives" then
        base_params = {}
        base_params = {}
        base_params = {}
    end
    
    return base_params
end

-- Process transliterations for heads or forms
local function process_translits(forms, cls_list, ir_list, tr_list)
    local results = {}
    
    for i = 1, #forms do
        local tr_overrides = {}
        for j = 1, 3 do
            local tr = tr_list
            if tr and tr ~= "" then
                table.insert(tr_overrides, tr)
            end
        end

        local cls_filtered, ira_filtered = {}, {}
        for j = 1, 3 do
            if not (tr_list and tr_list ~= "") then
                if cls_list and cls_list ~= "" then
                    table.insert(cls_filtered, cls_list)
                end
                if ir_list and ir_list ~= "" then
                    table.insert(ira_filtered, ir_list)
                end
            end
        end

        local cls_str = table.concat(cls_filtered, ", ")
        local ira_str = table.concat(ira_filtered, ", ")

        local base_tr = ""
        if cls_str ~= "" and ira_str ~= "" then
            base_tr = (cls_str == ira_str) and cls_str or (cls_str .. " / " .. ira_str)
        elseif cls_str ~= "" then
            base_tr = cls_str
        elseif ira_str ~= "" then
            base_tr = ira_str
        end

        local final_tr = base_tr
        if #tr_overrides > 0 then
            local overrides_str = table.concat(tr_overrides, " <i>or</i> ")
            final_tr = (final_tr ~= "") and (final_tr .. " <i>or</i> " .. overrides_str) or overrides_str
        end

        results = final_tr
    end
    
    return results
end

-- The main entry point.
function export.show(frame)
    local PAGENAME = mw.loadData("Module:headword/data").pagename
    local poscat = frame.args or error(
        "Part of speech has not been specified. Please pass parameter 1 to the module invocation.")

    local params = get_param_spec(poscat)
    local args = m_parameters.process(frame:getParent().args, params)

    -- Gather parameters
    local data = {
        lang = lang,
        pos_category = poscat,
        categories = {},
        heads = {},
        translits = {},
        inflections = {},
        id = args,
        sort_key = args,
        nomultiwordcat = args
    }

    -- Process heads
    local heads = {}
    if args then
        for i, head in ipairs(args) do
            if head then
                table.insert(heads, head)
            end
        end
    elseif args then
        table.insert(heads, args)
    else
        table.insert(heads, PAGENAME)
    end
    
    if #heads == 0 then
        heads = {PAGENAME}
    end

    -- Process head transliterations
    local cls_list = {}
    local ir_list = {}
    local tr_list = {}

    for i = 1, math.max(#heads, 3) do
        local cls_raw = args
        local ir_raw = args
        local tr = clean_translit(args)

        local cls_tr = cls_raw and fa_cls.tr(cls_raw) or ""
        local ir_tr = ""
        
        -- Check if IR is disabled for this index
        if ir_raw and not is_disabled(ir_raw) then
            ir_tr = fa_ira.IRA_tr(ir_raw) or ""
        elseif not ir_raw and cls_raw and not is_disabled(args) then
            ir_tr = fa_ira.IRA_tr(cls_raw) or ""
        end

        cls_list = cls_tr
        ir_list = ir_tr
        tr_list = tr
    end

    if #heads == 1 then
        -- Single head: combine all transliterations
        local translits = process_translits(heads, cls_list, ir_list, tr_list)
        data.heads = heads
        data.translits = translits
    else
        -- Multiple heads: assign translit to head
        data.heads = heads
        for i = 1, #heads do
            local tr = tr_list
            if tr and tr ~= "" then
                data.translits = tr
            else
                local cls_tr = cls_list or ""
                local ir_tr = ir_list or ""
                if cls_tr ~= "" and ir_tr ~= "" then
                    data.translits = (cls_tr == ir_tr) and cls_tr or (cls_tr .. " / " .. ir_tr)
                else
                    data.translits = cls_tr .. ir_tr
                end
            end
        end
    end

    data.no_redundant_head_cat = (#heads > 1)

    -- Call POS-specific function
    if pos_functions then
        pos_functions.func(args, data)
    end

    return require("Module:headword").full_headword(data)
end

-- Helper function to add Tajik forms
local function add_tajik_forms(args, data)
    for i = 1, 3 do
        local cls = args
        local tg = args
        local tgq = args or args

        if not is_disabled(tg) then
            if not tg and cls then
                tg = require("Module:tg-Latn-Cyrl-translit").tr(fa_cls.tr(cls))
            end
            if tg then
                local label = (i == 1 and "Tajik spelling" or "<i>or</i>")
                if tgq then
                    label = label .. " <span style=\"font-style: italic;\">(" .. tgq .. ")</span>"
                end
                table.insert(data.inflections, {
                    label = label,
                    { term = tg, lang = require("Module:languages").getByCode("tg") }
                })
            end
        end
    end
end

-- Generate automatic plural transliteration
local function generate_auto_plural_translit(base, base_zwnj, plural, cls_list, ir_list)
    local suffix_map = {
         = {base_zwnj ~= "" and "-hā" or "hā", base_zwnj ~= "" and "-hâ" or "hâ"},
         = {"āt", "ât"}, 
         = {"ān", "ân"},
         = {"yān", "yân"}
    }
    
    -- Check if base ends in vowel ی
    local base_is_vowel_ye = false
    if mw.ustring.match(base, "ی$") then
        for j = 1, 3 do
            local cls_tr = cls_list
            local ir_tr = ir_list
            if cls_tr and mw.ustring.match(cls_tr, "$") then
                base_is_vowel_ye = true
                break
            end
            if ir_tr and mw.ustring.match(ir_tr, "i$") then
                base_is_vowel_ye = true
                break
            end
        end
    end
    
    -- Determine applied suffix
    local applied_suffix
    if base_is_vowel_ye and mw.ustring.match(plural, "یان$") then
        if plural == base .. "ان" or plural == base .. base_zwnj .. "ان" then
            applied_suffix = "یان"
        end
    end
    
    if not applied_suffix then
        for suffix, _ in pairs(suffix_map) do
            if plural == base .. suffix or plural == base .. base_zwnj .. suffix then
                applied_suffix = suffix
                break
            end
        end
    end
    
    if not applied_suffix or not suffix_map then
        return nil
    end
    
    local cls_suffix = suffix_map
    local ir_suffix = suffix_map
    
    local cls_tr_list = {}
    local ir_tr_list = {}
    
    for j = 1, 3 do
        local cls_tr = cls_list
        local ir_tr = ir_list
        
        if cls_tr and cls_tr ~= "" then
            local final_cls_suffix = cls_suffix
            if applied_suffix == "یان" and mw.ustring.match(cls_tr, "$") then
                final_cls_suffix = "yān"
            end
            table.insert(cls_tr_list, cls_tr .. final_cls_suffix)
        end
        
        if ir_tr and ir_tr ~= "" then
            local final_ir_suffix = ir_suffix
            if applied_suffix == "یان" and mw.ustring.match(ir_tr, "i$") then
                final_ir_suffix = "yân"
            end
            table.insert(ir_tr_list, ir_tr .. final_ir_suffix)
        end
    end
    
    local cls_str = table.concat(cls_tr_list, ", ")
    local ir_str = table.concat(ir_tr_list, ", ")
    
    if cls_str ~= "" and ir_str ~= "" then
        return (cls_str == ir_str) and cls_str or (cls_str .. " / " .. ir_str)
    elseif cls_str ~= "" then
        return cls_str
    elseif ir_str ~= "" then
        return ir_str
    end
    
    return nil
end

pos_functions = {
    func = function(args, data)
        data.pos_category = "nouns"

        for i = 1, 4 do
            local pl = args
            if not pl then break end
            
            local plq = (args and args) or args
            
            local tr_variants = {}
            
            -- Main translit parameter
            local main_tr_key = "pl" .. (i == 1 and "" or tostring(i)) .. "tr"
            local main_tr = clean_translit(args)
            
            local alt_tr2 = clean_translit(args)
            local alt_tr3 = clean_translit(args)
            
            local base = data.heads
            local base_zwnj = export.ZWNJ(base)
            
            -- Get head transliterations
            local cls_list = {}
            local ir_list = {}
            for j = 1, 3 do
                local cls_raw = args
                local ir_raw = args
                
                if cls_raw then
                    cls_list = fa_cls.tr(cls_raw) or ""
                end
                
                if ir_raw and not is_disabled(ir_raw) then
                    ir_list = fa_ira.IRA_tr(ir_raw) or ""
                elseif not ir_raw and cls_raw then
                    ir_list = fa_ira.IRA_tr(cls_raw) or ""
                end
            end
            
            local auto_tr = generate_auto_plural_translit(base, base_zwnj, pl, cls_list, ir_list)
            if auto_tr then
                table.insert(tr_variants, auto_tr)
            end
            
            if main_tr and not auto_tr then
                table.insert(tr_variants, main_tr)
            end
            
            if alt_tr2 then
                table.insert(tr_variants, alt_tr2)
            end
            if alt_tr3 then
                table.insert(tr_variants, alt_tr3)
            end
            
            local final_tr = (#tr_variants > 0) and table.concat(tr_variants, " <i>or</i> ") or nil
            
            local label = (i == 1 and "plural" or "<i>or</i>")
            if plq then
                label = label .. " <span style=\"font-style: italic;\">(" .. plq .. ")</span>"
            end
            
            table.insert(data.inflections, {
                label = label,
                {term = pl, translit = final_tr}
            })
        end

        -- Add Tajik forms
        add_tajik_forms(args, data)
    end
}

pos_functions = {
    func = function(args, data)
        data.pos_category = "verbs"
        
        local prstems = {}
        for i = 1, 3 do
            local stem = args
            if stem then
                table.insert(prstems, stem)
            end
        end
        
        if #prstems > 0 then
            for i, stem in ipairs(prstems) do
                local prstemq = (args and args) or args
                local tr = clean_translit((args and args) or args)
                
                local label = (i == 1 and "present stem" or "<i>or</i>")
                if prstemq then
                    label = label .. " <span style=\"font-style: italic;\">(" .. prstemq .. ")</span>"
                end
                
                table.insert(data.inflections, {
                    label = label,
                    {term = stem, translit = tr}
                })
            end
        end
        
        -- Add Tajik forms
        add_tajik_forms(args, data)
    end
}

pos_functions = {
    func = function(args, data)
        data.pos_category = "adjectives"
        local word = data.heads
        local zwnj = export.ZWNJ(word)

        -- Handle comparative/superlative
        if args == "+" then
            local cmp_forms = {{term = word .. zwnj .. "ت" .. A .. "ر"}}
            local sup_forms = {{term = word .. zwnj .. "ت" .. A .. "رین"}}
            
            -- Handle alternative stem
            if args then
                local alt = args
                local alt_zwnj = (args ~= "-") and export.ZWNJ(alt) or ""
                
                local tr_cls = fa_cls.tr(alt) or ""
                local tr_ir = fa_ira.IRA_tr(alt) or ""
                
                local cls_suffix_cmp = alt_zwnj ~= "" and "-tar" or "tar"
                local cls_suffix_sup = alt_zwnj ~= "" and "-tarīn" or "tarīn"
                local ir_suffix_cmp = alt_zwnj ~= "" and "-tar" or "tar"
                local ir_suffix_sup = alt_zwnj ~= "" and "-tarin" or "tarin"
                
                local function combine_translit(cls, ira, cls_suffix, ir_suffix)
                    if cls == ira or ira == "" then
                        return cls .. cls_suffix
                    elseif cls == "" then
                        return ira .. ir_suffix
                    else
                        return cls .. cls_suffix .. " / " .. ira .. ir_suffix
                    end
                end
                
                local tr_cmp = combine_translit(tr_cls, tr_ir, cls_suffix_cmp, ir_suffix_cmp)
                local tr_sup = combine_translit(tr_cls, tr_ir, cls_suffix_sup, ir_suffix_sup)
                
                table.insert(cmp_forms, {
                    term = alt .. alt_zwnj .. "ت" .. A .. "ر",
                    translit = tr_cmp
                })
                table.insert(sup_forms, {
                    term = alt .. alt_zwnj .. "ت" .. A .. "رین",
                    translit = tr_sup
                })
            end
            
            table.insert(data.inflections, {
                label = "comparative",
                accel = {form = "comparative"},
                unpack(cmp_forms)
            })
            
            table.insert(data.inflections, {
                label = "superlative", 
                accel = {form = "superlative"},
                unpack(sup_forms)
            })
        end

        -- Add Tajik forms
        add_tajik_forms(args, data)
    end
}

return export