5
5
Sunday as the last (the European convention). Use setfirstweekday() to
6
6
set the first day of the week (0=Monday, 6=Sunday)."""
7
7
8
- import sys , datetime
8
+ import sys , datetime , locale
9
9
10
10
__all__ = ["IllegalMonthError" , "IllegalWeekdayError" , "setfirstweekday" ,
11
11
"firstweekday" , "isleap" , "leapdays" , "weekday" , "monthrange" ,
@@ -297,11 +297,13 @@ def formatweekheader(self, width):
297
297
"""
298
298
return ' ' .join (self .formatweekday (i , width ) for i in self .iterweekdays ())
299
299
300
- def formatmonthname (self , theyear , themonth , width ):
300
+ def formatmonthname (self , theyear , themonth , width , withyear = True ):
301
301
"""
302
302
Return a formatted month name.
303
303
"""
304
- s = "%s %r" % (month_name [themonth ], theyear )
304
+ s = month_name [themonth ]
305
+ if withyear :
306
+ s = "%s %r" % (s , theyear )
305
307
return s .center (width )
306
308
307
309
def prmonth (self , theyear , themonth , w = 0 , l = 0 ):
@@ -343,9 +345,12 @@ def formatyear(self, theyear, w=2, l=1, c=6, m=3):
343
345
# months in this row
344
346
months = xrange (m * i + 1 , min (m * (i + 1 )+ 1 , 13 ))
345
347
a ('\n ' * l )
346
- a (formatstring ((month_name [k ] for k in months ), colwidth , c ).rstrip ())
348
+ names = (self .formatmonthname (theyear , k , colwidth , False )
349
+ for k in months )
350
+ a (formatstring (names , colwidth , c ).rstrip ())
347
351
a ('\n ' * l )
348
- a (formatstring ((header for k in months ), colwidth , c ).rstrip ())
352
+ headers = (header for k in months )
353
+ a (formatstring (headers , colwidth , c ).rstrip ())
349
354
a ('\n ' * l )
350
355
# max number of weeks for this row
351
356
height = max (len (cal ) for cal in row )
@@ -474,7 +479,92 @@ def formatyearpage(self, theyear, width=3, css='calendar.css', encoding=None):
474
479
a (self .formatyear (theyear , width ))
475
480
a ('</body>\n ' )
476
481
a ('</html>\n ' )
477
- return '' .join (v ).encode (encoding )
482
+ return '' .join (v ).encode (encoding , "xmlcharrefreplace" )
483
+
484
+
485
+ class LocaleTextCalendar (TextCalendar ):
486
+ """
487
+ This class can be passed a locale name in the constructor and will return
488
+ month and weekday names in the specified locale. If this locale includes
489
+ an encoding all strings containing month and weekday names will be returned
490
+ as unicode.
491
+ """
492
+
493
+ def __init__ (self , firstweekday = 0 , locale = None ):
494
+ TextCalendar .__init__ (self , firstweekday )
495
+ if locale is None :
496
+ locale = locale .getdefaultlocale ()
497
+ self .locale = locale
498
+
499
+ def formatweekday (self , day , width ):
500
+ oldlocale = locale .setlocale (locale .LC_TIME , self .locale )
501
+ try :
502
+ encoding = locale .getlocale (locale .LC_TIME )[1 ]
503
+ if width >= 9 :
504
+ names = day_name
505
+ else :
506
+ names = day_abbr
507
+ name = names [day ]
508
+ if encoding is not None :
509
+ name = name .decode (encoding )
510
+ result = name [:width ].center (width )
511
+ finally :
512
+ locale .setlocale (locale .LC_TIME , oldlocale )
513
+ return result
514
+
515
+ def formatmonthname (self , theyear , themonth , width , withyear = True ):
516
+ oldlocale = locale .setlocale (locale .LC_TIME , self .locale )
517
+ try :
518
+ encoding = locale .getlocale (locale .LC_TIME )[1 ]
519
+ s = month_name [themonth ]
520
+ if encoding is not None :
521
+ s = s .decode (encoding )
522
+ if withyear :
523
+ s = "%s %r" % (s , theyear )
524
+ result = s .center (width )
525
+ finally :
526
+ locale .setlocale (locale .LC_TIME , oldlocale )
527
+ return result
528
+
529
+
530
+ class LocaleHTMLCalendar (HTMLCalendar ):
531
+ """
532
+ This class can be passed a locale name in the constructor and will return
533
+ month and weekday names in the specified locale. If this locale includes
534
+ an encoding all strings containing month and weekday names will be returned
535
+ as unicode.
536
+ """
537
+ def __init__ (self , firstweekday = 0 , locale = None ):
538
+ HTMLCalendar .__init__ (self , firstweekday )
539
+ if locale is None :
540
+ locale = locale .getdefaultlocale ()
541
+ self .locale = locale
542
+
543
+ def formatweekday (self , day ):
544
+ oldlocale = locale .setlocale (locale .LC_TIME , self .locale )
545
+ try :
546
+ encoding = locale .getlocale (locale .LC_TIME )[1 ]
547
+ s = day_abbr [day ]
548
+ if encoding is not None :
549
+ s = s .decode (encoding )
550
+ result = '<th class="%s">%s</th>' % (self .cssclasses [day ], s )
551
+ finally :
552
+ locale .setlocale (locale .LC_TIME , oldlocale )
553
+ return result
554
+
555
+ def formatmonthname (self , theyear , themonth , withyear = True ):
556
+ oldlocale = locale .setlocale (locale .LC_TIME , self .locale )
557
+ try :
558
+ encoding = locale .getlocale (locale .LC_TIME )[1 ]
559
+ s = month_name [themonth ]
560
+ if encoding is not None :
561
+ s = s .decode (encoding )
562
+ if withyear :
563
+ s = '%s %s' % (s , theyear )
564
+ result = '<tr><th colspan="7" class="month">%s</th></tr>' % s
565
+ finally :
566
+ locale .setlocale (locale .LC_TIME , oldlocale )
567
+ return result
478
568
479
569
480
570
# Support for old module level interface
@@ -524,34 +614,60 @@ def timegm(tuple):
524
614
525
615
def main (args ):
526
616
import optparse
527
- parser = optparse .OptionParser (usage = "usage: %prog [options] [year] [month]" )
528
- parser .add_option ("-w" , "--width" ,
529
- dest = "width" , type = "int" , default = 2 ,
530
- help = "width of date column (default 2, text only)" )
531
- parser .add_option ("-l" , "--lines" ,
532
- dest = "lines" , type = "int" , default = 1 ,
533
- help = "number of lines for each week (default 1, text only)" )
534
- parser .add_option ("-s" , "--spacing" ,
535
- dest = "spacing" , type = "int" , default = 6 ,
536
- help = "spacing between months (default 6, text only)" )
537
- parser .add_option ("-m" , "--months" ,
538
- dest = "months" , type = "int" , default = 3 ,
539
- help = "months per row (default 3, text only)" )
540
- parser .add_option ("-c" , "--css" ,
541
- dest = "css" , default = "calendar.css" ,
542
- help = "CSS to use for page (html only)" )
543
- parser .add_option ("-e" , "--encoding" ,
544
- dest = "encoding" , default = None ,
545
- help = "Encoding to use for CSS output (html only)" )
546
- parser .add_option ("-t" , "--type" ,
547
- dest = "type" , default = "text" ,
548
- choices = ("text" , "html" ),
549
- help = "output type (text or html)" )
617
+ parser = optparse .OptionParser (usage = "usage: %prog [options] [year [month]]" )
618
+ parser .add_option (
619
+ "-w" , "--width" ,
620
+ dest = "width" , type = "int" , default = 2 ,
621
+ help = "width of date column (default 2, text only)"
622
+ )
623
+ parser .add_option (
624
+ "-l" , "--lines" ,
625
+ dest = "lines" , type = "int" , default = 1 ,
626
+ help = "number of lines for each week (default 1, text only)"
627
+ )
628
+ parser .add_option (
629
+ "-s" , "--spacing" ,
630
+ dest = "spacing" , type = "int" , default = 6 ,
631
+ help = "spacing between months (default 6, text only)"
632
+ )
633
+ parser .add_option (
634
+ "-m" , "--months" ,
635
+ dest = "months" , type = "int" , default = 3 ,
636
+ help = "months per row (default 3, text only)"
637
+ )
638
+ parser .add_option (
639
+ "-c" , "--css" ,
640
+ dest = "css" , default = "calendar.css" ,
641
+ help = "CSS to use for page (html only)"
642
+ )
643
+ parser .add_option (
644
+ "-L" , "--locale" ,
645
+ dest = "locale" , default = None ,
646
+ help = "locale to be used from month and weekday names"
647
+ )
648
+ parser .add_option (
649
+ "-e" , "--encoding" ,
650
+ dest = "encoding" , default = None ,
651
+ help = "Encoding to use for output"
652
+ )
653
+ parser .add_option (
654
+ "-t" , "--type" ,
655
+ dest = "type" , default = "text" ,
656
+ choices = ("text" , "html" ),
657
+ help = "output type (text or html)"
658
+ )
550
659
551
660
(options , args ) = parser .parse_args (args )
552
661
662
+ if options .locale and not options .encoding :
663
+ parser .error ("if --locale is specified --encoding is required" )
664
+ sys .exit (1 )
665
+
553
666
if options .type == "html" :
554
- cal = HTMLCalendar ()
667
+ if options .locale :
668
+ cal = LocaleHTMLCalendar (locale = options .locale )
669
+ else :
670
+ cal = HTMLCalendar ()
555
671
encoding = options .encoding
556
672
if encoding is None :
557
673
encoding = sys .getdefaultencoding ()
@@ -564,20 +680,26 @@ def main(args):
564
680
parser .error ("incorrect number of arguments" )
565
681
sys .exit (1 )
566
682
else :
567
- cal = TextCalendar ()
683
+ if options .locale :
684
+ cal = LocaleTextCalendar (locale = options .locale )
685
+ else :
686
+ cal = TextCalendar ()
568
687
optdict = dict (w = options .width , l = options .lines )
569
688
if len (args ) != 3 :
570
689
optdict ["c" ] = options .spacing
571
690
optdict ["m" ] = options .months
572
691
if len (args ) == 1 :
573
- print cal .formatyear (datetime .date .today ().year , ** optdict )
692
+ result = cal .formatyear (datetime .date .today ().year , ** optdict )
574
693
elif len (args ) == 2 :
575
- print cal .formatyear (int (args [1 ]), ** optdict )
694
+ result = cal .formatyear (int (args [1 ]), ** optdict )
576
695
elif len (args ) == 3 :
577
- print cal .formatmonth (int (args [1 ]), int (args [2 ]), ** optdict )
696
+ result = cal .formatmonth (int (args [1 ]), int (args [2 ]), ** optdict )
578
697
else :
579
698
parser .error ("incorrect number of arguments" )
580
699
sys .exit (1 )
700
+ if options .encoding :
701
+ result = result .encode (options .encoding )
702
+ print result
581
703
582
704
583
705
if __name__ == "__main__" :
0 commit comments