Module:Furigana
跳到导航
跳到搜索
流 れた星 はどこへ行 く?旗 を掲 げ進 もう
用于标注一堆振假名。
用法
{{Photrans/button}} {{LyricsKai |original= {{振假名|template=Photrans |きらり空(そら)に響(ひび)く星(ほし)の声(こえ) ああ海(うみ)を照(て)らす 光(ひかり)を辿(たど)れたら 流(なが)れた星(ほし)はどこへ行(ゆ)く? きっと何(なに)かがそこで待(ま)ってる 旗(はた)を掲(かか)げ進(すす)もう いつでも月(つき)は歌(うた)い 旅人(たびびと)を導(みちび)いて 「もう迷(まよ)わなくていいから」 }} |translated= <!-- 略 --> }}
与下面这段代码效果相同。
{{Photrans/button}} {{LyricsKai |original= きらり{{Photrans|空|そら}}に{{Photrans|響|ひび}}く{{Photrans|星|ほし}}の{{Photrans|声|こえ}} ああ{{Photrans|海|うみ}}を{{Photrans|照|て}}らす {{Photrans|光|ひかり}}を{{Photrans|辿|たど}}れたら {{Photrans|流|なが}}れた{{Photrans|星|ほし}}はどこへ{{Photrans|行|ゆ}}く? きっと{{Photrans|何|なに}}かがそこで{{Photrans|待|ま}}ってる {{Photrans|旗|はた}}を{{Photrans|掲|かか}}げ{{Photrans|進|すす}}もう いつでも{{Photrans|月|つき}}は{{Photrans|歌|うた}}い {{Photrans|旅人|たびびと}}を{{Photrans|導|みちび}}いて 「もう{{Photrans|迷|まよ}}わなくていいから」 |translated= <!-- 略 --> }}
效果:
本段落中所使用的歌词,其著作权属于原著作权人,仅以介绍为目的引用。
きらり空 に響 く星 の声
亮晶晶 天空中回响着 星星的声音
ああ海 を照 らす 光 を辿 れたら
啊 追着照亮海面的光束
流星将去向何处
きっと何 かがそこで待 ってる
在那儿一定有什么在等着
扬起旗帜前进吧
いつでも月 は歌 い 旅人 を導 いて
无论何时 月儿在歌唱 为旅人指着路
「もう迷 わなくていいから」
所以不会再迷路了
参数
- 匿名参数:需要转换振假名的内容,可以传入多个参数。形如
漢字[1](かんじ)
的将被转换为{{template|漢字|かんじ}}
,注意是全角括号。 template
:振假名所用模板名,默认值为Ruby
。compatible
:为非空值时启用兼容模式。仅当不启用兼容模式会出问题时才应启用兼容模式。
模板不自带语言属性,请确保本模板外部标注了语言,例如,{{LyricsKai}}左栏默认标注了lang="ja"
。
连续汉字只标注一部分
用管道符隔开即可:
{{lj|{{振假名|……由崎|星空(ナサ)……}}}}
结果:……由崎
对比不隔开的效果:
{{lj|{{振假名|……由崎星空(ナサ)……}}}}
结果:……
汉字后的括号不是注音
要使汉字后的括号出现在正文中,使用管道符将汉字与括号隔开即可:
{{lj|{{振假名|世紀の覚醒|(2度寝ー3度寝ー)}}}}
结果:世紀の覚醒(2度寝ー3度寝ー)
想要注音的文字不是汉字
本模板内可以正常用其他注音模板:
{{lj|{{振假名|{{ruby|1人|ひとり}}でも大丈夫(だいじょうぶ)だからただ前(まえ)を見(み)て}}}}
结果:
从其他注音模板转换为本模板
一个工具模块Furigana/utils的transform
函数可用于转换源代码,使用时请替换引用(即subst:
)。它将自动识别所使用的注音模板(限{{Ruby}}、{{Photrans}}、{{Photrans2}}和{{Photransa}}),并选择出现次数最多的作为template
参数[2],未被选中的会保留原样。
{{LyricsKai |original= {{subst:#invoke:Furigana/utils|transform| きらり{{Photrans|空|そら}}に{{Photrans|響|ひび}}く{{Photrans|星|ほし}}の{{Photrans|声|こえ}} ああ{{Photrans|海|うみ}}を{{Photrans|照|て}}らす {{Photrans|光|ひかり}}を{{Photrans|辿|たど}}れたら {{Photrans|流|なが}}れた{{Photrans|星|ほし}}はどこへ{{ruby|行|ゆ}}く? きっと{{Photrans|何|なに}}かがそこで{{Photrans|待|ま}}ってる {{Photrans|旗|はた}}を{{Photrans|掲|かか}}げ{{Photrans|進|すす}}もう いつでも{{Photrans|月|つき}}は{{Photrans|歌|うた}}い {{Photrans|旅人|たびびと}}を{{Photrans|導|みちび}}いて 「もう{{Photrans|迷|まよ}}わなくていいから」 }} |translated= <!-- 略 --> }}
保存后代码将变为:
{{LyricsKai |original= {{振假名|template=Photrans |きらり空(そら)に響(ひび)く星(ほし)の声(こえ) ああ海(うみ)を照(て)らす 光(ひかり)を辿(たど)れたら 流(なが)れた星(ほし)はどこへ{{ruby|行|ゆ}}く? きっと何(なに)かがそこで待(ま)ってる 旗(はた)を掲(かか)げ進(すす)もう いつでも月(つき)は歌(うた)い 旅人(たびびと)を導(みちび)いて 「もう迷(まよ)わなくていいから」 }} |translated= <!-- 略 --> }}
该转换模块同样支持通过template
手动指定注音模板,不限于上面几个自动识别的模板。
注意,如果原始代码中,某个注音模板符合以下情况之一:
- 包含超过2个参数;
- 包含换行;
- 包含等号;
- 参数1不全是汉字[1];
- 嵌套了模板。
则该注音模板将保留原样。例如:
{{subst:#invoke:Furigana/utils|transform| きらり{{ruby|空|そら}}に{{ruby|響|ひび|ja}}く{{ruby|星|ほ し}}の{{ruby|声|{{黑幕|こえ}}}} {{ruby|1人|ひとり}} }}
保存后代码将变为:
{{振假名 |きらり空(そら)に{{ruby|響|ひび|ja}}く{{ruby|星|ほ し}}の{{ruby|声|{{黑幕|こえ}}}} {{ruby|1人|ひとり}} }}
模块测试结果(开发者用)
结果 |
---|
脚本错误:没有“Furigana/tests”这个模块。 |
|
注释
local p = {} -- 转化为upvalue,提升速度 local type = type local ipairs = ipairs local concat = table.concat local u_gsub = mw.ustring.gsub local u_sub = mw.ustring.sub local KANJI_LIKE_UNICODE_RANGES = { { 0x2E80, 0x2EFF }, -- CJK部首补充 { 0x3005, 0x3007 }, -- "々、〆、〇" { 0x31C0, 0x31EF }, -- CJK笔画 { 0x3400, 0x4DBF }, -- CJK统一表意文字扩展A { 0x4E00, 0x9FFF }, -- CJK统一表意文字 { 0xF900, 0xFAFF }, -- CJK兼容表意文字 { 0x20000, 0x2A6DF }, -- CJK统一表意文字扩展B { 0x2A700, 0x2EE5F }, -- CJK统一表意文字扩展C-I { 0x2F800, 0x2FA1F }, -- CJK兼容表意文字补充 { 0x30000, 0x323AF }, -- CJK统一表意文字扩展G-H } local KANJI_LIKE_PATTERN = (function () local char = mw.ustring.char local parts = {} for i, range in ipairs(KANJI_LIKE_UNICODE_RANGES) do parts[i] = type(range) == 'table' and char(range[1])..'-'..char(range[2]) or char(range) end return '['..concat(parts)..']' end)() --[[ 把<tag>、</tag>与其他文本分开。 ```lua divide_tags_and_non_tags('A<span title="(title)">B</span>C') --> { { type = 'unknown', content = 'A' }, { type = 'tag', content = '<span title="(title)">' }, { type = 'unknown', content = 'B' }, { type = 'tag', content = '</span>' }, { type = 'unknown', content = 'C' }, ``` ]] ---@param text string ---@return {type: 'tag' | 'unkown', content: string}[] local function extract_tags(text) local result = {} local rest = text :gsub( '(.-)(</?[:%a_][:%w_-.]*[^<>]*>)', function (non_tag, tag) if non_tag ~= '' then result[#result+1] = { type = 'unknown', content = non_tag } end result[#result+1] = { type = 'tag', content = tag } return '' end ) if rest ~= '' then result[#result+1] = { type = 'unknown', content = rest } end return result end local EXTRACT_RB_RT_PATTERN = '(.-)('..KANJI_LIKE_PATTERN..'+)(%b())' ---@param text string ---@param into_tokens ({type: 'ruby-part' | 'tag' | 'text', content: string} | {type: 'rb-rt', rb: string, rt: string})[] local function extract_rb_rt(text, into_tokens) for line_with_lf in text:gmatch('[^\n]*\n*') do local rest = u_gsub( line_with_lf, EXTRACT_RB_RT_PATTERN, function (before, rb, rt) if before ~= '' then into_tokens[#into_tokens+1] = { type = 'text', content = before } end into_tokens[#into_tokens+1] = { type = 'rb-rt', rb = rb, rt = u_sub(rt, 2, -2), -- 去除括号 } return '' end ) if rest ~= '' then into_tokens[#into_tokens+1] = { type = 'text', content = rest } end end end ---细节见测试 [[Module:Furigana/tests]]。 ---@param tokens {type: 'tag' | 'unkown', content: string}[] ---@param into_tokens ({type: 'ruby-part' | 'tag' | 'text', content: string} | {type: 'rb-rt', rb: string, rt: string})[] local function extract_others(tokens, into_tokens) local ruby_start_index = nil for i, token in ipairs(tokens) do if ruby_start_index then -- 如果处于<ruby>标签内,则所有token都是ruby-part into_tokens[#into_tokens+1] = { type = 'ruby-part', content = token.content } if token.type == 'tag' and token.content:match('^</[Rr][Uu][Bb][Yy]') then ruby_start_index = nil end elseif token.type == 'tag' then if token.content:match('^<[Rr][Uu][Bb][Yy]') then into_tokens[#into_tokens+1] = { type = 'ruby-part', content = token.content } ruby_start_index = i else ---@diagnostic disable-next-line: assign-type-mismatch into_tokens[#into_tokens+1] = token end else -- assert(token.type == 'unknown') extract_rb_rt(token.content, into_tokens) end end end ---将`texts`解析为tokens,细节见测试[[Module:Furigana/tests]]。 ---@param texts string[] ---@return ({type: 'ruby-part' | 'tag' | 'text', content: string} | {type: 'rb-rt', rb: string, rt: string})[] local function parse(texts) local tokens = {} for _, text in ipairs(texts) do extract_others(extract_tags(text), tokens) end return tokens end p.parse = parse ---用`render_ruby`渲染`tokens`中的`rb-rt` token,其余token不变,最终连接为一个字符串。 ---@param tokens ({type: 'ruby-part' | 'tag' | 'text', content: string} | {type: 'rb-rt', rb: string, rt: string})[] ---@param render_ruby fun(rb: string, rt: string): string ---@return string local function render(tokens, render_ruby) local result = {} for i, token in ipairs(tokens) do result[i] = token.type == 'rb-rt' and render_ruby(token.rb, token.rt) or token.content end return concat(result) end p.render = render ---将`texts`中用“汉字(注音)”表示的振假名替换为`render_ruby`的返回值。 ---@param texts string | string[] ---@param render_ruby fun(rb: string, rt: string): string ---@return string function p.process(texts, render_ruby) if type(texts) == 'string' then texts = { texts } end local tokens = parse(texts) return render(tokens, render_ruby) end function p.main(frame, args) if not args then local parent = frame:getParent() local templates = { ['Template:振假名'] = true, ['Template:Sandbox'] = true } if parent and templates[parent:getTitle()] then frame = parent end args = frame.args end local template = args.template or 'Ruby' if mw.isSubsting() then local prefix = '{{'..template..'|' return p.process(args, function (rb, rt) return prefix..rb..'|'..rt..'}}' end) end local is_compatible_mode = args.compatible and args.compatible ~= '' if not is_compatible_mode then -- 快速模式,通过字符串替换,避免多次调用frame:expandTemplate local placeholder_pattern = '!@$r[bt]$@!' local rb_placeholder = '!@$rb$@!' local rt_placeholder = '!@$rt$@!' local template_string = frame:expandTemplate { title = template, args = { rb_placeholder, rt_placeholder }, } if template_string:find(placeholder_pattern) then return p.process(args, function (rb, rt) return template_string:gsub(placeholder_pattern, { [rb_placeholder] = rb, [rt_placeholder] = rt }) end) end end return p.process(args, function (rb, rt) return frame:expandTemplate { title = template, args = { rb, rt }, } end) end return p