模組:Vgtn
外观

require('strict')
local getArgs = require('Module:Arguments').getArgs
local p = {}
local rule_data = require('Module:Vgtn/data')
local function unnest_table(data)
--[==[將嵌套的定義規則扁平化。
:param data: 雙層嵌套的表。
:return: 扁平化後的資料。
]==]
local rules = {}
for _, group in ipairs(data) do
for _, subgroup in ipairs(group) do
for _, rule in ipairs(subgroup) do
table.insert(rules, rule)
end
end
end
return rules
end
local function get_rule(rules, original, lang)
--[==[根据原文名和语言代码,从译名规则表中获取符合条件的首条规则。
指定语言代码时,返回原文名、语言标签皆匹配的首条定义项。
未指定语言代码时,返回与原文名匹配的首条定义项。
若无匹配项,则返回只有原文名(和语言代码)而无译名定义的空规则。
:param rules: 由译名规则构成的表。
:param original: 所查询的原文名。
:param lang: 原文名语言代码,可缺省。
:return: 一条译名定义规则。
示例
----
>>> local rules = {
>>> { 'Arend Jacobs', lang = 'de', cn = '阿伦德·雅各布斯' },
>>> { 'Arend Jacobs', lang = 'en', cn = '阿伦·雅各布斯' },
>>> }
>>> get_rule(rules, 'Arend Jacobs', 'en')
{ 'Arend', lang = 'en', cn = '阿伦·雅各布斯' },
>>> get_rule(rules, 'Arend Jacobs') -- 符合条件的首项结果
{ 'Arend', lang = 'de', cn = '阿伦德·雅各布斯' },
>>> get_rule(rules, 'Arend Jacobs', 'fr') -- 查无法语名稱的定义,返回空规则
{ 'Arend', lang = 'fr' },
>>> get_rule(rules, 'Kamisato Ayaka') -- 查无此原名,返回空规则
{ 'Kamisato Ayaka' },
]==]
for _, rule in ipairs(rules) do
if (original == rule[1]) and (lang == nil or lang == rule.lang) then
return rule
end
end
return { original, lang = lang }
end
local function get_part_name(name, part, sep)
--[==[提取姓名的指定部分。主要用于处理地区词转换时,只需要写姓氏的问题。
:param name: 待提取的姓名全名。
:param part: 所提取的部分索引(負數則表示逆序),为`nil`或0时返回全名。预设为`nil`。
:param sep: 分隔符。预设为中文间隔号('·'),但若姓名中不含间隔号时为空格(' ')。
:return: 所提取的姓名片段。
示例
----
>>> get_part_name('杰里米·帕里什', 2)
帕里什
>>> get_part_name('John D. Carmack', 3, ' ') -- 省略第三参数亦可得出结果
Carmack
]==]
if name == nil or part == nil or part == 0 then
return name
end
local split_result
if sep then
split_result = mw.text.split(name, sep, true)
elseif mw.ustring.find(name, '·') then
split_result = mw.text.split(name, '·', true)
else
split_result = mw.text.split(name, ' ', true)
end
if part > #split_result or part < - #split_result then
return name
elseif part > 0 then
return split_result[part]
else
return split_result[#split_result + part + 1]
end
end
local function parse_translation(rule, part, sep)
--[==[将译名定义规则中译名部分解释为维基代码,可根据分隔符取姓名片段。
若简体(`cn`、`sg`、`my`)和繁体(`tw`、`hk`、`mo`)两类译名均有定义,则返回内联转换代码`-{zh-xx:...;}-`。
若仅定义其中一种书写体系下的译名,则返回普通文字。
若未定义任何中文译名,则返回nil。
:param rule: 译名定义规则。
:param part: 所提取的姓名片段编号。例如对于译名'约翰·D·卡马克',可输入3仅列出'卡马克'。
:param sep: 片段的分隔符。预设为中文间隔号('·'),但若姓名中不含间隔号时为空格(' ')。
:return: 译名规则中译名部分对应的维基代码,以及其中一個中文譯名(用於生成頁面連結)。
示例
----
>>> rule = { 'Jeremy Parish', cn = '杰里米·帕里什', hk = '謝洛美·巴里殊', tw = '傑瑞米·派瑞許' }
>>> parse_translation(rule)
-{zh-cn:杰里米·帕里什; zh-hk:謝洛美·巴里殊; zh-tw:傑瑞米·派瑞許;}-
>>> parse_translation(rule, 2)
-{zh-cn:帕里什; zh-hk:巴里殊; zh-tw:派瑞許;}-
>>> -- 仅定义一种译名,不启用内联字词转换
>>> local rule = { 'John Carmack', lang='en', cn = '约翰·D·卡马克' }
>>> parse_translation(rule)
约翰·D·卡马克
>>> parse_translation(rule, 3)
卡马克
>>> -- 未定义简繁两种体系下的译名,故依然无法地区词转换,只生成了其中一种译名的普通文本。
>>> local rule = { 'Jeremy Parish', hk = '謝洛美·巴里殊', tw = '傑瑞米·派瑞許' }
>>> parse_translation(rule)
傑瑞米·派瑞許
>>> -- 完全未定义中文译名
>>> rule = { 'Jeremy Parish' }
>>> parse_translation(rule)
nil
]==]
local varieties = {}
local hant_variety_names, hant_flag = { 'tw', 'hk', 'mo' }, false
local hans_variety_names, hans_flag = { 'cn', 'sg', 'my' }, false
for _, v in ipairs(hant_variety_names) do
if rule[v] then
table.insert(varieties, { label = 'zh-' .. v, value = get_part_name(rule[v], part, sep) })
hant_flag = true
end
end
for _, v in ipairs(hans_variety_names) do
if rule[v] then
table.insert(varieties, { label = 'zh-' .. v, value = get_part_name(rule[v], part, sep) })
hans_flag = true
end
end
if #varieties == 0 then
return nil, nil
end
if not (hans_flag and hant_flag) then
return varieties[1].value, varieties[1].value
end
local result_fragments = {}
-- 内联转换定义按变种代码列出(强迫症)
table.sort(varieties, function(a, b)
return a.label < b.label
end)
for _, variety in ipairs(varieties) do
table.insert(result_fragments, variety.label .. ':' .. variety.value .. ';')
end
local result = table.concat(result_fragments, ' ')
result = '-{' .. result .. '}-'
return result, varieties[1].value
end
local function parse_original(rule, part, sep)
--[==[将译名定义规则中的原名部分解释为维基代码,可根据分隔符取姓名片段。
若定义原名的语言(`lang`),则套用{{lang}}模板生成语义规范的外文名。
若未定义原名的语言,则只用语言转换标签包裹原文`-{...}-`,避免可能的过度字词转换。
:param rule: 译名定义规则。
:param part: 所提取的姓名片段编号。例如对于原名'John D. Carmack',输入3可仅提取'Carmack'。
:param sep: 片段的分隔符。预设为中文间隔号('·'),但若姓名中不含间隔号时为空格(' ')。
:return: 译名规则中原名部分对应的维基代码,以及不加語文標籤的純文字原名。
示例
----
>>> local rule = { 'John D. Carmack', lang='en', cn = '约翰·D·卡马克' }
>>> parse_original(rule)
{{lang|en|John D. Carmack}}
>>> parse_translation(rule, 3)
{{lang|en|Carmack}}
>>> -- 未指定语言代码
>>> rule = { '浜崎あゆみ', tw = '濱崎步' }
>>> parse_translation(rule)
-{浜崎あゆみ}-
]==]
local original, lang = get_part_name(rule[1], part, sep), rule.lang
if lang == nil then
return '-{' .. original .. '}-', original
end
return mw.getCurrentFrame():expandTemplate { title = 'Lang', args = { lang, original } }, original
end
local function build_redlink_remark_text(target, linked_text, remark)
--[==[根据链接目标、链接文字、原文名,生成链接文字及附注。
所有参数均为可选值。
如果指定链接目标,则生成内部链接,且指定链接文字时生成管道链接;
若未指定链接目标,则以链接文字生成普通文字。
若指定原文名附注,则在链接后追加此标注。
:param target: 本地页面名链接。
:param linked_text: 管道链接文字。
:param remark: 需要括号附注的文字。
:return: 生成的维基代码。
]==]
linked_text = linked_text or target
local result_fragments = {}
if target then
table.insert(result_fragments, '[[')
table.insert(result_fragments, target)
if linked_text ~= target then
table.insert(result_fragments, '|')
table.insert(result_fragments, linked_text)
end
table.insert(result_fragments, ']]')
else
table.insert(result_fragments, linked_text)
end
if remark then
table.insert(result_fragments, '(')
table.insert(result_fragments, remark)
table.insert(result_fragments, ')')
end
return table.concat(result_fragments)
end
local function parse_rule(rule, part, sep, style, link)
--[==[将译名定义规则解析为维基代码
:param rule: 译名定义规则。
:param part: 所提取的姓名片段编号。例如对于译名'约翰·D·卡马克',可输入3仅列出'卡马克'。
:param sep: 片段的分隔符。预设为中文间隔号('·'),但若姓名中不含间隔号时为空格(' ')。
:param style: 生成的维基代码格式:
'link'或'redlink' — 生成普通内部链接;
'remark' — 生成无链接译文,并括号加注原文;
'link-remark'或'redlink-remark' — 以普通内部链接语法链接文本,并括号加注原文;
'iw'、'ilh'、'tsl'或'greenlink' — 当译名规则定义`iw`时,则生成绿色链接,否则为'link-remark'效果;
其他情况 — 无链接译文(预设值)。
:param link: 自定本地链接目标。
:return: 译名规则对应的维基代码。
示例
----
>>> local rule = { 'Jeremy Parish', lang = 'en', cn = '杰里米·帕里什', hk = '謝洛美·巴里殊', tw = '傑瑞米·派瑞許', iw = 'en:Jeremy Parish (writer)' }
>>> parse_rule(rule)
-{zh-cn:杰里米·帕里什; zh-hk:謝洛美·巴里殊; zh-tw:傑瑞米·派瑞許;}-
>>> parse_rule(rule, 2)
-{zh-cn:帕里什; zh-hk:巴里殊; zh-tw:派瑞許;}-
>>> parse_rule(rule, nil, nil, 'link-remark')
[[杰里米·帕里什|-{zh-cn:帕里什; zh-hk:巴里殊; zh-tw:派瑞許;}-]]({{lang|en|Jeremy Parish}})
>>> parse_rule(rule, -1, nil, 'ilh')
{{link-en|帕里什|Jeremy Parish (writer)|-{zh-cn:帕里什; zh-hk:巴里殊; zh-tw:派瑞許;}-}}
>>> parse_rule(rule, -1, nil, 'ilh', '杰里米·帕里什')
{{link-en|杰里米·帕里什|Jeremy Parish (writer)|-{zh-cn:帕里什; zh-hk:巴里殊; zh-tw:派瑞許;}-}}
]==]
local translation, local_title = parse_translation(rule, part, sep, link)
local_title = local_title or rule[1] -- 未定义译名时用原名兜底……吧
translation = translation or rule[1]
local_title = link or local_title
local remark, original = parse_original(rule, part, sep)
if (style == 'iw') or (style == 'ilh') or (style == 'tsl') or (style == 'greenlink') then
local _, _, iw_code, iw_title = mw.ustring.find(rule.iw or '', '^([^:]+):(.-)$')
if iw_code then
return mw.getCurrentFrame():expandTemplate { title = 'Link-' .. iw_code, args = { local_title, iw_title, translation } }
end
return build_redlink_remark_text(local_title, translation, original)
end
if (style == 'link-remark') or (style == 'redlink-remark') then
if translation ~= original then
return build_redlink_remark_text(local_title, translation, remark)
end
return build_redlink_remark_text(local_title, translation)
end
if style == 'remark' then
if translation ~= original then
return build_redlink_remark_text(nil, translation, remark)
end
return build_redlink_remark_text(nil, translation)
end
if (style == 'link') or (style == 'redlink') then
return build_redlink_remark_text(local_title, translation)
end
return translation
end
local function build_wikitable(data)
--[==[將定義規則轉換為易讀的維基表格。
:param data: 定義規則,結構為雙層嵌套表。
:result: 維基代碼,由若干二級目錄、三級目錄和維基表格構成。
]==]
local result_frags = {}
for _, group in ipairs(data) do
table.insert(result_frags, '==' .. group.name .. '==')
for _, subgroup in ipairs(group) do
table.insert(result_frags, '===' .. subgroup.name .. '===')
table.insert(result_frags, '{| class="wikitable sortable"')
table.insert(result_frags, '! 原名')
table.insert(result_frags, '! 中文譯名')
table.insert(result_frags, '! 地區詞轉換')
table.insert(result_frags, '! 備注')
for _, rule in ipairs(subgroup) do
local original = parse_original(rule)
local original_link = original
if rule.iw then
local _, _, iw_code, iw_title = mw.ustring.find(rule.iw or '', '^([^:]+):(.-)$')
if iw_code then
original_link = mw.getCurrentFrame():expandTemplate { title = 'Link-' .. iw_code, args = { rule[1], iw_title, original } }
else
original_link = build_redlink_remark_text(rule.iw or '', rule[1])
end
end
local translation = parse_translation(rule)
translation = translation or ''
local _, _, convert_code = mw.ustring.find(translation, '^%-{(.+)}%-$')
local comment = rule.comment or ''
table.insert(result_frags, '|-')
table.insert(result_frags, '! ' .. original_link)
table.insert(result_frags, '| ' .. translation)
if convert_code then
table.insert(result_frags, '| <code style="font-size: smaller; letter-spacing: -0.05em;">' .. convert_code .. '</code>')
else
table.insert(result_frags, '| ')
end
table.insert(result_frags, '| ' .. comment)
end -- rule
table.insert(result_frags, '|}')
end -- subgroup
end -- group
return table.concat(result_frags, '\n')
end
function p.main(frame)
local args = getArgs(frame)
return p._main(args)
end
function p._main(args)
local rules = unnest_table(rule_data)
local rule = get_rule(rules, args[1], args.lang)
return parse_rule(rule, tonumber(args.part), args.sep, args.style, args.link)
end
function p.wikitable(frame)
local args = getArgs(frame)
return p._wikitable(args)
end
function p._wikitable(args)
return build_wikitable(rule_data)
end
return p