پودمان:تقویم
ظاهر
شنبه
یکشنبه
دوشنبه
سهشنبه
چهارشنبه
پنجشنبه
جمعه
۱
۲
۳
۴
۵
۶
۷
۸ رمضان
۸
۹
۱۰
۱۱
۱۲
۱۳
۱۴
۱۵
۱۶
۱۷
۱۸
۱۹
۲۰
۲۱
۲۲
۲۳
۲۴
۲۵
۲۶
۲۷
۲۸
۲۹
ملی شدن نفت
شنبه
یکشنبه
دوشنبه
سهشنبه
چهارشنبه
پنجشنبه
جمعه
۱
۲
۳
۴
۵
۶
۷
۸ رمضان
۸
۹
۱۰
۱۱
۱۲
۱۳
۱۴
۱۵
۱۶
۱۷
۱۸
۱۹
۲۰
۲۱
۲۲
۲۳
۲۴
۲۵
۲۶
۲۷
۲۸
۲۹
ملی شدن نفت
-- =====================================================
-- پودمان تقویم شمسی
-- نسخه ۲۸: هوشمندسازی تابع تبدیل اعداد
-- =====================================================
local p = {}
-- -------------------------
-- دادههای ثابت
-- -------------------------
local farsi_digits = { '۰','۱','۲','۳','۴','۵','۶','۷','۸','۹' }
local month_names = {
'فروردین','اردیبهشت','خرداد','تیر','مرداد','شهریور',
'مهر','آبان','آذر','دی','بهمن','اسفند'
}
local week_days = {
'شنبه','یکشنبه','دوشنبه','سهشنبه','چهارشنبه','پنجشنبه','جمعه'
}
-- -------------------------
-- توابع کمکی
-- -------------------------
-- تابع toFarsiDigits (هوشمند شده)
local function toFarsiDigits(num)
if not num then return '' end
local s = tostring(num)
-- بررسی اینکه آیا رشته از قبل فارسی است یا نه
if s:match('[۰-۹]') then
return s -- اگر فارسی بود، دست نزن
end
-- اگر انگلیسی بود، تبدیل کن
return s:gsub('%d', function(d)
return farsi_digits[tonumber(d) + 1]
end)
end
-- بقیه توابع بدون تغییر...
local function normalizeArgs(val)
if not val then return nil end
val = tostring(val)
val = val:gsub('[\226\128\142\226\128\143]', '')
val = val:gsub('۰','0'):gsub('۱','1'):gsub('۲','2'):gsub('۳','3'):gsub('۴','4'):gsub('۵','5'):gsub('۶','6'):gsub('۷','7'):gsub('۸','8'):gsub('۹','9')
local n = val:match('^%s*(%d+)%s*$')
return n and tonumber(n) or nil
end
local function load_events_data()
local success, data = pcall(mw.loadData, 'Module:تقویم/data') -- مسیر پودمان داده
if success then return data else return {} end
end
local function clean_wiki_content(content)
if not content then return '' end
content = content:gsub('<noinclude>.-</noinclude>', '')
content = content:match('^%s*(.-)%s*$')
return content
end
local function get_wiki_page_content(page_title)
local title = mw.title.new(page_title)
if not title or not title.exists then return nil end
local content = title:getContent()
if not content then return nil end
local clean_text = clean_wiki_content(content)
if clean_text == '' then return nil end
local is_long = false
if #clean_text > 800 then
clean_text = clean_text:sub(1, 800) .. '...'
is_long = true
end
return { title = page_title, text = clean_text, is_long = is_long }
end
local function get_corrected_hijri(frame)
local final_day = frame:callParserFunction('#time', 'xmj', 'now -1 day')
local final_month = frame:callParserFunction('#time', 'xmF', 'now -1 day')
-- خروجی #time همیشه عدد انگلیسی است، اما برای اطمینان...
-- در نسخه جدید، toFarsiDigits خودش مدیریت میکند
return final_day, final_month
end
local function prev_month(y, m) return (m == 1) and y - 1 or y, (m == 1) and 12 or m - 1 end
local function next_month(y, m) return (m == 12) and y + 1 or y, (m == 12) and 1 or m + 1 end
local function gregorian_to_jalali(gy, gm, gd)
local gdm = {0,31,59,90,120,151,181,212,243,273,304,334}
local jy = (gy <= 1600) and 0 or 979
gy = gy - ((gy <= 1600) and 621 or 1600)
local gy2 = (gm > 2) and (gy + 1) or gy
local days = 365*gy + math.floor((gy2+3)/4) - math.floor((gy2+99)/100) + math.floor((gy2+399)/400) - 80 + gd + gdm[gm]
jy = jy + 33*math.floor(days/12053)
days = days % 12053
jy = jy + 4*math.floor(days/1461)
days = days % 1461
jy = jy + math.floor((days-1)/365)
if days > 365 then days = (days-1)%365 end
local jm = (days < 186) and 1 + math.floor(days/31) or 7 + math.floor((days - 186) / 30)
local jd = 1 + ((days < 186) and (days % 31) or ((days - 186) % 30))
return jy, jm, jd
end
local function is_persian_leap(y)
local r = (y - 474) % 33
return r==1 or r==5 or r==9 or r==13 or r==17 or r==22 or r==26 or r==30
end
local function days_in_month(y, m)
if m <= 6 then return 31 end
if m <= 11 then return 30 end
return is_persian_leap(y) and 30 or 29
end
local function persian_weekday(y, m, d)
local total = 0
for yy = 1400, y-1 do total = total + (is_persian_leap(yy) and 366 or 365) end
for mm = 1, m-1 do total = total + days_in_month(y, mm) end
total = total + (d-1)
return (1 + total) % 7
end
function p.main(frame)
local args = frame.args
local parent = frame:getParent()
if parent then for k,v in pairs(parent.args) do if not args[k] then args[k] = v end end end
local today = os.date('*t')
local ty, tm, td = gregorian_to_jalali(today.year, today.month, today.day)
local year = normalizeArgs(args['سال']) or ty
local month = normalizeArgs(args['ماه']) or tm
local month_name = args['نام_ماه'] or month_names[month]
local py, pm = prev_month(year, month)
local ny, nm = next_month(year, month)
local prev_month_name = month_names[pm]
local next_month_name = month_names[nm]
local year_fa = toFarsiDigits(year)
local h_day, h_month = get_corrected_hijri(frame)
local hijri_full = ''
if h_day and h_day ~= '' then
hijri_full = toFarsiDigits(h_day) .. ' ' .. h_month
end
local events = load_events_data()
local start = persian_weekday(year, month, 1)
local dim = days_in_month(year, month)
local out = {}
table.insert(out, '<div class="calendar-root">')
-- Header
table.insert(out, '<div class="calendar-header plainlinks">')
local prev_link = '[[' .. '۱ ' .. prev_month_name .. '|‹ ' .. prev_month_name .. ']]'
table.insert(out, '<span class="nav-btn prev">' .. prev_link .. '</span>')
local title_html = '[[' .. month_name .. ' (ماه)|' .. month_name .. ']] ' ..
'[[' .. 'سال ' .. year_fa .. ' هجری شمسی|' .. year_fa .. ']]'
table.insert(out, '<div class="calendar-title">' .. title_html .. '</div>')
local next_link = '[[' .. '۱ ' .. next_month_name .. '|' .. next_month_name .. ' ›]]'
table.insert(out, '<span class="nav-btn next">' .. next_link .. '</span>')
table.insert(out, '</div>')
-- Weekdays
table.insert(out, '<div class="calendar-weekdays">')
for i=1,7 do table.insert(out, '<div class="weekday">' .. week_days[i] .. '</div>') end
table.insert(out, '</div>')
-- Days Grid
table.insert(out, '<div class="calendar-grid">')
for i=1,start do table.insert(out, '<div class="day empty"></div>') end
for d=1,dim do
local cls = 'day'
local content_extra = ''
if persian_weekday(year, month, d) == 6 then cls = cls .. ' friday' end
if year==ty and month==tm and d==td then
cls = cls .. ' today'
if hijri_full ~= '' then
content_extra = content_extra .. '<div class="day-sub">' .. hijri_full .. '</div>'
end
end
local event_key = month .. '-' .. d
local event_val = events[event_key] or events[tostring(event_key)]
if event_val then
cls = cls .. ' has-event'
content_extra = content_extra .. '<div class="day-event">' .. event_val .. '</div>'
end
table.insert(out, '<div class="'..cls..'"><span class="day-main">'..toFarsiDigits(d)..'</span>'..content_extra..'</div>')
end
table.insert(out, '</div>')
-- Footer
if year == ty and month == tm then
table.insert(out, '<div class="calendar-footer-wrapper">')
-- Solar Events
local solar_page_title = toFarsiDigits(td) .. ' ' .. month_names[tm]
local solar_data = get_wiki_page_content(solar_page_title)
if solar_data then
table.insert(out, '<div class="footer-box solar-events">')
table.insert(out, '<div class="footer-header">📅 رویدادهای امروز (' .. solar_data.title .. ')</div>')
table.insert(out, '<div class="footer-content">' .. frame:preprocess(solar_data.text) .. '</div>')
if solar_data.is_long then
table.insert(out, '<div class="footer-more">[[' .. solar_data.title .. '|مشاهده کامل رویداد]]</div>')
end
table.insert(out, '</div>')
end
-- Hijri Events
if h_day and h_day ~= '' then
local hijri_page_title = toFarsiDigits(h_day) .. ' ' .. h_month
local hijri_data = get_wiki_page_content(hijri_page_title)
if hijri_data then
table.insert(out, '<div class="footer-box hijri-events">')
table.insert(out, '<div class="footer-header">🌙 رویدادهای قمری (' .. hijri_data.title .. ')</div>')
table.insert(out, '<div class="footer-content">' .. frame:preprocess(hijri_data.text) .. '</div>')
if hijri_data.is_long then
table.insert(out, '<div class="footer-more">[[' .. hijri_data.title .. '|مشاهده کامل رویداد]]</div>')
end
table.insert(out, '</div>')
end
end
table.insert(out, '</div>')
end
table.insert(out, '</div>')
table.insert(out, frame:extensionTag{ name='templatestyles', args={ src='پودمان:تقویم/styles.css' } })
return table.concat(out)
end
return p