mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
merge with DasIch/sphinx-i18n
This commit is contained in:
@@ -6,9 +6,8 @@ Internationalization
|
|||||||
.. versionadded:: 1.1
|
.. versionadded:: 1.1
|
||||||
|
|
||||||
Complementary to translations provided for Sphinx-generated messages such as
|
Complementary to translations provided for Sphinx-generated messages such as
|
||||||
navigation bars Sphinx provides mechanisms facilitating *document* translations
|
navigation bars, Sphinx provides mechanisms facilitating *document* translations
|
||||||
in itself. It relies on the existing configuration values :confval:`language`
|
in itself. It relies on the existing configuration values :confval:`language`
|
||||||
and :confval:`locale_dirs`.
|
and :confval:`locale_dirs`.
|
||||||
|
|
||||||
|
|
||||||
.. XXX write more!
|
.. XXX write more!
|
||||||
|
|||||||
@@ -5,17 +5,19 @@
|
|||||||
|
|
||||||
The MessageCatalogBuilder class.
|
The MessageCatalogBuilder class.
|
||||||
|
|
||||||
:copyright: Copyright 2010 by the Sphinx team, see AUTHORS.
|
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||||
:license: BSD, see LICENSE for details.
|
:license: BSD, see LICENSE for details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import collections
|
|
||||||
from datetime import datetime
|
|
||||||
from os import path
|
from os import path
|
||||||
|
from codecs import open
|
||||||
|
from datetime import datetime
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
from sphinx.builders import Builder
|
from sphinx.builders import Builder
|
||||||
|
from sphinx.builders.versioning import VersioningBuilderMixin
|
||||||
from sphinx.util.nodes import extract_messages
|
from sphinx.util.nodes import extract_messages
|
||||||
from sphinx.util.osutil import SEP
|
from sphinx.util.osutil import SEP, copyfile
|
||||||
from sphinx.util.console import darkgreen
|
from sphinx.util.console import darkgreen
|
||||||
|
|
||||||
POHEADER = ur"""
|
POHEADER = ur"""
|
||||||
@@ -39,14 +41,17 @@ msgstr ""
|
|||||||
|
|
||||||
"""[1:]
|
"""[1:]
|
||||||
|
|
||||||
class MessageCatalogBuilder(Builder):
|
|
||||||
|
class I18nBuilder(Builder, VersioningBuilderMixin):
|
||||||
"""
|
"""
|
||||||
Builds gettext-style message catalogs (.pot files).
|
General i18n builder.
|
||||||
"""
|
"""
|
||||||
name = 'gettext'
|
name = 'i18n'
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
self.catalogs = collections.defaultdict(list)
|
Builder.init(self)
|
||||||
|
VersioningBuilderMixin.init(self)
|
||||||
|
self.catalogs = defaultdict(dict)
|
||||||
|
|
||||||
def get_target_uri(self, docname, typ=None):
|
def get_target_uri(self, docname, typ=None):
|
||||||
return ''
|
return ''
|
||||||
@@ -58,18 +63,26 @@ class MessageCatalogBuilder(Builder):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def write_doc(self, docname, doctree):
|
def write_doc(self, docname, doctree):
|
||||||
"""
|
|
||||||
Store a document's translatable strings in the message catalog of its
|
|
||||||
section. For this purpose a document's *top-level directory* -- or
|
|
||||||
otherwise its *name* -- is considered its section.
|
|
||||||
"""
|
|
||||||
catalog = self.catalogs[docname.split(SEP, 1)[0]]
|
catalog = self.catalogs[docname.split(SEP, 1)[0]]
|
||||||
for _, msg in extract_messages(doctree):
|
|
||||||
# XXX msgctxt for duplicate messages
|
self.handle_versioning(docname, doctree, nodes.TextElement)
|
||||||
if msg not in catalog:
|
|
||||||
catalog.append(msg)
|
for node, msg in extract_messages(doctree):
|
||||||
|
catalog.setdefault(node.uid, msg)
|
||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
|
Builder.finish(self)
|
||||||
|
VersioningBuilderMixin.finish(self)
|
||||||
|
|
||||||
|
|
||||||
|
class MessageCatalogBuilder(I18nBuilder):
|
||||||
|
"""
|
||||||
|
Builds gettext-style message catalogs (.pot files).
|
||||||
|
"""
|
||||||
|
name = 'gettext'
|
||||||
|
|
||||||
|
def finish(self):
|
||||||
|
I18nBuilder.finish(self)
|
||||||
data = dict(
|
data = dict(
|
||||||
version = self.config.version,
|
version = self.config.version,
|
||||||
copyright = self.config.copyright,
|
copyright = self.config.copyright,
|
||||||
@@ -81,13 +94,15 @@ class MessageCatalogBuilder(Builder):
|
|||||||
self.catalogs.iteritems(), "writing message catalogs... ",
|
self.catalogs.iteritems(), "writing message catalogs... ",
|
||||||
lambda (section, _):darkgreen(section), len(self.catalogs)):
|
lambda (section, _):darkgreen(section), len(self.catalogs)):
|
||||||
|
|
||||||
pofile = open(path.join(self.outdir, '%s.pot' % section), 'w')
|
pofn = path.join(self.outdir, section + '.pot')
|
||||||
|
pofile = open(pofn, 'w', encoding='utf-8')
|
||||||
try:
|
try:
|
||||||
pofile.write(POHEADER % data)
|
pofile.write(POHEADER % data)
|
||||||
for message in messages:
|
for uid, message in messages.iteritems():
|
||||||
# message contains *one* line of text ready for translation
|
# message contains *one* line of text ready for translation
|
||||||
message = message.replace(u'\\', ur'\\').replace(u'"', ur'\"')
|
message = message.replace(u'\\', ur'\\'). \
|
||||||
pomsg = u'msgid "%s"\nmsgstr ""\n\n' % message
|
replace(u'"', ur'\"')
|
||||||
pofile.write(pomsg.encode('utf-8'))
|
pomsg = u'#%s\nmsgid "%s"\nmsgstr ""\n\n' % (uid, message)
|
||||||
|
pofile.write(pomsg)
|
||||||
finally:
|
finally:
|
||||||
pofile.close()
|
pofile.close()
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ class Locale(Transform):
|
|||||||
# XXX ctx not used
|
# XXX ctx not used
|
||||||
#ctx = node.parent
|
#ctx = node.parent
|
||||||
patch = new_document(source, settings)
|
patch = new_document(source, settings)
|
||||||
msgstr = catalog.ugettext(msg)
|
msgstr = catalog.gettext(msg)
|
||||||
# XXX add marker to untranslated parts
|
# XXX add marker to untranslated parts
|
||||||
if not msgstr or msgstr == msg: # as-of-yet untranslated
|
if not msgstr or msgstr == msg: # as-of-yet untranslated
|
||||||
continue
|
continue
|
||||||
@@ -793,6 +793,7 @@ class BuildEnvironment:
|
|||||||
if node['level'] < filterlevel:
|
if node['level'] < filterlevel:
|
||||||
node.parent.remove(node)
|
node.parent.remove(node)
|
||||||
|
|
||||||
|
|
||||||
def process_dependencies(self, docname, doctree):
|
def process_dependencies(self, docname, doctree):
|
||||||
"""
|
"""
|
||||||
Process docutils-generated dependency info.
|
Process docutils-generated dependency info.
|
||||||
|
|||||||
@@ -218,4 +218,6 @@ def init(locale_dirs, language, catalog='sphinx'):
|
|||||||
translator = gettext.NullTranslations()
|
translator = gettext.NullTranslations()
|
||||||
has_translation = False
|
has_translation = False
|
||||||
translators[catalog] = translator
|
translators[catalog] = translator
|
||||||
|
if hasattr(translator, 'ugettext'):
|
||||||
|
translator.gettext = translator.ugettext
|
||||||
return translator, has_translation
|
return translator, has_translation
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ def test_gettext(app):
|
|||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
print stdout
|
print stdout
|
||||||
print stderr
|
print stderr
|
||||||
assert False, 'msginit exited with return code %s' % p.returncode
|
assert False, 'msginit exited with return code %s' % \
|
||||||
|
p.returncode
|
||||||
assert (app.outdir / 'en_US.po').isfile(), 'msginit failed'
|
assert (app.outdir / 'en_US.po').isfile(), 'msginit failed'
|
||||||
try:
|
try:
|
||||||
p = Popen(['msgfmt', 'en_US.po', '-o',
|
p = Popen(['msgfmt', 'en_US.po', '-o',
|
||||||
@@ -59,12 +60,14 @@ def test_gettext(app):
|
|||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
print stdout
|
print stdout
|
||||||
print stderr
|
print stderr
|
||||||
assert False, 'msgfmt exited with return code %s' % p.returncode
|
assert False, 'msgfmt exited with return code %s' % \
|
||||||
assert (app.outdir / 'en' / 'LC_MESSAGES' / 'test_root.mo').isfile(), 'msgfmt failed'
|
p.returncode
|
||||||
|
assert (app.outdir / 'en' / 'LC_MESSAGES' / 'test_root.mo').isfile(), \
|
||||||
|
'msgfmt failed'
|
||||||
finally:
|
finally:
|
||||||
os.chdir(cwd)
|
os.chdir(cwd)
|
||||||
|
|
||||||
_ = gettext.translation('test_root', app.outdir, languages=['en']).ugettext
|
_ = gettext.translation('test_root', app.outdir, languages=['en']).gettext
|
||||||
assert _("Testing various markup") == u"Testing various markup"
|
assert _("Testing various markup") == u"Testing various markup"
|
||||||
|
|
||||||
@with_app(buildername='gettext')
|
@with_app(buildername='gettext')
|
||||||
@@ -95,7 +98,9 @@ def setup_patch():
|
|||||||
print stdout
|
print stdout
|
||||||
print stderr
|
print stderr
|
||||||
assert False, 'msgfmt exited with return code %s' % p.returncode
|
assert False, 'msgfmt exited with return code %s' % p.returncode
|
||||||
assert (test_root / 'xx' / 'LC_MESSAGES' / 'bom.mo').isfile(), 'msgfmt failed'
|
assert (test_root / 'xx' / 'LC_MESSAGES' / 'bom.mo').isfile(), \
|
||||||
|
'msgfmt failed'
|
||||||
|
|
||||||
def teardown_patch():
|
def teardown_patch():
|
||||||
(test_root / 'xx').rmtree()
|
(test_root / 'xx').rmtree()
|
||||||
test_patch.setup = setup_patch
|
test_patch.setup = setup_patch
|
||||||
|
|||||||
Reference in New Issue
Block a user