From 2355c2af62282ff36e56106495c09ed5cfcc3672 Mon Sep 17 00:00:00 2001
From: Ac_K <Acoustik666@gmail.com>
Date: Wed, 11 Jan 2023 01:29:22 +0100
Subject: [PATCH] ava: Generate Locale menu automatically (#4243)

Currently in `MenuMainBarView.axaml` we list all available languages and hardcode the language name with the language key.
It's a bit bad beause if we want to add a new language, we have to edit the `csproj` and the `axaml` with the translated language name and the language code.
I've put all translations in their respective locale files, add code into `MainMenuBarView` constructor to generate the menu automatically. Now we just have to edit the `csproj` if we want to add a new language.
---
 Ryujinx.Ava/Assets/Locales/de_DE.json         |  3 +-
 Ryujinx.Ava/Assets/Locales/el_GR.json         |  3 +-
 Ryujinx.Ava/Assets/Locales/en_US.json         |  4 +-
 Ryujinx.Ava/Assets/Locales/es_ES.json         |  3 +-
 Ryujinx.Ava/Assets/Locales/fr_FR.json         |  3 +-
 Ryujinx.Ava/Assets/Locales/it_IT.json         |  3 +-
 Ryujinx.Ava/Assets/Locales/ja_JP.json         |  3 +-
 Ryujinx.Ava/Assets/Locales/ko_KR.json         |  3 +-
 Ryujinx.Ava/Assets/Locales/pl_PL.json         |  3 +-
 Ryujinx.Ava/Assets/Locales/pt_BR.json         |  3 +-
 Ryujinx.Ava/Assets/Locales/ru_RU.json         |  3 +-
 Ryujinx.Ava/Assets/Locales/tr_TR.json         |  3 +-
 Ryujinx.Ava/Assets/Locales/uk_UA.json         |  3 +-
 Ryujinx.Ava/Assets/Locales/zh_CN.json         |  3 +-
 Ryujinx.Ava/Assets/Locales/zh_TW.json         |  3 +-
 Ryujinx.Ava/Common/Locale/LocaleManager.cs    |  1 -
 Ryujinx.Ava/Ryujinx.Ava.csproj                |  2 +
 .../UI/Views/Main/MainMenuBarView.axaml       | 58 +------------------
 .../UI/Views/Main/MainMenuBarView.axaml.cs    | 49 ++++++++++++++--
 Ryujinx.Common/Utilities/EmbeddedResources.cs |  8 +++
 20 files changed, 87 insertions(+), 77 deletions(-)

diff --git a/Ryujinx.Ava/Assets/Locales/de_DE.json b/Ryujinx.Ava/Assets/Locales/de_DE.json
index adda79caa9..671f369e78 100644
--- a/Ryujinx.Ava/Assets/Locales/de_DE.json
+++ b/Ryujinx.Ava/Assets/Locales/de_DE.json
@@ -1,4 +1,5 @@
 {
+  "Language": "Deutsch",
   "MenuBarFileOpenApplet": "Applet öffnen",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Öffnet das Mii Editor Applet im Standalone Modus",
   "SettingsTabInputDirectMouseAccess": "Direkter Mauszugriff",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "Konto wiederherstellen",
   "Recover": "Wiederherstellen",
   "UserProfilesRecoverHeading": "Speicherstände wurden für die folgenden Konten gefunden"
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Ava/Assets/Locales/el_GR.json b/Ryujinx.Ava/Assets/Locales/el_GR.json
index aef474ac97..5cd7a55401 100644
--- a/Ryujinx.Ava/Assets/Locales/el_GR.json
+++ b/Ryujinx.Ava/Assets/Locales/el_GR.json
@@ -1,4 +1,5 @@
 {
+  "Language": "Ελληνικά",
   "MenuBarFileOpenApplet": "Άνοιγμα Applet",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Άνοιγμα του Mii Editor Applet σε Αυτόνομη λειτουργία",
   "SettingsTabInputDirectMouseAccess": "Άμεση Πρόσβαση Ποντικιού",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
   "Recover": "Recover",
   "UserProfilesRecoverHeading": "Saves were found for the following accounts"
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Ava/Assets/Locales/en_US.json b/Ryujinx.Ava/Assets/Locales/en_US.json
index afd3f39325..46203463ac 100644
--- a/Ryujinx.Ava/Assets/Locales/en_US.json
+++ b/Ryujinx.Ava/Assets/Locales/en_US.json
@@ -1,4 +1,5 @@
 {
+  "Language": "English (US)",
   "MenuBarFileOpenApplet": "Open Applet",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Open Mii Editor Applet in Standalone mode",
   "SettingsTabInputDirectMouseAccess": "Direct Mouse Access",
@@ -610,4 +611,5 @@
   "UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
   "Recover": "Recover",
   "UserProfilesRecoverHeading" : "Saves were found for the following accounts"
-}
\ No newline at end of file
+}
+
diff --git a/Ryujinx.Ava/Assets/Locales/es_ES.json b/Ryujinx.Ava/Assets/Locales/es_ES.json
index 8275cdd887..1922318d0a 100644
--- a/Ryujinx.Ava/Assets/Locales/es_ES.json
+++ b/Ryujinx.Ava/Assets/Locales/es_ES.json
@@ -1,4 +1,5 @@
 {
+  "Language": "Español (ES)",
   "MenuBarFileOpenApplet": "Abrir applet",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Abre el editor de Mii en modo autónomo",
   "SettingsTabInputDirectMouseAccess": "Acceso directo al ratón",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
   "Recover": "Recover",
   "UserProfilesRecoverHeading": "Saves were found for the following accounts"
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Ava/Assets/Locales/fr_FR.json b/Ryujinx.Ava/Assets/Locales/fr_FR.json
index 634a996c03..938d0cc77f 100644
--- a/Ryujinx.Ava/Assets/Locales/fr_FR.json
+++ b/Ryujinx.Ava/Assets/Locales/fr_FR.json
@@ -1,4 +1,5 @@
 {
+  "Language": "Français",
   "MenuBarFileOpenApplet": "Ouvrir Applet",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Ouvrir l'Applet Mii Editor en mode Standalone",
   "SettingsTabInputDirectMouseAccess": "Accès direct à la souris",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "Récupérer les comptes perdus",
   "Recover": "Récupérer",
   "UserProfilesRecoverHeading": "Des sauvegardes ont été trouvées pour les comptes suivants"
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Ava/Assets/Locales/it_IT.json b/Ryujinx.Ava/Assets/Locales/it_IT.json
index b53dbf3707..fbdd4046d0 100644
--- a/Ryujinx.Ava/Assets/Locales/it_IT.json
+++ b/Ryujinx.Ava/Assets/Locales/it_IT.json
@@ -1,4 +1,5 @@
 {
+  "Language": "Italiano",
   "MenuBarFileOpenApplet": "Apri Applet",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Apri l'applet Mii Editor in modalità Standalone",
   "SettingsTabInputDirectMouseAccess": "Accesso diretto al mouse",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "Recupera il tuo account",
   "Recover": "Recupera",
   "UserProfilesRecoverHeading": "Sono stati trovati dei salvataggi per i seguenti account"
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Ava/Assets/Locales/ja_JP.json b/Ryujinx.Ava/Assets/Locales/ja_JP.json
index c779056baa..c88477f968 100644
--- a/Ryujinx.Ava/Assets/Locales/ja_JP.json
+++ b/Ryujinx.Ava/Assets/Locales/ja_JP.json
@@ -1,4 +1,5 @@
 {
+  "Language": "日本語",
   "MenuBarFileOpenApplet": "アプレットを開く",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "スタンドアロンモードで Mii エディタアプレットを開きます",
   "SettingsTabInputDirectMouseAccess": "マウス直接アクセス",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "アカウントの復旧",
   "Recover": "復旧",
   "UserProfilesRecoverHeading": "以下のアカウントのセーブデータが見つかりました"
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Ava/Assets/Locales/ko_KR.json b/Ryujinx.Ava/Assets/Locales/ko_KR.json
index 0efafc322e..5379efa9c4 100644
--- a/Ryujinx.Ava/Assets/Locales/ko_KR.json
+++ b/Ryujinx.Ava/Assets/Locales/ko_KR.json
@@ -1,4 +1,5 @@
 {
+  "Language": "한국어",
   "MenuBarFileOpenApplet": "애플릿 열기",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "독립 실행형 모드에서 Mii 편집기 애플릿 열기",
   "SettingsTabInputDirectMouseAccess": "직접 마우스 접속",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "잃어버린 계정 복구",
   "Recover": "복구",
   "UserProfilesRecoverHeading": "다음 계정에 대한 저장 발견"
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Ava/Assets/Locales/pl_PL.json b/Ryujinx.Ava/Assets/Locales/pl_PL.json
index 020f54b83d..3c1b541edb 100644
--- a/Ryujinx.Ava/Assets/Locales/pl_PL.json
+++ b/Ryujinx.Ava/Assets/Locales/pl_PL.json
@@ -1,4 +1,5 @@
 {
+  "Language": "Polski",
   "MenuBarFileOpenApplet": "Otwórz Aplet",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Otwórz aplet Mii Editor w trybie Indywidualnym",
   "SettingsTabInputDirectMouseAccess": "Bezpośredni Dostęp do Myszy",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "Odzyskaj Utracone Konta",
   "Recover": "Odzyskaj",
   "UserProfilesRecoverHeading": "Znaleziono zapisy dla następujących kont"
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Ava/Assets/Locales/pt_BR.json b/Ryujinx.Ava/Assets/Locales/pt_BR.json
index 6a377b0d6f..036b0a4bf0 100644
--- a/Ryujinx.Ava/Assets/Locales/pt_BR.json
+++ b/Ryujinx.Ava/Assets/Locales/pt_BR.json
@@ -1,4 +1,5 @@
 {
+  "Language": "Português (BR)",
   "MenuBarFileOpenApplet": "Abrir Applet",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Abrir editor Mii em modo avulso",
   "SettingsTabInputDirectMouseAccess": "Acesso direto ao mouse",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "Recuperar contas perdidas",
   "Recover": "Recuperar",
   "UserProfilesRecoverHeading": "Jogos salvos foram encontrados para as seguintes contas"
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Ava/Assets/Locales/ru_RU.json b/Ryujinx.Ava/Assets/Locales/ru_RU.json
index b5eadd6bbb..b3ad82be73 100644
--- a/Ryujinx.Ava/Assets/Locales/ru_RU.json
+++ b/Ryujinx.Ava/Assets/Locales/ru_RU.json
@@ -1,4 +1,5 @@
 {
+  "Language": "Русский",
   "MenuBarFileOpenApplet": "Открыть апплет",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Открыть апплет Mii Editor в автономном режиме.",
   "SettingsTabInputDirectMouseAccess": "Прямой доступ с помощью мыши",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
   "Recover": "Recover",
   "UserProfilesRecoverHeading": "Saves were found for the following accounts"
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Ava/Assets/Locales/tr_TR.json b/Ryujinx.Ava/Assets/Locales/tr_TR.json
index 623ad34ae8..ae14cdaf32 100644
--- a/Ryujinx.Ava/Assets/Locales/tr_TR.json
+++ b/Ryujinx.Ava/Assets/Locales/tr_TR.json
@@ -1,4 +1,5 @@
 {
+  "Language": "Türkçe",
   "MenuBarFileOpenApplet": "Applet'i Aç",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Mii Editör Applet'ini Bağımsız Mod'da Aç",
   "SettingsTabInputDirectMouseAccess": "Doğrudan Mouse Erişimi",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "Kayıp Hesapları Kurtar",
   "Recover": "Kurtar",
   "UserProfilesRecoverHeading": "Aşağıdaki hesaplar için kayıtlar bulundu"
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Ava/Assets/Locales/uk_UA.json b/Ryujinx.Ava/Assets/Locales/uk_UA.json
index e28d47c28e..01d433da6d 100644
--- a/Ryujinx.Ava/Assets/Locales/uk_UA.json
+++ b/Ryujinx.Ava/Assets/Locales/uk_UA.json
@@ -1,4 +1,5 @@
 {
+  "Language": "Yкраїнська",
   "MenuBarFileOpenApplet": "Відкрити аплет",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Відкрийте аплет Mii Editor в автономному режимі",
   "SettingsTabInputDirectMouseAccess": "Прямий доступ мишею",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "Відновлення втрачених облікових записів",
   "Recover": "Відновити",
   "UserProfilesRecoverHeading": "Знайдено збереження для наступних облікових записів"
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Ava/Assets/Locales/zh_CN.json b/Ryujinx.Ava/Assets/Locales/zh_CN.json
index 1fcfe8dabf..cd76951a7f 100644
--- a/Ryujinx.Ava/Assets/Locales/zh_CN.json
+++ b/Ryujinx.Ava/Assets/Locales/zh_CN.json
@@ -1,4 +1,5 @@
 {
+  "Language": "简体中文",
   "MenuBarFileOpenApplet": "打开小程序",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "打开独立的 Mii 小程序",
   "SettingsTabInputDirectMouseAccess": "直通鼠标操作",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "恢复丢失的账户",
   "Recover": "恢复",
   "UserProfilesRecoverHeading": "找到了这些用户的存档数据"
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Ava/Assets/Locales/zh_TW.json b/Ryujinx.Ava/Assets/Locales/zh_TW.json
index fcc16d78a9..963c0a8346 100644
--- a/Ryujinx.Ava/Assets/Locales/zh_TW.json
+++ b/Ryujinx.Ava/Assets/Locales/zh_TW.json
@@ -1,4 +1,5 @@
 {
+  "Language": "繁體中文",
   "MenuBarFileOpenApplet": "打開小程式",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "打開獨立的 Mii 小程式",
   "SettingsTabInputDirectMouseAccess": "直通滑鼠操作",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "恢復遺失的帳號",
   "Recover": "恢復",
   "UserProfilesRecoverHeading": "在以下帳號找到了一些遊戲存檔"
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Ava/Common/Locale/LocaleManager.cs b/Ryujinx.Ava/Common/Locale/LocaleManager.cs
index c2251f8512..5bcaa437e6 100644
--- a/Ryujinx.Ava/Common/Locale/LocaleManager.cs
+++ b/Ryujinx.Ava/Common/Locale/LocaleManager.cs
@@ -6,7 +6,6 @@ using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Globalization;
-using System.Text.Json;
 
 namespace Ryujinx.Ava.Common.Locale
 {
diff --git a/Ryujinx.Ava/Ryujinx.Ava.csproj b/Ryujinx.Ava/Ryujinx.Ava.csproj
index 5c001c672e..996817b9d5 100644
--- a/Ryujinx.Ava/Ryujinx.Ava.csproj
+++ b/Ryujinx.Ava/Ryujinx.Ava.csproj
@@ -145,6 +145,7 @@
     <None Remove="Assets\Locales\pt_BR.json" />
     <None Remove="Assets\Locales\ru_RU.json" />
     <None Remove="Assets\Locales\tr_TR.json" />
+    <None Remove="Assets\Locales\uk_UA.json" />
     <None Remove="Assets\Locales\zh_CN.json" />
     <None Remove="Assets\Locales\zh_TW.json" />
     <None Remove="Assets\Styles\Styles.xaml" />
@@ -165,6 +166,7 @@
     <EmbeddedResource Include="Assets\Locales\pt_BR.json" />
     <EmbeddedResource Include="Assets\Locales\ru_RU.json" />
     <EmbeddedResource Include="Assets\Locales\tr_TR.json" />
+    <EmbeddedResource Include="Assets\Locales\uk_UA.json" />
     <EmbeddedResource Include="Assets\Locales\zh_CN.json" />
     <EmbeddedResource Include="Assets\Locales\zh_TW.json" />
     <EmbeddedResource Include="Assets\Styles\Styles.xaml" />
diff --git a/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml b/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
index 0d0ae11937..bd26561a7a 100644
--- a/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
+++ b/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
@@ -77,63 +77,7 @@
                     </MenuItem.Icon>
                 </MenuItem>
                 <Separator />
-                <MenuItem Header="{locale:Locale MenuBarOptionsChangeLanguage}">
-                    <MenuItem
-                        Command="{ReflectionBinding ChangeLanguage}"
-                        CommandParameter="de_DE"
-                        Header="Deutsch" />
-                    <MenuItem
-                        Command="{ReflectionBinding ChangeLanguage}"
-                        CommandParameter="en_US"
-                        Header="English (US)" />
-                    <MenuItem
-                        Command="{ReflectionBinding ChangeLanguage}"
-                        CommandParameter="es_ES"
-                        Header="Español (ES)" />
-                    <MenuItem
-                        Command="{ReflectionBinding ChangeLanguage}"
-                        CommandParameter="fr_FR"
-                        Header="Français" />
-                    <MenuItem
-                        Command="{ReflectionBinding ChangeLanguage}"
-                        CommandParameter="it_IT"
-                        Header="Italiano" />
-                    <MenuItem
-                        Command="{ReflectionBinding ChangeLanguage}"
-                        CommandParameter="pt_BR"
-                        Header="Português (BR)" />
-                    <MenuItem
-                        Command="{ReflectionBinding ChangeLanguage}"
-                        CommandParameter="tr_TR"
-                        Header="Türkçe" />
-                    <MenuItem
-                        Command="{ReflectionBinding ChangeLanguage}"
-                        CommandParameter="el_GR"
-                        Header="Ελληνικά" />
-                    <MenuItem
-                        Command="{ReflectionBinding ChangeLanguage}"
-                        CommandParameter="pl_PL"
-                        Header="Polski" />
-                    <MenuItem
-                        Command="{ReflectionBinding ChangeLanguage}"
-                        CommandParameter="ru_RU"
-                        Header="Русский" />
-                    <MenuItem
-                        Command="{ReflectionBinding ChangeLanguage}"
-                        CommandParameter="zh_CN"
-                        Header="简体中文" />
-                    <MenuItem
-                        Command="{ReflectionBinding ChangeLanguage}"
-                        CommandParameter="zh_TW"
-                        Header="繁體中文" />
-                    <MenuItem
-                        Command="{ReflectionBinding ChangeLanguage}"
-                        CommandParameter="ja_JP"
-                        Header="日本語" />
-                    <MenuItem
-                        Command="{ReflectionBinding ChangeLanguage}"
-                        CommandParameter="ko_KR"
-                        Header="한국어" />
+                <MenuItem Name="ChangeLanguageMenuItem" Header="{locale:Locale MenuBarOptionsChangeLanguage}">
                 </MenuItem>
                 <Separator />
                 <MenuItem
diff --git a/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs b/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
index 788f47a1ab..31dbb1b775 100644
--- a/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
+++ b/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
@@ -1,13 +1,20 @@
 using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Interactivity;
-using Ryujinx.Ava.UI.ViewModels;
-using Ryujinx.Ava.UI.Windows;
-using System.Threading.Tasks;
 using LibHac.FsSystem;
 using LibHac.Ncm;
+using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.Ava.UI.Windows;
+using Ryujinx.Common;
+using Ryujinx.Common.Utilities;
 using Ryujinx.HLE.HOS;
 using Ryujinx.Modules;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
 
 namespace Ryujinx.Ava.UI.Views.Main
 {
@@ -19,13 +26,47 @@ namespace Ryujinx.Ava.UI.Views.Main
         public MainMenuBarView()
         {
             InitializeComponent();
+
+            List<MenuItem> menuItems = new();
+
+            string localePath = "Ryujinx.Ava/Assets/Locales";
+            string localeExt  = ".json";
+
+            string[] localesPath = EmbeddedResources.GetAllAvailableResources(localePath, localeExt);
+
+            Array.Sort(localesPath);
+
+            foreach (string locale in localesPath)
+            {
+                string languageCode = Path.GetFileNameWithoutExtension(locale).Split('.').Last();
+                string languageJson = EmbeddedResources.ReadAllText($"{localePath}/{languageCode}{localeExt}");
+                var    strings      = JsonHelper.Deserialize<Dictionary<string, string>>(languageJson);
+
+                if (!strings.TryGetValue("Language", out string languageName))
+                {
+                    languageName = languageCode;
+                }
+
+                MenuItem menuItem = new()
+                {
+                    Header  = languageName,
+                    Command = MiniCommand.Create(() =>
+                    {
+                        ViewModel.ChangeLanguage(languageCode);
+                    })
+                };
+
+                menuItems.Add(menuItem);
+            }
+
+            ChangeLanguageMenuItem.Items = menuItems.ToArray();
         }
 
         protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
         {
             base.OnAttachedToVisualTree(e);
 
-            if (this.VisualRoot is MainWindow window)
+            if (VisualRoot is MainWindow window)
             {
                 Window = window;
             }
diff --git a/Ryujinx.Common/Utilities/EmbeddedResources.cs b/Ryujinx.Common/Utilities/EmbeddedResources.cs
index 286d2c5ced..e7c8d7d701 100644
--- a/Ryujinx.Common/Utilities/EmbeddedResources.cs
+++ b/Ryujinx.Common/Utilities/EmbeddedResources.cs
@@ -1,5 +1,6 @@
 using System;
 using System.IO;
+using System.Linq;
 using System.Reflection;
 using System.Threading.Tasks;
 
@@ -127,6 +128,13 @@ namespace Ryujinx.Common
             return stream;
         }
 
+        public static string[] GetAllAvailableResources(string path, string ext = "")
+        {
+            return ResolveManifestPath(path).Item1.GetManifestResourceNames()
+                .Where(r => r.EndsWith(ext))
+                .ToArray();
+        }
+
         private static (Assembly, string) ResolveManifestPath(string filename)
         {
             var segments = filename.Split('/', 2, StringSplitOptions.RemoveEmptyEntries);