Mô đun:Year in other calendars

-- Load dependencies.
local getArgs = require('Module:Arguments').getArgs
local numToRoman = require( 'Module:Roman' ).main
local getOlympiad = require( 'Module:Ancient Olympiads' )._main
local getDynasty = require( 'Module:Ancient Egypt era' )._main
local getPharaoh = require( 'Module:Ancient Egypt kings' )._main
local numToArmenian = require( 'Module:Armenian' ).main
local getRegnal = require( 'Module:British regnal year' ).main
local japaneseEra = require( 'Module:Japanese calendar' ).era()
-- Define constants.
local lang = mw.language.getContentLanguage()
local currentYear = tonumber( lang:formatDate( 'Y' ) )
--------------------------------------------------------------------
-- Helper functions
--------------------------------------------------------------------
local function isInteger( num )
	-- Checks if a value is an integer. If so, returns the value converted to a number.
	-- If not, returns false.
	num = tonumber( num )
	if num and math.floor( num ) == num and num ~= math.huge then
		return num
	else
		return false
	end
end
local function BCToNum( s )
	-- Converts strings of the format "n BC" to their corresponding
	-- numerical values.
	if type( s ) ~= 'string' then
		return nil
	end
	s = mw.ustring.match( mw.ustring.upper( s ), '^(1-9%d*)%s*TCN$' )
	if not s then
		return nil
	end
	local num = tonumber( s )
	num = ( num - 1 ) * -1
	return num
end
local function numToBC( num )
	-- For BC years, returns a string with the year name appended with " BC".
	-- Otherwise returns nil.
	num = isInteger( num )
	if not num then return end
	if num %s', self.footnotes ) )
	end
	return tostring( root )
end
--------------------------------------------------------------------
-- Calendar group class definition
--------------------------------------------------------------------
--  Calendar groups are used to group different calendars together. 
--  Previously, the template did this by including a table row with
--  no year value. By using objects we can do the same thing more
--  semantically.
local calendarGroup = {}
calendarGroup.__index = calendarGroup
function calendarGroup:new( init )
	init = type( init ) == 'table' and init or {}
	local obj = {}
	-- Get the heading and throw an error if it is invalid.
	obj.heading = init.heading
	if type( obj.heading ) ~= 'string' then
		error( 'calendarGroup: no heading detected' )
	end
	-- Set the metatable and return the object.
	self.__index = self
	return setmetatable( obj, {
			__index = self
		})
end
function calendarGroup:addCalendar( calendar )
	-- Adds a calendar object to the calendar group.
	self.calendars = self.calendars or {}
	if type( calendar ) == 'table' and type( calendar.getLink ) == 'function' then
		table.insert( self.calendars, calendar )
	end
end
function calendarGroup:export()
	-- Exports the calendar group's wikitext.
	-- Indent and italicise each calendar's link if it exists.
	for i, calendar in ipairs( self.calendars ) do
		local link = calendar:getLink()
		if type( link ) == 'string' then
			self.calendars i :setRawLink( string.format( " - %s", link ) )
		end
	end
	-- Create the heading row html and export the calendar objects.
	local ret = mw.html.create()
	ret
	:tag( 'tr' )
	:tag( 'td' )
	:wikitext( self.heading )
	:done()
	:tag( 'td' ) -- Use a blank tag to make the html look nice.
	:allDone()
	for _, calendar in ipairs( self.calendars ) do
		ret:wikitext( calendar:export() )
	end
	return tostring( ret )
end
--------------------------------------------------------------------
-- Calendar class definition
--------------------------------------------------------------------
local calendar = {}
calendar.__index = calendar
calendar.type = 'calendar'
function calendar:new()
	local obj = {}
	return setmetatable( obj, {
			__index = self
		})
end
function calendar:setLink( link, display )
	-- Sets the calendar's wikilink, with optional display text and italics.
	if type( link ) ~= 'string' or link ==  then return end
	display = type( display ) == 'string' and display ~=  and display
	if display then
		self.link = string.format( '%s', link, display )
	else
		self.link = string.format( '%s', link )
	end
