PowerShell UICulture vs. Windows setting
Asked Answered
R

2

1

During my tinkering with PS 5.1 under Win 10, related to the objective of question Fully change language (including Culture) for the current PowerShell session, I came across a couple of related questions.

  1. Where is the Windows setting associated with the UICulture? I did not find the "Keyboard and Languages" tab of the "Region and Language" control panel as indicated here.

  2. Can this be persistently changed from within PS? All I found so far only persist in a session.


The setting Settings -> Time and Language -> Language -> Windows display language shows "Español (España)", and PS gives

> Get-UICulture ; [System.Threading.Thread]::CurrentThread.CurrentUICulture ; [CultureInfo]::CurrentUICulture ;
LCID             Name             DisplayName
----             ----             -----------
1033             en-US            English (United States)
1033             en-US            English (United States)
1033             en-US            English (United States)

without any intervening changes and in a session just launched.

Rikkiriksdag answered 15/7, 2020 at 7:26 Comment(0)
B
7

In .NET, cultures (System.Globalization.CultureInfo) are used to control two related, but independent aspects of (human) culture-specific for-display representations:

  • The effective UI culture, reflected in [cultureinfo]::CurrentUICulture, controls the (human) language that should be used for UI elements and end-user messages, such as error messages.

    • On Windows, its value is inherited from the so-called Windows display language, which is a persistent, user-specific setting that you can modify as described below.

    • In PowerShell, you can also query the effective UI culture via the automatic $PSUICulture variable (reports the culture name only) or the Get-UICulture cmdlet (reports a [cultureinfo] instance).
      Caveat: In Windows PowerShell, the value reported is the one that was in effect at session start-up time (which was the then-current persisted value), so any in-session changes are not reflected. This problem has been corrected in PowerShell [Core] v6+.

  • The effective culture, reflected in [cultureinfo]::CurrentCulture, controls the formats used to represent numbers, currency values, and date/time values.

    • On Windows, its value is inherited from the active locale, a.k.a. regional format, which are persistent, user-specific settings that you can modify as described below.

    • In PowerShell, you can also query the effective UI culture via the automatic $PSCulture variable (reports the culture name only) Get-Culture cmdlet (reports a [cultureinfo] instance).
      Caveat: In Windows PowerShell, the value reported is the one that was in effect at session start-up time, so any in-session changes are not reflected. This problem has been corrected in PowerShell [Core] v6+.


Switching to a different culture:

Interactive (GUI) methods, which are invariably persistent, for the current user:

  • UI culture, a.k.a Windows display language:

    • On Windows 10, open the Settings application (e.g., via Start Menu), go to category Time & Language, then click on Language in the sidebar on the left.

      • Shortcuts:

        • Open the Settings app quickly:

          • Use keyboard shortcut WinKey-i.
          • Run start ms-settings: (works from cmd too).
        • In Start Menu, simply type "Language" and select Language Settings from the result - this takes you directly to the relevant page in the Settings app.

        • Run intl.cpl to open the legacy Region Control Panel applet and click on the Language preferences link, which takes you to the relevant page in the Settings app.

  • Culture, a.k.a Regional format (locale):

    • On Windows 10, open the Settings application (e.g., via Start Menu), go to category Time & Language, then click on Region in the sidebar on the left, then select the desired culture under Regional format (the Region setting at the top does not control the culture).

      • Shortcuts:

        • In Start Menu, simply type "Regional format" and select Set regional format from the result - this takes you directly to the relevant page in the Settings app.

        • Run intl.cpl to open the legacy Region Control Panel applet and select the desired culture from the Format: drop-down list.

Note: These settings apply to .NET and non-.NET applications equally, assuming these applications are designed to respect the user's regional formats (locale, culture) and display language (UI culture) and come with language-specific resources.
By contrast, making in-session-only changes via [cultureinfo]::CurrentUICulture / [cultureinfo]::CurrentCulture (see below) applies to .NET applications only.

Programmatic methods:

  • Persistent, current-user changes (equivalents of the GUI methods):

    • UI culture, a.k.a Windows display language:

      • There is no Set-UICulture cmdlet, but in Windows 8 / Windows Server 2012 R2 and above you can use the Set-WinUILanguageOverride cmdlet.
        Note that the language pack for the language associated with the targeted culture must either come with the system or must have been downloaded previously.

      • Important: The change doesn't take effect until you either log off and back on or reboot.

    • Culture, a.k.a Regional format (locale):

      • Use the Set-Culture cmdlet, available in Windows 8 / Windows Server 2012 R2 and above.

      • Important: The change only takes effect in future PowerShell sessions, but no logoff / reboot is required.

  • In-session-only changes:

    • Important: Such changes are apply only to .NET-based applications. Therefore, calling a non-.NET console application from a PowerShell session in which culture was changed will have no impact on that console application. However, the change does take effect for calls to PowerShell cmdlets, scripts and functions. Even though the scope of the change is technically limited to the current thread, PowerShell also propagates the change to code executed in new threads (Start-ThreadJob and ForEach-Object -Parallel) as well as code executed on remote machines, via PowerShell remoting (e.g., Invoke-Command). Curiously, however, as of PowerShell 7.0, background jobs (Start-Job), which run in child processes, do not inherit the calling thread's culture - see this GitHub issue.

    • You can assign to [cultureinfo]::CurrentUICulture / [cultureinfo]::CurrentCulture to change the UI culture / culture for the current thread (only, non-persistently); e.g., the following command outputs the current date and time using the French culture:

      • [cultureinfo]::CurrentCulture = 'fr-FR'; Get-Date
    • Caveat: Due to a bug in Windows PowerShell, [cultureinfo]::CurrentUICulture and [cultureinfo]::CurrentCulture are unexpectedly reset to the session start-up values after every interactively submitted command; this problem has been fixed in PowerShell [Core] v6+ - see this answer.

    • The upshot is that if you want to run entire PowerShell sessions with different cultures than persistently configured, you can place assignments to [cultureinfo]::CurrentUICulture and [cultureinfo]::CurrentCulture in your $PROFILE file in PowerShell [Core] v6+, but you'll need a workaround for Windows PowerShell - see this answer.

      • Caveat: Windows PowerShell statically initializes $PSUICulture and $PSCulture and therefore these variables do not reflect the effective culture set by the workaround (which relies on modifying a non-public field); however, Get-UICulture / Get-Culture as well as [cultureinfo]::CurrentUICulture / [cultureinfo]::CurrentCulture do.
Bogtrotter answered 16/7, 2020 at 17:20 Comment(0)
R
0

This answer complements that by mklement0. The setting in a PS session is inherited from Win Settings -> Time and Language -> Language -> Display language for Windows upon starting the session.

So to change this "persistently" for all sessions one has to change the Windows setting. Alternatively, one can change this only for the PS session in profile.ps1, and this would not "taint" the Windows configuration.

I am not certain any of this can be managed by directly accessing HKEY_CURRENT_USER\Control Panel\International ([ref]) (or HKEY_CURRENT_USER\Volatile Environment?) from PS.

Note that (in Windows PowerShell) $PSUICulture is statically initialized at the time of the last Windows logon by retrieving the Windows setting above. So it is insensitive to the current PS setting (possibly changed during the current PS session). So $PSUICulture may differ from Get-UICulture. This would not apply to PowerShell Core.

Rikkiriksdag answered 23/7, 2020 at 15:33 Comment(7)
Good points; I've restructured my answer to incorporate most of them. I wouldn't recommend dealing with the registry directly, because changing the culture changes a whole raft of registry values. As for what $PSUICulture / $PSCulture / Get-UICulture / Get-Culture reflect: in PowerShell [Core] v6+, they - sensibly - reflect the values currently in effect. In Windows PowerShell, unfortunately, they always reflect the values at session start-up time.Bogtrotter
I've added a paragraph about the scope of in-session culture changes to my answer, which includes discovery of a surprising inconsistency. It is implied by my previous comment, but to spell it out: The statement "So $PSUICulture may differ from Get-UICulture." is not correct: for a given edition, the results are always the same (except for the data type), but the editions differ by what value they report (current value in PSCore, session-start-up value in WinPS). Can you please either correct this, or, given that my answer now hopefully tells the full story, consider deleting your answer?Bogtrotter
@Bogtrotter - This is what I see. > $PSUICulture ; Get-UICulture <br> es-ES <br> LCID Name DisplayName <br> ---- ---- ----------- <br> 1033 en-US English (United States) <br> Why do you say my statement is not correct? Perhaps I should rephrase "The screen output of $PSUICulture may differ from Get-UICulture"?Rikkiriksdag
1) > $PSUICulture ; (Get-UICulture).Name <br> es-ES <br> en-US Preceding this with [cultureinfo]::CurrentUICulture = <culture> ; does not change output with either 'en-US', 'es-ES', 'es-AR', 2) Script Set-PowerShellUICulture loaded in profile.ps1, 3) PS 5.1.17763.1007Rikkiriksdag
I see - that is solely because of the hack that Set-PowerShellUICulture constitutes (modification of a non-public field), so you should make that clear (you wouldn't face that problem in PowerShell [Core] v6+, where assigning to [cultureinfo]::CurrentUICulture in $PROFILE is sufficient). The reason for the discrepancy with the hack is that WinPS statically initializes $PSUICulture / $PSCulture, so it is unaware of the change performed by the hack. I've added a warning to my answer, and I've also left a(nother) comment at the answer that contains the hack.Bogtrotter
Ok. Would you think there is any implication in WinPS, other than the fact that the value of $PSUICulture may not be meaningful for the current session?Rikkiriksdag
It is the only ramification I am personally aware of, and I think it's the only one, but I'm not sure - that's the problem with using such a hack (as helpful as it is in principle).Bogtrotter

© 2022 - 2024 — McMap. All rights reserved.