local export = {}
local m_table = require( "Module:table" )
local m_links = require( "Module:links" )
local m_string_utilities = require( "Module:string utilities" )
local lang = require( "Module:languages" ).getByCode( "mn" )
local com = require( "Module:User:Theknightwho/mn-common" )
local iut = require( "Module:inflection utilities" )
local put = require("Module:parse utilities")
local m_para = require( "Module:parameters" )
local char = mw.ustring.char
local find = mw.ustring.find
local format = mw.ustring.format
local len = require( "Module:string" ).ulen
local match = mw.ustring.match
local gmatch = mw.ustring.gmatch
local sub = mw.ustring.sub
local gsub = mw.ustring.gsub
local lower = mw.ustring.lower
local split = mw.text.split
local reverse = require( "Module:string" ).reverse
local upper = mw.ustring.upper
table.append = require( "Module:table" ).append
local FVS = ""
local n = char( 0xFFF0 )
local g = char( 0xFFF1 )
local bor = char( 0xFFF2 )
local Russian = char( 0xFFF3 )
local proper = char( 0xFFF4 )
local output_noun_slots = {
attr = "attr|form",
nom_sg = "nom|s",
gen_sg = "gen|s",
acc_sg = "acc|s",
dat_loc_sg = "dat|-|loc|s",
gen_dat_sg = "gen|-|dat|s",
abl_sg = "abl|s",
dat_abl_sg = "dat|-|abl|s",
ins_sg = "ins|s",
com_sg = "com|s",
priv_sg = "priv|s",
dirc_sg = "dirc|s",
nom_pl = "nom|p",
gen_pl = "gen|p",
acc_pl = "acc|p",
dat_loc_pl = "dat|-|loc|p",
gen_dat_pl = "gen|-|dat|p",
abl_pl = "abl|p",
dat_abl_pl = "dat|-|abl|p",
ins_pl = "ins|p",
com_pl = "com|p",
priv_pl = "priv|p",
dirc_pl = "dirc|p",
spos_indgen_sg = "spos|indgen|s",
cpos_indgen_sg = "cpos|indgen|s",
spos_indgen_pl = "spos|indgen|p",
cpos_indgen_pl = "cpos|indgen|p",
spos_indloc_sg = "spos|indloc|s",
cpos_indloc_sg = "cpos|indloc|s",
spos_indloc_pl = "spos|indloc|p",
cpos_indloc_pl = "cpos|indloc|p",
nom_sg_refl = "refl poss|form|of the|nom|s",
gen_sg_refl = "refl poss|form|of the|gen|s",
acc_sg_refl = "refl poss|form|of the|acc|s",
dat_loc_sg_refl = "refl poss|form|of the|dat|-|loc|s",
gen_dat_sg_refl = "refl poss|form|of the|gen|-|dat|s",
abl_sg_refl = "refl poss|form|of the|abl|s",
dat_abl_sg_refl = "refl poss|form|of the|dat|-|abl|s",
ins_sg_refl = "refl poss|form|of the|ins|s",
com_sg_refl = "refl poss|form|of the|com|s",
priv_sg_refl = "refl poss|form|of the|priv|s",
dirc_sg_refl = "refl poss|form|of the|dirc|s",
nom_pl_refl = "refl poss|form|of the|nom|p",
gen_pl_refl = "refl poss|form|of the|gen|p",
acc_pl_refl = "refl poss|form|of the|acc|p",
dat_loc_pl_refl = "refl poss|form|of the|dat|-|loc|p",
gen_dat_pl_refl = "refl poss|form|of the|gen|-|dat|p",
abl_pl_refl = "refl poss|form|of the|abl|p",
dat_abl_pl_refl = "refl poss|form|of the|dat|-|abl|p",
ins_pl_refl = "refl poss|form|of the|ins|p",
com_pl_refl = "refl poss|form|of the|com|p",
priv_pl_refl = "refl poss|form|of the|priv|p",
dirc_pl_refl = "refl poss|form|of the|dirc|p",
nom = "nom",
gen = "gen",
acc = "acc",
dat_loc = "dat|loc",
abl = "abl",
ins = "ins",
com = "com",
priv = "priv",
dirc = "dirc",
nom_refl = "refl poss|form|of the|nom",
gen_refl = "refl poss|form|of the|gen",
acc_refl = "refl poss|form|of the|acc",
dat_loc_refl = "refl poss|form|of the|dat|-|loc",
abl_refl = "refl poss|form|of the|abl",
ins_refl = "refl poss|form|of the|ins",
com_refl = "refl poss|form|of the|com",
priv_refl = "refl poss|form|of the|priv",
dirc_refl = "refl poss|form|of the|dirc",
}
local output_noun_slots_with_linked = m_table.shallowcopy( output_noun_slots )
output_noun_slots_with_linked = "nom|s"
output_noun_slots_with_linked = "nom|p"
local input_params_to_slots_both = {
= "attr",
= "nom_sg",
= "gen_sg",
= "acc_sg",
= "dat_loc_sg",
= "gen_dat_sg",
= "abl_sg",
= "dat_abl_sg",
= "ins_sg",
= "com_sg",
= "priv_sg",
= "dirc_sg",
= "nom_pl",
= "gen_pl",
= "acc_pl",
= "dat_loc_pl",
= "gen_dat_pl",
= "abl_pl",
= "dat_abl_pl",
= "ins_pl",
= "com_pl",
= "priv_pl",
= "dirc_pl",
= "spos_indgen_sg",
= "cpos_indgen_sg",
= "spos_indgen_pl",
= "cpos_indgen_pl",
= "spos_indloc_sg",
= "cpos_indloc_sg",
= "spos_indloc_pl",
= "cpos_indloc_pl",
= "nom_sg_refl",
= "gen_sg_refl",
= "acc_sg_refl",
= "dat_loc_sg_refl",
= "gen_dat_sg_refl",
= "abl_sg_refl",
= "dat_abl_sg_refl",
= "ins_sg_refl",
= "com_sg_refl",
= "priv_sg_refl",
= "dirc_sg_refl",
= "nom_pl_refl",
= "gen_pl_refl",
= "acc_pl_refl",
= "dat_loc_pl_refl",
= "gen_dat_pl_refl",
= "abl_pl_refl",
= "dat_abl_pl_refl",
= "ins_pl_refl",
= "com_pl_refl",
= "priv_pl_refl",
= "dirc_pl_refl",
}
local input_params_to_slots_sg = {
= "attr",
= "nom_sg",
= "gen_sg",
= "acc_sg",
= "dat_loc_sg",
= "gen_dat_sg",
= "abl_sg",
= "dat_abl_sg",
= "ins_sg",
= "com_sg",
= "priv_sg",
= "dirc_sg",
= "spos_indgen_sg",
= "cpos_indgen_sg",
= "spos_indloc_sg",
= "cpos_indloc_sg",
= "nom_sg_refl",
= "gen_sg_refl",
= "acc_sg_refl",
= "dat_loc_sg_refl",
= "gen_dat_sg_refl",
= "abl_sg_refl",
= "dat_abl_sg_refl",
= "ins_sg_refl",
= "com_sg_refl",
= "priv_sg_refl",
= "dirc_sg_refl",
}
local input_params_to_slots_pl = {
= "attr",
= "nom_pl",
= "gen_pl",
= "acc_pl",
= "dat_loc_pl",
= "gen_dat_pl",
= "abl_pl",
= "dat_abl_pl",
= "ins_pl",
= "com_pl",
= "priv_pl",
= "dirc_pl",
= "spos_indgen_pl",
= "cpos_indgen_pl",
= "spos_indloc_pl",
= "cpos_indloc_pl",
= "nom_pl_refl",
= "gen_pl_refl",
= "acc_pl_refl",
= "dat_loc_pl_refl",
= "gen_dat_pl_refl",
= "abl_pl_refl",
= "dat_abl_pl_refl",
= "ins_pl_refl",
= "com_pl_refl",
= "priv_pl_refl",
= "dirc_pl_refl",
}
local input_params_to_slots_poss = {
= "nom",
= "gen",
= "acc",
= "dat_loc",
= "abl",
= "ins",
= "com",
= "priv",
= "dirc",
= "nom_refl",
= "gen_refl",
= "acc_refl",
= "dat_loc_refl",
= "abl_refl",
= "ins_refl",
= "com_refl",
= "priv_refl",
= "dirc_refl",
}
local cases = {
attr = true,
nom = true,
gen = true,
dat_loc = true,
gen_dat = true,
acc = true,
abl = true,
dat_abl = true,
ins = true,
com = true,
priv = true,
dirc = true,
}
local accented_cases = {
= "attr",
= "nom",
= "gen",
= "dat_loc",
= "gen_dat",
= "acc",
= "abl",
= "dat_abl",
= "ins",
= "com",
= "priv",
= "dirc",
}
local function skip_slot( number, slot )
return number == "sg" and find( slot, "_p$" ) or
number == "pl" and find( slot, "_s$" )
end
local function add( data, slot, stem_and_ending, footnotes )
local stem
local ending
if not stem_and_ending then
return
end
if skip_slot( data.number, slot ) then
return
end
if type( stem_and_ending ) == "string" then
stem = stem_and_ending
ending = ""
else
stem = stem_and_ending
ending = stem_and_ending
end
iut.add_forms( data.forms, slot, stem, ending, com.combine_stem_ending, lang )
end
local function process_slot_overrides( data, do_slot )
for slot, overrides in pairs( data.overrides ) do
if skip_slot( data.number, slot ) then
error( "Override specified for invalid slot '" .. slot .. "' due to '" .. data.number .. "' number restriction" )
end
if do_slot( slot ) then
data.forms = nil
local slot_is_plural = find( slot, "_p$" )
for _, override in ipairs( overrides ) do
for _, value in ipairs( override.values ) do
local form = value.form
local combined_notes = iut.combine_footnotes( data.footnotes, value.footnotes )
end
end
end
end
end
local function preprocess_inflection( infl )
local params = {}
if match( infl, n ) then params.n = true
elseif match( infl, g ) then params.g = true end
if match( infl, Russian ) then params.bor = "Russian"
elseif match( infl, bor ) then params.bor = true end
if match( infl, proper ) then params.proper = true end
infl = gsub( infl, "", "" )
local infl_orig = gsub( infl, com.stem_barrier, "" )
return infl, params, infl_orig
end
local function vowelharmony( infl, data )
return com.vowelharmony( infl, data )
end
local function propernoun( infl )
if sub( infl, 1, 1 ) ~= lower( sub( infl, 1, 1 ) ) then
return true
else
return false
end
end
local function insert_stem_barrier( data )
local syllables = com.syllables( data.lemma )
if #syllables > 1 and data.bor then
syllables = syllables .. com.stem_barrier
else
if #syllables > 1 then
syllables = syllables .. com.stem_barrier
end
end
return table.concat( syllables )
end
local function hidden_n( infl, params, vh )
infl = gsub( infl, n, "" )
local vh = vh or vowelharmony( infl, params )
local infl_no_stress = gsub( lang:makeEntryName( infl ), com.stem_barrier, "" )
local matches = {
{ { match( infl_no_stress, "$" ) },
"н"
},
{ { match( infl_no_stress, "$" ) },
"ин"
},
{ { match( infl_no_stress, "$" ) },
vh.Cyrl.a .. "н"
},
{ { match( infl_no_stress, "" .. FVS .. "?$" ) },
"ᠨ"
},
{ { match( infl_no_stress, "" .. FVS .. "?$" ) },
vh.Mong.u .. "ᠨ"
}
}
for s,t in ipairs( matches ) do
for _,m in pairs( t ) do
if m then
infl = gsub( infl, com.MVS, "" )
if match( infl_no_stress, "ь$" ) then
return sub( infl, 1, len( infl ) - 1 ) .. t, {}
else
return infl .. t, {}
end
end
end
end
end
local function hidden_g( infl )
infl = gsub( infl, g, "" )
return infl .. "г"
end
local function attributive( infl, vh )
local infl, params = preprocess_inflection( infl )
if params.n then
infl = hidden_n( infl, params, vh )
end
return com.remove_penultimate_short_vowel( infl, params )
end
local function plural( infl, vh )
local infl, params, infl_orig = preprocess_inflection( infl )
if params.n then infl, params = hidden_n( infl, params, vh )
elseif params.g then infl = hidden_g( infl ) end
local vh = vh or vowelharmony( infl, params )
local infl_no_fv, no_fv = com.remove_final_short_vowel( infl, params )
local infl_no_stress = gsub( lang:makeEntryName( infl ), com.stem_barrier, "" )
local infl_no_fv_no_stress = gsub( lang:makeEntryName( infl_no_fv ), com.stem_barrier, "" )
local matches = {
{ {
match( infl_no_stress, "ч.н$" ),
match( infl_no_stress, "ён$" )
},
"д"
},
{ { match( infl_no_stress, "$" ) },
"н" .. vh.Cyrl.uu .. "д"
},
{ {
match( infl_no_stress, "$" ),
match( infl_no_fv_no_stress, "$" ), -- C, and also loanwords with a word-final long vowel written as a single vowel
match( infl_no_stress, "$" ) and params.bor
},
"г" .. vh.Cyrl.uu .. "д"
},
{ { match( infl_no_stress, "$" ) },
"и" .. vh.Cyrl.u .. "д"
},
{ { match( infl_no_stress, "$" ) },
vh.Cyrl.u .. "д"
},
{ { match( infl_no_stress, "?$" ) },
vh.Cyrl.uu .. "д"
},
{ { match( infl_orig, "ᠨ$" ) },
"ᠳ"
},
{ { match( infl_no_stress, "" .. FVS .. "?$" ) },
com.NNBSP .. "ᠨ" .. vh.Mong.u .. "ᠭ" .. vh.Mong.u .. "ᠳ"
},
{ { match( infl_no_stress, "" .. FVS .. "?$" ) },
com.NNBSP .. vh.Mong.u .. "ᠳ"
}
}
for s,t in ipairs( matches ) do
for _,m in pairs( t ) do
if match( infl_no_stress, "^хүн$" ) then
return "хүмүүс"
elseif t == "д" or t == "ᠳ" then
return sub( infl, 1, len( infl ) - 1 ) .. t
else
if m and no_fv then
return infl_no_fv .. t
elseif m then
return com.remove_penultimate_short_vowel( infl .. t, params )
end
end
end
end
end
local function genitive( infl, vh )
local infl, params = preprocess_inflection( infl )
if params.n then infl, params = hidden_n( infl, params, vh )
elseif params.g then infl = hidden_g( infl ) end
local vh = vh or vowelharmony( infl, params )
local infl_no_fv, no_fv = com.remove_final_short_vowel( infl, params )
local infl_no_stress = gsub( lang:makeEntryName( infl ), com.stem_barrier, "" )
local infl_no_fv_no_stress = gsub( lang:makeEntryName( infl_no_fv ), com.stem_barrier, "" )
local matches = {
{ { match( infl_no_stress, "н$" ) },
vh.Cyrl.ii
},
{ {
match( infl_no_stress, "$" ),
match( infl_no_fv_no_stress, "и$" )
},
"н"
},
{ {
match( infl_no_stress, "$" ),
match( infl_no_fv_no_stress, "$" ), -- C, and also loanwords with a word-final long vowel written as a single vowel
match( infl_no_stress, "$" ) and params.bor
},
"гийн"
},
{ { match( infl_no_stress, "$" ) },
"ийн"
},
{ {
match( infl_no_stress, "$" ),
match( infl_no_stress, "$" ),
match( infl_no_stress, "$" ) -- not C
},
vh.Cyrl.ii .. "н"
},
{ { match( infl_no_stress, "" .. FVS .. "?$" ) },
com.NNBSP .. "ᠶᠢᠨ"
},
{ { match( infl_no_stress, "ᠨ" .. FVS .. "?$" ) },
com.NNBSP .. vh.Mong.u
},
{ { match( infl_no_stress, "" .. FVS .. "?$" ) },
com.NNBSP .. vh.Mong.u .. "ᠨ"
}
}
for s,t in ipairs( matches ) do
for _,m in pairs( t ) do
if m and no_fv then
return infl_no_fv .. t
elseif m then
return com.remove_penultimate_short_vowel( infl .. t, params )
end
end
end
end
local function accusative( infl, vh )
local infl, params = preprocess_inflection( infl )
if params.n then infl = gsub( infl, n, "" )
elseif params.g then return infl .. "г" end
local vh = vh or vowelharmony( infl, params )
local infl_no_fv, no_fv = com.remove_final_short_vowel( infl, params )
local infl_no_stress = gsub( lang:makeEntryName( infl ), com.stem_barrier, "" )
local infl_no_fv_no_stress = gsub( lang:makeEntryName( infl_no_fv ), com.stem_barrier, "" )
local matches = {
{ {
match( infl_no_stress, "$" ),
match( infl_no_stress, "$" ),
match( infl_no_fv_no_stress, "$" ), -- C, and also loanwords with a word-final long vowel written as a single vowel
match( infl_no_fv_no_stress, "и$" ),
match( infl_no_stress, "$" ) and params.bor
},
"г"
},
{ { match( infl_no_stress, "$" ) },
"ийг"
},
{ {
match( infl_no_stress, "$" ),
match( infl_no_stress, "$" ),
match( infl_no_stress, "$" ) -- not C
},
vh.Cyrl.ii .. "г"
},
{ { match( infl_no_stress, "" .. FVS .. "?$" ) },
com.NNBSP .. "ᠶᠢ"
},
{ { match( infl_no_stress, "" .. FVS .. "?$" ) },
com.NNBSP .. "ᠢ"
}
}
for s,t in ipairs( matches ) do
for _,m in pairs( t ) do
if m and no_fv then
return infl_no_fv .. t
elseif m then
return com.remove_penultimate_short_vowel( infl .. t, params )
end
end
end
end
local function dative_locative( infl, vh )
local infl, params = preprocess_inflection( infl )
if params.n then
infl = hidden_n( infl, params, vh )
end
local vh = vh or vowelharmony( infl, params )
local syllable_count = #com.syllables( infl )
local infl_no_fv = com.remove_final_short_vowel( infl, params )
local infl_no_stress = gsub( lang:makeEntryName( infl ), com.stem_barrier, "" )
local infl_no_fv_no_stress = gsub( lang:makeEntryName( infl_no_fv ), com.stem_barrier, "" )
local vowel = ""
local consonant = ""
local matches = {
{ {
match( infl_no_stress, "$" ) or match( infl_no_stress, "п$" ),
( match( infl_no_stress, "в$" ) or match( infl_no_stress, "б$" ) ) and ( syllable_count ~= 1 or match( infl_no_stress, "^" .. consonant .. consonant ) ),
match( infl_no_stress, vowel .. vowel .. "$" ) or match( infl_no_stress, consonant .. "р$" ),
( match( infl_no_stress, "р$" ) or match( infl_no_stress, vowel .. "с$" ) ) and ( syllable_count ~= 1 or params.proper ),
match( infl_no_stress, vowel .. "ь?с$" ),
match( infl_no_stress, "ьс$" ),
match( infl_no_stress, "ис$" ),
},
"т"
},
{ {
match( infl_no_stress, vowel .. "$" ),
match( infl_no_stress, "б$" ),
match( infl_no_stress, "$" ),
match( infl_no_stress, "ь$" ),
},
"д"
},
{ {
match( infl_no_stress, "ь?$" ),
match( infl_no_stress, "ь$" )
},
"ид"
},
{ { match( infl_no_stress, "" .. FVS .. "?$" ) },
com.NNBSP .. "ᠲ" .. vh.Mong.u
},
{ { match( infl_no_stress, "" .. FVS .. "?$" ) },
com.NNBSP .. "ᠳ" .. vh.Mong.u
},
{ { match( infl_no_stress, ".$" ) },
vh.Cyrl.a .. "д"
}
}
for s,t in ipairs( matches ) do
for _,m in pairs( t ) do
if m then
if match( infl_no_stress, "ь$" ) then
return infl_no_fv .. t
else
return com.remove_penultimate_short_vowel( infl .. t, params )
end
end
end
end
end
local function aa( infl, params )
local vh = vh or vowelharmony( infl, params )
local infl_no_fv, no_fv = com.remove_final_short_vowel( infl, params )
local infl_no_stress = gsub( lang:makeEntryName( infl ), com.stem_barrier, "" )
local infl_no_fv_no_stress = gsub( lang:makeEntryName( infl_no_fv ), com.stem_barrier, "" )
local matches = {
{ {
match( infl_no_stress, "$" ),
match( infl_no_stress, "$" ),
match( infl_no_fv_no_stress, "$" ), -- C, and also loanwords with a word-final long vowel written as a single vowel
match( infl_no_fv_no_stress, "и$" ),
match( infl_no_stress, "$" ) and params.bor
},
"г" .. vh.Cyrl.aa
},
{ { match( infl_no_stress, "$" ) },
vh.Cyrl.a
},
{ { match( infl_no_stress, "$" ) },
"и" .. vh.Cyrl.a
},
{ {
match( infl_no_stress, "$" ),
match( infl_no_stress, "$" ) -- not C
},
vh.Cyrl.aa
}
}
for s,t in ipairs( matches ) do
for _,m in pairs( t ) do
if m and no_fv then
return infl_no_fv .. t
elseif m then
return infl .. t
end
end
end
end
local function ablative( infl, vh )
local infl, params = preprocess_inflection( infl )
if params.n then infl, params = hidden_n( infl, params, vh )
elseif params.g then infl = hidden_g( infl ) end
local vh = vh or vowelharmony( infl, params )
if match( infl, com.NNBSP .. "" .. vh.Mong.u .. "$" ) then
return sub( infl, 1, len( infl ) - 1 ) .. vh.Mong.a .. "ᠴ" .. vh.Mong.a
elseif match( infl, "" .. FVS .. "?$" ) then
return infl .. com.NNBSP .. vh.Mong.a .. "ᠴ" .. vh.Mong.a
else
return com.remove_penultimate_short_vowel( aa( infl, params ) .. "с", params )
end
end
local function instrumental( infl, vh )
local infl, params = preprocess_inflection( infl )
if params.g then infl = hidden_g( infl ) end
if match( infl, "" .. FVS .. "?$" ) then
local matches = {
{ { match( infl, "" .. FVS .. "?$" ) },
com.NNBSP .. "ᠪ" .. vh.Mong.a .. "ᠷ"
},
{ { match( infl, "" .. FVS .. "?$" ) },
com.NNBSP .. "ᠢᠶ" .. vh.Mong.a .. "ᠷ"
}
}
for s,t in ipairs( matches ) do
for _,m in pairs( t ) do
if m then return infl .. t end
end
end
else
return com.remove_penultimate_short_vowel( aa( infl, params ) .. "р", params )
end
end
local function reflexive( infl, vh )
local infl, params = preprocess_inflection( infl )
if params.g then infl = hidden_g( infl ) end
if match( infl, "" .. FVS .. "?$" ) then
local matches = {
{ { match( infl, com.NNBSP .. "ᠶ?ᠢ$" ) },
"ᠶ" .. vh.Mong.u .. "ᠭ" .. vh.Mong.a .. "ᠨ"
},
{ { match( infl, com.NNBSP .. "" .. vh.Mong.u .. "$" ) },
vh.Mong.a .. "ᠭ" .. vh.Mong.a .. "ᠨ"
},
{ { match( infl, com.NNBSP .. vh.Mong.a .. "ᠴ" .. vh.Mong.a .. "$" ) },
"ᠭ" .. vh.Mong.a .. "ᠨ"
},
{ { match( infl, com.NNBSP .. "ᠲ" .. vh.Mong.a .. "ᠢ$" ) },
"ᠶᠢᠭ" .. vh.Mong.a .. "ᠨ"
},
{ { match( infl, "" .. FVS .. "?$" ) },
com.NNBSP .. "ᠪ" .. vh.Mong.a .. "ᠨ"
},
{ { match( infl, "" .. FVS .. "?$" ) },
com.NNBSP .. "ᠢᠶ" .. vh.Mong.a .. "ᠨ"
}
}
for s,t in ipairs( matches ) do
for _,m in pairs( t ) do
if m then
if match( infl, com.NNBSP .. "ᠶᠢ$" ) then
return sub( infl, 1, len( infl ) - 2 ) .. t
elseif match( infl, com.NNBSP .. "ᠢ$" ) or match( infl, com.NNBSP .. "" .. vh.Mong.u .. "$" ) or match( infl, com.NNBSP .. "ᠲ" .. vh.Mong.a .. "ᠢ$" ) then
return sub( infl, 1, len( infl ) - 1 ) .. t
else
return infl .. t
end
end
end
end
else
return com.remove_penultimate_short_vowel( aa( infl, params ), params ) .. n -- unstable nasal
end
end
local function comitative( infl, vh )
local infl, params = preprocess_inflection( infl )
local vh = vh or vowelharmony( infl, params )
if match( infl, "" .. FVS .. "?$" ) then
return infl .. com.NNBSP .. "ᠲ" .. vh.Mong.a .. "ᠢ"
elseif match( infl, "ь$" ) then
return sub( infl, 1, len( infl ) - 1 ) .. "ит" .. vh.Cyrl.ai
else
return com.remove_penultimate_short_vowel( infl .. "т" .. vh.Cyrl.ai, params )
end
end
local function privative( infl )
local infl = preprocess_inflection( infl )
if match( infl, "" .. FVS .. "?$" ) then
return infl .. com.NNBSP .. "ᠦᠭᠡᠢ"
else
return infl .. "гүй"
end
end
local function directive( infl, vh )
local infl, params = preprocess_inflection( infl )
local vh = vh or vowelharmony( infl, params )
if match( infl, "" .. FVS .. "?$" ) then
return infl .. com.NNBSP .. "ᠤᠷᠤᠭᠤ"
elseif match( infl, "рь?$" ) then
return infl .. " [[л" .. vh.Cyrl.uu
else
return infl .. " [[р" .. vh.Cyrl.uu
end
end
local function equative( infl )
end
local function singular_independent_genitive( infl )
local infl = preprocess_inflection( infl )
if match( infl, "" .. FVS .. "?$" ) then
return infl .. com.NNBSP .. "ᠬᠢ"
else
return infl .. "х"
end
end
local function collective_independent_genitive( infl, vh )
local infl, params = preprocess_inflection( infl )
local vh = vh or vowelharmony( infl, params )
if match( infl, "" .. FVS .. "?$" ) then
return infl .. com.NNBSP .. "ᠬᠢᠨ"
else
return infl .. "х" .. vh.Cyrl.a .. "н"
end
end
local function handle_derived_slots_and_overrides( data )
data.lemma = insert_stem_barrier( data )
if data.decl == "n" then data.lemma = data.lemma .. n end
if data.decl == "g" then data.lemma = data.lemma .. g end
if data.bor == "Russian" then
data.lemma = data.lemma .. Russian
elseif data.bor then
data.lemma = data.lemma .. bor
end
if data.proper then data.lemma = data.lemma .. proper end
if data.number ~= "spos" and data.number ~= "cpos" then
add( data, "attr", attributive( data.lemma ) )
add( data, "nom_sg", data.lemma )
add( data, "gen_sg", genitive( data.lemma ) )
add( data, "acc_sg", accusative( data.lemma ) )
add( data, "dat_loc_sg", dative_locative( data.lemma ) )
add( data, "abl_sg", ablative( data.lemma ) )
add( data, "ins_sg", instrumental( data.lemma ) )
add( data, "com_sg", comitative( data.lemma ) )
add( data, "priv_sg", privative( data.lemma ) )
add( data, "dirc_sg", directive( data.lemma ) )
add( data, "nom_pl", plural( data.lemma ) )
add( data, "gen_pl", genitive( data.forms.form ) )
add( data, "acc_pl", accusative( data.forms.form ) )
add( data, "dat_loc_pl", dative_locative( data.forms.form ) )
add( data, "abl_pl", ablative( data.forms.form ) )
add( data, "ins_pl", instrumental( data.forms.form ) )
add( data, "com_pl", comitative( data.forms.form ) )
add( data, "priv_pl", privative( data.forms.form ) )
add( data, "dirc_pl", directive( data.forms.form ) )
add( data, "spos_indgen_sg", singular_independent_genitive( data.forms.form ) )
add( data, "cpos_indgen_sg", collective_independent_genitive( data.forms.form ) )
add( data, "spos_indgen_pl", singular_independent_genitive( data.forms.form ) )
add( data, "cpos_indgen_pl", collective_independent_genitive( data.forms.form ) )
--"spos_indloc_sg",
--"cpos_indloc_sg",
--"spos_indloc_pl",
--"cpos_indloc_pl",
add( data, "nom_sg_refl", reflexive( data.forms.form ) )
add( data, "gen_sg_refl", reflexive( data.forms.form ) )
add( data, "acc_sg_refl", reflexive( data.forms.form ) )
add( data, "dat_loc_sg_refl", reflexive( data.forms.form ) )
add( data, "abl_sg_refl", reflexive( data.forms.form ) )
add( data, "ins_sg_refl", reflexive( data.forms.form ) )
add( data, "com_sg_refl", reflexive( data.forms.form ) )
add( data, "priv_sg_refl", reflexive( data.forms.form ) )
add( data, "dirc_sg_refl", reflexive( data.forms.form ) )
add( data, "nom_pl_refl", reflexive( data.forms.form ) )
add( data, "gen_pl_refl", reflexive( data.forms.form ) )
add( data, "acc_pl_refl", reflexive( data.forms.form ) )
add( data, "dat_loc_pl_refl", reflexive( data.forms.form ) )
add( data, "abl_pl_refl", reflexive( data.forms.form ) )
add( data, "ins_pl_refl", reflexive( data.forms.form ) )
add( data, "com_pl_refl", reflexive( data.forms.form ) )
add( data, "priv_pl_refl", reflexive( data.forms.form ) )
add( data, "dirc_pl_refl", reflexive( data.forms.form ) )
if data.gen_dat then
add( data, "gen_dat_sg", dative_locative( data.forms.form ) )
add( data, "gen_dat_pl", dative_locative( data.forms.form ) )
add( data, "gen_dat_sg_refl", reflexive( data.forms.form ) )
add( data, "gen_dat_pl_refl", reflexive( data.forms.form ) )
end
if data.dat_abl then
add( data, "dat_abl_sg", ablative( data.forms.form ) )
add( data, "dat_abl_sg_refl", reflexive( data.forms.form ) )
end
else
add( data, "nom", data.lemma )
if data.number == "cpos" then
add( data, "gen", genitive( data.lemma ) )
end
add( data, "acc", accusative( data.lemma ) )
add( data, "dat_loc", dative_locative( data.lemma ) )
add( data, "abl", ablative( data.lemma ) )
add( data, "ins", instrumental( data.lemma ) )
add( data, "com", comitative( data.lemma ) )
add( data, "priv", privative( data.lemma ) )
add( data, "dirc", directive( data.lemma ) )
add( data, "nom_refl", reflexive( data.forms.form ) )
if data.number == "cpos" then
add( data, "gen_refl", reflexive( data.forms.form ) )
end
add( data, "acc_refl", reflexive( data.forms.form ) )
add( data, "dat_loc_refl", reflexive( data.forms.form ) )
add( data, "abl_refl", reflexive( data.forms.form ) )
add( data, "ins_refl", reflexive( data.forms.form ) )
add( data, "com_refl", reflexive( data.forms.form ) )
add( data, "priv_refl", reflexive( data.forms.form ) )
add( data, "dirc_refl", reflexive( data.forms.form ) )
end
for _,form in pairs( data.forms ) do
for _,variant in ipairs( form ) do
variant.form = gsub( variant.form, "", "" )
if match( gsub( variant.form, data.orig_lemma, "" ), " " ) then variant.form = variant.form .. "]]" end
end
end
-- Compute linked versions of potential lemma slots, for use in {{mn-noun}}.
-- We substitute the original lemma (before removing links) for forms that
-- are the same as the lemma, if the original lemma has links.
for _, slot in ipairs( { "nom_sg", "nom_pl" } ) do
iut.insert_forms( data.forms, slot .. "_linked", iut.map_forms( data.forms, function( form )
if form == data.orig_lemma_no_links and find( data.orig_lemma, "%[%[" ) then
return data.orig_lemma
else
return form
end
end ) )
end
end
local function fetch_footnotes( separated_group )
local footnotes
for j = 2, #separated_group - 1, 2 do
if separated_group ~= "" then
error( "Extraneous text after bracketed footnotes: '" .. table.concat( separated_group ) .. "'" )
end
if not footnotes then
footnotes = {}
end
table.insert( footnotes, separated_group )
end
return footnotes
end
local function parse_override( segments, case )
local retval = { values = {} }
local part = segments
if cases then
-- ok
elseif accented_cases then
case = accented_cases
retval.stemstressed = true
else
error("Internal error: unrecognized case in override: '" .. table.concat(segments) .. "'")
end
local rest = sub( part, len(case)+1, len(case)+3 )
local slot
if find( rest, "^pl" ) then
rest = gsub( rest, "^pl", "" )
slot = case .. "_pl"
else
slot = case .. "_sl"
end
if find( rest, "^:" ) then
retval.full = true
rest = gsub( rest, "^:", "" )
end
segments = rest
local colon_separated_groups = put.split_alternating_runs( segments, ":" )
for i, colon_separated_group in ipairs( colon_separated_groups ) do
local value = {}
local form = colon_separated_group
if form == "" then
error( "Use - to indicate an empty ending for slot '" .. slot .. "': '" .. table.concat( segments .. "'" ) )
elseif form == "-" then
value.form = ""
else
value.form = form
end
value.footnotes = fetch_footnotes( colon_separated_group )
table.insert( retval.values, value )
end
return slot, retval
end
local function parse_indicator_spec( angle_bracket_spec )
local inside = match( angle_bracket_spec, "^<(.*)>$" )
local data = { overrides = {}, forms = {} }
if inside ~= "" then
local segments = put.parse_balanced_segment_run( inside, "" )
local dot_separated_groups = put.split_alternating_runs( segments, "%." )
for i, dot_separated_group in ipairs( dot_separated_groups ) do
local part = dot_separated_group
local case_prefix
for case,_ in pairs( cases ) do
if match( part, "^" .. case .. "" ) then
case_prefix = match( part, "^" .. case )
local slot, override = parse_override( dot_separated_group, case_prefix )
if data.overrides then
table.insert( data.overrides, override )
else
data.overrides = { override }
end
end
end
if case_prefix ~= nil then
elseif part == "" then
if #dot_separated_group == 1 then
error( "Blank indicator: '" .. inside .. "'" )
end
data.footnotes = fetch_footnotes( dot_separated_group )
elseif part == "r" or part == "n" or part == "g" then
if data.decl then
error( "Can't specify declension twice: '" .. inside .. "'" )
end
data.decl = part
elseif part == "sg" or part == "pl" or part == "spos" or part == "cpos" then
if data.number then
error( "Can't specify number twice: '" .. inside .. "'" )
end
data.number = part
elseif part == "gen_dat" then
if data.gen_dat then
error( "Can't specify genitive-dative twice: '" .. inside .. "'" )
end
data.gen_dat = true
elseif part == "dat_abl" then
if data.dat_abl then
error( "Can't specify dative-ablative twice: '" .. inside .. "'" )
end
data.dat_abl = true
elseif part == "а" or part == "о" or part == "ө" or part == "э" then
if data.vh_override then
error( "Can't specify vowel harmony twice: '" .. inside .. "'" )
end
data.vh_override = part
elseif part == "bor" or part == "Russian" then
if data.bor then
error( "Can't specify borrowing twice: '" .. inside .. "'" )
end
data.bor = part
elseif part == "proper" then
if data.proper then
error( "Can't specify proper noun twice: '" .. inside .. "'" )
end
data.proper = true
else
error( "Unrecognized indicator '" .. part .. "': '" .. inside .. "'" )
end
end
else
error( "Blank indicator: '" .. inside .. "'" )
end
return data
end
local function set_defaults_and_check_bad_indicators( data )
-- Set default values.
if not data.adj then
if data.proper then
data.number = data.number or "sg"
else
data.number = data.number or "both"
end
end
end
local function check_indicators_match_lemma( data )
-- Check for indicators that don't make sense given the context.
if data.decl == "n" and match( data.lemma, "н$" ) then
error( "Hidden-n declension cannot be specified with a lemma ending in н" )
end
if data.decl == "g" and not match( data.lemma, "н$" ) then
error( "Hidden-g declension can only be specified with a lemma ending in н" )
end
end
local function detect_indicator_spec( data )
if propernoun( data.lemma ) then data.proper = true end
set_defaults_and_check_bad_indicators( data )
check_indicators_match_lemma( data )
end
local function detect_all_indicator_specs( alternant_multiword_spec )
local is_multiword = #alternant_multiword_spec.alternant_or_word_specs > 1
iut.map_word_specs( alternant_multiword_spec, function( data )
detect_indicator_spec( data )
data.multiword = is_multiword
end )
end
local propagate_multiword_properties
local function propagate_alternant_properties( alternant_spec, property, mixed_value, nouns_only )
local seen_property
for _, multiword_spec in ipairs( alternant_spec.alternants ) do
propagate_multiword_properties( multiword_spec, property, mixed_value, nouns_only )
if seen_property == nil then
seen_property = multiword_spec
elseif multiword_spec and seen_property ~= multiword_spec then
seen_property = mixed_value
end
end
alternant_spec = seen_property
end
propagate_multiword_properties = function( multiword_spec, property, mixed_value, nouns_only )
local seen_property = nil
local last_seen_nounal_pos = 0
local word_specs = multiword_spec.alternant_or_word_specs or multiword_spec.word_specs
for i = 1, #word_specs do
local is_nounal
if word_specs.alternants then
propagate_alternant_properties( word_specs, property, mixed_value )
is_nounal = not not word_specs
elseif nouns_only then
is_nounal = not word_specs.adj
else
is_nounal = not not word_specs
end
if is_nounal then
if not word_specs then
error( "Internal error: noun-type word spec without " .. property .. " set" )
end
for j = last_seen_nounal_pos + 1, i - 1 do
word_specs = word_specs or word_specs
end
last_seen_nounal_pos = i
if seen_property == nil then
seen_property = word_specs
elseif seen_property ~= word_specs then
seen_property = mixed_value
end
end
end
if last_seen_nounal_pos > 0 then
for i = last_seen_nounal_pos + 1, #word_specs do
word_specs = word_specs or word_specs
end
end
multiword_spec = seen_property
end
local function propagate_properties_downward( alternant_multiword_spec, property, default_propval )
local propval1 = alternant_multiword_spec or default_propval
for _, alternant_or_word_spec in ipairs( alternant_multiword_spec.alternant_or_word_specs ) do
local propval2 = alternant_or_word_spec or propval1
if alternant_or_word_spec.alternants then
for _, multiword_spec in ipairs( alternant_or_word_spec.alternants ) do
local propval3 = multiword_spec or propval2
for _, word_spec in ipairs( multiword_spec.word_specs ) do
local propval4 = word_spec or propval3
if propval4 == "mixed" then
error( "Attempt to assign mixed " .. property .. " to word" )
end
word_spec = propval4
end
end
else
if propval2 == "mixed" then
error( "Attempt to assign mixed " .. property .. " to word" )
end
alternant_or_word_spec = propval2
end
end
end
local function propagate_properties( alternant_multiword_spec, property, default_propval, mixed_value )
propagate_multiword_properties( alternant_multiword_spec, property, mixed_value, "nouns only" )
propagate_multiword_properties( alternant_multiword_spec, property, mixed_value, false )
propagate_properties_downward( alternant_multiword_spec, property, default_propval )
end
local function normalize_all_lemmas( alternant_multiword_spec )
iut.map_word_specs( alternant_multiword_spec, function( data )
data.orig_lemma = data.lemma
data.orig_lemma_no_links = m_links.remove_links( data.lemma )
data.lemma = data.orig_lemma_no_links
end )
end
local function compute_categories_and_annotation( alternant_multiword_spec )
local cats = {}
local function insert( cattype )
m_table.insertIfNot( cats, "Mongolian " .. cattype )
end
if alternant_multiword_spec.pos == "noun" then
if alternant_multiword_spec.number == "sg" then
insert( "uncountable nouns" )
elseif alternant_multiword_spec.number == "pl" then
insert( "pluralia tantum" )
end
end
local annotation
if alternant_multiword_spec.manual then
alternant_multiword_spec.annotation =
alternant_multiword_spec.number == "sg" and "sg-only" or
alternant_multiword_spec.number == "pl" and "pl-only" or
alternant_multiword_spec.number == "spos" and "sg poss" or
alternant_multiword_spec.number == "cpos" and "col poss" or
""
else
local annparts = {}
local bor = nil
local decl = {}
local irregs = {}
local stems = {}
local reducible = nil
local vh = {}
local function do_word_spec( data )
m_table.insertIfNot( vh, vowelharmony( data.lemma, data ).Cyrl.a )
insert( vowelharmony( data.lemma, data ).Cyrl.a .. "-harmonic nouns" )
if data.decl == "r" then
m_table.insertIfNot( decl, "regular" )
insert( "regular declension nouns" )
elseif data.decl == "n" then
m_table.insertIfNot( decl, "hidden-n" )
insert( "hidden-n declension nouns" )
elseif data.decl == "g" then
m_table.insertIfNot( decl, "hidden-g" )
insert( "hidden-g declension nouns" )
end
if data.bor then bor = true end
--if voweldeletion( data.lemma, data ) ~= data.lemma then reducible = true end
end
local key_entry = alternant_multiword_spec.first_noun or 1
if #alternant_multiword_spec.alternant_or_word_specs >= key_entry then
local alternant_or_word_spec = alternant_multiword_spec.alternant_or_word_specs
if alternant_or_word_spec.alternants then
for _, multiword_spec in ipairs( alternant_or_word_spec.alternants ) do
key_entry = multiword_spec.first_noun or 1
if #multiword_spec.word_specs >= key_entry then
do_word_spec( multiword_spec.word_specs )
end
end
else
do_word_spec( alternant_or_word_spec )
end
end
if alternant_multiword_spec.pos == "proper noun" then
table.insert( annparts, "proper" )
elseif alternant_multiword_spec.number == "sg" then
table.insert( annparts, "sg-only" )
elseif alternant_multiword_spec.number == "pl" then
table.insert( annparts, "pl-only" )
elseif alternant_multiword_spec.number == "spos" then
table.insert( annparts, "sg poss" )
elseif alternant_multiword_spec.number == "cpos" then
table.insert( annparts, "col poss" )
end
if #vh > 0 then
table.insert( annparts, table.concat( vh, "/" ) .. "-harmonic" )
end
if #decl > 0 then
table.insert( annparts, table.concat( decl, "/" ) )
end
if bor then
table.insert( annparts, "borr" )
end
if reducible then
table.insert( annparts, "reduc" )
end
if #irregs > 0 then
table.insert( annparts, table.concat( irregs, " // " ) )
end
alternant_multiword_spec.annotation = table.concat( annparts, " " )
if #stems > 1 then
insert( "nouns with multiple stems" )
end
end
alternant_multiword_spec.categories = cats
end
local function combine_stem_ending( stem, ending )
return stem .. ending
end
local function show_forms( alternant_multiword_spec )
local lemmas = {}
if alternant_multiword_spec.forms.nom_sg then
for _, nom_sg in ipairs( alternant_multiword_spec.forms.nom_sg ) do
table.insert( lemmas, nom_sg.form )
end
elseif alternant_multiword_spec.forms.nom_pl then
for _, nom_pl in ipairs( alternant_multiword_spec.forms.nom_pl ) do
table.insert( lemmas, nom_pl.form )
end
end
local props = {
lemmas = lemmas,
slot_table = output_noun_slots_with_linked,
lang = lang,
canonicalize = function( form ) return form end,
include_translit = true,
footnotes = alternant_multiword_spec.footnotes,
allow_footnote_symbols = not not alternant_multiword_spec.footnotes,
}
iut.show_forms( alternant_multiword_spec.forms, props )
end
local function make_table( alternant_multiword_spec )
local forms = alternant_multiword_spec.forms
local function header( min_width )
min_width = min_width or "70"
return gsub( [===[
<div class="NavFrame" style="display:inline-block;min-width:MINWIDTHem">
<div class="NavHead" style="background:#eff7ff">{title}{annotation} </div>
<div class="NavContent">
{\op}| style="background:#f9f9f9;text-align:center;min-width:MINWIDTHem;width:100%" class="inflection-table"
|-
]===], "MINWIDTH", min_width )
end
local function reflexive( min_width, color )
min_width = min_width or "70"
color = color or "d9ebff"
return gsub( gsub( [===[|-
|{\cl}
<div class="NavFrame" min-width:MINWIDTHem">
<div class="NavHead" style="background:#COLOR">Reflexive possessive forms </div>
<div class="NavContent">
{\op}| style="background:#f9f9f9;text-align:center;min-width:MINWIDTHem;width:100%" class="inflection-table"
|-
]===], "MINWIDTH", min_width ), "COLOR", color )
end
local function add_case( case, name, sg, pl, refl )
if forms ~= "—" or forms ~= "—" then
local output = gsub( [===[|-
! style="background:#eff7ff" | NAME
]===], "NAME", name )
if sg then
if refl then
output = output .. gsub( [===[
| {CASE_sg_refl}
]===], "CASE", case )
else
output = output .. gsub( [===[
| {CASE_sg}
]===], "CASE", case )
end
end
if pl then
if refl then
output = output .. gsub( [===[
| {CASE_pl_refl}
]===], "CASE", case )
else
output = output .. gsub( [===[
| {CASE_pl}
]===], "CASE", case )
end
end
return output
else
return ""
end
end
local function template_footer()
return [===[|-
|{\cl}{notes_clause}</div></div>]===]
end
local table_spec_both = header( "45" ) .. [===[
! style="background:#d9ebff" | attributive
| colspan=2 | {attr}
|-
! style="background:#d9ebff;width:10em" |
! style="background:#d9ebff;width:17.5em" | singular / indefinite
! style="background:#d9ebff;width:17.5em" | definite plural
|-
! style="background:#eff7ff" | nominative
| {nom_sg}
| {nom_pl}
|-
! style="background:#eff7ff" | genitive
| {gen_sg}
| {gen_pl}
|-
! style="background:#eff7ff" | accusative
| {acc_sg}
| {acc_pl}
|-
! style="background:#eff7ff" | dative-locative
| {dat_loc_sg}
| {dat_loc_pl}
]===] .. add_case( "gen_dat", "genitive-dative", true, true ) .. [===[
|-
! style="background:#eff7ff" | ablative
| {abl_sg}
| {abl_pl}
]===] .. add_case( "dat_abl", "dative-ablative", true, true ) .. [===[
|-
! style="background:#eff7ff" | instrumental
| {ins_sg}
| {ins_pl}
|-
! style="background:#eff7ff" | comitative
| {com_sg}
| {com_pl}
|-
! style="background:#eff7ff" | privative
| {priv_sg}
| {priv_pl}
|-
! style="background:#eff7ff" | directive
| {dirc_sg}
| {dirc_pl}
]===] .. reflexive( "45" ) .. [===[
! style="background:#d9ebff;width:10em" |
! style="background:#d9ebff;width:17.5em" | singular / indefinite
! style="background:#d9ebff;width:17.5em" | definite plural
|-
! style="background:#eff7ff" | nominative
| {nom_sg_refl}
| {nom_pl_refl}
|-
! style="background:#eff7ff" | genitive
| {gen_sg_refl}
| {gen_pl_refl}
|-
! style="background:#eff7ff" | accusative
| {acc_sg_refl}
| {acc_pl_refl}
|-
! style="background:#eff7ff" | dative-locative
| {dat_loc_sg_refl}
| {dat_loc_pl_refl}
]===] .. add_case( "gen_dat", "genitive-dative", true, true, true ) .. [===[
|-
! style="background:#eff7ff" | ablative
| {abl_sg_refl}
| {abl_pl_refl}
]===] .. add_case( "dat_abl", "dative-ablative", true, true, true ) .. [===[
|-
! style="background:#eff7ff" | instrumental
| {ins_sg_refl}
| {ins_pl_refl}
|-
! style="background:#eff7ff" | comitative
| {com_sg_refl}
| {com_pl_refl}
|-
! style="background:#eff7ff" | privative
| {priv_sg_refl}
| {priv_pl_refl}
|-
! style="background:#eff7ff" | directive
| {dirc_sg_refl}
| {dirc_pl_refl}
|{\cl}</div></div>
{\op}| style="background:#f9f9f9;text-align:center;min-width:45em;width:100%" class="inflection-table"
|-
! style="background:#d9ebff;width:10em" | independent<br>genitive
! style="background:#d9ebff;width:17.5em" | singular / indefinite
! style="background:#d9ebff;width:17.5em" | definite plural
|-
! style="background:#eff7ff" | singular<br>possession
| {spos_indgen_sg}
| {spos_indgen_pl}
|-
! style="background:#eff7ff" | collective<br>possession
| {cpos_indgen_sg}
| {cpos_indgen_pl}
]===] .. template_footer()
local function table_spec_one( num, number )
return gsub( gsub( header( "30" ) .. [===[
! style="background:#d9ebff" | attributive
| {attr}
|-
! style="background:#d9ebff;width:10em" |
! style="background:#d9ebff;width:20em" | NUMBER
|-
! style="background:#eff7ff" | nominative
| {nom_NUM}
|-
! style="background:#eff7ff" | genitive
| {gen_NUM}
|-
! style="background:#eff7ff" | accusative
| {acc_NUM}
|-
! style="background:#eff7ff" | dative-locative
| {dat_loc_NUM}
]===] .. add_case( "gen_dat", "genitive-dative", true ) .. [===[
|-
! style="background:#eff7ff" | ablative
| {abl_NUM}
]===] .. add_case( "dat_abl", "dative-ablative", true ) .. [===[
|-
! style="background:#eff7ff" | instrumental
| {ins_NUM}
|-
! style="background:#eff7ff" | comitative
| {com_NUM}
|-
! style="background:#eff7ff" | privative
| {priv_NUM}
|-
! style="background:#eff7ff" | directive
| {dirc_NUM}
]===] .. reflexive( "30" ) .. [===[
! style="background:#d9ebff;width:10em" |
! style="background:#d9ebff;width:20em" | NUMBER
|-
! style="background:#eff7ff" | nominative
| {nom_NUM_refl}
|-
! style="background:#eff7ff" | genitive
| {gen_NUM_refl}
|-
! style="background:#eff7ff" | accusative
| {acc_NUM_refl}
|-
! style="background:#eff7ff" | dative-locative
| {dat_loc_NUM_refl}
]===] .. add_case( "gen_dat", "genitive-dative", true, nil, true ) .. [===[
|-
! style="background:#eff7ff" | ablative
| {abl_NUM_refl}
]===] .. add_case( "dat_abl", "dative-ablative", true, nil, true ) .. [===[
|-
! style="background:#eff7ff" | instrumental
| {ins_NUM_refl}
|-
! style="background:#eff7ff" | comitative
| {com_NUM_refl}
|-
! style="background:#eff7ff" | privative
| {priv_NUM_refl}
|-
! style="background:#eff7ff" | directive
| {dirc_NUM_refl}
|{\cl}</div></div>
{\op}| style="background:#f9f9f9;text-align:center;min-width:30em;width:100%" class="inflection-table"
|-
! style="background:#d9ebff;width:10em" | independent<br>genitive
! style="background:#d9ebff;width:20em" | NUMBER
|-
! style="background:#eff7ff" | singular<br>possession
| {spos_indgen_NUM}
|-
! style="background:#eff7ff" | collective<br>possession
| {cpos_indgen_NUM}
]===] .. template_footer(), "NUMBER", number ), "NUM", num )
end
local function table_spec_poss()
return header( "30" ) .. [===[
! style="background:#eff7ff;width:10em" | nominative
| style="width:20em" | {nom}
|-
! style="background:#eff7ff" | genitive
| {gen}
|-
! style="background:#eff7ff" | accusative
| {acc}
|-
! style="background:#eff7ff" | dative-locative
| {dat_loc}
|-
! style="background:#eff7ff" | ablative
| {abl}
|-
! style="background:#eff7ff" | instrumental
| {ins}
|-
! style="background:#eff7ff" | comitative
| {com}
|-
! style="background:#eff7ff" | privative
| {priv}
|-
! style="background:#eff7ff" | directive
| {dirc}
]===] .. reflexive( "30" ) .. [===[
! style="background:#eff7ff;width:10em" | nominative
| style="width:20em" | {nom_refl}
|-
! style="background:#eff7ff" | genitive
| {gen_refl}
|-
! style="background:#eff7ff" | accusative
| {acc_refl}
|-
! style="background:#eff7ff" | dative-locative
| {dat_loc_refl}
|-
! style="background:#eff7ff" | ablative
| {abl_refl}
|-
! style="background:#eff7ff" | instrumental
| {ins_refl}
|-
! style="background:#eff7ff" | comitative
| {com_refl}
|-
! style="background:#eff7ff" | privative
| {priv_refl}
|-
! style="background:#eff7ff" | directive
| {dirc_refl}
]===] .. template_footer()
end
local notes_template = [===[
<div style="width:100%;text-align:left;background:#d9ebff">
<div style="display:inline-block;text-align:left;padding-left:1em;padding-right:1em">
{footnote}
</div></div>
]===]
if alternant_multiword_spec.title then
forms.title = alternant_multiword_spec.title
else
forms.title = "Declension of <i lang=\"mn\" class=\"Cyrl\">" .. forms.lemma .. "</i>"
end
local annotation = alternant_multiword_spec.annotation or ""
if annotation == "" then
forms.annotation = ""
else
forms.annotation = " (<span style=\"font-weight:normal;font-size:small\">" .. annotation .. "</span>)"
end
local table_spec =
alternant_multiword_spec.number == "sg" and table_spec_one( "sg", "singular / indefinite" ) or
alternant_multiword_spec.number == "pl" and table_spec_one( "pl", "definite plural" ) or
alternant_multiword_spec.number == "spos" and table_spec_poss() or
alternant_multiword_spec.number == "cpos" and table_spec_poss() or
table_spec_both
forms.notes_clause = forms.footnote ~= "" and
m_string_utilities.format( notes_template, forms ) or ""
return m_string_utilities.format( table_spec, forms )
end
function export.do_generate_forms( parent_args, pos, from_headword, def )
local params = {
= { required = true, default = "хаан<r>" },
footnote = { list = true },
title = {},
pos = { default = "noun" }
}
local args = m_para.process( parent_args, params )
if not match( args, "<.*>" ) then error( "Please specify declension" ) end
local parse_props = {
parse_indicator_spec = parse_indicator_spec
}
local alternant_multiword_spec = iut.parse_inflected_text( args, parse_props )
alternant_multiword_spec.title = args.title
alternant_multiword_spec.pos = pos or args.pos
alternant_multiword_spec.footnotes = args.footnote
alternant_multiword_spec.args = args
normalize_all_lemmas( alternant_multiword_spec )
detect_all_indicator_specs( alternant_multiword_spec )
propagate_properties( alternant_multiword_spec, "number", "both", "both" )
local inflect_props = {
skip_slot = function( slot )
return skip_slot( alternant_multiword_spec.number, slot )
end,
slot_table = output_noun_slots_with_linked,
get_variants = get_variants,
inflect_word_spec = handle_derived_slots_and_overrides,
lang = lang
}
iut.inflect_multiword_or_alternant_multiword_spec( alternant_multiword_spec, inflect_props )
compute_categories_and_annotation( alternant_multiword_spec )
return alternant_multiword_spec
end
function export.show( frame )
local parent_args = frame:getParent().args or frame.args
local pos = propernoun( parent_args or "хаан" ) and "proper noun" or "noun"
local alternant_multiword_spec = export.do_generate_forms( parent_args, pos )
show_forms( alternant_multiword_spec )
return make_table( alternant_multiword_spec ) .. require( "Module:utilities" ).format_categories( alternant_multiword_spec.categories, lang )
end
function export.inflect_traditional_form( trad_form, cyrl_form, cyrl_form_args, inflection )
local parse_props = {
parse_indicator_spec = parse_indicator_spec
}
local alternant_multiword_spec = iut.parse_inflected_text( cyrl_form_args, parse_props )
local vh = vowelharmony( cyrl_form )
if alternant_multiword_spec.alternant_or_word_specs.decl == "n" then
trad_form = trad_form .. n
end
if match( inflection, "attr" ) then
trad_form = attributive( trad_form, vh )
end
if match( inflection, "|p$" ) then
trad_form = plural( trad_form, vh )
end
if match( inflection, "indgen" ) then
trad_form = genitive( trad_form, vh )
end
if match( inflection, "spos|indgen" ) then
trad_form = singular_independent_genitive( trad_form, vh )
end
if match( inflection, "cpos|indgen" ) then
trad_form = collective_independent_genitive( trad_form, vh )
end
if match( inflection, "gen" ) and not match( inflection, "indgen" ) then
trad_form = genitive( trad_form, vh )
end
if match( inflection, "acc" ) then
trad_form = accusative( trad_form, vh )
end
if match( inflection, "dat" ) then
trad_form = dative_locative( trad_form, vh )
end
if match( inflection, "abl" ) then
trad_form = ablative( trad_form, vh )
end
if match( inflection, "ins" ) then
trad_form = instrumental( trad_form, vh )
end
if match( inflection, "com" ) then
trad_form = comitative( trad_form, vh )
end
if match( inflection, "priv" ) then
trad_form = privative( trad_form, vh )
end
if match( inflection, "dirc" ) then
trad_form = directive( trad_form, vh )
end
if match( inflection, "refl" ) then
trad_form = reflexive( trad_form, vh )
end
return trad_form
end
return export