end
function calendar:setRawLink( s )
	-- Sets the calendar's wikilink as raw wikitext.
	if type( s ) ~= 'string' or s ==  then return end
	self.link = s
end
function calendar:getLink()
	-- Returns the calendar's link value.
	return self.link
end
function calendar:setYear( year )
	-- Sets a single year. Can be passed either a string or a number.
	-- If passed as a number, it is formatted with minus signs instead of hyphens.
	-- If passed as a string, no minus-sign formatting occurs; this should be done in the individual calendar definitions.
	if type( year ) == 'number' then
		year = tostring( year )
		self.year = formatNegative( year )
	elseif type( year ) == 'string' then
		self.year = year
	end
end
function calendar:setYearRange( year1, year2 )
	-- Sets a year range. Must be passed two numbers.
	if type( year1 ) == 'number' and type( year2 ) == 'number' then
		local year
		if year1 %s,
				gregorian.yearLink, gregorian.romanYear
				) )
	else
		gregorian:setYear( gregorian.yearLink )
	end
	box:addCalendar( gregorian ) 
----------------------------------------------------------------------
-- Ab urbe condita
----------------------------------------------------------------------

local abUrbe = calendar:new()
abUrbe:setLink( 'Ab urbe condita' )
abUrbe:setYear( year + 753 )
box:addCalendar( abUrbe )
----------------------------------------------------------------------
-- Regnal year
----------------------------------------------------------------------
local regnal = calendar:new()
regnal:setLink( 'Niên hiệu Anh', 'Năm niên hiệu Anh' )
regnal:setYear( getRegnal( year ) )
box:addCalendar( regnal )
----------------------------------------------------------------------
-- Armenian calendar
----------------------------------------------------------------------

local armenian = calendar:new()
armenian:setLink( 'Lịch Armenia' )
if year > 551 then
local armenianYear = year - 551
armenian:setYear( mw.ustring.format( '%sԹՎ %s', armenianYear, numToArmenian( armenianYear ) ) )
end
box:addCalendar( armenian )
----------------------------------------------------------------------
-- Assyrian calendar
----------------------------------------------------------------------
local assyrian = calendar:new()
assyrian:setLink( 'Lịch Assyria' )
assyrian:setYear( year + 4750 )
box:addCalendar( assyrian )

----------------------------------------------------------------------
-- Hindu calendars
----------------------------------------------------------------------
local hindu = calendarGroup:new{ heading = 'Lịch Ấn Độ giáo' }
-- Vikram Samvat
local vikramSamvat = calendar:new()
vikramSamvat:setLink( 'Vikram Samvat' )
vikramSamvat:setYearRange( year + 56, year + 57 )
hindu:addCalendar( vikramSamvat )
-- Shaka Samvat
local shakaSamvat = calendar:new()
shakaSamvat:setLink( 'Quốc lịch Ấn Độ', 'Shaka Samvat' )
if year - 76 > 0 then
shakaSamvat:setYearRange( year - 78, year - 77 )
end
hindu:addCalendar( shakaSamvat )
-- Kali Yuga

local kaliYuga = calendar:new()
kaliYuga:setLink( 'Kali Yuga' ) -- use italics
kaliYuga:setYearRange( year + 3101, year + 3102 )
hindu:addCalendar( kaliYuga )
box:addCalendarGroup( hindu )
----------------------------------------------------------------------
-- Bahá'í calendar
----------------------------------------------------------------------

local bahai = calendar:new()
bahai:setLink( "Lịch Bahá'í", 'Lịch Bahá’í' )
bahai:setYearRange( year - 1844, year - 1843 )
box:addCalendar( bahai )
----------------------------------------------------------------------
-- Bengali calendar
----------------------------------------------------------------------
local bengali = calendar:new()
bengali:setLink( 'Lịch Bengal' )
bengali:setYear( year - 593 )
box:addCalendar( bengali )
----------------------------------------------------------------------
-- Berber calendar
----------------------------------------------------------------------

