diff --git a/Directory.Packages.props b/Directory.Packages.props
index c02c1ae5..84d83d0d 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -50,5 +50,7 @@
     <PackageVersion Include="System.Net.NameResolution" Version="4.3.0" />
     <PackageVersion Include="System.Threading.ThreadPool" Version="4.3.0" />
     <PackageVersion Include="XamlNameReferenceGenerator" Version="1.5.1" />
+    <PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3"/>
+    <PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
   </ItemGroup>
 </Project>
diff --git a/Ryujinx.Ava/App.axaml.cs b/Ryujinx.Ava/App.axaml.cs
index e59f9bd3..e36cbfdd 100644
--- a/Ryujinx.Ava/App.axaml.cs
+++ b/Ryujinx.Ava/App.axaml.cs
@@ -59,11 +59,11 @@ namespace Ryujinx.Ava
                 if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
                 {
                     var result = await ContentDialogHelper.CreateConfirmationDialog(
-                        LocaleManager.Instance["DialogThemeRestartMessage"],
-                        LocaleManager.Instance["DialogThemeRestartSubMessage"],
-                        LocaleManager.Instance["InputDialogYes"],
-                        LocaleManager.Instance["InputDialogNo"],
-                        LocaleManager.Instance["DialogRestartRequiredMessage"]);
+                        LocaleManager.Instance[LocaleKeys.DialogThemeRestartMessage],
+                        LocaleManager.Instance[LocaleKeys.DialogThemeRestartSubMessage],
+                        LocaleManager.Instance[LocaleKeys.InputDialogYes],
+                        LocaleManager.Instance[LocaleKeys.InputDialogNo],
+                        LocaleManager.Instance[LocaleKeys.DialogRestartRequiredMessage]);
 
                     if (result == UserResult.Yes)
                     {
diff --git a/Ryujinx.Ava/AppHost.cs b/Ryujinx.Ava/AppHost.cs
index f8bd032c..0baa94c3 100644
--- a/Ryujinx.Ava/AppHost.cs
+++ b/Ryujinx.Ava/AppHost.cs
@@ -432,10 +432,10 @@ namespace Ryujinx.Ava
                     if (userError == UserError.NoFirmware)
                     {
                         UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
-                            LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"],
-                            string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"], firmwareVersion.VersionString),
-                            LocaleManager.Instance["InputDialogYes"],
-                            LocaleManager.Instance["InputDialogNo"],
+                            LocaleManager.Instance[LocaleKeys.DialogFirmwareNoFirmwareInstalledMessage],
+                            string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallEmbeddedMessage], firmwareVersion.VersionString),
+                            LocaleManager.Instance[LocaleKeys.InputDialogYes],
+                            LocaleManager.Instance[LocaleKeys.InputDialogNo],
                             "");
 
                         if (result != UserResult.Yes)
@@ -463,11 +463,11 @@ namespace Ryujinx.Ava
                         _parent.RefreshFirmwareStatus();
 
                         await ContentDialogHelper.CreateInfoDialog(
-                            string.Format(LocaleManager.Instance["DialogFirmwareInstalledMessage"], firmwareVersion.VersionString),
-                            string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString),
-                            LocaleManager.Instance["InputDialogOk"],
+                            string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstalledMessage], firmwareVersion.VersionString),
+                            string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallEmbeddedSuccessMessage], firmwareVersion.VersionString),
+                            LocaleManager.Instance[LocaleKeys.InputDialogOk],
                             "",
-                            LocaleManager.Instance["RyujinxInfo"]);
+                            LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
                     }
                 }
                 else
@@ -869,7 +869,7 @@ namespace Ryujinx.Ava
         public void UpdateStatus()
         {
             // Run a status update only when a frame is to be drawn. This prevents from updating the ui and wasting a render when no frame is queued
-            string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance["Docked"] : LocaleManager.Instance["Handheld"];
+            string dockedMode = ConfigurationState.Instance.System.EnableDockedMode ? LocaleManager.Instance[LocaleKeys.Docked] : LocaleManager.Instance[LocaleKeys.Handheld];
             float scale = GraphicsConfig.ResScale;
 
             if (scale != 1)
@@ -879,11 +879,11 @@ namespace Ryujinx.Ava
 
             StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
                 Device.EnableDeviceVsync,
-                LocaleManager.Instance["VolumeShort"] + $": {(int)(Device.GetVolume() * 100)}%",
+                LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%",
                 Renderer.IsVulkan ? "Vulkan" : "OpenGL",
                 dockedMode,
                 ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(),
-                LocaleManager.Instance["Game"] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
+                LocaleManager.Instance[LocaleKeys.Game] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
                 $"FIFO: {Device.Statistics.GetFifoPercent():00.00} %",
                 $"GPU: {_renderer.GetHardwareInfo().GpuVendor}"));
         }
diff --git a/Ryujinx.Ava/Common/ApplicationHelper.cs b/Ryujinx.Ava/Common/ApplicationHelper.cs
index 0c562dfe..8e5bdaec 100644
--- a/Ryujinx.Ava/Common/ApplicationHelper.cs
+++ b/Ryujinx.Ava/Common/ApplicationHelper.cs
@@ -81,7 +81,7 @@ namespace Ryujinx.Ava.Common
                     Dispatcher.UIThread.Post(async () =>
                     {
                         await ContentDialogHelper.CreateErrorDialog(
-                            string.Format(LocaleManager.Instance["DialogMessageCreateSaveErrorMessage"], result.ToStringWithName()));
+                            string.Format(LocaleManager.Instance[LocaleKeys.DialogMessageCreateSaveErrorMessage], result.ToStringWithName()));
                     });
 
                     return false;
@@ -100,7 +100,7 @@ namespace Ryujinx.Ava.Common
 
             Dispatcher.UIThread.Post(async () =>
             {
-                await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogMessageFindSaveErrorMessage"], result.ToStringWithName()));
+                await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogMessageFindSaveErrorMessage], result.ToStringWithName()));
             });
 
             return false;
@@ -151,7 +151,7 @@ namespace Ryujinx.Ava.Common
         public static async Task ExtractSection(NcaSectionType ncaSectionType, string titleFilePath,
             int programIndex = 0)
         {
-            OpenFolderDialog folderDialog = new() { Title = LocaleManager.Instance["FolderDialogExtractTitle"] };
+            OpenFolderDialog folderDialog = new() { Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle] };
 
             string destination = await folderDialog.ShowAsync(_owner);
 
@@ -164,11 +164,11 @@ namespace Ryujinx.Ava.Common
                     Dispatcher.UIThread.Post(async () =>
                     {
                         UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
-                            string.Format(LocaleManager.Instance["DialogNcaExtractionMessage"], ncaSectionType, Path.GetFileName(titleFilePath)),
+                            string.Format(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionMessage], ncaSectionType, Path.GetFileName(titleFilePath)),
                             "",
                             "",
-                            LocaleManager.Instance["InputDialogCancel"],
-                            LocaleManager.Instance["DialogNcaExtractionTitle"]);
+                            LocaleManager.Instance[LocaleKeys.InputDialogCancel],
+                            LocaleManager.Instance[LocaleKeys.DialogNcaExtractionTitle]);
 
                         if (result == UserResult.Cancel)
                         {
@@ -234,7 +234,7 @@ namespace Ryujinx.Ava.Common
                                 "Extraction failure. The main NCA was not present in the selected file");
                             Dispatcher.UIThread.InvokeAsync(async () =>
                             {
-                                await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogNcaExtractionMainNcaNotFoundErrorMessage"]);
+                                await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionMainNcaNotFoundErrorMessage]);
                             });
                             return;
                         }
@@ -275,7 +275,7 @@ namespace Ryujinx.Ava.Common
                                         $"LibHac returned error code: {resultCode.Value.ErrorCode}");
                                     Dispatcher.UIThread.InvokeAsync(async () =>
                                     {
-                                        await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogNcaExtractionCheckLogErrorMessage"]);
+                                        await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionCheckLogErrorMessage]);
                                     });
                                 }
                                 else if (resultCode.Value.IsSuccess())
@@ -283,11 +283,11 @@ namespace Ryujinx.Ava.Common
                                     Dispatcher.UIThread.InvokeAsync(async () =>
                                     {
                                         await ContentDialogHelper.CreateInfoDialog(
-                                            LocaleManager.Instance["DialogNcaExtractionSuccessMessage"],
+                                            LocaleManager.Instance[LocaleKeys.DialogNcaExtractionSuccessMessage],
                                             "",
-                                            LocaleManager.Instance["InputDialogOk"],
+                                            LocaleManager.Instance[LocaleKeys.InputDialogOk],
                                             "",
-                                            LocaleManager.Instance["DialogNcaExtractionTitle"]);
+                                            LocaleManager.Instance[LocaleKeys.DialogNcaExtractionTitle]);
                                     });
                                 }
                             }
