Skip to content

Commit

Permalink
feat: localization of dialogs
Browse files Browse the repository at this point in the history
  • Loading branch information
RokyZevon committed May 24, 2024
1 parent bc3f4a0 commit 0f033b9
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 57 deletions.
1 change: 0 additions & 1 deletion App.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ public static IServiceCollection AddServices(this IServiceCollection services) =
services.AddSingleton<ConfigurationService>()
.AddSingleton<ModificationService>()
.AddSingleton<DataToolsService>()
.AddSingleton<DialogService>()
.AddSingleton<LocalizationService>();

public static IServiceCollection AddViewModels(this IServiceCollection services) =>
Expand Down
20 changes: 18 additions & 2 deletions Assets/Langs/en-US.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
// Navigation
"modList": "Mod List",
"modList": "MOD List",
"settings": "Settings",

// Mod List
"dragToReorder": "Drag here to reorder. ",
"priority": "Priority",
"priorityTooltip": "The higher the priority (lower number), the more important the mod is, and it will overwrite others in conflicts. ",
"priorityTooltip": "The higher the priority (lower number), the more important the MOD is, and it will overwrite others in conflicts. ",
"preview": "Preview",
"previewTooltip": "Click to view a larger image. ",
"id": "ID",
Expand All @@ -24,4 +24,20 @@
"language": "Language",
"selectLanguage": "Select Language",
"gameVersionUnsupported": "Selected game version is not supported, please ensure your game version is up-to-date",

// Dialogs
"ok": "OK",
"cancel": "Cancel",
"conflictsTitle": "Conflicts Detected",
"conflictsContent1": "Found conflicts between: ",
"conflictsContent2": "Click 'OK' if the order is correct, or 'Cancel' to reorder or disable some",
"gameNotFound": "Please locate game in Settings first",
"modInstallSuccess": "MOD installed successfully",
"noDataDirInMod": "No {0} folder found in {1}, seems not a valid MOD",
"noDataDirInGame": "Could not found a data folder in game's root directory, please make sure the game path is correct",
"noEnabledMods": "No MODs have been enabled yet",
"permDeny": "Permission denied when trying to access file: ",
"copyError": "An error occurred while copying the file: ",
"invalidDataI": "Invalid data.i file: ",
"errGenDataI": "An error occurred while generating data.i file: ",
}
30 changes: 23 additions & 7 deletions Assets/Langs/ja-JP.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
// メニュー
"modList": "Mod リスト",
"modList": "MOD リスト",
"settings": "設定",

// Mod リスト
Expand All @@ -10,18 +10,34 @@
"preview": "プレビュー",
"previewTooltip": "クリックすると大きな画像が表示されます。",
"id":"ID",
"idTooltip": "Mods フォルダ内のフォルダ名。",
"idTooltip": "MOD フォルダ内のフォルダ名。",
"name":"名前",
"nameTooltip": "クリックして編集してください。",
"enabled": "有効",
"openModsFolder": "Mods フォルダを開く。",
"openModsFolder": "MOD フォルダを開く。",
"reload": "リロード",
"modIt": "Mod It",
"modIt": "Mod する",

// 設定
"gamePath": "ゲーム パス",
"locateGame": "ゲームを探す",
"gamePath": "ゲームパス",
"locateGame": "ゲームを選ぶ",
"language": "言語",
"selectLanguage": "言語を選択",
"gameVersionUnsupported": "ゲーム バージョンがサポートされていません,最新のバージョンを使用してください。"
"gameVersionUnsupported": "ゲーム バージョンがサポートされていません,最新のバージョンを使用してください。",

// Dialogs
"ok": "OK",
"cancel": "キャンセル",
"conflictsTitle": "競合が検出されました",
"conflictsContent1": "以下の Mod 間で競合が検出されました",
"conflictsContent2": "MOD の順序が正しいことを確認したら、「OK」 をクリックして続行し、MOD リストを調整する必要がある場合は、「キャンセル」 をクリックして順序を変更するか、MOD を無効にします。",
"gameNotFound": "まず設定からゲームを選択してください",
"modInstallSuccess": "MODのインストールに成功しました",
"noDataDirInMod": "{1} に {0} フォルダが見つかりません、有効な MOD ではないようです",
"noDataDirInGame": "ゲームのルートディレクトリに data フォルダが見つかりません。ゲームのパスが正しいことを確認してください。",
"noEnabledMods": "MOD はまだ有効になっていません",
"permDeny": "ファイルのアクセス権限がありません: ",
"copyError": "ファイルのコピー中にエラーが発生しました:",
"invalidDataI": "無効な data.i ファイル: ",
"errGenDataI": "data.i ファイルの生成中にエラーが発生しました: ",
}
28 changes: 22 additions & 6 deletions Assets/Langs/zh-CN.json
Original file line number Diff line number Diff line change
@@ -1,27 +1,43 @@
{
// 导航菜单
"modList": "Mod 列表",
"modList": "MOD 列表",
"settings": "设置",

// Mod 列表
"dragToReorder": "拖拽此处可重新排序",
"priority": "优先级",
"priorityTooltip": "优先级越高则 Mod 越重要, 当发生冲突时会覆盖掉优先级低的 Mod",
"priorityTooltip": "优先级越高则 MOD 越重要, 当发生冲突时会覆盖掉优先级低的 MOD",
"preview": "预览",
"previewTooltip": "点击查看大图",
"id": "ID",
"idTooltip": "Mods 文件夹中的每个 Mod 的文件夹名",
"idTooltip": "MOD 文件夹中的每个 MOD 的文件夹名",
"name": "名称",
"nameTooltip": "点击可以编辑",
"enabled": "启用",
"openModsFolder": "打开 Mod 文件夹",
"openModsFolder": "打开 MOD 文件夹",
"reload": "刷新",
"modIt": "Mod",
"modIt": "MOD",

// 设置
"gamePath": "游戏路径",
"locateGame": "选择游戏",
"language": "语言",
"selectLanguage": "选择语言",
"gameVersionUnsupported": "该版本的游戏不受支持, 请确保游戏本体已更新至最新"
"gameVersionUnsupported": "该版本的游戏不受支持, 请确保游戏本体已更新至最新",

// 弹窗
"ok": "确定",
"cancel": "取消",
"conflictsTitle": "发现冲突",
"conflictsContent1": "在以下 MOD 间发现冲突: ",
"conflictsContent2": "若确认 MOD 顺序正确, 点击 '确定' 以继续; 若需调整 MOD 列表, 点击 '取消' 并重新排序或禁用 MOD",
"gameNotFound": "请先在设置界面选择游戏路径",
"modInstallSuccess": "MOD 安装成功",
"noDataDirInMod": "未能在 {1} 中找到 {0} 文件夹, 看起来它不是一个有效的 MOD",
"noDataDirInGame": "未能在游戏根目录下找到 data 文件夹, 请确认游戏路径是否正确",
"noEnabledMods": "尚未启用任何 MOD",
"permDeny": "尝试访问文件时权限不足: ",
"copyError": "复制文件时发生错误: ",
"invalidDataI": "无效的 data.i 文件: ",
"errGenDataI": "生成 data.i 文件时发生错误: ",
}
34 changes: 34 additions & 0 deletions Helpers/MessageBoxHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls;
using MsBox.Avalonia;

namespace RelinkModOrganizer.Helpers;

public static class MessageBoxHelpers
{
public static async Task InfoAsync(string message)
{
var msgBox = MessageBoxManager.GetMessageBoxStandard(
string.Empty,
message,
MsBox.Avalonia.Enums.ButtonEnum.Ok,
MsBox.Avalonia.Enums.Icon.Info,
WindowStartupLocation.CenterScreen);
await msgBox.ShowAsync();
}

public static async Task ErrorAsync(string message)
{
var msgBox = MessageBoxManager.GetMessageBoxStandard(
string.Empty,
message,
MsBox.Avalonia.Enums.ButtonEnum.Ok,
MsBox.Avalonia.Enums.Icon.Error,
WindowStartupLocation.CenterScreen);
await msgBox.ShowAsync();
}
}
1 change: 1 addition & 0 deletions RelinkModOrganizer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.10" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.10" />
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="11.0.10.9" />
<PackageReference Include="MessageBox.Avalonia" Version="3.1.5.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<!--<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="8.0.0" />-->
</ItemGroup>
Expand Down
45 changes: 30 additions & 15 deletions Services/ModificationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,40 @@
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using DynamicData.Binding;
using ReactiveUI;
using RelinkModOrganizer.Models;
using RelinkModOrganizer.ThirdParties.DataTools;
using RelinkModOrganizer.ViewModels;
using Results = RelinkModOrganizer.TryResults;

namespace RelinkModOrganizer.Services;

public class ModificationService(
ConfigurationService configService,
DataToolsService dataToolsService)
DataToolsService dataToolsService,
LocalizationService localizationService)
{
public async Task<TryResult> LoadModsFromDiskAsync()
{
var modsDirPath = Path.Combine(AppContext.BaseDirectory, Consts.ModsDirName);

var modIds = new List<string>();
foreach (var modPath in Directory.EnumerateFileSystemEntries(modsDirPath, "*", SearchOption.TopDirectoryOnly))
foreach (var modPath in Directory.EnumerateFileSystemEntries(
modsDirPath,
"*",
SearchOption.TopDirectoryOnly))
{
var dataDir = Directory
.EnumerateDirectories(modPath, Consts.GameDataDirName, SearchOption.AllDirectories)
.FirstOrDefault();

if (string.IsNullOrWhiteSpace(dataDir))
return Results.Error($"No {Consts.GameDataDirName} folder found in {modPath}, seems not a valid mod");
{
var msg = string.Format(
localizationService.LocalizedStrings["noDataDirInMod"],
Consts.GameDataDirName,
modPath);
return Results.Error(msg);
}

var modId = Path.GetFileName(modPath);
var relativeFilePaths = Directory
Expand Down Expand Up @@ -92,7 +101,7 @@ public TryResult TryCleanUpGameDir()
{
var gameDirPath = configService.Config.GameDirPath;
if (string.IsNullOrWhiteSpace(gameDirPath))
return Results.Error("Game directory not set");
return Results.Error(localizationService.LocalizedStrings["gameNotFound"]);

var dataDirPath = Path.Combine(gameDirPath, Consts.GameDataDirName);
try
Expand All @@ -116,15 +125,15 @@ public async Task<TryResult> TryCopyModsAsync()
{
var gameDirPath = configService.Config.GameDirPath;
if (string.IsNullOrWhiteSpace(gameDirPath))
return Results.Error("Game directory not set");
return Results.Error(localizationService.LocalizedStrings["gameNotFound"]);

var gameDataPath = Path.Combine(gameDirPath, Consts.GameDataDirName);
if (!Directory.Exists(gameDataPath))
return Results.Error("Could not found a data directory in game directory, please make sure the game directory is correct");
return Results.Error(localizationService.LocalizedStrings["noDataDirInGame"]);

var enabledMods = configService.Config.Mods.Values.Where(mod => mod.Enabled);
if (!enabledMods.Any())
return Results.Error("No enabled mods found");
return Results.Error(localizationService.LocalizedStrings["noEnabledMods"]);

// Make sure bigger order mods are copied first, then smaller order mods can overwrite them
enabledMods = enabledMods.OrderByDescending(mod => mod.Order);
Expand All @@ -143,7 +152,13 @@ public async Task<TryResult> TryCopyModsAsync()
.EnumerateDirectories(srcModPath, Consts.GameDataDirName, SearchOption.AllDirectories)
.FirstOrDefault();
if (dataDirPath == null)
return Results.Error($"No '{Consts.GameDataDirName}' folder found in {srcModPath}, seems not a valid mod");
{
var msg = string.Format(
localizationService.LocalizedStrings["noDataDirInMod"],
Consts.GameDataDirName,
srcModPath);
return Results.Error(msg);
}

foreach (var filePath in mod.RelativeFilePaths)
{
Expand All @@ -160,11 +175,11 @@ public async Task<TryResult> TryCopyModsAsync()
}
catch (UnauthorizedAccessException ex)
{
return Results.Error($"Permission denied when trying to access file: {ex.Message}");
return Results.Error(localizationService.LocalizedStrings["permDeny"] + ex.Message);
}
catch (Exception ex)
{
return Results.Error($"An error occurred while copying the file: {ex.Message}");
return Results.Error(localizationService.LocalizedStrings["copyError"] + ex.Message);
}

return Results.Ok();
Expand All @@ -174,7 +189,7 @@ public async Task<TryResult> TryGenerateDataIndexAsync()
{
var gameDirPath = configService.Config.GameDirPath;
if (string.IsNullOrWhiteSpace(gameDirPath))
return Results.Error("Game directory not set");
return Results.Error(localizationService.LocalizedStrings["gameNotFound"]);

try
{
Expand All @@ -183,11 +198,11 @@ public async Task<TryResult> TryGenerateDataIndexAsync()
}
catch (ArgumentNullException ex)
{
return Results.Error($"Invalid data.i file: {ex.Message}");
return Results.Error(localizationService.LocalizedStrings["invalidDataI"] + ex.Message);
}
catch (Exception ex)
{
return Results.Error($"An error occurred while generating data.i file: {ex.Message}");
return Results.Error(localizationService.LocalizedStrings["errGenDataI"] + ex.Message);
}

return Results.Ok();
Expand Down
Loading

0 comments on commit 0f033b9

Please sign in to comment.