local berber = calendar:new()
berber:setLink( 'Lịch Berber' )
berber:setYear( year + 950 )
box:addCalendar( berber )
----------------------------------------------------------------------
-- Chinese calendar
----------------------------------------------------------------------

local chinese = calendar:new()
chinese:setLink( 'Can Chi' )
-- Define the information for the "heavenly stems" and "earthly branches" year cycles.
-- See Can Chi for information.
local heavenlyStems = {
{ '甲', 'Giáp' },   -- 1
{ '乙', 'Ất' },     -- 2
{ '丙', 'Bính' },   -- 3
{ '丁', 'Đinh' },   -- 4
{ '戊', 'Mậu' },    -- 5
{ '己', 'Kỷ' },     -- 6
{ '庚', 'Canh' },   -- 7
{ '辛', 'Tân' },    -- 8
{ '壬', 'Nhâm' },   -- 9
{ '癸', 'Quý' }     -- 10
}
local earthlyBranches = {
{ '子', 'Tý' },     -- 1
{ '丑', 'Sửu' },    -- 2
{ '寅', 'Dần' },    -- 3
{ '卯', 'Mão' },    -- 4
{ '辰', 'Thìn' },   -- 5
{ '巳', 'Tỵ' },     -- 6
{ '午', 'Ngọ' },    -- 7
{ '未', 'Mùi' },    -- 8
{ '申', 'Thân' },   -- 9
{ '酉', 'Dậu' },    -- 10
{ '戌', 'Tuất' },   -- 11
{ '亥', 'Hợi' }     -- 12
}
-- Calculate the cycle numbers from the year. The first sexagenary year corresponds to the previous year's entry
-- in :en:Chinese calendar correspondence table, as the Chinese New Year doesn't happen until Jan/Feb in
-- Gregorian years.
local sexagenaryYear1 = ( year - 4 ) % 60
local sexagenaryYear2 = ( year - 3 ) % 60
local heavenlyNum1 = sexagenaryYear1 % 10
local heavenlyNum2 = sexagenaryYear2 % 10
local earthlyNum1 = sexagenaryYear1 % 12
local earthlyNum2 = sexagenaryYear2 % 12
-- If the value is 0 increase it by one cycle so that we can use it with Lua arrays.
if heavenlyNum1 == 0 then
heavenlyNum1 = 10
end
if heavenlyNum2 == 0 then
heavenlyNum2 = 10
end
if earthlyNum1 == 0 then
earthlyNum1 = 12
end
if earthlyNum2 == 0 then
earthlyNum2 = 12
end
-- Get the data tables for each permutation.
local heavenlyTable1 = heavenlyStems heavenlyNum1 
local heavenlyTable2 = heavenlyStems heavenlyNum2 
local earthlyTable1 = earthlyBranches earthlyNum1 
local earthlyTable2 = earthlyBranches earthlyNum2 
-- Work out the continously-numbered year. (See :en:Chinese calendar#Continuously numbered years.)
local year1 = year + 2696
local year2 = year + 2697
local year1Alt = year1 - 60
local year2Alt = year2 - 60
-- Return all of that data in a (hopefully) reader-friendly format.
chinese:setYear( mw.ustring.format(
**%s %s (%s%s年)%d hoặc %d    — đến —%s %s (%s%s年)%d hoặc %d=,
heavenlyTable1 2 ,
earthlyTable1 2 ,
heavenlyTable1 1 ,
earthlyTable1 1 ,
year1,
year1Alt,
heavenlyTable2 2 ,
earthlyTable2 2 ,
heavenlyTable2 1 ,
earthlyTable2 1 ,
year2,
year2Alt
) )
box:addCalendar( chinese )

----------------------------------------------------------------------
-- Juche calendar
----------------------------------------------------------------------
local juche = calendar:new()
juche:setLink( 'Lịch Bắc Triều Tiên', 'Lịch Chủ thể' )
if year > 1911 then
juche:setYear( year - 1911 )
end
box:addCalendar( juche )

----------------------------------------------------------------------
-- Coptic calendar
----------------------------------------------------------------------
local coptic = calendar:new()
coptic:setLink( 'Lịch Copt' )
coptic:setYearRange( year - 284, year - 283 )
box:addCalendar( coptic )
----------------------------------------------------------------------
-- Minguo calendar
----------------------------------------------------------------------
local minguo = calendar:new()
minguo:setLink( 'Lịch Dân Quốc' )
if year > 1911 then
local minguoYear = year - 1911
minguo:setYear( mw.ustring.format( 'Dân Quốc %d民國%d年', minguoYear, minguoYear ) )
else
local minguoYear = 1911 - year + 1
minguo:setYear( mw.ustring.format( '%d trước Dân Quốc民前%d年', minguoYear, minguoYear ) )
end
box:addCalendar( minguo )

----------------------------------------------------------------------
-- Hebrew calendar
----------------------------------------------------------------------
local hebrew = calendar:new()
hebrew:setLink( 'Lịch Do Thái' )
hebrew:setYearRange( year + 3760, year + 3761 )
box:addCalendar( hebrew )
----------------------------------------------------------------------
-- Byzantine calendar
----------------------------------------------------------------------
local byzantine = calendar:new()
byzantine:setLink( 'Lịch Đông La Mã' )
byzantine:setYearRange( year + 5508, year + 5509 )
box:addCalendar( byzantine )
----------------------------------------------------------------------
-- Ethiopian calendar
----------------------------------------------------------------------
local ethiopian = calendar:new()
ethiopian:setLink( 'Lịch Ethiopia' )
ethiopian:setYearRange( year - 8, year - 7 )
box:addCalendar( ethiopian )
----------------------------------------------------------------------
-- Holocene calendar
----------------------------------------------------------------------
local holocene = calendar:new()
holocene:setLink( 'Thời kỳ con người', 'Lịch Holocen' )
holocene:setYear( year + 10000 )
box:addCalendar( holocene )
----------------------------------------------------------------------
-- Islamic calendar
----------------------------------------------------------------------
local islamic = calendar:new()
islamic:setLink( 'Lịch Hồi giáo' )
local islamicMult = 1.030684 -- the factor to multiply by
local islamicSub = 621.5643 -- the factor to subtract by
if year - 621 > 0 then
local year1 = math.floor( islamicMult * ( year - islamicSub ) )
local year2 = math.floor( islamicMult * ( year - islamicSub + 1 ) )
islamic:setYearRange( year1, year2 )
else
local year1 = math.ceil( -islamicMult * ( year - islamicSub ) )
local year2 = math.ceil( -islamicMult * ( year - islamicSub + 1 ) )
islamic:setYear( mw.ustring.format( '%d BH – %d BH', year1, year2 ) )
end
box:addCalendar( islamic )
----------------------------------------------------------------------
-- Igbo calendar
----------------------------------------------------------------------

-- In the old template this was a calendar group with just one calendar; intentionally adding this as a single
-- calendar here, as the previous behaviour looked like a mistake.
local igbo = calendar:new()
igbo:setLink( 'Lịch Igbo' )
igbo:setYearRange( year - 1000, year - 999 )
box:addCalendar( igbo )
----------------------------------------------------------------------
-- Iranian calendar
----------------------------------------------------------------------
local iranian = calendar:new()
iranian:setLink( 'Lịch Iran' )
if year - 621 > 0 then
iranian:setYearRange( year - 622, year - 621 )
else
iranian:setYear( mw.ustring.format( '%d BP – %d BP', 622 - year, 621 - year ) )
end
box:addCalendar( iranian )
----------------------------------------------------------------------
-- Julian calendar
----------------------------------------------------------------------
local julian = calendar:new()
julian:setLink( 'Lịch Julius' )
julian.yearVals = {
{ 1901, 'theo lịch Gregory trừ 13 ngày' },
{ 1900, 'theo lịch Gregory trừ 12 hay 13 ngày'},
{ 1801, 'theo lịch Gregory trừ 12 ngày' },
{ 1800, 'theo lịch Gregory trừ 11 hay 12 ngày' },
{ 1701, 'theo lịch Gregory trừ 11 ngày' },
{ 1700, 'theo lịch Gregory trừ 10 hay 11 ngày' },
{ 1582, 'theo lịch Gregory trừ 10 ngày' },
{ -45, gregorian.year }
}
for i, t in ipairs( julian.yearVals ) do
if year >= t 1  then
julian:setYear( t 2  )
break
end
end
box:addCalendar( julian )

----------------------------------------------------------------------
-- Burmese calendar
----------------------------------------------------------------------
local burmese = calendar:new()
burmese:setLink( 'Lịch Myanma truyền thống', 'Lịch Myanma' )
burmese:setYear( year - 638 )
box:addCalendar( burmese )
----------------------------------------------------------------------
-- Japanese calendar
----------------------------------------------------------------------
local japanese = calendar:new()
japanese:setLink( 'Lịch Nhật Bản' )
japanese.thisEra = japaneseEra:new{ year = year }
if japanese.thisEra then
local japaneseYearText = {}
japanese.oldEra = japanese.thisEra:getOldEra()
if japanese.oldEra and japanese.oldEra.eraYear and japanese.thisEra.article ~= japanese.oldEra.article then
japanese.oldText = mw.ustring.format( '%s %d', japanese.oldEra.link, japanese.oldEra.eraYear )
table.insert( japaneseYearText, japanese.oldText )
table.insert( japaneseYearText, ' / ' )
end
if japanese.thisEra.eraYear then
table.insert( japaneseYearText, mw.ustring.format( '%s %d', japanese.thisEra.link, japanese.thisEra.eraYear ) )
end
table.insert( japaneseYearText, mw.ustring.format( '(%s%s年)', japanese.thisEra.kanji, japanese.thisEra.eraYearKanji ) )
japanese:setYear( table.concat( japaneseYearText ) )
end
box:addCalendar( japanese )
----------------------------------------------------------------------
-- Buddhist calendar
----------------------------------------------------------------------
local buddhist = calendar:new()
buddhist:setLink( 'Phật lịch' )
buddhist:setYear( year + 544 )
box:addCalendar( buddhist )
----------------------------------------------------------------------
-- Thai solar calendar
----------------------------------------------------------------------
local thai = calendar:new()
thai:setLink( 'Dương lịch Thái' )
thai:setYear( year + 543 )
box:addCalendar( thai )

----------------------------------------------------------------------
-- Korean calendar
----------------------------------------------------------------------
local korean = calendar:new()
korean:setLink( 'Lịch Triều Tiên' )
korean:setYear( year + 2333 )
box:addCalendar( korean )

----------------------------------------------------------------------
-- Unix time
----------------------------------------------------------------------

local unix = calendar:new()
local function getUnixTime( year )
if year = 0 then
return unixTime
end
end
unix.thisYear = getUnixTime( year )
unix.nextYear = getUnixTime( year + 1 )
if unix.thisYear and unix.nextYear then
unix:setLink( 'Thời gian Unix' )
unix:setYearRange( unix.thisYear, unix.nextYear - 1 )
end
box:addCalendar( unix )
return box:export()
end
--------------------------------------------------------------------
-- Process arguments from #gọi
--------------------------------------------------------------------
local p = {}
function p.main( frame )
	-- Process the arguments and pass them to the box-building function.
	local args = getArgs( frame )
	-- Pass year argument with 'year' parameter or without any name but first argument
	args.year = args.year or args1
	return makeCalendarBox( args )
end
return p