diff --git a/Ryujinx.Ava/Common/Locale/LocaleExtension.cs b/Ryujinx.Ava/Common/Locale/LocaleExtension.cs
index 8fca1a00..6c54becd 100644
--- a/Ryujinx.Ava/Common/Locale/LocaleExtension.cs
+++ b/Ryujinx.Ava/Common/Locale/LocaleExtension.cs
@@ -7,16 +7,16 @@ namespace Ryujinx.Ava.Common.Locale
 {
     internal class LocaleExtension : MarkupExtension
     {
-        public LocaleExtension(string key)
+        public LocaleExtension(LocaleKeys key)
         {
             Key = key;
         }
 
-        public string Key { get; }
+        public LocaleKeys Key { get; }
 
         public override object ProvideValue(IServiceProvider serviceProvider)
         {
-            string keyToUse = Key;
+            LocaleKeys keyToUse = Key;
 
             ReflectionBindingExtension binding = new($"[{keyToUse}]")
             {
diff --git a/Ryujinx.Ava/Common/Locale/LocaleManager.cs b/Ryujinx.Ava/Common/Locale/LocaleManager.cs
index acbbf2df..c2251f85 100644
--- a/Ryujinx.Ava/Common/Locale/LocaleManager.cs
+++ b/Ryujinx.Ava/Common/Locale/LocaleManager.cs
@@ -2,6 +2,7 @@
 using Ryujinx.Common;
 using Ryujinx.Common.Utilities;
 using Ryujinx.Ui.Common.Configuration;
+using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Globalization;
@@ -13,17 +14,17 @@ namespace Ryujinx.Ava.Common.Locale
     {
         private const string DefaultLanguageCode = "en_US";
 
-        private Dictionary<string, string> _localeStrings;
-        private ConcurrentDictionary<string, object[]> _dynamicValues;
+        private Dictionary<LocaleKeys, string> _localeStrings;
+        private ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues;
 
         public static LocaleManager Instance { get; } = new LocaleManager();
-        public Dictionary<string, string> LocaleStrings { get => _localeStrings; set => _localeStrings = value; }
+        public Dictionary<LocaleKeys, string> LocaleStrings { get => _localeStrings; set => _localeStrings = value; }
 
 
         public LocaleManager()
         {
-            _localeStrings = new Dictionary<string, string>();
-            _dynamicValues = new ConcurrentDictionary<string, object[]>();
+            _localeStrings = new Dictionary<LocaleKeys, string>();
+            _dynamicValues = new ConcurrentDictionary<LocaleKeys, object[]>();
 
             Load();
         }
@@ -49,7 +50,7 @@ namespace Ryujinx.Ava.Common.Locale
             }
         }
 
-        public string this[string key]
+        public string this[LocaleKeys key]
         {
             get
             {
@@ -63,7 +64,7 @@ namespace Ryujinx.Ava.Common.Locale
                     return value;
                 }
 
-                return key;
+                return key.ToString();
             }
             set
             {
@@ -73,7 +74,7 @@ namespace Ryujinx.Ava.Common.Locale
             }
         }
 
-        public void UpdateDynamicValue(string key, params object[] values)
+        public void UpdateDynamicValue(LocaleKeys key, params object[] values)
         {
             _dynamicValues[key] = values;
 
@@ -98,7 +99,10 @@ namespace Ryujinx.Ava.Common.Locale
 
             foreach (var item in strings)
             {
-                this[item.Key] = item.Value;
+                if (Enum.TryParse<LocaleKeys>(item.Key, out var key))
+                {
+                    this[key] = item.Value;
+                }
             }
 
             if (Program.PreviewerDetached)
diff --git a/Ryujinx.Ava/Input/AvaloniaKeyboardDriver.cs b/Ryujinx.Ava/Input/AvaloniaKeyboardDriver.cs
index 31a53c32..b107898e 100644
--- a/Ryujinx.Ava/Input/AvaloniaKeyboardDriver.cs
+++ b/Ryujinx.Ava/Input/AvaloniaKeyboardDriver.cs
@@ -56,7 +56,7 @@ namespace Ryujinx.Ava.Input
                 return null;
             }
 
-            return new AvaloniaKeyboard(this, _keyboardIdentifers[0], LocaleManager.Instance["AllKeyboards"]);
+            return new AvaloniaKeyboard(this, _keyboardIdentifers[0], LocaleManager.Instance[LocaleKeys.AllKeyboards]);
         }
 
         protected virtual void Dispose(bool disposing)
diff --git a/Ryujinx.Ava/Modules/Updater/Updater.cs b/Ryujinx.Ava/Modules/Updater/Updater.cs
index d495131f..7bf147fe 100644
--- a/Ryujinx.Ava/Modules/Updater/Updater.cs
+++ b/Ryujinx.Ava/Modules/Updater/Updater.cs
@@ -84,7 +84,7 @@ namespace Ryujinx.Modules
                 Logger.Error?.Print(LogClass.Application, "Failed to convert the current Ryujinx version!");
                 Dispatcher.UIThread.Post(async () =>
                 {
-                    await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterConvertFailedMessage"], LocaleManager.Instance["DialogUpdaterCancelUpdateMessage"]);
+                    await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterConvertFailedMessage], LocaleManager.Instance[LocaleKeys.DialogUpdaterCancelUpdateMessage]);
                 });
 
                 return;
@@ -119,7 +119,7 @@ namespace Ryujinx.Modules
                                 {
                                     Dispatcher.UIThread.Post(async () =>
                                     {
-                                        await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance["DialogUpdaterAlreadyOnLatestVersionMessage"], "");
+                                        await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], "");
                                     });
                                 }
 
@@ -137,7 +137,7 @@ namespace Ryujinx.Modules
                         {
                             Dispatcher.UIThread.Post(async () =>
                             {
-                                await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance["DialogUpdaterAlreadyOnLatestVersionMessage"], "");
+                                await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], "");
                             });
                         }
 
@@ -150,7 +150,7 @@ namespace Ryujinx.Modules
                 Logger.Error?.Print(LogClass.Application, exception.Message);
                 Dispatcher.UIThread.Post(async () =>
                 {
-                    await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUpdaterFailedToGetVersionMessage"]);
+                    await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterFailedToGetVersionMessage]);
                 });
 
                 return;
@@ -165,7 +165,7 @@ namespace Ryujinx.Modules
                 Logger.Error?.Print(LogClass.Application, "Failed to convert the received Ryujinx version from Github!");
                 Dispatcher.UIThread.Post(async () =>
                 {
-                    await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterConvertFailedGithubMessage"], LocaleManager.Instance["DialogUpdaterCancelUpdateMessage"]);
+                    await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterConvertFailedGithubMessage], LocaleManager.Instance[LocaleKeys.DialogUpdaterCancelUpdateMessage]);
                 });
 
                 return;
@@ -177,7 +177,7 @@ namespace Ryujinx.Modules
                 {
                     Dispatcher.UIThread.Post(async () =>
                     {
-                        await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance["DialogUpdaterAlreadyOnLatestVersionMessage"], "");
+                        await ContentDialogHelper.CreateUpdaterInfoDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage], "");
                     });
                 }
 
@@ -210,8 +210,8 @@ namespace Ryujinx.Modules
             Dispatcher.UIThread.Post(async () =>
             {
                 // Show a message asking the user if they want to update
-                var shouldUpdate = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance["RyujinxUpdater"],
-                    LocaleManager.Instance["RyujinxUpdaterMessage"],
+                var shouldUpdate = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance[LocaleKeys.RyujinxUpdater],
+                    LocaleManager.Instance[LocaleKeys.RyujinxUpdaterMessage],
                     $"{Program.Version} -> {newVersion}");
 
                 if (shouldUpdate)
@@ -247,8 +247,8 @@ namespace Ryujinx.Modules
 
             var taskDialog = new TaskDialog()
             {
-                Header = LocaleManager.Instance["RyujinxUpdater"],
-                SubHeader = LocaleManager.Instance["UpdaterDownloading"],
+                Header = LocaleManager.Instance[LocaleKeys.RyujinxUpdater],
+                SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterDownloading],
                 IconSource = new SymbolIconSource { Symbol = Symbol.Download },
                 Buttons = { },
                 ShowProgressBar = true
@@ -272,9 +272,9 @@ namespace Ryujinx.Modules
 
             if (UpdateSuccessful)
             {
-                var shouldRestart = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance["RyujinxUpdater"],
-                    LocaleManager.Instance["DialogUpdaterCompleteMessage"],
-                    LocaleManager.Instance["DialogUpdaterRestartMessage"]);
+                var shouldRestart = await ContentDialogHelper.CreateChoiceDialog(LocaleManager.Instance[LocaleKeys.RyujinxUpdater],
+                    LocaleManager.Instance[LocaleKeys.DialogUpdaterCompleteMessage],
+                    LocaleManager.Instance[LocaleKeys.DialogUpdaterRestartMessage]);
 
                 if (shouldRestart)
                 {
@@ -478,7 +478,7 @@ namespace Ryujinx.Modules
         private static async void InstallUpdate(TaskDialog taskDialog, string updateFile)
         {
             // Extract Update
-            taskDialog.SubHeader = LocaleManager.Instance["UpdaterExtracting"];
+            taskDialog.SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterExtracting];
             taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
 
             if (OperatingSystem.IsLinux())
@@ -556,7 +556,7 @@ namespace Ryujinx.Modules
 
             List<string> allFiles = EnumerateFilesToDelete().ToList();
 
-            taskDialog.SubHeader = LocaleManager.Instance["UpdaterRenaming"];
+            taskDialog.SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterRenaming];
             taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
 
             // Replace old files
@@ -577,13 +577,13 @@ namespace Ryujinx.Modules
                     }
                     catch
                     {
-                        Logger.Warning?.Print(LogClass.Application, string.Format(LocaleManager.Instance["UpdaterRenameFailed"], file));
+                        Logger.Warning?.Print(LogClass.Application, string.Format(LocaleManager.Instance[LocaleKeys.UpdaterRenameFailed], file));
                     }
                 }
 
                 Dispatcher.UIThread.Post(() =>
                 {
-                    taskDialog.SubHeader = LocaleManager.Instance["UpdaterAddingFiles"];
+                    taskDialog.SubHeader = LocaleManager.Instance[LocaleKeys.UpdaterAddingFiles];
                     taskDialog.SetProgressBarState(0, TaskDialogProgressState.Normal);
                 });
 
@@ -607,8 +607,8 @@ namespace Ryujinx.Modules
             {
                 if (showWarnings)
                 {
-                    ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterArchNotSupportedMessage"],
-                        LocaleManager.Instance["DialogUpdaterArchNotSupportedSubMessage"]);
+                    ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterArchNotSupportedMessage],
+                        LocaleManager.Instance[LocaleKeys.DialogUpdaterArchNotSupportedSubMessage]);
                 }
 
                 return false;
@@ -618,8 +618,8 @@ namespace Ryujinx.Modules
             {
                 if (showWarnings)
                 {
-                    ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterNoInternetMessage"],
-                        LocaleManager.Instance["DialogUpdaterNoInternetSubMessage"]);
+                    ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterNoInternetMessage],
+                        LocaleManager.Instance[LocaleKeys.DialogUpdaterNoInternetSubMessage]);
                 }
 
                 return false;
@@ -629,8 +629,8 @@ namespace Ryujinx.Modules
             {
                 if (showWarnings)
                 {
-                    ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["DialogUpdaterDirtyBuildMessage"],
-                        LocaleManager.Instance["DialogUpdaterDirtyBuildSubMessage"]);
+                    ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.DialogUpdaterDirtyBuildMessage],
+                        LocaleManager.Instance[LocaleKeys.DialogUpdaterDirtyBuildSubMessage]);
                 }
 
                 return false;
@@ -642,11 +642,11 @@ namespace Ryujinx.Modules
             {
                 if (ReleaseInformations.IsFlatHubBuild())
                 {
-                    ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["UpdaterDisabledWarningTitle"], LocaleManager.Instance["DialogUpdaterFlatpakNotSupportedMessage"]);
+                    ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.UpdaterDisabledWarningTitle], LocaleManager.Instance[LocaleKeys.DialogUpdaterFlatpakNotSupportedMessage]);
                 }
                 else
                 {
-                    ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["UpdaterDisabledWarningTitle"], LocaleManager.Instance["DialogUpdaterDirtyBuildSubMessage"]);
+                    ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.UpdaterDisabledWarningTitle], LocaleManager.Instance[LocaleKeys.DialogUpdaterDirtyBuildSubMessage]);
                 }
             }
 
diff --git a/Ryujinx.Ava/Ryujinx.Ava.csproj b/Ryujinx.Ava/Ryujinx.Ava.csproj
index 6da11849..3e3bdc8c 100644
--- a/Ryujinx.Ava/Ryujinx.Ava.csproj
+++ b/Ryujinx.Ava/Ryujinx.Ava.csproj
@@ -58,6 +58,7 @@
     <ProjectReference Include="..\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj" />
     <ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
     <ProjectReference Include="..\Ryujinx.Ui.Common\Ryujinx.Ui.Common.csproj" />
+    <ProjectReference Include="..\Ryujinx.Ui.LocaleGenerator\Ryujinx.Ui.LocaleGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
   </ItemGroup>
 
   <ItemGroup>
@@ -158,4 +159,7 @@
     <EmbeddedResource Include="Assets\Locales\zh_TW.json" />
     <EmbeddedResource Include="Assets\Styles\Styles.xaml" />
   </ItemGroup>
+  <ItemGroup>
+      <AdditionalFiles Include="Assets\Locales\en_US.json" />
+  </ItemGroup>
 </Project>
