3

My Win 10 system has Spanish language. I mean to fully operate a PowerShell session in English. Across everything I tried (see below), I managed to change the UICulture to en-US for the current session, but not the Culture.

Is there any way I can permanently change the Culture for the current PowerShell session?


Changing the Culture (with no success):

    > $( Get-Culture ; Get-UICulture ; [System.Threading.Thread]::CurrentThread.CurrentCulture ; [System.Threading.Thread]::CurrentThread.CurrentUICulture ; [CultureInfo]::CurrentCulture ; [CultureInfo]::CurrentUICulture ; ) | Format-Table -Property LCID,Name,DisplayName,IsNeutralCulture,UseUserOverride,IsReadOnly
     LCID Name  DisplayName             IsNeutralCulture UseUserOverride IsReadOnly
     ---- ----  -----------             ---------------- --------------- ----------
    11274 es-AR Spanish (Argentina)                False            True      False
     1033 en-US English (United States)            False            True      False
    11274 es-AR Spanish (Argentina)                False            True      False
     1033 en-US English (United States)            False            True      False
    11274 es-AR Spanish (Argentina)                False            True      False
     1033 en-US English (United States)            False            True      False 
    > Set-Culture 'en-US'
    > [Threading.Thread]::CurrentThread.CurrentCulture='en-US'
    > $( Get-Culture ; Get-UICulture ; [System.Threading.Thread]::CurrentThread.CurrentCulture ; [System.Threading.Thread]::CurrentThread.CurrentUICulture ; [CultureInfo]::CurrentCulture ; [CultureInfo]::CurrentUICulture ; ) | Format-Table -Property LCID,Name,DisplayName,IsNeutralCulture,UseUserOverride,IsReadOnly
     LCID Name  DisplayName             IsNeutralCulture UseUserOverride IsReadOnly
     ---- ----  -----------             ---------------- --------------- ----------
    11274 es-AR Spanish (Argentina)                False            True      False
     1033 en-US English (United States)            False            True      False
    11274 es-AR Spanish (Argentina)                False            True      False
     1033 en-US English (United States)            False            True      False
    11274 es-AR Spanish (Argentina)                False            True      False
     1033 en-US English (United States)            False            True      False

Note: I inferred System.Threading.Thread and Threading.Thread are the same.


Other things I tried:

Answers here and here. Since they are SO posts, I guess not posting them here reduces the clutter. But I could add them if deemed convenient.

I found a few other posts, all repeating the same commands.


EDIT:

Methods for setting Culture:

S1. Win Settings -> Time and Language -> Region -> Regional Format

S2. Set-Culture <culture>

S3. [CultureInfo]::CurrentCulture=<culture>

S4. [Threading.Thread]::CurrentThread.CurrentCulture=<culture>

Methods for getting Culture:

G1. Same as S1.

G2. Get-Culture

G3. [CultureInfo]::CurrentCulture

G4. [Threading.Thread]::CurrentThread.CurrentCulture

What I found:

  1. S3/G3 and S4/G4 seem to involve the same session setting / environment variable / registry key, etc. (?), and to be completely equivalent.
  2. Method S1 affects (G2, G3, G4) in a new session.
  3. Method S2 affects G1 immediately, and (G3, G4) in a new session.
  4. Methods (S3, S4) affect (G3, G4) immediately (trivial) but only in the current thread, not session, and (1, 2) not at all.
  5. The options available in method S1 are richer than those for method S2. I can change in S1 to "Spanish (Argentina)", "English (US)", etc., and it will get reflected in PS. But if I change in S1 to "Spansh (Brazil)", then PS will show en-US, as if it were a fallback Culture.

1 Answers1

3

The following function will change both Culture and UICulture for the current PowerShell session in PowerShell 5.1:

function Set-PowerShellLanguage {
    
    Param (
        [Parameter(Mandatory)] 
        [System.Globalization.CultureInfo] $CultureInfo
    )

    if ($CultureInfo -notin (Get-WinUserLanguageList | % {$_.LanguageTag})) {
        Write-Error "Language pack for $CultureInfo is not installed."
        return
    }
    [System.Reflection.Assembly]::Load('System.Management.Automation').GetType('Microsoft.PowerShell.NativeCultureResolver').GetField('m_Culture', 'NonPublic, Static').SetValue($null, $CultureInfo)
    [System.Reflection.Assembly]::Load('System.Management.Automation').GetType('Microsoft.PowerShell.NativeCultureResolver').GetField('m_uiCulture', 'NonPublic, Static').SetValue($null, $CultureInfo)
}

It is actually a merge of the already linked answer and mkelement0's comment.

Example usage:

PS C:\> Get-Culture

LCID             Name             DisplayName
----             ----             -----------
1033             en-US            English (United States)


PS C:\> Get-UICulture

LCID             Name             DisplayName
----             ----             -----------
1033             en-US            English (United States)


PS C:\> Set-PowerShellLanguage 'es-AR'
PS C:\> Get-Culture

LCID             Name             DisplayName
----             ----             -----------
11274            es-AR            Spanish (Argentina)


PS C:\> Get-UICulture

LCID             Name             DisplayName
----             ----             -----------
11274            es-AR            Spanish (Argentina)


PS C:\>
stackprotector
  • 10,498
  • 4
  • 35
  • 64
  • Great! Is there an equivalent to `Get-WinUserLanguageList` for UICultures? The corresponding list of available culture may (perhaps) be different... I'm just guessing, I don't know. – sancho.s ReinstateMonicaCellio Jul 28 '20 at 07:46
  • @sancho.sReinstateMonicaCellio I think there is a misunderstanding. `Get-WinUserLanguageList` returns the installed language packs aka `CultureInfo`. There is no distinction between `Culture` and `UICulture`. It's more like you use one `CultureInfo` for both, `Culture` and `UICulture`, in the function above. I refactored some names to reduce ambiguities. – stackprotector Jul 28 '20 at 08:08
  • Just a note that this doesn't work on PowerShell v1. I'll try to find a workaround for downlevel versions. Also, the following works for PowerShell Core 6.0 and newer: [System.Threading.Thread]::CurrentThread.CurrentUICulture = $culture; [System.Threading.Thread]::CurrentThread.CurrentCulture = $culture – Frank Lesniak Jan 07 '21 at 15:06