Перейти к содержимому страницы
Открыть меню
Переключить меню настроек
Открыть персональное меню
Вы не представились системе
Ваш IP-адрес будет виден всем, если вы внесёте какие-либо изменения.

Модуль:Не переведено

Материал из вики «Вече»
Версия от 12:28, 28 сентября 2025; wp>ru.wikipedia (Импорт из русской Википедии, версия 148835792)
(разн.) ← Предыдущая версия | Текущая версия (разн.) | Следующая версия → (разн.)

Для документации этого модуля может быть создана страница Модуль:Не переведено/doc

local p = {}

local categories = {
	['error'] = 'Википедия:Статьи с некорректно заполненным шаблоном Не переведено',
	['outdated'] = 'Википедия:Статьи с неактуальным шаблоном Не переведено',
	['redirect'] = 'Википедия:Запросы на замену перенаправлений переводами',
	['unknown'] = 'Википедия:Статьи с неизвестными параметрами шаблонов серии Не переведено',
	['semiold'] = 'Википедия:Статьи с полустарым синтаксисом в шаблонах серии Не переведено',
	['probably_wrong'] = 'Википедия:Статьи с предположительно неверными параметрами в шаблонах серии Не переведено',
	['lang-not-exists'] = 'Википедия:Статьи с шаблоном Не переведено 2, использующие несуществующий шаблон lang-XX',
}

local function is_empty(param)
	return param == nil or param == ''
end

local function is_wikidata(lang)
	return lang == 'd'
end

local function getTitle(page, iw_title, is_wikidata_link)
	local success, result = pcall(function()
		if is_wikidata_link then
			local entity = mw.wikibase.getSitelink(iw_title)
			if entity ~= nil then
				return {
					title = entity,
					exists = true,
					-- предположение, что в Викиданных не перенаправление
					isRedirect = false,
				}
			end

			return nil
		else
			local title = mw.title.new(page)
			return {
				title = page,
				exists = title.exists,
				isRedirect = title.isRedirect,
			}
		end
	end)

	if success then
		return result
	end

	return nil
end

local function wikilink(title, text, tooltip, lang, style, is_redirect)
	if is_empty(text) then
		text = title
	end
	if not is_empty(lang) and lang ~= 'ru' then
		title = string.format(':%s:%s', lang, title)
	end
	if is_wikidata(lang) then
		title = title .. '#sitelinks-wikipedia'
	end
	if not is_empty(tooltip) then
		text = string.format('<span title="%s">%s</span>', tooltip, text)
	end
	if not is_empty(style) then
		text = string.format('<span style="%s">%s</span>', style, text)
	end
	if is_redirect then
		return string.format(
			'<span class="plainlinks">[%s %s]</span>',
			tostring(mw.uri.fullUrl(title, 'redirect=no')),
			text
		)
	elseif text ~= title then
		return string.format('[[%s|%s]]', title, text)
	else
		return string.format('[[%s]]', title)
	end
end

local function addMetadata(text, lang, article)
	return string.format(
		'<span data-interwiki-lang="%s" data-interwiki-article="%s">%s</span>',
		lang,
		article,
		text
	)
end

local function throwError(text, category_code, allow_cat)
	local error = require('Module:Error').error
	if category_code and allow_cat then
		return error({ text }) .. '[[Category:' .. categories[category_code] .. ']]'
	else
		return error({ text })
	end
end

function p._subst(mode, title, text, lang, iw_text)
	-- Вывести выделение строки за её пределами
	local selOffset = mw.ustring.find(text, "''")
	local sel = ''
	if selOffset ~= nil and selOffset == 1 then
		local oldText = text
		text = mw.text.trim(text, "'")
		sel = mw.ustring.rep("'", (mw.ustring.len(oldText) - mw.ustring.len(text)) / 2)
	end
	local result = sel .. wikilink(title, text) .. sel

	-- Вывести содержимое скобок в не переведено 2
	if mode == 2 then
		local iw_link = '{{lang-' .. lang .. '|' .. iw_text .. '}}'
		if is_empty(addition) then
			return string.format('%s (%s)', result, iw_link)
		else
			return string.format('%s (%s; %s)', result, iw_link, addition)
		end
	end

	return result
end

function p.main(frame)
	local yesno = require('Module:Yesno')
	local getArgs = require('Module:Arguments').getArgs
	local languages = mw.loadData('Module:Languages/data')
	local transformLangCase = require('Module:Languages').transformLangCase
	local prepositional = function(code)
		return transformLangCase(code, 'prepositional')
	end

	local args = getArgs(frame)

	local categories_list = {}
	local nocat = yesno(args['nocat'])
	local allow_cat = (
		mw.title.getCurrentTitle().namespace == 0 or mw.title.getCurrentTitle().namespace == 10
	) and not nocat

	-- определение какой из шаблонов "не переведено N"
	local mode = tonumber(args['mode'])
	mode = mode == 2 and 2 or 5
	local template_name = 'Не переведено'
	if mode ~= 5 then
		template_name = template_name .. ' ' .. tostring(mode)
	end

	-- проверка на неизвестные параметры
	local redundant_params = {}
	local good_params = { 'mode', 1, 2, 3, 4, 'l', 'leave', 'r', 'q', 'nocat' }
	if mode == 2 then
		table.insert(good_params, 5)
		table.insert(good_params, 'text')
		table.insert(good_params, 'текст')
	end
	for k, _ in pairs(args) do
		local is_good_param = false
		for _, v in pairs(good_params) do
			if k == v then
				is_good_param = true
			end
		end
		if not is_good_param then
			table.insert(redundant_params, k)
		end
	end
	if #redundant_params > 0 then
		table.insert(categories_list, { 'unknown', table.concat(redundant_params) })
	end

	-- получение параметров (кроме nocat)
	local title = args[1]
	local text = args[2]
	local lang = args[3]
	local iw_title = args[4]
	local iw_text = args[5]
	local quotes = yesno(args['q'])
	local addition = args['text'] or args['текст']
	local leave_always = yesno(args['l']) or yesno(args['leave'])
	local leave_if_redirect = yesno(args['r'])

	-- проверка правильности сырых параметров
	if not mw.isSubsting() then
		if is_empty(title) then
			return throwError(
				'не указано название статьи',
				'error',
				allow_cat
			)
		end
		if title:match('^:[a-z-]+:') then
			return throwError(
				'шаблон не поддерживает такой синтаксис',
				'semiold',
				allow_cat
			)
		end
		if is_empty(lang) and not is_empty(iw_title) and iw_title:match('^[a-z][a-z]$') then
			table.insert(categories_list, { 'probably_wrong', nil })
		end
	end

	-- приведение параметров к нужному виду
	if is_empty(text) then
		text = title
	end
	if is_empty(lang) then
		lang = 'en'
	else
		lang = mw.ustring.lower(lang)
	end
	if is_empty(iw_title) then
		iw_title = title
	end
	if is_empty(iw_text) then
		iw_text = iw_title
	end

	-- если используется с подстановкой, выбросить почти без обработки
	if mw.isSubsting() then
		return p._subst(mode, title, text, lang, iw_text)
	end

	-- получение страницы, чтобы знать, существует ли она и является ли она перенаправлением
	local isWikidataLink = is_wikidata(lang)
	local considerAsExists
	local isRedirect
	local considerAsRedirect
	if leave_always then -- если задано |l=1, то ничего не проверять, потому что дорого
		considerAsExists = false
		isRedirect = false
		considerAsRedirect = false
	else
		-- дорогая функция, после 500 вызова крашится
		local titleObject = getTitle(title, iw_title, isWikidataLink)
		if titleObject then
			title = titleObject.title
			considerAsExists = titleObject.exists
			isRedirect = titleObject.isRedirect
			considerAsRedirect = isRedirect and not leave_if_redirect
		else -- после 500 вызова или если в названии есть некорректные символы
			considerAsExists = false
			isRedirect = false
			considerAsRedirect = false
		end
	end

	-- проверка правильности обработанных параметров
	if lang ~= 'd' and languages[lang] == nil then
		return throwError(
			'некорректный ISO-код «' .. lang .. '»',
			'error',
			allow_cat
		)
	end
	if mode == 2 and isWikidataLink then
		return throwError(
			'шаблон Не переведено 2 не поддерживает Викиданные вместо языка'
		)
	end
	if mode == 2 and not mw.title.new('Template:Lang-' .. lang).exists then -- дорогая функция
		return throwError(
			'не найден шаблон '
				.. frame:expandTemplate({ title = 'tl', args = { 'lang-' .. lang } }),
			'lang-not-exists',
			allow_cat
		)
	end

	if mode == 5 and considerAsRedirect then
		table.insert(categories_list, { 'redirect', nil })
	elseif considerAsExists then
		table.insert(categories_list, { 'outdated', nil })
	end

	-- всплывающая подсказка к ссылке на иноязычную статью
	local iw_tooltip
	local ucfirst_title = mw.getContentLanguage():ucfirst(title)
	if isWikidataLink then
		iw_tooltip = string.format(
			'Элемент статьи «%s» в Викиданных',
			ucfirst_title
		)
	else
		iw_tooltip = string.format(
			'%s — версия статьи «%s» на %s',
			iw_title,
			ucfirst_title,
			prepositional(lang)
		)
	end

	-- формирование первой части - основной ссылки
	local main_text
	if considerAsExists or mode == 1 or mode == 2 or mode == 5 then
		main_text = wikilink(title, text, nil, nil, nil, isRedirect)
		if not considerAsExists then
			main_text = addMetadata(main_text, lang, iw_title)
		end
	else
		main_text = wikilink(iw_title, text, iw_tooltip, lang)
	end
	if mode == 4 and quotes then -- TODO: все шаблоны или отключить
		main_text = '«' .. main_text .. '»'
	end

	-- формирование второй части - языковой метки
	local post_text = ''
	if
		not (considerAsExists and not (isRedirect and leave_if_redirect))
		or mode == 2
		or (mode == 5 and considerAsRedirect)
	then
		-- для шаблона "не переведено"
		if mode == 1 then
			local lang_text
			if isWikidataLink then
				lang_text = 'ВД'
			else
				lang_text = languages[lang][1]
			end

			local iw_link = wikilink(iw_title, lang_text, iw_tooltip, lang)
			post_text = string.format(
				'<span class="noprint" style="white-space: nowrap; font-size: 85%%;"> (%s)</span>',
				iw_link
			)

		-- для шаблона "не переведено 2"
		elseif mode == 2 then
			local iw_link = ''
			if considerAsExists then
				iw_link = frame:expandTemplate({ title = 'lang-' .. lang, args = { iw_text } })
			else
				iw_link = frame:expandTemplate({
					title = 'lang-' .. lang,
					args = { wikilink(iw_title, iw_text, iw_tooltip, lang) },
				})
			end

			if is_empty(addition) then
				post_text = string.format(' (%s)', iw_link)
			else
				post_text = string.format(' (%s; %s)', iw_link, addition)
			end

		-- для шаблона "не переведено 3"
		-- TODO: вынести всё это добро в TemplateStyles
		elseif mode == 3 then
			local ref = string.format(
				-- неразрывный пробел на этой позиции предотвращает перенос перед элементом с display:inline-block в Хроме
				'<span style="font-size:117.6%%; margin-left:-0.43em; position:relative; top:0.28em;">%s</span>',
				frame:expandTemplate({
					title = 'ref-' .. (isWikidataLink and 'info' or lang),
					args = {
						isWikidataLink and 'ВД' or '',
					},
				})
			)
			local ru_link = wikilink(title, 'рус.')
			if not considerAsExists then
				ru_link = addMetadata(ru_link, lang, iw_title)
			end
			ru_link = string.format(
				-- position:absolute; позволяет точнее позиционировать пометку; иначе она «скачет», по крайней мере в Хроме
				'<span class="link-ru metadata" style="margin-left:-0.43em; position:absolute; left:0; z-index:1; margin-top:-0.35em;"><span style="visibility:hidden; margin-right:0.099em;">&nbsp;(</span>%s</span>',
				ru_link
			)
			post_text = string.format(
				-- размер шрифта и свойство display:inline-block указывается здесь из-за проблем с размерами шрифта в Хроме на Андроиде
				'&nbsp;<span style="display:inline-block; font-size:80%%; position:relative;">%s%s</span>',
				ref,
				ru_link
			)

		-- для шаблона "не переведено 4"
		elseif mode == 4 then
			local styles = ''
			if lang == 'fr' then
				styles = 'margin-right:0.3em;'
			elseif lang == 'fi' then
				styles = 'margin-right:0.35em;'
			elseif lang == 'it' then
				styles = 'margin-right:0.5em;'
			end

			local ru_link = wikilink(
				title,
				'ru',
				'Статья «'
					.. title
					.. '» в русском разделе отсутствует'
			)
			if not considerAsExists then
				ru_link = addMetadata(ru_link, lang, iw_title)
			end
			ru_link = string.format(
				'<sup style="margin-left:2px; position:relative; top:-1px;">%s</sup>',
				ru_link
			)
			local ref = string.format(
				'<sub style="margin-left:-0.94em; %s" title="По ссылке доступна статья на %s">%s</sub>',
				styles,
				prepositional(lang),
				lang
			)
			post_text = string.format('%s%s', ru_link, ref)

		-- для шаблона "не переведено 5"
		else
			local langText = '[???]'
			if lang == 'd' then
				langText = '[вд]'
			else
				langText = '[' .. (languages[lang] and languages[lang][1] or lang) .. ']'
			end

			post_text = string.format(
				'<sup class="noprint" style="font-style:normal; font-weight:normal;">%s</sup>',
				wikilink(iw_title, langText, iw_tooltip, lang)
			)
		end
	end

	-- формирование третьей части - уведомления о существовании страницы
	local exist_message = ''
	if considerAsExists and not (isRedirect and leave_if_redirect) then
		local exist_message_link
		if mode == 5 then
			if considerAsRedirect then
				exist_message_link = 'Шаблон:'
					.. template_name
					.. '#Если существует перенаправление'
			else
				exist_message_link = 'Шаблон:'
					.. template_name
					.. '#Если существует статья'
			end
		else
			exist_message_link = 'Шаблон:'
				.. template_name
				.. '#Действия после появления страницы'
		end

		if mode == 5 and considerAsRedirect then
			exist_message = string.format(
				'<sup class="noprint" style="margin:0 0 0 1px;">%s</sup>',
				wikilink(
					exist_message_link,
					'*',
					'Замените название перенаправления на название статьи либо уберите шаблон «'
						.. template_name
						.. '»',
					nil,
					'color:red;'
				)
			)
		else
			exist_message = string.format(
				'<sup class="noprint">%s</sup>',
				wikilink(
					exist_message_link,
					'?!',
					'Уберите шаблон «'
						.. template_name
						.. '» из статьи и замените его простой вики-ссылкой',
					nil,
					'color:red;'
				)
			)
		end

		exist_message = string.format(
			'<span style="font-style:normal; font-weight:bold;">%s</span>',
			exist_message
		)
	end

	local categories_text = ''
	if allow_cat then
		for _, category_data in pairs(categories_list) do
			local category_name = categories[category_data[1]]
			if category_data[2] ~= nil then
				category_name = category_name .. '|' .. category_data[2]
			end
			categories_text = categories_text .. '[[Category:' .. category_name .. ']]'
		end
	end

	local result
	if mode == 2 then
		result = main_text .. exist_message .. post_text .. categories_text
	else
		result = main_text .. post_text .. exist_message .. categories_text
	end

	return result
end

return p