local export = {}
--[=[
Authorship: Ben Wing <benwing2>
]=]
local m_links = require("Module:links")
local iut = require("Module:inflection utilities")
local lang = require("Module:languages").getByCode("hi")
local current_title = mw.title.getCurrentTitle()
local PAGENAME = current_title.text
local u = mw.ustring.char
local rsplit = mw.text.split
local rfind = mw.ustring.find
local rmatch = mw.ustring.match
local rsubn = mw.ustring.gsub
local usub = mw.ustring.sub
-- version of rsubn() that discards all but the first return value
local function rsub(term, foo, bar)
local retval = rsubn(term, foo, bar)
return retval
end
-- vowel diacritics; don't display nicely on their own
local AA = u(0x093e)
local AI = u(0x0948)
local AU = u(0x094c)
local E = u(0x0947)
local I = u(0x093f)
local II = u(0x0940)
local O = u(0x094b)
local U = u(0x0941)
local UU = u(0x0942)
local R = u(0x0943)
local VIRAMA = u(0x094d)
local TILDE = u(0x0303)
export.diacritic_to_independent = {
[AA] = "आ", [I] = "इ", [II] = "ई", [U] = "उ", [UU] = "ऊ",
[R] = "ऋ", [E] = "ए", [AI] = "ऐ", [O] = "ओ", [AU] = "औ",
}
local diacritic_list = {}
local independent_list = {}
for dia, ind in pairs(export.diacritic_to_independent) do
table.insert(independent_list, ind)
table.insert(diacritic_list, dia)
end
export.diacritics = table.concat(diacritic_list)
export.independents = table.concat(independent_list) .. "अ"
export.vowels = export.diacritics .. export.independents
export.transliterated_diacritics = "aāãeẽiīĩoõuūũṛ" .. TILDE
-- variant codes
export.VAR1 = u(0xFFF0)
export.VAR2 = u(0xFFF1)
export.VAR3 = u(0xFFF2)
export.VAR4 = u(0xFFF3)
export.VAR5 = u(0xFFF4)
export.VAR6 = u(0xFFF5)
export.var_code_c = "[" .. export.VAR1 .. export.VAR2 .. export.VAR3 .. export.VAR4 .. export.VAR5 .. export.VAR6 .. "]"
export.not_var_code_c = "[^" .. export.VAR1 .. export.VAR2 .. export.VAR3 .. export.VAR4 .. export.VAR5 .. export.VAR6 .. "]"
export.index_to_variant_code = {
[1] = export.VAR1,
[2] = export.VAR2,
[3] = export.VAR3,
[4] = export.VAR4,
[5] = export.VAR5,
[6] = export.VAR6,
}
function export.split_term_respelling(term)
if rfind(term, "//") then
local split = rsplit(term, "//")
if #split ~= 2 then
error("Term with respelling should have only one // in it: " .. term)
end
return unpack(split)
else
return term, nil
end
end
function export.transliterate_respelling(phon)
if not phon then
return nil
end
local hindi_range = "[ऀ-ॿ*]" -- 0x0900 to 0x097f; include *, which is a translit signal
if rfind(phon, "^%-?" .. hindi_range) then
return rsub((lang:transliterate(phon)), "%.", "")
end
return phon -- already transliterated
end
function export.add_form(base, stem, translit_stem, slot, ending, footnotes, link_words, double_word)
if not ending then
return
end
local function combine_stem_ending(stem, ending)
local result
if ending == "" then
result = stem
else
if rfind(stem, VIRAMA .. "$") and rfind(base.lemma, VIRAMA .. "$") then
stem = rsub(stem, VIRAMA .. "$", "")
end
if stem == "" or rfind(stem, "[" .. export.vowels .. "]$") then
-- A diacritic at the beginning of the ending should be converted to its independent form
-- if the stem does not end in a consonant.
if rfind(ending, "^[" .. export.diacritics .. "]") then
local ending_first = usub(ending, 1, 1)
ending = (export.diacritic_to_independent[ending_first] or ending_first) .. usub(ending, 2)
-- Diacritic e goes above the line and requires anusvara, but independent e does not
-- go above the line and prefers chandrabindu in endings.
ending = rsub(ending, "एं", "एँ")
end
end
-- Don't convert independent letters to diacritics after consonants because of cases like मई
-- where the independent letter belongs after the consonant.
result = stem .. ending
end
if link_words then
-- Add links around the words.
result = "[[" .. rsub(result, " ", "]] [[") .. "]]"
end
if double_word then
-- hack to support the progressive form of verbs, which is e.g. करते-करते
return result .. "-" .. result
else
return result
end
end
local function combine_stem_ending_tr(stem, ending)
local result
if not ending or ending == "" then
result = stem
else
-- When adding a non-null ending, remove final '-a' from the stem, but only
-- if the transliterated lemma also ended in '-a'. This way, a noun like
-- पुनश्च transliterated 'punaśca' "postscript" gets oblique plural transliterated
-- 'punaścõ' with dropped '-a', but मई transliterated 'maī' "May" with
-- transliterated stem 'ma' and ending singular ending '-ī' doesn't get the
-- '-a' dropped. A third case we need to handle correctly is इंटरव्यू "interview";
-- if we truncate the final ू '-ū' and then transliterate, we get 'iṇṭarvya'
-- with extra '-a' that may appear in the transliteration if we're not careful.
--
-- HACK! Handle प्रातः correctly by checking specially for lemma_translit ending
-- in -a or -aḥ and ending starting with a vowel. The proper way to do this
-- correctly that handles all of the above cases requires access to the original
-- (Devanagari) ending, and checks to see if the stem ends in '-a' and the ending
-- begins with a Devanagari diacritic; in this case, it's correct to elide the '-a'.
if base.lemma_translit and rfind(stem, "a$") and rfind(base.lemma_translit, "aḥ?$") and
rfind(ending, "^[" .. export.transliterated_diacritics .. "]") then
stem = rsub(stem, "a$", "")
end
result = stem .. ending
end
if double_word then
-- hack to support the progressive form of verbs, which is e.g. करते-करते
return result .. "-" .. result
else
return result
end
end
footnotes = iut.combine_footnotes(base.footnotes, footnotes)
local ending_obj = iut.combine_form_and_footnotes(ending, footnotes)
if translit_stem then
stem = {form = stem, translit = translit_stem}
end
iut.add_forms(base.forms, slot, stem, ending_obj, combine_stem_ending, lang,
combine_stem_ending_tr)
end
function export.strip_ending_from_stem(stem, translit_stem, ending)
local new_stem = rmatch(stem, "^(.*)" .. ending .. "$")
if not new_stem then
error("Internal error: Lemma or stem " .. stem .. " should end in " .. ending)
end
local new_translit_stem
if translit_stem then
local ending_translit = (lang:transliterate(ending))
new_translit_stem = rmatch(translit_stem, "^(.*)" .. ending_translit .. "$")
if not new_translit_stem then
error("Unable to strip ending " .. ending .. " (transliterated " .. ending_translit .. ") from transliteration " .. translit_stem)
end
end
return new_stem, new_translit_stem
end
function export.strip_ending(base, ending)
return export.strip_ending_from_stem(base.lemma, base.lemma_translit, ending)
end
-- Normalize all lemmas, splitting out phonetic respellings and substituting
-- the pagename for blank lemmas. Set `lemma_translit` to the transliteration of the
-- respelling, or (if `always_transliterate` is given) to the transliteration of the
-- lemma. `always_transliterate` should be specified for nouns and adjectives, where the
-- lemma transliteration should be carried over to all remaining forms (hence since अंकल
-- is transliterated 'aṅkal', the oblique plural अंकलों should be 'aṅkalõ' not #'aṅklõ',
-- the default transliteration). But it should not be specified for verbs, where this
-- carry-over doesn't apply: even though उगालना has transliteration 'ugalnā', the
-- perfective participle उगला has default transliteration 'uglā' not the carry-over
-- transliteration #'ugalā'.
function export.normalize_all_lemmas(alternant_multiword_spec, always_transliterate)
iut.map_word_specs(alternant_multiword_spec, function(base)
base.lemma, base.phon_lemma = export.split_term_respelling(base.lemma)
if base.lemma == "" then
base.lemma = PAGENAME
end
base.orig_lemma = base.lemma
base.orig_lemma_no_links = m_links.remove_links(base.lemma)
base.lemma = base.orig_lemma_no_links
if base.phon_lemma then
base.lemma_translit = export.transliterate_respelling(base.phon_lemma)
elseif always_transliterate then
base.lemma_translit = (lang:transliterate(base.lemma))
end
end)
end
--[=[
Remove redundant translit. We need to do all declension of nouns and adjectives using
manual translit because declined forms of nouns like अचकन "jacket" and कालाधन
"black money" may need manual translit, even though the base form itself doesn't
need manual translit. For example, अचकन has default translit ''ackan'', which is
correct, but the oblique plural अचकनों has default translit ''acaknõ'', which is
incorrect (correct is ''ackanõ'', with stem translit as in the base). In general,
such words need manual translit that forces the stem of the inflected form to have
the same translit as the stem of the base form. We want to remove redundant
manual translit so that accelerator-generated entries don't have unnecessary
manual translit in them. Finally, we need to remove redundant manual translit at
the very end, not as we decline each part of a multiword expression (which we
used to do), because of cases like कालाधन, which declines as if written काला धन.
Hence it has oblique plural कालेधनों, which has incorrect default translit
''kaledhnõ'' instead of correct ''kaledhanõ'', even though the individual parts
काले and धनों both have correct default translits.
]=]
function export.remove_redundant_translit(alternant_multiword_spec)
for slot, forms in pairs(alternant_multiword_spec.forms) do
alternant_multiword_spec.forms[slot] = iut.map_forms(forms, function(form, translit)
if translit and (lang:transliterate(m_links.remove_links(form))) == translit then
return form, nil
else
return form, translit
end
end)
end
end
function export.get_variants(form)
return rsub(form, export.not_var_code_c, "")
end
function export.remove_variant_codes(form)
return rsub(form, export.var_code_c, "")
end
-- Add variant codes to all slots with more than one form. The intention of variant
-- codes is to prevent there being N^2 slot variants in a verb like [[हिलना-डुलना]] in
-- slots that normally have N variants. Rather than combining all variants of [[हिलना]]
-- with all variants of [[डुलना]] for the given slot, we only want to combine parallel
-- variants. We implement this by tagging each variant with a "variant code" character
-- and rejecting combinations with mismatching variant code characters.
function export.add_variant_codes(base)
for slot, forms in pairs(base.forms) do
if #forms > 1 then
local index = 0
base.forms[slot] = iut.map_forms(forms, function(form, translit)
index = index + 1
local varcode = export.index_to_variant_code[index]
if not varcode then
error("Internal error: Encountered too many variants (" .. #forms .. "), no more variant codes available")
end
return form .. varcode, translit
end)
end
end
end
return export