Skip to content

Commit

Permalink
Merge pull request #173 from MicroCBer/localization
Browse files Browse the repository at this point in the history
Replace Strings with Localizable Resources
  • Loading branch information
Lauriethefish authored Jul 1, 2024
2 parents e4580ed + 20ab0e1 commit 195e43a
Show file tree
Hide file tree
Showing 32 changed files with 3,197 additions and 246 deletions.
26 changes: 17 additions & 9 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# All files
[*]
indent_style = space

# ReSharper properties
resharper_xml_indent_size = 2
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 4
Expand Down Expand Up @@ -47,22 +50,22 @@ dotnet_style_prefer_conditional_expression_over_return = true:silent
# Naming Conventions #
###############################
# Style Definitions
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# Use PascalCase for constant fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = warning
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const

# Use PascalCase for static readonly fields
dotnet_naming_symbols.static_readonly_fields.applicable_kinds = field
dotnet_naming_symbols.static_readonly_fields.required_modifiers = readonly,static
dotnet_naming_symbols.static_readonly_fields.applicable_kinds = field
dotnet_naming_symbols.static_readonly_fields.required_modifiers = readonly,static

dotnet_naming_rule.static_readonly_fields_should_be_pascal_case.severity = warning
dotnet_naming_rule.static_readonly_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.static_readonly_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_rule.static_readonly_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.static_readonly_fields_should_be_pascal_case.style = pascal_case_style
dotnet_style_operator_placement_when_wrapping = beginning_of_line
tab_width = 4
end_of_line = crlf
Expand Down Expand Up @@ -139,3 +142,8 @@ csharp_style_expression_bodied_local_functions = false:silent
[*.vb]
# Modifier preferences
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion

[*.{appxmanifest,axaml,build,dtd,nuspec,paml,uxml,xaml,xamlx,xoml,xsd}]
indent_style = space
indent_size = 2
tab_width = 4
4 changes: 4 additions & 0 deletions QuestPatcher.Core/Models/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ public string AppId
}
}

[DefaultValue(Language.Default)]
[JsonConverter(typeof(JsonStringEnumConverter))]
public Language Language { get; set; } = Language.Default;

private bool _displayLogs;

[DefaultValue(false)]
Expand Down
9 changes: 9 additions & 0 deletions QuestPatcher.Core/Models/Language.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace QuestPatcher.Core.Models
{
public enum Language
{
Default, // system default
English,
ChineseSimplified
}
}
22 changes: 19 additions & 3 deletions QuestPatcher/App.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Avalonia.Markup.Xaml;
using QuestPatcher.Core;
using QuestPatcher.Models;
using QuestPatcher.Resources;
using QuestPatcher.Services;
using Serilog;

Expand Down Expand Up @@ -95,10 +96,25 @@ public override void OnFrameworkInitializationCompleted()
Theme.LoadEmbeddedTheme("Styles/Themes/QuestPatcherDark.axaml", "Dark").ThemeStying);
}

DialogBuilder dialog = new()
string title;
string text;
try
{
Title = "Critical Error",
Text = "QuestPatcher encountered a critical error during early startup, which was unrecoverable.",
title = Strings.Loading_CriticalError_Title;
text = Strings.Loading_CriticalError_Text;
}
catch (Exception e)
{
// In case the resources failed to load
title = "Critical Error";
text = "QuestPatcher encountered a critical error during early startup, which was unrecoverable.";
Log.Error(e, "Failed to load critical error message from resource, using default");
}

var dialog = new DialogBuilder
{
Title = title,
Text = text,
HideCancelButton = true
};
dialog.WithException(ex);
Expand Down
58 changes: 29 additions & 29 deletions QuestPatcher/BrowseImportManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using QuestPatcher.Core;
using QuestPatcher.Core.Modding;
using QuestPatcher.Models;
using QuestPatcher.Resources;
using QuestPatcher.Services;
using Serilog;

