Georg Brandl avatar Georg Brandl committed 37f6191

Use a new "lazy" gettext function instead of using dummy _() to help text extraction.

Comments (0)

Files changed (4)

sphinx/builders/__init__.py

         Load translated strings from the configured localedirs if
         enabled in the configuration.
         """
-        self.translator = None
         if self.config.language is not None:
             self.info(bold('loading translations [%s]... ' %
                            self.config.language), nonl=True)
-            # the None entry is the system's default locale path
             locale_dirs = [None, path.join(package_dir, 'locale')] + \
                 [path.join(self.srcdir, x) for x in self.config.locale_dirs]
-            for dir_ in locale_dirs:
-                try:
-                    trans = gettext.translation('sphinx', localedir=dir_,
-                            languages=[self.config.language])
-                    if self.translator is None:
-                        self.translator = trans
-                    else:
-                        self.translator._catalog.update(trans.catalog)
-                except Exception:
-                    # Language couldn't be found in the specified path
-                    pass
-            if self.translator is not None:
+        self.translator, has_translation = locale.init(locale_dirs,
+                                                       self.config.language)
+        if self.config.language is not None:
+            if has_translation:
                 self.info('done')
             else:
                 self.info('locale not available')
-        if self.translator is None:
-            self.translator = gettext.NullTranslations()
-        self.translator.install(unicode=True)
-        locale.init()  # translate common labels
 
     def load_env(self):
         """Set up the build environment."""
         latex_docclass = ({}, None),
         # now deprecated - use latex_elements
         latex_preamble = ('', None),
+
+        # text options
+        text_sectionchars = ('*=-~"+`', 'text'),
+        text_windows_newlines = (False, 'text'),
     )
 
     def __init__(self, dirname, filename, overrides, tags):

sphinx/directives/desc.py

 
 from sphinx import addnodes
 from sphinx.domains import Domain, domains
+from sphinx.locale import l_
 from sphinx.util import ws_re
 from sphinx.util.compat import Directive, directive_dwim
 
         'module': directives.unchanged,
     }
 
-    _ = lambda x: x  # make gettext extraction in constants possible
-
     doc_fields_with_arg = {
         'param': '%param',
         'parameter': '%param',
         'kwarg': '%param',
         'kwparam': '%param',
         'type': '%type',
-        'raises': _('Raises'),
-        'raise': 'Raises',
-        'exception': 'Raises',
-        'except': 'Raises',
-        'var': _('Variable'),
-        'ivar': 'Variable',
-        'cvar': 'Variable',
-        'returns': _('Returns'),
-        'return': 'Returns',
+        'raises': l_('Raises'),
+        'raise': l_('Raises'),
+        'exception': l_('Raises'),
+        'except': l_('Raises'),
+        'var': l_('Variable'),
+        'ivar': l_('Variable'),
+        'cvar': l_('Variable'),
+        'returns': l_('Returns'),
+        'return': l_('Returns'),
     }
 
     doc_fields_with_linked_arg = ('raises', 'raise', 'exception', 'except')
 
     doc_fields_without_arg = {
-        'returns': 'Returns',
-        'return': 'Returns',
-        'rtype': _('Return type'),
+        'returns': l_('Returns'),
+        'return': l_('Returns'),
+        'rtype': l_('Return type'),
     }
 
     def handle_doc_fields(self, node):
                 fname, fbody = field
                 try:
                     typ, obj = fname.astext().split(None, 1)
-                    typdesc = _(self.doc_fields_with_arg[typ])
+                    typdesc = self.doc_fields_with_arg[typ]
                     if _is_only_paragraph(fbody):
                         children = fbody.children[0].children
                     else:
                 except (KeyError, ValueError):
                     fnametext = fname.astext()
                     try:
-                        typ = _(self.doc_fields_without_arg[fnametext])
+                        typ = self.doc_fields_without_arg[fnametext]
                     except KeyError:
                         # at least capitalize the field name
                         typ = fnametext.capitalize()
                 clsname, methname = name.rsplit('.', 1)
             except ValueError:
                 if modname:
-                    return '%s() (in module %s)' % (name, modname)
+                    return _('%s() (in module %s)') % (name, modname)
                 else:
                     return '%s()' % name
             if modname:
-                return '%s() (%s.%s class method)' % (methname, modname,
-                                                      clsname)
+                return _('%s() (%s.%s class method)') % (methname, modname,
+                                                         clsname)
             else:
-                return '%s() (%s class method)' % (methname, clsname)
+                return _('%s() (%s class method)') % (methname, clsname)
         elif self.desctype == 'attribute':
             try:
                 clsname, attrname = name.rsplit('.', 1)
         signode['ids'].append(targetname)
         self.state.document.note_explicit_target(signode)
         if indextemplate:
-            indexentry = _(indextemplate) % (name,)
+            indexentry = indextemplate % (name,)
             indextype = 'single'
             colon = indexentry.find(':')
             if colon != -1:
 # Note: the target directive is not registered here, it is used by the
 # application when registering additional xref types.
 
-_ = lambda x: x
-
 # Generic cross-reference types; they can be registered in the application;
 # the directives are either desc_directive or target_directive.
 additional_xref_types = {
     # directive name: (role name, index text, function to parse the desc node)
-    'envvar': ('envvar', _('environment variable; %s'), None),
+    'envvar': ('envvar', l_('environment variable; %s'), None),
 }
 
-del _
-
 
 directives.register_directive('default-domain', directive_dwim(DefaultDomain))
 directives.register_directive('describe', directive_dwim(DescDirective))

sphinx/locale/__init__.py

     :copyright: Copyright 2007-2009 by the Sphinx team, see AUTHORS.
     :license: BSD, see LICENSE for details.
 """
