Module:FormatSegmentRow
From Bodhicitta
Documentation for this module may be created at Module:FormatSegmentRow/doc
local p = {}
-- TransMemID prefixes that indicate a non-English SegmentTranslation
local TRANSMEM_LANG = {
['004-Tsadra-BCA-Root-Padmakara-French'] = 'french',
['021-Tsadra-BCA-Padmakara-Spanish'] = 'spanish',
}
-- Build language table, routing SegmentTranslation to the correct language
-- based on TransMemID (defaults to english)
local function buildLanguages(transMemLang)
local englishParams = (transMemLang == 'english') and {'SegmentTranslation'} or {}
local frenchParams = (transMemLang == 'french') and {'SegmentTranslation', 'FrenchTranslation', 'French'} or {'FrenchTranslation', 'French'}
local spanishParams = (transMemLang == 'spanish') and {'SegmentTranslation', 'Spanish'} or {'Spanish'}
return {
{ id = 'tibetan', params = {'SegmentSource'}, classPrefix = 'tibetan-version', textClass = 'text-160', langType = 'source' },
{ id = 'tibetan-tsadra', params = {'SegmentSourceTsadra'}, classPrefix = 'tibetan-tsadra-version', textClass = 'text-160', langType = 'source' },
{ id = 'english', params = englishParams, classPrefix = 'english-version', textClass = 'text-article', langType = 'translation' },
{ id = 'wylie', params = {'SourceTranslit'}, classPrefix = 'wylie-version', textClass = 'text-article', langType = 'translation' },
{ id = 'wylie-tsadra', params = {'SegmentTranslitTsadra'}, classPrefix = 'wylie-tsadra-version', textClass = 'text-article', langType = 'translation' },
{ id = 'french', params = frenchParams, classPrefix = 'french-version', textClass = 'text-article', langType = 'translation' },
{ id = 'spanish', params = spanishParams, classPrefix = 'spanish-version', textClass = 'text-article', langType = 'translation' },
{ id = 'devanagari', params = {'SanskritSource'}, classPrefix = 'devanagari-version', textClass = 'text-160', langType = 'source' },
{ id = 'sanskrit', params = {'SanskritTranslit'}, classPrefix = 'sanskrit-version', textClass = 'text-article', langType = 'translation' },
}
end
-- Priority order for default visible language per side, given available params
local leftPriority = { 'tibetan', 'tibetan-tsadra', 'devanagari', 'wylie', 'wylie-tsadra', 'sanskrit' }
local rightPriority = { 'english', 'french', 'spanish', 'wylie', 'wylie-tsadra' }
-- Get first non-empty value from a list of param names
local function getParamValue(args, paramNames)
for _, name in ipairs(paramNames) do
local val = args[name]
if val and mw.text.trim(val) ~= '' then
return mw.text.trim(val)
end
end
return nil
end
-- Resolve default language for a side: first priority-list entry with content in args
local function resolveDefault(args, priorityList, languages)
local paramsByLang = {}
for _, lang in ipairs(languages) do
paramsByLang[lang.id] = lang.params
end
for _, id in ipairs(priorityList) do
local params = paramsByLang[id]
if params and #params > 0 and getParamValue(args, params) then
return id
end
end
return priorityList[1]
end
-- Convert semicolon-separated page names into wiki links
local function wikiLinkList(str)
local links = {}
for page in mw.text.gsplit(str, '%s*;%s*') do
if page ~= '' then
table.insert(links, '[[' .. page .. ']]')
end
end
return table.concat(links, ', ')
end
-- Wrap content with poem extension tag (for translation-side verse formats)
local function wrapPoem(frame, content)
return frame:extensionTag('poem', '<p class="m-0">' .. content .. '</p>')
end
-- Apply SegmentFormat styling to content
-- isSource: true for source-type languages, false for translation-type
local function formatContent(content, format, isSource, frame, sabcheNum, quoteSource)
if not content then return nil end
if format == 'Root' then
if isSource then
return '<div class="pl-4" style="color: #8c1409;"><p>' .. content .. '</p></div>'
else
return '<div class="p-bl-fix pl-4 my-2" style="color: #8c1409;"><p>' .. content .. '</p></div>'
end
elseif format == 'Title' then
if isSource then
return '<span class="text-130" style="color: #467083;">' .. content .. '</span>'
else
return '<div class="h3 font-serif-alt" style="color: #467083; white-space: break-spaces;">' .. content .. '</div>'
end
elseif format == 'Commentary' or format == 'Commentary2' or format == 'Colophon' then
return content
elseif format == 'Quote' then
local noteSuffix = ''
if quoteSource and quoteSource ~= '' then
noteSuffix = frame:expandTemplate{ title = 'note', args = { 'source', wikiLinkList(quoteSource) } }
end
if isSource then
return '<div class="pl-4" style="color: #897435;">' .. content .. noteSuffix .. '</div>'
else
return '<div class="pl-4" style="color: #897435;">' .. wrapPoem(frame, content .. noteSuffix) .. '</div>'
end
elseif format == 'DoubleQuote' or format == 'Verse inside a quote' then
local noteSuffix = ''
if quoteSource and quoteSource ~= '' then
noteSuffix = frame:expandTemplate{ title = 'note', args = { 'source', wikiLinkList(quoteSource) } }
end
if isSource then
return '<div class="pl-5" style="color: #897435;">' .. content .. noteSuffix .. '</div>'
else
return '<div class="pl-5" style="color: #897435;">' .. wrapPoem(frame, content .. noteSuffix) .. '</div>'
end
elseif format == 'Sabche' then
if isSource then
return '<span style="color: #467083;">' .. content .. '</span>'
else
local sabche = '<div class="p-bl-fix"><span style="color: #467083;">' .. content .. '</span>'
if sabcheNum then
sabche = sabche .. ' <span class="float-right">' .. sabcheNum .. '</span>'
end
return sabche .. '</div>'
end
elseif format == 'SabcheHeading' then
if isSource then
return '<div class="mt-3" style="color: #467083;">' .. content .. '</div>'
else
local heading = '<div class="h5 mt-3 font-serif-alt" style="color: #467083;">' .. content
if sabcheNum then
heading = heading .. ' <span class="float-right">' .. sabcheNum .. '</span>'
end
return heading .. '</div>'
end
elseif format == 'SabcheSubHeading' then
if isSource then
return '<div class="mt-2" style="color: #467083;">' .. content .. '</div>'
else
local subheading = '<div class="h6 mt-2 font-serif-alt" style="color: #467083;">' .. content
if sabcheNum then
subheading = subheading .. ' <span class="float-right">' .. sabcheNum .. '</span>'
end
return subheading .. '</div>'
end
elseif format == 'Section Title1' then
if isSource then
return content
else
return '<div class="h3 font-serif-alt" style="color: #467083; white-space: break-spaces;">' .. content .. '</div>'
end
elseif format == 'Section Title2' then
if isSource then
return '<span class="text-120" style="color: #467083;">' .. content .. '</span>'
else
return '<div class="h4 font-serif-alt" style="color: #467083; white-space: break-spaces;">' .. content .. '</div>'
end
elseif format == 'Indented Verse' then
if isSource then
return '<div class="pl-4">' .. content .. '</div>'
else
return '<div class="pl-4">' .. wrapPoem(frame, content) .. '</div>'
end
elseif format == 'Root non-verse' then
return '<span style="color: #8c1409;">' .. content .. '</span>'
else
-- Default: no special formatting
return content
end
end
-- Render all language divs for one side (left or right)
local function renderSide(args, side, format, frame, defaultLang, languages)
local sabcheNum = getParamValue(args, {'SourceSabcheNumber'})
local quoteSource = getParamValue(args, {'QuoteSource'})
local parts = {}
for _, lang in ipairs(languages) do
if #lang.params > 0 then
local content = getParamValue(args, lang.params)
if content then
local isSource = (lang.langType == 'source')
local formatted = formatContent(content, format, isSource, frame, sabcheNum, quoteSource)
if formatted then
local hidden = lang.id ~= defaultLang and ' hidden' or ''
local classes = 'toggleable ' .. lang.classPrefix .. '-' .. side .. ' ' .. lang.textClass .. hidden
table.insert(parts, '<div class="' .. classes .. '">' .. formatted .. '</div>')
end
end
end
end
return table.concat(parts)
end
function p.main(frame)
local args = frame:getParent().args
local format = getParamValue(args, {'SegmentFormat'}) or 'Commentary'
-- Determine which language SegmentTranslation holds based on TransMemID
local transMemId = getParamValue(args, {'TransMemID'}) or ''
local transMemLang = TRANSMEM_LANG[transMemId] or 'english'
local languages = buildLanguages(transMemLang)
local defaultLeft = resolveDefault(args, leftPriority, languages)
local defaultRight = resolveDefault(args, rightPriority, languages)
-- Fetch SingleLanguage and SingleColumn from the current page via #show.
-- mw.smw.ask cannot reliably query the current page's own properties during
-- the same parse (SMW hasn't committed them yet), so we use frame:callParserFunction
-- with #show instead, which reads already-stored SMW values correctly.
local pageTitle = mw.title.getCurrentTitle().prefixedText
local singleLang = mw.text.trim(frame:callParserFunction('#show', pageTitle, '?SingleLanguage'))
if singleLang == '' then singleLang = nil else singleLang = singleLang:lower() end
local scRaw = mw.text.trim(frame:callParserFunction('#show', pageTitle, '?SingleColumn')):lower()
local singleColumn = (scRaw == 'true' or scRaw == '1' or scRaw == 't')
local svnRaw = mw.text.trim(frame:callParserFunction('#show', pageTitle, '?ShowVerseNumbers')):lower()
local showVerseNumbers = (svnRaw == 'true' or svnRaw == '1' or svnRaw == 't')
local verseNum = getParamValue(args, {'RootTextChapVerseNum', 'RootTextVerseNum'})
local showVerseCol = showVerseNumbers and verseNum ~= nil
local verseCol = ''
if showVerseCol then
verseCol = '<div class="col-1 text-right font-serif-alt text-160 pt-1 mb-3">' .. verseNum .. '</div>'
end
-- Determine which side the single language lives on
local singleIsLeft = singleLang and (function()
for _, id in ipairs(leftPriority) do if id == singleLang then return true end end
end)()
local singleIsRight = singleLang and (function()
for _, id in ipairs(rightPriority) do if id == singleLang then return true end end
end)()
-- Filter languages to only the requested one when in single-language mode
local function filterLanguages(langs, targetId)
local filtered = {}
for _, lang in ipairs(langs) do
if lang.id == targetId then
table.insert(filtered, lang)
end
end
return filtered
end
local output = ''
local mainClass = showVerseCol and 'col-11' or 'col-12'
local halfClass = showVerseCol and 'col-md-5' or 'col-md-6'
if singleColumn then
-- Single-column mode: all available languages in one column, left-side classes.
-- The language switcher (RootVerseToggles) still works since the togglable divs
-- use the same tibetan-version-left / wylie-version-left etc. class names.
local content = renderSide(args, 'left', format, frame, defaultLeft, languages)
output = verseCol .. '<div class="' .. mainClass .. ' font-serif line14 p-bl-fix mb-3">' .. content .. '</div>'
elseif singleLang then
-- Single-language mode: render only the matching column at full width
if singleIsLeft then
local filteredLangs = filterLanguages(languages, singleLang)
local content = renderSide(args, 'left', format, frame, singleLang, filteredLangs)
output = verseCol .. '<div class="' .. mainClass .. ' font-serif line14 p-bl-fix mb-3">' .. content .. '</div>'
elseif singleIsRight then
local filteredLangs = filterLanguages(languages, singleLang)
local content = renderSide(args, 'right', format, frame, singleLang, filteredLangs)
output = verseCol .. '<div class="' .. mainClass .. ' line14 p-bl-fix mb-3">' .. content .. '</div>'
else
-- Unknown language id: fall back to normal two-column layout
local left = renderSide(args, 'left', format, frame, defaultLeft, languages)
local right = renderSide(args, 'right', format, frame, defaultRight, languages)
output = verseCol .. '<div class="' .. halfClass .. ' font-serif line14 p-bl-fix mb-3">' .. left .. '</div>'
.. '<div class="' .. halfClass .. ' line14 p-bl-fix mb-3">' .. right .. '</div>'
end
else
-- Normal two-column layout
local left = renderSide(args, 'left', format, frame, defaultLeft, languages)
local right = renderSide(args, 'right', format, frame, defaultRight, languages)
output = verseCol .. '<div class="' .. halfClass .. ' font-serif line14 p-bl-fix mb-3">' .. left .. '</div>'
.. '<div class="' .. halfClass .. ' line14 p-bl-fix mb-3">' .. right .. '</div>'
end
return output
end
return p