Notes for "Translation - Check if code and template are prepared for it" task
Table of contents:
Contents
- Notes for "Translation - Check if code and template are prepared for it" task
-
Iteration #1
-
TODO
- Check lines with "flash("
- MoinMoin/
- MoinMoin/auth
- MoinMoin/config
- MoinMoin/converter
- MoinMoin/datastruct
- MoinMoin/filter
- MoinMoin/items
- MoinMoin/macro
- MoinMoin/mail
- MoinMoin/script
- MoinMoin/search
- MoinMoin/security
- MoinMoin/signalling
- MoinMoin/static
- MoinMoin/storage
- MoinMoin/themes
- MoinMoin/templates:
- MoinMoin/util
- contrib/
-
TODO
- Iteration #2
Translation - Check if code and template are prepared for it.
Snippets from IRC
Why not use %s placeholders in strings
<ThomasWaldmann> it is clear why %s or %d is no good?
<kennym> ThomasWaldmann: no, not really. Could you please explain that?
<kennym> you use %(blabla)s instead
<Roboraider> I'm back.
<dreimark> kennym: one who later has to translate it knows better what the meaning is
<dreimark> and the grammar logic can be completly different
<kennym> dreimark: so it's only a convention?
<ThomasWaldmann> python / jinja2 has placeholders in strings
<ThomasWaldmann> "%s is %s" depends on sequence
<dreimark> if you have two anonymous placeholders
<kennym> oh, sure!
<dreimark> it can get a different meaning in a translated string
<ThomasWaldmann> ngettext has no abbreviation btw, so you'll write ngettext(...) for that
Iteration #1
Check existing i18n and correct bad English.
TODO
Regex to find gettext calls:
_\(\"|_\(\'|N_\("
Check lines with "flash("
apps/frontend/views.py
495: flash(*msg)
523: flash(*msg)
594: flash(msg, "error")
596: flash(_('Account created, please log in now.'), "info")
660: flash(msg, "error")
661: flash(_("If this account exists, you will be notified."), "info")
722: flash(_("Your password has been changed, you can log in now."), "info")
724: flash(_('Your token is invalid!'), "error")
771: flash(hint, "info")
781: flash(msg, "error")
803: flash(_("You are now logged out."), "info")
935: flash(_("Your password has been changed."), "info")
967: flash(_("You must log in to use bookmarks."), "error")
support/flaskext/babel.py
223: flash(gettext('Language was changed'))
support/flask/helpers.py
204:def flash(message, category='message'):Nothing to do here...
MoinMoin/
No results.
MoinMoin/auth
http.py
62: response = Response(_('Please log in first.'), 401,
ldap_login.py
129: return ContinueLogin(user_obj, _('Missing password. Please enter user name and password.'))
199: return ContinueLogin(user_obj, _("Invalid username or password."))
245: return CancelLogin(_("Invalid username or password."))
259: return ContinueLogin(user_obj, _("LDAP server %(server)s failed.", server=server))
__init__.py
234: return ContinueLogin(user_obj, _('Missing password. Please enter user name and password.'))
242: return ContinueLogin(user_obj, _("Invalid username or password."))
245: msg = _('If you do not have an account, <a href="%(register_url)s">you can create one now</a>. ',
247: msg += _('<a href="%(recover_url)s">Forgot your password?</a>',Nothing to do here, either.
MoinMoin/config
default.py
333: return _("Password is too short.")
335: return _("Password has not enough different characters.")
341: return _("Password is too easy (password contains name or name contains password).")
350: return _("Password is too easy (keyboard sequence).")Better: "Password is too easily guessable."
MoinMoin/converter
html_out.py
598: children=[_('Contents'), headtogglelink])
macro.py
79: elem_error.append(_('<<%(macro_name)s: execution failed [%(error_msg)s] (see also the log)>>',Nothing to do.
MoinMoin/datastruct
No results.
MoinMoin/filter
No results.
MoinMoin/items
__init__.py
1243: title = _('Edit drawing %(filename)s (opens in new window)', filename=item_name)
1258: title = _('Clickable drawing: %(filename)s', filename=item_name)
1314: title = _('Edit drawing %(filename)s (opens in new window)', filename=self.name)
1331: title = _('Clickable drawing: %(filename)s', filename=self.name)Nothing to do.
MoinMoin/macro
WikiConfig.py
42: moin_page.h(attrib={moin_page.outline_level: '1'}, children=[_("Wiki configuration")]))
44: desc = _("This table shows all settings in this wiki that do not have default values. "
58: for text in [_('Variable name'), _('Setting'), ]:
WikiConfigHelp.py
42: for text in [_('Variable name'), _('Default'), _('Description'), ]:
GetText.py
21: translation = _(' '.join(args.positional))
GoTo.py
29: _("Go To Page"))) #HHH ?
HighlighterList.py
25: column_titles = [_('Lexer description'),
26: _('Lexer names'),
27: _('File patterns'),
28: _('Mimetypes'),Nothing to do.
MoinMoin/mail
sendmail.py
84: return (1, _("No recipients, nothing to do"))
158: return (0, _("Connection to mailserver '%(server)s' failed: %(reason)s",
174: return (0, _("Mail not sent"))
177: return (1, _("Mail sent OK"))"Mail sent OK" -- bad English. "Mail sent successfully" -- better
MoinMoin/script
No results
MoinMoin/search
Xapian/search.py
65: return self._getHits(pages), (search_results.estimate_is_exact and '' or _('about'), search_results.matches_estimated)
results.py
286: _("Results %(bs)s%(hitsFrom)d - %(hitsTo)d%(be)s "
299: formatter.text(_("seconds"))),
694: f.text(_('Previous')),
715: f.text(_('Next')),
747: rev_str = '%s: %d (%s)' % (_('rev'), rev, _('current'))
749: rev_str = '%s: %d' % (_('rev'), rev, )
750: lastmod_str = _('last modified: %s') % p.mtime(printable=True)
809: self.matchLabel = (_('match'), _('matches'))Oh, cool! Xapian! I love Xapian! Oops... I'm just the translator... looks all right.
MoinMoin/security
163: textcha_incorrect_msg = N_('The entered TextCha was incorrect.')
164: textcha_invalid_msg = N_('The TextCha question is invalid or has expired. Please try again.')
183: textcha = String.using(label=N_('TextCha')).validated_by(TextChaValid())Why do you use N_? Isn't calling gettext(), aka "_", enough?
Answer:
<dreimark> kennym: in the past we had to write words as CamelCase to get a link to a new item <dreimark> so yes it was by design. Now we can write it also as [[Site Map]] but that also in moin-2.0 not correct <dreimark> because in moin-2.0 it is not anymore a macro on a page <dreimark> it is a view now <dreimark> +sitemap <kennym> dreimark: and _() doesn't do the job? <dreimark> it does, there is no counter involved
Fixed.
MoinMoin/signalling
No results.
MoinMoin/static
No results.
MoinMoin/storage
No results.
MoinMoin/themes
__init__.py
45: title = N_('Access denied')
46: description = N_('You are not allowed to access this resource.')
338: (_('Global History'), 'global_history', 'frontend.global_history', False, ),
339: (_('Global Items Index'), 'global_index', 'frontend.global_index', False, ),
340: (_('Global Tags Index'), 'global_tags', 'frontend.global_tags', False, ),
341: (_('Wanted Items'), 'wanted_items', 'frontend.wanted_items', False, ),
342: (_('Orphaned Items'), 'orphaned_items', 'frontend.orphaned_items', False, ),
344: (_('-----------------------------------'), 'show', 'frontend.show_item', True),Does this sequence of dashes have to be localized???
345: (_('What links here?'), 'backlinks', 'frontend.backlinks', False, ),
346: (_('Local Site Map'), 'sitemap', 'frontend.sitemap', False, ),
347: (_('Items with similar names'), 'similar_names', 'frontend.similar_names', False, ),
348: (_('-----------------------------------'), 'show', 'frontend.show_item', True),and this?
349: (_('Copy Item'), 'copy', 'frontend.copy_item', False, ),
350: (_('Rename Item'), 'rename', 'frontend.rename_item', False, ),
351: (_('Delete Item'), 'delete', 'frontend.delete_item', False, ),
352: (_('Destroy Item'), 'destroy', 'frontend.destroy_item', False, ),
363: text = _('anonymous') # link textAnswer:
<kennym> and this one: _('-----------------------------------')
<kennym> is there any reason to localize dashes?
<dreimark> where did you find that?
<kennym> dreimark: http://moinmo.in/KennyMeyer/Notes#MoinMoin.2BAC8-themes
<kennym> dreimark: in MoinMoin/themes/__init__.py
<dreimark> ThomasWaldmann: http://hg.moinmo.in/moin/2.0-dev/annotate/edc4268a45db/MoinMoin/theme/__init__.py#l437
<dreimark> kennym: it is not needed.Fixed.
This has to be there. Reverted.
MoinMoin/templates:
- sitemap.html
Was SiteMap written together intentionally?
MoinMoin/util
paramparser.py
311: _('Argument "%(name)s" must be a boolean value, not "%(value)s"', name=name, value=arg))
314: _('Argument must be a boolean value, not "%(value)s"', value=arg))
340: _('Argument "%(name)s" must be an integer value, not "%(value)s"', name=name, value=arg))
343: _('Argument must be an integer value, not "%(value)s"', value=arg))
368: _('Argument "%(name)s" must be a floating point value, not "%(value)s"', name=name, value=arg))
371: _('Argument must be a floating point value, not "%(value)s"', value=arg))
398: _('Argument "%(name)s" must be a complex value, not "%(value)s"', name=name, value=arg))
401: _('Argument must be a complex value, not "%(value)s"', value=arg))
453: _('Argument "%(name)s" must be one of "%(choices)s", not "%(value)s"',
459: _('Argument must be one of "%(choices)s", not "%(value)s"',
685: raise ValueError(_('Too many arguments'))
690: raise ValueError(_('Cannot have arguments without name following'
706: raise ValueError(_('Argument "%(name)s" is required', name=argname))Nothing to do.
contrib/
No results.
Iteration #2
Check for untranslated strings.
TODO
MoinMoin/apps
Looks OK.
MoinMoin/auth
Also, looks OK.
MoinMoin/config
diff -r 6a47b7bfe7ef MoinMoin/config/default.py
--- a/MoinMoin/config/default.py Sat Dec 25 11:10:13 2010 -0300
+++ b/MoinMoin/config/default.py Sat Dec 25 13:34:15 2010 -0300
@@ -80,9 +80,9 @@
self.cache.item_template_regexact = re.compile(u'^%s$' % self.item_template_regex, re.UNICODE)
if not isinstance(self.superusers, list):
- msg = """The superusers setting in your wiki configuration is not a list
- (e.g. ['Sample User', 'AnotherUser']).
- Please change it in your wiki configuration and try again."""
+ msg = _("""The superusers setting in your wiki configuration is not
+ a list (e.g. ['Sample User', 'AnotherUser']). Please change
+ it in your wiki configuration and try again.""")
raise error.ConfigurationError(msg)
MoinMoin/converter
Looks OK.
MoinMoin/datastructs
Looks OK.
MoinMoin/filter
Looks OK.
MoinMoin/items
Not sure if these have to be i18nised:
https://bitbucket.org/km0r3/moin-2.0-dev/src/6a47b7bfe7ef/MoinMoin/items/__init__.py#cl-651
https://bitbucket.org/km0r3/moin-2.0-dev/src/6a47b7bfe7ef/MoinMoin/items/__init__.py#cl-653
There are actually more.
diff -r 6a47b7bfe7ef MoinMoin/items/__init__.py
--- a/MoinMoin/items/__init__.py Sat Dec 25 11:10:13 2010 -0300
+++ b/MoinMoin/items/__init__.py Sat Dec 25 14:27:27 2010 -0300
@@ -212,7 +212,9 @@
from MoinMoin.util.tree import moin_page, xlink
input_conv = reg.get(Type(self.mimetype), type_moin_document)
if not input_conv:
- raise TypeError("We cannot handle the conversion from %s to the DOM tree" % self.mimetype)
+ raise TypeError(_("We cannot handle the conversion from \
+ %(mimetype)s to the DOM tree",
+ mimetype=self.mimetype))
link_conv = reg.get(type_moin_document, type_moin_document,
links='extern', url_root=Iri(request.url_root))
smiley_conv = reg.get(type_moin_document, type_moin_document,
@@ -345,7 +347,8 @@
new_rev.write(content)
hash.update(content)
else:
- raise StorageError("unsupported content object: %r" % content)
+ raise StorageError(_("unsupported content object: %(content)r",
+ content=content))
return hash_name, unicode(hash.hexdigest())
def copy(self, name, comment=u''):
@@ -648,15 +651,17 @@
def _render_data_diff(self, oldrev, newrev):
hash_name = app.cfg.hash_algorithm
if oldrev[hash_name] == newrev[hash_name]:
- return "The items have the same data hash code (that means they very likely have the same data)."
+ return _("The items have the same data hash code (that means they \
+ very likely have the same data).")
else:
- return "The items have different data."
+ return _("The items have different data.")
_render_data_diff_text = _render_data_diff
_render_data_diff_raw = _render_data_diff
def _convert(self):
- return "Impossible to convert the data to the mimetype : %s" % request.values.get('mimetype')
+ return _("Impossible to convert the data to the mimetype :\
+ %(mimetype)s", mimetype=request.values.get('mimetype'))
def do_get(self):
hash = self.rev.get(app.cfg.hash_algorithm)
@@ -745,7 +750,10 @@
@param expected_members: set of expected member file names
"""
if not name in expected_members:
- raise StorageError("tried to add unexpected member %r to container item %r" % (name, self.name))
+ raise StorageError(_("tried to add unexpected member %(unexp_name)r to \
+ container item %(name)r",
+ unexp_name=name,
+ name=self.name))
if isinstance(name, unicode):
name = name.encode('utf-8')
temp_fname = os.path.join(tempfile.gettempdir(), 'TarContainer_' +
@@ -758,14 +766,15 @@
content = StringIO(content) # we need a file obj
elif not hasattr(content, 'read'):
logging.error("unsupported content object: %r" % content)
- raise StorageError("unsupported content object: %r" % content)
+ raise StorageError(_("unsupported content object: %(content)r",
+ content=content)
assert content_length >= 0 # we don't want -1 interpreted as 4G-1
ti.size = content_length
tf.addfile(ti, content)
tf_members = set(tf.getnames())
tf.close()
if tf_members - expected_members:
- msg = "found unexpected members in container item %r" % (self.name, )
+ msg = _("found unexpected members in container item %(item)r", item=self.name)
logging.error(msg)
os.remove(temp_fname)
raise StorageError(msg)
@@ -873,7 +882,7 @@
elif content_type == 'image/gif':
output_type = 'GIF'
else:
- raise ValueError("content_type %r not supported" % content_type)
+ raise ValueError(_("content_type %(content_type)r not supported", content_type=content_type))
# revision obj has read() seek() tell(), thus this works:
image = PILImage.open(self.rev)
@@ -970,7 +979,8 @@
elif content_type == 'image/gif':
output_type = 'GIF'
else:
- raise ValueError("content_type %r not supported" % content_type)
+ raise ValueError(_("content_type %(content_type)r not supported",
+ content_type=content_type))
oldimage = PILImage.open(oldrev)
newimage = PILImage.open(newrev)
diff -r 6a47b7bfe7ef MoinMoin/macro/Anchor.py
--- a/MoinMoin/macro/Anchor.py Sat Dec 25 11:10:13 2010 -0300
+++ b/MoinMoin/macro/Anchor.py Sat Dec 25 14:27:27 2010 -0300
@@ -12,7 +12,7 @@
class Macro(MacroInlineBase):
def macro(self, anchor=unicode):
if not anchor:
- raise ValueError("Anchor: you need to give an anchor name.")
+ raise ValueError("Anchor: you need to specify an anchor name.")
return moin_page.span(attrib={moin_page.id: anchor})
diff -r 6a47b7bfe7ef MoinMoin/mail/sendmail.py
--- a/MoinMoin/mail/sendmail.py Sat Dec 25 11:10:13 2010 -0300
+++ b/MoinMoin/mail/sendmail.py Sat Dec 25 14:27:27 2010 -0300
@@ -173,8 +173,8 @@
logging.exception("sendmail failed with an exception.")
return (0, _("Mail not sent"))
- logging.debug("Mail sent OK")
- return (1, _("Mail sent OK"))
+ logging.debug("Mail sent successfully")
+ return (1, _("Mail sent sucessfully"))
def encodeSpamSafeEmail(email_address, obfuscation_text=''):
""" Encodes a standard email address to an obfuscated address
MoinMoin/macro
There are also some strings I am not sure of if they have to be i18nised.
MoinMoin/mail
diff -r 6a47b7bfe7ef MoinMoin/mail/sendmail.py --- a/MoinMoin/mail/sendmail.py Sat Dec 25 11:10:13 2010 -0300 +++ b/MoinMoin/mail/sendmail.py Sat Dec 25 14:10:58 2010 -0300 @@ -173,8 +173,8 @@
- logging.exception("sendmail failed with an exception.") return (0, _("Mail not sent"))
- logging.debug("Mail sent OK") - return (1, _("Mail sent OK")) + logging.debug("Mail sent successfully") + return (1, _("Mail sent sucessfully"))
MoinMoin/script
<ThomasWaldmann> kennym: no don't i18n commandline. this is admin stuff, admins know english.
MoinMoin/search
--- a/MoinMoin/search/queryparser/__init__.py Sat Dec 25 11:10:13 2010 -0300
+++ b/MoinMoin/search/queryparser/__init__.py Sat Dec 25 14:42:24 2010 -0300
@@ -15,6 +15,7 @@
from MoinMoin import log
logging = log.getLogger(__name__)
+from MoinMoin import _, N_
from MoinMoin import config
from MoinMoin.util.paramparser import parse_quoted_separated_ext, ParserPrefix, BracketError
from MoinMoin.search.queryparser.expressions import AndExpression, OrExpression, TextSearch, TitleSearch, \
@@ -61,7 +62,7 @@
orexpr = OrExpression(terms)
terms = AndExpression(orexpr)
else:
- raise QueryError('Nothing to OR')
+ raise QueryError(_('Nothing to OR'))
remaining = self._analyse_items(items)
if remaining.__class__ == OrExpression:
for sub in remaining.subterms():
@@ -77,7 +78,7 @@
# being parsed rather than rejecting an empty string
# before parsing...
if not item:
- raise QueryError("Term too short")
+ raise QueryError(_("Term too short"))
regex = self.regex
case = self.case
if self.titlesearch:
@@ -97,7 +98,7 @@
while len(item) > 1:
m = item[0]
if m is None:
- raise QueryError("Invalid search prefix")
+ raise QueryError(_("Invalid search prefix"))
elif m == M:
negate = True
elif "title".startswith(m):
@@ -117,7 +118,7 @@
elif "domain".startswith(m):
domain = True
else:
- raise QueryError("Invalid search prefix")
+ raise QueryError(_("Invalid search prefix"))
item = item[1:]
text = item[0]
MoinMoin/security
diff -r 6a47b7bfe7ef MoinMoin/security/__init__.py
--- a/MoinMoin/security/__init__.py Sat Dec 25 11:10:13 2010 -0300
+++ b/MoinMoin/security/__init__.py Sat Dec 25 14:47:22 2010 -0300
@@ -23,6 +23,7 @@
from flask import flaskg
+from MoinMoin import _, N_
from MoinMoin import user
@@ -343,7 +344,7 @@
entries, self.rest = self.rest.split(':', 1)
except ValueError:
self.finished = 1
- raise StopIteration("Can't parse rest of string")
+ raise StopIteration(_("Can't parse rest of string"))
if entries == '':
entries = []
else:
diff -r 6a47b7bfe7ef MoinMoin/security/textcha.py
--- a/MoinMoin/security/textcha.py Sat Dec 25 11:10:13 2010 -0300
+++ b/MoinMoin/security/textcha.py Sat Dec 25 14:47:22 2010 -0300
@@ -40,7 +40,7 @@
from flatland import Form, String
from flatland.validation import Validator
-from MoinMoin import _
+from MoinMoin import _, N_
SHA1_LEN = 40 # length of hexdigest
TIMESTAMP_LEN = 10 # length of timestamp
@@ -180,4 +180,4 @@
class TextChaizedForm(Form):
"""a form providing TextCha support"""
textcha_question = String
- textcha = String.using(label=_('TextCha')).validated_by(TextChaValid())
+ textcha = String.using(label=N_('TextCha')).validated_by(TextChaValid())
MoinMoin/signalling
Looks OK.
MoinMoin/static
Looks OK.
MoinMoin/storage
Looks OK.
MoinMoin/support
3rd party libraries. Don't touch.
MoinMoin/templates
A lot of changes. Updated to newstyle-gettext.
MoinMoin/util
Looks OK.