+import gettext
+import UserString
 
-_ = lambda x: x
+from sphinx import package_dir
+
+
+class _TranslationProxy(UserString.UserString, object):
+    """Class for proxy strings from gettext translations.  This is a helper
+    for the lazy_* functions from this module.
+
+    The proxy implementation attempts to be as complete as possible, so that
+    the lazy objects should mostly work as expected, for example for sorting.
+
+    This inherits from UserString because some docutils versions use UserString
+    for their Text nodes, which then checks its argument for being either a
+    basestring or UserString, otherwise calls str() -- not unicode() -- on it.
+    This also inherits from object to make the __new__ method work.
+    """
+    __slots__ = ('_func', '_args')
+
+    def __new__(cls, func, *args):
+        if not args:
+            # not called with "function" and "arguments", but a plain string
+            return unicode(func)
+        return object.__new__(cls)
+
+    def __init__(self, func, *args):
+        self._func = func
+        self._args = args
+
+    data = property(lambda x: x._func(*x._args))
+
+    def __contains__(self, key):
+        return key in self.data
+
+    def __nonzero__(self):
+        return bool(self.data)
+
+    def __dir__(self):
+        return dir(unicode)
+
+    def __iter__(self):
+        return iter(self.data)
+
+    def __len__(self):
+        return len(self.data)
+
+    def __str__(self):
+        return str(self.data)
+
+    def __unicode__(self):
+        return unicode(self.data)
+
+    def __add__(self, other):
+        return self.data + other
+
+    def __radd__(self, other):
+        return other + self.data
+
+    def __mod__(self, other):
+        return self.data % other
+
+    def __rmod__(self, other):
+        return other % self.data
+
+    def __mul__(self, other):
+        return self.data * other
+
+    def __rmul__(self, other):
+        return other * self.data
+
+    def __lt__(self, other):
+        return self.data < other
+
+    def __le__(self, other):
+        return self.data <= other
+
+    def __eq__(self, other):
+        return self.data == other
+
+    def __ne__(self, other):
+        return self.data != other
+
+    def __gt__(self, other):
+        return self.data > other
+
+    def __ge__(self, other):
+        return self.data >= other
+
+    def __getattr__(self, name):
+        if name == '__members__':
+            return self.__dir__()
+        return getattr(self.data, name)
+
+    def __getstate__(self):
+        return self._func, self._args
+
+    def __setstate__(self, tup):
+        self._func, self._args = tup
+
+    def __getitem__(self, key):
+        return self.data[key]
+
+    def __copy__(self):
+        return self
+
+    def __repr__(self):
+        try:
+            return 'i' + repr(unicode(self.data))
+        except:
+            return '<%s broken>' % self.__class__.__name__
+
+def mygettext(string):
+    """Used instead of _ when creating TranslationProxies, because _ is not bound
+    yet at that time."""
+    return _(string)
+
+def lazy_gettext(string):
+    """A lazy version of `gettext`."""
+    #if isinstance(string, _TranslationProxy):
+    #    return string
+    return _TranslationProxy(mygettext, string)
+
+l_ = lazy_gettext
+
 
 admonitionlabels = {
-    'attention': _('Attention'),
-    'caution':   _('Caution'),
-    'danger':    _('Danger'),
-    'error':     _('Error'),
-    'hint':      _('Hint'),
-    'important': _('Important'),
-    'note':      _('Note'),
-    'seealso':   _('See Also'),
-    'tip':       _('Tip'),
-    'warning':   _('Warning'),
+    'attention': l_('Attention'),
+    'caution':   l_('Caution'),
+    'danger':    l_('Danger'),
+    'error':     l_('Error'),
+    'hint':      l_('Hint'),
+    'important': l_('Important'),
+    'note':      l_('Note'),
+    'seealso':   l_('See Also'),
+    'tip':       l_('Tip'),
+    'warning':   l_('Warning'),
 }
 
 versionlabels = {
-    'versionadded':   _('New in version %s'),
-    'versionchanged': _('Changed in version %s'),
-    'deprecated':     _('Deprecated since version %s'),
+    'versionadded':   l_('New in version %s'),
+    'versionchanged': l_('Changed in version %s'),
+    'deprecated':     l_('Deprecated since version %s'),
 }
 
 pairindextypes = {
-    'module':    _('module'),
-    'keyword':   _('keyword'),
-    'operator':  _('operator'),
-    'object':    _('object'),
-    'exception': _('exception'),
-    'statement': _('statement'),
-    'builtin':   _('built-in function'),
+    'module':    l_('module'),
+    'keyword':   l_('keyword'),
+    'operator':  l_('operator'),
+    'object':    l_('object'),
+    'exception': l_('exception'),
+    'statement': l_('statement'),
+    'builtin':   l_('built-in function'),
 }
 
-del _
 
-def init():
-    for dct in (admonitionlabels, versionlabels, pairindextypes):
-        for key in dct:
-            dct[key] = _(dct[key])
+def init(locale_dirs, language):
+    # the None entry is the system's default locale path
+    translator = None
+    has_translation = True
+    for dir_ in locale_dirs:
+        try:
+            trans = gettext.translation('sphinx', localedir=dir_,
+                    languages=[language])
+            if translator is None:
+                translator = trans
+            else:
+                translator._catalog.update(trans.catalog)
+        except Exception:
+            # Language couldn't be found in the specified path
+            pass
+    if translator is None:
+        translator = gettext.NullTranslations()
+        has_translation = False
+    translator.install(unicode=True)
+    return translator, has_translation
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.