local m_links = require('Module:links')
local export = {}
local lang = require("Module:languages").getByCode("la")
-- A wrapper function allowing the contents of this module to be called from
-- templates. For example, '{{#invoke:la-utilities|main|strip_macrons|mȳthos}}'
-- produces 'mythos'.
function export.main(frame)
if(frame.args[1] == 'strip_macrons') then
return lang:makeEntryName(frame.args[2])
end
if type(p[frame.args[1]]) == 'function' then
return p[frame.args[1]](frame.args[2], frame.args[3])
else
return p[frame.args[1]][frame.args[2]]
end
end
-- public domain
-- via http://snippets.luacode.org/?p=snippets/Check_string_ends_with_other_string_74
local function endswith(s, send)
return #s >= #send and s:find(send, #s-#send+1, true) and true or false
end
-- helper function
-- add suffixes to a stem based on which form is chosen.
-- parameter baseform is used for 2nd declension words (unused for 1st declension). Replaces 'W'.
-- num = 'sg' 'pl' 'both' or nil (nil is same as 'both')
-- loc = true or false (to add locative)
function export.decline(form, stem, baseform, num, loc)
local suffix = {
['1st'] = {
['title']='[[Appendix:Latin first declension|First declension]].',
['nom_sg']='Xa', ['gen_sg']='Xae', ['dat_sg']='Xae', ['acc_sg']='Xam', ['abl_sg']='Xā', ['voc_sg']='Xa',
['nom_pl']='Xae', ['gen_pl']='Xārum', ['dat_pl']='Xīs', ['acc_pl']='Xās', ['abl_pl']='Xīs', ['voc_pl']='Xae',
['if_loc'] = { ['title'] = '[[Appendix:Latin first declension|First declension]] with locative.',
['loc_sg']='Xae', ['loc_pl']='Xīs' } },
['1st-abus'] = { ['stem']='X',
['title']='[[Appendix:Latin first declension|First declension]] with dative/ablative plural in {{m|la||-ābus}}.',
['nom_sg']='Xa', ['gen_sg']='Xae', ['dat_sg']='Xae', ['acc_sg']='Xam', ['abl_sg']='Xā', ['voc_sg']='Xa',
['nom_pl']='Xae', ['gen_pl']='Xārum', ['dat_pl']='Xābus', ['acc_pl']='Xās', ['abl_pl']='Xābus', ['voc_pl']='Xae' },
['1st-Greek'] = { ['stem']='X',
['title']='[[Appendix:Latin first declension|First declension]], Greek type.',
['nom_sg']='Xē', ['gen_sg']='Xēs', ['dat_sg']='Xae', ['acc_sg']='Xēn', ['abl_sg']='Xē', ['voc_sg']='Xē',
['nom_pl']='Xae', ['gen_pl']='Xārum', ['dat_pl']='Xīs', ['acc_pl']='Xās', ['abl_pl']='Xīs', ['voc_pl']='Xae' },
['1st-Greek-Ma'] = {
['title']='[[Appendix:Latin first declension|First declension]], Greek type masculine in {{m|la||-ās}}.',
['nom_sg']='Xās', ['gen_sg']='Xae', ['dat_sg']='Xae', ['acc_sg']='Xān', ['abl_sg']='Xā', ['voc_sg']='Xā',
['nom_pl']='Xae', ['gen_pl']='Xārum', ['dat_pl']='Xīs', ['acc_pl']='Xās', ['abl_pl']='Xīs', ['voc_pl']='Xae' },
['1st-Greek-Me'] = {
['title']='[[Appendix:Latin first declension|First declension]], Greek type masculine in {{m|la||-ēs}}.',
['nom_sg']='Xēs', ['gen_sg']='Xae', ['dat_sg']='Xae', ['acc_sg']='Xēn', ['abl_sg']='Xē', ['voc_sg']='Xē',
['nom_pl']='Xae', ['gen_pl']='Xārum', ['dat_pl']='Xīs', ['acc_pl']='Xās', ['abl_pl']='Xīs', ['voc_pl']='Xae' },
['1st-am'] = {
['title']='[[Appendix:Latin first declension|First declension]] with nominative singular in {{m|la||-am}}.',
['nom_sg']='Xam', ['gen_sg']='Xae', ['dat_sg']='Xae', ['acc_sg']='Xam', ['abl_sg']='Xā', ['voc_sg']='Xam',
['nom_pl']='Xae', ['gen_pl']='Xārum', ['dat_pl']='Xīs', ['acc_pl']='Xās', ['abl_pl']='Xīs', ['voc_pl']='Xae' },
['2nd'] = {
['title']='[[Appendix:Latin second declension|Second declension]].',
['nom_sg']='Xus', ['gen_sg']='Xī', ['dat_sg']='Xō', ['acc_sg']='Xum', ['abl_sg']='Xō', ['voc_sg']='Xe',
['nom_pl']='Xī', ['gen_pl']='Xōrum', ['dat_pl']='Xīs', ['acc_pl']='Xōs', ['abl_pl']='Xīs', ['voc_pl']='Xī',
['if_loc'] = { ['title'] = '[[Appendix:Latin second declension|Second declension]] with locative.',
['loc_sg']='Xī', ['loc_pl']='Xīs' } },
['2nd-N'] = {
['title']='[[Appendix:Latin second declension|Second declension]] neuter.',
['nom_sg']='Xum', ['gen_sg']='Xī', ['dat_sg']='Xō', ['acc_sg']='Xum', ['abl_sg']='Xō', ['voc_sg']='Xum',
['nom_pl']='Xa', ['gen_pl']='Xōrum', ['dat_pl']='Xīs', ['acc_pl']='Xa', ['abl_pl']='Xīs', ['voc_pl']='Xa',
['if_loc'] = { ['title'] = '[[Appendix:Latin second declension|Second declension]] neuter with locative.',
['loc_sg']='Xī', ['loc_pl']='Xīs' } },
['2nd-er'] = {
['title']='[[Appendix:Latin second declension|Second declension]], nominative singular in {{m|la||-er}}.',
['nom_sg']='W', ['gen_sg']='Xī', ['dat_sg']='Xō', ['acc_sg']='Xum', ['abl_sg']='Xō', ['voc_sg']='W', ['voc_sg2']='Xe',
['nom_pl']='Xī', ['gen_pl']='Xōrum', ['dat_pl']='Xīs', ['acc_pl']='Xōs', ['abl_pl']='Xīs', ['voc_pl']='Xī',
['if_loc'] = { ['title'] = '[[Appendix:Latin second declension|Second declension]] with locative.',
['loc_sg']='Xī', ['loc_pl']='Xīs' } },
['2nd-Greek'] = {
['title']='[[Appendix:Latin second declension|Second declension]], Greek type',
['nom_sg']='Xos', ['gen_sg']='Xī', ['dat_sg']='Xō', ['acc_sg']='Xon', ['acc_sg2']= 'Xum', ['abl_sg']='Xō', ['voc_sg']='Xe',
['nom_pl']='Xī', ['gen_pl']='Xōrum', ['dat_pl']='Xīs', ['acc_pl']='Xōs', ['abl_pl']='Xīs', ['voc_pl']='Xī' },
['2nd-N-Greek'] = {
['title']='[[Appendix:Latin second declension|Second declension]] neuter, Greek type',
['nom_sg']='Xon', ['gen_sg']='Xī', ['dat_sg']='Xō', ['acc_sg']='Xon', ['abl_sg']='Xō', ['voc_sg']='Xon',
['nom_pl']='Xa', ['gen_pl']='Xōrum', ['dat_pl']='Xīs', ['acc_pl']='Xa', ['abl_pl']='Xīs', ['voc_pl']='Xa' },
['2nd-ius'] = { -- todo: footnote for gen_sg
['title']='[[Appendix:Latin second declension|Second declension]], nominative singular in {{m|la||-ius}}.',
['nom_sg']='Xïus', ['gen_sg']='Xïī', ['dat_sg']='Xiō', ['acc_sg']='Xium', ['abl_sg']='Xiō', ['voc_sg']='Xī',
['nom_pl']='Xiī', ['gen_pl']='Xiōrum', ['dat_pl']='Xiīs', ['acc_pl']='Xiōs', ['abl_pl']='Xiīs', ['voc_pl']='Xiī'},
['2nd-N-us'] = {
['title']='[[Appendix:Latin second declension|Second declension]] neuter with nominative/accusative/vocative in {{m|la||-us}}.',
['nom_sg']='Xus', ['gen_sg']='Xī', ['dat_sg']='Xō', ['acc_sg']='Xus', ['abl_sg']='Xō', ['voc_sg']='Xus' } }
local dtable = suffix[form]
if (dtable == nil) then error ('form missing: ' .. form ) end
dtable['stem'] = 'X'
dtable['no_include'] = { ['if_loc']=true, ['table']=true, ['no_include']=true, ['no_expand']=true }
dtable['no_expand'] = { ['title']=true, ['if_loc']=true, ['table']=true, ['no_include']=true, ['no_expand']=true }
if loc == true then
if (not dtable['if_loc']) then
error('locative cannot be used here')
end
for key, value in pairs(dtable['if_loc']) do
dtable[key] = value
end
end
for key, value in pairs(dtable) do
if (not dtable['no_expand'][key]) then
-- if (value == nil) then error('value missing for key: ' .. key ) end
-- if (stem == nil) then error('value missing for stem: ' .. stem ) end
dtable[key] = value:gsub('X', stem)
if (baseform ~= nil) then
dtable[key] = dtable[key]:gsub('W', baseform)
end
end
end
if num == 'sg' or num == 'pl' then
-- todo: include sg/pl in title
dtable['table']='la-decl-noun-table-single'
dtable['num'] = num
elseif num == nil and loc == true then
-- default to num=sg (if not desired, num=pl or num=both should be set by calling method)
dtable['table']='la-decl-noun-table-single'
dtable['num'] = 'sg' -- todo: check dtable['num'] isn't already filleda
else
dtable['table']='la-decl-noun-table'
end
-- not really needed now: values for expanding into old templates, which didn't have full table templates: (la-decl-1st-loc, la-decl-1st-p-loc)
--dtable[1] = export.strip_macrons(stem)
--dtable[2] = stem
return dtable
end
-- turn certain values of a declension table into links
-- helper function
function export.linkify(dtable)
local linkifable = {
['nom-sg']=true, ['gen-sg']=true, ['dat-sg']=true,
['acc-sg']=true, ['abl-sg']=true, ['voc-sg']=true, ['loc-sg']=true,
['nom-pl']=true, ['gen-pl']=true, ['dat-pl']=true, ['acc-pl']=true,
['abl-pl']=true, ['voc-pl']=true, ['loc-pl']=true
}
for key, value in pairs(dtable) do
if linkifable[key] then
dtable[key] = m_links.full_link(value, nil, lang)
end
end
end
-- Build a declension table, for a first declension Latin word.
-- See export.firstDeclensionTable for usage
function export.firstDeclensions(word, num, loc)
-- the two exceptional words which won't work automatically:
if word == 'dea' then word = 'deābus' elseif word == 'filia' then word = 'filiābus' end
local suffixes = {['a']='1st', ['ābus']='1st-abus', ['ē']='1st-Greek',
['ās']='1st-Greek-Ma', ['ēs']='1st-Greek-Me', ['am']='1st-am'
-- ['ae']='1st-pl', -- handle manually
-- ['īs']='1st-loc-pl' -- handle manually
}
local stem
word = mw.text.decode(word) -- sanitize
if num ~= nil and num == '{{{num}}}' then
num = nil -- defaults to 'both' (unless it's a locative)
elseif num == 'p' then
num = 'pl'
elseif num == 's' then
num = 'sg'
end
local useLoc = false
if loc ~= nil and (loc == 'y' or loc == '1') then
useLoc = true
end
-- special cases: check if word ends in -īs or -ae
if endswith(word, 'īs') and (num == nil or num == 'pl') then
local key = 'īs'
stem = word:sub(0, -(key:len())-1 )
return export.decline('1st', stem, nil, 'pl', true)
elseif endswith(word, 'ae') then
stem = word:sub(0, -3)
if (num == nil or num == 'pl') then
-- treat as plural nominative
return export.decline('1st', stem, nil, 'pl', useLoc)
elseif num == 'sg' then
-- treat as locative.
-- todo: tell the user to -loc template and -a word instead
return export.decline('1st', stem, nil, 'sg', true)
else
-- user has requested num=both.
return export.decline('1st', stem, nil, num, useLoc)
end
end
-- default case: uses 'suffixes' table to choose declension template
for key,value in pairs(suffixes) do
if endswith(word, key) then
stem = word:sub(0, -(key:len())-1)
return export.decline(value, stem, nil, num, useLoc)
end
end
-- error: Suffix not found. List allowed endings.
local allowed_endings = ''
for key,value in pairs(suffixes) do
allowed_endings = allowed_endings .. '-' .. key .. ' '
end
error('Parameter 1 (' .. word .. ') is not a Latin word or does not have an allowed word ending: ' .. allowed_endings .. '. Please see [[Template:la-decl-first]] for more information.', 2)
end
-- Build a declension table, for a second declension Latin word.
function export.secondDeclensions(word, word2, num, loc)
local suffixes = {['ius']='2nd-ius', ['us']='2nd', ['um']='2nd-N',
['r']='2nd-er', -- ignored except by error message
['os']='2nd-Greek', ['on']='2nd-N-Greek',
['ī']='2nd', ['a']='2nd-N'
-- -loc -N-loc -N-us
}
local stem
word = mw.text.decode(word) -- sanitize
if word2 ~= nil and (word2 == '' or word2 == '{{{2}}}') then
word2 = nil
end
if (word2 ~= nil) then word2 = mw.text.decode(word2) end
-- TODO: too much copy/paste code
if num ~= nil and num == '{{{num}}}' then
num = nil -- defaults to 'both' (unless it's a locative)
elseif num == 'p' then
num = 'pl'
elseif num == 's' then
num = 'sg'
end
local useLoc = false
if loc ~= nil and (loc == 'y' or loc == '1') then
useLoc = true
end
-- special case: locative with both sg and pl requested
if (useLoc) and (num == nil) then
if endswith(word, 'us') then num = 'sg'
elseif endswith(word, 'um') then num = 'sg'
elseif endswith(word, 'ī') then num = 'pl'
elseif endswith(word, 'a') then num = 'pl' end
end
-- special case:
if endswith(word, 'us') and (useLoc == false) and (num == 'sg') then
local key = 'us'
stem = word:sub(0, -(key:len())-1)
return export.decline('2nd-N-us', stem, nil, 'sg', useLoc)
end
-- special csae: -r words
if endswith(word, 'r') then
if (word2 == nil or word2:len() < 2) then
stem = word
return export.decline('2nd-er', stem, word, num, useLoc)
else
local key = 'ī'
stem = word2:sub(0, -(key:len())-1 )
return export.decline('2nd-er', stem, word, num, useLoc)
end
end
-- -- default case: uses 'suffixes' table to choose declension template
for key,value in pairs(suffixes) do
if endswith(word, key) then
stem = word:sub(0, -(key:len())-1)
return export.decline(value, stem, nil, num, useLoc)
end
end
-- error: Suffix not found. List allowed endings.
local allowed_endings = ''
for key,value in pairs(suffixes) do
allowed_endings = allowed_endings .. '-' .. key .. ' '
end
error('Parameter 1 (' .. word .. ') is not a Latin word or does not have an allowed word ending: ' .. allowed_endings .. '. Please see [[Template:la-decl-second]] for more information.', 2)
end
-- Create a declension table for a Latin word in the first declension.
-- called by [[Template:la-decl-first]]
-- Parameters:
-- 1 = the Latin word, with macrons. Usually the singular nominative form. The exceptions are:
-- a) if the word allows a locative form, give that the singular plural form: (ending in -ae), unless it only plural, then use that form (-īs). use loc=s for only singular (hides the plural column)
-- b) the word allows an -ābus suffix, in which case give that form
-- loc=s = singular locative form (or use -ae ending for parameter 1)
-- loc=pl = plural locative form (or use -īs ending for parameter 1)
-- todo: replace loc parameter with num parameter, and make it work for all inputs
function export.firstDeclensionTable(frame)
local NAMESPACE = mw.title.getCurrentTitle().nsText
local word = frame.args[1]
local num = frame.args['num']
local loc = frame.args['loc']
if word == nil or word == '' or word == '{{{1}}}' then
if NAMESPACE == "Template" then
word = "-a"
else
-- use page name
-- error('Missing argument. 1 required (a Latin word). See [[Template:la-decl-first]] for usage information.')
word = mw.title.getCurrentTitle().text
end
end
local decl = export.firstDeclensions(word, num, loc)
-- export.linkify(decl) -- not strictly needed, as done by Template:l now.
if decl['title'] ~= nil then
decl['title'] = frame:preprocess(decl['title']) -- process any templates contained within the title parameter
end
local tablename = decl['table']
for key, value in pairs(decl['no_include']) do
decl[key] = nil
end
return frame:expandTemplate{title = tablename, args = decl}
end
-- Create a declension table for a Latin word in the second declension.
-- called by [[Template:la-decl-second]]
function export.secondDeclensionTable(frame)
local NAMESPACE = mw.title.getCurrentTitle().nsText
local word = frame.args[1]
local word2 = frame.args[2]
local num = frame.args['num']
local loc = frame.args['loc']
if word == nil or word == '' or word == '{{{1}}}' then
if NAMESPACE == "Template" then
word = "-us"
else
-- use page name
-- error('Missing argument. 1 required (a Latin word). See [[Template:la-decl-first]] for usage information.')
word = mw.title.getCurrentTitle().text
end
end
local decl = export.secondDeclensions(word, word2, num, loc)
-- too much copy/paste below here (TODO: make a function)
if decl['title'] ~= nil then
decl['title'] = frame:preprocess(decl['title']) -- process any templates contained within the title parameter
end
local tablename = decl['table']
for key, value in pairs(decl['no_include']) do
decl[key] = nil
end
return frame:expandTemplate{title = tablename, args = decl}
end
-- Create a declension table for a word.
-- Parameters:
-- 1 = which declension: first, second, third, fourth, fifth (always first
-- 2 = the Latin word, with macrons. Usually the singular nominative form. The exceptions are:
-- a) for first declension words which allow a locative form, give that form (ending in -ae or -īs). Or use singular nominative and loc=s, or loc=pl (as for other declensions)
-- b) the word allows an -ābus suffix, in which case give that form
-- 3 = the stem (not used for first declension words)
-- loc=s = singular locative form
-- loc=pl = plural locative form
function export.declensionTable(frame)
-- TODO
end
function export.strip_macrons(frame)
return lang:makeEntryName(frame.args[1])
end
local patterns_override = {
["tūdō"] = "tūdin",
["is"] = "",
["āns"] = "ant",
["ēns"] = "ent",
["ōns"] = "ont",
["ceps"] = "cipit",
["us"] = "or",
["ex"] = "ic",
}
local patterns = {
["ma"] = "mat",
["e"] = "",
["men"] = "min",
["er"] = "r",
["or"] = "ōr",
["ō"] = "ōn",
["s"] = "t",
["x"] = "c",
}
function export.make_stem2(stem)
for key,val in pairs(patterns_override) do
if mw.ustring.match(stem,key.."$") then
stem = mw.ustring.gsub(stem,key.."$",val)
require('Module:debug').track("la-utilities/"..key)
return stem
end
end
for key,val in pairs(patterns) do
if mw.ustring.match(stem,key.."$") then
stem = mw.ustring.gsub(stem,key.."$",val)
require('Module:debug').track("la-utilities/"..key)
return stem
end
end
require('Module:debug').track("la-utilities")
return stem
end
return export