1.1 --- a/imiptools/client.py Wed Nov 04 23:35:16 2015 +0100
1.2 +++ b/imiptools/client.py Thu Nov 05 00:58:02 2015 +0100
1.3 @@ -26,6 +26,7 @@
1.4 uri_dict, uri_item, uri_items, uri_parts, uri_values
1.5 from imiptools.dates import check_permitted_values, format_datetime, get_default_timezone, \
1.6 get_duration, get_timestamp
1.7 +from imiptools.i18n import get_translator
1.8 from imiptools.period import can_schedule, remove_event_periods, \
1.9 remove_additional_periods, remove_affected_period, \
1.10 update_freebusy
1.11 @@ -59,6 +60,11 @@
1.12 self.preferences_dir = preferences_dir
1.13 self.preferences = None
1.14
1.15 + # Localise the messenger.
1.16 +
1.17 + if self.messenger:
1.18 + self.messenger.gettext = self.get_translator()
1.19 +
1.20 # Store-related methods.
1.21
1.22 def acquire_lock(self):
1.23 @@ -74,6 +80,12 @@
1.24 self.preferences = Preferences(self.user, self.preferences_dir)
1.25 return self.preferences
1.26
1.27 + def get_locale(self):
1.28 + return self.get_preferences().get("LANG", "en", True)
1.29 +
1.30 + def get_translator(self):
1.31 + return get_translator([self.get_locale()])
1.32 +
1.33 def get_user_attributes(self):
1.34 prefs = self.get_preferences()
1.35 return prefs and prefs.get_all(["CN"]) or {}
1.36 @@ -203,7 +215,7 @@
1.37 """
1.38
1.39 obj = obj or self.obj
1.40 - calendar_uri = get_uri(self.messenger.sender)
1.41 + calendar_uri = self.messenger and get_uri(self.messenger.sender)
1.42 for attendee, attendee_attr in uri_items(obj.get_items("ATTENDEE")):
1.43 if attendee != self.user:
1.44 if attendee_attr.get("SENT-BY") == calendar_uri:
1.45 @@ -224,7 +236,7 @@
1.46
1.47 # Search for the sender of the message or the calendar system address.
1.48
1.49 - senders = self.senders or [self.messenger.sender]
1.50 + senders = self.senders or self.messenger and [self.messenger.sender] or []
1.51
1.52 for attendee, attendee_attr in uri_items(self.obj.get_items("ATTENDEE")):
1.53 if get_address(attendee) in senders or \
1.54 @@ -618,6 +630,9 @@
1.55 recipient since the generic calendar user will be the actual sender.
1.56 """
1.57
1.58 + if not self.messenger:
1.59 + return
1.60 +
1.61 if not bcc_sender:
1.62 message = self.messenger.make_outgoing_message(parts, recipients)
1.63 self.messenger.sendmail(recipients, message.as_string())
1.64 @@ -629,6 +644,9 @@
1.65
1.66 "Send a message composed of the given 'parts' to the given user."
1.67
1.68 + if not self.messenger:
1.69 + return
1.70 +
1.71 sender = get_address(self.user)
1.72 message = self.messenger.make_outgoing_message(parts, [sender])
1.73 self.messenger.sendmail([sender], message.as_string())
2.1 --- a/imiptools/config.py Wed Nov 04 23:35:16 2015 +0100
2.2 +++ b/imiptools/config.py Thu Nov 05 00:58:02 2015 +0100
2.3 @@ -36,6 +36,11 @@
2.4
2.5 DEFAULT_DIR_PERMISSIONS = 02770
2.6
2.7 +# Internationalisation and translations support.
2.8 +
2.9 +LOCALE_DIR = "/usr/share/locale"
2.10 +TRANS_DOMAIN = "imip-agent"
2.11 +
2.12
2.13
2.14 # The availability of a management interface for calendar information.
3.1 --- a/imiptools/handlers/__init__.py Wed Nov 04 23:35:16 2015 +0100
3.2 +++ b/imiptools/handlers/__init__.py Thu Nov 05 00:58:02 2015 +0100
3.3 @@ -69,11 +69,13 @@
3.4
3.5 "Wrap any valid message for passing to the recipient."
3.6
3.7 + _ = self.get_translator()
3.8 +
3.9 texts = []
3.10 texts.append(text)
3.11 if link and self.have_manager():
3.12 - texts.append("If your mail program cannot handle this "
3.13 - "message, you may view the details here:\n\n%s" %
3.14 + texts.append(_("If your mail program cannot handle this "
3.15 + "message, you may view the details here:\n\n%s") %
3.16 get_object_url(self.uid, self.recurrenceid))
3.17
3.18 return self.add_result(None, None, MIMEText("\n".join(texts)))
4.1 --- a/imiptools/handlers/person.py Wed Nov 04 23:35:16 2015 +0100
4.2 +++ b/imiptools/handlers/person.py Thu Nov 05 00:58:02 2015 +0100
4.3 @@ -242,59 +242,75 @@
4.4
4.5 "Queue a suggested additional recurrence for any active event."
4.6
4.7 + _ = self.get_translator()
4.8 +
4.9 if self.allow_add() and self._process(self._add, queue=True):
4.10 - return self.wrap("An addition to an event has been received.")
4.11 + return self.wrap(_("An addition to an event has been received."))
4.12
4.13 def cancel(self):
4.14
4.15 "Queue a cancellation of any active event."
4.16
4.17 + _ = self.get_translator()
4.18 +
4.19 if self._cancel():
4.20 - return self.wrap("An event cancellation has been received.", link=False)
4.21 + return self.wrap(_("An event cancellation has been received."), link=False)
4.22
4.23 def counter(self):
4.24
4.25 "Record a counter-proposal to a proposed event."
4.26
4.27 + _ = self.get_translator()
4.28 +
4.29 if self._process(self._counter, from_organiser=False):
4.30 - return self.wrap("A counter proposal to an event invitation has been received.", link=True)
4.31 + return self.wrap(_("A counter proposal to an event invitation has been received."), link=True)
4.32
4.33 def declinecounter(self):
4.34
4.35 "Record a rejection of a counter-proposal."
4.36
4.37 + _ = self.get_translator()
4.38 +
4.39 if self._process(self._declinecounter):
4.40 - return self.wrap("Your counter proposal to an event invitation has been declined.", link=True)
4.41 + return self.wrap(_("Your counter proposal to an event invitation has been declined."), link=True)
4.42
4.43 def publish(self):
4.44
4.45 "Register details of any relevant event."
4.46
4.47 + _ = self.get_translator()
4.48 +
4.49 if self._publish():
4.50 - return self.wrap("Details of an event have been received.")
4.51 + return self.wrap(_("Details of an event have been received."))
4.52
4.53 def refresh(self):
4.54
4.55 "Requests to refresh events are handled either here or by the client."
4.56
4.57 + _ = self.get_translator()
4.58 +
4.59 if self.is_refreshing():
4.60 return self._process(self._refresh, from_organiser=False)
4.61 else:
4.62 - return self.wrap("A request for updated event details has been received.")
4.63 + return self.wrap(_("A request for updated event details has been received."))
4.64
4.65 def reply(self):
4.66
4.67 "Record replies and notify the recipient."
4.68
4.69 + _ = self.get_translator()
4.70 +
4.71 if self._process(self._schedule_for_organiser, from_organiser=False):
4.72 - return self.wrap("A reply to an event invitation has been received.")
4.73 + return self.wrap(_("A reply to an event invitation has been received."))
4.74
4.75 def request(self):
4.76
4.77 "Hold requests and notify the recipient."
4.78
4.79 + _ = self.get_translator()
4.80 +
4.81 if self._process(self._schedule_for_attendee, queue=True):
4.82 - return self.wrap("An event invitation has been received.")
4.83 + return self.wrap(_("An event invitation has been received."))
4.84
4.85 class Freebusy(CommonFreebusy, Handler):
4.86
4.87 @@ -304,23 +320,27 @@
4.88
4.89 "Register free/busy information."
4.90
4.91 + _ = self.get_translator()
4.92 +
4.93 self._record_freebusy(from_organiser=True)
4.94
4.95 # Produce a message if configured to do so.
4.96
4.97 if self.is_notifying():
4.98 - return self.wrap("A free/busy update has been received.", link=False)
4.99 + return self.wrap(_("A free/busy update has been received."), link=False)
4.100
4.101 def reply(self):
4.102
4.103 "Record replies and notify the recipient."
4.104
4.105 + _ = self.get_translator()
4.106 +
4.107 self._record_freebusy(from_organiser=False)
4.108
4.109 # Produce a message if configured to do so.
4.110
4.111 if self.is_notifying():
4.112 - return self.wrap("A reply to a free/busy request has been received.", link=False)
4.113 + return self.wrap(_("A reply to a free/busy request has been received."), link=False)
4.114
4.115 def request(self):
4.116
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/imiptools/i18n.py Thu Nov 05 00:58:02 2015 +0100
5.3 @@ -0,0 +1,37 @@
5.4 +#!/usr/bin/env python
5.5 +
5.6 +"""
5.7 +Internationalisation support.
5.8 +
5.9 +Copyright (C) 2015 Paul Boddie <paul@boddie.org.uk>
5.10 +
5.11 +This program is free software; you can redistribute it and/or modify it under
5.12 +the terms of the GNU General Public License as published by the Free Software
5.13 +Foundation; either version 3 of the License, or (at your option) any later
5.14 +version.
5.15 +
5.16 +This program is distributed in the hope that it will be useful, but WITHOUT
5.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
5.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
5.19 +details.
5.20 +
5.21 +You should have received a copy of the GNU General Public License along with
5.22 +this program. If not, see <http://www.gnu.org/licenses/>.
5.23 +"""
5.24 +
5.25 +from imiptools.config import LOCALE_DIR, TRANS_DOMAIN
5.26 +from os.path import abspath, exists, join, split
5.27 +import gettext
5.28 +
5.29 +def get_locale_dir():
5.30 + locale_dir = abspath(join(split(__file__)[0], "..", "locale"))
5.31 + if exists(locale_dir):
5.32 + return locale_dir
5.33 + else:
5.34 + return LOCALE_DIR
5.35 +
5.36 +def get_translator(languages):
5.37 + return gettext.translation(TRANS_DOMAIN, get_locale_dir(), languages,
5.38 + fallback=True).ugettext
5.39 +
5.40 +# vim: tabstop=4 expandtab shiftwidth=4
6.1 --- a/imiptools/mail.py Wed Nov 04 23:35:16 2015 +0100
6.2 +++ b/imiptools/mail.py Thu Nov 05 00:58:02 2015 +0100
6.3 @@ -25,22 +25,22 @@
6.4 from email.mime.text import MIMEText
6.5 from smtplib import LMTP, SMTP
6.6
6.7 -MESSAGE_SUBJECT = "Calendar system message"
6.8 +# Fake gettext function for strings to be translated later.
6.9 +
6.10 +_ = lambda s: s
6.11
6.12 -MESSAGE_TEXT = """\
6.13 -This is a message from the calendar system.
6.14 -"""
6.15 +MESSAGE_SUBJECT = _("Calendar system message")
6.16
6.17 -PREAMBLE_TEXT = """\
6.18 +PREAMBLE_TEXT = _("""\
6.19 This message contains several different parts, one of which will contain
6.20 calendar information that will only be understood by a suitable program.
6.21 -"""
6.22 +""")
6.23
6.24 class Messenger:
6.25
6.26 "Sending of outgoing messages."
6.27
6.28 - def __init__(self, lmtp_socket=None, local_smtp=False, sender=None, subject=None, body_text=None, preamble_text=None):
6.29 + def __init__(self, lmtp_socket=None, local_smtp=False, sender=None, subject=None, preamble_text=None):
6.30
6.31 """
6.32 Deliver to a local mail system using LMTP if 'lmtp_socket' is provided
6.33 @@ -50,9 +50,13 @@
6.34 self.lmtp_socket = lmtp_socket
6.35 self.local_smtp = local_smtp
6.36 self.sender = sender or MESSAGE_SENDER
6.37 - self.subject = subject or MESSAGE_SUBJECT
6.38 - self.body_text = body_text or MESSAGE_TEXT
6.39 - self.preamble_text = preamble_text or PREAMBLE_TEXT
6.40 + self.subject = subject
6.41 + self.preamble_text = preamble_text
6.42 +
6.43 + # The translation method is set by the client once locale information is
6.44 + # known.
6.45 +
6.46 + self.gettext = None
6.47
6.48 def local_delivery(self):
6.49
6.50 @@ -115,7 +119,8 @@
6.51 message["To"] = recipient
6.52 if outgoing_bcc:
6.53 message["Bcc"] = "%s+%s" % (OUTGOING_PREFIX, outgoing_bcc)
6.54 - message["Subject"] = self.subject
6.55 + message["Subject"] = self.subject or \
6.56 + self.gettext and self.gettext(MESSAGE_SUBJECT) or MESSAGE_SUBJECT
6.57
6.58 return message
6.59
6.60 @@ -153,7 +158,8 @@
6.61 "Return a container for the given 'parts'."
6.62
6.63 message = MIMEMultipart("mixed", _subparts=parts)
6.64 - message.preamble = self.preamble_text
6.65 + message.preamble = self.preamble_text or \
6.66 + self.gettext and self.gettext(PREAMBLE_TEXT) or PREAMBLE_TEXT
6.67 return message
6.68
6.69 def _copy_headers(self, message, msg):
7.1 --- a/imiptools/profile.py Wed Nov 04 23:35:16 2015 +0100
7.2 +++ b/imiptools/profile.py Thu Nov 05 00:58:02 2015 +0100
7.3 @@ -27,6 +27,10 @@
7.4 import codecs
7.5 import pytz
7.6
7.7 +# Fake gettext method for strings to be translated later.
7.8 +
7.9 +_ = lambda s: s
7.10 +
7.11 def identity_dict(l):
7.12 return dict([(i, i) for i in l])
7.13
7.14 @@ -56,45 +60,45 @@
7.15 known_key_choices = {
7.16 "TZID" : identity_dict(pytz.all_timezones),
7.17 "add_method_response" : {
7.18 - "add" : "Add events",
7.19 - "ignore" : "Ignore requests",
7.20 - "refresh" : "Ask for refreshed event details"
7.21 + "add" : _("Add events"),
7.22 + "ignore" : _("Ignore requests"),
7.23 + "refresh" : _("Ask for refreshed event details"),
7.24 },
7.25 "event_refreshing" : {
7.26 - "never" : "Do not respond",
7.27 - "always" : "Always respond"
7.28 + "never" : _("Do not respond"),
7.29 + "always" : _("Always respond"),
7.30 },
7.31 "freebusy_bundling" : {
7.32 - "never" : "Never",
7.33 - "always" : "Always"
7.34 + "never" : _("Never"),
7.35 + "always" : _("Always"),
7.36 },
7.37 "freebusy_messages" : {
7.38 - "none" : "Do not notify",
7.39 - "notify" : "Notify"
7.40 + "none" : _("Do not notify"),
7.41 + "notify" : _("Notify"),
7.42 },
7.43 "freebusy_publishing" : {
7.44 - "publish" : "Publish",
7.45 - "no" : "Do not publish"
7.46 + "publish" : _("Publish"),
7.47 + "no" : _("Do not publish"),
7.48 },
7.49 "freebusy_sharing" : {
7.50 - "share" : "Share",
7.51 - "no" : "Do not share"
7.52 + "share" : _("Share"),
7.53 + "no" : _("Do not share"),
7.54 },
7.55 "incoming" : {
7.56 - "message-only" : "Original message only",
7.57 - "message-then-summary" : "Original message followed by a separate summary message",
7.58 - "summary-then-message" : "Summary message followed by the original message",
7.59 - "summary-only" : "Summary message only",
7.60 - "summary-wraps-message" : "Summary message wrapping the original message"
7.61 + "message-only" : _("Original message only"),
7.62 + "message-then-summary" : _("Original message followed by a separate summary message"),
7.63 + "summary-then-message" : _("Summary message followed by the original message"),
7.64 + "summary-only" : _("Summary message only"),
7.65 + "summary-wraps-message" : _("Summary message wrapping the original message"),
7.66 },
7.67 "organiser_replacement" : {
7.68 - "any" : "Anyone",
7.69 - "attendee" : "Existing attendees only",
7.70 - "never" : "Never allow organiser replacement"
7.71 + "any" : _("Anyone"),
7.72 + "attendee" : _("Existing attendees only"),
7.73 + "never" : _("Never allow organiser replacement"),
7.74 },
7.75 "participating" : {
7.76 - "participate" : "Participate",
7.77 - "no" : "Do not participate"
7.78 + "participate" : _("Participate"),
7.79 + "no" : _("Do not participate"),
7.80 }
7.81 }
7.82
8.1 --- a/imipweb/calendar.py Wed Nov 04 23:35:16 2015 +0100
8.2 +++ b/imipweb/calendar.py Thu Nov 05 00:58:02 2015 +0100
8.3 @@ -44,6 +44,8 @@
8.4 the event page for further activity.
8.5 """
8.6
8.7 + _ = self.get_translator()
8.8 +
8.9 # Handle a submitted form.
8.10
8.11 args = self.env.get_args()
8.12 @@ -128,7 +130,7 @@
8.13 user_attr = self.get_user_attributes()
8.14
8.15 rwrite(("UID", {}, uid))
8.16 - rwrite(("SUMMARY", {}, summary or ("New event at %s" % utcnow)))
8.17 + rwrite(("SUMMARY", {}, summary or (_("New event at %s") % utcnow)))
8.18 rwrite(("DTSTAMP", {}, utcnow))
8.19 rwrite(("DTSTART", start_attr, start_value))
8.20 rwrite(("DTEND", end_attr, end_value))
8.21 @@ -212,6 +214,8 @@
8.22
8.23 "Show requests for the current user."
8.24
8.25 + _ = self.get_translator()
8.26 +
8.27 page = self.page
8.28 view_period = self.get_view_period()
8.29 duration = view_period and view_period.get_duration() or timedelta(1)
8.30 @@ -246,7 +250,7 @@
8.31 page.ul.close()
8.32
8.33 else:
8.34 - page.p("There are no pending requests.")
8.35 + page.p(_("There are no pending requests."))
8.36
8.37 page.div.close()
8.38
8.39 @@ -254,6 +258,8 @@
8.40
8.41 "Show participants for scheduling purposes."
8.42
8.43 + _ = self.get_translator()
8.44 +
8.45 page = self.page
8.46
8.47 # Show any specified participants together with controls to remove and
8.48 @@ -261,17 +267,17 @@
8.49
8.50 page.div(id="participants")
8.51
8.52 - page.p("Participants for scheduling:")
8.53 + page.p(_("Participants for scheduling:"))
8.54
8.55 for i, participant in enumerate(participants):
8.56 page.p()
8.57 page.input(name="participants", type="text", value=participant)
8.58 - page.input(name="remove-participant-%d" % i, type="submit", value="Remove")
8.59 + page.input(name="remove-participant-%d" % i, type="submit", value=_("Remove"))
8.60 page.p.close()
8.61
8.62 page.p()
8.63 page.input(name="participants", type="text")
8.64 - page.input(name="add-participant", type="submit", value="Add")
8.65 + page.input(name="add-participant", type="submit", value=_("Add"))
8.66 page.p.close()
8.67
8.68 page.div.close()
8.69 @@ -286,6 +292,8 @@
8.70 tables.
8.71 """
8.72
8.73 + _ = self.get_translator()
8.74 +
8.75 page = self.page
8.76 args = self.env.get_args()
8.77
8.78 @@ -293,12 +301,12 @@
8.79 self.control("hidebusy", "checkbox", "hide", ("hide" in args.get("hidebusy", [])), id="hidebusy", accesskey="B")
8.80
8.81 page.p(id_="calendar-controls", class_="controls")
8.82 - page.span("Select days or periods for a new event.")
8.83 - page.label("Hide busy time periods", for_="hidebusy", class_="hidebusy enable")
8.84 - page.label("Show busy time periods", for_="hidebusy", class_="hidebusy disable")
8.85 - page.label("Show empty days", for_="showdays", class_="showdays disable")
8.86 - page.label("Hide empty days", for_="showdays", class_="showdays enable")
8.87 - page.input(name="reset", type="submit", value="Clear selections", id="reset")
8.88 + page.span(_("Select days or periods for a new event."))
8.89 + page.label(_("Hide busy time periods"), for_="hidebusy", class_="hidebusy enable")
8.90 + page.label(_("Show busy time periods"), for_="hidebusy", class_="hidebusy disable")
8.91 + page.label(_("Show empty days"), for_="showdays", class_="showdays disable")
8.92 + page.label(_("Hide empty days"), for_="showdays", class_="showdays enable")
8.93 + page.input(name="reset", type="submit", value=_("Clear selections"), id="reset")
8.94 page.p.close()
8.95
8.96 def show_time_navigation(self, freebusy, view_period):
8.97 @@ -308,6 +316,8 @@
8.98 'freebusy' and for the period defined by 'view_period'.
8.99 """
8.100
8.101 + _ = self.get_translator()
8.102 +
8.103 page = self.page
8.104 view_start = view_period.get_start()
8.105 view_end = view_period.get_end()
8.106 @@ -326,13 +336,13 @@
8.107
8.108 if last_preceding:
8.109 preceding_start = last_preceding - duration
8.110 - page.label("Show earlier events", for_="earlier-events", class_="earlier-events")
8.111 + page.label(_("Show earlier events"), for_="earlier-events", class_="earlier-events")
8.112 page.input(name="earlier-events", id_="earlier-events", type="submit")
8.113 page.input(name="earlier-events-start", type="hidden", value=format_datetime(preceding_start))
8.114 page.input(name="earlier-events-end", type="hidden", value=format_datetime(last_preceding))
8.115
8.116 earlier_start = view_start - duration
8.117 - page.label("Show earlier", for_="earlier", class_="earlier")
8.118 + page.label(_("Show earlier"), for_="earlier", class_="earlier")
8.119 page.input(name="earlier", id_="earlier", type="submit")
8.120 page.input(name="earlier-start", type="hidden", value=format_datetime(earlier_start))
8.121 page.input(name="earlier-end", type="hidden", value=format_datetime(view_start))
8.122 @@ -341,14 +351,14 @@
8.123 page.input(name="end", type="hidden", value=format_datetime(view_end))
8.124
8.125 later_end = view_end + duration
8.126 - page.label("Show later", for_="later", class_="later")
8.127 + page.label(_("Show later"), for_="later", class_="later")
8.128 page.input(name="later", id_="later", type="submit")
8.129 page.input(name="later-start", type="hidden", value=format_datetime(view_end))
8.130 page.input(name="later-end", type="hidden", value=format_datetime(later_end))
8.131
8.132 if first_following:
8.133 following_end = first_following + duration
8.134 - page.label("Show later events", for_="later-events", class_="later-events")
8.135 + page.label(_("Show later events"), for_="later-events", class_="later-events")
8.136 page.input(name="later-events", id_="later-events", type="submit")
8.137 page.input(name="later-events-start", type="hidden", value=format_datetime(first_following))
8.138 page.input(name="later-events-end", type="hidden", value=format_datetime(following_end))
8.139 @@ -414,6 +424,8 @@
8.140
8.141 "Show a description of the 'view_period'."
8.142
8.143 + _ = self.get_translator()
8.144 +
8.145 page = self.page
8.146
8.147 view_start = view_period.get_start()
8.148 @@ -425,11 +437,13 @@
8.149 page.p(class_="view-period")
8.150
8.151 if view_start and view_end:
8.152 - page.add("Showing events from %s until %s" % (self.format_date(view_start, "full"), self.format_date(view_end, "full")))
8.153 + page.add(_("Showing events from %(start)s until %(end)s") % {
8.154 + "start" : self.format_date(view_start, "full"),
8.155 + "end" : self.format_date(view_end, "full")})
8.156 elif view_start:
8.157 - page.add("Showing events from %s" % self.format_date(view_start, "full"))
8.158 + page.add(_("Showing events from %s") % self.format_date(view_start, "full"))
8.159 elif view_end:
8.160 - page.add("Showing events until %s" % self.format_date(view_end, "full"))
8.161 + page.add(_("Showing events until %s") % self.format_date(view_end, "full"))
8.162
8.163 page.p.close()
8.164
8.165 @@ -440,6 +454,8 @@
8.166 collections of the given 'participants'.
8.167 """
8.168
8.169 + _ = self.get_translator()
8.170 +
8.171 # Obtain the user's timezone.
8.172
8.173 tzid = self.get_tzid()
8.174 @@ -451,7 +467,7 @@
8.175
8.176 period_groups = [request_summary, freebusy]
8.177 period_group_types = ["request", "freebusy"]
8.178 - period_group_sources = ["Pending requests", "Your schedule"]
8.179 + period_group_sources = [_("Pending requests"), _("Your schedule")]
8.180
8.181 for i, participant in enumerate(participants):
8.182 period_groups.append(self.store.get_freebusy_for_other(self.user, get_uri(participant)))
8.183 @@ -568,7 +584,9 @@
8.184
8.185 "Show the calendar for the current user."
8.186
8.187 - self.new_page(title="Calendar")
8.188 + _ = self.get_translator()
8.189 +
8.190 + self.new_page(title=_("Calendar"))
8.191 page = self.page
8.192
8.193 if self.handle_newevent():
8.194 @@ -756,6 +774,8 @@
8.195 the 'group_columns' defining the number of columns in each group.
8.196 """
8.197
8.198 + _ = self.get_translator()
8.199 +
8.200 page = self.page
8.201
8.202 # Determine the number of columns required. Where participants provide
8.203 @@ -817,13 +837,13 @@
8.204 # Show a button for scheduling a new event.
8.205
8.206 page.p(class_="newevent-with-periods")
8.207 - page.label("Summary:")
8.208 + page.label(_("Summary:"))
8.209 page.input(name="summary-%d" % i, type="text")
8.210 - page.input(name="newevent-%d" % i, type="submit", value="New event", accesskey="N")
8.211 + page.input(name="newevent-%d" % i, type="submit", value=_("New event"), accesskey="N")
8.212 page.p.close()
8.213
8.214 page.p(class_="newevent-with-periods")
8.215 - page.label("Clear selections", for_="reset", class_="reset")
8.216 + page.label(_("Clear selections"), for_="reset", class_="reset")
8.217 page.p.close()
8.218
8.219 page.div.close()
8.220 @@ -838,6 +858,8 @@
8.221 columns given by 'group_columns'.
8.222 """
8.223
8.224 + _ = self.get_translator()
8.225 +
8.226 page = self.page
8.227
8.228 # Obtain the user's timezone.
8.229 @@ -968,7 +990,7 @@
8.230 if not p.summary or \
8.231 group_type != "request" and self._have_request(p.uid, p.recurrenceid, None, True):
8.232
8.233 - page.span(p.summary or "(Participant is busy)")
8.234 + page.span(p.summary or _("(Participant is busy)"))
8.235
8.236 # Link to requests and events (including ones for
8.237 # which counter-proposals exist).
8.238 @@ -1045,11 +1067,13 @@
8.239 given 'colspan' configuring the cell's appearance.
8.240 """
8.241
8.242 + _ = self.get_translator()
8.243 +
8.244 page = self.page
8.245 page.td(class_="empty%s%s" % (point.indicator == Point.PRINCIPAL and " container" or "", at_end and " padding" or ""), colspan=colspan)
8.246 if point.indicator == Point.PRINCIPAL:
8.247 value, identifier = self._slot_value_and_identifier(point, endpoint)
8.248 - page.label("Select/deselect period", class_="newevent popup", for_=identifier)
8.249 + page.label(_("Select/deselect period"), class_="newevent popup", for_=identifier)
8.250 page.td.close()
8.251
8.252 def _day_value_and_identifier(self, day):
9.1 --- a/imipweb/event.py Wed Nov 04 23:35:16 2015 +0100
9.2 +++ b/imipweb/event.py Thu Nov 05 00:58:02 2015 +0100
9.3 @@ -138,6 +138,8 @@
9.4
9.5 "Show form controls for a request."
9.6
9.7 + _ = self.get_translator()
9.8 +
9.9 page = self.page
9.10 args = self.env.get_args()
9.11
9.12 @@ -145,41 +147,41 @@
9.13 is_attendee = self.user in attendees
9.14
9.15 if not self.obj.is_shared():
9.16 - page.p("This event has not been shared.")
9.17 + page.p(_("This event has not been shared."))
9.18
9.19 # Show appropriate options depending on the role of the user.
9.20
9.21 if is_attendee and not self.is_organiser():
9.22 - page.p("An action is required for this request:")
9.23 + page.p(_("An action is required for this request:"))
9.24
9.25 page.p()
9.26 - self.control("reply", "submit", "Send reply")
9.27 + self.control("reply", "submit", _("Send reply"))
9.28 page.add(" ")
9.29 - self.control("discard", "submit", "Discard event")
9.30 + self.control("discard", "submit", _("Discard event"))
9.31 page.add(" ")
9.32 - self.control("ignore", "submit", "Return to the calendar", class_="ignore")
9.33 + self.control("ignore", "submit", _("Return to the calendar"), class_="ignore")
9.34 page.p.close()
9.35
9.36 if self.is_organiser():
9.37 - page.p("As organiser, you can perform the following:")
9.38 + page.p(_("As organiser, you can perform the following:"))
9.39
9.40 page.p()
9.41 - self.control("create", "submit", "Update event")
9.42 + self.control("create", "submit", _("Update event"))
9.43 page.add(" ")
9.44
9.45 if self._get_counters(self.uid, self.recurrenceid):
9.46 - self.control("uncounter", "submit", "Ignore counter-proposals")
9.47 + self.control("uncounter", "submit", _("Ignore counter-proposals"))
9.48 page.add(" ")
9.49
9.50 if self.obj.is_shared() and not self._is_request():
9.51 - self.control("cancel", "submit", "Cancel event")
9.52 + self.control("cancel", "submit", _("Cancel event"))
9.53 else:
9.54 - self.control("discard", "submit", "Discard event")
9.55 + self.control("discard", "submit", _("Discard event"))
9.56
9.57 page.add(" ")
9.58 - self.control("ignore", "submit", "Return to the calendar", class_="ignore")
9.59 + self.control("ignore", "submit", _("Return to the calendar"), class_="ignore")
9.60 page.add(" ")
9.61 - self.control("save", "submit", "Save without sending")
9.62 + self.control("save", "submit", _("Save without sending"))
9.63 page.p.close()
9.64
9.65 def show_object_on_page(self, errors=None):
9.66 @@ -189,6 +191,8 @@
9.67 a suitable message for the different errors provided.
9.68 """
9.69
9.70 + _ = self.get_translator()
9.71 +
9.72 page = self.page
9.73 page.form(method="POST")
9.74
9.75 @@ -216,7 +220,7 @@
9.76 page.table(class_="object", cellspacing=5, cellpadding=5)
9.77 page.thead()
9.78 page.tr()
9.79 - page.th("Event", class_="mainheading", colspan=3)
9.80 + page.th(_("Event"), class_="mainheading", colspan=3)
9.81 page.tr.close()
9.82 page.thead.close()
9.83 page.tbody()
9.84 @@ -263,7 +267,7 @@
9.85
9.86 if replaced:
9.87 page.td(class_="objectvalue %s replaced" % field, rowspan=2, colspan=2)
9.88 - page.a("First occurrence replaced by a separate event", href=self.link_to(self.uid, replaced))
9.89 + page.a(_("First occurrence replaced by a separate event"), href=self.link_to(self.uid, replaced))
9.90 page.td.close()
9.91
9.92 # NOTE: Should provide a way of editing recurrences when the
9.93 @@ -272,7 +276,7 @@
9.94
9.95 elif excluded:
9.96 page.td(class_="objectvalue %s excluded" % field, rowspan=2, colspan=2)
9.97 - page.add("First occurrence excluded")
9.98 + page.add(_("First occurrence excluded"))
9.99 page.td.close()
9.100
9.101 page.tr.close()
9.102 @@ -283,7 +287,7 @@
9.103 page.tr()
9.104 page.td(colspan=2)
9.105 self.control("recur-add", "submit", "add", id="recur-add", class_="add")
9.106 - page.label("Add a recurrence", for_="recur-add", class_="add")
9.107 + page.label(_("Add a recurrence"), for_="recur-add", class_="add")
9.108 page.td.close()
9.109 page.tr.close()
9.110
9.111 @@ -324,7 +328,7 @@
9.112
9.113 page.td(colspan=2)
9.114 self.control("add", "submit", "add", id="add", class_="add")
9.115 - page.label("Add attendee", for_="add", class_="add")
9.116 + page.label(_("Add attendee"), for_="add", class_="add")
9.117 page.td.close()
9.118 page.tr.close()
9.119
9.120 @@ -364,6 +368,8 @@
9.121 'attendee' value, having 'attendee_attr' as any stored attributes.
9.122 """
9.123
9.124 + _ = self.get_translator()
9.125 +
9.126 page = self.page
9.127 args = self.env.get_args()
9.128
9.129 @@ -411,10 +417,10 @@
9.130 remove_type = self.can_remove_attendee(attendee_uri) and "submit" or "checkbox"
9.131 self.control("remove", remove_type, str(i), str(i) in args.get("remove", []), id="remove-%d" % i, class_="remove")
9.132
9.133 - page.label("Remove", for_="remove-%d" % i, class_="remove")
9.134 + page.label(_("Remove"), for_="remove-%d" % i, class_="remove")
9.135 page.label(for_="remove-%d" % i, class_="removed")
9.136 - page.add("(Uninvited)")
9.137 - page.span("Re-invite", class_="action")
9.138 + page.add(_("(Uninvited)"))
9.139 + page.span(_("Re-invite"), class_="action")
9.140 page.label.close()
9.141
9.142 page.td.close()
9.143 @@ -426,6 +432,8 @@
9.144 suitable message for the different errors provided.
9.145 """
9.146
9.147 + _ = self.get_translator()
9.148 +
9.149 page = self.page
9.150
9.151 # Obtain any parent object if this object is a specific recurrence.
9.152 @@ -436,7 +444,7 @@
9.153 return
9.154
9.155 page.p()
9.156 - page.a("This event modifies a recurring event.", href=self.link_to(self.uid))
9.157 + page.a(_("This event modifies a recurring event."), href=self.link_to(self.uid))
9.158 page.p.close()
9.159
9.160 # Obtain the periods associated with the event.
9.161 @@ -446,7 +454,7 @@
9.162 if len(recurrences) < 1:
9.163 return
9.164
9.165 - page.p("This event occurs on the following occasions within the next %d days:" % self.get_window_size())
9.166 + page.p(_("This event occurs on the following occasions within the next %d days:") % self.get_window_size())
9.167
9.168 # Show each recurrence in a separate table.
9.169
9.170 @@ -465,6 +473,8 @@
9.171 provided.
9.172 """
9.173
9.174 + _ = self.get_translator()
9.175 +
9.176 page = self.page
9.177 args = self.env.get_args()
9.178
9.179 @@ -475,7 +485,7 @@
9.180 self.show_object_datetime_controls(period, index)
9.181
9.182 page.table(cellspacing=5, cellpadding=5, class_="recurrence")
9.183 - page.caption(period.origin == "RRULE" and "Occurrence from rule" or "Occurrence")
9.184 + page.caption(period.origin == "RRULE" and _("Occurrence from rule") or _("Occurrence"))
9.185 page.tbody()
9.186
9.187 page.tr()
9.188 @@ -506,10 +516,10 @@
9.189 str(index) in args.get("recur-remove", []),
9.190 id="recur-remove-%d" % index, class_="remove")
9.191
9.192 - page.label("Remove", for_="recur-remove-%d" % index, class_="remove")
9.193 + page.label(_("Remove"), for_="recur-remove-%d" % index, class_="remove")
9.194 page.label(for_="recur-remove-%d" % index, class_="removed")
9.195 - page.add("(Removed)")
9.196 - page.span("Re-add", class_="action")
9.197 + page.add(_("(Removed)"))
9.198 + page.span(_("Re-add"), class_="action")
9.199 page.label.close()
9.200
9.201 page.td.close()
9.202 @@ -524,6 +534,8 @@
9.203
9.204 "Show any counter-proposals for the current object."
9.205
9.206 + _ = self.get_translator()
9.207 +
9.208 page = self.page
9.209 query = self.env.get_query()
9.210 counter = query.get("counter", [None])[0]
9.211 @@ -569,13 +581,13 @@
9.212 # Present the suggested attendees.
9.213
9.214 if suggested_attendees:
9.215 - page.p("The following attendees have been suggested for this event:")
9.216 + page.p(_("The following attendees have been suggested for this event:"))
9.217
9.218 page.table(cellspacing=5, cellpadding=5, class_="counters")
9.219 page.thead()
9.220 page.tr()
9.221 - page.th("Attendee")
9.222 - page.th("Suggested by...")
9.223 + page.th(_("Attendee"))
9.224 + page.th(_("Suggested by..."))
9.225 page.tr.close()
9.226 page.thead.close()
9.227 page.tbody()
9.228 @@ -599,17 +611,17 @@
9.229 # Present the suggested periods.
9.230
9.231 if suggested_periods:
9.232 - page.p("The following periods have been suggested for this event:")
9.233 + page.p(_("The following periods have been suggested for this event:"))
9.234
9.235 page.table(cellspacing=5, cellpadding=5, class_="counters")
9.236 page.thead()
9.237 page.tr()
9.238 - page.th("Periods", colspan=2)
9.239 - page.th("Suggested by...", rowspan=2)
9.240 + page.th(_("Periods"), colspan=2)
9.241 + page.th(_("Suggested by..."), rowspan=2)
9.242 page.tr.close()
9.243 page.tr()
9.244 - page.th("Start")
9.245 - page.th("End")
9.246 + page.th(_("Start"))
9.247 + page.th(_("End"))
9.248 page.tr.close()
9.249 page.thead.close()
9.250 page.tbody()
9.251 @@ -658,6 +670,8 @@
9.252
9.253 "Show conflicting events for the current object."
9.254
9.255 + _ = self.get_translator()
9.256 +
9.257 page = self.page
9.258 recurrenceids = self._get_active_recurrences(self.uid)
9.259
9.260 @@ -713,14 +727,14 @@
9.261 # Show any conflicts with periods of actual attendance.
9.262
9.263 if conflicts:
9.264 - page.p("This event conflicts with others:")
9.265 + page.p(_("This event conflicts with others:"))
9.266
9.267 page.table(cellspacing=5, cellpadding=5, class_="conflicts")
9.268 page.thead()
9.269 page.tr()
9.270 - page.th("Event")
9.271 - page.th("Start")
9.272 - page.th("End")
9.273 + page.th(_("Event"))
9.274 + page.th(_("Start"))
9.275 + page.th(_("End"))
9.276 page.tr.close()
9.277 page.thead.close()
9.278 page.tbody()
9.279 @@ -740,7 +754,7 @@
9.280 if p.summary:
9.281 page.a(p.summary, href=self.link_to(p.uid, p.recurrenceid))
9.282 else:
9.283 - page.add("(Unspecified event)")
9.284 + page.add(_("(Unspecified event)"))
9.285 page.td.close()
9.286
9.287 page.td(start)
9.288 @@ -1265,7 +1279,9 @@
9.289 self.update_current_attendees()
9.290 self.update_current_recurrences()
9.291
9.292 - self.new_page(title="Event")
9.293 + _ = self.get_translator()
9.294 +
9.295 + self.new_page(title=_("Event"))
9.296 self.show_object_on_page(errors)
9.297
9.298 return True
10.1 --- a/imipweb/profile.py Wed Nov 04 23:35:16 2015 +0100
10.2 +++ b/imipweb/profile.py Thu Nov 05 00:58:02 2015 +0100
10.3 @@ -115,6 +115,8 @@
10.4
10.5 "Show the preferences, indicating any 'errors' in the output."
10.6
10.7 + _ = self.get_translator()
10.8 +
10.9 page = self.page
10.10 settings = self.get_current_preferences()
10.11 prefs = self.get_preferences()
10.12 @@ -145,10 +147,16 @@
10.13 page.th.close()
10.14 page.td()
10.15
10.16 + # For unrestricted fields, show a text field.
10.17 +
10.18 if not choices:
10.19 page.input(name=name, value=(value or default), type="text", class_="preference", id_=name)
10.20 +
10.21 + # Otherwise, obtain the choices, localise the labels and show a
10.22 + # menu control.
10.23 +
10.24 else:
10.25 - choices = list(choices.items())
10.26 + choices = [(key, _(label)) for (key, label) in choices.items()]
10.27 choices.sort()
10.28 self.menu(name, default, choices, value is not None and [value] or None, class_="preference")
10.29
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/messages/en_GB.imip-agent.po Thu Nov 05 00:58:02 2015 +0100
11.3 @@ -0,0 +1,309 @@
11.4 +# Translations for imip-agent.
11.5 +# Copyright (C) 2015 Paul Boddie <paul@boddie.org.uk>
11.6 +# This file is distributed under the same license as the imip-agent package.
11.7 +# Paul Boddie <paul@boddie.org.uk>, 2015.
11.8 +#
11.9 +#, fuzzy
11.10 +msgid ""
11.11 +msgstr ""
11.12 +"Project-Id-Version: 4bc73eb1e076+\n"
11.13 +"Report-Msgid-Bugs-To: \n"
11.14 +"POT-Creation-Date: 2015-11-05 00:55+0100\n"
11.15 +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
11.16 +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11.17 +"Language-Team: LANGUAGE <LL@li.org>\n"
11.18 +"Language: \n"
11.19 +"MIME-Version: 1.0\n"
11.20 +"Content-Type: text/plain; charset=CHARSET\n"
11.21 +"Content-Transfer-Encoding: 8bit\n"
11.22 +
11.23 +msgid "Calendar system message"
11.24 +msgstr ""
11.25 +
11.26 +msgid ""
11.27 +"This message contains several different parts, one of which will contain\n"
11.28 +"calendar information that will only be understood by a suitable program.\n"
11.29 +msgstr ""
11.30 +
11.31 +msgid "An addition to an event has been received."
11.32 +msgstr ""
11.33 +
11.34 +msgid "An event cancellation has been received."
11.35 +msgstr ""
11.36 +
11.37 +msgid "A counter proposal to an event invitation has been received."
11.38 +msgstr ""
11.39 +
11.40 +msgid "Your counter proposal to an event invitation has been declined."
11.41 +msgstr ""
11.42 +
11.43 +msgid "Details of an event have been received."
11.44 +msgstr ""
11.45 +
11.46 +msgid "A request for updated event details has been received."
11.47 +msgstr ""
11.48 +
11.49 +msgid "A reply to an event invitation has been received."
11.50 +msgstr ""
11.51 +
11.52 +msgid "An event invitation has been received."
11.53 +msgstr ""
11.54 +
11.55 +msgid "A free/busy update has been received."
11.56 +msgstr ""
11.57 +
11.58 +msgid "A reply to a free/busy request has been received."
11.59 +msgstr ""
11.60 +
11.61 +#, python-format
11.62 +msgid ""
11.63 +"If your mail program cannot handle this message, you may view the details "
11.64 +"here:\n"
11.65 +"\n"
11.66 +"%s"
11.67 +msgstr ""
11.68 +
11.69 +msgid "Add events"
11.70 +msgstr ""
11.71 +
11.72 +msgid "Ignore requests"
11.73 +msgstr ""
11.74 +
11.75 +msgid "Ask for refreshed event details"
11.76 +msgstr ""
11.77 +
11.78 +msgid "Do not respond"
11.79 +msgstr ""
11.80 +
11.81 +msgid "Always respond"
11.82 +msgstr ""
11.83 +
11.84 +msgid "Never"
11.85 +msgstr ""
11.86 +
11.87 +msgid "Always"
11.88 +msgstr ""
11.89 +
11.90 +msgid "Do not notify"
11.91 +msgstr ""
11.92 +
11.93 +msgid "Notify"
11.94 +msgstr ""
11.95 +
11.96 +msgid "Publish"
11.97 +msgstr ""
11.98 +
11.99 +msgid "Do not publish"
11.100 +msgstr ""
11.101 +
11.102 +msgid "Share"
11.103 +msgstr ""
11.104 +
11.105 +msgid "Do not share"
11.106 +msgstr ""
11.107 +
11.108 +msgid "Original message only"
11.109 +msgstr ""
11.110 +
11.111 +msgid "Original message followed by a separate summary message"
11.112 +msgstr ""
11.113 +
11.114 +msgid "Summary message followed by the original message"
11.115 +msgstr ""
11.116 +
11.117 +msgid "Summary message only"
11.118 +msgstr ""
11.119 +
11.120 +msgid "Summary message wrapping the original message"
11.121 +msgstr ""
11.122 +
11.123 +msgid "Anyone"
11.124 +msgstr ""
11.125 +
11.126 +msgid "Existing attendees only"
11.127 +msgstr ""
11.128 +
11.129 +msgid "Never allow organiser replacement"
11.130 +msgstr ""
11.131 +
11.132 +msgid "Participate"
11.133 +msgstr ""
11.134 +
11.135 +msgid "Do not participate"
11.136 +msgstr ""
11.137 +
11.138 +#, python-format
11.139 +msgid "New event at %s"
11.140 +msgstr ""
11.141 +
11.142 +msgid "There are no pending requests."
11.143 +msgstr ""
11.144 +
11.145 +msgid "Participants for scheduling:"
11.146 +msgstr ""
11.147 +
11.148 +msgid "Remove"
11.149 +msgstr ""
11.150 +
11.151 +msgid "Add"
11.152 +msgstr ""
11.153 +
11.154 +msgid "Select days or periods for a new event."
11.155 +msgstr ""
11.156 +
11.157 +msgid "Hide busy time periods"
11.158 +msgstr ""
11.159 +
11.160 +msgid "Show busy time periods"
11.161 +msgstr ""
11.162 +
11.163 +msgid "Show empty days"
11.164 +msgstr ""
11.165 +
11.166 +msgid "Hide empty days"
11.167 +msgstr ""
11.168 +
11.169 +msgid "Clear selections"
11.170 +msgstr ""
11.171 +
11.172 +msgid "Show earlier events"
11.173 +msgstr ""
11.174 +
11.175 +msgid "Show earlier"
11.176 +msgstr ""
11.177 +
11.178 +msgid "Show later"
11.179 +msgstr ""
11.180 +
11.181 +msgid "Show later events"
11.182 +msgstr ""
11.183 +
11.184 +#, python-format
11.185 +msgid "Showing events from %(start)s until %(end)s"
11.186 +msgstr ""
11.187 +
11.188 +#, python-format
11.189 +msgid "Showing events from %s"
11.190 +msgstr ""
11.191 +
11.192 +#, python-format
11.193 +msgid "Showing events until %s"
11.194 +msgstr ""
11.195 +
11.196 +msgid "Pending requests"
11.197 +msgstr ""
11.198 +
11.199 +msgid "Your schedule"
11.200 +msgstr ""
11.201 +
11.202 +msgid "Calendar"
11.203 +msgstr ""
11.204 +
11.205 +msgid "Summary:"
11.206 +msgstr ""
11.207 +
11.208 +msgid "New event"
11.209 +msgstr ""
11.210 +
11.211 +msgid "(Participant is busy)"
11.212 +msgstr ""
11.213 +
11.214 +msgid "Select/deselect period"
11.215 +msgstr ""
11.216 +
11.217 +msgid "This event has not been shared."
11.218 +msgstr ""
11.219 +
11.220 +msgid "An action is required for this request:"
11.221 +msgstr ""
11.222 +
11.223 +msgid "Send reply"
11.224 +msgstr ""
11.225 +
11.226 +msgid "Discard event"
11.227 +msgstr ""
11.228 +
11.229 +msgid "Return to the calendar"
11.230 +msgstr ""
11.231 +
11.232 +msgid "As organiser, you can perform the following:"
11.233 +msgstr ""
11.234 +
11.235 +msgid "Update event"
11.236 +msgstr ""
11.237 +
11.238 +msgid "Ignore counter-proposals"
11.239 +msgstr ""
11.240 +
11.241 +msgid "Cancel event"
11.242 +msgstr ""
11.243 +
11.244 +msgid "Save without sending"
11.245 +msgstr ""
11.246 +
11.247 +msgid "Event"
11.248 +msgstr ""
11.249 +
11.250 +msgid "First occurrence replaced by a separate event"
11.251 +msgstr ""
11.252 +
11.253 +msgid "First occurrence excluded"
11.254 +msgstr ""
11.255 +
11.256 +msgid "Add a recurrence"
11.257 +msgstr ""
11.258 +
11.259 +msgid "Add attendee"
11.260 +msgstr ""
11.261 +
11.262 +msgid "(Uninvited)"
11.263 +msgstr ""
11.264 +
11.265 +msgid "Re-invite"
11.266 +msgstr ""
11.267 +
11.268 +msgid "This event modifies a recurring event."
11.269 +msgstr ""
11.270 +
11.271 +#, python-format
11.272 +msgid "This event occurs on the following occasions within the next %d days:"
11.273 +msgstr ""
11.274 +
11.275 +msgid "Occurrence from rule"
11.276 +msgstr ""
11.277 +
11.278 +msgid "Occurrence"
11.279 +msgstr ""
11.280 +
11.281 +msgid "(Removed)"
11.282 +msgstr ""
11.283 +
11.284 +msgid "Re-add"
11.285 +msgstr ""
11.286 +
11.287 +msgid "The following attendees have been suggested for this event:"
11.288 +msgstr ""
11.289 +
11.290 +msgid "Attendee"
11.291 +msgstr ""
11.292 +
11.293 +msgid "Suggested by..."
11.294 +msgstr ""
11.295 +
11.296 +msgid "The following periods have been suggested for this event:"
11.297 +msgstr ""
11.298 +
11.299 +msgid "Periods"
11.300 +msgstr ""
11.301 +
11.302 +msgid "Start"
11.303 +msgstr ""
11.304 +
11.305 +msgid "End"
11.306 +msgstr ""
11.307 +
11.308 +msgid "This event conflicts with others:"
11.309 +msgstr ""
11.310 +
11.311 +msgid "(Unspecified event)"
11.312 +msgstr ""
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/tools/i18n_format.sh Thu Nov 05 00:58:02 2015 +0100
12.3 @@ -0,0 +1,8 @@
12.4 +#!/bin/sh
12.5 +
12.6 +DOMAIN=imip-agent
12.7 +
12.8 +for FILENAME in messages/*.po ; do
12.9 + LOCALE_ID=`basename "$FILENAME" ".$DOMAIN.po"`
12.10 + msgfmt -o "locale/$LOCALE_ID/LC_MESSAGES/$DOMAIN.mo" "$FILENAME"
12.11 +done
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/tools/i18n_messages.sh Thu Nov 05 00:58:02 2015 +0100
13.3 @@ -0,0 +1,14 @@
13.4 +#!/bin/sh
13.5 +
13.6 +find imiptools imipweb -type f -name '*.py' | xargs xgettext -d imip-agent --no-location
13.7 +
13.8 + sed "s/SOME DESCRIPTIVE TITLE/Translations for imip-agent/" imip-agent.po \
13.9 +| sed "s/YEAR THE PACKAGE'S COPYRIGHT HOLDER/2015 Paul Boddie <paul@boddie.org.uk>/" \
13.10 +| sed "s/FIRST AUTHOR <EMAIL@ADDRESS>, YEAR/Paul Boddie <paul@boddie.org.uk>, 2015/" \
13.11 +| sed "s/PACKAGE VERSION/`hg id | cut -d ' ' -f 1`/" \
13.12 +| sed "s/PACKAGE/imip-agent/" \
13.13 +> imip-agent.pot
13.14 +
13.15 +for FILENAME in messages/*.po ; do
13.16 + msgmerge --update "$FILENAME" imip-agent.pot
13.17 +done