Skip to content

Commit fec35c9

Browse files
bpo-33710: Deprecate l*gettext() and related functions in the gettext module. (GH-10139)
They return encoded bytes and are Python 2 artifacts.
1 parent d9bff4e commit fec35c9

5 files changed

Lines changed: 233 additions & 67 deletions

File tree

Doc/library/gettext.rst

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class-based API instead.
5353
and :func:`ldngettext` functions.
5454
If *codeset* is omitted, then the current binding is returned.
5555

56+
.. deprecated-removed:: 3.8 3.10
57+
5658

5759
.. function:: textdomain(domain=None)
5860

@@ -112,9 +114,9 @@ class-based API instead.
112114
Unicode strings instead, since most Python applications will want to
113115
manipulate human readable text as strings instead of bytes. Further,
114116
it's possible that you may get unexpected Unicode-related exceptions
115-
if there are encoding problems with the translated strings. It is
116-
possible that the ``l*()`` functions will be deprecated in future Python
117-
versions due to their inherent problems and limitations.
117+
if there are encoding problems with the translated strings.
118+
119+
.. deprecated-removed:: 3.8 3.10
118120

119121

120122
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
192194
.. versionchanged:: 3.3
193195
:exc:`IOError` used to be raised instead of :exc:`OSError`.
194196

197+
.. deprecated-removed:: 3.8 3.10
198+
The *codeset* parameter.
199+
195200

196201
.. function:: install(domain, localedir=None, codeset=None, names=None)
197202

@@ -212,6 +217,9 @@ class can also install themselves in the built-in namespace as the function
212217
builtins namespace, so it is easily accessible in all modules of your
213218
application.
214219

220+
.. deprecated-removed:: 3.8 3.10
221+
The *codeset* parameter.
222+
215223

216224
The :class:`NullTranslations` class
217225
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -272,6 +280,8 @@ are the methods of :class:`!NullTranslations`:
272280
These methods should be avoided in Python 3. See the warning for the
273281
:func:`lgettext` function.
274282

283+
.. deprecated-removed:: 3.8 3.10
284+
275285

276286
.. method:: info()
277287

@@ -288,11 +298,15 @@ are the methods of :class:`!NullTranslations`:
288298
Return the encoding used to return translated messages in :meth:`.lgettext`
289299
and :meth:`.lngettext`.
290300

301+
.. deprecated-removed:: 3.8 3.10
302+
291303

292304
.. method:: set_output_charset(charset)
293305

294306
Change the encoding used to return translated messages.
295307

308+
.. deprecated-removed:: 3.8 3.10
309+
296310

297311
.. method:: install(names=None)
298312

@@ -393,6 +407,8 @@ unexpected, or if other problems occur while reading the file, instantiating a
393407
These methods should be avoided in Python 3. See the warning for the
394408
:func:`lgettext` function.
395409

410+
.. deprecated-removed:: 3.8 3.10
411+
396412

397413
Solaris message catalog support
398414
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Doc/whatsnew/3.8.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,23 @@ Deprecated
295295
versions. :class:`~ast.Constant` should be used instead.
296296
(Contributed by Serhiy Storchaka in :issue:`32892`.)
297297

298+
* The following functions and methods are deprecated in the :mod:`gettext`
299+
module: :func:`~gettext.lgettext`, :func:`~gettext.ldgettext`,
300+
:func:`~gettext.lngettext` and :func:`~gettext.ldngettext`.
301+
They return encoded bytes, and it's possible that you will get unexpected
302+
Unicode-related exceptions if there are encoding problems with the
303+
translated strings. It's much better to use alternatives which return
304+
Unicode strings in Python 3. These functions have been broken for a long time.
305+
306+
Function :func:`~gettext.bind_textdomain_codeset`, methods
307+
:meth:`~gettext.NullTranslations.output_charset` and
308+
:meth:`~gettext.NullTranslations.set_output_charset`, and the *codeset*
309+
parameter of functions :func:`~gettext.translation` and
310+
:func:`~gettext.install` are also deprecated, since they are only used for
311+
for the ``l*gettext()`` functions.
312+
313+
(Contributed by Serhiy Storchaka in :issue:`33710`.)
314+
298315

299316
Removed
300317
=======

Lib/gettext.py

Lines changed: 79 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -274,8 +274,14 @@ def gettext(self, message):
274274
return message
275275

