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 text
Answer:
<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.