因BWiki近期更新,普通用户无法直接访问除重定向、编辑表格外的特殊页面(如最近更改等),进行3次有效编辑后即可恢复。

全站通知:

模块:Tr

来自战争雷霆WIKI_BWIKI_哔哩哔哩
跳到导航 跳到搜索

此模块的文档可以在模块:Tr/doc创建

local database = mw.loadData( 'Module:Tr/db' )
local main_database = database.main
local prefix_database = database.prefix
local postfix_database = database.postfix

local input_frame --保存全局输入frame

-- 所有local函数,统一定义方便递归
local stripArticle, tcBasic, procNumberPostfix, procParenPostfix, proc, tcPlural

-- 尝试检查各种可能的复数变体,匹配就tc返回,否则nil
function tcPlural(str)
	if not str then return end
	local matches
	matches = str:match('^(.+)s$') -- -s
	if matches then
		if main_database[matches] then
			return main_database[matches] 
		else
			matches = matches:match('^(.+)e$') -- -es
			if matches then
				if main_database[matches] then
					return main_database[matches]
				else
					matches = matches:match('^(.+)i$') -- ies
					if matches then
						matches = matches..'y'
						if main_database[matches] then return main_database[matches] end
					else
						--和上一个匹配互斥,放在else可以省点事
						matches = str:match('^(.+)ves$') -- ves
						if matches then
							matches = matches..'f' -- -f
							if main_database[matches] then return main_database[matches] end
							matches = matches..'e' -- -fe
							if main_database[matches] then return main_database[matches] end
						end
					end
				end
			end
		end
	end
end

-- 脱冠词 成功脱掉返回脱掉后的文本,失败nil
function stripArticle(str)
	return str:match('^the%s+(.+)$') or str:match('^an?%s+(.+)$')
end

-- 基本:冠词/复数。
function tcBasic(en)
	if main_database[en] then return main_database[en] end
	local main = stripArticle(en)
	if main then
		--有冠词
		if main_database[main] then return main_database[main] end
		local zh = tcPlural(main)
		if zh then return zh end
	else
		--无冠词
		if main_database[en] then return main_database[en] end
	end
	return tcPlural(en)
end


-- 尝试去掉数字后缀,然后再次尝试做处理。
function procNumberPostfix(en)
	local main, number = en:match('^(.-)%s+([%d%.]+)$') --后缀允许数字和.混合。可能会带来少数没意义的匹配,问题不大。
	if main then
		zh = tcBasic(main) or proc(main) --前面还是要尝试基本款翻译,以应对 block 2 这样的情况
		if zh then
			return zh..' '..number..' ' --中文和数字之间要有空格
		end
	end
end

-- 尝试去掉括号后缀,然后再次尝试做处理。
function procParenPostfix(en)
	local main, postfix, postfix_zh
	main, postfix = en:match('^(.-)%s*(%b())$')
	if main then
		postfix_zh = postfix_database[postfix] -- 带着括号直接看是否有专用后缀
		if not postfix_zh then
			postfix = postfix:sub(2,-2)
			postfix_zh = postfix_database[postfix] or tcBasic(postfix) -- 没?去掉括号再看一次,同时处理普通后缀
			if postfix_zh then
				postfix_zh = '('..postfix_zh..')' -- 用中文括号。
			end
		end
	end

	--加上前面主体部分
	if postfix_zh then
		local zh = tcBasic(main) or proc(main)
		if zh then return zh..postfix_zh end
	end
end

