Модуль:Локаль

Материал из свободной русской энциклопедии «Традиция»
Перейти к: навигация, поиск

Модуль для типографики и прочего.

Функции:

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

-- Dependencies:
local keys	= require 'Module:TableTools'.numKeys
local merge	= require 'Module:Array'.table_merge
local u = mw.ustring
local gsub, char, sub, len, lower = u.gsub, u.char, u.sub, u.len, u.lower
local floor = math.floor
local clone	= mw.clone

local lang = mw.language.getContentLanguage ()

-- Get alternative titles from Help page:
local function names (main)
	local results = mw.smw.ask {
		[1]			= '[[Является представителем::Справка:Функция Lua]]'
				   .. '[[Название::' .. main .. ']]'
	  , [2]			= '?Другое название'
	  , mainlabel	= '-'
	  , link		= 'none'
	}
	local ret = results and results [1] ['Другое название'] or {}
	ret [#ret + 1] = main
	return ret
end	-- local function names (main)

-- Export APIs:
local function exportAPIs (export, implementation, settings)
	for service, system in pairs (settings.systems) do
		local APIs = type (service) == 'table' and service or {service}
		for _, alias in ipairs (APIs) do
			export [alias] = function (frame)
				return implementation (system, settings, frame.args)
			end
		end
	end	-- for service, system in pairs (settings.systems)
end	-- local function exportAPIs (export, implementation, settings)

-- Перевод арабских цифр в неарабские:
-- Numerals:
local numeralData = {
	systems = {
		-- Прописью:
		[{'прописью'}] = {
				  [1] = ' один'
		  , 	  [2] = ' два'
		  , 	  [3] = ' три'
		  ,		  [4] = ' четыре'
		  ,		  [5] = ' пять'
		  ,		  [6] = ' шесть'
		  ,		  [7] = ' семь'
		  ,		  [8] = ' восемь'
		  ,		  [9] = ' девять'
		  ,		 [11] = ' одиннадцать'
		  , 	 [12] = ' двенадцать'
		  , 	 [13] = ' тринадцать'
		  ,		 [14] = ' четырнадцать'
		  ,		 [15] = ' пятнадцать'
		  ,		 [16] = ' шестнадцать'
		  ,		 [17] = ' семнадцать'
		  ,		 [18] = ' восемнадцать'
		  ,		 [19] = ' девятнадцать'
		  ,		 [10] = ' десять'
		  , 	 [20] = ' двадцать'
		  , 	 [30] = ' тридцать'
		  ,		 [40] = ' сорок'
		  ,		 [50] = ' пятьдесят'
		  ,		 [60] = ' шестьдесят'
		  ,		 [70] = ' семьдесят'
		  ,		 [80] = ' восемьдесят'
		  ,		 [90] = ' девяносто'
		  ,		[100] = ' сто'
		  , 	[200] = ' двести'
		  , 	[300] = ' триста'
		  ,		[400] = ' четыреста'
		  ,		[500] = ' пятьсот'
		  ,		[600] = ' шестьсот'
		  ,		[700] = ' семьсот'
		  ,		[800] = ' восемьсот'
		  ,		[900] = ' девятьсот'
			 -- Тысячи:
		  ,		[1000] = function (str, number)
		  			local feminine = gsub (gsub (str, 'один$', 'одна'), 'два$', 'две')
		  			return feminine .. ' ' .. lang:plural (number, {'тысяча', 'тысячи', 'тысяч'})
		  		end
		  ,		[1000000] = function (str, number)
		  			return str .. ' ' .. lang:plural (number, {'миллион', 'миллиона', 'миллионов'})
		  		end
		  ,		[10000000000] = function (str, number)
		  			return str .. ' ' .. lang:plural (number, {'миллиард', 'миллиарда', 'миллиардов'})
		  		end
		  , wrap = function (str)
		  		-- Удаление пробела слева:
		  		return sub (str, 2)
		  	end
		}	-- [{'прописью'}] = {...}

		-- Римские цифры:
	  ,	[names 'римскими'] = {
				  [1] = 'I'
		  ,		  [4] = 'IV'
		  ,		  [5] = 'V'
		  ,  	  [9] = 'IX'
		  ,		 [10] = 'X'
		  ,		 [40] = 'XL'
		  ,		 [50] = 'L'
		  ,		 [90] = 'XC'
		  ,	 	[100] = 'C'
		  ,	 	[400] = 'CD'
		  ,	 	[500] = 'D'
		  ,	 	[900] = 'CM'
		  ,	   [1000] = 'M'
		  ,	   [5000] = 'ↁ'
		  ,   [10000] = 'ↂ'
		  ,   [50000] = 'ↇ'
		  ,  [100000] = 'ↈ'
		   -- Единственный случай, когда порог применения «цифры» отличается от её значения:
		  ,  [500000] = {digit = function (str)
				return '<span style="text-decoration: overline">' .. str .. '</span>'
			 end, value = 1000}
		  , [1000000] = function (str)
				return '<span style="padding-top: 1px; border-top: 1px solid; text-decoration: overline;">'
					.. str
					.. '</span>'
			end		  
		  , unicode = {
				   [1] = 'Ⅰ'
			  ,	   [2] = 'Ⅱ'
			  ,	   [3] = 'Ⅲ'
			  ,	   [4] = 'Ⅳ'
			  ,	   [5] = 'Ⅴ'
			  ,	   [6] = 'Ⅵ'
			  ,	   [7] = 'Ⅶ'
			  ,	   [8] = 'Ⅷ'
			  ,	   [9] = 'Ⅸ'
			  ,   [10] = 'Ⅹ'
			  ,   [11] = 'Ⅺ'
			  ,   [12] = 'Ⅻ'
			  ,   [40] = 'ⅩⅬ'
			  ,   [50] = 'Ⅼ'
			  ,   [90] = 'ⅩⅭ'
			  ,  [100] = 'Ⅽ'
			  ,  [400] = 'ⅭⅮ'
			  ,  [500] = 'Ⅾ'
			  ,  [900] = 'ⅭⅯ'
			  , [1000] = 'Ⅿ'			  
			  -- , API = {'римскими-юникод', 'римские-юникод', 'roman-unicode'}
			} -- ['unicode']
		  , ['unicode-small'] = {
				   [1] = 'ⅰ'
			  ,	   [2] = 'ⅱ'
			  ,	   [3] = 'ⅲ'
			  ,	   [4] = 'ⅳ'
			  ,	   [5] = 'ⅴ'
			  ,	   [6] = 'ⅵ'
			  ,	   [7] = 'ⅶ'
			  ,	   [8] = 'ⅷ'
			  ,	   [9] = 'ⅸ'
			  ,   [10] = 'ⅹ'
			  ,   [11] = 'ⅺ'
			  ,   [12] = 'ⅻ'
			  ,   [40] = 'ⅹⅼ'
			  ,   [50] = 'ⅼ'
			  ,   [90] = 'ⅹⅽ'
			  ,  [100] = 'ⅽ'
			  ,  [400] = 'ⅽⅾ'
			  ,  [500] = 'ⅾ'
			  ,  [900] = 'ⅽⅿ'
			  , [1000] = 'ⅿ'			  
			  --, API = {'римскими-юникод-малыми', 'римские-юникод-малые', 'roman-unicode-small'}
			} -- ['unicode-small']
		} -- [names 'римскими']

		-- Старые греческие «цифры»:
	  , [names 'греческими'] = {
			   [1] = 'Α'
		  ,	   [2] = 'Β'
		  ,	   [3] = 'Γ'
		  ,	   [4] = 'Δ'
		  ,	   [5] = 'Ε'
		  ,	   [6] = 'Ϛ'
		  ,	   [7] = 'Ζ'
		  ,	   [8] = 'Η'
		  ,	   [9] = 'Θ'
		  ,   [10] = 'Ι'
		  ,   [20] = 'Κ'
		  ,   [30] = 'Λ'
		  ,   [40] = 'Μ'
		  ,   [50] = 'Ν'
		  ,   [60] = 'Ξ'
		  ,   [70] = 'Ο'
		  ,   [80] = 'Π'
		  ,   [90] = 'Ϙ'
		  ,  [100] = 'Ρ'
		  ,  [200] = 'Σ'
		  ,  [300] = 'Τ'
		  ,  [400] = 'Υ'
		  ,  [500] = 'Φ'
		  ,  [600] = 'Χ'
		  ,  [700] = 'Ψ'
		  ,  [800] = 'Ω'
		  ,  [900] = 'Ϡ'
			-- Левая керая для тысяч:
		  , [1000] = function (str) return '͵' .. str end		  
		  , lang = 'el'
		} -- [names 'греческими']

		-- Аттические «цифры»:
		-- alternative_names (main)
	  , [names 'аттическими'] = {
				[1] = 'Ι'
		  ,		[5] = 'Π'
		  ,	   [10] = 'Δ'
		  ,	   [50] = char (0x10144)
		  ,   [100] = 'Η'
		  ,   [500] = char (0x10145)
		  ,  [1000] = 'Χ'
		  ,  [5000] = char (0x10146)
		  , [10000] = 'Μ'
		  , [50000] = char (0x10147)		  
		  , lang = 'el'		  
		} -- [names 'аттическими']

		-- Старые еврейские «цифры»:
	  , [names 'еврейскими'] = {
			   [1] = 'א'
		  ,	   [2] = 'ב'
		  ,	   [3] = 'ג'
		  ,	   [4] = 'ד'
		  ,	   [5] = 'ה'
		  ,	   [6] = 'ו'
		  ,	   [7] = 'ז'
		  ,	   [8] = 'ח'
		  ,	   [9] = 'ט'
		  ,   [10] = 'י'
			  -- Исключения для 15 и 16:		  
		  ,   [15] = 'טו'
		  ,   [16] = 'טז'
		  ,   [17] = 'יז'
		  ,   [18] = 'יח'
		  ,   [19] = 'יט'
		  ,   [20] = 'כ'
		  ,   [30] = 'ל'
		  ,   [40] = 'מ'
		  ,   [50] = 'נ'
		  ,   [60] = 'ס'
		  ,   [70] = 'ע'
		  ,   [80] = 'פ'
		  ,   [90] = 'צ'
		  ,  [100] = 'ק'
		  ,  [200] = 'ר'
		  ,  [300] = 'ש'
		  ,  [400] = 'ת'
		  ,	[1000] = function (str) return str .. '׳' end		  
		  , lang = 'he'
		  , wrap = function (str)
		  		if len (str) > 1 then
		  			-- Вставка гершаим перед последним символом, но не рядом с герешем:
		  			if not (sub (str, -1) == '׳' or sub (str, -2, -2) == '׳') then
		  				return sub (str, 1, -2) .. '״' .. sub (str, -1)
		  			else
		  				return str
		  			end
		  		else
		  			-- Вставка гереша:
		  			return str .. '׳'
		  		end	-- if mw.ustring.len (str) > 1
	  		end	-- wrap = function (str)
	  	  , rtl = true
		} -- [names 'еврейскими']

		-- Старые кириллические «цифры». Используется «малый счёт»:
	  , [names 'кириллицей'] = {
					[1] = 'А'
		  ,			[2] = 'В'
		  ,			[3] = 'Г'
		  ,			[4] = 'Д'
		  ,			[5] = 'Є'
		  ,			[6] = 'Ѕ'
		  ,			[7] = 'З'
		  ,			[8] = 'И'
		  ,			[9] = 'Ѳ'
		  ,		   [10] = 'І'
		  ,		   [11] = 'АІ'
		  ,		   [12] = 'ВІ'
		  ,		   [13] = 'ГІ'
		  ,		   [14] = 'ДІ'
		  ,		   [15] = 'ЄІ'
		  ,		   [16] = 'ЅІ'
		  ,		   [17] = 'ЗІ'
		  ,		   [18] = 'ИІ'
		  ,		   [19] = 'ѲІ'
		  ,		   [20] = 'К'
		  ,		   [30] = 'Л'
		  ,		   [40] = 'М'
		  ,		   [50] = 'Н'
		  ,		   [60] = 'Ѯ'
		  ,		   [70] = 'Ѻ'
		  ,		   [80] = 'П'
		  ,		   [90] = 'Ч'
		  ,		  [100] = 'Р'
		  ,		  [200] = 'С'
		  ,		  [300] = 'Т'
		  ,		  [400] = 'У'
		  ,		  [500] = 'Ф'
		  ,		  [600] = 'Х'
		  ,		  [700] = 'Ѱ'
		  ,		  [800] = 'Ω'
		  ,		  [900] = 'Ц'
			-- Тысячи:
		  ,		 [1000] = function (str) return gsub (str, '%a', '҂%0', n) end
			-- Тьмы:
		  ,		[10000] = function (str) return gsub (str, '%a', '%0⃝', n) end
			-- Легионы:
		  ,	   [100000] = function (str) return gsub (str, '%a', '%0҈', n) end
			-- Леодры:
		  ,   [1000000] = function (str) return gsub (str, '%a', '%0҉', n) end
			-- Вороны:
		  ,  [10000000] = function (str) return gsub (str, '%a', '%0꙰', n) end
			-- Колоды:
		  ,	[100000000] = function (str) return gsub (str, '%a', '%0꙱', n) end
		  , lang = 'cu'
		} -- [names 'кириллицей']

	}, -- systems

	-- Ошибки:
	noNumber	= 'Передайте аргумент',
	notAnumber  = 'Передайте целое число',
	notInteger  = 'Дроби не поддерживаются',
	notPositive = 'Неположительные числа не поддерживаются',

	-- Аргументы:
	argNumber = 1,		   -- число
	argLower  = 'строчными'
}

local function formatNumeralError (message, ...)
	if select ('#', ...) > 0 then
		message = string.format (message, ...)
	end
	return '<span class="error">' .. message .. '</span>'
end

-- Проверка правильности переданного параметра:
local function loadNumber (number, noNumber, notAnumber, notInteger, notPositive)
	-- Нет аргумента:
	if not number then
		return false, formatNumeralError (noNumber)
	end
 
	-- Проверки:
	local result = tonumber (number)
	-- Это число:
	if not result then
		return false, formatNumeralError (notAnumber, number)
	end
	-- Это целое:
	if math.floor (result) ~= result then
		return false, formatNumeralError (notInteger, number)
	end
	-- Это натуральное:
	if result <= 0 then
		return false, formatNumeralError (notPositive, number)
	end

	return true, result
end	-- local function loadNumber (number, noNumber, notAnumber, notInteger, notPositive)

-- Проверка правильности переданного параметра «строчными»:
local function loadLower (str)
	return true, str and str ~= ''
end 

--[[
 НАЗНАЧЕНИЕ:  Эта функция переводит натуральные числа арабскими цифрами в римские или другие.
 
 ПАРАМЕТРЫ:   number -- Натуральное число,
			  system -- система отображения, напр., «римскими»,
			  lower  -- true, чтобы привести вывод к нижнему регистру.
 
 ВЫВОД:	   Нет.
 
 ВОЗВРАТ:	 0, сообщение об ошибке - Ошибка из-за неверного аргумента
			  строка				 - число римскими цифрами
 
 ПРИМЕЧАНИЕ:  Все проверки аргумента уже проведены в loadNumber.
--]]
local function implement2nonarabic (number, conf)
	local ret = ''
	local residue = number
	
	local thresholds = keys (conf)
	-- table.sort () sort in place:
	table.sort (thresholds, function (a, b) --[[descending]] return a > b end)
	
	for _, threshold in ipairs (thresholds) do
		local value, digit = threshold, conf [threshold]
		if type (digit) == 'table' then
			value, digit = digit.value, digit.digit
		end
		local converted = ''
		if residue >= threshold then
			-- if the digit is at all applicable (the number is great enough):
			if type (digit) == 'string' then
				-- простая «цифра»:
				while residue >= value do
					residue = residue - value
					converted = converted .. digit
				end
			elseif type (digit) == 'function' then
				-- более сложное оформление для больших чисел:
				local quotient = floor (residue / value)
				converted = digit (implement2nonarabic (quotient, conf), quotient)
				residue = residue % value
			end
			ret = ret .. converted
		end -- if residue >= threshold then
	end	 -- for _, threshold in ipairs (thresholds) do
	return ret
end			 -- local function implement2nonarabic (number, conf)
 
-- Загрузка конфигурации системы счисления:
local function loadConf (conf, options)
	local loaded = clone (conf)
	-- Overrides:
	for _, override in ipairs (options) do
		loaded = merge (loaded, loaded [override])
	end
	return loaded
end				-- local function loadConf (conf, options)
	
-- Загрузка аргументов и вызов реализации:
local function toNonarabic (system, service, args)
	local ok
	-- Загрузка и проверка аргумента:
	local number
	ok, number = loadNumber (args [service.argNumber], service.noNumber, service.notAnumber, service.notInteger, service.notPositive)
	if not ok then
		-- Ошибка в аргументе:
		return number
	end
	-- Загрузка и проверка показателя нижнего регистра:
	local toLower = false
	ok, toLower = loadLower (args [service.argLower])
	if not ok then
		-- Ошибка в аргументе «строчными»:
		return toLower
	end
	
	-- Остальные аргументы — система счисления и дополнительные аргументы:
	local options = clone (args)
	options [service.argNumber]	= nil
	options [service.argLower]	= nil
	local conf = loadConf (system, options)
	-- Действительное преобразование:
	local ret = implement2nonarabic (number, conf)
	-- Постпроцессинг, если требуется:
	if conf.wrap and type (conf.wrap) == 'function' then
		ret = conf.wrap (ret)
	end
	-- Строчными, если просят:
	if toLower then ret = lower (ret) end	
	-- Обёртка в указатель на язык и указатель направления:
	local dir	= conf.rtl	and ' dir="rtl"'					or ''
	local lang	= conf.lang	and ' lang="' .. conf.lang .. '"'	or ''
	if conf.rtl or conf.lang then
		ret = '<span class="foreign-lang"' .. lang .. dir ..'>' .. ret .. '</span>'
	end
	return ret
end	-- local function toNonarabic (system, service, args)
 
local m = {}

-- Make all numeric systems available:
exportAPIs (m, toNonarabic, numeralData)

-- Перевод кириллицы в глаголицу:
local transliterationData = {
	systems = {
		-- Перевод кириллицы в глаголицу:	
		[names 'глаголицей'] = {
			-- Capital:
			['А'] = 'Ⰰ',
			['Б'] = 'Ⰱ',
			['В'] = 'Ⰲ',
			['Г'] = 'Ⰳ',
			['Д'] = 'Ⰴ',
			['Е'] = 'Ⰵ',
			['Ж'] = 'Ⰶ',
			['Ѕ'] = 'Ⰷ',
			['З'] = 'Ⰸ',
			['І'] = 'Ⰹ',
			['Ї'] = 'Ⰺ',
			['И'] = 'Ⰻ',
			['Й'] = 'Ⰻ',
			['Ћ'] = 'Ⰼ',
			['К'] = 'Ⰽ',
			['Л'] = 'Ⰾ',
			['М'] = 'Ⰿ',
			['Н'] = 'Ⱀ',
			['О'] = 'Ⱁ',
			['П'] = 'Ⱂ',
			['Р'] = 'Ⱃ',
			['С'] = 'Ⱄ',
			['Т'] = 'Ⱅ',
			['Ѵ'] = 'Ⱛ',
			['У'] = 'Ⱆ',
			['Ꙋ'] = 'Ⱆ',
			['Ѹ'] = 'Ⱆ',				
			['Ф'] = 'Ⱇ',
			['Х'] = 'Ⱈ',
			['Ѡ'] = 'Ⱉ',
			['?'] = 'Ⱊ',
			['Ц'] = 'Ⱌ',
			['Ч'] = 'Ⱍ',
			['Ш'] = 'Ⱎ',
			['Щ'] = 'Ⱋ',
			['Ъ'] = 'Ⱏ',
			['Ы'] = 'ⰟⰊ',
			['Ь'] = 'Ⱐ',
			['ѣ'] = 'Ⱑ',
			['Ё'] = 'Ⱖ',
			['H'] = 'Ⱒ',
			['Ю'] = 'Ⱓ',
			['Ѧ'] = 'Ⱔ',
			['Ѩ'] = 'Ⱗ',
			['Ѫ'] = 'Ⱘ',
			['Ѭ'] = 'Ⱙ',
			['Ѳ'] = 'Ⱚ',
			
			['Э'] = 'Ⰵ',
			['Я'] = 'Ⱔ',
	
			-- Lower:
			['а'] = 'ⰰ',
			['б'] = 'ⰱ',
			['в'] = 'ⰲ',
			['г'] = 'ⰳ',
			['д'] = 'ⰴ',
			['е'] = 'ⰵ',
			['ж'] = 'ⰶ',
			['ѕ'] = 'ⰷ',
			['з'] = 'ⰸ',
			['і'] = 'ⰹ',
			['ї'] = 'ⰺ',
			['и'] = 'ⰻ',
			['й'] = 'ⰻ',
			['ћ'] = 'ⰼ',
			['к'] = 'ⰽ',
			['л'] = 'ⰾ',
			['м'] = 'ⰿ',
			['н'] = 'ⱀ',
			['о'] = 'ⱁ',
			['п'] = 'ⱂ',
			['р'] = 'ⱃ',
			['с'] = 'ⱄ',
			['т'] = 'ⱅ',
			['ѵ'] = 'ⱛ',
			['у'] = 'ⱆ',
			['ꙋ'] = 'ⱆ',
			['ѹ'] = 'ⱆ',				
			['ф'] = 'ⱇ',
			['х'] = 'ⱈ',
			['ѡ'] = 'ⱉ',
			['?'] = 'ⱊ',
			['ц'] = 'ⱌ',
			['ч'] = 'ⱍ',
			['ш'] = 'ⱎ',
			['щ'] = 'ⱋ',
			['ъ'] = 'ⱏ',
			['ы'] = 'ⱏⰺ',
			['ь'] = 'ⱐ',
			['ѣ'] = 'ⱑ',
			['ё'] = 'ⱖ',
			['h'] = 'ⱒ',
			['ю'] = 'ⱓ',
			['ѧ'] = 'ⱔ',
			['ѩ'] = 'ⱗ',
			['ѫ'] = 'ⱘ',
			['ѭ'] = 'ⱙ',
			['ѳ'] = 'ⱚ',
			
			['э'] = 'ⰵ',
			['я'] = 'ⱔ'
		}	-- [names 'глаголицей']
	}	-- systems
	-- Ошибки:
  , noString	= 'Передайте кириллическую строку'
}	-- local transliterationData

local function implementTransliteration (from, corr)
	local glagolitic, _ = gsub (from, '.', corr)
	return glagolitic
end	-- local function implementTransliteration (from, corr)

local function transliterate (alphabet, transliterations, args)
	local str = table.concat (clone (args))
	if not str or str == '' then
		return formatNumeralError (transliterations.noString)
	else
		return implementTransliteration (str, alphabet)
	end
end	-- local function transliterate (alphabet, transliterations, args)

-- Make glagolitic available:
-- Make all transliteration systems available:
exportAPIs (m, transliterate, transliterationData)

return m