Модуль:Сапраўдны нумар старонкі

Глядзі Шаблон:Сапраўдны нумар старонкі.


-- Модуль, які ідэнтыфікуе сапраўдны нумар старонкі (праз інфармацыю з
-- 'pagelist' са старонкі індэкса). Выкарыстоўваецца ў прасторы старонак
-- у калонтытуле для аўтаматычнага адлюстравання нумароў старонак.
--
-- Параметры:
--  'калі':
--    'цотны'/'цотная'     - ігнараваць усё акрамя цотных старонак
--    'няцотны'/'няцотная' - ігнараваць усё акрамя няцотных старонак
--  'л'                    - дадаткова прычапіць кавалак тэксту злева
--  'п'                    - дадаткова прычапіць кавалак тэксту справа

local p = {}

-- TODO: move books information table to another script
-- These are the starting pages of each book chapter. The last number in
-- the table is the last page +1 (a would-be start of the next nonexisting chapter).
local translated_books = {
	["Прынц і жабрак (1928).pdf"] = {
		{
			bel_chapters = { 1, 2, 7, 15, 19, 27, 36, 39, 42, 45, 55, 60, 72, 77, 90, 102, 105, 116, 124, 129, 136, 141, 147, 150, 153, 161, 166, 177, 181, 183, 186, 192, 204, 212, 215 + 1 },
			eng_chapters = { 23, 27, 37, 49, 57, 73, 89, 97, 103, 109, 123, 133, 151, 161, 179, 195, 203, 223, 237, 247, 259, 269, 281, 289, 295, 309, 317, 333, 341, 347, 353, 365, 385, 399, 401 + 1 },
			prefix = ":s:en:The_Prince_and_the_Pauper/Chapter_",
			subst = { ["Chapter_34"] = "Conclusion" },
		}
	},
	["Прынц і жабрак (1940).pdf"] = {
		{
			bel_chapters = { 3, 4, 10, 17, 23, 32, 40, 45, 48, 50, 59, 64, 77, 81, 94, 105, 108, 120, 127, 133, 139, 143, 150, 154, 157, 164, 168, 178, 182, 184, 186, 192, 204, 212, 214 + 1 },
			eng_chapters = { 23, 27, 37, 49, 57, 73, 89, 97, 103, 109, 123, 133, 151, 161, 179, 195, 203, 223, 237, 247, 259, 269, 281, 289, 295, 309, 317, 333, 341, 347, 353, 365, 385, 399, 401 + 1 },
			prefix = ":s:en:The_Prince_and_the_Pauper/Chapter_",
			subst = { ["Chapter_34"] = "Conclusion" },
		}
	},
	["Востраў скарбаў.pdf"] = {
		{
			bel_chapters = { 3, 11, 17, 24, 31, 37, 45, 51, 57, 63, 68, 75, 82, 87, 92, 100, 105, 110, 114, 120, 126, 133, 138, 142, 146, 152, 160, 166, 174, 180, 187, 194, 200, 206, 212 + 1 },
			eng_chapters = { 1, 10, 19, 28, 37, 45, 54, 61, 69, 77, 85, 94, 103, 110, 118, 128, 135, 142, 149, 158, 166, 175, 184, 191, 199, 206, 218, 227, 238, 247, 257, 267, 276, 285, 292 + 1 },
			prefix = ":s:en:Treasure_Island_(1883)/Chapter_",
		}
	},
	["Апошні з магікан.pdf"] = {
--	    bel_chapters = { 3, 14, 26, 37, 51, 63, 78, 93, 108, 118, 131, 149, 165, 177, 195, 211, 228, 248, 261, 275, 290, 306, 321, 340, 357, 376, 390, 401, 416, 435, 452, 464, 482, 496 + 1 },
    	{
    		bel_chapters = { 3, 14, 26, 37, 51, 63, 78, 93, 108, 118, 131, 149, 164 + 1 },
    		eng_chapters = { 1, 24, 44, 64, 84, 105, 130, 156, 179, 199, 226, 256, 287 + 1 },
    		prefix = ":s:en:The_Last_of_the_Mohicans;_a_Narrative_of_1757/Volume_1/Chapter_"
    	},
    	{
    		bel_chapters = { 165, 177, 195, 211, 228, 248, 261, 275, 290, 306, 320 + 1 },
    		eng_chapters = { 1, 26, 58, 84, 111, 144, 171, 200, 227, 251, 276 + 1 },
    		prefix = ":s:en:The_Last_of_the_Mohicans;_a_Narrative_of_1757/Volume_2/Chapter_"
    	},
    	{
    		bel_chapters = { 321, 340, 357, 376, 390, 401, 416, 435, 452, 464, 482, 496 + 1 },
    		eng_chapters = { 1, 31, 58, 87, 111, 134, 157, 186, 213, 232, 266, 295 + 1 },
    		prefix = ":s:en:The_Last_of_the_Mohicans;_a_Narrative_of_1757/Volume_3/Chapter_"
    	},
	},
	["Домбі і сын.pdf"] = {
		{
			bel_chapters = { 3, 11, 19, 28, 38, 51, 67, 70, 85, 93, 101, 111, 126, 135, 153, 163, 168, 175, 189, 198, 207, 214, 229, 244, 252, 258, 270, 280, 287, 294, 303, 315, 330, 340, 350, 359, 368, 376, 384, 397, 410, 418, 429, 435, 442, 447, 456, 469, 477, 488, 500, 505, 517, 528, 535, 541, 556, 561, 569, 580, 586, 593, 597 + 1 },
			eng_chapters = { 1, 8, 16, 24, 33, 45, 61, 65, 79, 88, 97, 107, 120, 129, 146, 157, 161, 169, 183, 193, 203, 211, 225, 241, 250, 257, 269, 281, 289, 297, 309, 321, 334, 343, 353, 361, 370, 378, 385, 397, 409, 417, 428, 435, 442, 449, 458, 472, 481, 494, 507, 513, 524, 536, 545, 554, 571, 577, 588, 602, 611, 620, 624 + 1 },
			prefix = ":s:en:Dombey_and_Son_(1848)/Chapter_",
		}
	},
}

