Модуль:CenturyMetaCat

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
Документация

Модуль используется для навигации и категоризации категорий по векам (для категорий с заголовком, включающим «<римские цифры> век/века/веке»).

  • Определяет век и эру (до н.э / н.э.).
  • Создаёт навигационную линейку по векам.
  • Корректно работает с веками до нашей эры.
  • Добавляет категории.

Использование[править код]

{{#invoke:CenturyMetaCat|main
|Мир в <век> веке
|Мир <тысячелетие>-го тысячелетия!<ключ>
|Мир по векам!<ключ>
}}
  • <век> — век римскими цифрами без слова «век»
  • <тысячелетие> — тысячелетие числом (без окончания -е/-м/-го)
  • <ключ> — ключ сортировки, н. э. — номер века числом, до н. э. — отрицательное число начиная с -99 (-99 == I век до н. э. -98 == II век до н. э. и т. д.); нужен для корректной сортировки в категориях

Полная версия

{{#invoke:CenturyMetaCat|main
|Категория 1![ключ сортировки]![диапазон веков от]![диапазон веков до]
...
|Категория N[...]
|min = до какого века рисовать линейку слева, по умолчанию -39 (0 — рисовать только века нашей эры)
|max = до какого века рисовать линейку справа, по умолчанию 21
|range = сколько веков в линейке слева и справа, по умолчанию 5
|title = заголовок страницы, используемый вместо текущего (для тестов)
}}

Категории[править код]

Категория состоит из 4-х полей, разделенных ! (восклицательным знаком):

  • первое — название категории
  • второе — ключ сортировки (необязательно)
  • третье — начиная с какого века добавлять категорию (необязательно)
  • четвертое — каким веком заканчивать добавление категории (необязательно)

Примеры:

  • |Мир по векам!<ключ> — добавлять категорию «Мир по векам» с ключом сортировки <пробел><ключ>
  • |Графы Средних веков!<ключ>!5!15 — добавлять категорию «Графы Средних веков» в категории с V по XV века
  • |Книги в общественном достоянии!<ключ>!!19 — добавлять категорию «Книги в общественном достоянии» во все категории до XIX века включительно
N. B.

Есть эмпирическое правило: в категории обязательно должен быть или <век> (в названии), или <ключ> (в ключе сортировки), но не оба.

Другие опции[править код]

|min = до какого века рисовать линейку слева, по умолчанию -39 (0 — рисовать только века нашей эры)
|max = до какого века рисовать линейку справа, по умолчанию 21
|range = сколько веков в линейке слева и справа, по умолчанию 5
|title = заголовок страницы, используемый вместо текущего (для тестов)

Дополнительные функции[править код]

expand[править код]

  • заменяет <век> на текущий, по необходимости добавив «до н. э.»
  • заменяет <тысячелетие> на текущее, по необходимости добавив «до н. э.»
  • заменяет <ключ> на ключ сортировки

Пример:

