Module:Interlinear/sandbox2/gcl

local p = {} local data = mw.loadData("Module:Interlinear/data") local gloss_override = {} -- for custom gloss abbreviations local getArgs = require("Module:Arguments").getArgs local yesno = require("Module:Yesno")

-- -- Almost-global variables -- local frame, glossing_type, displaying_messages, msg

--- -- General settings --- local conf = { -- glossing abbreviations matching this pattern --		will not be rendered in small caps GlossSmallCapsExclude = "^[AOPS]$", -- if set to "label" gloss abbreviations are formatted as an with the "label" appearing in a tooltip -- if set to "wikilink" the abbreviation is formatted as a wikilink to the relevant wikipedia article -- if set to "none" abbreviations aren't formatted at all GlossingType = "label", ErrorCategory = "", AmbiguousGlossCategory = "", MessageGlossingError = "Error(s) in interlinear glossing", --e.g. G4 '4th gender' or CL7 'class 7' combining_gender_numbers = "[0-9][0-9]?$", combining_gender_prefixes = {G = "gender", CL = "class"}, combining_person = { ["1"] = "first person", ["2"] = "second person", ["3"] = "third person" },   combining_number = { S = "singular", SG = "singular", P = "plural", PL = "plural", D = "dual", DU = "dual", TRI = "trial" },   combining_gender = {F = "feminine", M = "masculine", N = "neuter"}, -- these are the non-all-upper-case strings -- that will be recognised as glossing abbreviations LowerCaseGlosses = { ["1sg"] = true, ["2sg"] = true, ["3sg"] = true, ["1du"] = true, ["2du"] = true, ["3du"] = true, ["1pl"] = true, ["2pl"] = true, ["3pl"] = true, ["Fsg"] = true, ["Fpl"] = true, ["Msg"] = true, ["Mpl"] = true, },   ErrorHelpLocation = "Template:Interlinear" }

- -- CSS styles and classes - conf.class = { GlossAbbr = "gloss-abbr", GlossAbbrAmb = "gloss-abbr-ambiguous", GlossAbbrError = "gloss-abbr-error", ErrorMessage = "error" }

- -- Sundry small functions - local function tidyCss(str) -- trims quotation marks str = mw.ustring.gsub(str, '^["\']*(.-)["\']*$', "%1") -- appends ";" if missing if mw.ustring.sub(str, -1) ~= ";" then str = str .. ";"   end return str end

local function highlight(text) if text then return ' ' .. text .. " "   else return "" end end

local function help_link(anchor) if anchor then return " (help)" else return "" end end

-- The following two functions update the glossing settings based on the received -- template arguments. set_global_glossing_settings updates the global settings -- that are valid for all gloss abbreviations. set_glossing_type -- returns the glossing type, which can vary between the different lines.

function set_global_glossing_settings(a) local style = "" if a.style then style = tidyCss(a.style) end if a.underline == "no" then style = style .. "text-decoration: none;" a.class = a.class .. " no_underline" end if a.small_caps == "no" then style = style .. "font-variant:normal; text-transform: none;" a.class = a.class .. " no_smallcaps" end if style ~= "" then conf.style.GlossAbbr = conf.style.GlossAbbr .. style end end

function set_glossing_type(glossing) if glossing then local GlossingType glossing = mw.ustring.lower(mw.text.trim(glossing)) if mw.ustring.find(glossing, "link") then GlossingType = "wikilink" elseif mw.ustring.find(glossing, "label") or mw.ustring.find(glossing, "no link") then GlossingType = "label" elseif mw.ustring.find(glossing, "no abbr") then GlossingType = "no abbr" elseif yesno(glossing) == false then GlossingType = nil elseif yesno(glossing) then GlossingType = conf.GlossingType else msg:add("error", 'Glossing type "' .. glossing .. '" not recognised') end return GlossingType else error("set_glossing_type: 'glossing' is nil or false", 2) end end

- -- The UserMessages object contains and processes error messages and warnings - local UserMessages = {errors = {}, warnings = {}, gloss_messages = {}} function UserMessages:add(msgtype, text, gloss) if msgtype == "gloss_message" then self.gloss_messages[gloss] = text elseif msgtype == "warning" then table.insert(self.warnings, text) elseif msgtype == "non-repeating error" then self.errors.nre = text elseif msgtype == "ambiguous gloss" then self.if_ambiguous_glosses = true elseif msgtype == "error" then table.insert(self.errors, text) else return error("UserMessages:add: unknown message type", 2) end end function UserMessages:print_errors local out = "" local namespace = mw.title.getCurrentTitle.namespace if next(self.errors) or self.warnings[1] then local err_span = mw.html.create("span") err_span:addClass(conf.class.ErrorMessage) for _, v in pairs(self.errors) do           err_span:wikitext(" " .. v .. ";") end -- non-talk namespaces, excluding user pages; -- if modifying please update the description on the category page if namespace % 2 == 0 and namespace ~= 2 then err_span:wikitext(conf.ErrorCategory) end out = tostring(err_span) mw.addWarning(conf.MessageGlossingError) end if self.if_ambiguous_glosses then if namespace == 0 then -- article namespace -- this category will only track articles out = out .. conf.AmbiguousGlossCategory end end return out end function UserMessages:print_warnings local out = "" -- Messages and warnings get displayed only if the page is being viewed in "preview" mode: if displaying_messages and (next(self.gloss_messages) or next(self.warnings)) then local div = mw.html.create("div") div:addClass("interlinear-preview-warning") :cssText("border: 1px solid #a2a9b1; background-color: #f8f9fa; width: 80%; padding: 0.2em;") :wikitext("This message box is shown only in preview:"):newline for _, v in ipairs(self.warnings) do           local p = div:tag("p") :addClass(conf.class.ErrorMessage) :wikitext(v) end if self.gloss_messages then div:wikitext(               "  To change any of the following default expansions, see the template's documentation: "            ) end for _, v in pairs(self.gloss_messages) do           div:wikitext(" " .. v .. " ") end out = out .. "\n\n" .. tostring(div) end return out end

- -- gloss_lookup receives a gloss abbreviation and tries to uncover its meaning. - function gloss_lookup(a, label, wikilink) local _label, _wikilink, _lookup, source = nil, nil, nil, nil if gloss_override[a] then _lookup = gloss_override[a] source = "local" elseif data.abbreviations[a] then _lookup = data.abbreviations[a] end if _lookup and _lookup.expansion ~= "" then _label, _wikilink = _lookup.expansion, _lookup.wikipage else local prefix = mw.ustring.sub(a, 1, 1) local suffix = mw.ustring.sub(a, 2) if conf.combining_person[prefix] then -- is it of the form 1PL or 3FS? _label = conf.combining_person[prefix] local _suffix = conf.combining_number[suffix] or conf.combining_gender[suffix] if _suffix then _label = _label .. ", " .. _suffix else local suffix1 = mw.ustring.sub(suffix, 1, 1) local suffix2 = mw.ustring.sub(suffix, 2) if conf.combining_gender[suffix1] and conf.combining_number[suffix2] then _label = _label .. ", " .. conf.combining_gender[suffix1] .. ", " .. conf.combining_number[suffix2] else _label = nil end end elseif mw.ustring.match(suffix, conf.combining_gender_numbers) then -- cases like G4 = gender 4 local _i, _j = mw.ustring.find(a, conf.combining_gender_numbers) local _pre = mw.ustring.sub(a, 1, _i - 1) local _suff = mw.ustring.sub(a, _i) if conf.combining_gender_prefixes[_pre] then _label = conf.combining_gender_prefixes[_pre] .. " " .. _suff end elseif prefix == "N" then -- dealing with cases like NPST = non-past local s = gloss_override[suffix] or data.abbreviations[suffix] if s ~= nil and not s.ExcludeNegation then _label = "non-" .. s.expansion _wikilink = s.wikipage end s = nil end end if _label == "" then _label = nil end if _wikilink == "" then _wikilink = nil end if not label then label = _label end if not wikilink then wikilink = _wikilink end return label, wikilink, source end

- -- Section transclusion - local page_content = nil -- lazy initilization local function get_section(section_name) if page_content == nil then local current_title = mw.title.getCurrentTitle page_content = current_title:getContent end if page_content then if mw.ustring.find(page_content, section_name, 1, true) then return frame:preprocess('') end end return '' end

local function set_custom_glosses(list) local abbs = mw.text.split(list, '[;\n\t]') for _,v in pairs(abbs) do		local gloss = mw.text.split(v, ':') local a = mw.text.trim(gloss[1]) if a and a ~= "" then gloss_override[a] = {} gloss_override[a].expansion = gloss[2] gloss_override[a].wikipage = gloss[3] end end end

--this looks for a list of glossing abbreviations on the page -- that transcludes the template: function view_abbreviations_list local _ablist_section = get_section('list-of-glossing-abbreviations') if _ablist_section and _ablist_section ~= "" then local _a = mw.ustring.gsub(_ablist_section, '', '') -- strips off the div tags set_custom_glosses(_a) end end

- -- format_gloss calls gloss_lookup to find the meaning of a gloss -- abbreviation, which it then proceeds to format - function format_gloss(gloss, label, wikilink) if string.sub(gloss, 1, 3) == "000" then -- checks for a common component of exposed strip markers (see mw:Strip marker) return gloss end local gloss2 = mw.ustring.gsub(gloss, "<.->", "") -- remove any html fluff gloss2 = mw.ustring.gsub(gloss2, "%'%'+", "") -- remove wiki bold/italic formatting gloss2 = mw.text.trim(mw.ustring.upper(gloss2)) if not (label or wikilink) or (not label and glossing_type == "label") or (not wikilink and glossing_type == "wikilink") then if glossing_type ~= "no abbr" then label, wikilink, source = gloss_lookup(gloss2, label, wikilink) end end local gloss_node if glossing_type == "no abbr" then gloss_node = mw.html.create("span") else gloss_node = mw.html.create("abbr") end gloss_node:addClass(conf.class.GlossAbbr) if label or wikilink then if mw.ustring.match(gloss, conf.GlossSmallCapsExclude) then gloss_node:addClass("gloss-not-smallcaps") end -- if not mw.ustring.match(gloss, "%l") -- and not mw.ustring.match(gloss, conf.GlossSmallCapsExclude) -- excluding glosses that contain lower-case characters -- then -- and also excluding A, O etc. from rendering in small caps --gloss_node:attr("style", conf.style.GlossAbbr) -- end local abbr_label = label or wikilink --       if label then --           abbr_label = label --       else --           abbr_label = wikilink --       end gloss_node:attr("title", abbr_label) if source ~= "local" and data.abbreviations[gloss2] then if data.abbreviations[gloss2].ambiguous then gloss_node:addClass(conf.class.GlossAbbrAmb) msg:add("ambiguous gloss") end end if glossing_type == "wikilink" and wikilink then gloss_node:wikitext("", gloss, "") else gloss_node:wikitext(gloss) end if source ~= "local" and displaying_messages then -- logging gloss lookups: local message = "" if label then message = "assuming " .. gloss2 .. ' means "' .. abbr_label .. '";' end if glossing_type == "wikilink" and wikilink then message = message .. " linking to " .. wikilink .. ";" end msg:add("gloss_message", message, gloss) end elseif glossing_type == "no abbr" then gloss_node:wikitext(gloss) else if displaying_messages then msg:add(               "warning",                "Gloss abbreviation " .. highlight(gloss2) .. "  not recognised" .. help_link("gloss abbr")            ) end msg:add("non-repeating error", "Unknown glossing abbreviation(s)" .. help_link("gloss abbr")) gloss_node :addClass(conf.class.GlossAbbrError) :addClass("error") :attr("title", gloss2 .. ": glossing abbreviation not found") :wikitext(gloss) end return tostring(gloss_node) end

-- The following function is called by Template:gcl and is used for formatting an individual glossing abbreviation

function gcl(gloss, label, wikilink) if not gloss then UserMessages:add("error", "No gloss supplied") return UserMessages:print end -- if a wikilink is supplied and glossing isn't set to 'label'... if wikilink and not args.glossing then glossing_type = "wikilink" end --    .. then the wikilink will be formatted as such if label == "" then label = nil end if wikilink == "" then wikilink = nil end return format_gloss(gloss, label, wikilink) end

function p.gcl(f) frame = f   local args = getArgs(frame, {    	trim = true,    	removeBlanks = false,    	parentOnly = true,    	wrappers = {"Template:Gcl"}    }) msg = UserMessages set_global_glossing_settings { style = args.style, underline = args.underline, small_caps = args["small-caps"] }   view_abbreviations_list if not args.glossing then glossing_type = conf.GlossingType -- a global variable else glossing_type = set_glossing_type(args.glossing) end local gloss, label, wikilink = args[1], args[2], args[3] return gcl(gloss, label, wikilink) --   if not gloss then --       UserMessages:add("error", "No gloss supplied") --       return UserMessages:print --   end --    -- if a wikilink is supplied and glossing isn't set to 'label'... --   if wikilink and not args.glossing then --       glossing_type = "wikilink" --   end --     .. then the wikilink will be formatted as such --   if label == "" then label = nil end --   if wikilink == "" then wikilink = nil end --   local result = format_gloss(gloss, label, wikilink) --   return result end

return p