diff --git a/Ryujinx.Ava/UI/Applet/AvaHostUiHandler.cs b/Ryujinx.Ava/UI/Applet/AvaHostUiHandler.cs
index a8e76275..f4d9bc80 100644
--- a/Ryujinx.Ava/UI/Applet/AvaHostUiHandler.cs
+++ b/Ryujinx.Ava/UI/Applet/AvaHostUiHandler.cs
@@ -33,15 +33,15 @@ namespace Ryujinx.Ava.UI.Applet
                 ? args.PlayerCountMin.ToString()
                 : $"{args.PlayerCountMin}-{args.PlayerCountMax}";
 
-            string key = args.PlayerCountMin == args.PlayerCountMax ? "DialogControllerAppletMessage" : "DialogControllerAppletMessagePlayerRange";
+            LocaleKeys key = args.PlayerCountMin == args.PlayerCountMax ? LocaleKeys.DialogControllerAppletMessage : LocaleKeys.DialogControllerAppletMessagePlayerRange;
 
             string message = string.Format(LocaleManager.Instance[key],
                                            playerCount,
                                            args.SupportedStyles,
                                            string.Join(", ", args.SupportedPlayers),
-                                           args.IsDocked ? LocaleManager.Instance["DialogControllerAppletDockModeSet"] : "");
+                                           args.IsDocked ? LocaleManager.Instance[LocaleKeys.DialogControllerAppletDockModeSet] : "");
 
-            return DisplayMessageDialog(LocaleManager.Instance["DialogControllerAppletTitle"], message);
+            return DisplayMessageDialog(LocaleManager.Instance[LocaleKeys.DialogControllerAppletTitle], message);
         }
 
         public bool DisplayMessageDialog(string title, string message)
@@ -62,9 +62,9 @@ namespace Ryujinx.Ava.UI.Applet
                        title,
                        message,
                        "",
-                       LocaleManager.Instance["DialogOpenSettingsWindowLabel"],
+                       LocaleManager.Instance[LocaleKeys.DialogOpenSettingsWindowLabel],
                        "",
-                       LocaleManager.Instance["SettingsButtonClose"],
+                       LocaleManager.Instance[LocaleKeys.SettingsButtonClose],
                        (int)Symbol.Important,
                        deferEvent,
                        async (window) =>
@@ -92,7 +92,7 @@ namespace Ryujinx.Ava.UI.Applet
                 }
                 catch (Exception ex)
                 {
-                    await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogMessageDialogErrorExceptionMessage"], ex));
+                    await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogMessageDialogErrorExceptionMessage], ex));
 
                     dialogCloseEvent.Set();
                 }
@@ -115,7 +115,7 @@ namespace Ryujinx.Ava.UI.Applet
             {
                 try
                 {
-                    var response = await SwkbdAppletDialog.ShowInputDialog(_parent, LocaleManager.Instance["SoftwareKeyboard"], args);
+                    var response = await SwkbdAppletDialog.ShowInputDialog(_parent, LocaleManager.Instance[LocaleKeys.SoftwareKeyboard], args);
 
                     if (response.Result == UserResult.Ok)
                     {
@@ -126,7 +126,7 @@ namespace Ryujinx.Ava.UI.Applet
                 catch (Exception ex)
                 {
                     error = true;
-                    await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogSoftwareKeyboardErrorExceptionMessage"], ex));
+                    await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogSoftwareKeyboardErrorExceptionMessage], ex));
                 }
                 finally
                 {
@@ -181,7 +181,7 @@ namespace Ryujinx.Ava.UI.Applet
                 catch (Exception ex)
                 {
                     dialogCloseEvent.Set();
-                    await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogErrorAppletErrorExceptionMessage"], ex));
+                    await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogErrorAppletErrorExceptionMessage], ex));
                 }
             });
 
diff --git a/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml.cs b/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml.cs
index a17826f8..4134797b 100644
--- a/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml.cs
+++ b/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml.cs
@@ -34,7 +34,7 @@ namespace Ryujinx.Ava.UI.Applet
             }
             else
             {
-                AddButton(LocaleManager.Instance["InputDialogOk"], 0);
+                AddButton(LocaleManager.Instance[LocaleKeys.InputDialogOk], 0);
             }
         }
 
diff --git a/Ryujinx.Ava/UI/Applet/SwkbdAppletDialog.axaml.cs b/Ryujinx.Ava/UI/Applet/SwkbdAppletDialog.axaml.cs
index 80be2979..78e6f237 100644
--- a/Ryujinx.Ava/UI/Applet/SwkbdAppletDialog.axaml.cs
+++ b/Ryujinx.Ava/UI/Applet/SwkbdAppletDialog.axaml.cs
@@ -86,7 +86,7 @@ namespace Ryujinx.Ava.UI.Controls
             contentDialog.PrimaryButtonText = args.SubmitText;
             contentDialog.IsPrimaryButtonEnabled = content._checkLength(content.Message.Length);
             contentDialog.SecondaryButtonText = "";
-            contentDialog.CloseButtonText = LocaleManager.Instance["InputDialogCancel"];
+            contentDialog.CloseButtonText = LocaleManager.Instance[LocaleKeys.InputDialogCancel];
             contentDialog.Content = content;
 
             TypedEventHandler<ContentDialog, ContentDialogClosedEventArgs> handler = (sender, eventArgs) =>
@@ -139,14 +139,14 @@ namespace Ryujinx.Ava.UI.Controls
             else if (_inputMin > 0 && _inputMax == int.MaxValue)
             {
                 Error.IsVisible = true;
-                Error.Text = string.Format(LocaleManager.Instance["SwkbdMinCharacters"], _inputMin);
+                Error.Text = string.Format(LocaleManager.Instance[LocaleKeys.SwkbdMinCharacters], _inputMin);
 
                 _checkLength = length => _inputMin <= length;
             }
             else
             {
                 Error.IsVisible = true;
-                Error.Text = string.Format(LocaleManager.Instance["SwkbdMinRangeCharacters"], _inputMin, _inputMax);
+                Error.Text = string.Format(LocaleManager.Instance[LocaleKeys.SwkbdMinRangeCharacters], _inputMin, _inputMax);
 
                 _checkLength = length => _inputMin <= length && length <= _inputMax;
             }
diff --git a/Ryujinx.Ava/UI/Controls/InputDialog.axaml.cs b/Ryujinx.Ava/UI/Controls/InputDialog.axaml.cs
index abaabd3b..8dba5e2b 100644
--- a/Ryujinx.Ava/UI/Controls/InputDialog.axaml.cs
+++ b/Ryujinx.Ava/UI/Controls/InputDialog.axaml.cs
@@ -39,9 +39,9 @@ namespace Ryujinx.Ava.UI.Controls
             ContentDialog contentDialog = new ContentDialog
             {
                 Title = title,
-                PrimaryButtonText = LocaleManager.Instance["InputDialogOk"],
+                PrimaryButtonText = LocaleManager.Instance[LocaleKeys.InputDialogOk],
                 SecondaryButtonText = "",
-                CloseButtonText = LocaleManager.Instance["InputDialogCancel"],
+                CloseButtonText = LocaleManager.Instance[LocaleKeys.InputDialogCancel],
                 Content = content,
                 PrimaryButtonCommand = MiniCommand.Create(() =>
                 {
diff --git a/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs b/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs
index 98f9e9e3..0c300267 100644
--- a/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs
+++ b/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs
@@ -65,10 +65,10 @@ namespace Ryujinx.Ava.UI.Controls
             var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
             ContentDialog contentDialog = new ContentDialog
             {
-                Title = LocaleManager.Instance["UserProfileWindowTitle"],
+                Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],
                 PrimaryButtonText = "",
                 SecondaryButtonText = "",
-                CloseButtonText = LocaleManager.Instance["UserProfilesClose"],
+                CloseButtonText = LocaleManager.Instance[LocaleKeys.UserProfilesClose],
                 Content = content,
                 Padding = new Thickness(0)
             };
diff --git a/Ryujinx.Ava/UI/Controls/ProfileImageSelectionDialog.axaml.cs b/Ryujinx.Ava/UI/Controls/ProfileImageSelectionDialog.axaml.cs
index 00183b69..46a2f507 100644
--- a/Ryujinx.Ava/UI/Controls/ProfileImageSelectionDialog.axaml.cs
+++ b/Ryujinx.Ava/UI/Controls/ProfileImageSelectionDialog.axaml.cs
@@ -55,7 +55,7 @@ namespace Ryujinx.Ava.UI.Controls
             OpenFileDialog dialog = new();
             dialog.Filters.Add(new FileDialogFilter
             {
-                Name = LocaleManager.Instance["AllSupportedFormats"],
+                Name = LocaleManager.Instance[LocaleKeys.AllSupportedFormats],
                 Extensions = { "jpg", "jpeg", "png", "bmp" }
             });
             dialog.Filters.Add(new FileDialogFilter { Name = "JPEG", Extensions = { "jpg", "jpeg" } });
diff --git a/Ryujinx.Ava/UI/Controls/SaveManager.axaml b/Ryujinx.Ava/UI/Controls/SaveManager.axaml
index b0dc4c6f..64674b65 100644
--- a/Ryujinx.Ava/UI/Controls/SaveManager.axaml
+++ b/Ryujinx.Ava/UI/Controls/SaveManager.axaml
@@ -62,7 +62,7 @@
                         <Label 
                             VerticalAlignment="Center" 
                             HorizontalContentAlignment="Left"
-                            Content="{locale:Locale Descending}" />
+                            Content="{locale:Locale OrderDescending}" />
                     </ComboBoxItem>
                 </ComboBox>
             </StackPanel>
diff --git a/Ryujinx.Ava/UI/Controls/UserEditor.axaml.cs b/Ryujinx.Ava/UI/Controls/UserEditor.axaml.cs
index 19fa29e5..18bb8b22 100644
--- a/Ryujinx.Ava/UI/Controls/UserEditor.axaml.cs
+++ b/Ryujinx.Ava/UI/Controls/UserEditor.axaml.cs
@@ -65,14 +65,14 @@ namespace Ryujinx.Ava.UI.Controls
 
             if (string.IsNullOrWhiteSpace(TempProfile.Name))
             {
-                DataValidationErrors.SetError(NameBox, new DataValidationException(LocaleManager.Instance["UserProfileEmptyNameError"]));
+                DataValidationErrors.SetError(NameBox, new DataValidationException(LocaleManager.Instance[LocaleKeys.UserProfileEmptyNameError]));
 
                 isInvalid = true;
             }
 
             if (TempProfile.Image == null)
             {
-                await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance["UserProfileNoImageError"], "");
+                await ContentDialogHelper.CreateWarningDialog(LocaleManager.Instance[LocaleKeys.UserProfileNoImageError], "");
 
                 isInvalid = true;
             }
diff --git a/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs b/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs
index cf30d99b..a098a8ea 100644
--- a/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs
+++ b/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs
@@ -170,7 +170,7 @@ namespace Ryujinx.Ava.UI.Helpers
                 secondaryButton,
                 closeButton,
                 iconSymbol,
-                primaryButton == LocaleManager.Instance["InputDialogYes"] ? UserResult.Yes : UserResult.Ok,
+                primaryButton == LocaleManager.Instance[LocaleKeys.InputDialogYes] ? UserResult.Yes : UserResult.Ok,
                 deferResetEvent,
                 doWhileDeferred,
                 DeferClose);
@@ -188,7 +188,7 @@ namespace Ryujinx.Ava.UI.Helpers
 
                 var deferral = args.GetDeferral();
 
-                result = primaryButton == LocaleManager.Instance["InputDialogYes"] ? UserResult.Yes : UserResult.Ok;
+                result = primaryButton == LocaleManager.Instance[LocaleKeys.InputDialogYes] ? UserResult.Yes : UserResult.Ok;
 
                 sender.PrimaryButtonClick -= DeferClose;
 
@@ -281,7 +281,7 @@ namespace Ryujinx.Ava.UI.Helpers
             UserResult primaryButtonResult = UserResult.Yes)
         {
             return await ShowContentDialog(
-                string.IsNullOrWhiteSpace(title) ? LocaleManager.Instance["DialogConfirmationTitle"] : title,
+                string.IsNullOrWhiteSpace(title) ? LocaleManager.Instance[LocaleKeys.DialogConfirmationTitle] : title,
                 primaryText,
                 secondaryText,
                 acceptButtonText,
@@ -299,24 +299,24 @@ namespace Ryujinx.Ava.UI.Helpers
         internal static async Task CreateUpdaterInfoDialog(string primary, string secondaryText)
         {
             await ShowContentDialog(
-                LocaleManager.Instance["DialogUpdaterTitle"],
+                LocaleManager.Instance[LocaleKeys.DialogUpdaterTitle],
                 primary,
                 secondaryText,
                 "",
                 "",
-                LocaleManager.Instance["InputDialogOk"],
+                LocaleManager.Instance[LocaleKeys.InputDialogOk],
                 (int)Symbol.Important);
         }
 
         internal static async Task CreateWarningDialog(string primary, string secondaryText)
         {
             await ShowContentDialog(
-                LocaleManager.Instance["DialogWarningTitle"],
+                LocaleManager.Instance[LocaleKeys.DialogWarningTitle],
                 primary,
                 secondaryText,
                 "",
                 "",
-                LocaleManager.Instance["InputDialogOk"],
+                LocaleManager.Instance[LocaleKeys.InputDialogOk],
                 (int)Symbol.Important);
         }
 
@@ -325,12 +325,12 @@ namespace Ryujinx.Ava.UI.Helpers
             Logger.Error?.Print(LogClass.Application, errorMessage);
 
             await ShowContentDialog(
-                LocaleManager.Instance["DialogErrorTitle"],
-                LocaleManager.Instance["DialogErrorMessage"],
+                LocaleManager.Instance[LocaleKeys.DialogErrorTitle],
+                LocaleManager.Instance[LocaleKeys.DialogErrorMessage],
                 errorMessage,
                 secondaryErrorMessage,
                 "",
-                LocaleManager.Instance["InputDialogOk"],
+                LocaleManager.Instance[LocaleKeys.InputDialogOk],
                 (int)Symbol.Dismiss);
         }
 
@@ -348,9 +348,9 @@ namespace Ryujinx.Ava.UI.Helpers
                     title,
                     primary,
                     secondaryText,
-                    LocaleManager.Instance["InputDialogYes"],
+                    LocaleManager.Instance[LocaleKeys.InputDialogYes],
                     "",
-                    LocaleManager.Instance["InputDialogNo"],
+                    LocaleManager.Instance[LocaleKeys.InputDialogNo],
                     (int)Symbol.Help,
                     UserResult.Yes);
 
@@ -362,17 +362,17 @@ namespace Ryujinx.Ava.UI.Helpers
         internal static async Task<bool> CreateExitDialog()
         {
             return await CreateChoiceDialog(
-                LocaleManager.Instance["DialogExitTitle"],
-                LocaleManager.Instance["DialogExitMessage"],
-                LocaleManager.Instance["DialogExitSubMessage"]);
+                LocaleManager.Instance[LocaleKeys.DialogExitTitle],
+                LocaleManager.Instance[LocaleKeys.DialogExitMessage],
+                LocaleManager.Instance[LocaleKeys.DialogExitSubMessage]);
         }
 
         internal static async Task<bool> CreateStopEmulationDialog()
         {
             return await CreateChoiceDialog(
-                LocaleManager.Instance["DialogStopEmulationTitle"],
-                LocaleManager.Instance["DialogStopEmulationMessage"],
-                LocaleManager.Instance["DialogExitSubMessage"]);
+                LocaleManager.Instance[LocaleKeys.DialogStopEmulationTitle],
+                LocaleManager.Instance[LocaleKeys.DialogStopEmulationMessage],
+                LocaleManager.Instance[LocaleKeys.DialogExitSubMessage]);
         }
 
         internal static async Task<string> CreateInputDialog(
diff --git a/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs b/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs
index ab8d6edc..06ec8e30 100644
--- a/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs
+++ b/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs
@@ -19,12 +19,12 @@ namespace Ryujinx.Ava.UI.Helpers
         {
             return error switch
             {
-                UserError.NoKeys => LocaleManager.Instance["UserErrorNoKeys"],
-                UserError.NoFirmware => LocaleManager.Instance["UserErrorNoFirmware"],
-                UserError.FirmwareParsingFailed => LocaleManager.Instance["UserErrorFirmwareParsingFailed"],
-                UserError.ApplicationNotFound => LocaleManager.Instance["UserErrorApplicationNotFound"],
-                UserError.Unknown => LocaleManager.Instance["UserErrorUnknown"],
-                _ => LocaleManager.Instance["UserErrorUndefined"]
+                UserError.NoKeys => LocaleManager.Instance[LocaleKeys.UserErrorNoKeys],
+                UserError.NoFirmware => LocaleManager.Instance[LocaleKeys.UserErrorNoFirmware],
+                UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailed],
+                UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFound],
+                UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknown],
+                _ => LocaleManager.Instance[LocaleKeys.UserErrorUndefined]
             };
         }
 
@@ -32,12 +32,12 @@ namespace Ryujinx.Ava.UI.Helpers
         {
             return error switch
             {
-                UserError.NoKeys => LocaleManager.Instance["UserErrorNoKeysDescription"],
-                UserError.NoFirmware => LocaleManager.Instance["UserErrorNoFirmwareDescription"],
-                UserError.FirmwareParsingFailed => LocaleManager.Instance["UserErrorFirmwareParsingFailedDescription"],
-                UserError.ApplicationNotFound => LocaleManager.Instance["UserErrorApplicationNotFoundDescription"],
-                UserError.Unknown => LocaleManager.Instance["UserErrorUnknownDescription"],
-                _ => LocaleManager.Instance["UserErrorUndefinedDescription"]
+                UserError.NoKeys => LocaleManager.Instance[LocaleKeys.UserErrorNoKeysDescription],
+                UserError.NoFirmware => LocaleManager.Instance[LocaleKeys.UserErrorNoFirmwareDescription],
+                UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailedDescription],
+                UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFoundDescription],
+                UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknownDescription],
+                _ => LocaleManager.Instance[LocaleKeys.UserErrorUndefinedDescription]
             };
         }
 
@@ -73,14 +73,14 @@ namespace Ryujinx.Ava.UI.Helpers
 
             bool isInSetupGuide = IsCoveredBySetupGuide(error);
 
-            string setupButtonLabel = isInSetupGuide ? LocaleManager.Instance["OpenSetupGuideMessage"] : "";
+            string setupButtonLabel = isInSetupGuide ? LocaleManager.Instance[LocaleKeys.OpenSetupGuideMessage] : "";
 
             var result = await ContentDialogHelper.CreateInfoDialog(
-                string.Format(LocaleManager.Instance["DialogUserErrorDialogMessage"], errorCode, GetErrorTitle(error)),
+                string.Format(LocaleManager.Instance[LocaleKeys.DialogUserErrorDialogMessage], errorCode, GetErrorTitle(error)),
                 GetErrorDescription(error) + (isInSetupGuide
-                    ? LocaleManager.Instance["DialogUserErrorDialogInfoMessage"]
-                    : ""), setupButtonLabel, LocaleManager.Instance["InputDialogOk"],
-                string.Format(LocaleManager.Instance["DialogUserErrorDialogTitle"], errorCode));
+                    ? LocaleManager.Instance[LocaleKeys.DialogUserErrorDialogInfoMessage]
+                    : ""), setupButtonLabel, LocaleManager.Instance[LocaleKeys.InputDialogOk],
+                string.Format(LocaleManager.Instance[LocaleKeys.DialogUserErrorDialogTitle], errorCode));
 
             if (result == UserResult.Ok)
             {
diff --git a/Ryujinx.Ava/UI/Models/Generic/LastPlayedSortComparer.cs b/Ryujinx.Ava/UI/Models/Generic/LastPlayedSortComparer.cs
index b322ed64..98caceb5 100644
--- a/Ryujinx.Ava/UI/Models/Generic/LastPlayedSortComparer.cs
+++ b/Ryujinx.Ava/UI/Models/Generic/LastPlayedSortComparer.cs
@@ -17,12 +17,12 @@ namespace Ryujinx.Ava.UI.Models.Generic
             string aValue = x.LastPlayed;
             string bValue = y.LastPlayed;
 
-            if (aValue == LocaleManager.Instance["Never"])
+            if (aValue == LocaleManager.Instance[LocaleKeys.Never])
             {
                 aValue = DateTime.UnixEpoch.ToString();
             }
 
-            if (bValue == LocaleManager.Instance["Never"])
+            if (bValue == LocaleManager.Instance[LocaleKeys.Never])
             {
                 bValue = DateTime.UnixEpoch.ToString();
             }
diff --git a/Ryujinx.Ava/UI/Models/SaveModel.cs b/Ryujinx.Ava/UI/Models/SaveModel.cs
index c9311104..3c20741f 100644
--- a/Ryujinx.Ava/UI/Models/SaveModel.cs
+++ b/Ryujinx.Ava/UI/Models/SaveModel.cs
@@ -107,10 +107,10 @@ namespace Ryujinx.Ava.UI.Models
 
         public async void Delete()
         {
-            var result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DeleteUserSave"],
-                LocaleManager.Instance["IrreversibleActionNote"],
-                LocaleManager.Instance["InputDialogYes"],
-                LocaleManager.Instance["InputDialogNo"], "");
+            var result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DeleteUserSave],
+                LocaleManager.Instance[LocaleKeys.IrreversibleActionNote],
+                LocaleManager.Instance[LocaleKeys.InputDialogYes],
+                LocaleManager.Instance[LocaleKeys.InputDialogNo], "");
 
             if (result == UserResult.Yes)
             {
diff --git a/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs b/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs
index 77203222..c3ba6230 100644
--- a/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs
+++ b/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs
@@ -11,8 +11,8 @@ namespace Ryujinx.Ava.UI.Models
         public string Path { get; }
 
         public string Label => IsNoUpdate
-            ? LocaleManager.Instance["NoUpdate"]
-            : string.Format(LocaleManager.Instance["TitleUpdateVersionLabel"], Control.DisplayVersionString.ToString(),
+            ? LocaleManager.Instance[LocaleKeys.NoUpdate]
+            : string.Format(LocaleManager.Instance[LocaleKeys.TitleUpdateVersionLabel], Control.DisplayVersionString.ToString(),
                 Path);
 
         public TitleUpdateModel(ApplicationControlProperty control, string path, bool isNoUpdate = false)
diff --git a/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs b/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs
index cf94a9aa..5561a20c 100644
--- a/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs
+++ b/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs
@@ -344,10 +344,10 @@ namespace Ryujinx.Ava.UI.ViewModels
 
                     if (usageString.Length == 0)
                     {
-                        usageString = LocaleManager.Instance["Unknown"] + ".";
+                        usageString = LocaleManager.Instance[LocaleKeys.Unknown] + ".";
                     }
 
-                    Usage = $"{LocaleManager.Instance["Usage"]} {(writable ? $" ({LocaleManager.Instance["Writable"]})" : "")} : {usageString}";
+                    Usage = $"{LocaleManager.Instance[LocaleKeys.Usage]} {(writable ? $" ({LocaleManager.Instance[LocaleKeys.Writable]})" : "")} : {usageString}";
                 }
             }
 
@@ -392,11 +392,11 @@ namespace Ryujinx.Ava.UI.ViewModels
                 return amiiboJsonString;
             }
 
-            await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance["DialogAmiiboApiTitle"],
-                LocaleManager.Instance["DialogAmiiboApiFailFetchMessage"],
-                LocaleManager.Instance["InputDialogOk"],
+            await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle],
+                LocaleManager.Instance[LocaleKeys.DialogAmiiboApiFailFetchMessage],
+                LocaleManager.Instance[LocaleKeys.InputDialogOk],
                 "",
-                LocaleManager.Instance["RyujinxInfo"]);
+                LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
 
             Close();
 
@@ -442,11 +442,11 @@ namespace Ryujinx.Ava.UI.ViewModels
 
         private async void ShowInfoDialog()
         {
-            await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance["DialogAmiiboApiTitle"],
-                LocaleManager.Instance["DialogAmiiboApiConnectErrorMessage"],
-                LocaleManager.Instance["InputDialogOk"],
+            await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle],
+                LocaleManager.Instance[LocaleKeys.DialogAmiiboApiConnectErrorMessage],
+                LocaleManager.Instance[LocaleKeys.InputDialogOk],
                 "",
-                LocaleManager.Instance["RyujinxInfo"]);
+                LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Ava/UI/ViewModels/ControllerSettingsViewModel.cs b/Ryujinx.Ava/UI/ViewModels/ControllerSettingsViewModel.cs
index 692d2a8c..6a2afad1 100644
--- a/Ryujinx.Ava/UI/ViewModels/ControllerSettingsViewModel.cs
+++ b/Ryujinx.Ava/UI/ViewModels/ControllerSettingsViewModel.cs
@@ -267,15 +267,15 @@ namespace Ryujinx.Ava.UI.ViewModels
 
             ControllerImage = ProControllerResource;
 
-            PlayerIndexes.Add(new(PlayerIndex.Player1, LocaleManager.Instance["ControllerSettingsPlayer1"]));
-            PlayerIndexes.Add(new(PlayerIndex.Player2, LocaleManager.Instance["ControllerSettingsPlayer2"]));
-            PlayerIndexes.Add(new(PlayerIndex.Player3, LocaleManager.Instance["ControllerSettingsPlayer3"]));
-            PlayerIndexes.Add(new(PlayerIndex.Player4, LocaleManager.Instance["ControllerSettingsPlayer4"]));
-            PlayerIndexes.Add(new(PlayerIndex.Player5, LocaleManager.Instance["ControllerSettingsPlayer5"]));
-            PlayerIndexes.Add(new(PlayerIndex.Player6, LocaleManager.Instance["ControllerSettingsPlayer6"]));
-            PlayerIndexes.Add(new(PlayerIndex.Player7, LocaleManager.Instance["ControllerSettingsPlayer7"]));
-            PlayerIndexes.Add(new(PlayerIndex.Player8, LocaleManager.Instance["ControllerSettingsPlayer8"]));
-            PlayerIndexes.Add(new(PlayerIndex.Handheld, LocaleManager.Instance["ControllerSettingsHandheld"]));
+            PlayerIndexes.Add(new(PlayerIndex.Player1, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer1]));
+            PlayerIndexes.Add(new(PlayerIndex.Player2, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer2]));
+            PlayerIndexes.Add(new(PlayerIndex.Player3, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer3]));
+            PlayerIndexes.Add(new(PlayerIndex.Player4, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer4]));
+            PlayerIndexes.Add(new(PlayerIndex.Player5, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer5]));
+            PlayerIndexes.Add(new(PlayerIndex.Player6, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer6]));
+            PlayerIndexes.Add(new(PlayerIndex.Player7, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer7]));
+            PlayerIndexes.Add(new(PlayerIndex.Player8, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer8]));
+            PlayerIndexes.Add(new(PlayerIndex.Handheld, LocaleManager.Instance[LocaleKeys.ControllerSettingsHandheld]));
         }
 
         private void LoadConfiguration(InputConfig inputConfig = null)
@@ -406,16 +406,16 @@ namespace Ryujinx.Ava.UI.ViewModels
 
             if (_playerId == PlayerIndex.Handheld)
             {
-                Controllers.Add(new(ControllerType.Handheld, LocaleManager.Instance["ControllerSettingsControllerTypeHandheld"]));
+                Controllers.Add(new(ControllerType.Handheld, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeHandheld]));
 
                 Controller = 0;
             }
             else
             {
-                Controllers.Add(new(ControllerType.ProController, LocaleManager.Instance["ControllerSettingsControllerTypeProController"]));
-                Controllers.Add(new(ControllerType.JoyconPair, LocaleManager.Instance["ControllerSettingsControllerTypeJoyConPair"]));
-                Controllers.Add(new(ControllerType.JoyconLeft, LocaleManager.Instance["ControllerSettingsControllerTypeJoyConLeft"]));
-                Controllers.Add(new(ControllerType.JoyconRight, LocaleManager.Instance["ControllerSettingsControllerTypeJoyConRight"]));
+                Controllers.Add(new(ControllerType.ProController, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeProController]));
+                Controllers.Add(new(ControllerType.JoyconPair, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConPair]));
+                Controllers.Add(new(ControllerType.JoyconLeft, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConLeft]));
+                Controllers.Add(new(ControllerType.JoyconRight, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConRight]));
 
                 if (Config != null && Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType) != -1)
                 {
@@ -455,7 +455,7 @@ namespace Ryujinx.Ava.UI.ViewModels
             {
                 Devices.Clear();
                 DeviceList.Clear();
-                Devices.Add((DeviceType.None, Disabled, LocaleManager.Instance["ControllerSettingsDeviceDisabled"]));
+                Devices.Add((DeviceType.None, Disabled, LocaleManager.Instance[LocaleKeys.ControllerSettingsDeviceDisabled]));
 
                 foreach (string id in _mainWindow.InputManager.KeyboardDriver.GamepadsIds)
                 {
@@ -517,7 +517,7 @@ namespace Ryujinx.Ava.UI.ViewModels
                 Directory.CreateDirectory(basePath);
             }
 
-            ProfilesList.Add((LocaleManager.Instance["ControllerSettingsProfileDefault"]));
+            ProfilesList.Add((LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault]));
 
             foreach (string profile in Directory.GetFiles(basePath, "*.json", SearchOption.AllDirectories))
             {
@@ -526,7 +526,7 @@ namespace Ryujinx.Ava.UI.ViewModels
 
             if (string.IsNullOrWhiteSpace(ProfileName))
             {
-                ProfileName = LocaleManager.Instance["ControllerSettingsProfileDefault"];
+                ProfileName = LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault];
             }
         }
 
@@ -687,7 +687,7 @@ namespace Ryujinx.Ava.UI.ViewModels
                 return;
             }
 
-            if (ProfileName == LocaleManager.Instance["ControllerSettingsProfileDefault"])
+            if (ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault])
             {
                 config = LoadDefaultConfiguration();
             }
@@ -717,7 +717,7 @@ namespace Ryujinx.Ava.UI.ViewModels
                 {
                     Logger.Error?.Print(LogClass.Configuration, $"Profile {ProfileName} is incompatible with the current input configuration system.");
 
-                    await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogProfileInvalidProfileErrorMessage"], ProfileName));
+                    await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileErrorMessage], ProfileName));
 
                     return;
                 }
@@ -749,9 +749,9 @@ namespace Ryujinx.Ava.UI.ViewModels
                 return;
             }
 
-            if (ProfileName == LocaleManager.Instance["ControllerSettingsProfileDefault"])
+            if (ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault])
             {
-                await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogProfileDefaultProfileOverwriteErrorMessage"]);
+                await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileDefaultProfileOverwriteErrorMessage]);
 
                 return;
             }
@@ -784,24 +784,24 @@ namespace Ryujinx.Ava.UI.ViewModels
                 }
                 else
                 {
-                    await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogProfileInvalidProfileNameErrorMessage"]);
+                    await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]);
                 }
             }
         }
 
         public async void RemoveProfile()
         {
-            if (Device == 0 || ProfileName == LocaleManager.Instance["ControllerSettingsProfileDefault"] || ProfilesList.IndexOf(ProfileName) == -1)
+            if (Device == 0 || ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault] || ProfilesList.IndexOf(ProfileName) == -1)
             {
                 return;
             }
 
             UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
-                LocaleManager.Instance["DialogProfileDeleteProfileTitle"],
-                LocaleManager.Instance["DialogProfileDeleteProfileMessage"],
-                LocaleManager.Instance["InputDialogYes"],
-                LocaleManager.Instance["InputDialogNo"],
-                LocaleManager.Instance["RyujinxConfirm"]);
+                LocaleManager.Instance[LocaleKeys.DialogProfileDeleteProfileTitle],
+                LocaleManager.Instance[LocaleKeys.DialogProfileDeleteProfileMessage],
+                LocaleManager.Instance[LocaleKeys.InputDialogYes],
+                LocaleManager.Instance[LocaleKeys.InputDialogNo],
+                LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
 
             if (result == UserResult.Yes)
             {
diff --git a/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs b/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs
index e6d97193..878af3f8 100644
--- a/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs
+++ b/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs
@@ -635,14 +635,14 @@ namespace Ryujinx.Ava.UI.ViewModels
             {
                 return SortMode switch
                 {
-                    ApplicationSort.Title           => LocaleManager.Instance["GameListHeaderApplication"],
-                    ApplicationSort.Developer       => LocaleManager.Instance["GameListHeaderDeveloper"],
-                    ApplicationSort.LastPlayed      => LocaleManager.Instance["GameListHeaderLastPlayed"],
-                    ApplicationSort.TotalTimePlayed => LocaleManager.Instance["GameListHeaderTimePlayed"],
-                    ApplicationSort.FileType        => LocaleManager.Instance["GameListHeaderFileExtension"],
-                    ApplicationSort.FileSize        => LocaleManager.Instance["GameListHeaderFileSize"],
-                    ApplicationSort.Path            => LocaleManager.Instance["GameListHeaderPath"],
-                    ApplicationSort.Favorite        => LocaleManager.Instance["CommonFavorite"],
+                    ApplicationSort.Title           => LocaleManager.Instance[LocaleKeys.GameListHeaderApplication],
+                    ApplicationSort.Developer       => LocaleManager.Instance[LocaleKeys.GameListHeaderDeveloper],
+                    ApplicationSort.LastPlayed      => LocaleManager.Instance[LocaleKeys.GameListHeaderLastPlayed],
+                    ApplicationSort.TotalTimePlayed => LocaleManager.Instance[LocaleKeys.GameListHeaderTimePlayed],
+                    ApplicationSort.FileType        => LocaleManager.Instance[LocaleKeys.GameListHeaderFileExtension],
+                    ApplicationSort.FileSize        => LocaleManager.Instance[LocaleKeys.GameListHeaderFileSize],
+                    ApplicationSort.Path            => LocaleManager.Instance[LocaleKeys.GameListHeaderPath],
+                    ApplicationSort.Favorite        => LocaleManager.Instance[LocaleKeys.CommonFavorite],
                     _                               => string.Empty,
                 };
             }
@@ -771,7 +771,7 @@ namespace Ryujinx.Ava.UI.ViewModels
             StatusBarProgressValue   = e.NumAppsLoaded;
             StatusBarProgressMaximum = e.NumAppsFound;
 
-            LocaleManager.Instance.UpdateDynamicValue("StatusBarGamesLoaded", StatusBarProgressValue, StatusBarProgressMaximum);
+            LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarGamesLoaded, StatusBarProgressValue, StatusBarProgressMaximum);
 
             Dispatcher.UIThread.Post(() =>
             {
@@ -805,7 +805,7 @@ namespace Ryujinx.Ava.UI.ViewModels
                 StatusBarProgressMaximum         = 0;
                 StatusBarProgressValue           = 0;
 
-                LocaleManager.Instance.UpdateDynamicValue("StatusBarGamesLoaded", 0, 0);
+                LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarGamesLoaded, 0, 0);
             });
 
             ReloadGameList();
