local m_links = require("Module:links")
local m_utilities = require("Module:utilities")
local ar_translit = require("Module:ar-translit")
local m_headword = require("Module:headword")
local m_languages = require("Module:languages")
local export = {}
local lang = m_languages.getByCode("ar")
local ar = lang
local sc = require("Module:scripts").getByCode("Arab")
local rfind = mw.ustring.find
local rmatch = mw.ustring.match
local rsubn = mw.ustring.gsub
local rsplit = mw.text.split
local u = mw.ustring.char
local consonants = ""
local function ine(x) -- If Not Empty
if x == "" then
return nil
else
return x
end
end
-- version of rsubn() that discards all but the first return value
function rsub(term, foo, bar)
local retval = rsubn(term, foo, bar)
return retval
end
-- synthesize a frame so that exported functions meant to be called from
-- templates can be called from the debug console.
function debug_frame(parargs, args)
return {args = args, getParent = function() return {args = parargs} end}
end
function export.catfix()
return m_utilities.catfix(lang, sc)
end
--------------------------- hamza processing ------------------------------
-- hamza variants
local HAMZA = u(0x0621) -- hamza on the line (stand-alone hamza) = ء
local HAMZA_ON_ALIF = u(0x0623)
local HAMZA_ON_WAW = u(0x0624)
local HAMZA_UNDER_ALIF = u(0x0625)
local HAMZA_ON_YA = u(0x0626)
local HAMZA_ANY = ""
local HAMZA_PH = u(0xFFF0) -- hamza placeholder
-- diacritics
local A = u(0x064E) -- fatḥa
local AN = u(0x064B) -- fatḥatān (fatḥa tanwīn)
local U = u(0x064F) -- ḍamma
local UN = u(0x064C) -- ḍammatān (ḍamma tanwīn)
local I = u(0x0650) -- kasra
local IN = u(0x064D) -- kasratān (kasra tanwīn)
local SK = u(0x0652) -- sukūn = no vowel
local SH = u(0x0651) -- šadda = gemination of consonants
local DAGGER_ALIF = u(0x0670)
local DIACRITIC_ANY_BUT_SH = ""
-- Pattern matching short vowels
local AIU = ""
-- Pattern matching any diacritics that may be on a consonant
local DIACRITIC = SH .. "?" .. DIACRITIC_ANY_BUT_SH
-- various letters and signs
local ALIF = u(0x0627) -- ʾalif = ا
local AMAQ = u(0x0649) -- ʾalif maqṣūra = ى
local AMAD = u(0x0622) -- ʾalif madda = آ
local WAW = u(0x0648) -- wāw = و
local YA = u(0x064A) -- yā = ي
local function link(term, tr, gloss, face, alt)
if word == "" or word == "—" then
return word
else
return m_links.full_link( { term = term, alt = alt, lang = lang, tr = tr, sc = sc, gloss = gloss }, face )
end
end
local function hamzaError(rootTable, output)
for i, letter in pairs(rootTable) do
if not rfind(letter, consonants) then
if rfind(letter, "") then
table.insert(output, '<span class="previewonly" style="font-size: small;"></span>')
require("Module:debug").track("ar-root/hamza-error") -- ]
else
error(letter .. ", the " .. ordinal .. " letter in the category name, is not a consonant.")
end
end
end
end
local function validateRoot(rootTable, joined_root)
if type(rootTable) ~= "table" then
error("rootTable is not a table", 2)
end
for i, letter in ipairs(rootTable) do
if mw.ustring.len(letter) > 1 then
error('"' .. letter .. '", the ' .. ordinal .. ' letter in the root "' .. joined_root .. '" should be a single letter.')
end
end
end
function export.ar_root(frame)
local output = {}
local categories = {}
local title = mw.title.getCurrentTitle()
local fulltitle = title.fullText
local pagename = title.text
local namespace = title.nsText
local params = {
= {},
= {},
= {},
= {},
= {},
= { type = "boolean", default = false },
= { type = "boolean", default = false },
= {},
= { alias_of = "t" },
= { default = "term" },
= { type = "boolean", default = false },
= { type = "boolean", default = false },
}
local args = require("Module:parameters").process(frame:getParent().args, params)
local argOffset = 0
local lang = ar
local rootLetters = {}
if args and not string.find(args, "%A") then
argOffset = 1
if args == "mt" then
error("Maltese (mt) roots are not supported, as they should"
.. "be written in the language's Latin-script orthography.")
end
lang = m_languages.getByCode(args) or m_languages.err(args, 1)
if not lang:hasAncestor(ar) then
error(("%s is not listed as an Arabic language."):format(
"[[:Category:" .. lang.getCategoryName() .. "|"
.. lang.getCanonicalName() .. "]] ("
.. lang.getCode() .. ")"
))
end
end
if not args and namespace == "Template" then
rootLetters = { "ك", "ت", "ب" }
elseif args and args then
rootLetters = { args, args, args, args }
elseif args then
rootLetters = rsplit(args, " ")
else
rootLetters = rsplit(fulltitle, " ")
end
hamzaError(rootLetters, output)
local joined_root = table.concat(rootLetters, " ")
validateRoot(rootLetters, joined_root)
local joined_tr = ar_translit.tr(table.concat(rootLetters, "-"), lang, sc, nil, nil, "force") or "-"
local cat = lang:getCanonicalName()
if fulltitle == joined_root then
table.insert(output, m_headword.full_headword({lang = lang, sc = sc, pos_category = "roots", categories = {}, heads = { joined_root }, translits = { joined_tr }}) )
table.insert(categories, ") or joined_root) .. "]]")
table.insert(categories, "]")
if args then
--require("Module:debug").track("ar-root") -- ]
end
else
if sc:countCharacters(pagename) < mw.ustring.len(pagename) - 2 then
--require("Module:debug").track("ar-root/title-not-ar") -- ]
if not args then
--require("Module:debug").track("ar-root/title-not-ar/cat") -- ]
end
end
local link_text
if args then
link_text = link(nil, joined_tr, ine(args), args, joined_root)
else
link_text = link(joined_root, joined_tr, ine(args), args )
end
table.insert(output, link_text)
table.insert(categories, m_utilities.format_categories( { cat .. " terms belonging to the root " .. joined_root }, lang) )
end
if args then
return joined_root
elseif args then
return table.concat(output)
elseif args then
return table.concat(categories)
else
return table.concat(output) .. table.concat(categories)
end
end
function export.ar_root2(parargs, args)
return export.ar_root(debug_frame(parargs, args))
end
function export.root_cat(frame)
output = {}
categories = {}
local title = mw.title.getCurrentTitle()
local pagename = title.text
local namespace = title.nsText
local args = frame:getParent().args
if namespace ~= "Category" then
error('The template "ar-root cat" should only be used in the category namespace.')
end
local root = {}
local joined_root
if rfind(pagename, "^Arabic terms belonging to the root ") then
before, joined_root = rmatch(pagename, "(Arabic terms belonging to the root )(.+)")
root = rsplit(joined_root, " ")
frame:callParserFunction(
"DISPLAYTITLE",
"Category:Arabic terms belonging to the root " ..
require("Module:script utilities").tag_text(
joined_root,
lang,
sc,
"term"
)
)
elseif pagename == "Arabic terms by root" then
table.insert(output, "This category holds lists of Arabic terms that belong to a certain root.")
table.insert(categories, "]")
table.insert(categories, "]")
elseif rfind(pagename, "^Arabic %d%-letter roots$") then
local number = rmatch(pagename, "Arabic (%d)%-letter roots")
table.insert(output, "This category holds lists of Arabic terms that belong to roots containing " .. number .. " consonants.")
table.insert(categories, "]")
else
error('The title for this category should begin with "Category:Arabic terms belonging to the root" and end in the root with spaces separating the letters.')
end
hamzaError(root, output)
if joined_root then
validateRoot(root, joined_root)
if mw.site.stats.pagesInCategory(title.text, "all") == 0 then
table.insert(categories, "]")
end
table.insert(categories, "]")
local lettercount = #root or error("Module:ar-utilities was unable to count the items in the table of root consonants.")
table.insert(categories, "]")
local joined_tr = ar_translit.tr(table.concat(root, "-"), nil, nil, nil, nil, "force") or "-"
local link_text = link(joined_root, joined_tr, ine(args) )
table.insert(output, "This category holds ] terms that are formed from the ] " .. link_text .. ".")
end
table.insert(output, "\n" .. mw.getCurrentFrame():expandTemplate{
title = "Template:categoryTOC-Arabic",
args = {}
})
return table.concat(output) .. table.concat(categories)
end
-- Used in {{ar-adj-in}} so that we can specify a full lemma rather than
-- requiring the user to truncate the -in ending. FIXME: Move ar-adj-in
-- into Lua.
function export.remove_in(frame)
local lemma = frame.args or error("Lemma required.")
return rsub(reorder_shadda(lemma), IN .. "$", "")
end
-- Used in {{ar-adj-an}} so that we can specify a full lemma rather than
-- requiring the user to truncate the -an ending. FIXME: Move ar-adj-an
-- into Lua.
function export.remove_an(frame)
local lemma = frame.args or error("Lemma required.")
return rsub(reorder_shadda(lemma), AN .. AMAQ .. "$", "")
end
-- Compare two words and find the alternation pattern (vowel changes, prefixes, suffixes etc.)
-- Still a WIP, doesn't work correctly yet.
function export.find_pattern(word1, word2)
return nil
end
function export.etymology(frame)
local text, categories = {}, {}
local linkText
local frame_params = {
= { required = true },
}
local frame_args = require("Module:parameters").process(frame.args, frame_params)
local anchor = frame_args
local data = {
= {
anchor = "Color or defect adjectives",
text = "color adjective",
categories = { "color/defect adjectives" },
},
= {
anchor = "Color or defect adjectives",
text = "defect adjective",
categories = { "color/defect adjectives" },
},
}
local params = {
= {},
= { type = boolean, default = false },
= { type = boolean, default = false },
= { alias_of = "lc" },
= { type = boolean, default = false},
}
local args = require("Module:parameters").process(frame:getParent().args, params)
if anchor and data then
local data = data
anchor = data.anchor or error('The data table does not include an anchor for "' .. anchor .. '".')
linkText = data.text or error('The data table does not include link text for "' .. anchor .. '".')
if not args.lc then
linkText = rsubn(linkText, "^%a", function(a) return mw.ustring.upper(a) end)
end
if not args.notext then
table.insert(text, "]")
end
if not args.nocat then
table.insert(categories, m_utilities.format_categories(data.categories, lang) )
end
else
error('The anchor "' .. tostring(anchor) .. '" is not found in the list of anchors.')
end
return table.concat(text) .. table.concat(categories)
end
return export