276276
def lgettext(self, message):
277+
import warnings
278+
warnings.warn('lgettext() is deprecated, use gettext() instead',
279+
DeprecationWarning, 2)
277280
if self._fallback:
278-
return self._fallback.lgettext(message)
281+
with warnings.catch_warnings():
282+
warnings.filterwarnings('ignore', r'.*\blgettext\b.*',
283+
DeprecationWarning)
284+
return self._fallback.lgettext(message)
279285
if self._output_charset:
280286
return message.encode(self._output_charset)
281287
return message.encode(locale.getpreferredencoding())
@@ -289,8 +295,14 @@ def ngettext(self, msgid1, msgid2, n):
289295
return msgid2
290296

291297
def lngettext(self, msgid1, msgid2, n):
298+
import warnings
299+
warnings.warn('lngettext() is deprecated, use ngettext() instead',
300+
DeprecationWarning, 2)
292301
if self._fallback:
293-
return self._fallback.lngettext(msgid1, msgid2, n)
302+
with warnings.catch_warnings():
303+
warnings.filterwarnings('ignore', r'.*\blngettext\b.*',
304+
DeprecationWarning)
305+
return self._fallback.lngettext(msgid1, msgid2, n)
294306
if n == 1:
295307
tmsg = msgid1
296308
else:
@@ -306,9 +318,15 @@ def charset(self):
306318
return self._charset
307319

308320
def output_charset(self):
321+
import warnings
322+
warnings.warn('output_charset() is deprecated',
323+
DeprecationWarning, 2)
309324
return self._output_charset
310325

311326
def set_output_charset(self, charset):
327+
import warnings
328+
warnings.warn('set_output_charset() is deprecated',
329+
DeprecationWarning, 2)
312330
self._output_charset = charset
313331

314332
def install(self, names=None):
@@ -424,6 +442,9 @@ def _parse(self, fp):
424442
transidx += 8
425443

426444
def lgettext(self, message):
445+
import warnings
446+
warnings.warn('lgettext() is deprecated, use gettext() instead',
447+
DeprecationWarning, 2)
427448
missing = object()
428449
tmsg = self._catalog.get(message, missing)
429450
if tmsg is missing:
@@ -435,6 +456,9 @@ def lgettext(self, message):
435456
return tmsg.encode(locale.getpreferredencoding())
436457

437458
def lngettext(self, msgid1, msgid2, n):
459+
import warnings
460+
warnings.warn('lngettext() is deprecated, use ngettext() instead',
461+
DeprecationWarning, 2)
438462
try:
439463
tmsg = self._catalog[(msgid1, self.plural(n))]
440464
except KeyError:
@@ -510,9 +534,10 @@ def find(domain, localedir=None, languages=None, all=False):
510534

511535
# a mapping between absolute .mo file path and Translation object
512536
_translations = {}
537+
_unspecified = ['unspecified']
513538

