モジュール:サンドボックス/本日晴天/仮リンク

モジュールの解説[作成]
require('strict')

local getArgs = require('モジュール:Arguments').getArgs
local yesno = require('モジュール:Yesno')
local lang_mapping = mw.loadData('モジュール:Wikipedia言語名/lang mapping')
local TEMPLATESTYLES = 'モジュール:サンドボックス/本日晴天/仮リンク/styles.css'

--------------------------------------------------------------------------------
-- BaseIllクラス(抽象クラス)
-- 日本語版記事の表示やカテゴリの出力などを実装
-- コンストラクタとmakeOtherLangLink()は派生クラスで実装する必要がある
--------------------------------------------------------------------------------
local BaseIll = {}
BaseIll.__index = BaseIll

function BaseIll:_init(args)
	-- 必須引数が指定されていない場合はエラーメッセージを表示する
	if args[1] and args[2] and args[3] then
	else
		error('第1引数から第3引数までは必須です。')
	end
	
	self.args = args
	self.title = mw.title.new(args[1])
	self.link = args[1]
	self.label = args.label
	self.preserve = yesno(args.preserve, true)
	self.preserveRedirect = self.preserve or yesno(args.redirect, true)
	
	self.jafix = args.jafix
	if self.jafix == '1' then
		self.jafix = '日本語版記事名を検討する必要があります。'
	end
	
	self.fixme = args.FIXME
	if self.fixme == '1' then
		self.fixme = 'このリンクは修正が必要です。'
	end
end

function BaseIll:setTitleStatus()
	if not self.title.exists then
		-- alt引数 alt1からalt4まで対応
		for i = 1, 4 do
			local altX = self.args['alt' .. i]
			if not altX then
				break
			end
			local altXTitle = mw.title.new(altX)
			if altXTitle.exists then
				self.label = self.link
				self.title = altXTitle
				self.link = altX
				break
			end
		end
	end
	if self.title.exists then
		if self.fixme then
			-- FIXME引数指定
			self.titleStatus = 'fixme'
		elseif self.preserveRedirect and self.title.isRedirect then
			-- リダイレクトかつ、他言語版強制表示
			self.titleStatus = 'redirect'
		elseif self.preserve then
			-- 他言語版強制表示
			self.titleStatus = 'preserve'
		else
			self.titleStatus = 'resolved'
		end
	else
		self.titleStatus = 'unresolved'
	end
end

function BaseIll:export()
	local args = self.args
	local label = self.label
	local link = self.link
	
	local result = mw.html.create()
		:wikitext(
			mw.getCurrentFrame():extensionTag('templatestyles', '', { src = TEMPLATESTYLES }),
			'<span class="ill ill-',
			self.titleStatus,
			'">'
		)
	
	if label and mw.title.equals(mw.title.new(label), self.title) then
		link = label
		label = nil
	end
	
	-- 日本語版の記事名を表示
	if yesno(self.args.nolink) and not self.title.exists then
		result:wikitext(mw.text.tag('span', { title = link }, label or link))
	else
		result:wikitext('[[', link)
		if label then
			result:wikitext('|', label)
		end
		result:wikitext(']]')
	end
	
	if yesno(args.br, true) then
		result:wikitext('<br />')
	end
	
	result:wikitext(self:makeOtherLangLink())

	-- 訳語疑問点タグ
	if self.jafix then
		result:wikitext(
			'<sup class="noprint Inline-Template nowrap">&#91;<span title="',
			self.jafix,
			'">訳語疑問点</span>&#93;</sup>'
			)
	end
	
	-- 要リンク修正タグ
	if self.fixme then
		result:wikitext('<sup class="noprint Inline-Template nowrap">&#91;[[:Category:',
			'FIXME引数が指定された仮リンクを含むページ|<span title="',
			self.fixme,
			'">要リンク修正</span>&#93;</sup>'
			)
	end
	
	result:wikitext('</span>')
	
	if args.this and not mw.title.equals(mw.title.new(args.this), mw.title.getCurrentTitle()) then
		-- args.thisが使われており、かつ現在のページ名がargs.thisの値と等しくない場合は
		-- カテゴリを付与しない
	else
		result:node(self:exportCategories())
	end
	
	return tostring(result)
end

