From fcce7bd887d9d39f45456009f2f5ad48e6a4c476 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Wed, 19 Mar 2025 17:33:35 +0000 Subject: [PATCH 01/11] Initial --- Doc/library/gettext.rst | 10 +++++++--- Lib/gettext.py | 16 +++++++++++----- Lib/test/test_gettext.py | 10 +++++++++- ...2025-03-19-17-30-00.gh-issue-64243.fuheq3.rst | 2 ++ 4 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-03-19-17-30-00.gh-issue-64243.fuheq3.rst diff --git a/Doc/library/gettext.rst b/Doc/library/gettext.rst index d0de83907eb297..4179dc24c0d265 100644 --- a/Doc/library/gettext.rst +++ b/Doc/library/gettext.rst @@ -130,9 +130,10 @@ install themselves in the built-in namespace as the function :func:`!_`. strings, where each string is a language code. If *localedir* is not given, then the default system locale directory is used. - [#]_ If *languages* is not given, then the following environment variables are - searched: :envvar:`LANGUAGE`, :envvar:`LC_ALL`, :envvar:`LC_MESSAGES`, and - :envvar:`LANG`. The first one returning a non-empty value is used for the + [#]_ If *languages* is not given, then the environment variable :envvar:`LANGUAGE` + is searched, it falls back to :func:`locale.getlocale`, which in turn falls + back to the environment variables :envvar:`LC_ALL`, :envvar:`LC_MESSAGES`, and + :envvar:`LANG` where the first one returning a non-empty value is used for the *languages* variable. The environment variables should contain a colon separated list of languages, which will be split on the colon to produce the expected list of language code strings. @@ -147,6 +148,9 @@ install themselves in the built-in namespace as the function :func:`!_`. of all file names, in the order in which they appear in the languages list or the environment variables. + .. versionchanged:: next + :func:`locale.getlocale` is used to generate *languages* if *languages* is + not provided. .. function:: translation(domain, localedir=None, languages=None, class_=None, fallback=False) diff --git a/Lib/gettext.py b/Lib/gettext.py index 6c11ab2b1eb570..3565977f068136 100644 --- a/Lib/gettext.py +++ b/Lib/gettext.py @@ -46,6 +46,7 @@ import operator import os import sys +import locale __all__ = ['NullTranslations', 'GNUTranslations', 'Catalog', @@ -491,11 +492,16 @@ def find(domain, localedir=None, languages=None, all=False): localedir = _default_localedir if languages is None: languages = [] - for envar in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'): - val = os.environ.get(envar) - if val: - languages = val.split(':') - break + if os.environ.get('LANGUAGE'): + languages = os.environ.get('LANGUAGE').split(',') + elif locale.getlocale() != (None, None): + languages.append(".".join(filter(None, locale.getlocale()))) + else: + for envar in ('LC_ALL', 'LC_MESSAGES', 'LANG'): + val = os.environ.get(envar) + if val: + languages = val.split(':') + break if 'C' not in languages: languages.append('C') # now normalize and expand the languages diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index 0fbd90dcb485f8..cb8f375facb3fc 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -1,3 +1,4 @@ +import locale import os import base64 import gettext @@ -736,7 +737,8 @@ def create_mo_file(self, lang): f.write(GNU_MO_DATA) return mo_file - def test_find_with_env_vars(self): + @unittest.mock.patch("locale.getlocale", return_value=(None, None)) + def test_find_with_env_vars(self, patch_getlocale): # test that find correctly finds the environment variables # when languages are not supplied mo_file = self.create_mo_file("ga_IE") @@ -747,6 +749,12 @@ def test_find_with_env_vars(self): self.assertEqual(result, mo_file) self.env.unset(var) + @unittest.mock.patch("locale.getlocale", return_value=('ga_IE', 'UTF-8')) + def test_process_vars_override(self, patch_getlocale): + mo_file = self.create_mo_file("ga_IE") + result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) + self.assertEqual(result, mo_file) + def test_find_with_languages(self): # test that passed languages are used self.env.set('LANGUAGE', 'pt_BR') diff --git a/Misc/NEWS.d/next/Library/2025-03-19-17-30-00.gh-issue-64243.fuheq3.rst b/Misc/NEWS.d/next/Library/2025-03-19-17-30-00.gh-issue-64243.fuheq3.rst new file mode 100644 index 00000000000000..84fead5f88fe00 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-03-19-17-30-00.gh-issue-64243.fuheq3.rst @@ -0,0 +1,2 @@ +Implement a fall back to :func:`locale.getlocale` in :func:`gettext.find` if +*languages* is not provided and :envvar:`LANGUAGES` is not set. From 03ca427c5561b5ec6005520f2015da9d16af70d6 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Wed, 19 Mar 2025 18:48:02 +0000 Subject: [PATCH 02/11] Correct NEWS --- .../next/Library/2025-03-19-17-30-00.gh-issue-64243.fuheq3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-03-19-17-30-00.gh-issue-64243.fuheq3.rst b/Misc/NEWS.d/next/Library/2025-03-19-17-30-00.gh-issue-64243.fuheq3.rst index 84fead5f88fe00..8e301340c4fa48 100644 --- a/Misc/NEWS.d/next/Library/2025-03-19-17-30-00.gh-issue-64243.fuheq3.rst +++ b/Misc/NEWS.d/next/Library/2025-03-19-17-30-00.gh-issue-64243.fuheq3.rst @@ -1,2 +1,2 @@ Implement a fall back to :func:`locale.getlocale` in :func:`gettext.find` if -*languages* is not provided and :envvar:`LANGUAGES` is not set. +*languages* is not provided and :envvar:`LANGUAGE` is not set. From f9851e12a99d29bfbc21ab2a0bba0b413afbfe35 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Mon, 31 Mar 2025 18:14:00 +0100 Subject: [PATCH 03/11] Tomas's feedback --- Lib/gettext.py | 8 ++++---- Lib/test/test_gettext.py | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Lib/gettext.py b/Lib/gettext.py index 3565977f068136..672a54c82f1c0f 100644 --- a/Lib/gettext.py +++ b/Lib/gettext.py @@ -492,10 +492,10 @@ def find(domain, localedir=None, languages=None, all=False): localedir = _default_localedir if languages is None: languages = [] - if os.environ.get('LANGUAGE'): - languages = os.environ.get('LANGUAGE').split(',') - elif locale.getlocale() != (None, None): - languages.append(".".join(filter(None, locale.getlocale()))) + if val := os.environ.get('LANGUAGE'): + languages = val.split(':') + elif (loc := locale.getlocale()) != (None, None): + languages.append(".".join(filter(None, loc))) else: for envar in ('LC_ALL', 'LC_MESSAGES', 'LANG'): val = os.environ.get(envar) diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index cb8f375facb3fc..09e5c861566d6c 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -748,6 +748,13 @@ def test_find_with_env_vars(self, patch_getlocale): localedir=os.path.join(self.tempdir, "locale")) self.assertEqual(result, mo_file) self.env.unset(var) + # test fallbacks + for var in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'): + self.env.set(var, 'es_ES:ga_IE:fr_FR') + result = gettext.find("mofile", + localedir=os.path.join(self.tempdir, "locale")) + self.assertEqual(result, mo_file) + self.env.unset(var) @unittest.mock.patch("locale.getlocale", return_value=('ga_IE', 'UTF-8')) def test_process_vars_override(self, patch_getlocale): From 4f3734269d4e547363ad6fc17e569433340fe808 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Sat, 5 Apr 2025 13:52:48 +0100 Subject: [PATCH 04/11] Tomas's suggestion + typo spotted while testing --- Lib/gettext.py | 2 +- Lib/test/test_gettext.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/gettext.py b/Lib/gettext.py index 672a54c82f1c0f..cf34771e64a296 100644 --- a/Lib/gettext.py +++ b/Lib/gettext.py @@ -495,7 +495,7 @@ def find(domain, localedir=None, languages=None, all=False): if val := os.environ.get('LANGUAGE'): languages = val.split(':') elif (loc := locale.getlocale()) != (None, None): - languages.append(".".join(filter(None, loc))) + languages = [".".join(filter(None, loc))] else: for envar in ('LC_ALL', 'LC_MESSAGES', 'LANG'): val = os.environ.get(envar) diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index 09e5c861566d6c..4900b8b2b62ea3 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -813,7 +813,7 @@ def test__all__(self): unittest.main() -# For reference, here's the .po file used to created the GNU_MO_DATA above. +# For reference, here's the .po file used to create the GNU_MO_DATA above. # # The original version was automatically generated from the sources with # pygettext. Later it was manually modified to add plural forms support. From c85d0c26adb8eb494e2671e9e383e83b1ea8c332 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Wed, 30 Apr 2025 21:04:23 +0100 Subject: [PATCH 05/11] Serhiy's review --- Doc/library/gettext.rst | 4 ++-- Lib/gettext.py | 3 +-- Lib/test/test_gettext.py | 39 ++++++++++++++++++++------------------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Doc/library/gettext.rst b/Doc/library/gettext.rst index 4179dc24c0d265..6a8385426ad744 100644 --- a/Doc/library/gettext.rst +++ b/Doc/library/gettext.rst @@ -131,7 +131,7 @@ install themselves in the built-in namespace as the function :func:`!_`. If *localedir* is not given, then the default system locale directory is used. [#]_ If *languages* is not given, then the environment variable :envvar:`LANGUAGE` - is searched, it falls back to :func:`locale.getlocale`, which in turn falls + is searched, it falls back to :func:`locale.setlocale`, which in turn falls back to the environment variables :envvar:`LC_ALL`, :envvar:`LC_MESSAGES`, and :envvar:`LANG` where the first one returning a non-empty value is used for the *languages* variable. The environment variables should contain a colon separated @@ -149,7 +149,7 @@ install themselves in the built-in namespace as the function :func:`!_`. the environment variables. .. versionchanged:: next - :func:`locale.getlocale` is used to generate *languages* if *languages* is + :func:`locale.setlocale` is used to generate *languages* if *languages* is not provided. .. function:: translation(domain, localedir=None, languages=None, class_=None, fallback=False) diff --git a/Lib/gettext.py b/Lib/gettext.py index cf34771e64a296..13d49aa618ef5c 100644 --- a/Lib/gettext.py +++ b/Lib/gettext.py @@ -230,7 +230,6 @@ def func(n): def _expand_lang(loc): - import locale loc = locale.normalize(loc) COMPONENT_CODESET = 1 << 0 COMPONENT_TERRITORY = 1 << 1 @@ -494,7 +493,7 @@ def find(domain, localedir=None, languages=None, all=False): languages = [] if val := os.environ.get('LANGUAGE'): languages = val.split(':') - elif (loc := locale.getlocale()) != (None, None): + elif (loc := locale.setlocale(locale.LC_MESSAGES)) != (None, None): languages = [".".join(filter(None, loc))] else: for envar in ('LC_ALL', 'LC_MESSAGES', 'LANG'): diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index 4900b8b2b62ea3..fc44c89f410caf 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -1,4 +1,3 @@ -import locale import os import base64 import gettext @@ -737,30 +736,32 @@ def create_mo_file(self, lang): f.write(GNU_MO_DATA) return mo_file - @unittest.mock.patch("locale.getlocale", return_value=(None, None)) - def test_find_with_env_vars(self, patch_getlocale): - # test that find correctly finds the environment variables - # when languages are not supplied - mo_file = self.create_mo_file("ga_IE") - for var in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'): - self.env.set(var, 'ga_IE') - result = gettext.find("mofile", - localedir=os.path.join(self.tempdir, "locale")) - self.assertEqual(result, mo_file) - self.env.unset(var) - # test fallbacks + def _for_all_vars(self, mo_file, locale): for var in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'): - self.env.set(var, 'es_ES:ga_IE:fr_FR') + self.env.set(var, locale) result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) - self.assertEqual(result, mo_file) + self.assertEqual(mo_file, result) self.env.unset(var) - @unittest.mock.patch("locale.getlocale", return_value=('ga_IE', 'UTF-8')) - def test_process_vars_override(self, patch_getlocale): + @unittest.mock.patch("locale.setlocale", return_value=(None, None)) + def test_find_with_env_vars(self, patch_getlocale): + # test that find correctly finds the environment variables + # when languages are not supplied mo_file = self.create_mo_file("ga_IE") - result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) - self.assertEqual(result, mo_file) + self._for_all_vars(mo_file, "ga_IE") + self._for_all_vars(mo_file, "ga_IE.UTF-8") + self._for_all_vars(mo_file, "es_ES:ga_IE:fr_FR") + self._for_all_vars(mo_file, "ga_IE@euro") + + def test_process_vars_override(self): + mo_file = self.create_mo_file("ga_IE") + with unittest.mock.patch("locale.setlocale", return_value=('ga_IE', 'UTF-8')): + result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) + self.assertEqual(mo_file, result) + with unittest.mock.patch("locale.setlocale", return_value=('ga_IE', None)): + result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) + self.assertEqual(mo_file, result) def test_find_with_languages(self): # test that passed languages are used From c40039fa3dbc4a120da243d1e79e8fcbe8d27aa7 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Thu, 19 Jun 2025 15:20:29 +0100 Subject: [PATCH 06/11] Review --- Doc/library/gettext.rst | 4 +-- Lib/gettext.py | 4 +-- Lib/test/test_gettext.py | 59 +++++++++++++++++++++++++++++++--------- 3 files changed, 50 insertions(+), 17 deletions(-) diff --git a/Doc/library/gettext.rst b/Doc/library/gettext.rst index 6a8385426ad744..3a352ccea6f582 100644 --- a/Doc/library/gettext.rst +++ b/Doc/library/gettext.rst @@ -131,8 +131,8 @@ install themselves in the built-in namespace as the function :func:`!_`. If *localedir* is not given, then the default system locale directory is used. [#]_ If *languages* is not given, then the environment variable :envvar:`LANGUAGE` - is searched, it falls back to :func:`locale.setlocale`, which in turn falls - back to the environment variables :envvar:`LC_ALL`, :envvar:`LC_MESSAGES`, and + is searched, it falls back to the current locale or to the environment + variables :envvar:`LC_ALL`, :envvar:`LC_MESSAGES`, and :envvar:`LANG` where the first one returning a non-empty value is used for the *languages* variable. The environment variables should contain a colon separated list of languages, which will be split on the colon to produce the expected list diff --git a/Lib/gettext.py b/Lib/gettext.py index 13d49aa618ef5c..f26bd67d2a4a4c 100644 --- a/Lib/gettext.py +++ b/Lib/gettext.py @@ -493,8 +493,8 @@ def find(domain, localedir=None, languages=None, all=False): languages = [] if val := os.environ.get('LANGUAGE'): languages = val.split(':') - elif (loc := locale.setlocale(locale.LC_MESSAGES)) != (None, None): - languages = [".".join(filter(None, loc))] + elif loc := locale.setlocale(locale.LC_MESSAGES): + languages = loc.split(':') else: for envar in ('LC_ALL', 'LC_MESSAGES', 'LANG'): val = os.environ.get(envar) diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index fc44c89f410caf..4f994f6a22e22f 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -1,3 +1,6 @@ +import sys + +import locale import os import base64 import gettext @@ -6,8 +9,7 @@ from functools import partial from test import support -from test.support import os_helper - +from test.support import os_helper, run_with_locale # TODO: # - Add new tests, for example for "dgettext" @@ -736,32 +738,63 @@ def create_mo_file(self, lang): f.write(GNU_MO_DATA) return mo_file - def _for_all_vars(self, mo_file, locale): + def _for_all_vars(self, mo_file, locale, expected=True): for var in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'): self.env.set(var, locale) result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) - self.assertEqual(mo_file, result) + if expected: + self.assertEqual(mo_file, result) + else: + self.assertIsNone(result) self.env.unset(var) - @unittest.mock.patch("locale.setlocale", return_value=(None, None)) + @unittest.mock.patch("locale.setlocale", return_value='') def test_find_with_env_vars(self, patch_getlocale): # test that find correctly finds the environment variables # when languages are not supplied + mo_file = self.create_mo_file("ca_ES") + self._for_all_vars(mo_file, "ca_ES") + self._for_all_vars(mo_file, "ca_ES.UTF-8") + self._for_all_vars(mo_file, "ca_ES.UTF-8.mo") + self._for_all_vars(mo_file, "es_ES:ca_ES:fr_FR") + self._for_all_vars(mo_file, "ca_ES@euro") + self._for_all_vars(mo_file, "ca_ES.UTF-8@euro") + self._for_all_vars(mo_file, "ca_ES@valencia") + self._for_all_vars(mo_file, "C", expected=False) + self._for_all_vars(mo_file, "C.UTF-8", expected=False) + + @unittest.mock.patch('gettext._expand_lang') + def test_encoding_not_ignored(self, patch_expand_lang): + self.env.set('LANGUAGE', 'ga_IE.UTF-8') + gettext.find("mofile") + patch_expand_lang.assert_any_call('ga_IE.UTF-8') + self.env.unset('LANGUAGE') + + def test_find_LANGUAGE_priority(self): + orig = locale.setlocale(locale.LC_MESSAGES) + self.addCleanup(lambda: locale.setlocale(locale.LC_MESSAGES, orig)) + self.env.set('LANGUAGE', 'ga_IE') + self.env.set('LC_ALL', 'pt_BR') + locale.setlocale(locale.LC_MESSAGES, 'pt_BR') mo_file = self.create_mo_file("ga_IE") - self._for_all_vars(mo_file, "ga_IE") - self._for_all_vars(mo_file, "ga_IE.UTF-8") - self._for_all_vars(mo_file, "es_ES:ga_IE:fr_FR") - self._for_all_vars(mo_file, "ga_IE@euro") + + result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) + self.assertEqual(result, mo_file) + locale.setlocale(locale.LC_MESSAGES, orig) def test_process_vars_override(self): - mo_file = self.create_mo_file("ga_IE") - with unittest.mock.patch("locale.setlocale", return_value=('ga_IE', 'UTF-8')): + orig = locale.setlocale(locale.LC_MESSAGES) + self.addCleanup(lambda: locale.setlocale(locale.LC_MESSAGES, orig)) + mo_file = self.create_mo_file("ca_ES") + for loc in ("ca_ES", "ca_ES.UTF-8", "ca_ES@euro", "ca_ES@valencia"): + locale.setlocale(locale.LC_MESSAGES, loc) result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) self.assertEqual(mo_file, result) - with unittest.mock.patch("locale.setlocale", return_value=('ga_IE', None)): + for loc in ("C", "C.UTF-8"): + locale.setlocale(locale.LC_MESSAGES, loc) result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) - self.assertEqual(mo_file, result) + self.assertIsNone(result) def test_find_with_languages(self): # test that passed languages are used From d75292d33ed8a8369d789a3f614e893d8183eee6 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Thu, 19 Jun 2025 15:37:57 +0100 Subject: [PATCH 07/11] Who even uses this "Windows" thing...? --- Lib/gettext.py | 2 +- Lib/test/test_gettext.py | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Lib/gettext.py b/Lib/gettext.py index f26bd67d2a4a4c..40087b1cee2060 100644 --- a/Lib/gettext.py +++ b/Lib/gettext.py @@ -493,7 +493,7 @@ def find(domain, localedir=None, languages=None, all=False): languages = [] if val := os.environ.get('LANGUAGE'): languages = val.split(':') - elif loc := locale.setlocale(locale.LC_MESSAGES): + elif os.name == 'posix' and (loc := locale.setlocale(locale.LC_MESSAGES)): languages = loc.split(':') else: for envar in ('LC_ALL', 'LC_MESSAGES', 'LANG'): diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index 4f994f6a22e22f..e442d4b60d4826 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -771,18 +771,20 @@ def test_encoding_not_ignored(self, patch_expand_lang): patch_expand_lang.assert_any_call('ga_IE.UTF-8') self.env.unset('LANGUAGE') + @unittest.skipIf(os.name != "posix", "LC_MESSAGES is posix only") def test_find_LANGUAGE_priority(self): - orig = locale.setlocale(locale.LC_MESSAGES) - self.addCleanup(lambda: locale.setlocale(locale.LC_MESSAGES, orig)) self.env.set('LANGUAGE', 'ga_IE') self.env.set('LC_ALL', 'pt_BR') - locale.setlocale(locale.LC_MESSAGES, 'pt_BR') + if os.name != "posix": + orig = locale.setlocale(locale.LC_MESSAGES) + self.addCleanup(lambda: locale.setlocale(locale.LC_MESSAGES, orig)) + locale.setlocale(locale.LC_MESSAGES, 'pt_BR') mo_file = self.create_mo_file("ga_IE") result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) self.assertEqual(result, mo_file) - locale.setlocale(locale.LC_MESSAGES, orig) + @unittest.skipIf(os.name != "posix", "LC_MESSAGES is posix only") def test_process_vars_override(self): orig = locale.setlocale(locale.LC_MESSAGES) self.addCleanup(lambda: locale.setlocale(locale.LC_MESSAGES, orig)) From 7e2a5645d063e1fecab2dd3577e71e59b3fd93fa Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Thu, 19 Jun 2025 15:39:34 +0100 Subject: [PATCH 08/11] Clean up --- Lib/test/test_gettext.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index e442d4b60d4826..3210f37325f9ca 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -1,5 +1,3 @@ -import sys - import locale import os import base64 @@ -9,7 +7,7 @@ from functools import partial from test import support -from test.support import os_helper, run_with_locale +from test.support import os_helper # TODO: # - Add new tests, for example for "dgettext" From ff7d10a36a27417f6356d0453603c324f85f49ea Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Thu, 19 Jun 2025 16:01:00 +0100 Subject: [PATCH 09/11] Clean up confusion --- Lib/gettext.py | 4 ++-- Lib/test/test_gettext.py | 20 ++++++++------------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Lib/gettext.py b/Lib/gettext.py index 40087b1cee2060..55397026ba3f08 100644 --- a/Lib/gettext.py +++ b/Lib/gettext.py @@ -493,8 +493,8 @@ def find(domain, localedir=None, languages=None, all=False): languages = [] if val := os.environ.get('LANGUAGE'): languages = val.split(':') - elif os.name == 'posix' and (loc := locale.setlocale(locale.LC_MESSAGES)): - languages = loc.split(':') + elif (loc := locale.getlocale()) != (None, None): + languages = [".".join(filter(None, loc))] else: for envar in ('LC_ALL', 'LC_MESSAGES', 'LANG'): val = os.environ.get(envar) diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index 3210f37325f9ca..7daad14edbf7c8 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -747,7 +747,7 @@ def _for_all_vars(self, mo_file, locale, expected=True): self.assertIsNone(result) self.env.unset(var) - @unittest.mock.patch("locale.setlocale", return_value='') + @unittest.mock.patch("locale.getlocale", return_value=(None, None)) def test_find_with_env_vars(self, patch_getlocale): # test that find correctly finds the environment variables # when languages are not supplied @@ -769,30 +769,26 @@ def test_encoding_not_ignored(self, patch_expand_lang): patch_expand_lang.assert_any_call('ga_IE.UTF-8') self.env.unset('LANGUAGE') - @unittest.skipIf(os.name != "posix", "LC_MESSAGES is posix only") def test_find_LANGUAGE_priority(self): self.env.set('LANGUAGE', 'ga_IE') self.env.set('LC_ALL', 'pt_BR') - if os.name != "posix": - orig = locale.setlocale(locale.LC_MESSAGES) - self.addCleanup(lambda: locale.setlocale(locale.LC_MESSAGES, orig)) - locale.setlocale(locale.LC_MESSAGES, 'pt_BR') + orig = locale.setlocale(locale.LC_ALL) + self.addCleanup(lambda: locale.setlocale(locale.LC_ALL, orig)) + locale.setlocale(locale.LC_ALL, 'pt_BR') mo_file = self.create_mo_file("ga_IE") - result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) self.assertEqual(result, mo_file) - @unittest.skipIf(os.name != "posix", "LC_MESSAGES is posix only") def test_process_vars_override(self): - orig = locale.setlocale(locale.LC_MESSAGES) - self.addCleanup(lambda: locale.setlocale(locale.LC_MESSAGES, orig)) + orig = locale.setlocale(locale.LC_ALL) + self.addCleanup(lambda: locale.setlocale(locale.LC_ALL, orig)) mo_file = self.create_mo_file("ca_ES") for loc in ("ca_ES", "ca_ES.UTF-8", "ca_ES@euro", "ca_ES@valencia"): - locale.setlocale(locale.LC_MESSAGES, loc) + locale.setlocale(locale.LC_ALL, loc) result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) self.assertEqual(mo_file, result) for loc in ("C", "C.UTF-8"): - locale.setlocale(locale.LC_MESSAGES, loc) + locale.setlocale(locale.LC_ALL, loc) result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) self.assertIsNone(result) From 307c7f33d033e825bfcae88384ae25c0b1b3e6b6 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Thu, 19 Jun 2025 17:09:53 +0100 Subject: [PATCH 10/11] Skip unsupported locales --- Lib/test/test_gettext.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index 7daad14edbf7c8..2542910f289b31 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -771,10 +771,10 @@ def test_encoding_not_ignored(self, patch_expand_lang): def test_find_LANGUAGE_priority(self): self.env.set('LANGUAGE', 'ga_IE') - self.env.set('LC_ALL', 'pt_BR') + self.env.set('LC_ALL', 'C') orig = locale.setlocale(locale.LC_ALL) self.addCleanup(lambda: locale.setlocale(locale.LC_ALL, orig)) - locale.setlocale(locale.LC_ALL, 'pt_BR') + locale.setlocale(locale.LC_ALL, 'C') mo_file = self.create_mo_file("ga_IE") result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) self.assertEqual(result, mo_file) @@ -784,7 +784,10 @@ def test_process_vars_override(self): self.addCleanup(lambda: locale.setlocale(locale.LC_ALL, orig)) mo_file = self.create_mo_file("ca_ES") for loc in ("ca_ES", "ca_ES.UTF-8", "ca_ES@euro", "ca_ES@valencia"): - locale.setlocale(locale.LC_ALL, loc) + try: + locale.setlocale(locale.LC_ALL, loc) + except locale.Error: + self.skipTest('platform does not support locale') result = gettext.find("mofile", localedir=os.path.join(self.tempdir, "locale")) self.assertEqual(mo_file, result) for loc in ("C", "C.UTF-8"): From fed61fbb8bb54c5944decc0b03b9e28cd98c32e7 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Thu, 19 Jun 2025 17:24:50 +0100 Subject: [PATCH 11/11] Fix new test --- Lib/test/test_gettext.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_gettext.py b/Lib/test/test_gettext.py index 28cc9846705ce5..0a976fce084c4b 100644 --- a/Lib/test/test_gettext.py +++ b/Lib/test/test_gettext.py @@ -10,6 +10,7 @@ from test.support import cpython_only, os_helper from test.support.import_helper import ensure_lazy_imports + # TODO: # - Add new tests, for example for "dgettext" # - Tests should have only one assert. @@ -982,7 +983,7 @@ def test__all__(self): @cpython_only def test_lazy_import(self): - ensure_lazy_imports("gettext", {"re", "warnings", "locale"}) + ensure_lazy_imports("gettext", {"re", "warnings"}) if __name__ == '__main__': pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy