Repository: microsoft/terminal (language: cpp)

Issue:
No language options
### Windows Terminal version

1.22.240723001

### Windows build number

19045.4651

### Other Software

_No response_

### Steps to reproduce

download 1.22.240723001
double click wt.exe
open setting-appearance

### Expected Behavior

can set language under setting-appearance

### Actual Behavior

no language settings in GUI:
![image](https://github.com/user-attachments/assets/274ad516-842f-4558-8e84-70ea2ee7f80f)



Discussion / hints:
We currently rely on the [`PrimaryLanguageOverride` API](https://learn.microsoft.com/en-us/uwp/api/windows.globalization.applicationlanguages.primarylanguageoverride?view=winrt-26100) to implement language switching. Unfortunately, that API only works for packaged applications so we cannot offer it when Windows Terminal is unpackaged.

However, it raises a good point... We officially offer an unpackaged distribution of Windows Terminal, so it should also offer this feature. I suspect it's possible for us to easily reproduce the `PrimaryLanguageOverride` API ourselves.
Thank you sir, I expect you can add this feature soon.
If we want to fix this, we need an open issue to track the process. 🙂 I'll mark this for discussion and then we can decide internally if this is worth pursuing or not.

Fix patch:
diff --git a/src/cascadia/TerminalApp/AppLogic.cpp b/src/cascadia/TerminalApp/AppLogic.cpp
index b892c10cb55..b7e0eae91a7 100644
--- a/src/cascadia/TerminalApp/AppLogic.cpp
+++ b/src/cascadia/TerminalApp/AppLogic.cpp
@@ -331,8 +331,16 @@ namespace winrt::TerminalApp::implementation
     void AppLogic::_ApplyLanguageSettingChange() noexcept
     try
     {
+        const auto language = _settings.GlobalSettings().Language();
+
         if (!IsPackaged())
         {
+            if (!language.empty())
+            {
+                // We cannot use the packaged app API, PrimaryLanguageOverride, but we *can* tell the resource loader
+                // to set the Language for all loaded resources to the user's preferred language.
+                winrt::Windows::ApplicationModel::Resources::Core::ResourceContext::SetGlobalQualifierValue(L"Language", language);
+            }
             return;
         }
 
@@ -340,8 +348,6 @@ namespace winrt::TerminalApp::implementation
 
         // NOTE: PrimaryLanguageOverride throws if this instance is unpackaged.
         const auto primaryLanguageOverride = ApplicationLanguages::PrimaryLanguageOverride();
-        const auto language = _settings.GlobalSettings().Language();
-
         if (primaryLanguageOverride != language)
         {
             ApplicationLanguages::PrimaryLanguageOverride(language);
diff --git a/src/cascadia/TerminalApp/pch.h b/src/cascadia/TerminalApp/pch.h
index 394990ee34d..85b7090a936 100644
--- a/src/cascadia/TerminalApp/pch.h
+++ b/src/cascadia/TerminalApp/pch.h
@@ -27,6 +27,7 @@
 
 #include <winrt/Windows.ApplicationModel.h>
 #include <winrt/Windows.ApplicationModel.DataTransfer.h>
+#include <winrt/Windows.ApplicationModel.Resources.Core.h>
 #include <winrt/Windows.Foundation.h>
 #include <winrt/Windows.Foundation.Collections.h>
 #include <winrt/Windows.Foundation.Metadata.h>
diff --git a/src/cascadia/TerminalSettingsEditor/Launch.xaml b/src/cascadia/TerminalSettingsEditor/Launch.xaml
index 8aeca2f92b3..44feee7016e 100644
--- a/src/cascadia/TerminalSettingsEditor/Launch.xaml
+++ b/src/cascadia/TerminalSettingsEditor/Launch.xaml
@@ -140,8 +140,7 @@
             </local:SettingContainer>
 
             <!--  Language  -->
-            <local:SettingContainer x:Uid="Globals_Language"
-                                    Visibility="{x:Bind ViewModel.LanguageSelectorAvailable}">
+            <local:SettingContainer x:Uid="Globals_Language">
                 <ComboBox ItemsSource="{x:Bind ViewModel.LanguageList}"
                           SelectedItem="{x:Bind ViewModel.CurrentLanguage, Mode=TwoWay}"
                           Style="{StaticResource ComboBoxSettingStyle}">
diff --git a/src/cascadia/TerminalSettingsEditor/LaunchViewModel.cpp b/src/cascadia/TerminalSettingsEditor/LaunchViewModel.cpp
index 440f43211a4..cf99cadb9a0 100644
--- a/src/cascadia/TerminalSettingsEditor/LaunchViewModel.cpp
+++ b/src/cascadia/TerminalSettingsEditor/LaunchViewModel.cpp
@@ -82,16 +82,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
         return language.NativeName();
     }
 
-    // Returns whether the language selector is available/shown.
-    //
-    // winrt::Windows::Globalization::ApplicationLanguages::PrimaryLanguageOverride()
-    // doesn't work for unpackaged applications. The corresponding code in TerminalApp is disabled.
-    // It would be confusing for our users if we presented a dysfunctional language selector.
-    bool LaunchViewModel::LanguageSelectorAvailable()
-    {
-        return IsPackaged();
-    }
-
     // Returns the list of languages the user may override the application language with.
     // The returned list are BCP 47 language tags like {"und", "en-US", "de-DE", "es-ES", ...}.
     // "und" is short for "undefined" and is synonymous for "Use system language" in this code.
@@ -102,12 +92,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
             return _languageList;
         }
 
-        if (!LanguageSelectorAvailable())
-        {
-            _languageList = {};
-            return _languageList;
-        }
-
         // In order to return the language list this code does the following:
         // [1] Get all possible languages we want to allow the user to choose.
         //     We have to acquire languages from multiple sources, creating duplicates. See below at [1].
@@ -179,19 +163,24 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
             return _currentLanguage;
         }
 
-        if (!LanguageSelectorAvailable())
+        winrt::hstring currentLanguage;
+        if (IsPackaged())
         {
-            _currentLanguage = {};
-            return _currentLanguage;
+            // NOTE: PrimaryLanguageOverride throws if this instance is unpackaged.
+            currentLanguage = winrt::Windows::Globalization::ApplicationLanguages::PrimaryLanguageOverride();
+        }
+        else
+        {
+            if (_Settings.GlobalSettings().HasLanguage())
+            {
+                currentLanguage = _Settings.GlobalSettings().Language();
+            }
         }
 
-        // NOTE: PrimaryLanguageOverride throws if this instance is unpackaged.
-        auto currentLanguage = winrt::Windows::Globalization::ApplicationLanguages::PrimaryLanguageOverride();
         if (currentLanguage.empty())
         {
             currentLanguage = systemLanguageTag;
         }
-
         _currentLanguage = winrt::box_value(currentLanguage);
         return _currentLanguage;
     }
diff --git a/src/cascadia/TerminalSettingsEditor/LaunchViewModel.h b/src/cascadia/TerminalSettingsEditor/LaunchViewModel.h
index d96046524f4..98851b74dc3 100644
--- a/src/cascadia/TerminalSettingsEditor/LaunchViewModel.h
+++ b/src/cascadia/TerminalSettingsEditor/LaunchViewModel.h
@@ -20,7 +20,6 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
         // "Deutsch (Deutschland)". This works independently of the user's locale.
         static winrt::hstring LanguageDisplayConverter(const winrt::hstring& tag);
 
-        bool LanguageSelectorAvailable();
         winrt::Windows::Foundation::Collections::IObservableVector<winrt::hstring> LanguageList();
         winrt::Windows::Foundation::IInspectable CurrentLanguage();
         void CurrentLanguage(const winrt::Windows::Foundation::IInspectable& tag);
diff --git a/src/cascadia/TerminalSettingsEditor/LaunchViewModel.idl b/src/cascadia/TerminalSettingsEditor/LaunchViewModel.idl
index 3781c24b876..fe39cbccb10 100644
--- a/src/cascadia/TerminalSettingsEditor/LaunchViewModel.idl
+++ b/src/cascadia/TerminalSettingsEditor/LaunchViewModel.idl
@@ -10,7 +10,6 @@ namespace Microsoft.Terminal.Settings.Editor
     runtimeclass LaunchViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
     {
         static String LanguageDisplayConverter(String tag);
-        Boolean LanguageSelectorAvailable { get; };
         Windows.Foundation.Collections.IObservableVector<String> LanguageList { get; };
         IInspectable CurrentLanguage;
 


Test patch: