Commit fec35c99 authored by Serhiy Storchaka's avatar Serhiy Storchaka Committed by GitHub

bpo-33710: Deprecate l*gettext() and related functions in the gettext module. (GH-10139)

They return encoded bytes and are Python 2 artifacts.
parent d9bff4e8
...@@ -53,6 +53,8 @@ class-based API instead. ...@@ -53,6 +53,8 @@ class-based API instead.
and :func:`ldngettext` functions. and :func:`ldngettext` functions.
If *codeset* is omitted, then the current binding is returned. If *codeset* is omitted, then the current binding is returned.
.. deprecated-removed:: 3.8 3.10
.. function:: textdomain(domain=None) .. function:: textdomain(domain=None)
...@@ -112,9 +114,9 @@ class-based API instead. ...@@ -112,9 +114,9 @@ class-based API instead.
Unicode strings instead, since most Python applications will want to Unicode strings instead, since most Python applications will want to
manipulate human readable text as strings instead of bytes. Further, manipulate human readable text as strings instead of bytes. Further,
it's possible that you may get unexpected Unicode-related exceptions it's possible that you may get unexpected Unicode-related exceptions
if there are encoding problems with the translated strings. It is if there are encoding problems with the translated strings.
possible that the ``l*()`` functions will be deprecated in future Python
versions due to their inherent problems and limitations. .. deprecated-removed:: 3.8 3.10
Note that GNU :program:`gettext` also defines a :func:`dcgettext` method, but Note that GNU :program:`gettext` also defines a :func:`dcgettext` method, but
...@@ -192,6 +194,9 @@ class can also install themselves in the built-in namespace as the function ...@@ -192,6 +194,9 @@ class can also install themselves in the built-in namespace as the function
.. versionchanged:: 3.3 .. versionchanged:: 3.3
:exc:`IOError` used to be raised instead of :exc:`OSError`. :exc:`IOError` used to be raised instead of :exc:`OSError`.
.. deprecated-removed:: 3.8 3.10
The *codeset* parameter.
.. function:: install(domain, localedir=None, codeset=None, names=None) .. function:: install(domain, localedir=None, codeset=None, names=None)
...@@ -212,6 +217,9 @@ class can also install themselves in the built-in namespace as the function ...@@ -212,6 +217,9 @@ class can also install themselves in the built-in namespace as the function
builtins namespace, so it is easily accessible in all modules of your builtins namespace, so it is easily accessible in all modules of your
application. application.
.. deprecated-removed:: 3.8 3.10
The *codeset* parameter.
The :class:`NullTranslations` class The :class:`NullTranslations` class
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...@@ -272,6 +280,8 @@ are the methods of :class:`!NullTranslations`: ...@@ -272,6 +280,8 @@ are the methods of :class:`!NullTranslations`:
These methods should be avoided in Python 3. See the warning for the These methods should be avoided in Python 3. See the warning for the
:func:`lgettext` function. :func:`lgettext` function.
.. deprecated-removed:: 3.8 3.10
.. method:: info() .. method:: info()
...@@ -288,11 +298,15 @@ are the methods of :class:`!NullTranslations`: ...@@ -288,11 +298,15 @@ are the methods of :class:`!NullTranslations`:
Return the encoding used to return translated messages in :meth:`.lgettext` Return the encoding used to return translated messages in :meth:`.lgettext`
and :meth:`.lngettext`. and :meth:`.lngettext`.
.. deprecated-removed:: 3.8 3.10
.. method:: set_output_charset(charset) .. method:: set_output_charset(charset)
Change the encoding used to return translated messages. Change the encoding used to return translated messages.
.. deprecated-removed:: 3.8 3.10
.. method:: install(names=None) .. method:: install(names=None)
...@@ -393,6 +407,8 @@ unexpected, or if other problems occur while reading the file, instantiating a ...@@ -393,6 +407,8 @@ unexpected, or if other problems occur while reading the file, instantiating a
These methods should be avoided in Python 3. See the warning for the These methods should be avoided in Python 3. See the warning for the
:func:`lgettext` function. :func:`lgettext` function.
.. deprecated-removed:: 3.8 3.10
Solaris message catalog support Solaris message catalog support
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
......
...@@ -295,6 +295,23 @@ Deprecated ...@@ -295,6 +295,23 @@ Deprecated
versions. :class:`~ast.Constant` should be used instead. versions. :class:`~ast.Constant` should be used instead.
(Contributed by Serhiy Storchaka in :issue:`32892`.) (Contributed by Serhiy Storchaka in :issue:`32892`.)
* The following functions and methods are deprecated in the :mod:`gettext`
module: :func:`~gettext.lgettext`, :func:`~gettext.ldgettext`,
:func:`~gettext.lngettext` and :func:`~gettext.ldngettext`.
They return encoded bytes, and it's possible that you will get unexpected
Unicode-related exceptions if there are encoding problems with the
translated strings. It's much better to use alternatives which return
Unicode strings in Python 3. These functions have been broken for a long time.
Function :func:`~gettext.bind_textdomain_codeset`, methods
:meth:`~gettext.NullTranslations.output_charset` and
:meth:`~gettext.NullTranslations.set_output_charset`, and the *codeset*
parameter of functions :func:`~gettext.translation` and
:func:`~gettext.install` are also deprecated, since they are only used for
for the ``l*gettext()`` functions.
(Contributed by Serhiy Storchaka in :issue:`33710`.)
Removed Removed
======= =======
......
...@@ -274,7 +274,13 @@ class NullTranslations: ...@@ -274,7 +274,13 @@ class NullTranslations:
return message return message
def lgettext(self, message): def lgettext(self, message):
import warnings
warnings.warn('lgettext() is deprecated, use gettext() instead',
DeprecationWarning, 2)
if self._fallback: if self._fallback:
with warnings.catch_warnings():
warnings.filterwarnings('ignore', r'.*\blgettext\b.*',
DeprecationWarning)
return self._fallback.lgettext(message) return self._fallback.lgettext(message)
if self._output_charset: if self._output_charset:
return message.encode(self._output_charset) return message.encode(self._output_charset)
...@@ -289,7 +295,13 @@ class NullTranslations: ...@@ -289,7 +295,13 @@ class NullTranslations:
return msgid2 return msgid2
def lngettext(self, msgid1, msgid2, n): def lngettext(self, msgid1, msgid2, n):
import warnings
warnings.warn('lngettext() is deprecated, use ngettext() instead',
DeprecationWarning, 2)
if self._fallback: if self._fallback:
with warnings.catch_warnings():
warnings.filterwarnings('ignore', r'.*\blngettext\b.*',
DeprecationWarning)
return self._fallback.lngettext(msgid1, msgid2, n) return self._fallback.lngettext(msgid1, msgid2, n)
if n == 1: if n == 1:
tmsg = msgid1 tmsg = msgid1
...@@ -306,9 +318,15 @@ class NullTranslations: ...@@ -306,9 +318,15 @@ class NullTranslations:
return self._charset return self._charset
def output_charset(self): def output_charset(self):
import warnings
warnings.warn('output_charset() is deprecated',
DeprecationWarning, 2)
return self._output_charset return self._output_charset
def set_output_charset(self, charset): def set_output_charset(self, charset):
import warnings
warnings.warn('set_output_charset() is deprecated',
DeprecationWarning, 2)
self._output_charset = charset self._output_charset = charset
def install(self, names=None): def install(self, names=None):
...@@ -424,6 +442,9 @@ class GNUTranslations(NullTranslations): ...@@ -424,6 +442,9 @@ class GNUTranslations(NullTranslations):
transidx += 8 transidx += 8
def lgettext(self, message): def lgettext(self, message):
import warnings
warnings.warn('lgettext() is deprecated, use gettext() instead',
DeprecationWarning, 2)
missing = object() missing = object()
tmsg = self._catalog.get(message, missing) tmsg = self._catalog.get(message, missing)
if tmsg is missing: if tmsg is missing:
...@@ -435,6 +456,9 @@ class GNUTranslations(NullTranslations): ...@@ -435,6 +456,9 @@ class GNUTranslations(NullTranslations):
return tmsg.encode(locale.getpreferredencoding()) return tmsg.encode(locale.getpreferredencoding())
def lngettext(self, msgid1, msgid2, n): def lngettext(self, msgid1, msgid2, n):
import warnings
warnings.warn('lngettext() is deprecated, use ngettext() instead',
DeprecationWarning, 2)
try: try:
tmsg = self._catalog[(msgid1, self.plural(n))] tmsg = self._catalog[(msgid1, self.plural(n))]
except KeyError: except KeyError:
...@@ -510,9 +534,10 @@ def find(domain, localedir=None, languages=None, all=False): ...@@ -510,9 +534,10 @@ def find(domain, localedir=None, languages=None, all=False):
# a mapping between absolute .mo file path and Translation object # a mapping between absolute .mo file path and Translation object
_translations = {} _translations = {}
_unspecified = ['unspecified']
def translation(domain, localedir=None, languages=None, def translation(domain, localedir=None, languages=None,
class_=None, fallback=False, codeset=None): class_=None, fallback=False, codeset=_unspecified):
if class_ is None: if class_ is None:
class_ = GNUTranslations class_ = GNUTranslations
mofiles = find(domain, localedir, languages, all=True) mofiles = find(domain, localedir, languages, all=True)
...@@ -538,7 +563,14 @@ def translation(domain, localedir=None, languages=None, ...@@ -538,7 +563,14 @@ def translation(domain, localedir=None, languages=None,
# are not used. # are not used.
import copy import copy
t = copy.copy(t) t = copy.copy(t)
if codeset is not _unspecified:
import warnings
warnings.warn('parameter codeset is deprecated',
DeprecationWarning, 2)
if codeset: if codeset:
with warnings.catch_warnings():
warnings.filterwarnings('ignore', r'.*\bset_output_charset\b.*',
DeprecationWarning)
t.set_output_charset(codeset) t.set_output_charset(codeset)
if result is None: if result is None:
result = t result = t
...@@ -547,7 +579,7 @@ def translation(domain, localedir=None, languages=None, ...@@ -547,7 +579,7 @@ def translation(domain, localedir=None, languages=None,
return result return result
def install(domain, localedir=None, codeset=None, names=None): def install(domain, localedir=None, codeset=_unspecified, names=None):
t = translation(domain, localedir, fallback=True, codeset=codeset) t = translation(domain, localedir, fallback=True, codeset=codeset)
t.install(names) t.install(names)
...@@ -576,6 +608,9 @@ def bindtextdomain(domain, localedir=None): ...@@ -576,6 +608,9 @@ def bindtextdomain(domain, localedir=None):
def bind_textdomain_codeset(domain, codeset=None): def bind_textdomain_codeset(domain, codeset=None):
import warnings
warnings.warn('bind_textdomain_codeset() is deprecated',
DeprecationWarning, 2)
global _localecodesets global _localecodesets
if codeset is not None: if codeset is not None:
_localecodesets[domain] = codeset _localecodesets[domain] = codeset
...@@ -584,24 +619,31 @@ def bind_textdomain_codeset(domain, codeset=None): ...@@ -584,24 +619,31 @@ def bind_textdomain_codeset(domain, codeset=None):
def dgettext(domain, message): def dgettext(domain, message):
try: try:
t = translation(domain, _localedirs.get(domain, None), t = translation(domain, _localedirs.get(domain, None))
codeset=_localecodesets.get(domain))
except OSError: except OSError:
return message return message
return t.gettext(message) return t.gettext(message)
def ldgettext(domain, message): def ldgettext(domain, message):
import warnings
warnings.warn('ldgettext() is deprecated, use dgettext() instead',
DeprecationWarning, 2)
codeset = _localecodesets.get(domain) codeset = _localecodesets.get(domain)
try: try:
with warnings.catch_warnings():
warnings.filterwarnings('ignore', r'.*\bparameter codeset\b.*',
DeprecationWarning)
t = translation(domain, _localedirs.get(domain, None), codeset=codeset) t = translation(domain, _localedirs.get(domain, None), codeset=codeset)
except OSError: except OSError:
return message.encode(codeset or locale.getpreferredencoding()) return message.encode(codeset or locale.getpreferredencoding())
with warnings.catch_warnings():
warnings.filterwarnings('ignore', r'.*\blgettext\b.*',
DeprecationWarning)
return t.lgettext(message) return t.lgettext(message)
def dngettext(domain, msgid1, msgid2, n): def dngettext(domain, msgid1, msgid2, n):
try: try:
t = translation(domain, _localedirs.get(domain, None), t = translation(domain, _localedirs.get(domain, None))
codeset=_localecodesets.get(domain))
except OSError: except OSError:
if n == 1: if n == 1:
return msgid1 return msgid1
...@@ -610,8 +652,14 @@ def dngettext(domain, msgid1, msgid2, n): ...@@ -610,8 +652,14 @@ def dngettext(domain, msgid1, msgid2, n):
return t.ngettext(msgid1, msgid2, n) return t.ngettext(msgid1, msgid2, n)
def ldngettext(domain, msgid1, msgid2, n): def ldngettext(domain, msgid1, msgid2, n):
import warnings
warnings.warn('ldngettext() is deprecated, use dngettext() instead',
DeprecationWarning, 2)
codeset = _localecodesets.get(domain) codeset = _localecodesets.get(domain)
try: try:
with warnings.catch_warnings():
warnings.filterwarnings('ignore', r'.*\bparameter codeset\b.*',
DeprecationWarning)
t = translation(domain, _localedirs.get(domain, None), codeset=codeset) t = translation(domain, _localedirs.get(domain, None), codeset=codeset)
except OSError: except OSError:
if n == 1: if n == 1:
...@@ -619,18 +667,33 @@ def ldngettext(domain, msgid1, msgid2, n): ...@@ -619,18 +667,33 @@ def ldngettext(domain, msgid1, msgid2, n):
else: else:
tmsg = msgid2 tmsg = msgid2
return tmsg.encode(codeset or locale.getpreferredencoding()) return tmsg.encode(codeset or locale.getpreferredencoding())
with warnings.catch_warnings():
warnings.filterwarnings('ignore', r'.*\blngettext\b.*',
DeprecationWarning)
return t.lngettext(msgid1, msgid2, n) return t.lngettext(msgid1, msgid2, n)
def gettext(message): def gettext(message):
return dgettext(_current_domain, message) return dgettext(_current_domain, message)
def lgettext(message): def lgettext(message):
import warnings
warnings.warn('lgettext() is deprecated, use gettext() instead',
DeprecationWarning, 2)
with warnings.catch_warnings():
warnings.filterwarnings('ignore', r'.*\bldgettext\b.*',
DeprecationWarning)
return ldgettext(_current_domain, message) return ldgettext(_current_domain, message)
def ngettext(msgid1, msgid2, n): def ngettext(msgid1, msgid2, n):
return dngettext(_current_domain, msgid1, msgid2, n) return dngettext(_current_domain, msgid1, msgid2, n)
def lngettext(msgid1, msgid2, n): def lngettext(msgid1, msgid2, n):
import warnings
warnings.warn('lngettext() is deprecated, use ngettext() instead',
DeprecationWarning, 2)
with warnings.catch_warnings():
warnings.filterwarnings('ignore', r'.*\bldngettext\b.*',
DeprecationWarning)
return ldngettext(_current_domain, msgid1, msgid2, n) return ldngettext(_current_domain, msgid1, msgid2, n)
# dcgettext() has been deemed unnecessary and is not implemented. # dcgettext() has been deemed unnecessary and is not implemented.
......
This diff is collapsed.
Deprecated ``l*gettext()`` functions and methods in the :mod:`gettext`
module. They return encoded bytes instead of Unicode strings and are
artifacts from Python 2 times. Also deprecated functions and methods related
to setting the charset for ``l*gettext()`` functions and methods.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment