Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Close #10062: Change the default language to 'en' #10067

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGES
Expand Up @@ -21,12 +21,18 @@ Incompatible changes
intersphinx should resolve, or explicitly set the value of this configuration
variable to an empty list.
* #9999: LaTeX: separate terms from their definitions by a CR (refs: #9985)
* #10062: Change the default language to ``'en'`` if any language is not set in
``conf.py``

Deprecated
----------

* setuptools integration. The ``build_sphinx`` sub-command for setup.py is
marked as deprecated to follow the policy of setuptools team.
* The ``locale`` argument of ``sphinx.util.i18n:babel_format_date()`` becomes
required
* The ``language`` argument of ``sphinx.util.i18n:format_date()`` becomes
required
* ``sphinx.writers.latex.LaTeXWriter.docclasses``

Features added
Expand Down
10 changes: 10 additions & 0 deletions doc/extdev/deprecated.rst
Expand Up @@ -27,6 +27,16 @@ The following is a list of deprecated interfaces.
- 7.0
- N/A

* - The ``locale`` argument of ``sphinx.util.i18n:babel_format_date()``
- 5.0
- 7.0
- N/A

* - The ``language`` argument of ``sphinx.util.i18n:format_date()``
- 5.0
- 7.0
- N/A

* - ``sphinx.writers.latex.LaTeXWriter.docclasses``
- 5.0
- 7.0
Expand Down
5 changes: 2 additions & 3 deletions sphinx/application.py
Expand Up @@ -266,7 +266,7 @@ def _init_i18n(self) -> None:
"""Load translated strings from the configured localedirs if enabled in
the configuration.
"""
if self.config.language is None:
if self.config.language == 'en':
self.translator, has_translation = locale.init([], None)
else:
logger.info(bold(__('loading translations [%s]... ') % self.config.language),
Expand All @@ -285,8 +285,7 @@ def _init_i18n(self) -> None:
locale_dirs += [path.join(package_dir, 'locale')]

self.translator, has_translation = locale.init(locale_dirs, self.config.language)
if has_translation or self.config.language == 'en':
# "en" never needs to be translated
if has_translation:
logger.info(__('done'))
else:
logger.info(__('not available for built-in messages'))
Expand Down
11 changes: 4 additions & 7 deletions sphinx/builders/html/__init__.py
Expand Up @@ -326,7 +326,7 @@ def init_js_files(self) -> None:
attrs.setdefault('priority', 800) # User's JSs are loaded after extensions'
self.add_js_file(filename, **attrs)

if self.config.language and self._get_translations_js():
if self._get_translations_js():
self.add_js_file('translations.js')

def add_js_file(self, filename: str, **kwargs: Any) -> None:
Expand Down Expand Up @@ -431,8 +431,6 @@ def prepare_writing(self, docnames: Set[str]) -> None:
if self.search:
from sphinx.search import IndexBuilder
lang = self.config.html_search_language or self.config.language
if not lang:
lang = 'en'
self.indexer = IndexBuilder(self.env, lang,
self.config.html_search_options,
self.config.html_search_scorer)
Expand Down Expand Up @@ -767,10 +765,9 @@ def create_pygments_style_file(self) -> None:

def copy_translation_js(self) -> None:
"""Copy a JavaScript file for translations."""
if self.config.language is not None:
jsfile = self._get_translations_js()
if jsfile:
copyfile(jsfile, path.join(self.outdir, '_static', 'translations.js'))
jsfile = self._get_translations_js()
if jsfile:
copyfile(jsfile, path.join(self.outdir, '_static', 'translations.js'))

def copy_stemmer_js(self) -> None:
"""Copy a JavaScript file for stemmer."""
Expand Down
30 changes: 12 additions & 18 deletions sphinx/builders/latex/__init__.py
Expand Up @@ -170,9 +170,8 @@ def init_context(self) -> None:
self.context.update(ADDITIONAL_SETTINGS.get(self.config.latex_engine, {}))

# Add special settings for (latex_engine, language_code)
if self.config.language:
key = (self.config.latex_engine, self.config.language[:2])
self.context.update(ADDITIONAL_SETTINGS.get(key, {}))
key = (self.config.latex_engine, self.config.language[:2])
self.context.update(ADDITIONAL_SETTINGS.get(key, {}))

# Apply user settings to context
self.context.update(self.config.latex_elements)
Expand Down Expand Up @@ -203,7 +202,7 @@ def update_context(self) -> None:

def init_babel(self) -> None:
self.babel = ExtBabel(self.config.language, not self.context['babel'])
if self.config.language and not self.babel.is_supported_language():
if not self.babel.is_supported_language():
# emit warning if specified language is invalid
# (only emitting, nothing changed to processing)
logger.warning(__('no Babel option known for language %r'),
Expand Down Expand Up @@ -232,12 +231,11 @@ def init_multilingual(self) -> None:
self.context['classoptions'] += ',' + self.babel.get_language()
# this branch is not taken for xelatex/lualatex if default settings
self.context['multilingual'] = self.context['babel']
if self.config.language:
self.context['shorthandoff'] = SHORTHANDOFF
self.context['shorthandoff'] = SHORTHANDOFF

# Times fonts don't work with Cyrillic languages
if self.babel.uses_cyrillic() and 'fontpkg' not in self.config.latex_elements:
self.context['fontpkg'] = ''
# Times fonts don't work with Cyrillic languages
if self.babel.uses_cyrillic() and 'fontpkg' not in self.config.latex_elements:
self.context['fontpkg'] = ''
elif self.context['polyglossia']:
self.context['classoptions'] += ',' + self.babel.get_language()
options = self.babel.get_mainlanguage_options()
Expand Down Expand Up @@ -380,14 +378,10 @@ def copy_support_files(self) -> None:
# configure usage of xindy (impacts Makefile and latexmkrc)
# FIXME: convert this rather to a confval with suitable default
# according to language ? but would require extra documentation
if self.config.language:
xindy_lang_option = \
XINDY_LANG_OPTIONS.get(self.config.language[:2],
'-L general -C utf8 ')
xindy_cyrillic = self.config.language[:2] in XINDY_CYRILLIC_SCRIPTS
else:
xindy_lang_option = '-L english -C utf8 '
xindy_cyrillic = False
xindy_lang_option = XINDY_LANG_OPTIONS.get(self.config.language[:2],
'-L general -C utf8 ')
xindy_cyrillic = self.config.language[:2] in XINDY_CYRILLIC_SCRIPTS

context = {
'latex_engine': self.config.latex_engine,
'xindy_use': self.config.latex_use_xindy,
Expand Down Expand Up @@ -474,7 +468,7 @@ def default_latex_engine(config: Config) -> str:
""" Better default latex_engine settings for specific languages. """
if config.language == 'ja':
return 'uplatex'
elif (config.language or '').startswith('zh'):
elif config.language.startswith('zh'):
return 'xelatex'
elif config.language == 'el':
return 'xelatex'
Expand Down
2 changes: 1 addition & 1 deletion sphinx/builders/latex/util.py
Expand Up @@ -20,7 +20,7 @@ def __init__(self, language_code: str, use_polyglossia: bool = False) -> None:
self.language_code = language_code
self.use_polyglossia = use_polyglossia
self.supported = True
super().__init__(language_code or '')
super().__init__(language_code)

def uses_cyrillic(self) -> bool:
return self.language in self.cyrillic_languages
Expand Down
2 changes: 1 addition & 1 deletion sphinx/config.py
Expand Up @@ -100,7 +100,7 @@ class Config:
# the real default is locale-dependent
'today_fmt': (None, 'env', [str]),

'language': (None, 'env', [str]),
'language': ('en', 'env', [str]),
'locale_dirs': (['locales'], 'env', []),
'figure_language_filename': ('{root}.{language}{ext}', 'env', [str]),
'gettext_allow_fuzzy_translations': (False, 'gettext', []),
Expand Down
2 changes: 1 addition & 1 deletion sphinx/environment/__init__.py
Expand Up @@ -261,7 +261,7 @@ def _update_settings(self, config: Config) -> None:
"""Update settings by new config."""
self.settings['input_encoding'] = config.source_encoding
self.settings['trim_footnote_reference_space'] = config.trim_footnote_reference_space
self.settings['language_code'] = config.language or 'en'
self.settings['language_code'] = config.language

# Allow to disable by 3rd party extension (workaround)
self.settings.setdefault('smart_quotes', True)
Expand Down
16 changes: 7 additions & 9 deletions sphinx/environment/collectors/asset.py
Expand Up @@ -64,18 +64,16 @@ def process_doc(self, app: Sphinx, doctree: nodes.document) -> None:
rel_imgpath, full_imgpath = app.env.relfn2path(imguri, docname)
node['uri'] = rel_imgpath

if app.config.language:
# Search language-specific figures at first
i18n_imguri = get_image_filename_for_language(imguri, app.env)
_, full_i18n_imgpath = app.env.relfn2path(i18n_imguri, docname)
self.collect_candidates(app.env, full_i18n_imgpath, candidates, node)
# Search language-specific figures at first
i18n_imguri = get_image_filename_for_language(imguri, app.env)
_, full_i18n_imgpath = app.env.relfn2path(i18n_imguri, docname)
self.collect_candidates(app.env, full_i18n_imgpath, candidates, node)

self.collect_candidates(app.env, full_imgpath, candidates, node)
else:
if app.config.language:
# substitute imguri by figure_language_filename
# (ex. foo.png -> foo.en.png)
imguri = search_image_for_language(imguri, app.env)
# substitute imguri by figure_language_filename
# (ex. foo.png -> foo.en.png)
imguri = search_image_for_language(imguri, app.env)

# Update `node['uri']` to a relative path from srcdir
# from a relative path from current document.
Expand Down
21 changes: 12 additions & 9 deletions sphinx/util/i18n.py
Expand Up @@ -10,14 +10,16 @@

import os
import re
import warnings
from datetime import datetime, timezone
from os import path
from typing import TYPE_CHECKING, Callable, Generator, List, NamedTuple, Optional, Tuple, Union
from typing import TYPE_CHECKING, Callable, Generator, List, NamedTuple, Tuple, Union

import babel.dates
from babel.messages.mofile import write_mo
from babel.messages.pofile import read_po

from sphinx.deprecation import RemovedInSphinx70Warning
from sphinx.errors import SphinxError
from sphinx.locale import __
from sphinx.util import logging
Expand Down Expand Up @@ -173,9 +175,11 @@ def docname_to_domain(docname: str, compaction: Union[bool, str]) -> str:
date_format_re = re.compile('(%s)' % '|'.join(date_format_mappings))


def babel_format_date(date: datetime, format: str, locale: Optional[str],
def babel_format_date(date: datetime, format: str, locale: str,
formatter: Callable = babel.dates.format_date) -> str:
if locale is None:
warnings.warn('The locale argument for babel_format_date() becomes required.',
RemovedInSphinx70Warning)
locale = 'en'

# Check if we have the tzinfo attribute. If not we cannot do any time
Expand All @@ -194,7 +198,7 @@ def babel_format_date(date: datetime, format: str, locale: Optional[str],
return format


def format_date(format: str, date: datetime = None, language: Optional[str] = None) -> str:
def format_date(format: str, date: datetime = None, language: str = None) -> str:
if date is None:
# If time is not specified, try to use $SOURCE_DATE_EPOCH variable
# See https://wiki.debian.org/ReproducibleBuilds/TimestampsProposal
Expand All @@ -204,6 +208,11 @@ def format_date(format: str, date: datetime = None, language: Optional[str] = No
else:
date = datetime.now(timezone.utc).astimezone()

if language is None:
warnings.warn('The language argument for format_date() becomes required.',
RemovedInSphinx70Warning)
language = 'en'

result = []
tokens = date_format_re.split(format)
for token in tokens:
Expand All @@ -229,9 +238,6 @@ def format_date(format: str, date: datetime = None, language: Optional[str] = No


def get_image_filename_for_language(filename: str, env: "BuildEnvironment") -> str:
if not env.config.language:
return filename

filename_format = env.config.figure_language_filename
d = dict()
d['root'], d['ext'] = path.splitext(filename)
Expand All @@ -252,9 +258,6 @@ def get_image_filename_for_language(filename: str, env: "BuildEnvironment") -> s


def search_image_for_language(filename: str, env: "BuildEnvironment") -> str:
if not env.config.language:
return filename

translated = get_image_filename_for_language(filename, env)
_, abspath = env.relfn2path(translated)
if path.exists(abspath):
Expand Down
4 changes: 2 additions & 2 deletions sphinx/writers/latex.py
Expand Up @@ -333,15 +333,15 @@ def __init__(self, document: nodes.document, builder: "LaTeXBuilder",
if self.config.numfig and self.config.math_numfig:
sphinxpkgoptions.append('mathnumfig')

if (self.config.language not in {None, 'en', 'ja'} and
if (self.config.language not in {'en', 'ja'} and
'fncychap' not in self.config.latex_elements):
# use Sonny style if any language specified (except English)
self.elements['fncychap'] = (r'\usepackage[Sonny]{fncychap}' + CR +
r'\ChNameVar{\Large\normalfont\sffamily}' + CR +
r'\ChTitleVar{\Large\normalfont\sffamily}')

self.babel = self.builder.babel
if self.config.language and not self.babel.is_supported_language():
if not self.babel.is_supported_language():
# emit warning if specified language is invalid
# (only emitting, nothing changed to processing)
logger.warning(__('no Babel option known for language %r'),
Expand Down
2 changes: 1 addition & 1 deletion tests/test_build_latex.py
Expand Up @@ -528,7 +528,7 @@ def test_babel_with_no_language_settings(app, status, warning):
assert '\\usepackage[Bjarne]{fncychap}' in result
assert ('\\addto\\captionsenglish{\\renewcommand{\\contentsname}{Table of content}}\n'
in result)
assert '\\shorthandoff' not in result
assert '\\shorthandoff{"}' in result

# sphinxmessages.sty
result = (app.outdir / 'sphinxmessages.sty').read_text()
Expand Down
18 changes: 0 additions & 18 deletions tests/test_util_i18n.py
Expand Up @@ -98,15 +98,6 @@ def test_format_date():
def test_get_filename_for_language(app):
app.env.temp_data['docname'] = 'index'

# language is None
app.env.config.language = None
assert app.env.config.language is None
assert i18n.get_image_filename_for_language('foo.png', app.env) == 'foo.png'
assert i18n.get_image_filename_for_language('foo.bar.png', app.env) == 'foo.bar.png'
assert i18n.get_image_filename_for_language('subdir/foo.png', app.env) == 'subdir/foo.png'
assert i18n.get_image_filename_for_language('../foo.png', app.env) == '../foo.png'
assert i18n.get_image_filename_for_language('foo', app.env) == 'foo'

# language is en
app.env.config.language = 'en'
assert i18n.get_image_filename_for_language('foo.png', app.env) == 'foo.en.png'
Expand All @@ -115,15 +106,6 @@ def test_get_filename_for_language(app):
assert i18n.get_image_filename_for_language('../foo.png', app.env) == '../foo.en.png'
assert i18n.get_image_filename_for_language('foo', app.env) == 'foo.en'

# modify figure_language_filename and language is None
app.env.config.language = None
app.env.config.figure_language_filename = 'images/{language}/{root}{ext}'
assert i18n.get_image_filename_for_language('foo.png', app.env) == 'foo.png'
assert i18n.get_image_filename_for_language('foo.bar.png', app.env) == 'foo.bar.png'
assert i18n.get_image_filename_for_language('subdir/foo.png', app.env) == 'subdir/foo.png'
assert i18n.get_image_filename_for_language('../foo.png', app.env) == '../foo.png'
assert i18n.get_image_filename_for_language('foo', app.env) == 'foo'

# modify figure_language_filename and language is 'en'
app.env.config.language = 'en'
app.env.config.figure_language_filename = 'images/{language}/{root}{ext}'
Expand Down