Kaydet (Commit) 48d5e508 authored tarafından Walter Dörwald's avatar Walter Dörwald

Bug #947906: Add classes LocaleTextCalendar and LocaleHTMLCalendar,

that output localized month and weekday names and can cope
with encodings.
üst 1c5a59f8
...@@ -176,6 +176,24 @@ to the system default encoding). ...@@ -176,6 +176,24 @@ to the system default encoding).
\end{methoddesc} \end{methoddesc}
\begin{classdesc}{LocaleTextCalendar}{\optional{firstweekday\optional{, locale}}}
This subclass of \class{TextCalendar} 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.
\versionadded{2.5}
\end{classdesc}
\begin{classdesc}{LocaleHTMLCalendar}{\optional{firstweekday\optional{, locale}}}
This subclass of \class{HTMLCalendar} 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.
\versionadded{2.5}
\end{classdesc}
For simple text calendars this module provides the following functions. For simple text calendars this module provides the following functions.
\begin{funcdesc}{setfirstweekday}{weekday} \begin{funcdesc}{setfirstweekday}{weekday}
......
...@@ -5,7 +5,7 @@ default, these calendars have Monday as the first day of the week, and ...@@ -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 Sunday as the last (the European convention). Use setfirstweekday() to
set the first day of the week (0=Monday, 6=Sunday).""" set the first day of the week (0=Monday, 6=Sunday)."""
import sys, datetime import sys, datetime, locale
__all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday", __all__ = ["IllegalMonthError", "IllegalWeekdayError", "setfirstweekday",
"firstweekday", "isleap", "leapdays", "weekday", "monthrange", "firstweekday", "isleap", "leapdays", "weekday", "monthrange",
...@@ -297,11 +297,13 @@ class TextCalendar(Calendar): ...@@ -297,11 +297,13 @@ class TextCalendar(Calendar):
""" """
return ' '.join(self.formatweekday(i, width) for i in self.iterweekdays()) 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. 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) return s.center(width)
def prmonth(self, theyear, themonth, w=0, l=0): def prmonth(self, theyear, themonth, w=0, l=0):
...@@ -343,9 +345,12 @@ class TextCalendar(Calendar): ...@@ -343,9 +345,12 @@ class TextCalendar(Calendar):
# months in this row # months in this row
months = xrange(m*i+1, min(m*(i+1)+1, 13)) months = xrange(m*i+1, min(m*(i+1)+1, 13))
a('\n'*l) 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('\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) a('\n'*l)
# max number of weeks for this row # max number of weeks for this row
height = max(len(cal) for cal in row) height = max(len(cal) for cal in row)
...@@ -474,7 +479,92 @@ class HTMLCalendar(Calendar): ...@@ -474,7 +479,92 @@ class HTMLCalendar(Calendar):
a(self.formatyear(theyear, width)) a(self.formatyear(theyear, width))
a('</body>\n') a('</body>\n')
a('</html>\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 # Support for old module level interface
...@@ -524,34 +614,60 @@ def timegm(tuple): ...@@ -524,34 +614,60 @@ def timegm(tuple):
def main(args): def main(args):
import optparse import optparse
parser = optparse.OptionParser(usage="usage: %prog [options] [year] [month]") parser = optparse.OptionParser(usage="usage: %prog [options] [year [month]]")
parser.add_option("-w", "--width", parser.add_option(
dest="width", type="int", default=2, "-w", "--width",
help="width of date column (default 2, text only)") dest="width", type="int", default=2,
parser.add_option("-l", "--lines", help="width of date column (default 2, text only)"
dest="lines", type="int", default=1, )
help="number of lines for each week (default 1, text only)") parser.add_option(
parser.add_option("-s", "--spacing", "-l", "--lines",
dest="spacing", type="int", default=6, dest="lines", type="int", default=1,
help="spacing between months (default 6, text only)") help="number of lines for each week (default 1, text only)"
parser.add_option("-m", "--months", )
dest="months", type="int", default=3, parser.add_option(
help="months per row (default 3, text only)") "-s", "--spacing",
parser.add_option("-c", "--css", dest="spacing", type="int", default=6,
dest="css", default="calendar.css", help="spacing between months (default 6, text only)"
help="CSS to use for page (html only)") )
parser.add_option("-e", "--encoding", parser.add_option(
dest="encoding", default=None, "-m", "--months",
help="Encoding to use for CSS output (html only)") dest="months", type="int", default=3,
parser.add_option("-t", "--type", help="months per row (default 3, text only)"
dest="type", default="text", )
choices=("text", "html"), parser.add_option(
help="output type (text or html)") "-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) (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": if options.type == "html":
cal = HTMLCalendar() if options.locale:
cal = LocaleHTMLCalendar(locale=options.locale)
else:
cal = HTMLCalendar()
encoding = options.encoding encoding = options.encoding
if encoding is None: if encoding is None:
encoding = sys.getdefaultencoding() encoding = sys.getdefaultencoding()
...@@ -564,20 +680,26 @@ def main(args): ...@@ -564,20 +680,26 @@ def main(args):
parser.error("incorrect number of arguments") parser.error("incorrect number of arguments")
sys.exit(1) sys.exit(1)
else: else:
cal = TextCalendar() if options.locale:
cal = LocaleTextCalendar(locale=options.locale)
else:
cal = TextCalendar()
optdict = dict(w=options.width, l=options.lines) optdict = dict(w=options.width, l=options.lines)
if len(args) != 3: if len(args) != 3:
optdict["c"] = options.spacing optdict["c"] = options.spacing
optdict["m"] = options.months optdict["m"] = options.months
if len(args) == 1: if len(args) == 1:
print cal.formatyear(datetime.date.today().year, **optdict) result = cal.formatyear(datetime.date.today().year, **optdict)
elif len(args) == 2: elif len(args) == 2:
print cal.formatyear(int(args[1]), **optdict) result = cal.formatyear(int(args[1]), **optdict)
elif len(args) == 3: 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: else:
parser.error("incorrect number of arguments") parser.error("incorrect number of arguments")
sys.exit(1) sys.exit(1)
if options.encoding:
result = result.encode(options.encoding)
print result
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -920,7 +920,9 @@ Library ...@@ -920,7 +920,9 @@ Library
- Bug #947906: An object oriented interface has been added to the calendar - Bug #947906: An object oriented interface has been added to the calendar
module. It's possible to generate HTML calendar now and the module can be module. It's possible to generate HTML calendar now and the module can be
called as a script (e.g. via ``python -mcalendar``). called as a script (e.g. via ``python -mcalendar``). Localized month and
weekday names can be ouput (even if an exotic encoding is used) using
special classes that use unicode.
Build Build
----- -----
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment