Skip to content

[Bug]: Current locale not honored on Windows #25006

Open

Description

@StefRe

Bug summary

  1. Date formatting using strftime format codes should use the current locale's names. While this works as expected on Linux, ConciseDateFormatter by default shows English month names etc. when running on a non-English locale. It only works correctly after explicitly setting the locale to the current one by locale.setlocale(locale.LC_ALL, '').

  2. Setting axes.formatter.use_locale to True doesn't have any effect on Windows unless you explicitly set the locale to the current one by locale.setlocale(locale.LC_ALL, '') (again, it works correctly on Linux). I don't understand why this is so as __init__ does exactly the same thing but for some reason without effect on Windows:

    if rcParams['axes.formatter.use_locale']:
    locale.setlocale(locale.LC_ALL, '')

Code for reproduction

import locale
import platform

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

dates = np.arange(np.datetime64('2022-12-01'), np.datetime64('2022-12-02'), np.timedelta64(1, 'h'))
values = np.zeros_like(dates, dtype=int)

def plot(title):
    fig, ax = plt.subplots(figsize=(6, 1.5), layout='constrained')
    ax.plot(dates, values, 'white')
    ax.xaxis.set_major_formatter(mpl.dates.ConciseDateFormatter(mpl.dates.AutoDateLocator()))
    ax.text(.5, .5,
            f"{locale.getlocale() = }\n{ax.yaxis.get_major_formatter().get_useLocale() = }\n({platform.system()})",
            transform=ax.transAxes, ha='center', va='center')
    ax.set_title(title)
    fig.savefig(title + '.png')

# use \N{MODIFIER LETTER COLON} instead of regular colon for Windows file names
plot('1꞉ default')

with mpl.rc_context({'axes.formatter.use_locale': True}):
    plot('2꞉ axes.formatter.use_locale = True')

locale.setlocale(locale.LC_ALL, '')
plot("3꞉ setlocale(locale.LC_ALL, '')")

with mpl.rc_context({'axes.formatter.use_locale': True}):
    plot("4꞉ axes.formatter.use_locale = True after setlocale(locale.LC_ALL, '')")

Actual outcome

On Windows:

1꞉ default--> should be Dez instead of Dec

1꞉ default

2: axes.formatter.use_locale = True --> should be 0,00 instead of 0.00

2꞉ axes formatter use_locale = True

3: after setlocale(locale.LC_ALL, '') --> this works correctly

3꞉ setlocale(locale LC_ALL, '')

4: axes.formatter.use_locale = True after setlocale(locale.LC_ALL, '') --> this works correctly too

4꞉ axes formatter use_locale = True after setlocale(locale LC_ALL, '')

Expected outcome

On Linux

All four cases are correct. The expected outcome on Windows is the same as on Linux.

1꞉ default

2꞉ axes formatter use_locale = True

3꞉ setlocale(locale LC_ALL, '')

4꞉ axes formatter use_locale = True after setlocale(locale LC_ALL, '')

Additional information

The issue is only on Windows, everything is fine on Linux (can't test it on MacOS but I suppose it'd be the same as on Linux).

Operating system

Windows

Matplotlib Version

3.6.3

Matplotlib Backend

No response

Python version

3.10

Jupyter version

No response

Installation

conda

Activity

  1. StefRe commented on Jan 16, 2023

    @StefRe
    ContributorAuthor

    As a side note, the Formatting date ticks using ConciseDateFormatter example incorrectly speaks about localization where it must read customization: Python's strftime format codes always use the locale's names for days, months etc. so there is neither the necessity nor the possibility of a localization in matplotlib. If you want to localize the names you must set the locale accordingly, you can't do it by changing the formatter's formats.

  2. StefRe commented on Jan 31, 2023

    @StefRe
    ContributorAuthor

    I found the culprit: this has nothing to do with Windows or Linux but with the Gtk backend. Using any Gtk backend sets the locale to the user's default setting (same as locale.setlocale(locale.LC_ALL, '')).

    Running

    import subprocess
    import matplotlib as mpl
    
    for backend in mpl.rcsetup.all_backends:
        cp = subprocess.run(['python.exe', 'use_backend.py', backend], capture_output=True)
        print(cp.stdout.decode())

    with the following use_backend.py:

    import locale
    import sys
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    
    backend = sys.argv[1]
    try:
        print(backend, end=': ')
        old_locale = locale.setlocale(locale.LC_NUMERIC)
        mpl.use(backend)
        plt.subplots()
        new_locale = locale.setlocale(locale.LC_NUMERIC)
        print(f'left {old_locale} unchanged' if new_locale == old_locale else f'changed locale from {old_locale} to {new_locale}')
    except Exception as ex:
        print(f'raised {type(ex).__name__}')

    gives the following output (Windows 10):

    GTK3Agg: changed locale from C to de_DE
    GTK3Cairo: changed locale from C to de_DE
    GTK4Agg: changed locale from C to de_DE
    GTK4Cairo: changed locale from C to de_DE
    MacOSX: raised ImportError
    nbAgg: left C unchanged
    QtAgg: left C unchanged
    QtCairo: left C unchanged
    Qt5Agg: left C unchanged
    Qt5Cairo: left C unchanged
    TkAgg: left C unchanged
    TkCairo: left C unchanged
    WebAgg: left C unchanged
    WX: left C unchanged
    WXAgg: left C unchanged
    WXCairo: left C unchanged
    agg: left C unchanged
    cairo: left C unchanged
    pdf: left C unchanged
    pgf: left C unchanged
    ps: left C unchanged
    svg: left C unchanged
    template: left C unchanged
    

    @oscargus: could you remove the "OS: Microsoft" tag, please.

    I don't have a Mac so maybe someone can run the above on MacOS, just for completeness.

  3. StefRe commented on Jan 31, 2023

    @StefRe
    ContributorAuthor

    Regarding using locale number and date formatting in matplotlib:

    1. The rcParams['axes.formatter.use_locale'] parameter doesn't work as one would expect: it only has any effect (sets the locale) when set in the config file (see here); later changes directly to the mpl.rcParams or using the mpl.rc_context context manager have no effect as they don't trigger the setting of the locale. As solution could be to move the setlocale call from matplotlib's __init__ to __setitem__ of RcParams.
    2. Setting rcParams['axes.formatter.use_locale'] to True in the config file also effects date formatting (%a, %A, %b, %B, %c,, %x, %X). This should be documented.
    3. Maybe the locale should be reset to C when using any Gtk backend to be consitent with other backends, although this is a breaking API change. If we don't want to do this for backward compatibility reasons the specific behaviour of the Gtk backends with regard to locales should be documented.
    4. Fix the wording of the Localization of date formats example (see comment above: [Bug]: Current locale not honored on Windows #25006 (comment))

    Any thoughts, in particular to 3. and 1.?

  4. anntzer commented on Jan 31, 2023

    @anntzer
    Contributor

    Point 1. (using __setitem__) seems reasonable.
    Regarding 3., our longstanding policy has been that if a GUI toolkit resets the locale, we should not undo that ourselves; see #6706 and the various linked issues.

  5. tacaswell commented on Jan 31, 2023

    @tacaswell
    Member

    Agree on 1 that moving this __setitem__ is a good idea.

    Agree on 2 that it is worth pointing out the full extent of this setting.

    On 3, I also agree with @anntzer that if the GUIs are doing things we should not get in the way at the backend level. A way my thinking has changed a bit from 2016 is that there might be a case for forcing the locale in pyplot. We (I) have started to think of pyplot as our "application" so doing work there to make the behavior consistent is probably reasonable (if you do not want us to "help", do not import pyplot!).

  6. mironleon commented on Apr 9, 2026

    @mironleon

    I'm also running into this bug. If I run the script from the comment above, I get the following

    gtk3agg: raised ImportError
    gtk3cairo: raised ImportError
    gtk4agg: raised ImportError
    gtk4cairo: raised ImportError
    macosx: raised ImportError
    nbagg: left C unchanged
    notebook: left C unchanged
    qtagg: changed locale from C to nl_NL.UTF-8
    qtcairo: raised ImportError
    qt5agg: raised ImportError
    qt5cairo: raised ImportError
    tkagg: left C unchanged
    tkcairo: raised ImportError
    webagg: left C unchanged
    wx: raised ModuleNotFoundError
    wxagg: raised ModuleNotFoundError
    wxcairo: raised ModuleNotFoundError
    agg: left C unchanged
    cairo: raised ImportError
    pdf: left C unchanged
    pgf: left C unchanged
    ps: left C unchanged
    svg: left C unchanged
    template: left C unchanged
    

    qtagg is the default backend on my machine.

    Which means in our scientific simulation library, a script can fail if it includes a matplotlib plotting call, since that changes the locale and afterwards we use tinyexpr (via Cython) to parse an expression. This program is locale dependent and only really works with the C numeric locale.

    If anyone can give some pointers, I'd be happy to try and fix this, since it is a very annoying an subtle bug

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions