Préparation traduction en => fr Part1

This commit is contained in:
2025-09-21 11:27:19 +02:00
parent 78089a9fc7
commit 17aa6e247c
10 changed files with 616 additions and 98 deletions

View File

@@ -0,0 +1,48 @@
using System.Globalization;
namespace MareSynchronos.Localization;
public static class LocalizationExtensions
{
public static string Loc(this string fallbackEnglish, params object[] formatArgs)
{
var service = LocalizationService.Instance;
if (service == null) return FormatFallback(fallbackEnglish, formatArgs);
return service.GetString(fallbackEnglish, formatArgs);
}
public static string LocKey(this string key, string fallbackEnglish, params object[] formatArgs)
{
var service = LocalizationService.Instance;
if (service == null) return FormatFallback(fallbackEnglish, formatArgs);
return service.GetString(key, fallbackEnglish, formatArgs);
}
public static string LocLabel(this string labelWithId, params object[] formatArgs)
{
if (string.IsNullOrEmpty(labelWithId)) return labelWithId;
var separatorIndex = labelWithId.IndexOf("##", StringComparison.Ordinal);
if (separatorIndex < 0)
{
return labelWithId.Loc(formatArgs);
}
var label = labelWithId[..separatorIndex];
var id = labelWithId[separatorIndex..];
return string.Concat(label.Loc(formatArgs), id);
}
private static string FormatFallback(string fallback, params object[] args)
{
if (args == null || args.Length == 0) return fallback;
try
{
return string.Format(CultureInfo.CurrentCulture, fallback, args);
}
catch
{
return fallback;
}
}
}

View File

@@ -0,0 +1,231 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text.Json;
using System.Threading;
using Dalamud.Plugin;
using MareSynchronos.MareConfiguration;
using MareSynchronos.MareConfiguration.Models;
using Microsoft.Extensions.Logging;
namespace MareSynchronos.Localization;
public class LocalizationService
{
private readonly ILogger<LocalizationService> _logger;
private readonly IDalamudPluginInterface _pluginInterface;
private readonly MareConfigService _configService;
private readonly Dictionary<LocalizationLanguage, Dictionary<string, string>> _translations = new();
private readonly HashSet<string> _missingLocalizationsLogged = new(StringComparer.Ordinal);
private readonly Lock _missingLocalizationsLock = new();
private static readonly JsonSerializerOptions JsonOptions = new()
{
AllowTrailingCommas = true
};
public static LocalizationService? Instance { get; private set; }
public LocalizationService(ILogger<LocalizationService> logger, IDalamudPluginInterface pluginInterface, MareConfigService configService)
{
_logger = logger;
_pluginInterface = pluginInterface;
_configService = configService;
Instance = this;
foreach (var language in Enum.GetValues<LocalizationLanguage>())
{
_translations[language] = LoadLanguage(language);
}
}
public LocalizationLanguage CurrentLanguage => _configService.Current.Language;
public static IEnumerable<LocalizationLanguage> SupportedLanguages => Enum.GetValues<LocalizationLanguage>();
public string GetString(string fallbackEnglish, params object[] formatArgs)
{
return GetStringInternal(null, fallbackEnglish, formatArgs);
}
public string GetString(string key, string fallbackEnglish, params object[] formatArgs)
{
return GetStringInternal(key, fallbackEnglish, formatArgs);
}
public string GetLanguageDisplayName(LocalizationLanguage language)
{
var fallback = language switch
{
LocalizationLanguage.French => "Français",
LocalizationLanguage.English => "English",
_ => language.ToString()
};
return GetRawString($"Language.DisplayName.{language}", fallback);
}
public void ReloadLanguage(LocalizationLanguage language)
{
_translations[language] = LoadLanguage(language);
}
public void ReloadAll()
{
foreach (var language in Enum.GetValues<LocalizationLanguage>())
{
ReloadLanguage(language);
}
}
private string GetStringInternal(string? key, string fallbackEnglish, params object[] formatArgs)
{
var usedKey = string.IsNullOrWhiteSpace(key) ? fallbackEnglish : key;
var text = GetRawString(usedKey, fallbackEnglish);
if (formatArgs != null && formatArgs.Length > 0)
{
try
{
return string.Format(CultureInfo.CurrentCulture, text, formatArgs);
}
catch (FormatException ex)
{
_logger.LogWarning(ex, "Localization format mismatch for key {Key} with text '{Text}'", usedKey, text);
try
{
return string.Format(CultureInfo.CurrentCulture, fallbackEnglish, formatArgs);
}
catch
{
return fallbackEnglish;
}
}
}
return text;
}
private string GetRawString(string key, string fallbackEnglish)
{
if (TryGetString(CurrentLanguage, key, out var localized))
{
return localized;
}
LogMissingLocalization(CurrentLanguage, key, fallbackEnglish);
if (TryGetString(LocalizationLanguage.English, key, out var english))
{
return english;
}
if (CurrentLanguage != LocalizationLanguage.English)
{
LogMissingLocalization(LocalizationLanguage.English, key, fallbackEnglish);
}
return fallbackEnglish;
}
private bool TryGetString(LocalizationLanguage language, string key, out string value)
{
var dictionary = GetDictionary(language);
if (dictionary.TryGetValue(key, out var text) && !string.IsNullOrWhiteSpace(text))
{
value = text;
return true;
}
value = string.Empty;
return false;
}
private Dictionary<string, string> GetDictionary(LocalizationLanguage language)
{
if (!_translations.TryGetValue(language, out var dictionary))
{
dictionary = LoadLanguage(language);
_translations[language] = dictionary;
}
return dictionary;
}
private Dictionary<string, string> LoadLanguage(LocalizationLanguage language)
{
var baseDirectory = _pluginInterface.AssemblyLocation.DirectoryName ?? string.Empty;
var localizationDirectory = Path.Combine(baseDirectory, "Localization");
var languageCode = GetLanguageCode(language);
var filePath = Path.Combine(localizationDirectory, $"{languageCode}.json");
Dictionary<string, string>? translations = null;
if (File.Exists(filePath))
{
try
{
using var stream = File.OpenRead(filePath);
translations = DeserializeTranslations(stream);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to load localization data from {FilePath}", filePath);
}
}
if (translations == null)
{
var assembly = Assembly.GetExecutingAssembly();
var resourceName = $"{assembly.GetName().Name}.Localization.{languageCode}.json";
using var resourceStream = assembly.GetManifestResourceStream(resourceName);
if (resourceStream != null)
{
try
{
translations = DeserializeTranslations(resourceStream);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to load embedded localization resource {Resource}", resourceName);
}
}
}
if (translations == null)
{
_logger.LogDebug("Localization data for {Language} not found on disk or embedded, using empty dictionary.", language);
translations = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
return translations;
}
private void LogMissingLocalization(LocalizationLanguage language, string key, string fallback)
{
var marker = $"{language}:{key}";
using var scope = _missingLocalizationsLock.EnterScope();
if (_missingLocalizationsLogged.Contains(marker)) return;
_missingLocalizationsLogged.Add(marker);
_logger.LogDebug("Missing localization for {Language} ({Key}). Using fallback '{Fallback}'.", language, key, fallback);
}
private static string GetLanguageCode(LocalizationLanguage language) => language switch
{
LocalizationLanguage.French => "fr",
LocalizationLanguage.English => "en",
_ => language.ToString().ToLowerInvariant(),
};
private static Dictionary<string, string>? DeserializeTranslations(Stream stream)
{
var translations = JsonSerializer.Deserialize<Dictionary<string, string>>(stream, JsonOptions);
return translations != null
? new Dictionary<string, string>(translations, StringComparer.OrdinalIgnoreCase)
: null;
}
}

View File

@@ -0,0 +1,96 @@
{
"Language.DisplayName.French": "French",
"Language.DisplayName.English": "English",
"Settings.General.LocalizationHeading": "Localization",
"Settings.General.Language": "Language",
"Settings.General.Language.Description": "Select the plugin language. Any missing translations will be shown in English.",
"Settings.General.NotesHeading": "Notes",
"Settings.General.Notes.Export": "Export all your user notes to clipboard",
"Settings.General.Notes.Import": "Import notes from clipboard",
"Settings.General.Notes.Overwrite": "Overwrite existing notes",
"Settings.General.Notes.Overwrite.Description": "If this option is selected all already existing notes for UIDs will be overwritten by the imported notes.",
"Settings.General.Notes.Import.Success": "User Notes successfully imported",
"Settings.General.Notes.Import.Failure": "Attempt to import notes from clipboard failed. Check formatting and try again",
"Settings.General.Notes.OpenPopup": "Open Notes Popup on user addition",
"Settings.General.Notes.OpenPopup.Description": "This will open a popup that allows you to set the notes for a user after successfully adding them to your individual pairs.",
"Settings.Transfers.Blocked.Description": "Files that you attempted to upload or download that were forbidden to be transferred by their creators will appear here. If you see file paths from your drive here, then those files were not allowed to be uploaded. If you see hashes, those files were not allowed to be downloaded. Ask your paired friend to send you the mod in question through other means or acquire the mod yourself.",
"Settings.Transfers.Blocked.Column.Hash": "Hash/Filename",
"Settings.Transfers.Blocked.Column.ForbiddenBy": "Forbidden by",
"Settings.Transfers.Heading": "Transfer Settings",
"Settings.Transfers.GlobalLimit.Label": "Global Download Speed Limit",
"Settings.Transfers.GlobalLimit.Unit.BytePerSec": "Byte/s",
"Settings.Transfers.GlobalLimit.Unit.KiloBytePerSec": "KB/s",
"Settings.Transfers.GlobalLimit.Unit.MegaBytePerSec": "MB/s",
"Settings.Transfers.GlobalLimit.Hint": "0 = No limit/infinite",
"Settings.Transfers.MaxParallelDownloads": "Maximum Parallel Downloads",
"Settings.Transfers.AutoDetect.Heading": "AutoDetect",
"Settings.Transfers.AutoDetect.EnableNearby": "Enable Nearby detection (beta)",
"Settings.Transfers.AutoDetect.AllowRequests": "Allow pair requests",
"Settings.Transfers.AutoDetect.Notification.Title": "Nearby Detection",
"Settings.Transfers.AutoDetect.Notification.Enabled": "Pair requests enabled: others can invite you.",
"Settings.Transfers.AutoDetect.Notification.Disabled": "Pair requests disabled: others cannot invite you.",
"Settings.Transfers.AutoDetect.MaxDistance": "Max distance (meters)",
"Settings.Transfers.UI.Heading": "Transfer UI",
"Settings.Transfers.UI.ShowWindow": "Show separate transfer window",
"Settings.Transfers.UI.ShowWindow.Description": "The download window will show the current progress of outstanding downloads.\n\nWhat do W/Q/P/D stand for?\nW = Waiting for Slot (see Maximum Parallel Downloads)\nQ = Queued on Server, waiting for queue ready signal\nP = Processing download (aka downloading)\nD = Decompressing download",
"Settings.Transfers.UI.EditWindowPosition": "Edit Transfer Window position",
"Settings.Transfers.UI.ShowTransferBars": "Show transfer bars rendered below players",
"Settings.Transfers.UI.ShowTransferBars.Description": "This will render a progress bar during the download at the feet of the player you are downloading from.",
"Settings.Transfers.UI.ShowDownloadText": "Show Download Text",
"Settings.Transfers.UI.ShowDownloadText.Description": "Shows download text (amount of MiB downloaded) in the transfer bars",
"Settings.Transfers.UI.BarWidth": "Transfer Bar Width",
"Settings.Transfers.UI.BarWidth.Description": "Width of the displayed transfer bars (will never be less wide than the displayed text)",
"Settings.Transfers.UI.BarHeight": "Transfer Bar Height",
"Settings.Transfers.UI.BarHeight.Description": "Height of the displayed transfer bars (will never be less tall than the displayed text)",
"Settings.Transfers.UI.ShowUploading": "Show 'Uploading' text below players that are currently uploading",
"Settings.Transfers.UI.ShowUploading.Description": "This will render an 'Uploading' text at the feet of the player that is in progress of uploading data.",
"Settings.Transfers.UI.ShowUploadingBigText": "Large font for 'Uploading' text",
"Settings.Transfers.UI.ShowUploadingBigText.Description": "This will render an 'Uploading' text in a larger font.",
"Settings.UI.Heading": "UI",
"Settings.UI.EnableRightClick": "Enable Game Right Click Menu Entries",
"Settings.UI.EnableRightClick.Description": "This will add Umbra related right click menu entries in the game UI on paired players.",
"Settings.UI.EnableDtrEntry": "Display status and visible pair count in Server Info Bar",
"Settings.UI.EnableDtrEntry.Description": "This will add Umbra connection status and visible pair count in the Server Info Bar.\nYou can further configure this through your Dalamud Settings.",
"Settings.UI.Dtr.ShowUid": "Show visible character's UID in tooltip",
"Settings.UI.Dtr.PreferNotes": "Prefer notes over player names in tooltip",
"Settings.UI.Dtr.UseColors": "Color-code the Server Info Bar entry according to status",
"Settings.UI.Dtr.ColorDefault": "Default",
"Settings.UI.Dtr.ColorNotConnected": "Not Connected",
"Settings.UI.Dtr.ColorPairsInRange": "Pairs in Range",
"Settings.UI.NameColors.Enable": "Color nameplates of paired players",
"Settings.UI.NameColors.Character": "Character Name Color",
"Settings.UI.NameColors.Blocked": "Blocked Character Color",
"Settings.UI.VisibleGroup": "Show separate Visible group",
"Settings.UI.VisibleGroup.Description": "This will show all currently visible users in a special 'Visible' group in the main UI.",
"Settings.UI.OfflineGroup": "Show separate Offline group",
"Settings.UI.OfflineGroup.Description": "This will show all currently offline users in a special 'Offline' group in the main UI.",
"Settings.UI.ShowPlayerNames": "Show player names",
"Settings.UI.ShowPlayerNames.Description": "This will show character names instead of UIDs when possible",
"Settings.UI.Profiles.Show": "Show Profiles on Hover",
"Settings.UI.Profiles.Show.Description": "This will show the configured user profile after a set delay",
"Settings.UI.Profiles.PopoutRight": "Popout profiles on the right",
"Settings.UI.Profiles.PopoutRight.Description": "Will show profiles on the right side of the main UI",
"Settings.UI.Profiles.HoverDelay": "Hover Delay",
"Settings.UI.Profiles.HoverDelay.Description": "Delay until the profile should be displayed",
"Settings.UI.Profiles.ShowNsfw": "Show profiles marked as NSFW",
"Settings.UI.Profiles.ShowNsfw.Description": "Will show profiles that have the NSFW tag enabled",
"Settings.Notifications.Heading": "Notifications",
"Settings.Notifications.InfoDisplay": "Info Notification Display",
"Settings.Notifications.InfoDisplay.Description": "The location where \"Info\" notifications will display.\n'Nowhere' will not show any Info notifications\n'Chat' will print Info notifications in chat\n'Toast' will show Warning toast notifications in the bottom right corner\n'Both' will show chat as well as the toast notification",
"Settings.Notifications.WarningDisplay": "Warning Notification Display",
"Settings.Notifications.WarningDisplay.Description": "The location where \"Warning\" notifications will display.\n'Nowhere' will not show any Warning notifications\n'Chat' will print Warning notifications in chat\n'Toast' will show Warning toast notifications in the bottom right corner\n'Both' will show chat as well as the toast notification",
"Settings.Notifications.ErrorDisplay": "Error Notification Display",
"Settings.Notifications.ErrorDisplay.Description": "The location where \"Error\" notifications will display.\n'Nowhere' will not show any Error notifications\n'Chat' will print Error notifications in chat\n'Toast' will show Error toast notifications in the bottom right corner\n'Both' will show chat as well as the toast notification",
"Settings.Notifications.Location.Nowhere": "Nowhere",
"Settings.Notifications.Location.Chat": "Chat",
"Settings.Notifications.Location.Toast": "Toast",
"Settings.Notifications.Location.Both": "Both",
"Settings.Notifications.DisableOptionalWarnings": "Disable optional plugin warnings",
"Settings.Notifications.DisableOptionalWarnings.Description": "Enabling this will not show any \"Warning\" labeled messages for missing optional plugins.",
"Settings.Notifications.EnableOnlineNotifications": "Enable online notifications",
"Settings.Notifications.EnableOnlineNotifications.Description": "Enabling this will show a small notification (type: Info) in the bottom right corner when pairs go online.",
"Settings.Notifications.IndividualPairsOnly": "Notify only for individual pairs",
"Settings.Notifications.IndividualPairsOnly.Description": "Enabling this will only show online notifications (type: Info) for individual pairs.",
"Settings.Notifications.NamedPairsOnly": "Notify only for named pairs",
"Settings.Notifications.NamedPairsOnly.Description": "Enabling this will only show online notifications (type: Info) for pairs where you have set an individual note."
}

View File

@@ -0,0 +1,96 @@
{
"Language.DisplayName.French": "Français",
"Language.DisplayName.English": "Anglais",
"Settings.General.LocalizationHeading": "Langue du plugin",
"Settings.General.Language": "Langue",
"Settings.General.Language.Description": "Sélectionnez la langue du plugin. Les traductions manquantes seront affichées en anglais.",
"Settings.General.NotesHeading": "",
"Settings.General.Notes.Export": "",
"Settings.General.Notes.Import": "",
"Settings.General.Notes.Overwrite": "",
"Settings.General.Notes.Overwrite.Description": "",
"Settings.General.Notes.Import.Success": "",
"Settings.General.Notes.Import.Failure": "",
"Settings.General.Notes.OpenPopup": "",
"Settings.General.Notes.OpenPopup.Description": "",
"Settings.Transfers.Blocked.Description": "",
"Settings.Transfers.Blocked.Column.Hash": "",
"Settings.Transfers.Blocked.Column.ForbiddenBy": "",
"Settings.Transfers.Heading": "",
"Settings.Transfers.GlobalLimit.Label": "",
"Settings.Transfers.GlobalLimit.Unit.BytePerSec": "",
"Settings.Transfers.GlobalLimit.Unit.KiloBytePerSec": "",
"Settings.Transfers.GlobalLimit.Unit.MegaBytePerSec": "",
"Settings.Transfers.GlobalLimit.Hint": "",
"Settings.Transfers.MaxParallelDownloads": "",
"Settings.Transfers.AutoDetect.Heading": "",
"Settings.Transfers.AutoDetect.EnableNearby": "",
"Settings.Transfers.AutoDetect.AllowRequests": "",
"Settings.Transfers.AutoDetect.Notification.Title": "",
"Settings.Transfers.AutoDetect.Notification.Enabled": "",
"Settings.Transfers.AutoDetect.Notification.Disabled": "",
"Settings.Transfers.AutoDetect.MaxDistance": "",
"Settings.Transfers.UI.Heading": "",
"Settings.Transfers.UI.ShowWindow": "",
"Settings.Transfers.UI.ShowWindow.Description": "",
"Settings.Transfers.UI.EditWindowPosition": "",
"Settings.Transfers.UI.ShowTransferBars": "",
"Settings.Transfers.UI.ShowTransferBars.Description": "",
"Settings.Transfers.UI.ShowDownloadText": "",
"Settings.Transfers.UI.ShowDownloadText.Description": "",
"Settings.Transfers.UI.BarWidth": "",
"Settings.Transfers.UI.BarWidth.Description": "",
"Settings.Transfers.UI.BarHeight": "",
"Settings.Transfers.UI.BarHeight.Description": "",
"Settings.Transfers.UI.ShowUploading": "",
"Settings.Transfers.UI.ShowUploading.Description": "",
"Settings.Transfers.UI.ShowUploadingBigText": "",
"Settings.Transfers.UI.ShowUploadingBigText.Description": "",
"Settings.UI.Heading": "",
"Settings.UI.EnableRightClick": "",
"Settings.UI.EnableRightClick.Description": "",
"Settings.UI.EnableDtrEntry": "",
"Settings.UI.EnableDtrEntry.Description": "",
"Settings.UI.Dtr.ShowUid": "",
"Settings.UI.Dtr.PreferNotes": "",
"Settings.UI.Dtr.UseColors": "",
"Settings.UI.Dtr.ColorDefault": "",
"Settings.UI.Dtr.ColorNotConnected": "",
"Settings.UI.Dtr.ColorPairsInRange": "",
"Settings.UI.NameColors.Enable": "",
"Settings.UI.NameColors.Character": "",
"Settings.UI.NameColors.Blocked": "",
"Settings.UI.VisibleGroup": "",
"Settings.UI.VisibleGroup.Description": "",
"Settings.UI.OfflineGroup": "",
"Settings.UI.OfflineGroup.Description": "",
"Settings.UI.ShowPlayerNames": "",
"Settings.UI.ShowPlayerNames.Description": "",
"Settings.UI.Profiles.Show": "",
"Settings.UI.Profiles.Show.Description": "",
"Settings.UI.Profiles.PopoutRight": "",
"Settings.UI.Profiles.PopoutRight.Description": "",
"Settings.UI.Profiles.HoverDelay": "",
"Settings.UI.Profiles.HoverDelay.Description": "",
"Settings.UI.Profiles.ShowNsfw": "",
"Settings.UI.Profiles.ShowNsfw.Description": "",
"Settings.Notifications.Heading": "",
"Settings.Notifications.InfoDisplay": "",
"Settings.Notifications.InfoDisplay.Description": "",
"Settings.Notifications.WarningDisplay": "",
"Settings.Notifications.WarningDisplay.Description": "",
"Settings.Notifications.ErrorDisplay": "",
"Settings.Notifications.ErrorDisplay.Description": "",
"Settings.Notifications.Location.Nowhere": "",
"Settings.Notifications.Location.Chat": "",
"Settings.Notifications.Location.Toast": "",
"Settings.Notifications.Location.Both": "",
"Settings.Notifications.DisableOptionalWarnings": "",
"Settings.Notifications.DisableOptionalWarnings.Description": "",
"Settings.Notifications.EnableOnlineNotifications": "",
"Settings.Notifications.EnableOnlineNotifications.Description": "",
"Settings.Notifications.IndividualPairsOnly": "",
"Settings.Notifications.IndividualPairsOnly.Description": "",
"Settings.Notifications.NamedPairsOnly": "",
"Settings.Notifications.NamedPairsOnly.Description": ""
}

View File

@@ -12,6 +12,7 @@ public class MareConfig : IMareConfiguration
public bool AcceptedAgreement { get; set; } = false; public bool AcceptedAgreement { get; set; } = false;
public string CacheFolder { get; set; } = string.Empty; public string CacheFolder { get; set; } = string.Empty;
public bool DisableOptionalPluginWarnings { get; set; } = false; public bool DisableOptionalPluginWarnings { get; set; } = false;
public LocalizationLanguage Language { get; set; } = LocalizationLanguage.French;
public bool EnableDtrEntry { get; set; } = true; public bool EnableDtrEntry { get; set; } = true;
public int DtrStyle { get; set; } = 0; public int DtrStyle { get; set; } = 0;
public bool ShowUidInDtrTooltip { get; set; } = true; public bool ShowUidInDtrTooltip { get; set; } = true;

View File

@@ -0,0 +1,7 @@
namespace MareSynchronos.MareConfiguration.Models;
public enum LocalizationLanguage
{
French = 0,
English = 1,
}

View File

@@ -60,4 +60,14 @@
<None Include="..\.editorconfig" Link=".editorconfig" /> <None Include="..\.editorconfig" Link=".editorconfig" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\\*.json" />
</ItemGroup>
<ItemGroup>
<Content Include="Localization\\*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project> </Project>

View File

@@ -6,6 +6,7 @@ using Dalamud.Plugin.Services;
using MareSynchronos.FileCache; using MareSynchronos.FileCache;
using MareSynchronos.Interop; using MareSynchronos.Interop;
using MareSynchronos.Interop.Ipc; using MareSynchronos.Interop.Ipc;
using MareSynchronos.Localization;
using MareSynchronos.MareConfiguration; using MareSynchronos.MareConfiguration;
using MareSynchronos.MareConfiguration.Configurations; using MareSynchronos.MareConfiguration.Configurations;
using MareSynchronos.PlayerData.Factories; using MareSynchronos.PlayerData.Factories;
@@ -91,6 +92,7 @@ public sealed class Plugin : IDalamudPlugin
collection.AddSingleton<MareMediator>(); collection.AddSingleton<MareMediator>();
collection.AddSingleton<FileCacheManager>(); collection.AddSingleton<FileCacheManager>();
collection.AddSingleton<ServerConfigurationManager>(); collection.AddSingleton<ServerConfigurationManager>();
collection.AddSingleton<LocalizationService>();
collection.AddSingleton<ApiController>(); collection.AddSingleton<ApiController>();
collection.AddSingleton<PerformanceCollectorService>(); collection.AddSingleton<PerformanceCollectorService>();
collection.AddSingleton<HubFactory>(); collection.AddSingleton<HubFactory>();

View File

@@ -9,6 +9,7 @@ using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Comparer; using MareSynchronos.API.Data.Comparer;
using MareSynchronos.FileCache; using MareSynchronos.FileCache;
using MareSynchronos.Interop.Ipc; using MareSynchronos.Interop.Ipc;
using MareSynchronos.Localization;
using MareSynchronos.MareConfiguration; using MareSynchronos.MareConfiguration;
using MareSynchronos.MareConfiguration.Models; using MareSynchronos.MareConfiguration.Models;
using MareSynchronos.PlayerData.Handlers; using MareSynchronos.PlayerData.Handlers;
@@ -134,6 +135,11 @@ public class SettingsUi : WindowMediatorSubscriberBase
base.OnClose(); base.OnClose();
} }
private string L(string key, string fallback, params object[] args)
{
return _uiShared.Localize(key, fallback, args);
}
private void DrawBlockedTransfers() private void DrawBlockedTransfers()
{ {
_lastTab = "BlockedTransfers"; _lastTab = "BlockedTransfers";
@@ -171,13 +177,13 @@ public class SettingsUi : WindowMediatorSubscriberBase
private void DrawCurrentTransfers() private void DrawCurrentTransfers()
{ {
_lastTab = "Transfers"; _lastTab = "Transfers";
_uiShared.BigText("Transfer Settings"); _uiShared.BigText(L("Settings.Transfers.Heading", "Transfer Settings"));
int maxParallelDownloads = _configService.Current.ParallelDownloads; int maxParallelDownloads = _configService.Current.ParallelDownloads;
int downloadSpeedLimit = _configService.Current.DownloadSpeedLimitInBytes; int downloadSpeedLimit = _configService.Current.DownloadSpeedLimitInBytes;
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Global Download Speed Limit"); ImGui.TextUnformatted(L("Settings.Transfers.GlobalLimit.Label", "Global Download Speed Limit"));
ImGui.SameLine(); ImGui.SameLine();
ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale); ImGui.SetNextItemWidth(100 * ImGuiHelpers.GlobalScale);
if (ImGui.InputInt("###speedlimit", ref downloadSpeedLimit)) if (ImGui.InputInt("###speedlimit", ref downloadSpeedLimit))
@@ -191,9 +197,9 @@ public class SettingsUi : WindowMediatorSubscriberBase
_uiShared.DrawCombo("###speed", [DownloadSpeeds.Bps, DownloadSpeeds.KBps, DownloadSpeeds.MBps], _uiShared.DrawCombo("###speed", [DownloadSpeeds.Bps, DownloadSpeeds.KBps, DownloadSpeeds.MBps],
(s) => s switch (s) => s switch
{ {
DownloadSpeeds.Bps => "Byte/s", DownloadSpeeds.Bps => L("Settings.Transfers.GlobalLimit.Unit.BytePerSec", "Byte/s"),
DownloadSpeeds.KBps => "KB/s", DownloadSpeeds.KBps => L("Settings.Transfers.GlobalLimit.Unit.KiloBytePerSec", "KB/s"),
DownloadSpeeds.MBps => "MB/s", DownloadSpeeds.MBps => L("Settings.Transfers.GlobalLimit.Unit.MegaBytePerSec", "MB/s"),
_ => throw new NotSupportedException() _ => throw new NotSupportedException()
}, (s) => }, (s) =>
{ {
@@ -203,19 +209,19 @@ public class SettingsUi : WindowMediatorSubscriberBase
}, _configService.Current.DownloadSpeedType); }, _configService.Current.DownloadSpeedType);
ImGui.SameLine(); ImGui.SameLine();
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("0 = No limit/infinite"); ImGui.TextUnformatted(L("Settings.Transfers.GlobalLimit.Hint", "0 = No limit/infinite"));
ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale); ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale);
if (ImGui.SliderInt("Maximum Parallel Downloads", ref maxParallelDownloads, 1, 10)) if (ImGui.SliderInt(L("Settings.Transfers.MaxParallelDownloads", "Maximum Parallel Downloads"), ref maxParallelDownloads, 1, 10))
{ {
_configService.Current.ParallelDownloads = maxParallelDownloads; _configService.Current.ParallelDownloads = maxParallelDownloads;
_configService.Save(); _configService.Save();
} }
ImGui.Separator(); ImGui.Separator();
_uiShared.BigText("AutoDetect"); _uiShared.BigText(L("Settings.Transfers.AutoDetect.Heading", "AutoDetect"));
bool enableDiscovery = _configService.Current.EnableAutoDetectDiscovery; bool enableDiscovery = _configService.Current.EnableAutoDetectDiscovery;
if (ImGui.Checkbox("Enable Nearby detection (beta)", ref enableDiscovery)) if (ImGui.Checkbox(L("Settings.Transfers.AutoDetect.EnableNearby", "Enable Nearby detection (beta)"), ref enableDiscovery))
{ {
_configService.Current.EnableAutoDetectDiscovery = enableDiscovery; _configService.Current.EnableAutoDetectDiscovery = enableDiscovery;
_configService.Save(); _configService.Save();
@@ -236,7 +242,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
using (ImRaii.Disabled(!enableDiscovery)) using (ImRaii.Disabled(!enableDiscovery))
{ {
bool allowRequests = _configService.Current.AllowAutoDetectPairRequests; bool allowRequests = _configService.Current.AllowAutoDetectPairRequests;
if (ImGui.Checkbox("Allow pair requests", ref allowRequests)) if (ImGui.Checkbox(L("Settings.Transfers.AutoDetect.AllowRequests", "Allow pair requests"), ref allowRequests))
{ {
_configService.Current.AllowAutoDetectPairRequests = allowRequests; _configService.Current.AllowAutoDetectPairRequests = allowRequests;
_configService.Save(); _configService.Save();
@@ -246,8 +252,10 @@ public class SettingsUi : WindowMediatorSubscriberBase
// user-facing info toast // user-facing info toast
Mediator.Publish(new NotificationMessage( Mediator.Publish(new NotificationMessage(
"Nearby Detection", L("Settings.Transfers.AutoDetect.Notification.Title", "Nearby Detection"),
allowRequests ? "Pair requests enabled: others can invite you." : "Pair requests disabled: others cannot invite you.", allowRequests
? L("Settings.Transfers.AutoDetect.Notification.Enabled", "Pair requests enabled: others can invite you.")
: L("Settings.Transfers.AutoDetect.Notification.Disabled", "Pair requests disabled: others cannot invite you."),
NotificationType.Info, NotificationType.Info,
default)); default));
} }
@@ -259,7 +267,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.Indent(); ImGui.Indent();
int maxMeters = _configService.Current.AutoDetectMaxDistanceMeters; int maxMeters = _configService.Current.AutoDetectMaxDistanceMeters;
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale); ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
if (ImGui.SliderInt("Max distance (meters)", ref maxMeters, 5, 100)) if (ImGui.SliderInt(L("Settings.Transfers.AutoDetect.MaxDistance", "Max distance (meters)"), ref maxMeters, 5, 100))
{ {
_configService.Current.AutoDetectMaxDistanceMeters = maxMeters; _configService.Current.AutoDetectMaxDistanceMeters = maxMeters;
_configService.Save(); _configService.Save();
@@ -268,23 +276,20 @@ public class SettingsUi : WindowMediatorSubscriberBase
} }
ImGui.Separator(); ImGui.Separator();
_uiShared.BigText("Transfer UI"); _uiShared.BigText(L("Settings.Transfers.UI.Heading", "Transfer UI"));
bool showTransferWindow = _configService.Current.ShowTransferWindow; bool showTransferWindow = _configService.Current.ShowTransferWindow;
if (ImGui.Checkbox("Show separate transfer window", ref showTransferWindow)) if (ImGui.Checkbox(L("Settings.Transfers.UI.ShowWindow", "Show separate transfer window"), ref showTransferWindow))
{ {
_configService.Current.ShowTransferWindow = showTransferWindow; _configService.Current.ShowTransferWindow = showTransferWindow;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText($"The download window will show the current progress of outstanding downloads.{Environment.NewLine}{Environment.NewLine}" + _uiShared.DrawHelpText(L("Settings.Transfers.UI.ShowWindow.Description",
$"What do W/Q/P/D stand for?{Environment.NewLine}W = Waiting for Slot (see Maximum Parallel Downloads){Environment.NewLine}" + "The download window will show the current progress of outstanding downloads.\n\nWhat do W/Q/P/D stand for?\nW = Waiting for Slot (see Maximum Parallel Downloads)\nQ = Queued on Server, waiting for queue ready signal\nP = Processing download (aka downloading)\nD = Decompressing download"));
$"Q = Queued on Server, waiting for queue ready signal{Environment.NewLine}" +
$"P = Processing download (aka downloading){Environment.NewLine}" +
$"D = Decompressing download");
if (!_configService.Current.ShowTransferWindow) ImGui.BeginDisabled(); if (!_configService.Current.ShowTransferWindow) ImGui.BeginDisabled();
ImGui.Indent(); ImGui.Indent();
bool editTransferWindowPosition = _uiShared.EditTrackerPosition; bool editTransferWindowPosition = _uiShared.EditTrackerPosition;
if (ImGui.Checkbox("Edit Transfer Window position", ref editTransferWindowPosition)) if (ImGui.Checkbox(L("Settings.Transfers.UI.EditWindowPosition", "Edit Transfer Window position"), ref editTransferWindowPosition))
{ {
_uiShared.EditTrackerPosition = editTransferWindowPosition; _uiShared.EditTrackerPosition = editTransferWindowPosition;
} }
@@ -292,60 +297,60 @@ public class SettingsUi : WindowMediatorSubscriberBase
if (!_configService.Current.ShowTransferWindow) ImGui.EndDisabled(); if (!_configService.Current.ShowTransferWindow) ImGui.EndDisabled();
bool showTransferBars = _configService.Current.ShowTransferBars; bool showTransferBars = _configService.Current.ShowTransferBars;
if (ImGui.Checkbox("Show transfer bars rendered below players", ref showTransferBars)) if (ImGui.Checkbox(L("Settings.Transfers.UI.ShowTransferBars", "Show transfer bars rendered below players"), ref showTransferBars))
{ {
_configService.Current.ShowTransferBars = showTransferBars; _configService.Current.ShowTransferBars = showTransferBars;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("This will render a progress bar during the download at the feet of the player you are downloading from."); _uiShared.DrawHelpText(L("Settings.Transfers.UI.ShowTransferBars.Description", "This will render a progress bar during the download at the feet of the player you are downloading from."));
if (!showTransferBars) ImGui.BeginDisabled(); if (!showTransferBars) ImGui.BeginDisabled();
ImGui.Indent(); ImGui.Indent();
bool transferBarShowText = _configService.Current.TransferBarsShowText; bool transferBarShowText = _configService.Current.TransferBarsShowText;
if (ImGui.Checkbox("Show Download Text", ref transferBarShowText)) if (ImGui.Checkbox(L("Settings.Transfers.UI.ShowDownloadText", "Show Download Text"), ref transferBarShowText))
{ {
_configService.Current.TransferBarsShowText = transferBarShowText; _configService.Current.TransferBarsShowText = transferBarShowText;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("Shows download text (amount of MiB downloaded) in the transfer bars"); _uiShared.DrawHelpText(L("Settings.Transfers.UI.ShowDownloadText.Description", "Shows download text (amount of MiB downloaded) in the transfer bars"));
int transferBarWidth = _configService.Current.TransferBarsWidth; int transferBarWidth = _configService.Current.TransferBarsWidth;
ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale); ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale);
if (ImGui.SliderInt("Transfer Bar Width", ref transferBarWidth, 0, 500)) if (ImGui.SliderInt(L("Settings.Transfers.UI.BarWidth", "Transfer Bar Width"), ref transferBarWidth, 0, 500))
{ {
if (transferBarWidth < 10) if (transferBarWidth < 10)
transferBarWidth = 10; transferBarWidth = 10;
_configService.Current.TransferBarsWidth = transferBarWidth; _configService.Current.TransferBarsWidth = transferBarWidth;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("Width of the displayed transfer bars (will never be less wide than the displayed text)"); _uiShared.DrawHelpText(L("Settings.Transfers.UI.BarWidth.Description", "Width of the displayed transfer bars (will never be less wide than the displayed text)"));
int transferBarHeight = _configService.Current.TransferBarsHeight; int transferBarHeight = _configService.Current.TransferBarsHeight;
ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale); ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale);
if (ImGui.SliderInt("Transfer Bar Height", ref transferBarHeight, 0, 50)) if (ImGui.SliderInt(L("Settings.Transfers.UI.BarHeight", "Transfer Bar Height"), ref transferBarHeight, 0, 50))
{ {
if (transferBarHeight < 2) if (transferBarHeight < 2)
transferBarHeight = 2; transferBarHeight = 2;
_configService.Current.TransferBarsHeight = transferBarHeight; _configService.Current.TransferBarsHeight = transferBarHeight;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("Height of the displayed transfer bars (will never be less tall than the displayed text)"); _uiShared.DrawHelpText(L("Settings.Transfers.UI.BarHeight.Description", "Height of the displayed transfer bars (will never be less tall than the displayed text)"));
bool showUploading = _configService.Current.ShowUploading; bool showUploading = _configService.Current.ShowUploading;
if (ImGui.Checkbox("Show 'Uploading' text below players that are currently uploading", ref showUploading)) if (ImGui.Checkbox(L("Settings.Transfers.UI.ShowUploading", "Show 'Uploading' text below players that are currently uploading"), ref showUploading))
{ {
_configService.Current.ShowUploading = showUploading; _configService.Current.ShowUploading = showUploading;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("This will render an 'Uploading' text at the feet of the player that is in progress of uploading data."); _uiShared.DrawHelpText(L("Settings.Transfers.UI.ShowUploading.Description", "This will render an 'Uploading' text at the feet of the player that is in progress of uploading data."));
ImGui.Unindent(); ImGui.Unindent();
if (!showUploading) ImGui.BeginDisabled(); if (!showUploading) ImGui.BeginDisabled();
ImGui.Indent(); ImGui.Indent();
bool showUploadingBigText = _configService.Current.ShowUploadingBigText; bool showUploadingBigText = _configService.Current.ShowUploadingBigText;
if (ImGui.Checkbox("Large font for 'Uploading' text", ref showUploadingBigText)) if (ImGui.Checkbox(L("Settings.Transfers.UI.ShowUploadingBigText", "Large font for 'Uploading' text"), ref showUploadingBigText))
{ {
_configService.Current.ShowUploadingBigText = showUploadingBigText; _configService.Current.ShowUploadingBigText = showUploadingBigText;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("This will render an 'Uploading' text in a larger font."); _uiShared.DrawHelpText(L("Settings.Transfers.UI.ShowUploadingBigText.Description", "This will render an 'Uploading' text in a larger font."));
ImGui.Unindent(); ImGui.Unindent();
@@ -970,12 +975,30 @@ public class SettingsUi : WindowMediatorSubscriberBase
_lastTab = "General"; _lastTab = "General";
_uiShared.BigText("Notes"); _uiShared.BigText(L("Settings.General.LocalizationHeading", "Localization"));
if (_uiShared.IconTextButton(FontAwesomeIcon.StickyNote, "Export all your user notes to clipboard")) ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale);
_uiShared.DrawCombo(
L("Settings.General.Language", "Language") + "###settings-language",
LocalizationService.SupportedLanguages,
lang => _uiShared.Localization.GetLanguageDisplayName(lang),
selectedLanguage =>
{
if (selectedLanguage == _configService.Current.Language) return;
_configService.Current.Language = selectedLanguage;
_configService.Save();
_uiShared.Localization.ReloadAll();
},
_configService.Current.Language);
_uiShared.DrawHelpText(L("Settings.General.Language.Description", "Select the plugin language. Any missing translations will be shown in English."));
ImGui.Separator();
_uiShared.BigText(L("Settings.General.NotesHeading", "Notes"));
if (_uiShared.IconTextButton(FontAwesomeIcon.StickyNote, L("Settings.General.Notes.Export", "Export all your user notes to clipboard")))
{ {
ImGui.SetClipboardText(UiSharedService.GetNotes(_pairManager.DirectPairs.UnionBy(_pairManager.GroupPairs.SelectMany(p => p.Value), p => p.UserData, UserDataComparer.Instance).ToList())); ImGui.SetClipboardText(UiSharedService.GetNotes(_pairManager.DirectPairs.UnionBy(_pairManager.GroupPairs.SelectMany(p => p.Value), p => p.UserData, UserDataComparer.Instance).ToList()));
} }
if (_uiShared.IconTextButton(FontAwesomeIcon.FileImport, "Import notes from clipboard")) if (_uiShared.IconTextButton(FontAwesomeIcon.FileImport, L("Settings.General.Notes.Import", "Import notes from clipboard")))
{ {
_notesSuccessfullyApplied = null; _notesSuccessfullyApplied = null;
var notes = ImGui.GetClipboardText(); var notes = ImGui.GetClipboardText();
@@ -983,28 +1006,28 @@ public class SettingsUi : WindowMediatorSubscriberBase
} }
ImGui.SameLine(); ImGui.SameLine();
ImGui.Checkbox("Overwrite existing notes", ref _overwriteExistingLabels); ImGui.Checkbox(L("Settings.General.Notes.Overwrite", "Overwrite existing notes"), ref _overwriteExistingLabels);
_uiShared.DrawHelpText("If this option is selected all already existing notes for UIDs will be overwritten by the imported notes."); _uiShared.DrawHelpText(L("Settings.General.Notes.Overwrite.Description", "If this option is selected all already existing notes for UIDs will be overwritten by the imported notes."));
if (_notesSuccessfullyApplied.HasValue && _notesSuccessfullyApplied.Value) if (_notesSuccessfullyApplied.HasValue && _notesSuccessfullyApplied.Value)
{ {
UiSharedService.ColorTextWrapped("User Notes successfully imported", UiSharedService.AccentColor); UiSharedService.ColorTextWrapped(L("Settings.General.Notes.Import.Success", "User Notes successfully imported"), UiSharedService.AccentColor);
} }
else if (_notesSuccessfullyApplied.HasValue && !_notesSuccessfullyApplied.Value) else if (_notesSuccessfullyApplied.HasValue && !_notesSuccessfullyApplied.Value)
{ {
UiSharedService.ColorTextWrapped("Attempt to import notes from clipboard failed. Check formatting and try again", ImGuiColors.DalamudRed); UiSharedService.ColorTextWrapped(L("Settings.General.Notes.Import.Failure", "Attempt to import notes from clipboard failed. Check formatting and try again"), ImGuiColors.DalamudRed);
} }
var openPopupOnAddition = _configService.Current.OpenPopupOnAdd; var openPopupOnAddition = _configService.Current.OpenPopupOnAdd;
if (ImGui.Checkbox("Open Notes Popup on user addition", ref openPopupOnAddition)) if (ImGui.Checkbox(L("Settings.General.Notes.OpenPopup", "Open Notes Popup on user addition"), ref openPopupOnAddition))
{ {
_configService.Current.OpenPopupOnAdd = openPopupOnAddition; _configService.Current.OpenPopupOnAdd = openPopupOnAddition;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("This will open a popup that allows you to set the notes for a user after successfully adding them to your individual pairs."); _uiShared.DrawHelpText(L("Settings.General.Notes.OpenPopup.Description", "This will open a popup that allows you to set the notes for a user after successfully adding them to your individual pairs."));
ImGui.Separator(); ImGui.Separator();
_uiShared.BigText("UI"); _uiShared.BigText(L("Settings.UI.Heading", "UI"));
var showCharacterNames = _configService.Current.ShowCharacterNames; var showCharacterNames = _configService.Current.ShowCharacterNames;
var showVisibleSeparate = _configService.Current.ShowVisibleUsersSeparately; var showVisibleSeparate = _configService.Current.ShowVisibleUsersSeparately;
var showOfflineSeparate = _configService.Current.ShowOfflineUsersSeparately; var showOfflineSeparate = _configService.Current.ShowOfflineUsersSeparately;
@@ -1021,30 +1044,30 @@ public class SettingsUi : WindowMediatorSubscriberBase
var dtrColorsNotConnected = _configService.Current.DtrColorsNotConnected; var dtrColorsNotConnected = _configService.Current.DtrColorsNotConnected;
var dtrColorsPairsInRange = _configService.Current.DtrColorsPairsInRange; var dtrColorsPairsInRange = _configService.Current.DtrColorsPairsInRange;
if (ImGui.Checkbox("Enable Game Right Click Menu Entries", ref enableRightClickMenu)) if (ImGui.Checkbox(L("Settings.UI.EnableRightClick", "Enable Game Right Click Menu Entries"), ref enableRightClickMenu))
{ {
_configService.Current.EnableRightClickMenus = enableRightClickMenu; _configService.Current.EnableRightClickMenus = enableRightClickMenu;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("This will add Umbra related right click menu entries in the game UI on paired players."); _uiShared.DrawHelpText(L("Settings.UI.EnableRightClick.Description", "This will add Umbra related right click menu entries in the game UI on paired players."));
if (ImGui.Checkbox("Display status and visible pair count in Server Info Bar", ref enableDtrEntry)) if (ImGui.Checkbox(L("Settings.UI.EnableDtrEntry", "Display status and visible pair count in Server Info Bar"), ref enableDtrEntry))
{ {
_configService.Current.EnableDtrEntry = enableDtrEntry; _configService.Current.EnableDtrEntry = enableDtrEntry;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("This will add Umbra connection status and visible pair count in the Server Info Bar.\nYou can further configure this through your Dalamud Settings."); _uiShared.DrawHelpText(L("Settings.UI.EnableDtrEntry.Description", "This will add Umbra connection status and visible pair count in the Server Info Bar.\nYou can further configure this through your Dalamud Settings."));
using (ImRaii.Disabled(!enableDtrEntry)) using (ImRaii.Disabled(!enableDtrEntry))
{ {
using var indent = ImRaii.PushIndent(); using var indent = ImRaii.PushIndent();
if (ImGui.Checkbox("Show visible character's UID in tooltip", ref showUidInDtrTooltip)) if (ImGui.Checkbox(L("Settings.UI.Dtr.ShowUid", "Show visible character's UID in tooltip"), ref showUidInDtrTooltip))
{ {
_configService.Current.ShowUidInDtrTooltip = showUidInDtrTooltip; _configService.Current.ShowUidInDtrTooltip = showUidInDtrTooltip;
_configService.Save(); _configService.Save();
} }
if (ImGui.Checkbox("Prefer notes over player names in tooltip", ref preferNoteInDtrTooltip)) if (ImGui.Checkbox(L("Settings.UI.Dtr.PreferNotes", "Prefer notes over player names in tooltip"), ref preferNoteInDtrTooltip))
{ {
_configService.Current.PreferNoteInDtrTooltip = preferNoteInDtrTooltip; _configService.Current.PreferNoteInDtrTooltip = preferNoteInDtrTooltip;
_configService.Save(); _configService.Save();
@@ -1052,7 +1075,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
DrawDtrStyleCombo(); DrawDtrStyleCombo();
if (ImGui.Checkbox("Color-code the Server Info Bar entry according to status", ref useColorsInDtr)) if (ImGui.Checkbox(L("Settings.UI.Dtr.UseColors", "Color-code the Server Info Bar entry according to status"), ref useColorsInDtr))
{ {
_configService.Current.UseColorsInDtr = useColorsInDtr; _configService.Current.UseColorsInDtr = useColorsInDtr;
_configService.Save(); _configService.Save();
@@ -1061,21 +1084,21 @@ public class SettingsUi : WindowMediatorSubscriberBase
using (ImRaii.Disabled(!useColorsInDtr)) using (ImRaii.Disabled(!useColorsInDtr))
{ {
using var indent2 = ImRaii.PushIndent(); using var indent2 = ImRaii.PushIndent();
if (InputDtrColors("Default", ref dtrColorsDefault)) if (InputDtrColors(L("Settings.UI.Dtr.ColorDefault", "Default"), ref dtrColorsDefault))
{ {
_configService.Current.DtrColorsDefault = dtrColorsDefault; _configService.Current.DtrColorsDefault = dtrColorsDefault;
_configService.Save(); _configService.Save();
} }
ImGui.SameLine(); ImGui.SameLine();
if (InputDtrColors("Not Connected", ref dtrColorsNotConnected)) if (InputDtrColors(L("Settings.UI.Dtr.ColorNotConnected", "Not Connected"), ref dtrColorsNotConnected))
{ {
_configService.Current.DtrColorsNotConnected = dtrColorsNotConnected; _configService.Current.DtrColorsNotConnected = dtrColorsNotConnected;
_configService.Save(); _configService.Save();
} }
ImGui.SameLine(); ImGui.SameLine();
if (InputDtrColors("Pairs in Range", ref dtrColorsPairsInRange)) if (InputDtrColors(L("Settings.UI.Dtr.ColorPairsInRange", "Pairs in Range"), ref dtrColorsPairsInRange))
{ {
_configService.Current.DtrColorsPairsInRange = dtrColorsPairsInRange; _configService.Current.DtrColorsPairsInRange = dtrColorsPairsInRange;
_configService.Save(); _configService.Save();
@@ -1086,7 +1109,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
var useNameColors = _configService.Current.UseNameColors; var useNameColors = _configService.Current.UseNameColors;
var nameColors = _configService.Current.NameColors; var nameColors = _configService.Current.NameColors;
var autoPausedNameColors = _configService.Current.BlockedNameColors; var autoPausedNameColors = _configService.Current.BlockedNameColors;
if (ImGui.Checkbox("Color nameplates of paired players", ref useNameColors)) if (ImGui.Checkbox(L("Settings.UI.NameColors.Enable", "Color nameplates of paired players"), ref useNameColors))
{ {
_configService.Current.UseNameColors = useNameColors; _configService.Current.UseNameColors = useNameColors;
_configService.Save(); _configService.Save();
@@ -1096,7 +1119,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
using (ImRaii.Disabled(!useNameColors)) using (ImRaii.Disabled(!useNameColors))
{ {
using var indent = ImRaii.PushIndent(); using var indent = ImRaii.PushIndent();
if (InputDtrColors("Character Name Color", ref nameColors)) if (InputDtrColors(L("Settings.UI.NameColors.Character", "Character Name Color"), ref nameColors))
{ {
_configService.Current.NameColors = nameColors; _configService.Current.NameColors = nameColors;
_configService.Save(); _configService.Save();
@@ -1105,7 +1128,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.SameLine(); ImGui.SameLine();
if (InputDtrColors("Blocked Character Color", ref autoPausedNameColors)) if (InputDtrColors(L("Settings.UI.NameColors.Blocked", "Blocked Character Color"), ref autoPausedNameColors))
{ {
_configService.Current.BlockedNameColors = autoPausedNameColors; _configService.Current.BlockedNameColors = autoPausedNameColors;
_configService.Save(); _configService.Save();
@@ -1113,59 +1136,59 @@ public class SettingsUi : WindowMediatorSubscriberBase
} }
} }
if (ImGui.Checkbox("Show separate Visible group", ref showVisibleSeparate)) if (ImGui.Checkbox(L("Settings.UI.VisibleGroup", "Show separate Visible group"), ref showVisibleSeparate))
{ {
_configService.Current.ShowVisibleUsersSeparately = showVisibleSeparate; _configService.Current.ShowVisibleUsersSeparately = showVisibleSeparate;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("This will show all currently visible users in a special 'Visible' group in the main UI."); _uiShared.DrawHelpText(L("Settings.UI.VisibleGroup.Description", "This will show all currently visible users in a special 'Visible' group in the main UI."));
if (ImGui.Checkbox("Show separate Offline group", ref showOfflineSeparate)) if (ImGui.Checkbox(L("Settings.UI.OfflineGroup", "Show separate Offline group"), ref showOfflineSeparate))
{ {
_configService.Current.ShowOfflineUsersSeparately = showOfflineSeparate; _configService.Current.ShowOfflineUsersSeparately = showOfflineSeparate;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("This will show all currently offline users in a special 'Offline' group in the main UI."); _uiShared.DrawHelpText(L("Settings.UI.OfflineGroup.Description", "This will show all currently offline users in a special 'Offline' group in the main UI."));
if (ImGui.Checkbox("Show player names", ref showCharacterNames)) if (ImGui.Checkbox(L("Settings.UI.ShowPlayerNames", "Show player names"), ref showCharacterNames))
{ {
_configService.Current.ShowCharacterNames = showCharacterNames; _configService.Current.ShowCharacterNames = showCharacterNames;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("This will show character names instead of UIDs when possible"); _uiShared.DrawHelpText(L("Settings.UI.ShowPlayerNames.Description", "This will show character names instead of UIDs when possible"));
if (ImGui.Checkbox("Show Profiles on Hover", ref showProfiles)) if (ImGui.Checkbox(L("Settings.UI.Profiles.Show", "Show Profiles on Hover"), ref showProfiles))
{ {
Mediator.Publish(new ClearProfileDataMessage()); Mediator.Publish(new ClearProfileDataMessage());
_configService.Current.ProfilesShow = showProfiles; _configService.Current.ProfilesShow = showProfiles;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("This will show the configured user profile after a set delay"); _uiShared.DrawHelpText(L("Settings.UI.Profiles.Show.Description", "This will show the configured user profile after a set delay"));
ImGui.Indent(); ImGui.Indent();
if (!showProfiles) ImGui.BeginDisabled(); if (!showProfiles) ImGui.BeginDisabled();
if (ImGui.Checkbox("Popout profiles on the right", ref profileOnRight)) if (ImGui.Checkbox(L("Settings.UI.Profiles.PopoutRight", "Popout profiles on the right"), ref profileOnRight))
{ {
_configService.Current.ProfilePopoutRight = profileOnRight; _configService.Current.ProfilePopoutRight = profileOnRight;
_configService.Save(); _configService.Save();
Mediator.Publish(new CompactUiChange(Vector2.Zero, Vector2.Zero)); Mediator.Publish(new CompactUiChange(Vector2.Zero, Vector2.Zero));
} }
_uiShared.DrawHelpText("Will show profiles on the right side of the main UI"); _uiShared.DrawHelpText(L("Settings.UI.Profiles.PopoutRight.Description", "Will show profiles on the right side of the main UI"));
ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale); ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale);
if (ImGui.SliderFloat("Hover Delay", ref profileDelay, 1, 10)) if (ImGui.SliderFloat(L("Settings.UI.Profiles.HoverDelay", "Hover Delay"), ref profileDelay, 1, 10))
{ {
_configService.Current.ProfileDelay = profileDelay; _configService.Current.ProfileDelay = profileDelay;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("Delay until the profile should be displayed"); _uiShared.DrawHelpText(L("Settings.UI.Profiles.HoverDelay.Description", "Delay until the profile should be displayed"));
if (!showProfiles) ImGui.EndDisabled(); if (!showProfiles) ImGui.EndDisabled();
ImGui.Unindent(); ImGui.Unindent();
if (ImGui.Checkbox("Show profiles marked as NSFW", ref showNsfwProfiles)) if (ImGui.Checkbox(L("Settings.UI.Profiles.ShowNsfw", "Show profiles marked as NSFW"), ref showNsfwProfiles))
{ {
Mediator.Publish(new ClearProfileDataMessage()); Mediator.Publish(new ClearProfileDataMessage());
_configService.Current.ProfilesAllowNsfw = showNsfwProfiles; _configService.Current.ProfilesAllowNsfw = showNsfwProfiles;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("Will show profiles that have the NSFW tag enabled"); _uiShared.DrawHelpText(L("Settings.UI.Profiles.ShowNsfw.Description", "Will show profiles that have the NSFW tag enabled"));
ImGui.Separator(); ImGui.Separator();
@@ -1176,72 +1199,69 @@ public class SettingsUi : WindowMediatorSubscriberBase
_uiShared.BigText("Notifications"); _uiShared.BigText("Notifications");
ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale); ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale);
_uiShared.DrawCombo("Info Notification Display##settingsUi", (NotificationLocation[])Enum.GetValues(typeof(NotificationLocation)), (i) => i.ToString(), _uiShared.DrawCombo(L("Settings.Notifications.InfoDisplay", "Info Notification Display") + "##settingsUi",
(NotificationLocation[])Enum.GetValues(typeof(NotificationLocation)),
i => L($"Settings.Notifications.Location.{i}", i.ToString()),
(i) => (i) =>
{ {
_configService.Current.InfoNotification = i; _configService.Current.InfoNotification = i;
_configService.Save(); _configService.Save();
}, _configService.Current.InfoNotification); }, _configService.Current.InfoNotification);
_uiShared.DrawHelpText("The location where \"Info\" notifications will display." _uiShared.DrawHelpText(L("Settings.Notifications.InfoDisplay.Description",
+ Environment.NewLine + "'Nowhere' will not show any Info notifications" "The location where \"Info\" notifications will display.\n'Nowhere' will not show any Info notifications\n'Chat' will print Info notifications in chat\n'Toast' will show Warning toast notifications in the bottom right corner\n'Both' will show chat as well as the toast notification"));
+ Environment.NewLine + "'Chat' will print Info notifications in chat"
+ Environment.NewLine + "'Toast' will show Warning toast notifications in the bottom right corner"
+ Environment.NewLine + "'Both' will show chat as well as the toast notification");
ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale); ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale);
_uiShared.DrawCombo("Warning Notification Display##settingsUi", (NotificationLocation[])Enum.GetValues(typeof(NotificationLocation)), (i) => i.ToString(), _uiShared.DrawCombo(L("Settings.Notifications.WarningDisplay", "Warning Notification Display") + "##settingsUi",
(NotificationLocation[])Enum.GetValues(typeof(NotificationLocation)),
i => L($"Settings.Notifications.Location.{i}", i.ToString()),
(i) => (i) =>
{ {
_configService.Current.WarningNotification = i; _configService.Current.WarningNotification = i;
_configService.Save(); _configService.Save();
}, _configService.Current.WarningNotification); }, _configService.Current.WarningNotification);
_uiShared.DrawHelpText("The location where \"Warning\" notifications will display." _uiShared.DrawHelpText(L("Settings.Notifications.WarningDisplay.Description",
+ Environment.NewLine + "'Nowhere' will not show any Warning notifications" "The location where \"Warning\" notifications will display.\n'Nowhere' will not show any Warning notifications\n'Chat' will print Warning notifications in chat\n'Toast' will show Warning toast notifications in the bottom right corner\n'Both' will show chat as well as the toast notification"));
+ Environment.NewLine + "'Chat' will print Warning notifications in chat"
+ Environment.NewLine + "'Toast' will show Warning toast notifications in the bottom right corner"
+ Environment.NewLine + "'Both' will show chat as well as the toast notification");
ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale); ImGui.SetNextItemWidth(250 * ImGuiHelpers.GlobalScale);
_uiShared.DrawCombo("Error Notification Display##settingsUi", (NotificationLocation[])Enum.GetValues(typeof(NotificationLocation)), (i) => i.ToString(), _uiShared.DrawCombo(L("Settings.Notifications.ErrorDisplay", "Error Notification Display") + "##settingsUi",
(NotificationLocation[])Enum.GetValues(typeof(NotificationLocation)),
i => L($"Settings.Notifications.Location.{i}", i.ToString()),
(i) => (i) =>
{ {
_configService.Current.ErrorNotification = i; _configService.Current.ErrorNotification = i;
_configService.Save(); _configService.Save();
}, _configService.Current.ErrorNotification); }, _configService.Current.ErrorNotification);
_uiShared.DrawHelpText("The location where \"Error\" notifications will display." _uiShared.DrawHelpText(L("Settings.Notifications.ErrorDisplay.Description",
+ Environment.NewLine + "'Nowhere' will not show any Error notifications" "The location where \"Error\" notifications will display.\n'Nowhere' will not show any Error notifications\n'Chat' will print Error notifications in chat\n'Toast' will show Error toast notifications in the bottom right corner\n'Both' will show chat as well as the toast notification"));
+ Environment.NewLine + "'Chat' will print Error notifications in chat"
+ Environment.NewLine + "'Toast' will show Error toast notifications in the bottom right corner"
+ Environment.NewLine + "'Both' will show chat as well as the toast notification");
if (ImGui.Checkbox("Disable optional plugin warnings", ref disableOptionalPluginWarnings)) if (ImGui.Checkbox(L("Settings.Notifications.DisableOptionalWarnings", "Disable optional plugin warnings"), ref disableOptionalPluginWarnings))
{ {
_configService.Current.DisableOptionalPluginWarnings = disableOptionalPluginWarnings; _configService.Current.DisableOptionalPluginWarnings = disableOptionalPluginWarnings;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("Enabling this will not show any \"Warning\" labeled messages for missing optional plugins."); _uiShared.DrawHelpText(L("Settings.Notifications.DisableOptionalWarnings.Description", "Enabling this will not show any \"Warning\" labeled messages for missing optional plugins."));
if (ImGui.Checkbox("Enable online notifications", ref onlineNotifs)) if (ImGui.Checkbox(L("Settings.Notifications.EnableOnlineNotifications", "Enable online notifications"), ref onlineNotifs))
{ {
_configService.Current.ShowOnlineNotifications = onlineNotifs; _configService.Current.ShowOnlineNotifications = onlineNotifs;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("Enabling this will show a small notification (type: Info) in the bottom right corner when pairs go online."); _uiShared.DrawHelpText(L("Settings.Notifications.EnableOnlineNotifications.Description", "Enabling this will show a small notification (type: Info) in the bottom right corner when pairs go online."));
using (ImRaii.Disabled(!onlineNotifs)) using (ImRaii.Disabled(!onlineNotifs))
{ {
using var indent = ImRaii.PushIndent(); using var indent = ImRaii.PushIndent();
if (ImGui.Checkbox("Notify only for individual pairs", ref onlineNotifsPairsOnly)) if (ImGui.Checkbox(L("Settings.Notifications.IndividualPairsOnly", "Notify only for individual pairs"), ref onlineNotifsPairsOnly))
{ {
_configService.Current.ShowOnlineNotificationsOnlyForIndividualPairs = onlineNotifsPairsOnly; _configService.Current.ShowOnlineNotificationsOnlyForIndividualPairs = onlineNotifsPairsOnly;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("Enabling this will only show online notifications (type: Info) for individual pairs."); _uiShared.DrawHelpText(L("Settings.Notifications.IndividualPairsOnly.Description", "Enabling this will only show online notifications (type: Info) for individual pairs."));
if (ImGui.Checkbox("Notify only for named pairs", ref onlineNotifsNamedOnly)) if (ImGui.Checkbox(L("Settings.Notifications.NamedPairsOnly", "Notify only for named pairs"), ref onlineNotifsNamedOnly))
{ {
_configService.Current.ShowOnlineNotificationsOnlyForNamedPairs = onlineNotifsNamedOnly; _configService.Current.ShowOnlineNotificationsOnlyForNamedPairs = onlineNotifsNamedOnly;
_configService.Save(); _configService.Save();
} }
_uiShared.DrawHelpText("Enabling this will only show online notifications (type: Info) for pairs where you have set an individual note."); _uiShared.DrawHelpText(L("Settings.Notifications.NamedPairsOnly.Description", "Enabling this will only show online notifications (type: Info) for pairs where you have set an individual note."));
} }
} }

View File

@@ -12,6 +12,7 @@ using Dalamud.Plugin.Services;
using Dalamud.Utility; using Dalamud.Utility;
using MareSynchronos.FileCache; using MareSynchronos.FileCache;
using MareSynchronos.Interop.Ipc; using MareSynchronos.Interop.Ipc;
using MareSynchronos.Localization;
using MareSynchronos.MareConfiguration; using MareSynchronos.MareConfiguration;
using MareSynchronos.MareConfiguration.Models; using MareSynchronos.MareConfiguration.Models;
using MareSynchronos.PlayerData.Pairs; using MareSynchronos.PlayerData.Pairs;
@@ -53,6 +54,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
private readonly DalamudUtilService _dalamudUtil; private readonly DalamudUtilService _dalamudUtil;
private readonly IpcManager _ipcManager; private readonly IpcManager _ipcManager;
private readonly IDalamudPluginInterface _pluginInterface; private readonly IDalamudPluginInterface _pluginInterface;
private readonly LocalizationService _localizationService;
private readonly ITextureProvider _textureProvider; private readonly ITextureProvider _textureProvider;
private readonly Dictionary<string, object> _selectedComboItems = new(StringComparer.Ordinal); private readonly Dictionary<string, object> _selectedComboItems = new(StringComparer.Ordinal);
private readonly ServerConfigurationManager _serverConfigurationManager; private readonly ServerConfigurationManager _serverConfigurationManager;
@@ -84,7 +86,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
public UiSharedService(ILogger<UiSharedService> logger, IpcManager ipcManager, ApiController apiController, public UiSharedService(ILogger<UiSharedService> logger, IpcManager ipcManager, ApiController apiController,
CacheMonitor cacheMonitor, FileDialogManager fileDialogManager, CacheMonitor cacheMonitor, FileDialogManager fileDialogManager,
MareConfigService configService, DalamudUtilService dalamudUtil, IDalamudPluginInterface pluginInterface, MareConfigService configService, DalamudUtilService dalamudUtil, IDalamudPluginInterface pluginInterface,
ITextureProvider textureProvider, LocalizationService localizationService, ITextureProvider textureProvider,
ServerConfigurationManager serverManager, MareMediator mediator) : base(logger, mediator) ServerConfigurationManager serverManager, MareMediator mediator) : base(logger, mediator)
{ {
_ipcManager = ipcManager; _ipcManager = ipcManager;
@@ -94,6 +96,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
_configService = configService; _configService = configService;
_dalamudUtil = dalamudUtil; _dalamudUtil = dalamudUtil;
_pluginInterface = pluginInterface; _pluginInterface = pluginInterface;
_localizationService = localizationService;
_textureProvider = textureProvider; _textureProvider = textureProvider;
_serverConfigurationManager = serverManager; _serverConfigurationManager = serverManager;
@@ -124,6 +127,10 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
} }
public ApiController ApiController => _apiController; public ApiController ApiController => _apiController;
public LocalizationService Localization => _localizationService;
public string Localize(string key, string fallback, params object[] args) => _localizationService.GetString(key, fallback, args);
public string Localize(string fallback, params object[] args) => _localizationService.GetString(fallback, args);
public bool EditTrackerPosition { get; set; } public bool EditTrackerPosition { get; set; }