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.
This commit is contained in:
Ac_K 2023-01-11 01:29:22 +01:00 committed by GitHub
parent 5e0f8e8738
commit 2355c2af62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 87 additions and 77 deletions

View File

@ -1,4 +1,5 @@
{ {
"Language": "Deutsch",
"MenuBarFileOpenApplet": "Applet öffnen", "MenuBarFileOpenApplet": "Applet öffnen",
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Öffnet das Mii Editor Applet im Standalone Modus", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Öffnet das Mii Editor Applet im Standalone Modus",
"SettingsTabInputDirectMouseAccess": "Direkter Mauszugriff", "SettingsTabInputDirectMouseAccess": "Direkter Mauszugriff",
@ -610,4 +611,4 @@
"UserProfilesRecoverLostAccounts": "Konto wiederherstellen", "UserProfilesRecoverLostAccounts": "Konto wiederherstellen",
"Recover": "Wiederherstellen", "Recover": "Wiederherstellen",
"UserProfilesRecoverHeading": "Speicherstände wurden für die folgenden Konten gefunden" "UserProfilesRecoverHeading": "Speicherstände wurden für die folgenden Konten gefunden"
} }

View File

@ -1,4 +1,5 @@
{ {
"Language": "Ελληνικά",
"MenuBarFileOpenApplet": "Άνοιγμα Applet", "MenuBarFileOpenApplet": "Άνοιγμα Applet",
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Άνοιγμα του Mii Editor Applet σε Αυτόνομη λειτουργία", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Άνοιγμα του Mii Editor Applet σε Αυτόνομη λειτουργία",
"SettingsTabInputDirectMouseAccess": "Άμεση Πρόσβαση Ποντικιού", "SettingsTabInputDirectMouseAccess": "Άμεση Πρόσβαση Ποντικιού",
@ -610,4 +611,4 @@
"UserProfilesRecoverLostAccounts": "Recover Lost Accounts", "UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
"Recover": "Recover", "Recover": "Recover",
"UserProfilesRecoverHeading": "Saves were found for the following accounts" "UserProfilesRecoverHeading": "Saves were found for the following accounts"
} }

View File

@ -1,4 +1,5 @@
{ {
"Language": "English (US)",
"MenuBarFileOpenApplet": "Open Applet", "MenuBarFileOpenApplet": "Open Applet",
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Open Mii Editor Applet in Standalone mode", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Open Mii Editor Applet in Standalone mode",
"SettingsTabInputDirectMouseAccess": "Direct Mouse Access", "SettingsTabInputDirectMouseAccess": "Direct Mouse Access",
@ -610,4 +611,5 @@
"UserProfilesRecoverLostAccounts": "Recover Lost Accounts", "UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
"Recover": "Recover", "Recover": "Recover",
"UserProfilesRecoverHeading" : "Saves were found for the following accounts" "UserProfilesRecoverHeading" : "Saves were found for the following accounts"
} }

View File

@ -1,4 +1,5 @@
{ {
"Language": "Español (ES)",
"MenuBarFileOpenApplet": "Abrir applet", "MenuBarFileOpenApplet": "Abrir applet",
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Abre el editor de Mii en modo autónomo", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Abre el editor de Mii en modo autónomo",
"SettingsTabInputDirectMouseAccess": "Acceso directo al ratón", "SettingsTabInputDirectMouseAccess": "Acceso directo al ratón",
@ -610,4 +611,4 @@
"UserProfilesRecoverLostAccounts": "Recover Lost Accounts", "UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
"Recover": "Recover", "Recover": "Recover",
"UserProfilesRecoverHeading": "Saves were found for the following accounts" "UserProfilesRecoverHeading": "Saves were found for the following accounts"
} }

View File

@ -1,4 +1,5 @@
{ {
"Language": "Français",
"MenuBarFileOpenApplet": "Ouvrir Applet", "MenuBarFileOpenApplet": "Ouvrir Applet",
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Ouvrir l'Applet Mii Editor en mode Standalone", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Ouvrir l'Applet Mii Editor en mode Standalone",
"SettingsTabInputDirectMouseAccess": "Accès direct à la souris", "SettingsTabInputDirectMouseAccess": "Accès direct à la souris",
@ -610,4 +611,4 @@
"UserProfilesRecoverLostAccounts": "Récupérer les comptes perdus", "UserProfilesRecoverLostAccounts": "Récupérer les comptes perdus",
"Recover": "Récupérer", "Recover": "Récupérer",
"UserProfilesRecoverHeading": "Des sauvegardes ont été trouvées pour les comptes suivants" "UserProfilesRecoverHeading": "Des sauvegardes ont été trouvées pour les comptes suivants"
} }

View File

@ -1,4 +1,5 @@
{ {
"Language": "Italiano",
"MenuBarFileOpenApplet": "Apri Applet", "MenuBarFileOpenApplet": "Apri Applet",
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Apri l'applet Mii Editor in modalità Standalone", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Apri l'applet Mii Editor in modalità Standalone",
"SettingsTabInputDirectMouseAccess": "Accesso diretto al mouse", "SettingsTabInputDirectMouseAccess": "Accesso diretto al mouse",
@ -610,4 +611,4 @@
"UserProfilesRecoverLostAccounts": "Recupera il tuo account", "UserProfilesRecoverLostAccounts": "Recupera il tuo account",
"Recover": "Recupera", "Recover": "Recupera",
"UserProfilesRecoverHeading": "Sono stati trovati dei salvataggi per i seguenti account" "UserProfilesRecoverHeading": "Sono stati trovati dei salvataggi per i seguenti account"
} }

View File

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

View File

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

View File

@ -1,4 +1,5 @@
{ {
"Language": "Polski",
"MenuBarFileOpenApplet": "Otwórz Aplet", "MenuBarFileOpenApplet": "Otwórz Aplet",
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Otwórz aplet Mii Editor w trybie Indywidualnym", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Otwórz aplet Mii Editor w trybie Indywidualnym",
"SettingsTabInputDirectMouseAccess": "Bezpośredni Dostęp do Myszy", "SettingsTabInputDirectMouseAccess": "Bezpośredni Dostęp do Myszy",
@ -610,4 +611,4 @@
"UserProfilesRecoverLostAccounts": "Odzyskaj Utracone Konta", "UserProfilesRecoverLostAccounts": "Odzyskaj Utracone Konta",
"Recover": "Odzyskaj", "Recover": "Odzyskaj",
"UserProfilesRecoverHeading": "Znaleziono zapisy dla następujących kont" "UserProfilesRecoverHeading": "Znaleziono zapisy dla następujących kont"
} }

View File

@ -1,4 +1,5 @@
{ {
"Language": "Português (BR)",
"MenuBarFileOpenApplet": "Abrir Applet", "MenuBarFileOpenApplet": "Abrir Applet",
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Abrir editor Mii em modo avulso", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Abrir editor Mii em modo avulso",
"SettingsTabInputDirectMouseAccess": "Acesso direto ao mouse", "SettingsTabInputDirectMouseAccess": "Acesso direto ao mouse",
@ -610,4 +611,4 @@
"UserProfilesRecoverLostAccounts": "Recuperar contas perdidas", "UserProfilesRecoverLostAccounts": "Recuperar contas perdidas",
"Recover": "Recuperar", "Recover": "Recuperar",
"UserProfilesRecoverHeading": "Jogos salvos foram encontrados para as seguintes contas" "UserProfilesRecoverHeading": "Jogos salvos foram encontrados para as seguintes contas"
} }

View File

@ -1,4 +1,5 @@
{ {
"Language": "Русский",
"MenuBarFileOpenApplet": "Открыть апплет", "MenuBarFileOpenApplet": "Открыть апплет",
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Открыть апплет Mii Editor в автономном режиме.", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Открыть апплет Mii Editor в автономном режиме.",
"SettingsTabInputDirectMouseAccess": "Прямой доступ с помощью мыши", "SettingsTabInputDirectMouseAccess": "Прямой доступ с помощью мыши",
@ -610,4 +611,4 @@
"UserProfilesRecoverLostAccounts": "Recover Lost Accounts", "UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
"Recover": "Recover", "Recover": "Recover",
"UserProfilesRecoverHeading": "Saves were found for the following accounts" "UserProfilesRecoverHeading": "Saves were found for the following accounts"
} }

View File

@ -1,4 +1,5 @@
{ {
"Language": "Türkçe",
"MenuBarFileOpenApplet": "Applet'i Aç", "MenuBarFileOpenApplet": "Applet'i Aç",
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Mii Editör Applet'ini Bağımsız Mod'da Aç", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Mii Editör Applet'ini Bağımsız Mod'da Aç",
"SettingsTabInputDirectMouseAccess": "Doğrudan Mouse Erişimi", "SettingsTabInputDirectMouseAccess": "Doğrudan Mouse Erişimi",
@ -610,4 +611,4 @@
"UserProfilesRecoverLostAccounts": "Kayıp Hesapları Kurtar", "UserProfilesRecoverLostAccounts": "Kayıp Hesapları Kurtar",
"Recover": "Kurtar", "Recover": "Kurtar",
"UserProfilesRecoverHeading": "Aşağıdaki hesaplar için kayıtlar bulundu" "UserProfilesRecoverHeading": "Aşağıdaki hesaplar için kayıtlar bulundu"
} }

View File

@ -1,4 +1,5 @@
{ {
"Language": "Yкраїнська",
"MenuBarFileOpenApplet": "Відкрити аплет", "MenuBarFileOpenApplet": "Відкрити аплет",
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Відкрийте аплет Mii Editor в автономному режимі", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Відкрийте аплет Mii Editor в автономному режимі",
"SettingsTabInputDirectMouseAccess": "Прямий доступ мишею", "SettingsTabInputDirectMouseAccess": "Прямий доступ мишею",
@ -610,4 +611,4 @@
"UserProfilesRecoverLostAccounts": "Відновлення втрачених облікових записів", "UserProfilesRecoverLostAccounts": "Відновлення втрачених облікових записів",
"Recover": "Відновити", "Recover": "Відновити",
"UserProfilesRecoverHeading": "Знайдено збереження для наступних облікових записів" "UserProfilesRecoverHeading": "Знайдено збереження для наступних облікових записів"
} }

View File

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

View File

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

View File

@ -6,7 +6,6 @@ using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Text.Json;
namespace Ryujinx.Ava.Common.Locale namespace Ryujinx.Ava.Common.Locale
{ {

View File

@ -145,6 +145,7 @@
<None Remove="Assets\Locales\pt_BR.json" /> <None Remove="Assets\Locales\pt_BR.json" />
<None Remove="Assets\Locales\ru_RU.json" /> <None Remove="Assets\Locales\ru_RU.json" />
<None Remove="Assets\Locales\tr_TR.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_CN.json" />
<None Remove="Assets\Locales\zh_TW.json" /> <None Remove="Assets\Locales\zh_TW.json" />
<None Remove="Assets\Styles\Styles.xaml" /> <None Remove="Assets\Styles\Styles.xaml" />
@ -165,6 +166,7 @@
<EmbeddedResource Include="Assets\Locales\pt_BR.json" /> <EmbeddedResource Include="Assets\Locales\pt_BR.json" />
<EmbeddedResource Include="Assets\Locales\ru_RU.json" /> <EmbeddedResource Include="Assets\Locales\ru_RU.json" />
<EmbeddedResource Include="Assets\Locales\tr_TR.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_CN.json" />
<EmbeddedResource Include="Assets\Locales\zh_TW.json" /> <EmbeddedResource Include="Assets\Locales\zh_TW.json" />
<EmbeddedResource Include="Assets\Styles\Styles.xaml" /> <EmbeddedResource Include="Assets\Styles\Styles.xaml" />

View File

@ -77,63 +77,7 @@
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<Separator /> <Separator />
<MenuItem Header="{locale:Locale MenuBarOptionsChangeLanguage}"> <MenuItem Name="ChangeLanguageMenuItem" 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> </MenuItem>
<Separator /> <Separator />
<MenuItem <MenuItem

View File

@ -1,13 +1,20 @@
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Windows;
using System.Threading.Tasks;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Ncm; 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.HLE.HOS;
using Ryujinx.Modules; 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 namespace Ryujinx.Ava.UI.Views.Main
{ {
@ -19,13 +26,47 @@ namespace Ryujinx.Ava.UI.Views.Main
public MainMenuBarView() public MainMenuBarView()
{ {
InitializeComponent(); 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) protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{ {
base.OnAttachedToVisualTree(e); base.OnAttachedToVisualTree(e);
if (this.VisualRoot is MainWindow window) if (VisualRoot is MainWindow window)
{ {
Window = window; Window = window;
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -127,6 +128,13 @@ namespace Ryujinx.Common
return stream; 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) private static (Assembly, string) ResolveManifestPath(string filename)
{ {
var segments = filename.Split('/', 2, StringSplitOptions.RemoveEmptyEntries); var segments = filename.Split('/', 2, StringSplitOptions.RemoveEmptyEntries);