Bug #947906: Add classes LocaleTextCalendar and LocaleHTMLCalendar,

that output localized month and weekday names and can cope
with encodings.
This commit is contained in:
Walter Dörwald 2006-04-01 07:57:00 +00:00
parent 1c5a59f80a
commit 48d5e508eb
3 changed files with 177 additions and 35 deletions

View file

@ -5,7 +5,7 @@ default, these calendars have Monday as the first day of the week, and
Sunday as the last (the European convention). Use setfirstweekday() to
set the first day of the week (0=Monday, 6=Sunday)."""
import sys, datetime
import sys, datetime, locale
__all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday",
"firstweekday", "isleap", "leapdays", "weekday", "monthrange",
@ -297,11 +297,13 @@ class TextCalendar(Calendar):
"""
return ' '.join(self.formatweekday(i, width) for i in self.iterweekdays())
def formatmonthname(self, theyear, themonth, width):
def formatmonthname(self, theyear, themonth, width, withyear=True):
"""
Return a formatted month name.
"""
s = "%s %r" % (month_name[themonth], theyear)
s = month_name[themonth]
if withyear:
s = "%s %r" % (s, theyear)
return s.center(width)
def prmonth(self, theyear, themonth, w=0, l=0):
@ -343,9 +345,12 @@ class TextCalendar(Calendar):
# months in this row
months = xrange(m*i+1, min(m*(i+1)+1, 13))
a('\n'*l)
a(formatstring((month_name[k] for k in months), colwidth, c).rstrip())
names = (self.formatmonthname(theyear, k, colwidth, False)
for k in months)
a(formatstring(names, colwidth, c).rstrip())
a('\n'*l)
a(formatstring((header for k in months), colwidth, c).rstrip())
headers = (header for k in months)
a(formatstring(headers, colwidth, c).rstrip())
a('\n'*l)
# max number of weeks for this row
height = max(len(cal) for cal in row)
@ -474,7 +479,92 @@ class HTMLCalendar(Calendar):
a(self.formatyear(theyear, width))
a('</body>\n')
a('</html>\n')
return ''.join(v).encode(encoding)
return ''.join(v).encode(encoding, "xmlcharrefreplace")
class LocaleTextCalendar(TextCalendar):
"""
This class can be passed a locale name in the constructor and will return
month and weekday names in the specified locale. If this locale includes
an encoding all strings containing month and weekday names will be returned
as unicode.
"""
def __init__(self, firstweekday=0, locale=None):
TextCalendar.__init__(self, firstweekday)
if locale is None:
locale = locale.getdefaultlocale()
self.locale = locale
def formatweekday(self, day, width):
oldlocale = locale.setlocale(locale.LC_TIME, self.locale)
try:
encoding = locale.getlocale(locale.LC_TIME)[1]
if width >= 9:
names = day_name
else:
names = day_abbr
name = names[day]
if encoding is not None:
name = name.decode(encoding)
result = name[:width].center(width)
finally:
locale.setlocale(locale.LC_TIME, oldlocale)
return result
def formatmonthname(self, theyear, themonth, width, withyear=True):
oldlocale = locale.setlocale(locale.LC_TIME, self.locale)
try:
encoding = locale.getlocale(locale.LC_TIME)[1]
s = month_name[themonth]
if encoding is not None:
s = s.decode(encoding)
if withyear:
s = "%s %r" % (s, theyear)
result = s.center(width)
finally:
locale.setlocale(locale.LC_TIME, oldlocale)
return result
class LocaleHTMLCalendar(HTMLCalendar):
"""
This class can be passed a locale name in the constructor and will return
month and weekday names in the specified locale. If this locale includes
an encoding all strings containing month and weekday names will be returned
as unicode.
"""
def __init__(self, firstweekday=0, locale=None):
HTMLCalendar.__init__(self, firstweekday)
if locale is None:
locale = locale.getdefaultlocale()
self.locale = locale
def formatweekday(self, day):
oldlocale = locale.setlocale(locale.LC_TIME, self.locale)
try:
encoding = locale.getlocale(locale.LC_TIME)[1]
s = day_abbr[day]
if encoding is not None:
s = s.decode(encoding)
result = '<th class="%s">%s</th>' % (self.cssclasses[day], s)
finally:
locale.setlocale(locale.LC_TIME, oldlocale)
return result
def formatmonthname(self, theyear, themonth, withyear=True):
oldlocale = locale.setlocale(locale.LC_TIME, self.locale)
try:
encoding = locale.getlocale(locale.LC_TIME)[1]
s = month_name[themonth]
if encoding is not None:
s = s.decode(encoding)
if withyear:
s = '%s %s' % (s, theyear)
result = '<tr><th colspan="7" class="month">%s</th></tr>' % s
finally:
locale.setlocale(locale.LC_TIME, oldlocale)
return result
# Support for old module level interface
@ -524,34 +614,60 @@ def timegm(tuple):
def main(args):
import optparse
parser = optparse.OptionParser(usage="usage: %prog [options] [year] [month]")
parser.add_option("-w", "--width",
dest="width", type="int", default=2,
help="width of date column (default 2, text only)")
parser.add_option("-l", "--lines",
dest="lines", type="int", default=1,
help="number of lines for each week (default 1, text only)")
parser.add_option("-s", "--spacing",
dest="spacing", type="int", default=6,
help="spacing between months (default 6, text only)")
parser.add_option("-m", "--months",
dest="months", type="int", default=3,
help="months per row (default 3, text only)")
parser.add_option("-c", "--css",
dest="css", default="calendar.css",
help="CSS to use for page (html only)")
parser.add_option("-e", "--encoding",
dest="encoding", default=None,
help="Encoding to use for CSS output (html only)")
parser.add_option("-t", "--type",
dest="type", default="text",
choices=("text", "html"),
help="output type (text or html)")
parser = optparse.OptionParser(usage="usage: %prog [options] [year [month]]")
parser.add_option(
"-w", "--width",
dest="width", type="int", default=2,
help="width of date column (default 2, text only)"
)
parser.add_option(
"-l", "--lines",
dest="lines", type="int", default=1,
help="number of lines for each week (default 1, text only)"
)
parser.add_option(
"-s", "--spacing",
dest="spacing", type="int", default=6,
help="spacing between months (default 6, text only)"
)
parser.add_option(
"-m", "--months",
dest="months", type="int", default=3,
help="months per row (default 3, text only)"
)
parser.add_option(
"-c", "--css",
dest="css", default="calendar.css",
help="CSS to use for page (html only)"
)
parser.add_option(
"-L", "--locale",
dest="locale", default=None,
help="locale to be used from month and weekday names"
)
parser.add_option(
"-e", "--encoding",
dest="encoding", default=None,
help="Encoding to use for output"
)
parser.add_option(
"-t", "--type",
dest="type", default="text",
choices=("text", "html"),
help="output type (text or html)"
)
(options, args) = parser.parse_args(args)
if options.locale and not options.encoding:
parser.error("if --locale is specified --encoding is required")
sys.exit(1)
if options.type == "html":
cal = HTMLCalendar()
if options.locale:
cal = LocaleHTMLCalendar(locale=options.locale)
else:
cal = HTMLCalendar()
encoding = options.encoding
if encoding is None:
encoding = sys.getdefaultencoding()
@ -564,20 +680,26 @@ def main(args):
parser.error("incorrect number of arguments")
sys.exit(1)
else:
cal = TextCalendar()
if options.locale:
cal = LocaleTextCalendar(locale=options.locale)
else:
cal = TextCalendar()
optdict = dict(w=options.width, l=options.lines)
if len(args) != 3:
optdict["c"] = options.spacing
optdict["m"] = options.months
if len(args) == 1:
print cal.formatyear(datetime.date.today().year, **optdict)
result = cal.formatyear(datetime.date.today().year, **optdict)
elif len(args) == 2:
print cal.formatyear(int(args[1]), **optdict)
result = cal.formatyear(int(args[1]), **optdict)
elif len(args) == 3:
print cal.formatmonth(int(args[1]), int(args[2]), **optdict)
result = cal.formatmonth(int(args[1]), int(args[2]), **optdict)
else:
parser.error("incorrect number of arguments")
sys.exit(1)
if options.encoding:
result = result.encode(options.encoding)
print result
if __name__ == "__main__":