Модуль:MetaCat

Материал из DZWIKI
Перейти к навигации Перейти к поиску
Документация


Универсальный модуль для полосы навигации и автокатегоризации категорий по временным периодам (годам, десятилетиям, векам, тысячелетиям) и географическим объектам (странам, регионам, городам, частям света).

Вызов модуля осуществляется через {{#invoke:MetaCat|main|...}}. Подмодули напрямую вызывать не следует — они загружаются автоматически.

Архитектура

Модуль MetaCat — главный диспетчер системы. Автоматически определяет тип категории по заголовку страницы и делегирует обработку соответствующему подмодулю:

  • MetaCat/Core — общая логика, утилиты, фабрики, навигация
  • MetaCat/Year — обработчик категорий годов
  • MetaCat/Decade — обработчик категорий десятилетий
  • MetaCat/Century — обработчик категорий веков
  • MetaCat/Millennium — обработчик категорий тысячелетий
  • MetaCat/Geo — обработчик географических объектов (страны, регионы, города)

Возможности

Временные периоды:

  • Автоматическое определение типа категории по заголовку страницы (год, десятилетие, век, тысячелетие).
  • Поддержка эр: н. э. и до н. э.

Географические объекты:

  • Определение страны, региона, города, части света из заголовка в любом падеже.
  • Автоматическое определение родительских объектов (для города — регион и страна, для страны — часть света и т. д.).
  • Определение государства, в которое входила страна в указанный временной период.
  • Поддержка ключей в разных падежах (именительный, родительный, предложный с предлогом).
  • Настраиваемые ключи сортировки для геообъектов через поле sorting в JSON (например, «Республика Корея» → «Корея»).

Категоризация:

  • Добавление категорий с ключами для времени и географии.
  • Проверка существования категорий перед публикацией (?) с возможностью указать замены (~).
  • Фильтрация категорий по геообъектам через [+тип:значение] и [-тип:значение].
  • Поддержка диапазонов публикации для веков и тысячелетий.

Навигация:

  • Навигационная линейка по периодам с настраиваемым количеством элементов.
  • Автоматический учёт границ существования геообъектов (min/max из JSON).
  • Режим skip-gaps — показ только существующих категорий в навигации.
  • Режим split — разветвления в навигации: на границах вхождения в государства (state) и на границах преемственности стран (past/next).

Прочее:

  • Автоматическое добавление {{автоиндекс}} (от 200 статей, расширенный от 1200).

Используемые списки данных

  • Модуль:Find topic — падежные формы географических объектов
  • geo-country.json — данные о странах: название, годы существования (min/max), ключ сортировки, альтернативные названия (aliases), государства в которые входила страна (state), предшественники и преемники (past/next)
  • geo-city.json — данные о городах: название, годы существования (min/max), ключ сортировки, страна (country), регион (region, или none для городов без промежуточного региона)
  • geo-region.json — данные о регионах (административно-территориальных единицах первого уровня): название, годы существования (min/max), ключ сортировки, год вхождения в текущую страну (since), год выхода из страны (until), флаг no_region (true — пропустить, false — искать родительский регион), сгруппированные по странам
  • geo-continent.json — данные о частях света: название, список стран (country), исторические страны (historical_country), альтернативные названия (aliases), подрегионы (subregion), специальная запись none для стран без части света

Использование

{{#invoke:MetaCat|main
|Категория 1![ключ сортировки]
|?Категория 2![ключ сортировки]
|~Категория 3![ключ сортировки]
...
|Категория N[...]
|min = минимальный период для навигации
|max = максимальный период для навигации
|range = количество элементов в линейке слева и справа, по умолчанию 5
}}

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

  1. Название категории
  2. Ключ сортировки (необязателен)

Примеры:

  • |Мир по годам! <ключ> — добавлять категорию «Мир по годам» с ключом сортировки <пробел><ключ>.
  • |?Персоналии по годам!<ключ> — добавлять категорию «Персоналии по годам» только если она существует.

Диапазоны публикации

Для категорий веков и тысячелетий поддерживаются дополнительные части, позволяющие ограничить публикацию категории определённым диапазоном:

|Название категории!ключ сортировки!с какого периода!по какой период

Примеры:

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

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

{{#invoke:MetaCat|main
|Категория 1![ключ сортировки]![диапазон от]![диапазон до]
|?Категория 2![ключ сортировки]
|~Категория 3![ключ сортировки]
...
|Категория N[...]
|min = минимальный период для навигации
|max = максимальный период для навигации
|range = количество элементов в линейке слева и справа
|force = year/decade/century/millennium/geo
|split=1
|skip-gaps=1
|skip-1century=1
|show-question=1
<!-- для отладки -->
|title = заголовок страницы
|skip-type-check=1
|noindex=1
|nonav=1
}}

Ключи

Ключи времени

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

Для периодов до н. э. к значению автоматически добавляется «до н. э.».

Формат ключа сортировки <ключ>:

Тип Н. э. До н. э.
Год год числом «0» перед (год − 10000): 1 год до н. э. → 0-9999
Десятилетие десятилетие числом;
для 0-х годов н. э. → 5
«0» перед (десятилетие − 10000): 10-е до н. э. → 0-9990;
для 0-х годов до н. э. → 0-9995
Век номер века «0» перед (век − 100): I век до н. э. → 0-99
Тысячелетие номер тысячелетия «0» перед (тысячелетие − 100): 1-е тыс. до н. э. → 0-99
Месяц двузначный номер месяца (01—12)

Грамматические исправления выполняются автоматически:

  • «в <век> веке» → «во II веке» (для II века)
  • «в <год> году» → «во 2 году» (для 2 года)
  • «о <век> веке» → «об XI веке» (для XI века)
  • «в <тысячелетие>-м тысячелетии» → «во 2-м тысячелетии» (для 2-го тысячелетия)

Географические ключи

  • <страна>, <страны>, <в стране> — значение, соответствующее названию страны в необходимом падеже (именительный, родительный, предложный с предлогом), к которой относится категория.
    • <государство>, <государства>, <в государстве> — значение, соответствующее названию государства в необходимом падеже, в которое входила страна в период времени, которому соответствует категория. Государство определяется по полю state в geo-country.json.
  • <часть света>, <части света>, <в части света> — значение, соответствующее названию части света в необходимом падеже, к которой относится категория.
    • <континент>, <континента>, <на континенте> — значение, соответствующее названию родительской части света для подрегионов. Используется для объектов группы subregion в geo-continent.json, позволяя помещать подрегионы (Северная Америка, Южная Америка, Центральная Америка, Карибский регион) в родительскую часть света (Америка).
  • <город>, <города>, <в городе> — значение, соответствующее названию города в необходимом падеже, к которому относится категория.
  • <регион>, <региона>, <в регионе> — значение, соответствующее названию региона (административной единицы первого уровня) в необходимом падеже, к которому относится категория.
  • <месяц>, <месяца>, <в месяце> — значение, соответствующее названию месяца в необходимом падеже.

Именительный, родительный и предложный падежи для географических объектов подставляются автоматически. Вариант предложного падежа у стран и государств автоматически выводится с нужным предлогом «в/во/на». Для частей света в предложном падеже автоматически ставится предлог «в».

Капитализация: если ключ стоит в начале названия категории, первая буква значения автоматически становится заглавной.

Ключи в сортировочном ключе

В сортировочном ключе (после !) допустимы только:

  • <ключ> — для временных категорий
  • <месяц> — для категорий по месяцам
  • Именительный падеж гео-типов: <страна>, <государство>, <город>, <регион>, <часть света>, <континент>

Использование других форм (родительный, предложный падежи) в сортировочном ключе вызовет предупреждение в документации.

Определение типа категории

Модуль определяет тип категории по следующему алгоритму:

  1. Параметр force (кроме force=geo) — принудительно задаёт тип.
  2. Паттерны времени в заголовке страницы:
    • Год: N году, N года, N год — «в 1990 году», «1990 года», «1990 год»
    • Десятилетие: N0-х годов, N0-е годы, N0-х годах — «1990-х годов», «1990-е годы», «в 1990-х годах»
    • Век: X веке, X века — «в XX веке», «XX века»
    • Тысячелетие: N-е тысячелетие, N-м тысячелетии, N-го тысячелетия — «2-е тысячелетие», «во 2-м тысячелетии», «2-го тысячелетия»
  3. Ключи времени в аргументах шаблона: <год>, <десятилетие>, <век>, <тысячелетие>.
  4. Географические ключи в аргументах: <страна>, <город>, <месяц> и т. п. → тип geo.
  5. Географические объекты в заголовке — поиск через модуль Find topic (страна, часть света, город, регион, месяц) → тип geo.
  6. Если ничего не найдено — тип не определён, выводится ошибка.

Определение геообъекта

Геообъект определяется из заголовка страницы через модуль Find topic. Приоритет поиска зависит от наличия соответствующих ключей в шаблоне:

  1. Город — если есть ключ <город>
  2. Регион — если есть ключ <регион>
  3. Страна — если есть ключ <страна> или <государство>
  4. Часть света — если есть ключ <часть света>

Родительские объекты определяются автоматически:

  • Город → регион (если указан ключ) → страна → часть света
  • Регион → страна → часть света
  • Страна → часть света, государство (по временному периоду из поля state)
  • Подрегион → родительский континент (по полю subregion)

Особые случаи:

  • Город-субъект (no_region: true в geo-region.json) — город, являющийся административной единицей первого уровня (Москва, Санкт-Петербург, Киев, Минск). При использовании ключа <регион> для таких городов категория не публикуется, так как они сами являются регионами.
  • Город с родительским регионом (no_region: false в geo-region.json) — для таких городов (например, Севастополь) ищется родительский регион через поле region в geo-city.json (Севастополь → Крым). Флаг no_region в geo-region.json является триггером для поиска родительского региона в geo-city.json.
  • Город без промежуточного региона (region: "none" в geo-city.json) — ключ <регион> не заполняется, категория с ключом региона пропускается без ошибки.
  • Страна в списке none в geo-continent.json — ключи части света не заполняются.
  • Отдельные страны вкладываются в государства, но не в части света. Так, например ФРГ и ГДР помещаются в Германию как <государство> (через state: "always"), а в частях света помещены в none.

Механизм проверки на существование категорий

Следующие символы, указанные перед названием категории, добавляют условия к её публикации:

  • ? — категория публикуется только если она существует.
  • ~ — является заменой для несуществующей категории ?. Обязательно должна следовать сразу за ней на следующей строке, иначе игнорируется. Замены публикуются без проверок на существование. Для одной проверяемой категории может указываться несколько замен подряд.

Для случаев, когда страны расположены в двух частях светах или государствах, проверка на существование категорий осуществляется для каждой из них. Если одна из категорий не существует, то будет опубликована замена для соответствующего ключа.

Параметр show-question

Включение: show-question=1

При включённом режиме категории с префиксом ? публикуются всегда, независимо от их существования. Если категория не существует, она будет опубликована как красная ссылка.

Поведение ~ не меняется — замены по-прежнему публикуются только когда категория ? не найдена.

Условия фильтрации ([+тип:значение] и [-тип:значение]) автоматически наследуются от ?-строки к следующим ~-строкам, если у них нет собственных условий.

Фильтрация категорий по геообъектам

Возможность указывать, что категория должна устанавливаться только для конкретного геообъекта. Ставится перед названием категории и перед префиксами проверки на существование.

Синтаксис
  • [+тип:значение] — включение: категория публикуется только для указанных геообъектов.
  • [-тип:значение] — исключение: категория публикуется для всех геообъектов, кроме указанных.
Переменные
  • Типы: страна, государство, часть света, континент (родительская часть света), город, регион.
  • Значение — название геообъекта в именительном падеже; можно перечислять через запятую. Если название содержит запятую, его можно заключить в круглые скобки: (Корея, Pair).

Комбинирование: Для одной категории можно указать несколько фильтров подряд:

|[+часть света:Европа][-страна:Россия]Категория для Европы кроме России
Примеры
|[+страна:Россия]Категория только для России
|[-страна:США,Канада]Категория для всех стран кроме США и Канады
|[+часть света:Европа]Европейская категория
|[-часть света:подрегионы]Исключить подрегионы

Специальные фильтры

страна:непризнанные — фильтрует непризнанные и частично признанные государства. Список берётся из поля unrecognized_country в geo-continent.json для каждой части света.

страна:исторические — фильтрует исторические страны. Список берётся из поля historical_country в geo-continent.json для каждой части света. Это страны, которые больше не существуют, но иногда группируются вместе.

страна:одновековые — фильтрует страны, существовавшие только в одном веке. См. раздел #skip-1century.

часть света:подрегионы — фильтрует подрегионы частей света (Северная Америка, Южная Америка, Центральная Америка, Карибский регион, Океания). Определяется по полю subregion в geo-continent.json.

часть света:нет — фильтрует страны без привязки к части света. Эти страны перечислены в специальной записи none в geo-continent.json. По умолчанию для таких стран ключи части света не заполняются. Однако при использовании фильтра [+часть света:нет] часть света для них будет определяться, так как эти страны заполнены и в none, и в конкретные части света в geo-continent.json.

регион:нет — фильтрует города-субъекты, у которых в geo-region.json указан флаг no_region: true для текущей страны. Для таких городов ключ <регион> не заполняется автоматически, категория пропускается. Однако если в geo-city.json указано поле region, родительский регион будет найден при наличии ключа сортировки с городом (например, !<город>).

Множественная принадлежность городов

Некоторые города могут относиться к нескольким странам. В geo-city.json такие города указываются с массивом стран в поле country.

При обработке категорий для таких городов модуль проверяет условия фильтрации для каждой страны отдельно. Это позволяет создавать разные категории для одного города в зависимости от страны:

|[+город:Севастополь][+страна:Россия]<год> год в России по субъектам!<город>
|[+город:Севастополь][+страна:Украина]<год> год <в стране> по регионам!<город>

Автоматическое разделение категорий по типам стран

Для geo-шаблонов (только страны, без временных периодов) модуль автоматически разделяет категории «по странам» на подкатегории для исторических и непризнанных государств.

Условия срабатывания
  1. Шаблон имеет тип geo (без временных плейсхолдеров <год>, <век> и т. д.)
  2. В строке категории присутствует маркер по странам! — фраза «по странам» непосредственно перед восклицательным знаком
  3. После ! следует ключ <страна> (возможно через сортировочные символы)
  4. В строке отсутствуют ручные фильтры [+страна:...] или [-страна:...]
Логика работы

При выполнении условий модуль проверяет тип страны:

  • Для исторических стран (из historical_country в geo-continent.json) — поиск категории с заменой «по странам» на:
    1. «исторических государств»
    2. «по историческим государствам»
  • Для непризнанных стран (из unrecognized_country в geo-continent.json) — поиск категории с заменой «по странам» на:
    1. «непризнанных и частично признанных государств»
    2. «по непризнанным и частично признанным государствам»

Если альтернативная категория существует — страна публикуется в неё. Если не существует — остаётся в исходной категории «по странам».

Параметры

Основные параметры

  • min, max — минимальная и максимальная граница времени для навигационной линейки. Отрицательные значения для периодов до н. э.
Значения по умолчанию:
  • Год: min = −40000, max = 2100
  • Десятилетие: min = −40000, max = 2100
  • Век: min = −39, max = 21
  • Тысячелетие: min = −5, max = 3
Приоритет границ: если для геообъекта в JSON указаны min/max, они сравниваются с параметрами шаблона. Итоговая граница — максимум из min шаблона и min геообъекта (для левой границы), минимум из max шаблона и max геообъекта (для правой границы). То есть используется более узкий диапазон.
  • range — количество элементов в навигационной линейке слева и справа от текущей даты. По умолчанию 5.
Параметры для отладки
  • title — заголовок страницы.
  • noindex=1 — отключает добавление шаблона {{автоиндекс}}.
  • nonav=1 — отключает добавление навигационной линейки.
  • skip-type-check=1 — отключает проверку соответствия типа шаблона и категории.

Форсирование типов (force)

Принудительное указание типа категории. Возможные значения: year, decade, century, millennium, geo.

force=year — особое поведение:

  • Если стандартный паттерн года не найден в заголовке, модуль ищет любые 4-значные числа в диапазоне 1—9999. Используется для категорий соревнований, где слово «год» часто опускается.
  • Найденное число используется как год для навигации и ключей.

force=geo — особое поведение:

  • Модуль работает только с географическими ключами, игнорируя временные.
  • Навигационная линейка не создаётся.

Пропуск несуществующих категорий (skip-gaps)

Режим пропуска несуществующих категорий в навигации. Включение: skip-gaps=1

При включённом режиме в навигационной линейке показываются только существующие (синие) категории. Несуществующие пропускаются, вместо них берутся следующие существующие.

Алгоритм:

  1. Проверка выполняется батчами по 25 категорий, максимум 4 батча в каждую сторону (до 100 категорий).
  2. Собираются существующие категории в пределах проверенного диапазона.
  3. Если существующих категорий меньше, чем задано в range, недостающие элементы добиваются красными ссылками.
  4. Для стран с разветвлениями (split) проверяются также категории стран-преемников.

Пример — категории Олимпийских игр (проводятся раз в 4 года, летние и зимние чередуются через 2 года):

  • Для категории «Летние Олимпийские игры 2020» при skip-gaps=1 и range=3 навигация покажет: 2008, 2012, 2016, 2020, 2024, 2028, 2032 (только существующие категории летних игр).
  • Без skip-gaps: 2017, 2018, 2019, 2020, 2021, 2022, 2023 — большинство красными ссылками.

Система связей стран (split)

Режим разветвлений в навигации. Включение: split=1

Создаёт разветвления на основе двух типов связей, указанных в geo-country.json:

1. Связь через state — государства, в которые входила страна. На границах периодов вхождения (start_year/end_year) в навигации появляются разветвления со ссылками на государство. Также влияет на ключ <государство>.

  • Формат: "Государство": [год_начала, год_конца]
  • Спецзначение "now" — связь действует по сей день (год_конца не ограничен).
  • Спецзначение "always" — связь на всё время существования страны. Для split берутся min/max страны, для <государство> — подставляется всегда. Пример: ФРГ и ГДР с "Германия": "always" — в навигации разветвления появятся в 1949 и 1990 (min/max этих стран).

2. Связь через past/next — предшественники и преемники страны. На границе min текущей страны добавляются ссылки на предшественников (past), на границе max — ссылки на преемников (next).

Обозначения в навигации

Символы зависят от направления связи:

Символ Значение Пример
Текущая страна вошла в состав государства Грузия вошла в СССР в 1922 → у Грузии: (↑ СССР)
Текущая страна вышла из состава государства Грузия вышла из СССР в 1991 → у Грузии: (↓ СССР)
↑↓ Вход и выход в одном периоде Грузия в XX веке: (↑↓ СССР)
+ Другая страна вошла в состав текущей Абхазия вошла в Грузию в 1921 → у Грузии: (+ Абхазия)
Другая страна вышла из состава текущей Южная Осетия вышла из Грузии в 1991 → у Грузии: (− Южная Осетия)
± Вход и выход другой страны в одном периоде Грузия в XX веке: (± Южная Осетия)
Предшественник (past) СССР: (Российская империя ←)
Преемник (next) Российская империя: (→ СССР)

Логика символов:

  • Стрелки вверх/вниз (↑↓) — текущая страна является «членом», входящим в более крупное государство.
  • Плюс/минус (+−) — текущая страна является «контейнером», в который входят другие страны.
  • Стрелки влево/вправо (← →) — косвенная преемственность между странами (past/next).

Сортировка связей

Связанные страны в одном периоде сортируются по приоритету:

  1. По дате события (год вхождения/выхода)
  2. По типу связи: past/next (← →), member (↑↓), container (+−)
  3. По алфавиту

Отключение категорий одновековых стран (skip-1century)

Режим для одновековых стран — убирает упоминания веков из названий категорий. Включение: skip-1century=1

«Одновековая страна» — страна, годы существования которой (поля min и max в geo-country.json) полностью укладываются в один век. Например, СССР (1922—1991) существовал только в XX веке.

Фразы, удаляемые из названий публикующихся категорий:

  • <век> века, <век> века до н. э.
  • в <век> веке, во <век> веке, в <век> веке до н. э., во <век> веке до н. э.
  • по векам

Для стран, существовавших в нескольких веках, поведение не меняется.

Связанный фильтр: [+страна:одновековые] позволяет публиковать категорию только для одновековых стран.

Ключ <1век>

Ключ <1век> подставляет век одновековой страны. Используется только вместе с фильтром [+страна:одновековые] в шаблонах для стран (без века в заголовке), когда нужно поместить корневую категорию одновековой страны в категорию века.

Пример использования:

[+страна:одновековые]Спорт в <1век> веке по странам

Для категории «Спорт в СССР» это создаст ссылку на «Спорт в XX веке по странам».

Дополнительные функции

expand

Расширяет ключи в строке на основе заголовка страницы. Заменяет <год>, <десятилетие>, <век>, <тысячелетие>, <ключ> на соответствующие значения. Для периодов до н. э. автоматически добавляется «до н. э.».

Примеры:

  • {{#invoke:MetaCat|expand|Мир <год> года}} на странице Категория:Земля в 100 году до н. э. вернёт Мир 100 года до н. э..
  • {{#invoke:MetaCat|expand|События <век> века}} на странице Категория:Россия в XX веке вернёт События XX века.
  • {{#invoke:MetaCat|expand|История <страны>}} на странице Категория:Россия в XX веке вернёт История России.

detect_type

Отладочная функция. Возвращает определённый тип категории и соответствующий модуль.

Примеры:

  • {{#invoke:MetaCat|detect_type|title=Россия в XX веке}} вернёт Тип: century → модуль: Century.
  • {{#invoke:MetaCat|detect_type|title=Москва в 1990 году}} вернёт Тип: year → модуль: Year.
  • {{#invoke:MetaCat|detect_type|title=События 1990-х годов}} вернёт Тип: decade → модуль: Decade.

century_from_title

Функция модуля Century. Возвращает номер века из заголовка числом. Для веков до н. э. возвращает отрицательное число.

Примеры:

  • {{#invoke:MetaCat/Century|century_from_title|title=Россия в XX веке}} вернёт 20.
  • {{#invoke:MetaCat/Century|century_from_title|title=Древний Рим в I веке до н. э.}} вернёт -1.

Категории отслеживания

В модуль встроено автодобавление в категории отслеживания шаблонов, в которых он используется. Однако, так как проверка пространства страницы и размещение происходит через код модуля, то необходимо избегать помещения модуля в тег <includeonly></includeonly> на странице шаблона. Модуль нужно размещать вне подобных тегов.

Категории, отслеживающие включение модуля

По модулям:

По типам ключей:

Модуль автоматически категоризирует шаблоны по используемым ключам. Формируется категория из компонентов: география + время. Месяцы добавляются как отдельная категория.

Время
География и география + время
Месяцы

Категории, отслеживающие использование параметров

Модуль автоматически добавляет шаблоны в отслеживающие категории при использовании определённых параметров:

Обслуживающие категории

Проверки через шаблон документации

См. также

-- ══════════════════════════════════════════════════════════════════════════════
-- ◆ MetaCat - Универсальный модуль категоризации для Википедии
-- ══════════════════════════════════════════════════════════════════════════════
--
-- Главный диспетчер системы MetaCat. Автоматически определяет тип категории
-- по заголовку страницы и делегирует обработку соответствующему модулю.
--
-- АРХИТЕКТУРА:
--   MetaCat (диспетчер)
--     ├── MetaCat/Core       — общая логика, утилиты, фабрики
--     ├── MetaCat/Year       — обработчик категорий годов
--     ├── MetaCat/Decade     — обработчик категорий десятилетий
--     ├── MetaCat/Century    — обработчик категорий веков
--     ├── MetaCat/Millennium — обработчик категорий тысячелетий
--     └── MetaCat/Geo        — обработчик географических объектов (страны, части света, города, регионы)
--
-- ПРИОРИТЕТ ОПРЕДЕЛЕНИЯ ТИПА:
--   1. Параметр force=year/decade/century (принудительный тип)
--   2. Временные паттерны в заголовке (год/десятилетие/век)
--   3. Временные плейсхолдеры в аргументах (<год>, <век>)
--   4. Географические плейсхолдеры (<страна>, <город>)
--   5. Географические объекты в заголовке (через Find topic)
--
-- ══════════════════════════════════════════════════════════════════════════════

local p = {}

-- ══════════════════════════════════════════════════════════════════════════════
-- ▼ РАЗДЕЛ 1: ЗАВИСИМОСТИ
-- ══════════════════════════════════════════════════════════════════════════════

local getArgs = require('Модуль:Arguments').getArgs
local Core = require('Модуль:MetaCat/Core')

-- ══════════════════════════════════════════════════════════════════════════════
-- ▼ РАЗДЕЛ 2: КОНФИГУРАЦИЯ
-- ══════════════════════════════════════════════════════════════════════════════

local MODULES = {
	year       = { module = 'Year',       supports_expand = true },
	decade     = { module = 'Decade',     supports_expand = true },
	century    = { module = 'Century',    supports_expand = true },
	millennium = { module = 'Millennium', supports_expand = true },
	geo        = { module = 'Geo',        supports_expand = true }
}

-- ══════════════════════════════════════════════════════════════════════════════
-- ▼ РАЗДЕЛ 3: ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
-- ══════════════════════════════════════════════════════════════════════════════

local function get_module_name(category_type)
	return MODULES[category_type] and MODULES[category_type].module or nil
end

local function supports_expand(category_type)
	return MODULES[category_type] and MODULES[category_type].supports_expand or false
end

local function build_module_map(category_type)
	local module_map = {}
	if category_type then
		local module_name = get_module_name(category_type)
		if module_name then
			module_map[category_type] = module_name
		end
	end
	return module_map
end

local function parse_common_params(frame)
	local args = getArgs(frame)
	local title = args['title'] or mw.title.getCurrentTitle().text
	return args, title
end

-- ══════════════════════════════════════════════════════════════════════════════
-- ▼ РАЗДЕЛ 4: ДЕТЕКЦИЯ ТИПА КАТЕГОРИИ
-- ══════════════════════════════════════════════════════════════════════════════

-- ▼ Определение типа по плейсхолдерам в аргументах (общая логика)
local function detect_type_from_placeholders(args)
	if not args then return nil end
	
	local template_type = Core.detect_template_time_type(args)
	if template_type then
		return template_type
	end
	
	for _, arg in pairs(args) do
		if type(arg) == 'string' then
			if Core.has_country_placeholders(arg) or Core.has_month_placeholder(arg) then
				return 'geo'
			end
		end
	end
	
	return nil
end

-- ▼ Определение типа категории (для страниц категорий)
-- Приоритет: force → заголовок → плейсхолдеры
local function detect_category_type(title, args)
	-- Приоритет 0: Принудительный тип через параметр force (кроме force=geo)
	if args and args['force'] then
		local force_type = mw.ustring.lower(args['force'])
		if force_type ~= 'geo' and MODULES[force_type] then
			return force_type
		end
	end

	-- Приоритет 1: Временные паттерны в заголовке
	local time_type = Core.detect_category_time_type(title, args)
	if time_type then
		return time_type
	end

	-- Приоритет 2: Плейсхолдеры в аргументах
	return detect_type_from_placeholders(args)
end

-- ▼ Определение типа шаблона (для категоризации шаблонов)
-- Приоритет: force → плейсхолдеры → заголовок
local function detect_template_type(title, args)
	-- Приоритет 0: Принудительный тип через параметр force (кроме force=geo)
	if args and args['force'] then
		local force_type = mw.ustring.lower(args['force'])
		if force_type ~= 'geo' and MODULES[force_type] then
			return force_type
		end
	end

	-- Приоритет 1: Плейсхолдеры в аргументах
	local placeholder_type = detect_type_from_placeholders(args)
	if placeholder_type then
		return placeholder_type
	end

	-- Приоритет 2: Временные паттерны в заголовке (fallback)
	return Core.detect_category_time_type(title, args)
end

-- ══════════════════════════════════════════════════════════════════════════════
-- ▼ РАЗДЕЛ 5: ПУБЛИЧНЫЙ API
-- ══════════════════════════════════════════════════════════════════════════════

-- ▼ Главная функция модуля
function p.main(frame)
	local args, title = parse_common_params(frame)

	-- Категоризация шаблонов
	-- Для шаблонов тип определяется по плейсхолдерам в аргументах (приоритет), затем по заголовку
	if mw.title.getCurrentTitle().namespace == 10 then
		local template_type = detect_template_type(title, args)
		local module_name = template_type and get_module_name(template_type)
		local full_module_name = module_name and ('MetaCat/' .. module_name) or 'MetaCat'
		return Core.template_module_categories(full_module_name, args)
	end

	local category_type = detect_category_type(title, args)
	local module_map = build_module_map(category_type)
	return Core.dispatch_to_module(frame, category_type, module_map, 'MetaCat')
end

-- ▼ Функция расширения плейсхолдеров
function p.expand(frame)
	local args, title = parse_common_params(frame)
	local category_type = detect_category_type(title, args)

	if not category_type or not supports_expand(category_type) then
		return ''
	end

	local module_map = build_module_map(category_type)
	return Core.expand_with_module(frame, category_type, module_map)
end

-- ▼ Отладка: определение типа категории
function p.detect_type(frame)
	local args, title = parse_common_params(frame)
	local category_type = detect_category_type(title, args)

	if not category_type then
		return '<span class="error">Тип категории: не определён</span>'
	end

	local module_name = get_module_name(category_type)
	return string.format('Тип: %s → модуль: %s', category_type, module_name or 'неизвестен')
end

return p