function BaseIll:exportCategories()
	local sortkey
	local namespace = mw.title.getCurrentTitle().namespace
	
	if namespace % 2 == 0 then	-- ノートページ以外
		if namespace <= 18 then
			sortkey = tostring(namespace / 2)
		else
			sortkey = "9" .. namespace
		end
	else	-- ノートページ
		if namespace < 10 then
			sortkey = "話00" .. namespace
		elseif namespace < 100 then
			sortkey = "話0" .. namespace
		else
			sortkey = "話" .. namespace
		end
	end
	
	local categories = mw.html.create()
	
	-- カテゴリの出力
	if self.title.exists then
		-- 日本語版が記事・リダイレクト問わず存在する場合
		-- preserve引数、redirect引数の有無は関係しない
		if namespace == 0 then
			categories:wikitext('[[Category:解消済み仮リンクを含む記事]]')
		else
			categories:wikitext('[[Category:解消済み仮リンクを含むページ|', sortkey, ']]')
		end
	end
	if self.link ~= self.args[1] then
		-- alt1などの値が日本語版のリンクとして用いられた場合
		categories:wikitext('[[Category:代替記事名にリンクしている仮リンクを含むページ|', sortkey, ']]')
	end
	if self.preserve then
		categories:wikitext('[[Category:preserve引数が指定された仮リンクを含むページ|', sortkey, ']]')
	end
	if self.preserveRedirect then
		categories:wikitext('[[Category:redirect引数が指定された仮リンクを含むページ|', sortkey, ']]')
	end
	if self.jafix then
		categories:wikitext('[[Category:訳語に疑問点のある記事|仮リンク]]')
	end
	if self.fixme then
		categories:wikitext('[[Category:FIXME引数が指定された仮リンクを含むページ|', sortkey, ']]')
	end
	
	return categories
end

--------------------------------------------------------------------------------
-- Illクラス(BaseIllを継承)
-- {{仮リンク}}用
-- 他言語版記事へのリンクを生成する部分を実装
--------------------------------------------------------------------------------
local Ill = setmetatable({}, { __index = BaseIll })
Ill.__index = Ill

function Ill.new(frame)
	local obj = setmetatable({}, Ill)
	obj:_init(getArgs(frame, { wrappers = '利用者:本日晴天/sandbox/Template:仮リンク', readOnly = true }))
	return obj
end

function Ill._otherLangLink(langCode, pageName)
	-- ウィキデータの場合は「wikidata」、それ以外の場合は言語名+「版」とする
	if langCode == 'wikidata' or langCode == 'Wikidata' then
		return '[[:d:' .. pageName .. '|wikidata]]'
	end
	
	-- 言語名を取得
	local langDisp = lang_mapping.long[langCode]
	if not langDisp then
		error('不明な言語コード"' .. langCode .. '"が指定されました。')
	end
	
	return string.format('[[:%s:%s|%s版]]',	langCode, pageName, langDisp)
end

function Ill:makeOtherLangLink()
	local args = self.args
	local t = {}
	
	local i = 2
	while args[i] and args[i + 1] do
		table.insert(t, Ill._otherLangLink(args[i], args[i + 1]))
		i = i + 2
	end
	
	return '<span class="noprint ill-otherlang nowrap">('
		.. table.concat(t, '、')
		.. (args.add or '')
		.. ')</span>'
end

--------------------------------------------------------------------------------
-- IllVipnクラス(BaseIllを継承)
-- {{日本語版にない記事リンク}}用
-- 他言語版記事へのリンクを生成する部分を実装
--------------------------------------------------------------------------------
local IllVipn = setmetatable({}, { __index = BaseIll })
IllVipn.__index = IllVipn

function IllVipn.new(frame)
	local obj = setmetatable({}, IllVipn)
	obj:_init(getArgs(frame, { wrappers = '利用者:本日晴天/sandbox/Template:日本語版にない記事リンク', readOnly = true }))
	return obj
end

function IllVipn:makeOtherLangLink()
	local args = self.args
	local langCode = args[2]
	local pageName = args[3]
	
	-- 言語名を取得
	local langPage = lang_mapping.long[langCode] 
	if not langPage then
		error('不明な言語コード"' .. langCode .. '"が指定されました。')
	end
	
	-- 言語短縮名を取得
	local langShort
	if (args.short == 'on') or yesno(args.short) then
		langShort = lang_mapping.short[langCode]
	end
	
	-- 言語名を表示
	local langLink
	if yesno(args.links) == false then
		langLink = langShort or langPage
	elseif langShort then
		langLink = '[[' .. langPage .. '|' .. langShort .. ']]'
	else
		langLink = '[[' .. langPage .. ']]'
	end
	
	return string.format(
		'<span class="ill-otherlang-vipn">(%s: <span lang="%s">[[:%s:%s|%s]]</span>%s)</span>',
		langLink,
		langCode,
		langCode,
		pageName,
		args.interwikilabel or pageName,
		args.add or ''
		)
end

--------------------------------------------------------------------------------
-- モジュールの出力
-- ill()は{{仮リンク}}用、ill_vipn()は{{日本語版にない記事リンク}}用
--------------------------------------------------------------------------------
local function ill(frame)
	local obj = Ill.new(frame)
	obj:setTitleStatus()
	return obj:export()
end

local function illVipn(frame)
	local obj = IllVipn.new(frame)
	obj:setTitleStatus()
	return obj:export()
end

return {
	ill = ill,
	ill_vipn = illVipn
}