-- Calculate the length of the overlappping area of two intervals
local function calc_overlap(min_a, max_a, min_b, max_b)
	if max_a <= min_b or max_b <= min_a then
		return 0 -- no overlap at all
	end
	if min_a <= min_b and max_a >= max_b then
		return max_b - min_b -- b is fully enclosed by a
	end
	if min_b <= min_a and max_b >= max_a then
		return max_a - min_a -- a is fully enclosed by b
	end
	if max_a >= min_b and max_a <= max_b then
		return max_a - min_b -- partial overlap, a is on the left side
	end
	if max_b >= min_a and max_b <= max_a then
		return max_b - min_a -- partial overlap, b is on the left side
	end
end

-- Find the most suitable English page, assuming that the sizes of all pages
-- are roughly the same (that's not how it is in reality)
local function nearest_page(belsize, engsize, beloffs)
	local bel_frac_page_start = beloffs / belsize
	local bel_frac_page_end = (beloffs + 1) / belsize
	local best_overlap = 0
	local best_eng_offs = nil
	for i = 0, engsize - 1 do
		local eng_frac_page_start = i / engsize
		local eng_frac_page_end = (i + 1) / engsize
		local overlap = calc_overlap(eng_frac_page_start, eng_frac_page_end, bel_frac_page_start, bel_frac_page_end)
		if overlap > best_overlap then
			best_overlap = overlap
			best_eng_offs = i
		end
	end
	return best_eng_offs
end

-- Return either just a plain number or a link to an English book chapter
-- with the approximate page. Implemented via having some tabulated data with
-- chapters layout for a few known books.
local function format_page_num(page_name, num)
	local page_name = page_name:gsub("/.*$", "")
	if translated_books[page_name] then
		for _, translated_book in ipairs(translated_books[page_name]) do
			if #translated_book.bel_chapters == #translated_book.eng_chapters then
				chapter = nil
				for i = 1, #translated_book.bel_chapters do
					if translated_book.bel_chapters[i] > num then
						break
					end
					chapter = i
				end
				if chapter and chapter ~= #translated_book.bel_chapters then
					local engsize = translated_book.eng_chapters[chapter + 1] -
			                		translated_book.eng_chapters[chapter]
					local belsize = translated_book.bel_chapters[chapter + 1] -
			                		translated_book.bel_chapters[chapter]
					local beloffs = num - translated_book.bel_chapters[chapter]
					local engoffs = nearest_page(belsize, engsize, beloffs)
					local result = "[[" .. translated_book.prefix .. tostring(chapter) ..
				        "#" .. tostring(translated_book.eng_chapters[chapter] + engoffs) .. "|" .. tostring(num) .. "]]"
		    		if translated_book.subst then
				    	for k, v in pairs(translated_book.subst) do
		    				result = result:gsub(k, v)
		    			end
		    		end
		    		return result
				end
			end
		end
	else
		return tostring(num)
	end
end

local function _page_number(cond, page_name, leftpad, rightpad)
	leftpad = leftpad or ""
	rightpad = rightpad or ""
	if not page_name then
		page_name = mw.title.getCurrentTitle().text
	end
	
	local page_name = page_name:gsub("^.*:", "")
	local page = mw.ext.proofreadPage.newPage(page_name)
	local num = tonumber(page.displayedNumber)

    if not num then
    	return ""
    end

	if cond and (cond == 'цотны' or cond == 'цотная') then
		if num % 2 == 0 then
			return leftpad .. format_page_num(page_name, num) .. rightpad
		end
	end

	if cond and (cond == 'няцотны' or cond == 'няцотная') then
		if num % 2 ~= 0 then
			return leftpad .. format_page_num(page_name, num) .. rightpad
		end
	end

	if not cond or cond == '' or cond == 'любы' or cond == 'любая' or cond == 'заўсёды' then
		return leftpad .. format_page_num(page_name, num) .. rightpad
	end
	
	return ""
end

function p.page_number(frame)
	local cond = (frame.args['калі'] or frame.args[1]) or (frame:getParent().args['калі'] or frame:getParent().args[1])
	local leftpad = (frame.args['л'] or frame.args[2]) or (frame:getParent().args['л'] or frame:getParent().args[2])
	local rightpad = (frame.args['п'] or frame.args[3]) or (frame:getParent().args['п'] or frame:getParent().args[3])
	local pagename = (frame.args['старонка'] or frame.args[4]) or (frame:getParent().args['старонка'] or frame:getParent().args[4])
	return _page_number(cond, pagename, leftpad, rightpad)
end

-- This should be in a different module, but initially added here for testing
function p.footer_padding(frame)
	local spacing = (frame.args[1]) or (frame:getParent().args[1])
	if spacing then
	    return frame:preprocess("\n\n<references/><div style=\"height:" .. spacing .. ";font-size:" .. spacing .. ";\">&nbsp;</div>")
	end
	return frame:preprocess("\n\n<references/>")
end

p._page_number = _page_number
return p