514539
def translation(domain, localedir=None, languages=None,
515-
class_=None, fallback=False, codeset=None):
540+
class_=None, fallback=False, codeset=_unspecified):
516541
if class_ is None:
517542
class_ = GNUTranslations
518543
mofiles = find(domain, localedir, languages, all=True)
@@ -538,16 +563,23 @@ def translation(domain, localedir=None, languages=None,
538563
# are not used.
539564
import copy
540565
t = copy.copy(t)
541-
if codeset:
542-
t.set_output_charset(codeset)
566+
if codeset is not _unspecified:
567+
import warnings
568+
warnings.warn('parameter codeset is deprecated',
569+
DeprecationWarning, 2)
570+
if codeset:
571+
with warnings.catch_warnings():
572+
warnings.filterwarnings('ignore', r'.*\bset_output_charset\b.*',
573+
DeprecationWarning)
574+
t.set_output_charset(codeset)
543575
if result is None:
544576
result = t
545577
else:
546578
result.add_fallback(t)
547579
return result
548580

549581

550-
def install(domain, localedir=None, codeset=None, names=None):
582+
def install(domain, localedir=None, codeset=_unspecified, names=None):
551583
t = translation(domain, localedir, fallback=True, codeset=codeset)
552584
t.install(names)
553585

@@ -576,6 +608,9 @@ def bindtextdomain(domain, localedir=None):
576608

577609

578610
def bind_textdomain_codeset(domain, codeset=None):
611+
import warnings
612+
warnings.warn('bind_textdomain_codeset() is deprecated',
613+
DeprecationWarning, 2)
579614
global _localecodesets
580615
if codeset is not None:
581616
_localecodesets[domain] = codeset
@@ -584,24 +619,31 @@ def bind_textdomain_codeset(domain, codeset=None):
584619

585620
def dgettext(domain, message):
586621
try:
587-
t = translation(domain, _localedirs.get(domain, None),
588-
codeset=_localecodesets.get(domain))
622+
t = translation(domain, _localedirs.get(domain, None))
589623
except OSError:
590624
return message
591625
return t.gettext(message)
592626

593627
def ldgettext(domain, message):
628+
import warnings
629+
warnings.warn('ldgettext() is deprecated, use dgettext() instead',
630+
DeprecationWarning, 2)
594631
codeset = _localecodesets.get(domain)
595632
try:
596-
t = translation(domain, _localedirs.get(domain, None), codeset=codeset)
633+
with warnings.catch_warnings():
634+
warnings.filterwarnings('ignore', r'.*\bparameter codeset\b.*',
635+
DeprecationWarning)
636+
t = translation(domain, _localedirs.get(domain, None), codeset=codeset)
597637
except OSError:
598638
return message.encode(codeset or locale.getpreferredencoding())
599-
return t.lgettext(message)
639+
with warnings.catch_warnings():
640+
warnings.filterwarnings('ignore', r'.*\blgettext\b.*',
641+
DeprecationWarning)
642+
return t.lgettext(message)
600643

601644
def dngettext(domain, msgid1, msgid2, n):
602645
try:
603-
t = translation(domain, _localedirs.get(domain, None),
604-
codeset=_localecodesets.get(domain))
646+
t = translation(domain, _localedirs.get(domain, None))
605647
except OSError:
606648
if n == 1:
607649
return msgid1
@@ -610,28 +652,49 @@ def dngettext(domain, msgid1, msgid2, n):
610652
return t.ngettext(msgid1, msgid2, n)
611653

612654
def ldngettext(domain, msgid1, msgid2, n):
655+
import warnings
656+
warnings.warn('ldngettext() is deprecated, use dngettext() instead',
657+
DeprecationWarning, 2)
613658
codeset = _localecodesets.get(domain)
614659
try:
615-
t = translation(domain, _localedirs.get(domain, None), codeset=codeset)
660+
with warnings.catch_warnings():
661+
warnings.filterwarnings('ignore', r'.*\bparameter codeset\b.*',
662+
DeprecationWarning)
663+
t = translation(domain, _localedirs.get(domain, None), codeset=codeset)
616664
except OSError:
617665
if n == 1:
618666
tmsg = msgid1
619667
else:
620668
tmsg = msgid2
621669
return tmsg.encode(codeset or locale.getpreferredencoding())
622-
return t.lngettext(msgid1, msgid2, n)
670+
with warnings.catch_warnings():
671+
warnings.filterwarnings('ignore', r'.*\blngettext\b.*',
672+
DeprecationWarning)
673+
return t.lngettext(msgid1, msgid2, n)
623674

624675
def gettext(message):
625676
return dgettext(_current_domain, message)
626677

627678
def lgettext(message):
628-
return ldgettext(_current_domain, message)
679+
import warnings
680+
warnings.warn('lgettext() is deprecated, use gettext() instead',
681+
DeprecationWarning, 2)
682+
with warnings.catch_warnings():
683+
warnings.filterwarnings('ignore', r'.*\bldgettext\b.*',
684+
DeprecationWarning)
685+
return ldgettext(_current_domain, message)
629686

630687
def ngettext(msgid1, msgid2, n):
631688
return dngettext(_current_domain, msgid1, msgid2, n)
632689

633690
def lngettext(msgid1, msgid2, n):
634-
return ldngettext(_current_domain, msgid1, msgid2, n)
691+
import warnings
692+
warnings.warn('lngettext() is deprecated, use ngettext() instead',
693+
DeprecationWarning, 2)
694+
with warnings.catch_warnings():
695+
warnings.filterwarnings('ignore', r'.*\bldngettext\b.*',
696+
DeprecationWarning)
697+
return ldngettext(_current_domain, msgid1, msgid2, n)
635698

636699
# dcgettext() has been deemed unnecessary and is not implemented.
637700

0 commit comments

Comments
 (0)