@@ -835,12 +835,12 @@ namespace Ryujinx.Ava.UI.ViewModels
         {
             OpenFileDialog dialog = new()
             {
-                Title = LocaleManager.Instance["OpenFileDialogTitle"]
+                Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle]
             };
 
             dialog.Filters.Add(new FileDialogFilter
             {
-                Name = LocaleManager.Instance["AllSupportedFormats"],
+                Name = LocaleManager.Instance[LocaleKeys.AllSupportedFormats],
                 Extensions =
                 {
                     "nsp",
@@ -871,7 +871,7 @@ namespace Ryujinx.Ava.UI.ViewModels
         {
             OpenFolderDialog dialog = new()
             {
-                Title = LocaleManager.Instance["OpenFolderDialogTitle"]
+                Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle]
             };
 
             string folder = await dialog.ShowAsync(_owner);
@@ -1039,11 +1039,11 @@ namespace Ryujinx.Ava.UI.ViewModels
                         {
                             case PtcLoadingState.Start:
                             case PtcLoadingState.Loading:
-                                LoadHeading            = LocaleManager.Instance["CompilingPPTC"];
+                                LoadHeading            = LocaleManager.Instance[LocaleKeys.CompilingPPTC];
                                 IsLoadingIndeterminate = false;
                                 break;
                             case PtcLoadingState.Loaded:
-                                LoadHeading            = string.Format(LocaleManager.Instance["LoadingHeading"], TitleName);
+                                LoadHeading            = string.Format(LocaleManager.Instance[LocaleKeys.LoadingHeading], TitleName);
                                 IsLoadingIndeterminate = true;
                                 CacheLoadStatus        = "";
                                 break;
@@ -1055,11 +1055,11 @@ namespace Ryujinx.Ava.UI.ViewModels
                         {
                             case ShaderCacheLoadingState.Start:
                             case ShaderCacheLoadingState.Loading:
-                                LoadHeading            = LocaleManager.Instance["CompilingShaders"];
+                                LoadHeading            = LocaleManager.Instance[LocaleKeys.CompilingShaders];
                                 IsLoadingIndeterminate = false;
                                 break;
                             case ShaderCacheLoadingState.Loaded:
-                                LoadHeading            = string.Format(LocaleManager.Instance["LoadingHeading"], TitleName);
+                                LoadHeading            = string.Format(LocaleManager.Instance[LocaleKeys.LoadingHeading], TitleName);
                                 IsLoadingIndeterminate = true;
                                 CacheLoadStatus        = "";
                                 break;
@@ -1083,7 +1083,7 @@ namespace Ryujinx.Ava.UI.ViewModels
                     {
                         Dispatcher.UIThread.Post(async () =>
                         {
-                            await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]);
+                            await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogRyujinxErrorMessage], LocaleManager.Instance[LocaleKeys.DialogInvalidTitleIdErrorMessage]);
                         });
 
                         return;
@@ -1166,11 +1166,11 @@ namespace Ryujinx.Ava.UI.ViewModels
                 DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "1"));
 
                 // FIXME: Found a way to reproduce the bold effect on the title name (fork?).
-                UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"], 
-                                                                                       string.Format(LocaleManager.Instance["DialogPPTCDeletionMessage"], selection.TitleName),
-                                                                                       LocaleManager.Instance["InputDialogYes"],
-                                                                                       LocaleManager.Instance["InputDialogNo"],
-                                                                                       LocaleManager.Instance["RyujinxConfirm"]);
+                UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning], 
+                                                                                       string.Format(LocaleManager.Instance[LocaleKeys.DialogPPTCDeletionMessage], selection.TitleName),
+                                                                                       LocaleManager.Instance[LocaleKeys.InputDialogYes],
+                                                                                       LocaleManager.Instance[LocaleKeys.InputDialogNo],
+                                                                                       LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
 
                 List<FileInfo> cacheFiles = new();
 
@@ -1194,7 +1194,7 @@ namespace Ryujinx.Ava.UI.ViewModels
                         }
                         catch (Exception e)
                         {
-                            await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogPPTCDeletionErrorMessage"], file.Name, e));
+                            await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogPPTCDeletionErrorMessage], file.Name, e));
                         }
                     }
                 }
@@ -1230,11 +1230,11 @@ namespace Ryujinx.Ava.UI.ViewModels
                 DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader"));
 
                 // FIXME: Found a way to reproduce the bold effect on the title name (fork?).
-                UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
-                                                                                       string.Format(LocaleManager.Instance["DialogShaderDeletionMessage"], selection.TitleName),
-                                                                                       LocaleManager.Instance["InputDialogYes"],
-                                                                                       LocaleManager.Instance["InputDialogNo"],
-                                                                                       LocaleManager.Instance["RyujinxConfirm"]);
+                UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
+                                                                                       string.Format(LocaleManager.Instance[LocaleKeys.DialogShaderDeletionMessage], selection.TitleName),
+                                                                                       LocaleManager.Instance[LocaleKeys.InputDialogYes],
+                                                                                       LocaleManager.Instance[LocaleKeys.InputDialogNo],
+                                                                                       LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
 
                 List<DirectoryInfo> oldCacheDirectories = new();
                 List<FileInfo>      newCacheFiles       = new();
@@ -1256,7 +1256,7 @@ namespace Ryujinx.Ava.UI.ViewModels
                         }
                         catch (Exception e)
                         {
-                            await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogPPTCDeletionErrorMessage"], directory.Name, e));
+                            await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogPPTCDeletionErrorMessage], directory.Name, e));
                         }
                     }
                 }
@@ -1269,7 +1269,7 @@ namespace Ryujinx.Ava.UI.ViewModels
                     }
                     catch (Exception e)
                     {
-                        await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["ShaderCachePurgeError"], file.Name, e));
+                        await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.ShaderCachePurgeError], file.Name, e));
                     }
                 }
             }
@@ -1337,7 +1337,7 @@ namespace Ryujinx.Ava.UI.ViewModels
                     {
                         Dispatcher.UIThread.Post(async () =>
                         {
-                            await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]);
+                            await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogRyujinxErrorMessage], LocaleManager.Instance[LocaleKeys.DialogInvalidTitleIdErrorMessage]);
                         });
 
                         return;
@@ -1360,7 +1360,7 @@ namespace Ryujinx.Ava.UI.ViewModels
                     {
                         Dispatcher.UIThread.Post(async () =>
                         {
-                            await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]);
+                            await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogRyujinxErrorMessage], LocaleManager.Instance[LocaleKeys.DialogInvalidTitleIdErrorMessage]);
                         });
 
                         return;
@@ -1417,32 +1417,32 @@ namespace Ryujinx.Ava.UI.ViewModels
 
                 if (firmwareVersion == null)
                 {
-                    await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareNotFoundErrorMessage"], filename));
+                    await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareNotFoundErrorMessage], filename));
 
                     return;
                 }
 
-                string dialogTitle = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallTitle"], firmwareVersion.VersionString);
+                string dialogTitle = string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallTitle], firmwareVersion.VersionString);
 
                 SystemVersion currentVersion = _owner.ContentManager.GetCurrentFirmwareVersion();
 
-                string dialogMessage = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallMessage"], firmwareVersion.VersionString);
+                string dialogMessage = string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallMessage], firmwareVersion.VersionString);
 
                 if (currentVersion != null)
                 {
-                    dialogMessage += string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallSubMessage"], currentVersion.VersionString);
+                    dialogMessage += string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallSubMessage], currentVersion.VersionString);
                 }
 
-                dialogMessage += LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallConfirmMessage"];
+                dialogMessage += LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallConfirmMessage];
 
                 UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
                     dialogTitle,
                     dialogMessage,
-                    LocaleManager.Instance["InputDialogYes"],
-                    LocaleManager.Instance["InputDialogNo"],
-                    LocaleManager.Instance["RyujinxConfirm"]);
+                    LocaleManager.Instance[LocaleKeys.InputDialogYes],
+                    LocaleManager.Instance[LocaleKeys.InputDialogNo],
+                    LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
 
-                UpdateWaitWindow waitingDialog = ContentDialogHelper.CreateWaitingDialog(dialogTitle, LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallWaitMessage"]);
+                UpdateWaitWindow waitingDialog = ContentDialogHelper.CreateWaitingDialog(dialogTitle, LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallWaitMessage]);
 
                 if (result == UserResult.Yes)
                 {
@@ -1463,9 +1463,9 @@ namespace Ryujinx.Ava.UI.ViewModels
                             {
                                 waitingDialog.Close();
 
-                                string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallSuccessMessage"], firmwareVersion.VersionString);
+                                string message = string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallSuccessMessage], firmwareVersion.VersionString);
 
-                                await ContentDialogHelper.CreateInfoDialog(dialogTitle, message, LocaleManager.Instance["InputDialogOk"], "", LocaleManager.Instance["RyujinxInfo"]);
+                                await ContentDialogHelper.CreateInfoDialog(dialogTitle, message, LocaleManager.Instance[LocaleKeys.InputDialogOk], "", LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
 
                                 Logger.Info?.Print(LogClass.Application, message);
 
@@ -1513,7 +1513,7 @@ namespace Ryujinx.Ava.UI.ViewModels
         public async void InstallFirmwareFromFile()
         {
             OpenFileDialog dialog = new() { AllowMultiple = false };
-            dialog.Filters.Add(new FileDialogFilter { Name = LocaleManager.Instance["FileDialogAllTypes"], Extensions = { "xci", "zip" } });
+            dialog.Filters.Add(new FileDialogFilter { Name = LocaleManager.Instance[LocaleKeys.FileDialogAllTypes], Extensions = { "xci", "zip" } });
             dialog.Filters.Add(new FileDialogFilter { Name = "XCI",                                        Extensions = { "xci" } });
             dialog.Filters.Add(new FileDialogFilter { Name = "ZIP",                                        Extensions = { "zip" } });
 
diff --git a/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs b/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs
index de1bde46..5570800a 100644
--- a/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs
+++ b/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs
@@ -73,11 +73,11 @@ namespace Ryujinx.Ava.UI.ViewModels
                     {
                         Dispatcher.UIThread.Post(async () =>
                         {
-                            await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance["DialogSettingsBackendThreadingWarningMessage"],
+                            await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage],
                                                                        "",
                                                                        "",
-                                                                       LocaleManager.Instance["InputDialogOk"],
-                                                                       LocaleManager.Instance["DialogSettingsBackendThreadingWarningTitle"]);
+                                                                       LocaleManager.Instance[LocaleKeys.InputDialogOk],
+                                                                       LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningTitle]);
                         });
                     }
                 }
@@ -306,11 +306,11 @@ namespace Ryujinx.Ava.UI.ViewModels
         {
             var dialog = new OpenFileDialog()
             {
-                Title = LocaleManager.Instance["SettingsSelectThemeFileDialogTitle"],
+                Title = LocaleManager.Instance[LocaleKeys.SettingsSelectThemeFileDialogTitle],
                 AllowMultiple = false
             };
 
-            dialog.Filters.Add(new FileDialogFilter() { Extensions = { "xaml" }, Name = LocaleManager.Instance["SettingsXamlThemeFile"] });
+            dialog.Filters.Add(new FileDialogFilter() { Extensions = { "xaml" }, Name = LocaleManager.Instance[LocaleKeys.SettingsXamlThemeFile] });
 
             var file = await dialog.ShowAsync(_owner);
 
diff --git a/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs b/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs
index 7b2e1d39..3f0a85c9 100644
--- a/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs
+++ b/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs
@@ -149,10 +149,10 @@ namespace Ryujinx.Ava.UI.ViewModels
             
             ContentDialog contentDialog = new ContentDialog
             {
-                Title = string.Format(LocaleManager.Instance["SaveManagerHeading"], userProfile.Name),
+                Title = string.Format(LocaleManager.Instance[LocaleKeys.SaveManagerHeading], userProfile.Name),
                 PrimaryButtonText = "",
                 SecondaryButtonText = "",
-                CloseButtonText = LocaleManager.Instance["UserProfilesClose"],
+                CloseButtonText = LocaleManager.Instance[LocaleKeys.UserProfilesClose],
                 Content = manager,
                 Padding = new Thickness(0)
             };
@@ -180,7 +180,7 @@ namespace Ryujinx.Ava.UI.ViewModels
                     {
                         Dispatcher.UIThread.Post(async () =>
                         {
-                            await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUserProfileDeletionWarningMessage"]);
+                            await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionWarningMessage]);
                         });
 
                         return;
@@ -190,8 +190,8 @@ namespace Ryujinx.Ava.UI.ViewModels
                 }
 
                 var result =
-                    await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogUserProfileDeletionConfirmMessage"], "",
-                        LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], "");
+                    await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionConfirmMessage], "",
+                        LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogNo], "");
 
                 if (result == UserResult.Yes)
                 {
diff --git a/Ryujinx.Ava/UI/Windows/AboutWindow.axaml.cs b/Ryujinx.Ava/UI/Windows/AboutWindow.axaml.cs
index 2fb17e3a..99280b87 100644
--- a/Ryujinx.Ava/UI/Windows/AboutWindow.axaml.cs
+++ b/Ryujinx.Ava/UI/Windows/AboutWindow.axaml.cs
@@ -17,7 +17,7 @@ namespace Ryujinx.Ava.UI.Windows
         {
             if (Program.PreviewerDetached)
             {
-                Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["MenuBarHelpAbout"];
+                Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.MenuBarHelpAbout];
             }
 
             Version = Program.Version;
@@ -32,7 +32,7 @@ namespace Ryujinx.Ava.UI.Windows
         public string Supporters { get; set; }
         public string Version { get; set; }
 
-        public string Developers => string.Format(LocaleManager.Instance["AboutPageDeveloperListMore"], "gdkchan, Ac_K, Thog, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, Xpl0itR, GoffyDude, »jD«");
+        public string Developers => string.Format(LocaleManager.Instance[LocaleKeys.AboutPageDeveloperListMore], "gdkchan, Ac_K, Thog, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, Xpl0itR, GoffyDude, »jD«");
 
         private void Button_OnClick(object sender, RoutedEventArgs e)
         {
@@ -46,7 +46,7 @@ namespace Ryujinx.Ava.UI.Windows
         {
             if (!NetworkInterface.GetIsNetworkAvailable())
             {
-                Supporters = LocaleManager.Instance["ConnectionError"];
+                Supporters = LocaleManager.Instance[LocaleKeys.ConnectionError];
 
                 return;
             }
@@ -61,7 +61,7 @@ namespace Ryujinx.Ava.UI.Windows
             }
             catch
             {
-                Supporters = LocaleManager.Instance["ApiError"];
+                Supporters = LocaleManager.Instance[LocaleKeys.ApiError];
             }
 
             await Dispatcher.UIThread.InvokeAsync(() => SupportersTextBlock.Text = Supporters);
diff --git a/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml.cs b/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml.cs
index 68d16f35..5368a133 100644
--- a/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml.cs
+++ b/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml.cs
@@ -17,7 +17,7 @@ namespace Ryujinx.Ava.UI.Windows
 
             InitializeComponent();
 
-            Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["Amiibo"];
+            Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.Amiibo];
         }
 
         public AmiiboWindow()
@@ -30,7 +30,7 @@ namespace Ryujinx.Ava.UI.Windows
 
             if (Program.PreviewerDetached)
             {
-                Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["Amiibo"];
+                Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.Amiibo];
             }
         }
 
diff --git a/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs b/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs
index d31212c1..b27d20d3 100644
--- a/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs
+++ b/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs
@@ -24,14 +24,14 @@ namespace Ryujinx.Ava.UI.Windows
 
             InitializeComponent();
 
-            Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["CheatWindowTitle"];
+            Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.CheatWindowTitle];
         }
 
         public CheatWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName)
         {
             LoadedCheats = new AvaloniaList<CheatsList>();
 
-            Heading = string.Format(LocaleManager.Instance["CheatWindowHeading"], titleName, titleId.ToUpper());
+            Heading = string.Format(LocaleManager.Instance[LocaleKeys.CheatWindowHeading], titleName, titleId.ToUpper());
 
             InitializeComponent();
 
@@ -86,7 +86,7 @@ namespace Ryujinx.Ava.UI.Windows
 
             DataContext = this;
             
-            Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["CheatWindowTitle"];
+            Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.CheatWindowTitle];
         }
 
         public void Save()
diff --git a/Ryujinx.Ava/UI/Windows/ControllerSettingsWindow.axaml.cs b/Ryujinx.Ava/UI/Windows/ControllerSettingsWindow.axaml.cs
index df083085..2864b6da 100644
--- a/Ryujinx.Ava/UI/Windows/ControllerSettingsWindow.axaml.cs
+++ b/Ryujinx.Ava/UI/Windows/ControllerSettingsWindow.axaml.cs
@@ -148,11 +148,11 @@ namespace Ryujinx.Ava.UI.Windows
                 _dialogOpen = true;
 
                 var result = await ContentDialogHelper.CreateConfirmationDialog(
-                    LocaleManager.Instance["DialogControllerSettingsModifiedConfirmMessage"],
-                    LocaleManager.Instance["DialogControllerSettingsModifiedConfirmSubMessage"],
-                    LocaleManager.Instance["InputDialogYes"],
-                    LocaleManager.Instance["InputDialogNo"],
-                    LocaleManager.Instance["RyujinxConfirm"]);
+                    LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmMessage],
+                    LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmSubMessage],
+                    LocaleManager.Instance[LocaleKeys.InputDialogYes],
+                    LocaleManager.Instance[LocaleKeys.InputDialogNo],
+                    LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
 
                 if (result == UserResult.Yes)
                 {
diff --git a/Ryujinx.Ava/UI/Windows/DownloadableContentManagerWindow.axaml.cs b/Ryujinx.Ava/UI/Windows/DownloadableContentManagerWindow.axaml.cs
index 11be9383..fa9d70e2 100644
--- a/Ryujinx.Ava/UI/Windows/DownloadableContentManagerWindow.axaml.cs
+++ b/Ryujinx.Ava/UI/Windows/DownloadableContentManagerWindow.axaml.cs
@@ -43,7 +43,7 @@ namespace Ryujinx.Ava.UI.Windows
 
             InitializeComponent();
 
-            Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["DlcWindowTitle"]} - {_titleName} ({_titleId:X16})";
+            Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.DlcWindowTitle]} - {_titleName} ({_titleId:X16})";
         }
 
         public DownloadableContentManagerWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
@@ -73,7 +73,7 @@ namespace Ryujinx.Ava.UI.Windows
 
             DlcDataGrid.SelectionChanged += DlcDataGrid_SelectionChanged;
 
-            Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["DlcWindowTitle"]} - {_titleName} ({_titleId:X16})";
+            Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.DlcWindowTitle]} - {_titleName} ({_titleId:X16})";
 
             LoadDownloadableContents();
             PrintHeading();
@@ -86,7 +86,7 @@ namespace Ryujinx.Ava.UI.Windows
 
         private void PrintHeading()
         {
-            Heading.Text = string.Format(LocaleManager.Instance["DlcWindowHeading"], _downloadableContents.Count, _titleName, _titleId.ToString("X16"));
+            Heading.Text = string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], _downloadableContents.Count, _titleName, _titleId.ToString("X16"));
         }
 
         private void LoadDownloadableContents()
@@ -133,7 +133,7 @@ namespace Ryujinx.Ava.UI.Windows
             {
                 Dispatcher.UIThread.InvokeAsync(async () =>
                 {
-                    await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogDlcLoadNcaErrorMessage"], ex.Message, containerPath));
+                    await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogDlcLoadNcaErrorMessage], ex.Message, containerPath));
                 });
             }
 
@@ -181,7 +181,7 @@ namespace Ryujinx.Ava.UI.Windows
 
             if (!containsDownloadableContent)
             {
-                await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogDlcNoDlcErrorMessage"]);
+                await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogDlcNoDlcErrorMessage]);
             }
         }
 
@@ -241,7 +241,7 @@ namespace Ryujinx.Ava.UI.Windows
         {
             OpenFileDialog dialog = new OpenFileDialog()
             { 
-                Title         = LocaleManager.Instance["SelectDlcDialogTitle"],
+                Title         = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle],
                 AllowMultiple = true
             };
 
diff --git a/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs b/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs
index 08332da8..b2d822c3 100644
--- a/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs
+++ b/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs
@@ -179,12 +179,12 @@ namespace Ryujinx.Ava.UI.Windows
         {
             if (ConfigurationState.Instance.Logger.EnableTrace.Value)
             {
-                string mainMessage = LocaleManager.Instance["DialogPerformanceCheckLoggingEnabledMessage"];
-                string secondaryMessage = LocaleManager.Instance["DialogPerformanceCheckLoggingEnabledConfirmMessage"];
+                string mainMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckLoggingEnabledMessage];
+                string secondaryMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckLoggingEnabledConfirmMessage];
 
                 UserResult result = await ContentDialogHelper.CreateConfirmationDialog(mainMessage, secondaryMessage,
-                    LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"],
-                    LocaleManager.Instance["RyujinxConfirm"]);
+                    LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogNo],
+                    LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
 
                 if (result != UserResult.Yes)
                 {
@@ -196,13 +196,13 @@ namespace Ryujinx.Ava.UI.Windows
 
             if (!string.IsNullOrWhiteSpace(ConfigurationState.Instance.Graphics.ShadersDumpPath.Value))
             {
-                string mainMessage = LocaleManager.Instance["DialogPerformanceCheckShaderDumpEnabledMessage"];
+                string mainMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckShaderDumpEnabledMessage];
                 string secondaryMessage =
-                    LocaleManager.Instance["DialogPerformanceCheckShaderDumpEnabledConfirmMessage"];
+                    LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckShaderDumpEnabledConfirmMessage];
 
                 UserResult result = await ContentDialogHelper.CreateConfirmationDialog(mainMessage, secondaryMessage,
-                    LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"],
-                    LocaleManager.Instance["RyujinxConfirm"]);
+                    LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogNo],
+                    LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
 
                 if (result != UserResult.Yes)
                 {
@@ -227,11 +227,11 @@ namespace Ryujinx.Ava.UI.Windows
             if (AppHost != null)
             {
                 await ContentDialogHelper.CreateInfoDialog(
-                    LocaleManager.Instance["DialogLoadAppGameAlreadyLoadedMessage"],
-                    LocaleManager.Instance["DialogLoadAppGameAlreadyLoadedSubMessage"],
-                    LocaleManager.Instance["InputDialogOk"],
+                    LocaleManager.Instance[LocaleKeys.DialogLoadAppGameAlreadyLoadedMessage],
+                    LocaleManager.Instance[LocaleKeys.DialogLoadAppGameAlreadyLoadedSubMessage],
+                    LocaleManager.Instance[LocaleKeys.InputDialogOk],
                     "",
-                    LocaleManager.Instance["RyujinxInfo"]);
+                    LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
 
                 return;
             }
@@ -274,7 +274,7 @@ namespace Ryujinx.Ava.UI.Windows
                 }
 
                 CanUpdate = false;
-                ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance["LoadingHeading"], AppHost.Device.Application.TitleName) : titleName;
+                ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance[LocaleKeys.LoadingHeading], AppHost.Device.Application.TitleName) : titleName;
                 ViewModel.TitleName   = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
 
                 SwitchToGameControl(startFullscreen);
@@ -500,14 +500,14 @@ namespace Ryujinx.Ava.UI.Windows
 
             if (version != null)
             {
-                LocaleManager.Instance.UpdateDynamicValue("StatusBarSystemVersion",
+                LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarSystemVersion,
                     version.VersionString);
 
                 hasApplet = version.Major > 3;
             }
             else
             {
-                LocaleManager.Instance.UpdateDynamicValue("StatusBarSystemVersion", "0.0");
+                LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarSystemVersion, "0.0");
             }
 
             ViewModel.IsAppletMenuActive = hasApplet;
diff --git a/Ryujinx.Ava/UI/Windows/MotionSettingsWindow.axaml.cs b/Ryujinx.Ava/UI/Windows/MotionSettingsWindow.axaml.cs
index 215525fc..c686e7c3 100644
--- a/Ryujinx.Ava/UI/Windows/MotionSettingsWindow.axaml.cs
+++ b/Ryujinx.Ava/UI/Windows/MotionSettingsWindow.axaml.cs
@@ -45,10 +45,10 @@ namespace Ryujinx.Ava.UI.Windows
 
             ContentDialog contentDialog = new ContentDialog
             {
-                Title = LocaleManager.Instance["ControllerMotionTitle"],
-                PrimaryButtonText = LocaleManager.Instance["ControllerSettingsSave"],
+                Title = LocaleManager.Instance[LocaleKeys.ControllerMotionTitle],
+                PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave],
                 SecondaryButtonText = "",
-                CloseButtonText = LocaleManager.Instance["ControllerSettingsClose"],
+                CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose],
                 Content = content
             };
             contentDialog.PrimaryButtonClick += (sender, args) =>
diff --git a/Ryujinx.Ava/UI/Windows/RumbleSettingsWindow.axaml.cs b/Ryujinx.Ava/UI/Windows/RumbleSettingsWindow.axaml.cs
index f645ae35..178109d6 100644
--- a/Ryujinx.Ava/UI/Windows/RumbleSettingsWindow.axaml.cs
+++ b/Ryujinx.Ava/UI/Windows/RumbleSettingsWindow.axaml.cs
@@ -37,10 +37,10 @@ namespace Ryujinx.Ava.UI.Windows
 
             ContentDialog contentDialog = new ContentDialog
             {
-                Title = LocaleManager.Instance["ControllerRumbleTitle"],
-                PrimaryButtonText = LocaleManager.Instance["ControllerSettingsSave"],
+                Title = LocaleManager.Instance[LocaleKeys.ControllerRumbleTitle],
+                PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave],
                 SecondaryButtonText = "",
-                CloseButtonText = LocaleManager.Instance["ControllerSettingsClose"],
+                CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose],
                 Content = content,
             };
             
diff --git a/Ryujinx.Ava/UI/Windows/SettingsWindow.axaml.cs b/Ryujinx.Ava/UI/Windows/SettingsWindow.axaml.cs
index f3aa1d5e..ae489b86 100644
--- a/Ryujinx.Ava/UI/Windows/SettingsWindow.axaml.cs
+++ b/Ryujinx.Ava/UI/Windows/SettingsWindow.axaml.cs
@@ -29,7 +29,7 @@ namespace Ryujinx.Ava.UI.Windows
 
         public SettingsWindow(VirtualFileSystem virtualFileSystem, ContentManager contentManager)
         {
-            Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["Settings"]}";
+            Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.Settings]}";
 
             ViewModel   = new SettingsViewModel(virtualFileSystem, contentManager, this);
             DataContext = ViewModel;
diff --git a/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs b/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs
index 03c2b098..29dc5351 100644
--- a/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs
+++ b/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs
@@ -43,7 +43,7 @@ namespace Ryujinx.Ava.UI.Windows
 
             InitializeComponent();
             
-            Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["UpdateWindowTitle"]} - {_titleName} ({_titleId:X16})";
+            Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.UpdateWindowTitle]} - {_titleName} ({_titleId:X16})";
         }
 
         public TitleUpdateWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
@@ -73,7 +73,7 @@ namespace Ryujinx.Ava.UI.Windows
 
             InitializeComponent();
 
-            Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["UpdateWindowTitle"]} - {_titleName} ({_titleId:X16})";
+            Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.UpdateWindowTitle]} - {_titleName} ({_titleId:X16})";
 
             LoadUpdates();
             PrintHeading();
@@ -81,7 +81,7 @@ namespace Ryujinx.Ava.UI.Windows
 
         private void PrintHeading()
         {
-            Heading.Text = string.Format(LocaleManager.Instance["GameUpdateWindowHeading"], _titleUpdates.Count, _titleName, _titleId.ToString("X16"));
+            Heading.Text = string.Format(LocaleManager.Instance[LocaleKeys.GameUpdateWindowHeading], _titleUpdates.Count, _titleName, _titleId.ToString("X16"));
         }
 
         private void LoadUpdates()
@@ -148,7 +148,7 @@ namespace Ryujinx.Ava.UI.Windows
                     {
                         Dispatcher.UIThread.Post(async () =>
                         {
-                            await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUpdateAddUpdateErrorMessage"]);
+                            await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage]);
                         });
                     }
                 }
@@ -156,7 +156,7 @@ namespace Ryujinx.Ava.UI.Windows
                 {
                     Dispatcher.UIThread.Post(async () =>
                     {
-                        await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogDlcLoadNcaErrorMessage"], ex.Message, path));
+                        await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogDlcLoadNcaErrorMessage], ex.Message, path));
                     });
                 }
             }
@@ -193,7 +193,7 @@ namespace Ryujinx.Ava.UI.Windows
         {
             OpenFileDialog dialog = new()
             {
-                Title         = LocaleManager.Instance["SelectUpdateDialogTitle"],
+                Title         = LocaleManager.Instance[LocaleKeys.SelectUpdateDialogTitle],
                 AllowMultiple = true
             };
 
diff --git a/Ryujinx.Ui.LocaleGenerator/LocaleGenerator.cs b/Ryujinx.Ui.LocaleGenerator/LocaleGenerator.cs
new file mode 100644
index 00000000..f154e704
--- /dev/null
+++ b/Ryujinx.Ui.LocaleGenerator/LocaleGenerator.cs
@@ -0,0 +1,30 @@
+using Microsoft.CodeAnalysis;
+using System.Linq;
+
+namespace Ryujinx.Ui.LocaleGenerator
+{
+    [Generator]
+    public class LocaleGenerator : IIncrementalGenerator
+    {
+        public void Initialize(IncrementalGeneratorInitializationContext context)
+        {
+            var englishLocaleFile = context.AdditionalTextsProvider.Where(static x => x.Path.EndsWith("en_US.json"));
+
+            IncrementalValuesProvider<string> contents = englishLocaleFile.Select((text, cancellationToken) => text.GetText(cancellationToken)!.ToString());
+
+            context.RegisterSourceOutput(contents, (spc, content) =>
+            {
+                var lines = content.Split('\n').Where(x => x.Trim().StartsWith("\"")).Select(x => x.Split(':').First().Trim().Replace("\"", ""));
+                string enumSource = "namespace Ryujinx.Ava.Common.Locale;\n";
+                enumSource += "internal enum LocaleKeys\n{\n";
+                foreach (var line in lines)
+                {
+                    enumSource += $"    {line},\n";
+                }
+                enumSource += "}\n";
+
+                spc.AddSource("LocaleKeys", enumSource);
+            });
+        }
+    }
+}
diff --git a/Ryujinx.Ui.LocaleGenerator/Ryujinx.Ui.LocaleGenerator.csproj b/Ryujinx.Ui.LocaleGenerator/Ryujinx.Ui.LocaleGenerator.csproj
new file mode 100644
index 00000000..0960455d
--- /dev/null
+++ b/Ryujinx.Ui.LocaleGenerator/Ryujinx.Ui.LocaleGenerator.csproj
@@ -0,0 +1,20 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+      <TargetFramework>netstandard2.0</TargetFramework>
+      <Nullable>enable</Nullable>
+      <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
+      <CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
+      <IsRoslynComponent>true</IsRoslynComponent>
+      <LangVersion>latest</LangVersion>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+    <PackageReference Include="Microsoft.CodeAnalysis.CSharp"/>
+  </ItemGroup>
+
+</Project>
diff --git a/Ryujinx.sln b/Ryujinx.sln
index 0915ef98..1eaf006c 100644
--- a/Ryujinx.sln
+++ b/Ryujinx.sln
@@ -73,12 +73,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ava", "Ryujinx.Ava\
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.Common", "Ryujinx.Ui.Common\Ryujinx.Ui.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Horizon.Generators", "Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Generators", "Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj", "{D4D09B08-D580-4D69-B886-C35D2853F6C8}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spv.Generator", "Spv.Generator\Spv.Generator.csproj", "{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}"
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.LocaleGenerator", "Ryujinx.Ui.LocaleGenerator\Ryujinx.Ui.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -225,6 +227,10 @@ Global
 		{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE