Skip to content

Commit

Permalink
Improve pluralization of translated strings
Browse files Browse the repository at this point in the history
Switch a few strings containing numeric variables to ngettext from
gettext, to ensure they can be properly translated. Use "num" more
consistently as the placeholder for numeric variables in strings
marked with ngettext, to make things easier for translators.
  • Loading branch information
rmol committed Oct 8, 2020
1 parent 9761c1c commit ee5bd0b
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 28 deletions.
36 changes: 23 additions & 13 deletions securedrop/journalist_app/forms.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

from flask_babel import lazy_gettext as gettext
from flask_babel import lazy_gettext as gettext, ngettext
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed, FileRequired
from wtforms import (TextAreaField, StringField, BooleanField, HiddenField,
Expand All @@ -12,27 +12,37 @@

def otp_secret_validation(form, field):
strip_whitespace = field.data.replace(' ', '')
if len(strip_whitespace) != 40:
raise ValidationError(gettext(
'HOTP secrets are 40 characters long - '
'you have entered {num_chars}.'.format(
num_chars=len(strip_whitespace)
)))
input_length = len(strip_whitespace)
if input_length != 40:
raise ValidationError(
ngettext(
'HOTP secrets must be 40 characters long. You have entered {num}.',
'HOTP secrets must be 40 characters long. You have entered {num}.',
input_length
).format(num=input_length)
)


def minimum_length_validation(form, field):
if len(field.data) < Journalist.MIN_USERNAME_LEN:
raise ValidationError(
gettext('Must be at least {min_chars} '
'characters long.'
.format(min_chars=Journalist.MIN_USERNAME_LEN)))
ngettext(
'Must be at least {num} characters long.',
'Must be at least {num} characters long.',
Journalist.MIN_USERNAME_LEN
).format(num=Journalist.MIN_USERNAME_LEN)
)


def name_length_validation(form, field):
if len(field.data) > Journalist.MAX_NAME_LEN:
raise ValidationError(gettext(
'Cannot be longer than {max_chars} characters.'
.format(max_chars=Journalist.MAX_NAME_LEN)))
raise ValidationError(
ngettext(
'Cannot be longer than {num} characters.',
'Cannot be longer than {num} characters.',
Journalist.MAX_NAME_LEN
).format(num=Journalist.MAX_NAME_LEN)
)


def check_invalid_usernames(form, field):
Expand Down
32 changes: 21 additions & 11 deletions securedrop/journalist_app/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,10 @@ def validate_user(
# ngettext is needed although we always have period > 1
# see https://github.com/freedomofpress/securedrop/issues/2422
login_flashed_msg += ngettext(
"Please wait at least {seconds} second "
"before logging in again.",
"Please wait at least {seconds} seconds "
"before logging in again.", period).format(seconds=period)
"Please wait at least {num} second before logging in again.",
"Please wait at least {num} seconds before logging in again.",
period
).format(num=period)
else:
try:
user = Journalist.query.filter_by(
Expand Down Expand Up @@ -239,10 +239,15 @@ def bulk_delete(
except ValueError:
deletion_errors += 1

flash(ngettext("Submission deleted.",
"{num} submissions deleted.".format(
num=len(items_selected)),
len(items_selected)), "notification")
num_selected = len(items_selected)
flash(
ngettext(
"Submission deleted.",
"{num} submissions deleted.",
num_selected
).format(num=num_selected),
"notification"
)
if deletion_errors > 0:
current_app.logger.error("Disconnected submission entries (%d) were detected",
deletion_errors)
Expand Down Expand Up @@ -301,9 +306,14 @@ def col_delete(cols_selected: List[str]) -> werkzeug.Response:
db.session.commit()

num = len(cols_selected)
flash(ngettext('{num} collection deleted', '{num} collections deleted',
num).format(num=num),
"notification")
flash(
ngettext(
'{num} collection deleted',
'{num} collections deleted',
num
).format(num=num),
"notification"
)

return redirect(url_for('main.index'))

Expand Down
6 changes: 3 additions & 3 deletions securedrop/journalist_templates/_source_row.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
{% endif %}
</div>
<div class="submission-count">
<span><i class="far fa-file-archive"></i> {{ ngettext('1 doc', '{doc_num} docs', docs).format(doc_num=docs) }}</span>
<span><i class="far fa-file-alt"></i> {{ ngettext('1 message', '{msg_num} messages', msgs).format(msg_num=msgs) }}</span>
<span><i class="far fa-file-archive"></i> {{ ngettext('1 doc', '{num} docs', docs).format(num=docs) }}</span>
<span><i class="far fa-file-alt"></i> {{ ngettext('1 message', '{num} messages', msgs).format(num=msgs) }}</span>
{% if source.num_unread > 0 %}
<span class="unread">
<a class="btn small" href="/download_unread/{{ source.filesystem_id }}"><i class="fa fa-download"></i> {{ ngettext('1 unread', '{num_unread} unread', source.num_unread).format(num_unread=source.num_unread) }}</a>
<a class="btn small" href="/download_unread/{{ source.filesystem_id }}"><i class="fa fa-download"></i> {{ ngettext('1 unread', '{num} unread', source.num_unread).format(num=source.num_unread)}}</a>
</span>
{% endif %}
</div>
Expand Down
2 changes: 1 addition & 1 deletion securedrop/journalist_templates/delete.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{% block body %}

{% with count=items_selected|length %}
<p>{{ ngettext('The following file has been selected for <strong>permanent deletion</strong>:', 'The following {files} files have been selected for <strong>permanent deletion</strong>:', count).format(files=count)|safe }}</p>
<p>{{ ngettext('The following file has been selected for <strong>permanent deletion</strong>:', 'The following {num} files have been selected for <strong>permanent deletion</strong>:', count).format(num=count)|safe }}</p>
{% endwith %}

<form action="/bulk" method="post">
Expand Down

0 comments on commit ee5bd0b

Please sign in to comment.