diff options
-rw-r--r-- | aurweb/l10n.py | 16 | ||||
-rwxr-xr-x | aurweb/scripts/notify.py | 258 | ||||
-rw-r--r-- | po/Makefile | 21 | ||||
-rw-r--r-- | test/setup.sh | 18 |
4 files changed, 189 insertions, 124 deletions
diff --git a/aurweb/l10n.py b/aurweb/l10n.py new file mode 100644 index 00000000..e58e3fe2 --- /dev/null +++ b/aurweb/l10n.py @@ -0,0 +1,16 @@ +import gettext + + +class Translator: + def __init__(self): + self._translator = {} + + def translate(self, s, lang): + if lang == 'en': + return s + if lang not in self._translator: + self._translator[lang] = gettext.translation("aur", + "../../web/locale", + languages=[lang]) + self._translator[lang].install() + return _(s) diff --git a/aurweb/scripts/notify.py b/aurweb/scripts/notify.py index a6370133..9f1f7a5d 100755 --- a/aurweb/scripts/notify.py +++ b/aurweb/scripts/notify.py @@ -7,6 +7,7 @@ import textwrap import aurweb.config import aurweb.db +import aurweb.l10n aur_location = aurweb.config.get('options', 'aur_location') @@ -40,36 +41,37 @@ def pkgbase_from_pkgreq(conn, reqid): return cur.fetchone()[0] -def get_user_email(conn, uid): - cur = conn.execute('SELECT Email FROM Users WHERE ID = ?', [uid]) - return cur.fetchone()[0] - - class Notification: + def __init__(self): + self._l10n = aurweb.l10n.Translator() + def get_refs(self): return () def get_headers(self): return {} - def send(self): + def get_body_fmt(self, lang): body = '' - for line in self.get_body().splitlines(): + for line in self.get_body(lang).splitlines(): body += textwrap.fill(line, break_long_words=False) + '\n' for i, ref in enumerate(self.get_refs()): body += '\n' + '[%d] %s' % (i + 1, ref) - body = body.rstrip() + return body.rstrip() + def send(self): sendmail = aurweb.config.get('notifications', 'sendmail') sender = aurweb.config.get('notifications', 'sender') reply_to = aurweb.config.get('notifications', 'reply-to') for recipient in self.get_recipients(): - msg = email.mime.text.MIMEText(body, 'plain', 'utf-8') - msg['Subject'] = self.get_subject() + to, lang = recipient + msg = email.mime.text.MIMEText(self.get_body_fmt(lang), + 'plain', 'utf-8') + msg['Subject'] = self.get_subject(lang) msg['From'] = sender msg['Reply-to'] = reply_to - msg['To'] = recipient + msg['To'] = to for key, value in self.get_headers().items(): msg[key] = value @@ -81,66 +83,76 @@ class Notification: class ResetKeyNotification(Notification): def __init__(self, conn, uid): - cur = conn.execute('SELECT UserName, Email, ResetKey FROM Users ' + - 'WHERE ID = ?', [uid]) - self._username, self._to, self._resetkey = cur.fetchone() + cur = conn.execute('SELECT UserName, Email, LangPreference, ' + + 'ResetKey FROM Users WHERE ID = ?', [uid]) + self._username, self._to, self._lang, self._resetkey = cur.fetchone() + super().__init__() def get_recipients(self): - return [self._to] + return [(self._to, self._lang)] - def get_subject(self): - return 'AUR Password Reset' + def get_subject(self, lang): + return self._l10n.translate('AUR Password Reset', lang) - def get_body(self): - return 'A password reset request was submitted for the account %s ' \ - 'associated with your email address. If you wish to reset ' \ - 'your password follow the link [1] below, otherwise ignore ' \ - 'this message and nothing will happen.' % (self._username) + def get_body(self, lang): + return self._l10n.translate( + 'A password reset request was submitted for the account %s ' + 'associated with your email address. If you wish to reset ' + 'your password follow the link [1] below, otherwise ignore ' + 'this message and nothing will happen.', lang) % \ + (self._username) def get_refs(self): return (aur_location + '/passreset/?resetkey=' + self._resetkey,) class WelcomeNotification(ResetKeyNotification): - def get_subject(self): - return 'Welcome to the Arch User Repository' + def get_subject(self, lang): + return self._l10n.translate('Welcome to the Arch User Repository', + lang) - def get_body(self): - return 'Welcome to the Arch User Repository! In order to set an ' \ - 'initial password for your new account, please click the ' \ - 'link [1] below. If the link does not work, try copying and ' \ - 'pasting it into your browser.' + def get_body(self, lang): + return self._l10n.translate( + 'Welcome to the Arch User Repository! In order to set an ' + 'initial password for your new account, please click the ' + 'link [1] below. If the link does not work, try copying and ' + 'pasting it into your browser.', lang) class CommentNotification(Notification): def __init__(self, conn, uid, pkgbase_id, comment_id): self._user = username_from_id(conn, uid) self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + - 'INNER JOIN PackageNotifications ' + + cur = conn.execute('SELECT DISTINCT Users.Email, Users.LangPreference ' + 'FROM Users INNER JOIN PackageNotifications ' + 'ON PackageNotifications.UserID = Users.ID WHERE ' + 'Users.CommentNotify = 1 AND ' + 'PackageNotifications.UserID != ? AND ' + 'PackageNotifications.PackageBaseID = ?', [uid, pkgbase_id]) - self._to = [row[0] for row in cur.fetchall()] + self._recipients = cur.fetchall() cur = conn.execute('SELECT Comments FROM PackageComments WHERE ID = ?', [comment_id]) self._text = cur.fetchone()[0] + super().__init__() def get_recipients(self): - return self._to + return self._recipients - def get_subject(self): - return 'AUR Comment for %s' % (self._pkgbase) + def get_subject(self, lang): + return self._l10n.translate('AUR Comment for %s', lang) % \ + (self._pkgbase) - def get_body(self): - body = '%s [1] added the following comment to %s [2]:' % \ - (self._user, self._pkgbase) + def get_body(self, lang): + body = self._l10n.translate( + '%s [1] added the following comment to %s [2]:', lang) % \ + (self._user, self._pkgbase) body += '\n\n' + self._text + '\n\n' - body += 'If you no longer wish to receive notifications about this ' \ - 'package, please go to the package page [2] and select ' \ - '"%s".' % ('Disable notifications') + dnlabel = self._l10n.translate('Disable notifications', lang) + body += self._l10n.translate( + 'If you no longer wish to receive notifications about this ' + 'package, please go to the package page [2] and select ' + '"%s".', lang) % dnlabel return body def get_refs(self): @@ -157,28 +169,33 @@ class UpdateNotification(Notification): def __init__(self, conn, uid, pkgbase_id): self._user = username_from_id(conn, uid) self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + cur = conn.execute('SELECT DISTINCT Users.Email, ' + + 'Users.LangPreference FROM Users ' + 'INNER JOIN PackageNotifications ' + 'ON PackageNotifications.UserID = Users.ID WHERE ' + 'Users.UpdateNotify = 1 AND ' + 'PackageNotifications.UserID != ? AND ' + 'PackageNotifications.PackageBaseID = ?', [uid, pkgbase_id]) - self._to = [row[0] for row in cur.fetchall()] + self._recipients = cur.fetchall() + super().__init__() def get_recipients(self): - return self._to + return self._recipients - def get_subject(self): - return 'AUR Package Update: %s' % (self._pkgbase) + def get_subject(self, lang): + return self._l10n.translate('AUR Package Update: %s', lang) % \ + (self._pkgbase) - def get_body(self): - body = '%s [1] pushed a new commit to %s [2].' % \ - (self._user, self._pkgbase) + def get_body(self, lang): + body = self._l10n.translate('%s [1] pushed a new commit to %s [2].', + lang) % (self._user, self._pkgbase) body += '\n\n' - body += 'If you no longer wish to receive notifications about this ' \ - 'package, please go to the package page [2] and select ' \ - '"%s".' % ('Disable notifications') + dnlabel = self._l10n.translate('Disable notifications', lang) + body += self._l10n.translate( + 'If you no longer wish to receive notifications about this ' + 'package, please go to the package page [2] and select ' + '"%s".', lang) % dnlabel return body def get_refs(self): @@ -195,27 +212,31 @@ class FlagNotification(Notification): def __init__(self, conn, uid, pkgbase_id): self._user = username_from_id(conn, uid) self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + cur = conn.execute('SELECT DISTINCT Users.Email, ' + + 'Users.LangPreference FROM Users ' + 'LEFT JOIN PackageComaintainers ' + 'ON PackageComaintainers.UsersID = Users.ID ' + 'INNER JOIN PackageBases ' + 'ON PackageBases.MaintainerUID = Users.ID OR ' + 'PackageBases.ID = PackageComaintainers.PackageBaseID ' + 'WHERE PackageBases.ID = ?', [pkgbase_id]) - self._to = [row[0] for row in cur.fetchall()] + self._recipients = cur.fetchall() cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' + 'ID = ?', [pkgbase_id]) self._text = cur.fetchone()[0] + super().__init__() def get_recipients(self): - return self._to + return self._recipients - def get_subject(self): - return 'AUR Out-of-date Notification for %s' % (self._pkgbase) + def get_subject(self, lang): + return self._l10n.translate('AUR Out-of-date Notification for %s', + lang) % (self._pkgbase) - def get_body(self): - body = 'Your package %s [1] has been flagged out-of-date by ' \ - '%s [2]:' % (self._pkgbase, self._user) + def get_body(self, lang): + body = self._l10n.translate( + 'Your package %s [1] has been flagged out-of-date by ' + '%s [2]:', lang) % (self._pkgbase, self._user) body += '\n\n' + self._text return body @@ -228,23 +249,26 @@ class OwnershipEventNotification(Notification): def __init__(self, conn, uid, pkgbase_id): self._user = username_from_id(conn, uid) self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + cur = conn.execute('SELECT DISTINCT Users.Email, ' + + 'Users.LangPreference FROM Users ' + 'INNER JOIN PackageNotifications ' + 'ON PackageNotifications.UserID = Users.ID WHERE ' + 'Users.OwnershipNotify = 1 AND ' + 'PackageNotifications.UserID != ? AND ' + 'PackageNotifications.PackageBaseID = ?', [uid, pkgbase_id]) - self._to = [row[0] for row in cur.fetchall()] + self._recipients = cur.fetchall() cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' + 'ID = ?', [pkgbase_id]) self._text = cur.fetchone()[0] + super().__init__() def get_recipients(self): - return self._to + return self._recipients - def get_subject(self): - return 'AUR Ownership Notification for %s' % (self._pkgbase) + def get_subject(self, lang): + return self._l10n.translate('AUR Ownership Notification for %s', + lang) % (self._pkgbase) def get_refs(self): return (aur_location + '/pkgbase/' + self._pkgbase + '/', @@ -252,42 +276,50 @@ class OwnershipEventNotification(Notification): class AdoptNotification(OwnershipEventNotification): - def get_body(self): - return 'The package %s [1] was adopted by %s [2].' % \ - (self._pkgbase, self._user) + def get_body(self, lang): + return self._l10n.translate( + 'The package %s [1] was adopted by %s [2].', lang) % \ + (self._pkgbase, self._user) class DisownNotification(OwnershipEventNotification): def get_body(self): - return 'The package %s [1] was disowned by %s [2].' % \ - (self._pkgbase, self._user) + return self._l10n.translate( + 'The package %s [1] was disowned by %s [2].', lang) % \ + (self._pkgbase, self._user) class ComaintainershipEventNotification(Notification): def __init__(self, conn, uid, pkgbase_id): self._pkgbase = pkgbase_from_id(conn, pkgbase_id) - self._to = get_user_email(conn, uid) + cur = conn.execute('SELECT Email, LangPreference FROM Users ' + + 'WHERE ID = ?', [uid]) + self._to, self._lang = cur.fetchone() + super().__init__() def get_recipients(self): - return [self._to] + return [(self._to, self._lang)] - def get_subject(self): - return 'AUR Co-Maintainer Notification for %s' % (self._pkgbase) + def get_subject(self, lang): + return self._l10n.translate('AUR Co-Maintainer Notification for %s', + lang) % (self._pkgbase) def get_refs(self): return (aur_location + '/pkgbase/' + self._pkgbase + '/',) class ComaintainerAddNotification(ComaintainershipEventNotification): - def get_body(self): - return 'You were added to the co-maintainer list of %s [1].' % \ - (self._pkgbase) + def get_body(self, lang): + return self._l10n.translate( + 'You were added to the co-maintainer list of %s [1].', + lang) % (self._pkgbase) class ComaintainerRemoveNotification(ComaintainershipEventNotification): - def get_body(self): - return 'You were removed from the co-maintainer list of %s [1].' % \ - (self._pkgbase) + def get_body(self, lang): + return self._l10n.translate( + 'You were removed from the co-maintainer list of %s [1].', + lang) % (self._pkgbase) class DeleteNotification(Notification): @@ -298,31 +330,36 @@ class DeleteNotification(Notification): self._new_pkgbase = pkgbase_from_id(conn, new_pkgbase_id) else: self._new_pkgbase = None - cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' + + cur = conn.execute('SELECT DISTINCT Users.Email, ' + + 'Users.LangPreference FROM Users ' + 'INNER JOIN PackageNotifications ' + 'ON PackageNotifications.UserID = Users.ID WHERE ' + 'PackageNotifications.UserID != ? AND ' + 'PackageNotifications.PackageBaseID = ?', [uid, old_pkgbase_id]) - self._to = [row[0] for row in cur.fetchall()] + self._recipients = cur.fetchall() + super().__init__() def get_recipients(self): - return self._to + return self._recipients - def get_subject(self): - return 'AUR Package deleted: %s' % (self._old_pkgbase) + def get_subject(self, lang): + return self._l10n.translate('AUR Package deleted: %s', lang) % \ + (self._old_pkgbase) - def get_body(self): + def get_body(self, lang): if self._new_pkgbase: - return '%s [1] merged %s [2] into %s [3].\n\n' \ - 'If you no longer wish receive notifications about the ' \ - 'new package, please go to [3] and click "%s".' % \ - (self._user, self._old_pkgbase, self._new_pkgbase, - 'Disable notifications') + dnlabel = self._l10n.translate('Disable notifications', lang) + return self._l10n.translate( + '%s [1] merged %s [2] into %s [3].\n\n' + 'If you no longer wish receive notifications about the ' + 'new package, please go to [3] and click "%s".', lang) % \ + (self._user, self._old_pkgbase, self._new_pkgbase, dnlabel) else: - return '%s [1] deleted %s [2].\n\n' \ - 'You will no longer receive notifications about this ' \ - 'package.' % (self._user, self._old_pkgbase) + return self._l10n.translate( + '%s [1] deleted %s [2].\n\n' + 'You will no longer receive notifications about this ' + 'package.', lang) % (self._user, self._old_pkgbase) def get_refs(self): refs = (aur_location + '/account/' + self._user + '/', @@ -353,13 +390,13 @@ class RequestOpenNotification(Notification): self._merge_into = merge_into def get_recipients(self): - return [self._to] + return [(self._to, 'en')] - def get_subject(self): + def get_subject(self, lang): return '[PRQ#%d] %s Request for %s' % \ (self._reqid, self._reqtype.title(), self._pkgbase) - def get_body(self): + def get_body(self, lang): if self._merge_into: body = '%s [1] filed a request to merge %s [2] into %s [3]:' % \ (self._user, self._pkgbase, self._merge_into) @@ -405,12 +442,12 @@ class RequestCloseNotification(Notification): self._reason = reason def get_recipients(self): - return [self._to] + return [(self._to, 'en')] - def get_subject(self): + def get_subject(self, lang): return '[PRQ#%d] Request %s' % (self._reqid, self._reason.title()) - def get_body(self): + def get_body(self, lang): if self._user: body = 'Request #%d has been %s by %s [1]' % \ (self._reqid, self._reason, self._user) @@ -440,22 +477,25 @@ class RequestCloseNotification(Notification): class TUVoteReminderNotification(Notification): def __init__(self, conn, vote_id): self._vote_id = int(vote_id) - cur = conn.execute('SELECT Email FROM Users ' + + cur = conn.execute('SELECT Email, LangPreference FROM Users ' + 'WHERE AccountTypeID IN (2, 4) AND ID NOT IN ' + '(SELECT UserID FROM TU_Votes ' + 'WHERE TU_Votes.VoteID = ?)', [vote_id]) - self._to = [row[0] for row in cur.fetchall()] + self._recipients = cur.fetchall() + super().__init__() def get_recipients(self): - return self._to + return self._recipients - def get_subject(self): - return 'TU Vote Reminder: Proposal %d' % (self._vote_id) + def get_subject(self, lang): + return self._l10n.translate('TU Vote Reminder: Proposal %d', lang) % \ + (self._vote_id) - def get_body(self): - return 'Please remember to cast your vote on proposal %d [1]. ' \ - 'The voting period ends in less than 48 hours.' % \ - (self._vote_id) + def get_body(self, lang): + return self._l10n.translate( + 'Please remember to cast your vote on proposal %d [1]. ' + 'The voting period ends in less than 48 hours.', lang) % \ + (self._vote_id) def get_refs(self): return (aur_location + '/tu/?id=' + str(self._vote_id),) diff --git a/po/Makefile b/po/Makefile index d0ed7418..78073f86 100644 --- a/po/Makefile +++ b/po/Makefile @@ -48,23 +48,32 @@ all: ${MOFILES} lang=`echo $@ | sed -e 's/\.po-update$$//'`; \ msgmerge -U --no-location --lang="$$lang" $< aur.pot -POTFILES: - find ../web -type f -name '*.php' -printf '%P\n' | sort >POTFILES +POTFILES-php: + find ../web -type f -name '*.php' -printf '%P\n' | sort >POTFILES-php -update-pot: POTFILES +POTFILES-py: + find ../aurweb -type f -name '*.py' -printf '%P\n' | sort >POTFILES-py + +update-pot: POTFILES-php POTFILES-py pkgname=AUR; \ pkgver=`sed -n 's/.*"AURWEB_VERSION", "\(.*\)".*/\1/p' ../web/lib/version.inc.php`; \ xgettext --default-domain=aur -L php --keyword=__ --keyword=_n:1,2 \ --add-location=file --add-comments=TRANSLATORS: \ --package-name="$$pkgname" --package-version="$$pkgver" \ --msgid-bugs-address='${MSGID_BUGS_ADDRESS}' \ - --directory ../web --files-from POTFILES -o aur.pot + --directory ../web --files-from POTFILES-php -o aur.pot; \ + xgettext --default-domain=aur -L python --join-existing \ + --keyword=translate \ + --add-location=file --add-comments=TRANSLATORS: \ + --package-name="$$pkgname" --package-version="$$pkgver" \ + --msgid-bugs-address='${MSGID_BUGS_ADDRESS}' \ + --directory ../aurweb --files-from POTFILES-py -o aur.pot update-po: ${MAKE} ${UPDATEPOFILES} clean: - rm -f *.mo *.po\~ POTFILES + rm -f *.mo *.po\~ POTFILES-php POTFILES-py install: all for l in ${LOCALES}; do mkdir -p ${DESTDIR}${PREFIX}/$$l/LC_MESSAGES/; done @@ -73,4 +82,4 @@ install: all uninstall: for l in ${LOCALES}; do rm -rf ${DESTDIR}${PREFIX}/$$l/LC_MESSAGES/; done -.PHONY: all update-pot update-po clean install uninstall POTFILES +.PHONY: all update-pot update-po clean install uninstall POTFILES-php POTFILES-py diff --git a/test/setup.sh b/test/setup.sh index 5e10fec8..535e8190 100644 --- a/test/setup.sh +++ b/test/setup.sh @@ -114,15 +114,15 @@ DBSCHEMA="$TOPLEVEL/schema/aur-schema-sqlite.sql" rm -f aur.db sqlite3 aur.db <"$DBSCHEMA" -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (1, 'user', '!', 'user@localhost', 1);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (2, 'tu', '!', 'tu@localhost', 2);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (3, 'dev', '!', 'dev@localhost', 3);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (4, 'user2', '!', 'user2@localhost', 1);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (5, 'user3', '!', 'user3@localhost', 1);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (6, 'user4', '!', 'user4@localhost', 1);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (7, 'tu2', '!', 'tu2@localhost', 2);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (8, 'tu3', '!', 'tu3@localhost', 2);" | sqlite3 aur.db -echo "INSERT INTO Users (ID, UserName, Passwd, Email, AccountTypeID) VALUES (9, 'tu4', '!', 'tu4@localhost', 2);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (1, 'user', '!', 'user@localhost', 'en', 1);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (2, 'tu', '!', 'tu@localhost', 'en', 2);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (3, 'dev', '!', 'dev@localhost', 'en', 3);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (4, 'user2', '!', 'user2@localhost', 'en', 1);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (5, 'user3', '!', 'user3@localhost', 'en', 1);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (6, 'user4', '!', 'user4@localhost', 'en', 1);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (7, 'tu2', '!', 'tu2@localhost', 'en', 2);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (8, 'tu3', '!', 'tu3@localhost', 'en', 2);" | sqlite3 aur.db +echo "INSERT INTO Users (ID, UserName, Passwd, Email, LangPreference, AccountTypeID) VALUES (9, 'tu4', '!', 'tu4@localhost', 'en', 2);" | sqlite3 aur.db echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (1, '$AUTH_FINGERPRINT_USER', '$AUTH_KEYTYPE_USER $AUTH_KEYTEXT_USER');" | sqlite3 aur.db echo "INSERT INTO SSHPubKeys (UserID, Fingerprint, PubKey) VALUES (2, '$AUTH_FINGERPRINT_TU', '$AUTH_KEYTYPE_TU $AUTH_KEYTEXT_TU');" | sqlite3 aur.db |