该模块提供了一种简便的创建大段带翻译歌词的方法,可以在歌词中使用多种颜色来分辨不同的演唱者。
本模块被包装成模板{{LyricsKai/colors}}使用,不建议在只有单个演唱者的歌曲条目中使用本模块。
local module = {} local getArgs = require('Module:Arguments').getArgs local rainbow = require('Module:rainbow')._main local genCharaBlock = require('Module:Lyrics/colors/sub')._charaBlock local buildLyrics = require('Module:Lyrics')._lyrics local initHandler = require('Module:HooksHandler').init function module.parseArgs(colorsStr, charasStr, charaBlock) local colors = mw.text.split(mw.ustring.gsub(colorsStr, ';+$', ''), '%s*;+%s*') local aliases = {} for idx, val in ipairs(colors) do if mw.ustring.find(val, '=', 1, true) then colors[idx], aliases[idx] = mw.ustring.match(val, '^%s*([^=]+)%f[%s=]%s*=%s*(.+)%f[%s%z]%s*$') end end local charas = mw.text.split(mw.ustring.gsub(charasStr, ';+$', ''), '%s*;+%s*') for idx, val in ipairs(charas) do if charaBlock then charas[idx] = mw.ustring.gsub(val, '%(.+%)', '') end end local map_aliases = {} for idx, val in pairs(aliases) do map_aliases[val] = idx end for idx, val in pairs(charas) do map_aliases[val] = idx end return colors, map_aliases, charas end function module.parse(colors, charas, chorusName, sentence) local count_colors = #colors -- 包裹节点 local chorus = '合唱' if #charas > count_colors then chorus = charas[#charas] end if chorusName ~='' then chorus = chorusName end for i=1, #sentence do local preParsed = mw.ustring.gsub(sentence[i], '(@%d%d?)([^@\n]+)\n-', function(m1, m2) if m1:len() > 2 and tonumber(m1:sub(2)) > count_colors then m1 = m1:sub(1, 2) m2 = m1:sub(3) .. m2 end return mw.ustring.format('<*span title="%s" style="color:%s">%s<*/span>', m1, m1, m2) end) if mw.ustring.find(sentence[i], '^@d+.-@.') or mw.ustring.find(sentence[i], '^[^@]') then preParsed = '<span class="NoTitlebox" title="'..chorus..'">'..preParsed..'</span>' end sentence[i] = preParsed end local mode = { lg = 'linear', rg = 'radial', rlg = 'repeating-linear', rrg = 'repeating-radial', rb = 'linear' } local special_color = {} for idx, val in ipairs(colors) do local match = val:match('^([lrc][lr]?[gbo])%(', 1) if match and (mode[match] or match == 'co') then special_color[idx] = match end end for i, material in ipairs(sentence) do local need_special = {} material = mw.ustring.gsub(material, 'color:@(%d+)', function (m) m = tonumber(m) if special_color[m] then need_special[special_color[m]] = true end return 'color:' .. (colors[m] or '') end) material = mw.ustring.gsub(material, 'title="@(%d+)"', function (m) m = tonumber(m) return charas[m] and ('title="' .. charas[m] ..'"') or '' end) -- 渐变色实现 for k, _ in pairs(need_special) do v = mode[k] if v then material = mw.ustring.gsub(material, '<%*span ([^>]-)style="color:'..k..'(%(.-%))">(.-)<%*/span>', function(s1, s2, s3) if k == 'rb' then local pattern = '' s2 = mw.ustring.gsub(s2, '%((.+)%)', '%1') local colors = mw.text.split(s2, ',', true) local quotient = 100 / #colors for i, v in ipairs(colors) do local color = mw.text.trim(v) if i == 1 then pattern = color..' '..quotient..'%' else pattern = pattern..', '..color..' '..(quotient * (i - 1))..'%'..', '..color..' '..(quotient * i)..'%' end end s2 = '('..pattern..')' end local style = 'background:-webkit-'..v..'-gradient'..s2..';-webkit-background-clip:text;-webkit-text-fill-color:transparent;-webkit-box-decoration-break:clone;' --[[ s3 = mw.ustring.gsub(s3, '<rt%s*([^>]-)%s*>', function(s) if s ~= '' then local before, attr, after = mw.ustring.match(s, '^(.-style=")([^"]*)(".*)$') if attr ~= nil and mw.text.trim(attr) == '' then attr = nil end if attr ~= nil then s = before..attr..'; '..style..after else s = (before or s..' style="')..style..(after or '"') end else s = ' style="'..style..'"' end return '<rt '..s..'>' end) ]]-- -- 额外套一层span,以免影响titlebox return '<span '..s1..'><span class="Lyrics-gradient" style="'..style..'">'..s3..'</span></span>' end) end end -- 交替色实现 if need_special['co'] then material = mw.ustring.gsub(material, '<%*span ([^>]-)style="color:co%((.-)%)">(.-)<%*/span>', function(s1, s2, s3) local colors = mw.text.split(s2, ',') for idx, val in ipairs(colors) do colors[idx] = mw.text.trim(val) end return '<span '..s1..'>'..rainbow(colors, s3)..'</span>' end) end -- 整理节点 sentence[i] = mw.ustring.gsub(mw.ustring.gsub(material, '<%*(/?span)', '<%1'), '@', '') end return sentence end local preSplit = function (original, translated, customArgs) local ce = {} local deal = function (text) text = mw.ustring.gsub(text, '%$([%d%$%[@])', function(s) if not ce[s] then ce[s] = mw.getCurrentFrame():expandTemplate{ title = 'ce', args = {s} } end return ce[s] end) text = mw.ustring.gsub(text, '@%[([^%[]-)%]', function(match) return '@' .. (customArgs.map_aliases[match] and customArgs.map_aliases[match] or '['..match..']') end) return text end return deal(original), deal(translated) end local preParse = function (original, translated, customArgs) original = module.parse(customArgs.colors, customArgs.charas, customArgs.chorusName, original) if customArgs.traColors and translated then translated = module.parse(customArgs.colors, customArgs.charas, customArgs.chorusName, translated) end end local preOutput = function (html, customArgs) if customArgs.doCharaBlock then html = '<p>' .. genCharaBlock(customArgs.genCharaBlock) .. '</p>' .. html end local css = mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Template:LyricsKai/colors/styles.css' } } return css .. html end function module.initHooks(args, hooksHandler, customArgs) customArgs.traColors = (args.traColors or '') == 'on' customArgs.doCharaBlock = (args.charaBlock or '') == 'on' customArgs.chorusName = args.chorusName or '' customArgs.colors, customArgs.map_aliases, customArgs.charas = module.parseArgs(args.colors or '', args.charas or '', customArgs.doCharaBlock) customArgs.genCharaBlock = { colors = args.colors or '', charas = args.charas or '', groupName = args.groupName, groupColor = args.lstyle } return hooksHandler({ preSplit = preSplit, preParse = preParse, preOutput = preOutput }) end function module.main(frame) local args = getArgs(frame, { wrappers = 'Template:LyricsKai/colors' }) local hooksHandler, customArgs = initHandler(), {} local hookTrigger = module.initHooks(args, hooksHandler, customArgs) return buildLyrics(args, hookTrigger, customArgs) end return module