Модуль:CountryMetaCat
Модуль используется для навигации и автокатегоризации категорий по странам (для категорий с заголовком, включающим название стран в именительном, родительном или предложном падеже). Модуль использует механизм обнаружения модуля Модуль:Find country с его списком стран и падежей.
- Определяет название страны из заголовка в любом падеже.
- В категориях меняет падеж страны в нужный.
- Определяет, в какой части света (континенте) расположена страна и публикует её/их в нужном падеже.
- Позволяет проверить существование категории или опубликовать замену для неё.
- Добавляет {{автоиндекс}} (появляется от 200 статей, расширенный индекс от 1200 статей).
- Добавляет категории.
Используемые базы данных:
- Страны, их падежные формы и предлоги: Find country/countries.json.
- Страны по частям света: CountryMetaCat/country-continents.json.
Использование
[править код]{{#invoke:CountryMetaCat|main |Появились <в стране> |События <части света>!текст для сортировки }}
<страна>
— страна в именительном падеже.<страны>
— страна в родительном падеже.<в стране>
— страна в предложном падеже, включая предлог (автоматически выбирает «в/во/на»).<часть света>
— часть света в именительном падеже.<части света>
— часть света в родительном падеже.<в части света>
— часть света в предложном падеже, включая предлог «в».
Вызов ключа части света обрабатывает помещение в соответствующую часть света, а также в некоторые надрегионы. Для отдельных стран работает механизм разделения на несколько частей света, когда страна, расположенная одновременно в двух частях света, будет автоматически получать две категории каждой части света. В случае, если один ключей <часть света> используется только в качестве ключа сортировки, а название категории при этом не меняется, то категория публикуется только один раз с первым ключом сортировки.
Механизм проверки существования категорий
?
— указывается первым символом перед названием категории, которую необходимо проверять на существование. Если категория существует, она публикуется. Если не существует, ищется замена для публикации на следующей строке, которая должна начинаться с символа~
. В случае неудачи категория не публикуется.~
— указывается первым символом перед названием категории, которая публикуется (без проверки на существование) только в том случае, если на предыдущей строке категория с?
не создана. Во всех остальных случаях пропускается.
Для проверок работает механизм раздваивания по частям света. Будет проверяться на существование категория с каждой частью света и подбираться замена для соответствующей (замена также должна содержать ключ <части света>).
Полная версия
{{#invoke:CountryMetaCat|main |Категория 1![ключ сортировки] |?Категория 2![ключ сортировки] |~Категория 3![ключ сортировки] ... |Категория N[...] |title = заголовок страницы, используемый вместо текущего (для тестов) |noindex = 1 (указывается, если необходимо отключить добавления шаблона индекса) }}
Категория состоит из двух полей, разделенных !
(восклицательным знаком):
- первое — название категории (с возможностью проверок через
?
и~
) - второе — ключ сортировки (необязательно)
Дополнительные функции
[править код]resolve_country
— используется для экспорта в другие модули. Принимает заголовок страницы (или принимает title) + строку. Обрабатывает строку, если в ней содержалась заготовка страны или части света. Возвращает таблицу со значениями:result
— основной вариант строки для единственного результата (или первого континента),extra_result
— возможный второй вариант строки для второго континента,error
— код ошибки (0 — ошибки нет, 1 — страна не найдена, 2 — континент не найден).
Категории отслеживания
[править код]- Википедия:Страницы с некорректным использованием модуля CountryMetaCat — отслеживание использований с несуществующими странами или частями света.
- Шаблоны, использующие модуль CountryMetaCat (9) — в модуль встроено автодобавление в эту категорию страниц, на которых он используется, при условии что страница является шаблоном. Однако, так как проверка пространства страницы и размещение происходит через код модуля, то необходимо избегать помещения модуля в тег
<includeonly></includeonly>
на странице шаблона. Модуль нужно размещать вне любых подобных тэгов. - Категория:Шаблоны, использующие индекс категории (автоматический)
См. также
[править код]- Модуль:YearMetaCat2 — аналог для годов и десятилетий
- Модуль:DecadeMetaCat — аналог для десятилетий
- Модуль:CenturyMetaCat — аналог для веков
- Модуль:YearMetaCat — аналог для годов и десятилетий
local p = {}
local getArgs = require('Модуль:Arguments').getArgs
local sparseIpairs = require('Модуль:TableTools').sparseIpairs
local gsub = mw.ustring.gsub
local findCountry = require('Модуль:Find country')
local error_category = '[[Категория:Википедия:Страницы с некорректным использованием модуля CountryMetaCat]]'
local function error_string(s)
return '<span class="error">' .. s .. '</span>'
end
-- Безопасное получение данных о стране в указанном падеже
local function get_safe_country_case(country, case)
if not country then
return "" -- Возврат пустой строки, если страна не найдена
end
-- Поиск страны в указанном падеже
local result = findCountry.findcountryinstring(country, case)
if not result or result:match("^Ошибка") then
result = "" -- Возврат пустой строки в случае ошибки
end
return result
end
-- Проверка существования категории до символа "!"
local function category_exists(category_name)
if not category_name or category_name == '' then return false end
-- Удаление ключа сортировки после "!"
local clean_category_name = mw.ustring.match(category_name, "^(.-)!")
clean_category_name = clean_category_name or category_name -- Если ключа сортировки нет, используется полное название
local title = mw.title.new('Категория:' .. clean_category_name)
return title and title.exists -- Проверка, существует ли категория
end
-- Проверка на наличие плейсхолдеров частей света
local function has_continent_placeholders(args)
local continent_placeholders = {'<часть света>', '<части света>', '<в части света>'}
for _, value in pairs(args) do
if type(value) == "string" then
for _, placeholder in ipairs(continent_placeholders) do
-- Проверка строки на наличие плейсхолдеров
if mw.ustring.find(value, placeholder, 1, true) then
return true
end
end
end
end
return false
end
-- Замена плейсхолдеров страны и континента на реальные значения
local function process_placeholders(s, country, continent, continents_data)
if not s then return "" end
-- Проверека используется ли пробел после ключа сортировки
local has_exclamation_space = mw.ustring.find(s, "! ")
-- Обработка подстановок для страны
local country_cases = {
['<страна>'] = country or "",
['<страны>'] = get_safe_country_case(country, 'родительный'),
['<в стране>'] = get_safe_country_case(country, 'предлог')
}
for placeholder, value in pairs(country_cases) do
s = gsub(s, placeholder, value)
end
-- Обработка подстановок для континента, если данные континента заданы
if continent and continents_data then
local continent_case = {
['именительный'] = '',
['родительный'] = '',
['предложный'] = ''
}
-- Поиск данных о континенте и его падежах
for _, continent_data in ipairs(continents_data.continents) do
if continent_data.name == continent and continent_data.cases then
for case, value in pairs(continent_data.cases) do
continent_case[case] = value
end
break
end
end
-- Замена плейсхолдеров континента
s = gsub(s, '<часть света>', continent_case['именительный'])
s = gsub(s, '<части света>', continent_case['родительный'])
s = gsub(s, '<в части света>', continent_case['предложный'] ~= "" and 'в ' .. continent_case['предложный'] or '')
else
-- Замена на пустые значения, если континент не найден
s = gsub(s, '<часть света>', '')
s = gsub(s, '<части света>', '')
s = gsub(s, '<в части света>', '')
end
-- Очищение строки от лишних символов
s = gsub(s, " !", "!")
s = mw.ustring.gsub(s, "[%!%s]+$", "")
if has_exclamation_space and not mw.ustring.find(s, "!") then
-- Возвращается пробел после ключа сортировки, если использовался
s = s .. "! "
end
return s
end
-- Обработка категорий с использованием плейсхолдеров стран и частей света
local function process_category_placeholders(args, country, continent_list, continents_data)
local categories = {}
for _, arg in ipairs(args) do
if type(arg) == "string" and arg ~= "" then
local has_placeholders = has_continent_placeholders(args)
local continents = has_placeholders and continent_list or {continent_list[1]}
-- Обработка каждой категории для каждого континента
for _, continent in ipairs(continents) do
local processed_string = process_placeholders(arg, country, continent, continents_data)
if processed_string ~= '' and not categories[processed_string] then
table.insert(categories, processed_string)
categories[processed_string] = true
end
end
end
end
return categories
end
-- Обработка страны с поиском привязанных континентов
local function process_country_and_continent(args, title, use_continents)
local country = findCountry.findcountryinstring(title, 'именительный')
if not country or country == "" then
return "", {}, error_string("Ошибка: страна не найдена. ") .. error_category, 1
end
local continents_found = {}
local continents_data = nil
if use_continents then
continents_data = mw.loadJsonData('Модуль:CountryMetaCat/country-continents.json')
if continents_data and continents_data.continents then
for _, continent in ipairs(continents_data.continents) do
if continent.countries then
for _, c in ipairs(continent.countries) do
if c == country then
table.insert(continents_found, continent.name)
break
end
end
end
end
end
end
local error_message = nil
if use_continents and #continents_found == 0 then
error_message = error_string("Ошибка: часть света не найдена для страны " .. country .. ". ") .. error_category
return country, continents_found, error_message, 2, continents_data
end
return country, continents_found, nil, nil, continents_data
end
-- Функция для создания категорий с обработкой континентов
local function cats(args, country, continent_list, continents_data)
local ret = ''
local added_categories = {} -- Отслеживание добавленных категорий без ключей сортировки
local skip_first_tilde = true -- Пропуск первой строки с ~
for i, arg in sparseIpairs(args) do
if type(arg) == "string" and arg ~= "" then
local first_char = mw.ustring.sub(arg, 1, 1)
local rest_string = mw.ustring.sub(arg, 2):gsub("^%s+", "")
-- Обработка для 1 континента
local function process_for_continent(continent)
local result = ''
if first_char == '?' then
-- Проверка категории с ?
local check_category = process_placeholders(rest_string, country, continent, continents_data)
local category_name = mw.ustring.match(check_category, "^(.-)!") or check_category -- Извлекаем название без ключа сортировки
if category_exists(check_category) then
-- Публикация категории, если она существует
if not added_categories[category_name] then
result = string.format('[[Категория:%s]]', mw.ustring.gsub(check_category, "!", "|"))
added_categories[category_name] = true -- Добавление категории без ключа сортировки
end
else
-- Проверка следующей строки с символом ~
local next_arg = args[i + 1] -- Следующая строка
if next_arg and mw.ustring.sub(next_arg, 1, 1) == '~' then
-- Если следующая строка начинается с ~, публикуем её как замену
local then_category = process_placeholders(mw.ustring.sub(next_arg, 2):gsub("^%s+", ""), country, continent, continents_data)
local then_category_name = mw.ustring.match(then_category, "^(.-)!") or then_category -- Извлекаем название без ключа сортировки
if not added_categories[then_category_name] then
result = string.format('[[Категория:%s]]', mw.ustring.gsub(then_category, "!", "|"))
added_categories[then_category_name] = true -- Отслеживаем категорию без ключа сортировки
end
end
end
elseif first_char == '~' then
-- Пропускаем первую строку с ~, если до неё не было ?
if skip_first_tilde then
skip_first_tilde = false
else
-- Иначе игнорируем ~, если нет связанной строки с ?
end
else
-- Обычная категория, если нет символов "?" или "~"
local category = process_placeholders(arg, country, continent, continents_data)
local category_name = mw.ustring.match(category, "^(.-)!") or category -- Извлекаем название без ключа сортировки
if not added_categories[category_name] then
result = string.format('[[Категория:%s]]', mw.ustring.gsub(category, "!", "|"))
added_categories[category_name] = true -- Отслеживаем категорию без ключа сортировки
end
end
return result
end
-- Если континентов нет или он один
ret = ret .. process_for_continent(continent_list[1])
-- Если континентов больше одного
if #continent_list > 1 then
ret = ret .. process_for_continent(continent_list[2])
end
end
end
return ret
end
function p.main(frame)
local args = getArgs(frame)
local title = args.title or mw.title.getCurrentTitle().text
if mw.title.getCurrentTitle().namespace == 10 then
return "[[Категория:Шаблоны, использующие модуль CountryMetaCat]]" ..
"[[Категория:Шаблоны, использующие индекс категории (автоматический)]]"
end
-- Определение необходимости использования континентов
local use_continents = has_continent_placeholders(args)
-- Обработка страны и континента
local country, continent_list, error_message, error_code, continents_data = process_country_and_continent(args, title, use_continents)
-- Возврат ошибки, если страна не найдена
if error_code == 1 then
return error_message
end
local ret = ''
-- Публикация категорий
ret = ret .. cats(args, country, continent_list, continents_data)
-- Добавление ошибки, если континент не найден
if error_code == 2 then
ret = ret .. error_message
end
-- Добавление индекса категории, если параметр noindex не установлен
if args.noindex ~= "1" then
ret = mw.getCurrentFrame():preprocess('{{индекс категории (автоматический)}}\n') .. ret
end
return ret
end
function p.resolve_country(frame)
local args = getArgs(frame)
return p._resolve_country(args)
end
-- Функция значений экспорта стран и континентов
function p._resolve_country(args)
local title = args.title or mw.title.getCurrentTitle().text
-- Определение необходимости использования континентов
local use_continents = has_continent_placeholders(args)
-- Обработка страны и континента
local country, continent_list, error_message, error_code, continents_data = process_country_and_continent(args, title, use_continents)
local result = {result = '', extra_result = nil, error = error_code or 0}
local added_categories = {}
-- Обрабатываем основной результат
result.result = process_placeholders(args[1] or '', country, continent_list[1], continents_data)
-- Проверяем, нужно ли возвращать extra_result
if #continent_list > 1 then
result.extra_result = process_placeholders(args[1], country, continent_list[2], continents_data)
end
-- Добавление категорий, если они уникальны
if result.result ~= '' and not added_categories[result.result] then
added_categories[result.result] = true
end
if result.extra_result and result.extra_result ~= '' and not added_categories[result.extra_result] then
added_categories[result.extra_result] = true
end
return result
end
return {
main = p.main,
resolve_country = p.resolve_country
}