Модуль:DecadeMetaCatМодуль используется для полосы навигации и автокатегоризации категорий по десятилетиям (для категорий с заголовком, включающим «<число кратное 10>-е/-х годы/годов/годах»). Возможности
Используемые списки данных для стран:
Использование{{#invoke:DecadeMetaCat|main |Мир <десятилетие>-х годов по странам |Мир <век> века <страны>!<ключ> |Мир по десятилетиям <в стране>!<ключ> |Мир <десятилетие>-х годов <в части света>!<страна> }} Категория состоит из 2-х частей, разделенных Переменные
Именительный, родительный и предложный падежи для стран, частей света и государств подставляются автоматически, соответственно указанным переменным. Вариант предложного падежа у стран и государств автоматически выводится с нужным предлогом «в/во/на». Для частей света в предложном падеже автоматически ставится предлог «в». Следующие символы, указанные перед названием категории, осуществляют механизм проверки на существование категорий:
Для отдельных стран, расположенных на двух частях света или входящих в два государства, выполняется механизм раздваивания категорий с соответствующими переменными. Если переменная указана лишь в качестве ключа сортировки, то категория публикуется только один раз. Проверка на существование категорий осуществляется для каждой из частей света или государства в названии. Если одна из категорий не существует, то будет опубликована замена для соответствующей переменной. Полная версия{{#invoke:DecadeMetaCat|main |Категория 1![ключ сортировки] |?Категория 2![ключ сортировки] |~Категория 3![ключ сортировки] ... |Категория N[...] |min = до какого года рисовать линейку слева, по умолчанию -40000 (0 — рисовать только года нашей эры) |max = до какого года рисовать линейку справа, по умолчанию 2100 |range = сколько десятилетий в линейке слева и справа, по умолчанию 5 }} Дополнительные параметры: |title = заголовок страницы, используемый вместо текущего |noindex = 1 (указывается, если необходимо отключить добавления шаблона индекса) |nonav = 1 (указывается, если необходимо отключить добавления навигационной линейки) Дополнительные функцииexpand
Например, Страны и части света функция не обрабатывает.
Категории отслеживания
См. также
---*- mode: lua; coding: utf-8; -*-
local p = {}
-- Переменные
local dec -- десятилетие, положительное число
local BC -- 0 == н.э. 1 == до н.э.
local templ -- строка-шаблон вида 'Мир в %s-е годы%s'
local title = mw.title.getCurrentTitle().text
-- Опции
local dec_min = -40000 -- 0 == только н.э.
local dec_max = 2100 -- 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 findCountry = require('Модуль:Find country')
local countryModule = require('Модуль:CountryMetaCat')
-- Инициализация трекера для ошибок
local error_list = {}
local decade_range_error = nil
local country_error_flag = false
local unique_errors = {}
------------------ Ошибки ------------------
-- Сбор и обработка ошибок
local function add_error(error_code, additional_info)
local error_specific = {
[1] = 'Ошибка: десятилетие не найдено.',
[2] = 'Минимальное десятилетие, ограниченное шаблоном: ' .. (additional_info or "") .. '.',
[3] = 'Максимальное десятилетие, ограниченное шаблоном: ' .. (additional_info or "") .. '.',
[4] = 'Минимальное десятилетие для ' .. (additional_info or "") .. '.',
[5] = 'Максимальное десятилетие для ' .. (additional_info or "") .. '.',
[6] = 'Ошибка: страна не найдена.',
[7] = 'Ошибка: часть света для страны не найдена.',
[8] = 'Ошибка: обнаружено два десятилетия.'
}
if error_code >= 2 and error_code <= 5 then
if not decade_range_error then
decade_range_error = {message = 'Ошибка: десятилетие не попадает в заданный диапазон.', details = {}}
table.insert(error_list, decade_range_error)
end
table.insert(decade_range_error.details, error_specific[error_code])
else
local error_message = '<span class="error">' .. error_specific[error_code] .. '</span>'
if not unique_errors[error_message] then
unique_errors[error_message] = true
table.insert(error_list, {message = error_message})
end
end
end
-- Публикация всех ошибок в едином блоке
local function publish_errors()
local error_category = '[[Категория:Википедия:Страницы с некорректным использованием модуля DecadeMetaCat]]'
if #error_list == 0 then
return ''
end
local result = '<div class="error-list">'
for _, err in ipairs(error_list) do
if err.details then
result = result .. '<span class="error">' .. err.message
for _, detail in ipairs(err.details) do
result = result .. ' ' .. detail
end
result = result .. '</span>'
else
result = result .. err.message
end
end
result = result .. '</div>'
result = result .. error_category
return result
end
--------------- Считывание и обработка десятилетий ---------------
-- Считывание десятилетия из строки
local function get_dec(t)
local decades = {}
for dec in mw.ustring.gmatch(t, '([0-9]*0)-[ех] год') do
table.insert(decades, tonumber(dec)) -- Преобразование строки в число
end
if #decades == 0 then
add_error(1) -- Ошибка "не найден"
return nil
elseif #decades > 1 then
add_error(8) -- Ошибка "обнаружено два"
return nil
end
return decades[1] -- Возврат единственного найденнего значения
end
-- Замена плейсхолдеров (десятилетие, век, ключ) на реальные значения
local function do_expand(s)
-- <десятилетие> - десятилетие числом (без окончания -е/-х)
-- <ключ> - ключ сортировки, н.э. - номер года,
-- до н.э. - отрицательное число начиная с -10000 (-10000 == 0-е годы до н.э. -9990 == 10-е годы до н.э. -9980 == 20-е годы до н.э. и т.д.)
-- <век> - век римскими цифрами
local c = toroman(math.floor(dec / 100) + 1)
-- Обработка для II века (в/во)
if c == 'II' then
s = gsub(s, ' в <век>', ' во <век>')
end
if BC == 1 then
s = gsub(s, '<десятилетие>(-[ех] год[ыоа][вх]?)', dec..'%1 до н. э.') -- годы/годов/годах
s = gsub(s, '<ключ>', '0' .. (dec - 10000)) -- Преобразование ключа для до н.э.
s = gsub(s, '<век> (век[еа]?)', c..' %1 до н. э.')
else
s = gsub(s, '<десятилетие>', dec)
if dec == 0 then
s = gsub(s, '<ключ>', '5') -- Ключ 5 для 0-х н. э.
else
s = gsub(s, '<ключ>', dec)
end
s = gsub(s, '<век>', c)
end
return s
end
--------------- Обработка min/max ---------------
-- Поиск данных о стране в JSON-файле по названию или алиасу
local function find_country_in_json(country_name)
local country_data = mw.loadJsonData('Модуль:YearMetaCat2/country-years.json')
for _, country in ipairs(country_data.countries) do
if country.name == country_name then
return country
end
if country.aliases then
for _, alias in ipairs(country.aliases) do
if alias == country_name then
return country
end
end
end
end
return nil
end
-- Проверка, попадает ли десятилетие в диапазон страны или вручную заданные значения
local function check_decade_in_bounds(args)
args = args or {}
local country_name = findCountry.findcountryinstring(title)
local country_data = find_country_in_json(country_name)
-- Корректировка для до н.э.
local dec_adjusted = (BC == 1) and -dec or dec
-- Ручные ограничения min и max (только для десятилетий)
local manual_min = tonumber(args['min'])
local manual_max = tonumber(args['max'])
-- Преобразуем годы из JSON в десятилетия, если данные найдены
local country_min = country_data and country_data.min and math.floor(country_data.min / 10) * 10 or nil
local country_max = country_data and country_data.max and math.floor(country_data.max / 10) * 10 or nil
-- Определение активных границ
local effective_min = manual_min or country_min
local effective_max = manual_max or country_max
-- Проверка минимального значения
if effective_min and dec_adjusted < effective_min then
if manual_min then
-- Если задано вручную
add_error(2, string.format("%d-е", manual_min))
elseif country_min then
-- Если данные из страны
add_error(4, string.format("%s: %d-е (минимальный год: %d)", country_name, country_min, country_data.min))
end
end
-- Проверка максимального значения
if effective_max and dec_adjusted > effective_max then
if manual_max then
-- Если задано вручную
add_error(3, string.format("%d-е", manual_max))
elseif country_max then
-- Если данные из страны
add_error(5, string.format("%s: %d-е (максимальный год: %d)", country_name, country_max, country_data.max))
end
end
end
--------------- Считывание и обработка стран ---------------
-- Проверка на наличие плейсхолдеров, связанных со странами
local function has_country_placeholders(s)
local placeholders = {
'<страна>', '<страны>', '<в стране>',
'<часть света>', '<части света>', '<в части света>',
'<государство>', '<государства>', '<в государстве>'
}
-- Проверка на стандартные плейсхолдеры
for _, placeholder in ipairs(placeholders) do
if s:find(placeholder, 1, true) then
return true
end
end
-- Проверка на плейсхолдеры с указанием названия страны (например, <государство:Название страны>)
local complex_placeholders = {
'<государство:[^>]+>',
'<государства:[^>]+>',
'<в государстве:[^>]+>'
}
for _, pattern in ipairs(complex_placeholders) do
if s:find(pattern) then
return true
end
end
return false
end
-- Обработка стран, частей света стран или государств
local function process_country_placeholders(s, title, current_dec)
if type(s) ~= 'string' then return {}, nil end
local result_lines = {}
local added_categories = {}
-- Вызываем resolve_country с нужными параметрами
local country_result = countryModule.resolve_country({
[1] = s,
title = title,
type = "decade",
time = current_dec
})
if country_result then
-- Обработка основного результата
if country_result.result and country_result.result ~= "" then
table.insert(result_lines, {text = country_result.result, type = "main"})
end
-- Обработка дополнительного результата
if country_result.extra_result and country_result.extra_result ~= "" then
table.insert(result_lines, {text = country_result.extra_result, type = "extra"})
end
-- Обработка ошибок от country_module
if country_result.error and country_result.error > 0 then
add_error(country_result.error == 1 and 6 or 7)
country_error_flag = true
end
end
return result_lines
end
--------------- Форматирование строк ---------------
-- Формирование шаблона строки для отображения года с учётом до н. э.
local function get_templ(s)
-- Формируем строку-шаблон вида: 'Мир в 90-е годы до н. э.' -> 'Мир в %s-е годы%s'
local t
t, BC = gsub(s, '[0-9]*0(-[ех] год[ыоа][вх]?) до н%. э.', '%%s%1%%s')
local n = BC
if BC ~= 1 then
t, n = gsub(s, '[0-9]*0(-[ех] год[ыоа][вх]?)', '%%s%1%%s')
end
if n ~= 1 then -- Ошибка, если совпадений нет или их больше одного
add_error(1)
end
templ = t
end
-- Форматирование года с учётом до н. э.
local function format(d, wiki)
local bcs, t
if d < 0 then
d = -d - 10
bcs = ' до н. э.'
t = '−'..d
else
bcs = ''
t = d
end
local s
if wiki then
s = string.format(templ, d, bcs)
s = string.format('[[:К:%s|%s]]', s, t)
else
s = t
end
return s
end
--------------- Список категорий ---------------
-- Проверка на существование категории
local function category_exists(category_name)
if not category_name or category_name == '' then return false end
-- Удаление символов ? ~ вначале или ! с текстом вконце
category_name = mw.ustring.match(category_name, "^[%?~]*(.-)!") or category_name
local title = mw.title.new('Категория:' .. category_name)
return title and title.exists
end
-- Основная обработка категорий
local function cats(args)
local ret = ''
local added_categories = {}
local lines = {}
-- Вспомогательная функция для добавления категории
local function add_category(text)
local processed = do_expand(text:gsub("!", "|"))
local categories = mw.text.split(processed, "|")
local cat_name = categories[1]
if not added_categories[cat_name] then
ret = ret .. string.format('[[Категория:%s%s]]',
cat_name,
categories[2] and ('|' .. categories[2]) or ''
)
added_categories[cat_name] = true
return true
end
return false
end
-- Обработка входных аргументов и заполнение lines
for i, arg in sparseIpairs(args) do
if type(arg) == "string" and arg ~= "" then
if has_country_placeholders(arg) then
local result = process_country_placeholders(arg, title, dec)
lines[i] = {
original = arg,
results = result or {},
is_placeholder = true
}
else
local text = do_expand(arg)
lines[i] = {
original = arg,
results = {
{text = text, type = "main"},
{text = text, type = "extra"}
},
is_placeholder = false
}
end
end
end
local i = 1
while i <= #lines do
local line = lines[i]
if line then
local first_char = mw.ustring.sub(line.original, 1, 1)
if first_char == '?' then
local exists = {main = false, extra = false}
local questions = {main = {}, extra = {}}
-- Проверяем существование категорий
for _, result in ipairs(line.results) do
local text = result.text:sub(2):gsub("^%s+", "")
local cat_name = do_expand(text:match("^(.-)!") or text)
questions[result.type][cat_name] = text
if category_exists(cat_name) then
exists[result.type] = true
add_category(result.text:sub(2))
end
end
local j = i + 1
while j <= #lines and mw.ustring.sub(lines[j].original, 1, 1) == '~' do
for _, result in ipairs(lines[j].results) do
if not exists[result.type] and next(questions[result.type]) then
add_category(result.text:sub(2))
end
end
j = j + 1
end
i = j - 1
elseif first_char ~= '~' then
for _, result in ipairs(line.results) do
if result.text and result.text ~= "" then
add_category(result.text)
end
end
end
end
i = i + 1
end
return ret
end
--------------- Навигационный блок ---------------
local function navbox()
-- Корректировка для до н. э.
local d = (BC == 1) and (-dec - 10) or dec
local wt = mw.html.create('div'):addClass('ts-module-Индекс_категории hlist')
local row = wt:tag('ul')
-- Корректировка min и max для до н. э.
dec_min = (dec_min < 0) and (dec_min - 10) or dec_min
dec_max = (dec_max < 0) and (dec_max - 10) or dec_max
local country_data = find_country_in_json(findCountry.findcountryinstring(title))
-- Определение минимального и максимального десятилетий для страны
local country_min_decade = country_data and country_data.min and
math.max(dec_min, math.floor(country_data.min / 10) * 10) or dec_min
local country_max_decade = country_data and country_data.max and
math.min(dec_max, math.floor(country_data.max / 10) * 10 + 9) or dec_max
-- Определение стартового и конечного десятилетий
local dstart = math.max(country_min_decade, d - range * 10)
local dend = math.min(country_max_decade, d + range * 10)
-- Если диапазон некорректный, возвращаем пустую строку
if dend < dstart then return "" end
-- Добавляем элементы в навигационную полоску
for i = dstart, dend, 10 do
row:tag('li'):wikitext(format(i, true))
end
return getStyles() .. tostring(wt)
end
--------------- Вывод ---------------
function p.main(frame)
local args = getArgs(frame)
title = args['title'] or title
range = tonumber(args['range'] or range)
if mw.title.getCurrentTitle().namespace == 10 then -- проверка пространства шаблонов
return "[[Категория:Шаблоны, использующие модуль DecadeMetaCat]]" ..
"[[Категория:Шаблоны, использующие индекс категории (автоматический)]]"
end
-- Обработка вручную заданных min и max
dec_min = tonumber(args['min'] or dec_min)
dec_max = tonumber(args['max'] or dec_max)
-- Нахождение десятилетия по заголовку страницы
dec = get_dec(title)
if not dec then
return publish_errors() -- Возврат ошибок и прекращаем выполнение, если десятилетие не найдено
end
-- Создание шаблона-строки
get_templ(title)
-- Стандартная категоризация
local categories = cats(args)
-- Проверка, попадает ли год в допустимые границы
check_decade_in_bounds(args)
local output = ""
-- Навигационная полоска с отключением
if args['nonav'] ~= "1" then
output = output .. navbox(title)
end
-- Автоиндекс с отключением
if args['noindex'] ~= "1" then
output = output .. mw.getCurrentFrame():preprocess('{{индекс категории (автоматический)}}\n')
end
-- Преобразование таблицы категорий в строку, если это таблица
if type(categories) == "table" then
local flat_categories = {}
for _, value in ipairs(categories) do
table.insert(flat_categories, value.text)
end
categories = table.concat(flat_categories, '')
end
output = output .. publish_errors()
return output .. (categories or "")
end
-- Вспомогательная функция для развёртывания
function p.expand(frame)
local args = getArgs(frame)
title = args['title'] or title
dec = get_dec(title)
if not dec then
return publish_errors()
end
BC = mw.ustring.find(title, '[0-9]*0-[ех] год[ыоа][вх]? до н%. э%.')
if BC then
BC = 1
else
BC = 0
end
return do_expand(args[1])
end
return p
|
Portal di Ensiklopedia Dunia