-- 复杂处理:先尝试做,/and/or分割,然后考虑数字后缀、然后尝试括号后缀、然后专用后缀/前缀、然后普通后缀/前缀。
function proc(en)
	local a, b, zh_a, zh_b

	-- and/or 要考虑牛津逗号的问题,否则会导致 a, b, and c 最后被分离出“and c”片段。另外 “, and”附近的空格问题要处理。
	-- X and Y
	a, sep, b = en:match('^(.-)%s*([,%s])%s*and%s+(.+)$')
	if a then
		zh_a = tcBasic(a) or proc(a)
		if zh_a then
			zh_b = tcBasic(b) or proc(b)
			if zh_b then
				return zh_a..((sep == ',') and '、和' or '和')..zh_b
			end
		end
	end
	-- X or Y
	a, sep, b = en:match('^(.-)%s*([,%s])%s*or%s+(.+)$')
	if a then
		zh_a = tcBasic(a) or proc(a)
		if zh_a then
			zh_b = tcBasic(b) or proc(b)
			if zh_b then
				return zh_a..((sep == ',') and '、或' or '或')..zh_b
			end
		end
	end

	-- X , Y  and  X / Y
	a, sep, b = en:match('^(.-)%s*([,/])%s*(.+)$')
	if a then
		zh_a = tcBasic(a) or proc(a)
		if zh_a then
			zh_b = tcBasic(b) or proc(b)
			if zh_b then
				return zh_a..((sep == ',') and '、' or '/')..zh_b
			end
		end
	end

	local zh, postfix_main, prefix_main, postfix, prefix, postfix_zh, prefix_zh

	zh = procNumberPostfix(en)
	if zh then return zh end

	zh = procParenPostfix(en)
	if zh then return zh end
	
	--尝试解析后缀
	postfix_main, postfix = en:match('^(.-)%s+([%w%d]+)$')
	
	--专用后缀
	if postfix_main then
		postfix_zh = postfix_database[postfix]
		if postfix_zh then
			zh = tcBasic(postfix_main) or proc(postfix_main)
			if zh then return zh..postfix_zh end
		end
	end
	
	--尝试解析前缀:
	en = stripArticle(en) or en -- 预脱冠词,否则前缀分析没意义
	prefix, prefix_main = en:match('^(%S+)%s+(.+)$')

	-- 专用前缀
	if prefix_main then
		prefix_zh = prefix_database[prefix]
		if prefix_zh then
			zh = tcBasic(prefix_main) or proc(prefix_main)
			if zh then return prefix_zh..zh	end
		end
	end
		
	-- 普通后缀:
	if postfix_main then
		postfix_zh = tcBasic(postfix)
		if postfix_zh then
			zh = tcBasic(postfix_main) or proc(postfix_main)
			if zh then return zh..postfix_zh end
		end
	end
	
	-- 普通前缀
	if prefix_main then
		prefix_zh = tcBasic(prefix)
		if prefix_zh then
			zh = tcBasic(prefix_main) or proc(prefix_main)
			if zh then return prefix_zh..zh end
		end
	end

end



-- 主返回点
return { go = function(frame)
	input_frame = frame
	local input = frame.args[1]:match("^%s*(.-)%s*$") --module内要自己trim
	local en = input:lower()
	local zh, m
	--有冠词试试不脱冠词直接测试复数,补充template内的缺失(诸如 The Axe 这种天生带 the 的专有名词)
	if en:match('^the%s+(.+)$') then
		zh = tcPlural(en)
		if zh then return zh end
	end
	-- -ves结尾的额外测试一下复数,s/es/ies在模板内已经搞过了。
	local matches = en:match('^(.+)ves$')
	if matches then
		m = stripArticle(matches) or matches -- 冠词还是要脱
		--无冠词版本这里4个其实有重复,但不影响效率。
		local t = m..'f'
		if main_database[t] then return main_database[t] end
		local t = m..'fe'
		if main_database[t] then return main_database[t] end
		local t = matches..'f'
		if main_database[t] then return main_database[t] end
		local t = matches..'fe'
		if main_database[t] then return main_database[t] end
	end

	-- 其他复杂变体
	zh = proc(en)

	if zh then
		-- 处理空格问题
		zh = zh:gsub("%s+"," ")
		zh = zh:gsub("%s*(%s*","(")
		zh = zh:gsub("%s*)%s*",")")
		zh = zh:gsub("!%s+","!")
		zh = zh:gsub("?%s+","?")
		zh = zh:match("^%s*(.-)%s*$")
		return zh
	end

	-- 最后的fallback
	return input
	
end }