Expand Down Expand Up @@ -169,8 +170,8 @@ public async Task AttemptImportUri(Uri uri)
{
var builder = new DialogBuilder
{
Title = "Failed to download file",
Text = $"Downloading the file from {uri} failed, and thus the file could not be imported.",
Title = Strings.BrowseImport_DownloadFailed_Title,
Text = String.Format(Strings.BrowseImport_DownloadFailed_Text, uri),
HideCancelButton = true
};
await builder.OpenDialogue(_mainWindow);
Expand All @@ -191,8 +192,8 @@ public async Task AttemptImportUri(Uri uri)
{
var builder = new DialogBuilder
{
Title = "Failed to import file from URL",
Text = $"The server at {uri} did not provide a valid file extension, and so QuestPatcher doesn't know how the import the file.",
Title = Strings.BrowseImport_BadUrl_Title,
Text = String.Format(Strings.BrowseImport_BadUrl_Text, uri),
HideCancelButton = true
};
await builder.OpenDialogue(_mainWindow);
Expand Down Expand Up @@ -259,16 +260,16 @@ private async Task ProcessImportQueue()

bool multiple = failedFiles.Count > 1;

DialogBuilder builder = new()
var builder = new DialogBuilder
{
Title = "Import Failed",
Title = Strings.BrowseImport_ImportFailed_Title,
HideCancelButton = true
};

if (multiple)
{
// Show the exceptions for multiple files in the logs to avoid a giagantic dialog
builder.Text = "Multiple files failed to install. Check logs for details about each";
builder.Text = Strings.BrowseImport_ImportFailed_Multiple_Text;
foreach (var pair in failedFiles)
{
Log.Error("Failed to install {FileName}: {Error}", Path.GetFileName(pair.Key), pair.Value.Message);
Expand All @@ -279,20 +280,20 @@ private async Task ProcessImportQueue()
{
// Display single files with more detail for the user
string filePath = failedFiles.Keys.First();
var exception = failedFiles.Values.First();

var ex = failedFiles.Values.First();
string fileName = Path.GetFileName(filePath);
// Don't display the full stack trace for InstallationExceptions, since these are thrown by QP and are not bugs/issues
if (exception is InstallationException)
if (ex is InstallationException)
{
builder.Text = $"{Path.GetFileName(filePath)} failed to install: {exception.Message}";
builder.Text = String.Format(Strings.BrowseImport_ImportFailed_Single_Exception_Text, fileName, ex.Message);
}
else
{
builder.Text = $"The file {Path.GetFileName(filePath)} failed to install";
builder.WithException(exception);
builder.Text = String.Format(Strings.BrowseImport_ImportFailed_Single_Text, fileName);
builder.WithException(ex);
}
Log.Error("Failed to install {FileName}: {Error}", Path.GetFileName(filePath), exception.Message);
Log.Debug(exception, "Full Error");
Log.Error("Failed to install {FileName}: {Error}", fileName, ex.Message);
Log.Debug(ex, "Full Error");
}

await builder.OpenDialogue(_mainWindow);
Expand Down Expand Up @@ -423,10 +424,10 @@ private async Task ImportUnknownFile(FileImportInfo importInfo)
{
FileCopyType? selectedType = null;

DialogBuilder builder = new()
var builder = new DialogBuilder
{
Title = "Multiple Import Options",
Text = $"{Path.GetFileName(path)} can be imported as multiple types of file. Please select what you would like it to be installed as.",
Title = Strings.BrowseImport_MultipleImport_Title,
Text = String.Format(Strings.BrowseImport_MultipleImport_Text, Path.GetFileName(path)),
HideOkButton = true,
HideCancelButton = true
};
Expand Down Expand Up @@ -468,14 +469,13 @@ private async Task<bool> TryImportMod(FileImportInfo importInfo)

if (mod.ModLoader != _installManager.InstalledApp?.ModLoader)
{
DialogBuilder builder = new()
var builder = new DialogBuilder
{
Title = "Wrong Mod Loader",
Text = $"The mod you are trying to install needs the modloader {mod.ModLoader}, however your app has the modloader {_installManager.InstalledApp?.ModLoader} installed."
+ "\nWould you like to repatch your app with the required modloader?"
Title = Strings.Mod_WrongModLoader_Title,
Text = String.Format(Strings.Mod_WrongModLoader_Text, mod.ModLoader, _installManager.InstalledApp?.ModLoader)
};
builder.OkButton.Text = "Repatch";
builder.CancelButton.Text = "Not now";
builder.OkButton.Text = Strings.Mod_WrongModLoader_Repatch;
builder.CancelButton.Text = Strings.Generic_NotNow;
if (await builder.OpenDialogue(_mainWindow))
{
_uiService.OpenRepatchMenu(mod.ModLoader);
Expand All @@ -489,13 +489,13 @@ private async Task<bool> TryImportMod(FileImportInfo importInfo)
// Prompt the user for outdated mods instead of enabling them automatically
if (mod.PackageVersion != null && mod.PackageVersion != _installManager.InstalledApp.Version)
{
DialogBuilder builder = new()
var builder = new DialogBuilder
{
Title = "Outdated Mod",
Text = $"The mod just installed is for version {mod.PackageVersion} of your app, however you have {_installManager.InstalledApp.Version}. Enabling the mod may crash the game, or not work."
Title = Strings.Mod_OutdatedMod_Title,
Text = String.Format(Strings.Mod_OutdatedMod_Text, mod.PackageVersion, _installManager.InstalledApp.Version),
};
builder.OkButton.Text = "Enable Now";
builder.CancelButton.Text = "Cancel";
builder.OkButton.Text = Strings.Mod_OutdatedMod_EnableNow;
builder.CancelButton.Text = Strings.Generic_Cancel;

if (!await builder.OpenDialogue(_mainWindow))
{
Expand Down
4 changes: 2 additions & 2 deletions QuestPatcher/DialogBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public class DialogBuilder
/// </summary>
public ButtonInfo OkButton { get; set; } = new()
{
Text = "OK",
Text = Resources.Strings.Generic_OK,
ReturnValue = true,
CloseDialogue = true
};
Expand All @@ -71,7 +71,7 @@ public class DialogBuilder
/// </summary>
public ButtonInfo CancelButton { get; set; } = new()
{
Text = "Cancel",
Text = Resources.Strings.Generic_Cancel,
ReturnValue = false,
CloseDialogue = true
};
Expand Down
18 changes: 18 additions & 0 deletions QuestPatcher/LanguageEnumExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Globalization;
using QuestPatcher.Core.Models;

namespace QuestPatcher
{
public static class LanguageEnumExtensions
{
public static CultureInfo? ToCultureInfo(this Language language)
{
return language switch
{
Language.English => new CultureInfo("en-US"),
Language.ChineseSimplified => new CultureInfo("zh-hans"),
_ => null
};
}
}
}
18 changes: 18 additions & 0 deletions QuestPatcher/QuestPatcher.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,22 @@
<ItemGroup>
<UpToDateCheckInput Remove="views\SelectDeviceWindow.axaml" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Update="Resources\Strings.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Update="Resources\Strings.zh-hans.resx">
<DependentUpon>Strings.resx</DependentUpon>
</EmbeddedResource>
</ItemGroup>

<ItemGroup>
<Compile Update="Resources\Strings.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Strings.resx</DependentUpon>
</Compile>
</ItemGroup>
</Project>
9 changes: 9 additions & 0 deletions QuestPatcher/QuestPatcher.csproj.user
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<ItemGroup>
<EmbeddedResource Update="Resources\Strings.resx">
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
</Project>
Loading

0 comments on commit 195e43a

Please sign in to comment.