Module:interlinear: Difference between revisions
No edit summary |
No edit summary |
||
| Line 4: | Line 4: | ||
local getArgs = require('Module:Arguments').getArgs | local getArgs = require('Module:Arguments').getArgs | ||
local yesno = require('Module:Yesno') | local yesno = require('Module:Yesno') | ||
local | local languages = require('Module:languages') -- Switched from Module:Lang/data | ||
-------------------------- | -------------------------- | ||
| Line 15: | Line 15: | ||
------------------- | ------------------- | ||
local conf = { --settings | local conf = { --settings | ||
WordSeparator = " \n\r\t", | WordSeparator = " \n\r\t", | ||
GlossAbbrPattern = "^([Ø0-9A-Z]+)$", | GlossAbbrPattern = "^([Ø0-9A-Z]+)$", | ||
GlossAbbrBoundary = "-.,;:<>‹›⟨⟩/\\~+=%?%s%[%]()%_\127'", | GlossAbbrBoundary = "-.,;:<>‹›⟨⟩/\\~+=%?%s%[%]()%_\127'", | ||
GlossExcludeTable = {I = true,}, | GlossExcludeTable = {I = true,}, | ||
GlossExcludePattern = '^[0-9][0-9]+$', | GlossExcludePattern = '^[0-9][0-9]+$', | ||
GlossSmallCapsExclude = "^[AOPS]$", | GlossSmallCapsExclude = "^[AOPS]$", | ||
GlossingType = "label", | GlossingType = "label", | ||
ErrorCategory = "[[Category:Pages with errors in interlinear text]]", | ErrorCategory = "[[Category:Pages with errors in interlinear text]]", | ||
AmbiguousGlossCategory = "[[Category:Articles with ambiguous glossing abbreviations]]", | AmbiguousGlossCategory = "[[Category:Articles with ambiguous glossing abbreviations]]", | ||
MessageGlossingError = "Error(s) in interlinear glossing", | MessageGlossingError = "Error(s) in interlinear glossing", | ||
combining_gender_numbers = "[0-9][0-9]?$", | combining_gender_numbers = "[0-9][0-9]?$", | ||
combining_gender_prefixes = {G = "gender", CL = "class"}, | combining_gender_prefixes = {G = "gender", CL = "class"}, | ||
combining_person = {["1"] = "first person", ["2"] = "second person", ["3"] = "third person",}, | combining_person = {["1"] = "first person", ["2"] = "second person", ["3"] = "third person",}, | ||
| Line 45: | Line 42: | ||
["1pl"] = true, ["2pl"] = true, ["3pl"] = true, | ["1pl"] = true, ["2pl"] = true, ["3pl"] = true, | ||
["Fsg"] = true, ["Fpl"] = true, ["Msg"] = true, ["Mpl"] = true, | ["Fsg"] = true, ["Fpl"] = true, ["Msg"] = true, ["Mpl"] = true, | ||
}, | }, | ||
ErrorHelpLocation = "Template:Interlinear", | ErrorHelpLocation = "Template:Interlinear", | ||
} | } | ||
| Line 52: | Line 49: | ||
-- CSS styles and classes | -- CSS styles and classes | ||
--------------------- | --------------------- | ||
conf.style = { | conf.style = { | ||
WordDiv = "float: left; margin-bottom: 0.3em;", | WordDiv = "float: left; margin-bottom: 0.3em;", | ||
WordMargin = "margin-right: 1em;", | WordMargin = "margin-right: 1em;", | ||
WordP = "margin: 0px;", | WordP = "margin: 0px;", | ||
GlossAbbr = "font-variant: small-caps; font-variant-numeric: lining-nums; text-transform: lowercase; ", | GlossAbbr = "font-variant: small-caps; font-variant-numeric: lining-nums; text-transform: lowercase; ", | ||
HiddenText = "display: none;", | HiddenText = "display: none;", | ||
EndDiv = "clear: left; display: block;", | EndDiv = "clear: left; display: block;", | ||
ErrorMessage = "font-size: inherit", | ErrorMessage = "font-size: inherit", | ||
} | } | ||
conf.class = { | conf.class = { | ||
Interlinear = "interlinear", | Interlinear = "interlinear", | ||
GlossAbbr = "gloss-abbr", | GlossAbbr = "gloss-abbr", | ||
| Line 68: | Line 65: | ||
ErrorMessage = "error", | ErrorMessage = "error", | ||
} | } | ||
--------------------- | --------------------- | ||
-- Section transclusion | -- Section transclusion | ||
--------------------- | --------------------- | ||
local page_content = nil | local page_content = nil | ||
local function get_section(frame, section_name) | local function get_section(frame, section_name) | ||
if page_content == nil then | if page_content == nil then | ||
| Line 84: | Line 82: | ||
return '' | return '' | ||
end | end | ||
--------------------- | --------------------- | ||
-- Sundry small functions | -- Sundry small functions | ||
| Line 92: | Line 91: | ||
local function tidyCss(str) | local function tidyCss(str) | ||
str = mw.ustring.gsub(str, '^[\"\']*(.-)[\"\']*$', "%1") | str = mw.ustring.gsub(str, '^[\"\']*(.-)[\"\']*$', "%1") | ||
if mw.ustring.sub(str, -1) ~= ";" then str = str .. ";" end | if mw.ustring.sub(str, -1) ~= ";" then str = str .. ";" end | ||
return str | return str | ||
end | end | ||
local function highlight(text) | local function highlight(text) | ||
if text then | if text then return '' .. text .. '' else return "" end | ||
end | end | ||
| Line 107: | Line 104: | ||
end | end | ||
local function is_empty(str) | local function is_empty(str) | ||
if not str then return true end | if not str then return true end | ||
if mw.ustring.find(str, "[^" .. conf.WordSeparator .. "]") | if mw.ustring.find(str, "[^" .. conf.WordSeparator .. "]") | ||
| Line 120: | Line 117: | ||
end | end | ||
-- | -- Trial implementation of automatic transliteration using Module:languages: | ||
local function transliterate (str, | local function transliterate (str, lang_code) | ||
if not lang_code then | |||
msg:add("error", "Source language for transliteration is not set") | |||
return "" | |||
end | |||
-- Integration with Module:languages | |||
local lang_obj = languages.getByCode(lang_code) | |||
if lang_obj and type(lang_obj.transliterate) == "function" then | |||
return lang_obj:transliterate(str) or "" | |||
end | |||
-- Fallback for specific modules if getByCode doesn't provide it | |||
local lookup = {grc = {module = 'Module:Ancient Greek', funct = "transliterate", } } | local lookup = {grc = {module = 'Module:Ancient Greek', funct = "transliterate", } } | ||
local t = lookup[lang_code] | |||
if t then | |||
local module = require(t.module) | |||
return module[t.funct](str) | |||
else | |||
msg:add("error", "Can't find transliterator for language '" .. lang_code .. "'") | |||
end | end | ||
return "" | return "" | ||
end | end | ||
-------------------- | -------------------- | ||
-- | -- Glossing settings | ||
-------------------- | -------------------- | ||
local function set_global_glossing_settings(a) | local function set_global_glossing_settings(a) | ||
local style = "" | local style = "" | ||
if a.style then style = tidyCss(a.style) end | if a.style then style = tidyCss(a.style) end | ||
if a.underline == "no" then | if a.underline == "no" then style = style .. "text-decoration: none;" end | ||
if a.small_caps == "no" then style = style .. "font-variant:normal; text-transform: none;" end | |||
if a.small_caps == "no" then | |||
if style ~= "" then conf.style.GlossAbbr = conf.style.GlossAbbr .. style end | if style ~= "" then conf.style.GlossAbbr = conf.style.GlossAbbr .. style end | ||
end | end | ||
| Line 158: | Line 159: | ||
if mw.ustring.find(glossing, 'link') then | if mw.ustring.find(glossing, 'link') then | ||
GlossingType = "wikilink" | GlossingType = "wikilink" | ||
elseif mw.ustring.find(glossing, 'label') | elseif mw.ustring.find(glossing, 'label') or mw.ustring.find(glossing, 'no link') then | ||
GlossingType = 'label' | GlossingType = 'label' | ||
elseif mw.ustring.find(glossing, 'no abbr') then | elseif mw.ustring.find(glossing, 'no abbr') then | ||
| Line 188: | Line 188: | ||
--------------------- | --------------------- | ||
-- | -- UserMessages object | ||
--------------------- | --------------------- | ||
local UserMessages = {errors = {}, warnings = {}, gloss_messages = {}} | local UserMessages = {errors = {}, warnings = {}, gloss_messages = {}} | ||
function UserMessages:add(msgtype, text, gloss) | function UserMessages:add(msgtype, text, gloss) | ||
if msgtype == "gloss_message" then | if msgtype == "gloss_message" then self.gloss_messages[gloss] = text | ||
elseif msgtype == "warning" then table.insert(self.warnings, text) | |||
elseif msgtype == "warning" then | elseif msgtype == "non-repeating error" then self.errors.nre = text | ||
elseif msgtype == "ambiguous gloss" then self.if_ambiguous_glosses = true | |||
elseif msgtype == "non-repeating error" then | elseif msgtype == "error" then table.insert(self.errors, text) | ||
else return error("UserMessages:add(): unknown message type", 2) end | |||
elseif msgtype == "ambiguous gloss" then | |||
elseif msgtype == "error" then | |||
else return error("UserMessages:add(): unknown message type", 2) | |||
end | end | ||
function UserMessages:print_errors() | function UserMessages:print_errors() | ||
| Line 212: | Line 206: | ||
err_span:attr("style", conf.style.ErrorMessage) | err_span:attr("style", conf.style.ErrorMessage) | ||
err_span:addClass(conf.class.ErrorMessage) | err_span:addClass(conf.class.ErrorMessage) | ||
for _,v in pairs(self.errors) do | for _,v in pairs(self.errors) do err_span:wikitext(" " .. v .. ";") end | ||
if namespace % 2 == 0 and namespace ~= 2 then err_span:wikitext(conf.ErrorCategory) end | |||
if namespace % 2 == 0 and namespace ~= 2 | |||
out = tostring(err_span) | out = tostring(err_span) | ||
mw.addWarning(conf.MessageGlossingError) | mw.addWarning(conf.MessageGlossingError) | ||
end | end | ||
if self.if_ambiguous_glosses then | if self.if_ambiguous_glosses then | ||
if namespace == 0 | if namespace == 0 then out = out .. conf.AmbiguousGlossCategory end | ||
end | end | ||
return out | return out | ||
| Line 229: | Line 218: | ||
function UserMessages:print_warnings() | function UserMessages:print_warnings() | ||
local out = "" | local out = "" | ||
if displaying_messages and (next(self.gloss_messages) or next(self.warnings)) then | if displaying_messages and (next(self.gloss_messages) or next(self.warnings)) then | ||
local div = mw.html.create("div") | local div = mw.html.create("div") | ||
| Line 244: | Line 232: | ||
if self.gloss_messages then | if self.gloss_messages then | ||
div:wikitext("<p> To change any of the following default expansions, see [[Template:Interlinear/doc#Custom abbreviations|the template's documentation]]:</p>") | div:wikitext("<p> To change any of the following default expansions, see [[Template:Interlinear/doc#Custom abbreviations|the template's documentation]]:</p>") | ||
end | |||
for _,v in pairs(self.gloss_messages) do | for _,v in pairs(self.gloss_messages) do | ||
div:wikitext("<p>" .. v .. "</p>") | div:wikitext("<p>" .. v .. "</p>") | ||
| Line 254: | Line 242: | ||
--------------------- | --------------------- | ||
-- | -- Gloss Lookup & Format | ||
--------------------- | --------------------- | ||
local function gloss_lookup(a, label, wikilink) | local function gloss_lookup(a, label, wikilink) | ||
| Line 267: | Line 255: | ||
local prefix = mw.ustring.sub(a,1,1) | local prefix = mw.ustring.sub(a,1,1) | ||
local suffix = mw.ustring.sub(a,2) | local suffix = mw.ustring.sub(a,2) | ||
if conf.combining_person[prefix] then | if conf.combining_person[prefix] then | ||
_label = conf.combining_person[prefix] | _label = conf.combining_person[prefix] | ||
local _suffix = conf.combining_number[suffix] or conf.combining_gender[suffix] | local _suffix = conf.combining_number[suffix] or conf.combining_gender[suffix] | ||
| Line 275: | Line 263: | ||
local suffix1 = mw.ustring.sub(suffix,1,1) | local suffix1 = mw.ustring.sub(suffix,1,1) | ||
local suffix2 = mw.ustring.sub(suffix,2) | local suffix2 = mw.ustring.sub(suffix,2) | ||
if conf.combining_gender[suffix1] | if conf.combining_gender[suffix1] and conf.combining_number[suffix2] then | ||
_label = _label .. ", " .. conf.combining_gender[suffix1] .. ", " .. conf.combining_number[suffix2] | _label = _label .. ", " .. conf.combining_gender[suffix1] .. ", " .. conf.combining_number[suffix2] | ||
else _label = nil end | else _label = nil end | ||
end | end | ||
elseif mw.ustring.match(suffix,conf.combining_gender_numbers) then | elseif mw.ustring.match(suffix,conf.combining_gender_numbers) then | ||
local _i,_j = mw.ustring.find(a, conf.combining_gender_numbers) | local _i,_j = mw.ustring.find(a, conf.combining_gender_numbers) | ||
local _pre = mw.ustring.sub(a, 1, _i - 1) | local _pre = mw.ustring.sub(a, 1, _i - 1) | ||
| Line 287: | Line 274: | ||
_label = conf.combining_gender_prefixes[_pre] .. " " .. _suff | _label = conf.combining_gender_prefixes[_pre] .. " " .. _suff | ||
end | end | ||
elseif prefix == "N" then | elseif prefix == "N" then | ||
local s = gloss_override[suffix] or data.abbreviations[suffix] | local s = gloss_override[suffix] or data.abbreviations[suffix] | ||
if s ~= nil and not s.ExcludeNegation then | if s ~= nil and not s.ExcludeNegation then | ||
| Line 303: | Line 290: | ||
end | end | ||
local function format_gloss(gloss, label, wikilink) | local function format_gloss(gloss, label, wikilink) | ||
if string.sub(gloss,1,3) == "000" then | if string.sub(gloss,1,3) == "000" then return gloss end | ||
local gloss2 = mw.ustring.gsub(gloss,"<.->","") | |||
gloss2 = mw.ustring.gsub(gloss2, "%'%'+", "") | |||
local gloss2 = mw.ustring.gsub(gloss,"<.->","") | |||
gloss2 = mw.ustring.gsub(gloss2, "%'%'+", "") | |||
gloss2 = mw.text.trim(mw.ustring.upper(gloss2)) | gloss2 = mw.text.trim(mw.ustring.upper(gloss2)) | ||
if not (label or wikilink) | 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 | end | ||
local gloss_node | local gloss_node | ||
if glossing_type == "no abbr" | if glossing_type == "no abbr" then gloss_node = mw.html.create("span") | ||
else gloss_node = mw.html.create("abbr") end | else gloss_node = mw.html.create("abbr") end | ||
gloss_node:addClass(conf.class.GlossAbbr) | gloss_node:addClass(conf.class.GlossAbbr) | ||
if label or wikilink then | if label or wikilink then | ||
if not mw.ustring.match(gloss, "%l") | if not mw.ustring.match(gloss, "%l") and not mw.ustring.match(gloss,conf.GlossSmallCapsExclude) then | ||
gloss_node:attr("style", conf.style.GlossAbbr) | |||
end | end | ||
local abbr_label | local abbr_label = label and label or wikilink | ||
gloss_node:attr("title", abbr_label) | gloss_node:attr("title", abbr_label) | ||
if source ~= "local" and data.abbreviations[gloss2] then | if source ~= "local" and data.abbreviations[gloss2] then | ||
if data.abbreviations[gloss2].ambiguous then | if data.abbreviations[gloss2].ambiguous then | ||
gloss_node:addClass(conf.class.GlossAbbrAmb) | gloss_node:addClass(conf.class.GlossAbbrAmb) | ||
msg:add("ambiguous gloss") | |||
end | |||
end | end | ||
if glossing_type == "wikilink" and wikilink | if glossing_type == "wikilink" and wikilink then gloss_node:wikitext("[[w:", wikilink, "|" , gloss, "]]") | ||
else gloss_node:wikitext(gloss) end | |||
if source ~= "local" and displaying_messages then | if source ~= "local" and displaying_messages then | ||
local message = "" | local message = "" | ||
if label then | if label then message = "assuming " .. gloss2 .. " means \"" .. abbr_label .. "\";" end | ||
if glossing_type == "wikilink" and wikilink then | if glossing_type == "wikilink" and wikilink then | ||
message = message .. " linking to [[w:" .. wikilink .. "|" .. wikilink .. "]];" | message = message .. " linking to [[w:" .. wikilink .. "|" .. wikilink .. "]];" | ||
| Line 354: | Line 326: | ||
msg:add("gloss_message", message, gloss) | msg:add("gloss_message", message, gloss) | ||
end | end | ||
elseif glossing_type == "no abbr" | elseif glossing_type == "no abbr" then | ||
gloss_node:attr("style", conf.style.GlossAbbr):wikitext(gloss) | |||
else | else | ||
if displaying_messages then | if displaying_messages then | ||
| Line 363: | Line 333: | ||
end | end | ||
msg:add("non-repeating error", "Unknown glossing abbreviation(s)" .. help_link("gloss abbr")) | msg:add("non-repeating error", "Unknown glossing abbreviation(s)" .. help_link("gloss abbr")) | ||
gloss_node | gloss_node:addClass(conf.class.GlossAbbrError):addClass("error"):css("font-size", "100%") | ||
:attr("title", gloss2 .. ": glossing abbreviation not found") | :attr("title", gloss2 .. ": glossing abbreviation not found") | ||
:attr("style", conf.style.ErrorMessage) | :attr("style", conf.style.ErrorMessage) | ||
| Line 374: | Line 341: | ||
end | end | ||
local function find_gloss(word) | local function find_gloss(word) | ||
local function scan_gloss(boundary, gloss_abbr) | local function scan_gloss(boundary, gloss_abbr) | ||
if (mw.ustring.match(gloss_abbr, conf.GlossAbbrPattern) | if (mw.ustring.match(gloss_abbr, conf.GlossAbbrPattern) or conf.LowerCaseGlosses[gloss_abbr]) | ||
and not (conf.GlossExcludeTable[gloss_abbr] or mw.ustring.match(gloss_abbr, conf.GlossExcludePattern)) then | |||
and not (conf.GlossExcludeTable[gloss_abbr] | gloss_abbr = format_gloss(gloss_abbr) | ||
end | end | ||
return boundary .. gloss_abbr | return boundary .. gloss_abbr | ||
end | end | ||
local word = mw.text.decode(word, true) | local word = mw.text.decode(word, true) | ||
if word == "I" | if word == "I" then return word end | ||
local pattern = "([" .. conf.GlossAbbrBoundary .. "]?)([^" .. conf.GlossAbbrBoundary .. "]+)" | local pattern = "([" .. conf.GlossAbbrBoundary .. "]?)([^" .. conf.GlossAbbrBoundary .. "]+)" | ||
word = mw.ustring.gsub(word, pattern, scan_gloss) | word = mw.ustring.gsub(word, pattern, scan_gloss) | ||
return word | return word | ||
end | end | ||
local function parse(cline, i, tags_found,ifglossing) | local function parse(cline, i, tags_found,ifglossing) | ||
local function issue_error(message, culprit) | local function issue_error(message, culprit) | ||
UserMessages:add("error", message .. ": ''" .. mw.ustring.sub(cline.whole, 1, i-1) .. "'''" .. culprit .. "'''''") | UserMessages:add("error", message .. ": ''" .. mw.ustring.sub(cline.whole, 1, i-1) .. "'''" .. culprit .. "'''''") | ||
end | end | ||
if i > cline.length then return i end | if i > cline.length then return i end | ||
local next_step, j, _, chunk | local next_step, j, _, chunk | ||
local probe = mw.ustring.sub(cline.whole,i,i) | local probe = mw.ustring.sub(cline.whole,i,i) | ||
if mw.ustring.match(probe,"[" .. conf.WordSeparator .. "]") and tags_found == 0 | if mw.ustring.match(probe,"[" .. conf.WordSeparator .. "]") and tags_found == 0 then | ||
next_step = i-1 | |||
elseif probe == "[" then | elseif probe == "[" then | ||
if mw.ustring.sub(cline.whole,i+1,i+1) == "[" then | if mw.ustring.sub(cline.whole,i+1,i+1) == "[" then | ||
_,j,chunk = mw.ustring.find(cline.whole,"(%[%[.-%]%])", i) | _,j,chunk = mw.ustring.find(cline.whole,"(%[%[.-%]%])", i) | ||
else chunk = "["; j = i end | else chunk = "["; j = i end | ||
buffer = buffer .. chunk | buffer = buffer .. chunk | ||
next_step = parse(cline, j+1,tags_found,ifglossing) | next_step = parse(cline, j+1,tags_found,ifglossing) | ||
elseif probe == "{" and tags_found == 0 then | elseif probe == "{" and tags_found == 0 then | ||
_,j,chunk = mw.ustring.find(cline.whole,"(.-)(})", i+1) | _,j,chunk = mw.ustring.find(cline.whole,"(.-)(})", i+1) | ||
if not chunk then | if not chunk then | ||
| Line 432: | Line 383: | ||
buffer = buffer .. chunk | buffer = buffer .. chunk | ||
next_step = parse(cline, j+1,tags_found,ifglossing) | next_step = parse(cline, j+1,tags_found,ifglossing) | ||
elseif probe == "<" then | elseif probe == "<" then | ||
local _,j,chunk = mw.ustring.find(cline.whole,"(<.->)",i) | local _,j,chunk = mw.ustring.find(cline.whole,"(<.->)",i) | ||
if not chunk then | if not chunk then | ||
issue_error("Unclosed angle bracket", "<") | issue_error("Unclosed angle bracket", "<") | ||
chunk = highlight("<"); j = i | chunk = highlight("<"); j = i | ||
elseif mw.ustring.sub(cline.whole,i,i+1) == "</" then | elseif mw.ustring.sub(cline.whole,i,i+1) == "</" then | ||
if | if mw.ustring.find(chunk, "</abbr>", 1, true) then ifglossing=true end | ||
tags_found = tags_found - 1 | tags_found = tags_found - 1 | ||
elseif not mw.ustring.match(chunk, "/>$") | elseif not mw.ustring.match(chunk, "/>$") then | ||
if ifglossing == true and mw.ustring.find(chunk, conf.class.GlossAbbr, 1, true) then ifglossing = false end | |||
tags_found = tags_found + 1 | tags_found = tags_found + 1 | ||
end | end | ||
buffer = buffer .. chunk | buffer = buffer .. chunk | ||
next_step = parse(cline, j+1,tags_found,ifglossing) | next_step = parse(cline, j+1,tags_found,ifglossing) | ||
else | else | ||
local _,k,chunk = mw.ustring.find(cline.whole,"(..-)([ <[])",i) | local _,k,chunk = mw.ustring.find(cline.whole,"(..-)([ <[])",i) | ||
if k then | if k then | ||
if ifglossing==true then | if ifglossing==true then buffer = buffer .. find_gloss(chunk) | ||
else | else | ||
if cline.tone_sup then chunk = tone_sup(chunk) end | if cline.tone_sup then chunk = tone_sup(chunk) end | ||
| Line 461: | Line 406: | ||
end | end | ||
next_step = parse(cline, k, tags_found, ifglossing) | next_step = parse(cline, k, tags_found, ifglossing) | ||
else | else | ||
if ifglossing == true then | if ifglossing == true then chunk = find_gloss(mw.ustring.sub(cline.whole,i)) | ||
else | else | ||
chunk = mw.ustring.sub(cline.whole,i) | chunk = mw.ustring.sub(cline.whole,i) | ||
| Line 474: | Line 418: | ||
return next_step | return next_step | ||
end | end | ||
function p.gcl(frame) | function p.gcl(frame) | ||
local args = getArgs(frame,{ | local args = getArgs(frame,{ trim = true, removeBlanks = false, parentOnly = true, wrappers = {'Template:Grammatical category label'}, }) | ||
msg = UserMessages | msg = UserMessages | ||
set_global_glossing_settings{style = args.style, underline = args.underline, small_caps = args['small-caps']} | set_global_glossing_settings{style = args.style, underline = args.underline, small_caps = args['small-caps']} | ||
if not args.glossing then | if not args.glossing then glossing_type = conf.GlossingType else glossing_type = set_glossing_type(args.glossing) end | ||
local gloss, label, wikilink = args[1], args[2], args[3] | local gloss, label, wikilink = args[1], args[2], args[3] | ||
if not gloss then UserMessages:add("error", "No gloss supplied") | if not gloss then UserMessages:add("error", "No gloss supplied") return UserMessages:print() end | ||
if wikilink and not args.glossing then glossing_type = 'wikilink' end | |||
if wikilink and not args.glossing then | |||
if label == "" then label = nil end | if label == "" then label = nil end | ||
if wikilink == "" then wikilink = nil end | if wikilink == "" then wikilink = nil end | ||
| Line 501: | Line 433: | ||
end | end | ||
function p.interlinearise(frame) | function p.interlinearise(frame) | ||
local if_auto_translit = false | local if_auto_translit = false | ||
local args = getArgs(frame, { | local args = getArgs(frame, { trim = true, removeBlanks = false, parentFirst = true, wrappers = {'Template:Interlinear', 'Template:Fs interlinear'}, }) | ||
local template_name = frame:getParent():getTitle() | local template_name = frame:getParent():getTitle() | ||
if template_name == 'Template:Fs interlinear' then | if template_name == 'Template:Fs interlinear' then | ||
| Line 525: | Line 444: | ||
if args.transl and not args.transl2 then args.transl2 = args.transl end | if args.transl and not args.transl2 then args.transl2 = args.transl end | ||
if_auto_translit = true | if_auto_translit = true | ||
end | end | ||
local revid = frame:preprocess( "{{REVISIONID}}" ) | local revid = frame:preprocess( "{{REVISIONID}}" ) | ||
if | if revid == "" then | ||
if not args['display-messages'] or yesno(args['display-messages']) then | if not args['display-messages'] or yesno(args['display-messages']) then displaying_messages = true end | ||
end | end | ||
msg = UserMessages | msg = UserMessages | ||
| Line 537: | Line 454: | ||
local function set_italics(n) | local function set_italics(n) | ||
line[n].attr.style = line[n].attr.style .. "font-style: italic;" | line[n].attr.style = line[n].attr.style .. "font-style: italic;" | ||
line[n].tone_sup = true | line[n].tone_sup = true | ||
if args['tone-superscripting'] and not yesno(args['tone-superscripting']) | if args['tone-superscripting'] and not yesno(args['tone-superscripting']) then line[n].tone_sup = false end | ||
end | end | ||
if args.glossing then | if args.glossing then | ||
local _gl = set_glossing_type(args.glossing) | local _gl = set_glossing_type(args.glossing) | ||
if _gl then conf.GlossingType = _gl end | if _gl then conf.GlossingType = _gl end | ||
end | end | ||
local _ablist_section = get_section(frame, 'list-of-glossing-abbreviations') | local _ablist_section = get_section(frame, 'list-of-glossing-abbreviations') | ||
if _ablist_section and _ablist_section ~= "" then | if _ablist_section and _ablist_section ~= "" then | ||
local _a = mw.ustring.gsub(_ablist_section, '< | local _a = mw.ustring.gsub(_ablist_section, '<div.->', '') | ||
set_custom_glosses(_a) | set_custom_glosses(_a) | ||
end | end | ||
local _ablist = args.abbreviations | local _ablist = args.abbreviations | ||
if _ablist and _ablist ~= "" | if _ablist and _ablist ~= "" then set_custom_glosses(_ablist) end | ||
local _ablist = args.ablist | local _ablist = args.ablist | ||
if _ablist and _ablist ~= "" | if _ablist and _ablist ~= "" then set_custom_glosses(_ablist) end | ||
local _spacing = tonumber(args.spacing) | local _spacing = tonumber(args.spacing) | ||
if _spacing and _spacing <= 20 | if _spacing and _spacing <= 20 then conf.style.WordDiv = conf.style.WordDiv .. 'margin-right: ' .. _spacing .. 'em;' | ||
else conf.style.WordDiv = conf.style.WordDiv .. conf.style.WordMargin end | |||
else conf.style.WordDiv = conf.style.WordDiv .. conf.style.WordMargin | |||
local offset, last_line = 0, 0 | local offset, last_line = 0, 0 | ||
for j,v in ipairs(args) do | for j,v in ipairs(args) do | ||
last_line = last_line +1 | last_line = last_line + 1 | ||
if is_empty(v) | if is_empty(v) then offset = offset + 1 | ||
else | else | ||
local i = j - offset | local i = j - offset | ||
| Line 576: | Line 485: | ||
v = normalise(v) | v = normalise(v) | ||
if if_auto_translit and v == "auto" and i > 1 then | if if_auto_translit and v == "auto" and i > 1 then | ||
local source_line = line[i-1] | local source_line = line[i-1] | ||
local src_lang = source_line.lang | local src_lang = source_line.lang or args.lang | ||
if src_lang then | if src_lang then | ||
v = transliterate(source_line.whole, src_lang) | |||
else v = ""; msg:add("error", "No language specified for automatic transliteration") | else v = ""; msg:add("error", "No language specified for automatic transliteration") end | ||
end | |||
end | |||
line[i].whole = v | line[i].whole = v | ||
| Line 596: | Line 502: | ||
end | end | ||
line[i].class = "" | line[i].class = "" | ||
local _style = args["style" .. i] | local _style = args["style" .. i] | ||
if not _style then _style = "" | if not _style then _style = "" else _style = tidyCss(_style) end | ||
line[i].attr = {style = conf.style.WordP .. _style} | line[i].attr = {style = conf.style.WordP .. _style} | ||
local _lang = args["lang" .. i] | local _lang = args["lang" .. i] | ||
if _lang and #_lang > 1 then | if _lang and #_lang > 1 then line[i].lang = _lang | ||
else _lang = args.lang | else _lang = args.lang | ||
if _lang and #_lang > 1 and i == 1 then | if _lang and #_lang > 1 and i == 1 then line[i].lang = _lang end | ||
end | end | ||
line[i].attr.lang = line[i].lang | line[i].attr.lang = line[i].lang | ||
if template_name == 'Template:Fs interlinear' then | if template_name == 'Template:Fs interlinear' then | ||
if _lang == "bo" and i == 1 then | if _lang == "bo" and i == 1 then | ||
| Line 620: | Line 519: | ||
end | end | ||
end | end | ||
if template_name == 'Template:Interlinear' then | if template_name == 'Template:Interlinear' then | ||
if _lang == "nv" and i == 1 then | if _lang == "nv" and i == 1 then | ||
| Line 627: | Line 525: | ||
end | end | ||
if yesno(args["italics" .. i]) then | if yesno(args["italics" .. i]) then set_italics(i) end | ||
local _transl = args["transl" .. i] | local _transl = args["transl" .. i] | ||
if _transl and #_transl > 1 then | if _transl and #_transl > 1 then | ||
_transl = mw.ustring.lower(_transl) | _transl = mw.ustring.lower(_transl) | ||
local | |||
if | -- Look up transliteration schema titles dynamically from Module:languages | ||
local langObj = languages.getByCode(_lang or "en") | |||
local t_title = _transl .. " transliteration" -- generic fallback | |||
if langObj and type(langObj.getTranslitTitle) == "function" then | |||
t_title = langObj:getTranslitTitle(_transl) or t_title | |||
end | end | ||
line[i].attr.title = t_title | |||
end | end | ||
| Line 650: | Line 543: | ||
if _glossing then | if _glossing then | ||
line[i].glossing = set_glossing_type(_glossing) | line[i].glossing = set_glossing_type(_glossing) | ||
if not ((i == 1 and not yesno(_glossing)) or (i == 2 and yesno(_glossing))) then | if not ((i == 1 and not yesno(_glossing)) or (i == 2 and yesno(_glossing))) then | ||
line.HasCustomGlossing = true | line.HasCustomGlossing = true | ||
| Line 657: | Line 549: | ||
local _ipa = args['ipa' .. i] | local _ipa = args['ipa' .. i] | ||
if yesno(_ipa) then | if yesno(_ipa) then line[i].class = "IPA" end | ||
local _class = args['class' .. i] | local _class = args['class' .. i] | ||
if _class then | if _class then line[i].class = line[i].class .. " " .. _class end | ||
if line[i].class == "" then line[i].class = nil end | |||
end | |||
end | |||
if line[i].class == "" | |||
end | |||
end | |||
local line_count = #line | local line_count = #line | ||
| Line 683: | Line 568: | ||
set_italics(n) | set_italics(n) | ||
elseif not (_italics and not yesno(_italics)) and not (args["italics1"] and not yesno(args["italics1"])) then | elseif not (_italics and not yesno(_italics)) and not (args["italics1"] and not yesno(args["italics1"])) then | ||
set_italics(1) | set_italics(1) | ||
end | end | ||
free_translation = args[last_line] | free_translation = args[last_line] | ||
if not is_empty(free_translation) then | if not is_empty(free_translation) then line [line_count] = nil end | ||
end | end | ||
if yesno(args.glossing) == false then line.HasCustomGlossing = true end | |||
if yesno(args.glossing) == false then | |||
if not line.HasCustomGlossing then | if not line.HasCustomGlossing then | ||
if line_count == 1 then | if line_count == 1 then line[1].glossing = conf.GlossingType | ||
elseif line[2] then line[2].glossing = conf.GlossingType end | |||
elseif line[2] then | |||
end | end | ||
set_global_glossing_settings{style = args['glossing-style'], underline = args.underline, small_caps = args['small-caps']} | set_global_glossing_settings{style = args['glossing-style'], underline = args.underline, small_caps = args['small-caps']} | ||
for i,v in ipairs(line) do | for i,v in ipairs(line) do | ||
local ifglossing = false | local ifglossing = false | ||
if line[i].glossing then | if line[i].glossing then | ||
ifglossing = true | ifglossing = true | ||
glossing_type = line[i].glossing | glossing_type = line[i].glossing | ||
end | end | ||
local wc, n = 1, 1 | local wc, n = 1, 1 | ||
| Line 725: | Line 597: | ||
end | end | ||
local number_of_words, mismatch_found = 0, false | local number_of_words, mismatch_found = 0, false | ||
for i,v in ipairs(line) do | for i,v in ipairs(line) do | ||
local wc = #line[i].words | local wc = #line[i].words | ||
if wc ~= number_of_words then | if wc ~= number_of_words then | ||
if i ~= 1 and wc ~= 0 then | if i ~= 1 and wc ~= 0 then mismatch_found = true end | ||
if wc > number_of_words then number_of_words = wc end | |||
if wc > number_of_words then | |||
end | end | ||
end | end | ||
if mismatch_found then | if mismatch_found then | ||
local error_text = "Mismatch in the number of words between lines: " | local error_text = "Mismatch in the number of words between lines: " | ||
| Line 745: | Line 612: | ||
error_text = error_text .. wc .. " word(s) in line " .. i .. ", " | error_text = error_text .. wc .. " word(s) in line " .. i .. ", " | ||
if wc ~= number_of_words then | if wc ~= number_of_words then | ||
for current_word = wc+1, number_of_words do | for current_word = wc+1, number_of_words do line[i].words[current_word] = " " end | ||
end | end | ||
end | end | ||
if string.sub(error_text, -2) == ", " | if string.sub(error_text, -2) == ", " then error_text = string.sub(error_text, 1, #error_text - 2) .. " " end | ||
error_text = error_text .. help_link("mismatch") | error_text = error_text .. help_link("mismatch") | ||
UserMessages:add("error", error_text) | UserMessages:add("error", error_text) | ||
end | end | ||
if line_count == 1 then | if line_count == 1 then | ||
local span = mw.html.create('span') | local span = mw.html.create('span') | ||
span:attr(line[1].attr) | span:attr(line[1].attr) | ||
for wi = 1, number_of_words do | for wi = 1, number_of_words do | ||
local space | local space = (wi < number_of_words) and " " or "" | ||
span:wikitext(line[1].words[wi] .. space) | span:wikitext(line[1].words[wi] .. space) | ||
end | end | ||
| Line 772: | Line 630: | ||
end | end | ||
local div = mw.html.create("div") | local div = mw.html.create("div") | ||
div:addClass(conf.class.Interlinear) | div:addClass(conf.class.Interlinear) | ||
local number, indent = nil, nil | local number, indent = nil, nil | ||
if args.number and args.number ~= "" | if args.number and args.number ~= "" then number = args.number end | ||
if args.indent and args.indent ~="" then indent = args.indent end | |||
if args.indent and args.indent ~="" | |||
if indent or number then | if indent or number then | ||
if not indent then indent = "4" end | if not indent then indent = "4" end | ||
div:css("margin-left", indent .. 'em') | div:css("margin-left", indent .. 'em') | ||
if number then | if number then | ||
div:tag("div") | div:tag("div"):css("position", "absolute"):css("left", "1em"):wikitext(args.number) | ||
end | end | ||
end | end | ||
if args.box and args.box ~= "" then | if args.box and args.box ~= "" then | ||
div:css("background-color", "#f8f9fa") | div:css("background-color", "#f8f9fa"):css("border", "1px solid #eaecf0"):css("padding", "1em") end | ||
if args.top and args.top ~= "" then div:tag("div"):wikitext(args.top) end | |||
if args.top and args.top ~= "" then | |||
for wi = 1, number_of_words do | for wi = 1, number_of_words do | ||
local div2 = div:tag("div") | local div2 = div:tag("div"):attr("style", conf.style.WordDiv) | ||
for i,_ in ipairs (line) do | for i,_ in ipairs (line) do | ||
if line[i].whole ~= "" then | if line[i].whole ~= "" then | ||
local p = div2:tag("p") | local p = div2:tag("p") | ||
p:attr(line[i].attr) | p:attr(line[i].attr) | ||
if line[i].class then | if line[i].class then p:addClass(line[i].class) end | ||
local _text = line[i].words[wi] | local _text = line[i].words[wi] | ||
if _text == "" or _text == " " | if _text == "" or _text == " " then _text = " " end | ||
p:wikitext(_text) | p:wikitext(_text) | ||
end | end | ||
| Line 821: | Line 662: | ||
end | end | ||
if line.hasComments then | if line.hasComments then | ||
local divc = div:tag("div") | local divc = div:tag("div"):attr("style", conf.style.WordDiv) | ||
for i,_ in ipairs (line) do | for i,_ in ipairs (line) do | ||
local p = divc:tag("p") | local p = divc:tag("p"):attr("style", conf.style.WordP) | ||
if line[i].c then p:wikitext(line[i].c) else p:wikitext(" ") end | |||
if line[i].c then | |||
end | end | ||
end | end | ||
for i,v in ipairs(line) do | for i,v in ipairs(line) do | ||
local hidden_line = div:tag("p") | local hidden_line = div:tag("p") | ||
hidden_line:attr("style", conf.style.HiddenText) | hidden_line:attr("style", conf.style.HiddenText):wikitext(v.whole) | ||
end | end | ||
local ft_line = div:tag("p") | local ft_line = div:tag("p") | ||
if free_translation and free_translation ~= "" then | if free_translation and free_translation ~= "" then | ||
| Line 848: | Line 680: | ||
ft_line:wikitext(free_translation) | ft_line:wikitext(free_translation) | ||
end | end | ||
if args.bottom and args.bottom ~= "" | if args.bottom and args.bottom ~= "" then | ||
local bottom = div:tag('p') | |||
bottom:css('margin-top', '0') | bottom:css('margin-top', '0') | ||
bottom:wikitext(args.bottom) | bottom:wikitext(args.bottom) | ||
end | end | ||
ft_line:node(msg:print_errors()) | ft_line:node(msg:print_errors()) | ||
local end_div = div:tag("div") | local end_div = div:tag("div") | ||
end_div:attr("style", conf.style.EndDiv) | |||
div:newline() | div:newline() | ||
local temp_track = "" | local temp_track = "" | ||
if last_line == 2 | if last_line == 2 then temp_track = "[[Category:Pages with interlinear glosses using two unnamed parameters]]" end | ||
if last_line > 3 and template_name ~= 'Template:Fs interlinear' then temp_track = "[[Category:Pages with interlinear glosses using more than three unnamed parameters]]" end | |||
if last_line > 3 and template_name ~= 'Template:Fs interlinear' | |||
return tostring(div) .. temp_track .. msg:print_warnings() | return tostring(div) .. temp_track .. msg:print_warnings() | ||
end | end | ||
return p | return p | ||