Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Lib/locale.py
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,11 @@ def getpreferredencoding(do_setlocale=True):
#
# removed 'el_gr@euro'
# removed 'uz_uz@cyrillic'
#
# gh-151316:
# Prefer UTF-8 for en_IN. X11 locale.alias maps en_IN to ISO8859-1 and that
# entry overrides glibc's en_IN/UTF-8 during makelocalealias regeneration,
# so hardcode the modern codeset (mirroring the c.utf8 carve-out).

locale_alias = {
'a3': 'az_AZ.KOI8-C',
Expand Down Expand Up @@ -1066,7 +1071,7 @@ def getpreferredencoding(do_setlocale=True):
'en_hk': 'en_HK.ISO8859-1',
'en_ie': 'en_IE.ISO8859-1',
'en_il': 'en_IL.ISO8859-1',
'en_in': 'en_IN.ISO8859-1',
'en_in': 'en_IN.UTF-8',
'en_ng': 'en_NG.UTF-8',
'en_nz': 'en_NZ.ISO8859-1',
'en_ph': 'en_PH.ISO8859-1',
Expand Down
39 changes: 39 additions & 0 deletions Lib/test/test_locale.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,13 @@ def test_english(self):
self.check('english', 'en_EN.ISO8859-1')
self.check('english_uk.ascii', 'en_GB.ISO8859-1')

def test_en_in_utf8(self):
# gh-151316: en_IN is UTF-8 on modern glibc; do not invent ISO8859-1.
self.check('en_IN', 'en_IN.UTF-8')
self.check('en_in', 'en_IN.UTF-8')
self.assertEqual(locale._parse_localename('en_IN'), ('en_IN', 'UTF-8'))
self.assertEqual(locale._parse_localename('en_in'), ('en_IN', 'UTF-8'))

def test_hyphenated_encoding(self):
self.check('az_AZ.iso88599e', 'az_AZ.ISO8859-9E')
self.check('az_AZ.ISO8859-9E', 'az_AZ.ISO8859-9E')
Expand Down Expand Up @@ -642,6 +649,38 @@ def test_getlocale_with_modifier(self, localename, localetuple):
self.assertEqual(locale.getlocale(locale.LC_CTYPE), localetuple)


class TestEnINLocale(unittest.TestCase):
"""gh-151316: en_IN must round-trip without inventing ISO8859-1."""

def setUp(self):
self.oldlocale = locale.setlocale(locale.LC_CTYPE)
self.addCleanup(locale.setlocale, locale.LC_CTYPE, self.oldlocale)

def test_getlocale_setlocale_roundtrip(self):
try:
locale.setlocale(locale.LC_CTYPE, 'en_IN')
except locale.Error as exc:
self.skipTest(str(exc))
loc = locale.getlocale(locale.LC_CTYPE)
self.assertEqual(loc[0], 'en_IN')
self.assertNotEqual(loc[1], 'ISO8859-1')
locale.setlocale(locale.LC_CTYPE, loc)
self.assertEqual(locale.getlocale(locale.LC_CTYPE), loc)

def test_setlocale_from_getlocale_tuple(self):
# Reproduces the issue report: setlocale(LC_*, getlocale()).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is irrelevant as a comment.

try:
locale.setlocale(locale.LC_CTYPE, 'en_IN.UTF-8')
except locale.Error:
try:
locale.setlocale(locale.LC_CTYPE, 'en_IN')
except locale.Error as exc:
self.skipTest(str(exc))
loc = locale.getlocale(locale.LC_CTYPE)
locale.setlocale(locale.LC_CTYPE, loc)
self.assertEqual(locale.getlocale(locale.LC_CTYPE)[0], 'en_IN')


class TestMiscellaneous(unittest.TestCase):
def test_defaults_UTF8(self):
# Issue #18378: on (at least) macOS setting LC_CTYPE to "UTF-8" is
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
:mod:`locale` now maps the ``en_IN`` locale alias to ``en_IN.UTF-8``
instead of the obsolete X11 ``ISO8859-1`` codeset. This restores
``setlocale(getlocale())`` round-trips on modern glibc systems where
``en_IN`` is UTF-8-only.
3 changes: 3 additions & 0 deletions Tools/i18n/makelocalealias.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ def check(data):
# Hardcode 'c.utf8' -> 'C.UTF-8' because 'en_US.UTF-8' does not exist
# on all platforms.
data['c.utf8'] = 'C.UTF-8'
# Hardcode 'en_in' -> 'en_IN.UTF-8'. X11 locale.alias still maps en_IN to
# ISO8859-1 and would otherwise override glibc's en_IN/UTF-8 (gh-151316).
data['en_in'] = 'en_IN.UTF-8'
while True:
# Repeat optimization while the size is decreased.
n = len(data)
Expand Down
Loading