Просмотр исходного кода

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.
Ac_K 3 лет назад
Родитель
Сommit
2355c2af62

+ 2 - 1
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"
-}
+}

+ 2 - 1
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"
-}
+}

+ 3 - 1
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"
-}
+}
+

+ 2 - 1
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"
-}
+}

+ 2 - 1
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"
-}
+}

+ 2 - 1
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"
-}
+}

+ 2 - 1
Ryujinx.Ava/Assets/Locales/ja_JP.json

@@ -1,4 +1,5 @@
 {
+  "Language": "日本語",
   "MenuBarFileOpenApplet": "アプレットを開く",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "スタンドアロンモードで Mii エディタアプレットを開きます",
   "SettingsTabInputDirectMouseAccess": "マウス直接アクセス",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "アカウントの復旧",
   "Recover": "復旧",
   "UserProfilesRecoverHeading": "以下のアカウントのセーブデータが見つかりました"
-}
+}

+ 2 - 1
Ryujinx.Ava/Assets/Locales/ko_KR.json

@@ -1,4 +1,5 @@
 {
+  "Language": "한국어",
   "MenuBarFileOpenApplet": "애플릿 열기",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "독립 실행형 모드에서 Mii 편집기 애플릿 열기",
   "SettingsTabInputDirectMouseAccess": "직접 마우스 접속",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "잃어버린 계정 복구",
   "Recover": "복구",
   "UserProfilesRecoverHeading": "다음 계정에 대한 저장 발견"
-}
+}

+ 2 - 1
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"
-}
+}

+ 2 - 1
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"
-}
+}

+ 2 - 1
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"
-}
+}

+ 2 - 1
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"
-}
+}

+ 2 - 1
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": "Знайдено збереження для наступних облікових записів"
-}
+}

+ 2 - 1
Ryujinx.Ava/Assets/Locales/zh_CN.json

@@ -1,4 +1,5 @@
 {
+  "Language": "简体中文",
   "MenuBarFileOpenApplet": "打开小程序",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "打开独立的 Mii 小程序",
   "SettingsTabInputDirectMouseAccess": "直通鼠标操作",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "恢复丢失的账户",
   "Recover": "恢复",
   "UserProfilesRecoverHeading": "找到了这些用户的存档数据"
-}
+}

+ 2 - 1
Ryujinx.Ava/Assets/Locales/zh_TW.json

@@ -1,4 +1,5 @@
 {
+  "Language": "繁體中文",
   "MenuBarFileOpenApplet": "打開小程式",
   "MenuBarFileOpenAppletOpenMiiAppletToolTip": "打開獨立的 Mii 小程式",
   "SettingsTabInputDirectMouseAccess": "直通滑鼠操作",
@@ -610,4 +611,4 @@
   "UserProfilesRecoverLostAccounts": "恢復遺失的帳號",
   "Recover": "恢復",
   "UserProfilesRecoverHeading": "在以下帳號找到了一些遊戲存檔"
-}
+}

+ 0 - 1
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
 {

+ 2 - 0
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" />

+ 1 - 57
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

+ 45 - 4
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;
             }

+ 8 - 0
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);