Documentation for this module may be created at Модул:ru-adjective/doc

--[=[
    Модули мазкур дар вазифаҳои барои ташкили мизњои оҳанги барои Забони русӣ.

    Далелҳоро:
        1: рақами намунаи стресс
        2: поя
        3: навъи хам карданӣ (одатан танҳо аз хотимаи)
        4: пасванд шакл камтар (интихобан, нобаёнӣ = бунёдӣ)

    Истилоњот парвандаи:
        nom: неизборенӣ
        gen: родителенӣ
        dat: дателнӣ
        acc: винителнӣ
        ins: олатбобӣ
        pre: пешояндӣ
        par: партитивӣ
        loc: локативӣ
        voc: вокативӣ
]=]--

local m_utilities = require("Module:utilities")
local m_links = require("Module:links")
local com = require("Module:ru-common")
local strutils = require("Module:string utilities")

local export = {}

local lang = require("Module:languages").getByCode("ru")

local declensions = {}
local decline = nil

local velar = {
    ["г"] = true,
    ["к"] = true,
    ["х"] = true,
}

-- The main entry point.
-- This is the only function that can be invoked from a template.
function export.show(frame)
    local args = frame:getParent().args
    PAGENAME = mw.title.getCurrentTitle().text
    SUBPAGENAME = mw.title.getCurrentTitle().subpageText
    NAMESPACE = mw.title.getCurrentTitle().nsText

    local declension_type = args[2]
    local short_forms_allowed = declension_type == "ый" or declension_type == "ой" or declension_type == "ий"
    args[3] = (args[3] ~= "") and args[3] or (not short_forms_allowed and args[1]) or nil
    args[0] = com.make_unstressed_once(args[1])
    args[2] = args[3] and com.make_unstressed_once(args[3])

    args["hint"] = mw.ustring.sub(args[1], -1)
    if velar[args["hint"]] and declension_type == "ий" then
        declension_type = "ый"
    end

    decline(args, declensions[declension_type], declension_type == "ой", short_forms_allowed)

    return make_table(args)
end

declensions["ый"] = {
    ["nom_m"] = "ый",
    ["nom_n"] = "ое",
    ["nom_f"] = "ая",
    ["nom_p"] = "ые",
    ["gen_m"] = "ого",
    ["gen_f"] = "ой",
    ["gen_p"] = "ых",
    ["dat_m"] = "ому",
    ["dat_f"] = "ой",
    ["dat_p"] = "ым",
    ["acc_f"] = "ую",
    ["acc_n"] = "ое",
    ["ins_m"] = "ым",
    ["ins_f"] = {"ой", "ою"},
    ["ins_p"] = "ыми",
    ["pre_m"] = "ом",
    ["pre_f"] = "ой",
    ["pre_p"] = "ых",
}

declensions["ий"] = {
    ["nom_m"] = "ий",
    ["nom_n"] = "ее",
    ["nom_f"] = "яя",
    ["nom_p"] = "ие",
    ["gen_m"] = "его",
    ["gen_f"] = "ей",
    ["gen_p"] = "их",
    ["dat_m"] = "ему",
    ["dat_f"] = "ей",
    ["dat_p"] = "им",
    ["acc_f"] = "юю",
    ["acc_n"] = "ее",
    ["ins_m"] = "им",
    ["ins_f"] = {"ей", "ею"},
    ["ins_p"] = "ими",
    ["pre_m"] = "ем",
    ["pre_f"] = "ей",
    ["pre_p"] = "их",
}

declensions["ой"] = {
    ["nom_m"] = "о́й",
    ["nom_n"] = "о́е",
    ["nom_f"] = "а́я",
    ["nom_p"] = "ы́е",
    ["gen_m"] = "о́го",
    ["gen_f"] = "о́й",
    ["gen_p"] = "ы́х",
    ["dat_m"] = "о́му",
    ["dat_f"] = "о́й",
    ["dat_p"] = "ы́м",
    ["acc_f"] = "у́ю",
    ["acc_n"] = "о́е",
    ["ins_m"] = "ы́м",
    ["ins_f"] = {"о́й", "о́ю"},
    ["ins_p"] = "ы́ми",
    ["pre_m"] = "о́м",
    ["pre_f"] = "о́й",
    ["pre_p"] = "ы́х",
}

declensions["ьий"] = {
    ["nom_m"] = "ий",
    ["nom_n"] = "ье",
    ["nom_f"] = "ья",
    ["nom_p"] = "ьи",
    ["gen_m"] = "ьего",
    ["gen_f"] = "ьей",
    ["gen_p"] = "ьих",
    ["dat_m"] = "ьему",
    ["dat_f"] = "ьей",
    ["dat_p"] = "ьим",
    ["acc_f"] = "ью",
    ["acc_n"] = "ье",
    ["ins_m"] = "ьим",
    ["ins_f"] = {"ьей", "ьею"},
    ["ins_p"] = "ьими",
    ["pre_m"] = "ьем",
    ["pre_f"] = "ьей",
    ["pre_p"] = "ьих",
}

declensions["short"] = {
    ["nom_m"] = "",
    ["nom_n"] = "о",
    ["nom_f"] = "а",
    ["nom_p"] = "ы",
    ["gen_m"] = "а",
    ["gen_f"] = "ой",
    ["gen_p"] = "ых",
    ["dat_m"] = "у",
    ["dat_f"] = "ой",
    ["dat_p"] = "ым",
    ["acc_f"] = "у",
    ["acc_n"] = "о",
    ["ins_m"] = "ым",
    ["ins_f"] = {"ой", "ою"},
    ["ins_p"] = "ыми",
    ["pre_m"] = "ом",
    ["pre_f"] = "ой",
    ["pre_p"] = "ых",
}

declensions["mixed"] = {
    ["nom_m"] = "",
    ["nom_n"] = "о",
    ["nom_f"] = "а",
    ["nom_p"] = "ы",
    ["gen_m"] = "ого",
    ["gen_f"] = "ой",
    ["gen_p"] = "ых",
    ["dat_m"] = "ому",
    ["dat_f"] = "ой",
    ["dat_p"] = "ым",
    ["acc_f"] = "у",
    ["acc_n"] = "о",
    ["ins_m"] = "ым",
    ["ins_f"] = {"ой", "ою"},
    ["ins_p"] = "ыми",
    ["pre_m"] = "ом",
    ["pre_f"] = "ой",
    ["pre_p"] = "ых",
}

local stressed_sibilant_rules = {
    ["я"] = "а",
    ["ы"] = "и",
    ["ё"] = "о́",
    ["ю"] = "у",
}

local stressed_c_rules = {
    ["я"] = "а",
    ["ё"] = "о́",
    ["ю"] = "у",
}

local unstressed_sibilant_rules = {
    ["я"] = "а",
    ["ы"] = "и",
    ["о"] = "е",
    ["ю"] = "у",
}

local unstressed_c_rules = {
    ["я"] = "а",
    ["о"] = "е",
    ["ю"] = "у",
}

local velar_rules = {
    ["ы"] = "и",
}

local stressed_rules = {
    ["ш"] = stressed_sibilant_rules,
    ["щ"] = stressed_sibilant_rules,
    ["ч"] = stressed_sibilant_rules,
    ["ж"] = stressed_sibilant_rules,
    ["ц"] = stressed_c_rules,
    ["к"] = velar_rules,
    ["г"] = velar_rules,
    ["х"] = velar_rules,
}

local unstressed_rules = {
    ["ш"] = unstressed_sibilant_rules,
    ["щ"] = unstressed_sibilant_rules,
    ["ч"] = unstressed_sibilant_rules,
    ["ж"] = unstressed_sibilant_rules,
    ["ц"] = unstressed_c_rules,
    ["к"] = velar_rules,
    ["г"] = velar_rules,
    ["х"] = velar_rules,
}

local consonantal_suffixes = {
    [""] = true,
    ["ь"] = true,
    ["й"] = true,
}

local function attach_unstressed(args, suf)
    if suf == nil then
        return nil
    elseif consonantal_suffixes[suf] then
        if mw.ustring.find(args[3], "[йь]$") then
            return args[3]
        else
            if suf == "й" or suf == "ь" then
                if mw.ustring.find(args[3], "[аеёиіоуэюяѣ́]$") then
                    suf = "й"
                else
                    suf = "ь"
                end
            end
            return args[3] .. suf
        end
    end
    suf = com.make_unstressed(suf)
    local first = mw.ustring.sub(suf, 1, 1)
    local rules = unstressed_rules[args["hint"]]
    if rules then
        local conv = rules[first]
        if conv then
            suf = conv .. mw.ustring.sub(suf, 2)
        end
    end
    return args[1] .. suf
end

local function attach_stressed(args, suf)
    if suf == nil then
        return nil
    elseif not mw.ustring.find(suf, "[ё́]") then -- if suf has no "ё" or accent marks
        return attach_unstressed(args, suf)
    end
    local first = mw.ustring.sub(suf, 1, 1)
    local rules = stressed_rules[args["hint"]]
    if rules then
        local conv = rules[first]
        if conv then
            suf = conv .. mw.ustring.sub(suf, 2)
        end
    end
    return args[0] .. suf
end

local function attach_with(args, suf, fun)
    if type(suf) == "table" then
        local tbl = {}
        for _, x in ipairs(suf) do
            table.insert(tbl, attach_with(args, x, fun))
        end
        return tbl
    else
        return fun(args, suf)
    end
end

local function gen_form(args, decl, case, fun)
    args[case] = (args[case] ~= "") and args[case] or attach_with(args, decl[case], fun)
end

decline = function(args, decl, stressed, short_forms_allowed)
    local attacher = stressed and attach_stressed or attach_unstressed
    gen_form(args, decl, "nom_m", attacher)
    gen_form(args, decl, "nom_n", attacher)
    gen_form(args, decl, "nom_f", attacher)
    gen_form(args, decl, "nom_p", attacher)
    gen_form(args, decl, "gen_m", attacher)
    gen_form(args, decl, "gen_f", attacher)
    gen_form(args, decl, "gen_p", attacher)
    gen_form(args, decl, "dat_m", attacher)
    gen_form(args, decl, "dat_f", attacher)
    gen_form(args, decl, "dat_p", attacher)
    gen_form(args, decl, "acc_f", attacher)
    gen_form(args, decl, "acc_n", attacher)
    gen_form(args, decl, "ins_m", attacher)
    gen_form(args, decl, "ins_f", attacher)
    gen_form(args, decl, "ins_p", attacher)
    gen_form(args, decl, "pre_m", attacher)
    gen_form(args, decl, "pre_f", attacher)
    gen_form(args, decl, "pre_p", attacher)
    if short_forms_allowed then
        args["short_m"] = args["short_m"] or (args[3] ~= "" and args[3]) or nil
        args["short_n"] = args["short_n"] or (args[4] ~= "" and args[4]) or nil
        args["short_f"] = args["short_f"] or (args[5] ~= "" and args[5]) or nil
        args["short_p"] = args["short_p"] or (args[6] ~= "" and args[6]) or nil
    else
        args["short_m"] = nil
        args["short_n"] = nil
        args["short_f"] = nil
        args["short_p"] = nil
    end

end

local form_temp = [=[{term}<br/><span style="color: #888">{tr}</span>]=]
local title_temp = [=[Declension of <b lang="ru" class="Cyrl">{lemma}</b>]=]

local template = nil
local short_clause = nil

local cases = {
    ["nom_m"] = true,
    ["nom_n"] = true,
    ["nom_f"] = true,
    ["nom_p"] = true,
    ["gen_m"] = true,
    ["gen_f"] = true,
    ["gen_p"] = true,
    ["dat_m"] = true,
    ["dat_f"] = true,
    ["dat_p"] = true,
    ["acc_f"] = true,
    ["acc_n"] = true,
    ["ins_m"] = true,
    ["ins_f"] = true,
    ["ins_p"] = true,
    ["pre_m"] = true,
    ["pre_f"] = true,
    ["pre_p"] = true,
    ["short_m"] = true,
    ["short_n"] = true,
    ["short_f"] = true,
    ["short_p"] = true,
}