{{#invoke:CenturyMetaCat|expand|Мир в <век> веке}}

на странице «К:Земля I века до н. э.» вернёт:

Мир в I веке до н. э.

century_from_title[править код]

Возвращает век из заголовка числом, для веков до н.э. с минусом.

См. также[править код]

---*- mode: lua; coding: utf-8; -*-

local p = {}

-- константы
local ROMAN = {
	I = 1,
	IV = 4,
	V = 5,
	IX = 9,
	X = 10,
	--XL = 40,
	--L = 50,
}

-- переменные
local cent -- век, положительное число
local roman_cent -- век римскими цифрами
local BC   -- 0 == н.э. 1 == до н.э.
local templ -- строка-шаблон вида 'Мир в %s веке%s'
local title = mw.title.getCurrentTitle().text

-- опции
local cent_min -- число, по умолчанию -39, 0 == только н.э.
local cent_max -- число, по умолчанию 21 (XXI век)
local range = 5

-- экспортируемые функции
local getArgs = require('Module:Arguments').getArgs
local sparseIpairs = require('Module:TableTools').sparseIpairs
local toroman = require('Module:Roman').convert
local getStyles = require('Модуль:Индекс категории').getStyles
local gsub = mw.ustring.gsub

local function roman_to_int(s)
	local i = 1
	local num = 0
	while i <= s:len() do
		local c
		if i < s:len() then
			c = ROMAN[s:sub(i, i+1)]
		end
		if c then
			num = num + c
			i = i + 2
		else
			num = num + ROMAN[s:sub(i, i)]
			i = i + 1
		end
	end
	return num
end

local function get_templ(s)
	-- формируем строку-шаблон вида:
	-- 'Мир в XI веке до н. э.' -> 'Мир в %s веке%s'
	-- определяем BC 
	local t
	t, BC = gsub(s, '[IVX]+ (век[еа]?) до н%. э%.', '%%s %1%%s')
	local n = BC
	if BC ~= 1 then
		t, n = gsub(s, '[IVX]+ (век[еа]?)', '%%s %1%%s')
	end
	if n ~= 1 then
		-- не найдено или найдено больше одного
		error('Век не найден')
	end
	-- в/во, о/об
	t = gsub(t, 'во %%s веке', 'в %%s веке')
	templ = gsub(t, 'об %%s веке', 'о %%s веке')
end

local function get_cent(t)
	local _, _, rc = mw.ustring.find(t, '([IVX]+) век')
	roman_cent = rc
	if not roman_cent then error('век не найден') end
	cent = roman_to_int(roman_cent)
end

local function format(c, wiki)
	local bcs, t
	if c < 1 then
		c = 1 - c
		bcs = ' до н. э.'
		--t = toroman(c)..' до н. э.'
		t = '-'..toroman(c)
	else
		bcs = ''
		t = toroman(c)
	end
	local s
	if wiki then
		-- в/во, о/об
		local tt = templ
		if c == 2 then
			tt = gsub(tt, 'в %%s веке', 'во %%s веке')
		end
		if c == 11 then
			tt = gsub(tt, 'о %%s веке', 'об %%s веке')
		end
		s = string.format(tt, toroman(c), bcs)
		s = string.format('[[:К:%s|%s]]', s, t)
	else
		s = t
	end
	return s
end

local function navbox()
	local c = cent
	if BC == 1 then
		-- пропускаем 0
		-- I до н.э. c == 0, II до н.э. c == -1 и т.д.
		c = 1 - cent
	end
	local wt = mw.html.create('div')
		:addClass('ts-module-Индекс_категории hlist')
	local row = wt:tag('ul')
	local cstart
	if cent_min < 1 then
		cstart = math.max(cent_min+1, c - range)
	else
		cstart = math.max(cent_min, c - range)
	end
	local cend = math.min(cent_max, c + range) -- FIXME: до н.э.
	for i = cstart, cend do
		row:tag('li'):wikitext(format(i, true))
	end
	return getStyles() .. tostring(wt)
end

local function do_expand(s)
-- <век> - век римскими цифрами без слова "век" (XVII)
-- <тысячелетие> - тысячелетие числом (без добавления -е/-м/-го)
-- <ключ> - ключ сортировки, н.э. - номер века числом,
-- до н.э. - отрицательное число начиная с -99 (-99 == I век до н.э. -98 == II век до н.э. и т.д.)
	local mil = math.floor((cent-1)/10)+1 -- тысячелетие
	-- в/во, о/об ?
	if mil == 2 then
		s = gsub(s, ' в <тысячелетие>', ' во <тысячелетие>')
	end
	if BC == 1 then
		s = gsub(s, '<век> (век[еа]?)', roman_cent .. ' %1 до н. э.')
		s = gsub(s, '<тысячелетие>(-[емг][о]? тысячелети[еия])', mil..'%1 до н. э.') -- 2-е/2-м/2-го
		s = gsub(s, '<ключ>', cent-100)
	else
		s = gsub(s, '<век>', roman_cent)
		s = gsub(s, '<тысячелетие>', mil)
		s = gsub(s, '<ключ>', cent)
	end
	return s
end

local function cats(args)
	local c, t
	local ret = ''
	for _, c in sparseIpairs(args) do
		t = mw.text.split(c, '!', true)
		-- диапазон веков для кат.
		local cmin = -99
		if t[3] and t[3] ~= '' then
			cmin = tonumber(t[3])
		end
		local cmax = 99
		if t[4] and t[4] ~= '' then
			cmax = tonumber(t[4])
		end
		local cc = cent
		if BC == 1 then cc = -cent end
		if cc >= cmin and cc <= cmax then
			-- в/во, о/об
			local tt = t[1]
			if cent == 2 then
				tt = gsub(tt, 'в <век> веке', 'во <век> веке')
			end
			if cent == 11 then
				tt = gsub(tt, 'о <век> веке', 'об <век> веке')
			end
			if t[2] and mw.text.trim(t[2]) ~= '' then
				ret = ret .. string.format('[[Категория:%s|%s]]', tt, mw.text.trim(t[2]))
			else
				ret = ret .. string.format('[[Категория:%s]]', tt)
			end
		end
	end
	return do_expand(ret)
end

function p.main(frame)
	local args = getArgs(frame)
	title = args['title'] or title
	-- разбор аргументов
	range = tonumber(args['range'] or 5)
	cent_min = tonumber(args['min'] or -39)
	cent_max = tonumber(args['max'] or 21)
	-- нахождение текушего века
	get_cent(title)
	-- создание шаблона-строки
	get_templ(title)
	-- создание навбокса и категорий
	return navbox(title) .. cats(args)
end

function p.expand(frame)
	local args = getArgs(frame)
	title = args['title'] or title
	get_cent(title)
	BC = mw.ustring.find(title, '[IVX]+ век[еа]? до н%. э%.')
	if BC then
		BC = 1
	else
		BC = 0
	end
	-- в/во, о/об
	local tt = args[1]
	if cent == 2 then
		tt = gsub(args[1], 'в <век> веке', 'во <век> веке')
	end
	if cent == 11 then
		tt = gsub(tt, 'о <век> веке', 'об <век> веке')
	end
	return do_expand(tt)
end

function p.century_from_title(frame)
	local args = getArgs(frame)
	title = args['title'] or title
	BC = mw.ustring.find(title, '[IVX]+ век[еа]? до н%. э%.')
	get_cent(title)
	if BC then
		return -cent
	end
	return cent
end

return p