-- Make the table
function make_table(args)
    args["lemma"] = args["nom_m"]
    args["title"] = (args["title"] ~= "") and args["title"] or strutils.format(title_temp, args)

    for case in pairs(cases) do
        if args[case] == "-" then
            args[case] = "&mdash;"
        elseif args[case] and args[case] ~= "" then
            local term = nil
            local tr = nil
            local typ = type(args[case])
            if typ ~= "table" and mw.ustring.find(args[case], ",") then
                args[case] = mw.text.split(args[case], "%s*,%s*")
                typ = type(args[case])
            end
            if typ == "table" then
                local sep = ""
                term = ""
                for _, x in ipairs(args[case]) do
                    term = term .. sep .. "[[" .. x .. "]]"
                    sep = ", "
                end
                tr = lang:transliterate(m_links.remove_links(term))
                term = m_links.full_link(term, nil, lang, nil, nil, nil, {tr = "-"}, false)
            else
                tr = lang:transliterate(m_links.remove_links(args[case]))
                term = m_links.full_link(args[case], nil, lang, nil, nil, nil, {tr = "-"}, false)
            end
            if case == "gen_m" then
                tr = mw.ustring.gsub(tr, "([oeóé]́?)go$", "%1vo")
            end
            args[case] = strutils.format(form_temp, {["term"] = term, ["tr"] = tr})
        else
            args[case] = nil
        end
    end

    if args["short_m"] or args["short_n"] or args["short_f"] or args["short_p"] then
        args["short_m"] = args["short_m"] or "&mdash;"
        args["short_n"] = args["short_n"] or "&mdash;"
        args["short_f"] = args["short_f"] or "&mdash;"
        args["short_p"] = args["short_p"] or "&mdash;"
        args["short_clause"] = strutils.format(short_clause, args)
    else
        args["short_clause"] = ""
    end

    return strutils.format(template, args)
end

short_clause = [===[

! style="height:0.2em;background:#d9ebff" colspan="6" |
|-
! style="background:#eff7ff" colspan="2" | short form
| {short_m}
| {short_n}
| {short_f}
| {short_p}]===]

template = [===[
<div>
<div class="NavFrame" style="display: inline-block; min-width: 70em">
<div class="NavHead" style="background:#eff7ff">{title}</div>
<div class="NavContent">
{\op}| style="background:#F9F9F9;text-align:center; min-width:70em" class="inflection-table"
|-
! style="width:20%;background:#d9ebff" colspan="2" | 
! style="background:#d9ebff" | masculine
! style="background:#d9ebff" | neuter
! style="background:#d9ebff" | feminine
! style="background:#d9ebff" | plural
|-
! style="background:#eff7ff" colspan="2" | nominative
| {nom_m}
| {nom_n}
| {nom_f}
| {nom_p}
|-
! style="background:#eff7ff" colspan="2" | genitive
| colspan="2" | {gen_m}
| {gen_f}
| {gen_p}
|-
! style="background:#eff7ff" colspan="2" | dative
| colspan="2" | {dat_m}
| {dat_f}
| {dat_p}
|-
! style="background:#eff7ff" rowspan="2" | accusative
! style="background:#eff7ff" | animate
| {gen_m}
| rowspan="2" | {acc_n}
| rowspan="2" | {acc_f}
| {gen_p}
|-
! style="background:#eff7ff" | inanimate
| {nom_m}
| {nom_p}
|-
! style="background:#eff7ff" colspan="2" | instrumental
| colspan="2" | {ins_m}
| {ins_f}
| {ins_p}
|-
! style="background:#eff7ff" colspan="2" | prepositional
| colspan="2" | {pre_m}
| {pre_f}
| {pre_p}
|-{short_clause}
|{\cl}</div></div></div>]===]

return export