diff --git a/ChatTwo/ChatTwo.csproj b/ChatTwo/ChatTwo.csproj
index d2b3ab9..0aef2f9 100755
--- a/ChatTwo/ChatTwo.csproj
+++ b/ChatTwo/ChatTwo.csproj
@@ -35,6 +35,11 @@
+
+
+
diff --git a/ChatTwo/Plugin.cs b/ChatTwo/Plugin.cs
index 84aef30..28c1af0 100755
--- a/ChatTwo/Plugin.cs
+++ b/ChatTwo/Plugin.cs
@@ -129,8 +129,8 @@ public sealed class Plugin : IDalamudPlugin
Notification.AddNotification(new Dalamud.Interface.ImGuiNotification.Notification
{
- Title = "Hellion Chat",
- Content = "Privacy filter activated by default. Settings → Privacy to adjust.",
+ Title = HellionStrings.Migration_Notification_Title,
+ Content = HellionStrings.Migration_Notification_Content,
Type = Dalamud.Interface.ImGuiNotification.NotificationType.Info,
InitialDuration = TimeSpan.FromSeconds(15),
});
@@ -392,6 +392,7 @@ public sealed class Plugin : IDalamudPlugin
: new CultureInfo(Config.LanguageOverride.Code());
Language.Culture = info;
+ HellionStrings.Culture = info;
}
private static readonly string[] ChatAddonNames =
diff --git a/ChatTwo/Resources/HellionStrings.Designer.cs b/ChatTwo/Resources/HellionStrings.Designer.cs
new file mode 100644
index 0000000..a8e9864
--- /dev/null
+++ b/ChatTwo/Resources/HellionStrings.Designer.cs
@@ -0,0 +1,102 @@
+//------------------------------------------------------------------------------
+//
+// Hand-maintained strongly-typed accessor for HellionStrings.resx.
+// Mirrors the layout of Language.Designer.cs so the same Plugin.cs
+// LanguageChanged handler can update Culture for both classes.
+//
+//------------------------------------------------------------------------------
+
+#nullable enable
+
+namespace ChatTwo.Resources;
+
+[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute]
+internal class HellionStrings
+{
+ private static global::System.Resources.ResourceManager? resourceMan;
+ private static global::System.Globalization.CultureInfo? resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal HellionStrings() { }
+
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if (resourceMan is null)
+ resourceMan = new global::System.Resources.ResourceManager("ChatTwo.Resources.HellionStrings", typeof(HellionStrings).Assembly);
+ return resourceMan;
+ }
+ }
+
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo? Culture
+ {
+ get => resourceCulture;
+ set => resourceCulture = value;
+ }
+
+ private static string Get(string key)
+ => ResourceManager.GetString(key, resourceCulture) ?? key;
+
+ internal static string Privacy_Tab_Title => Get(nameof(Privacy_Tab_Title));
+ internal static string Privacy_FilterEnabled_Name => Get(nameof(Privacy_FilterEnabled_Name));
+ internal static string Privacy_FilterEnabled_Description => Get(nameof(Privacy_FilterEnabled_Description));
+ internal static string Privacy_Whitelist_Help => Get(nameof(Privacy_Whitelist_Help));
+ internal static string Privacy_Preset_PrivacyFirst => Get(nameof(Privacy_Preset_PrivacyFirst));
+ internal static string Privacy_Preset_ClearAll => Get(nameof(Privacy_Preset_ClearAll));
+ internal static string Privacy_Preset_SelectAll => Get(nameof(Privacy_Preset_SelectAll));
+ internal static string Privacy_Group_DirectMessages => Get(nameof(Privacy_Group_DirectMessages));
+ internal static string Privacy_Group_PartyAlliance => Get(nameof(Privacy_Group_PartyAlliance));
+ internal static string Privacy_Group_FreeCompany => Get(nameof(Privacy_Group_FreeCompany));
+ internal static string Privacy_Group_Linkshells => Get(nameof(Privacy_Group_Linkshells));
+ internal static string Privacy_Group_CrossLinkshells => Get(nameof(Privacy_Group_CrossLinkshells));
+ internal static string Privacy_Group_ExtraChat => Get(nameof(Privacy_Group_ExtraChat));
+ internal static string Privacy_Group_PublicChat => Get(nameof(Privacy_Group_PublicChat));
+ internal static string Privacy_Group_SystemLogs => Get(nameof(Privacy_Group_SystemLogs));
+ internal static string Privacy_PersistUnknown_Name => Get(nameof(Privacy_PersistUnknown_Name));
+ internal static string Privacy_PersistUnknown_Description => Get(nameof(Privacy_PersistUnknown_Description));
+
+ internal static string Cleanup_Heading => Get(nameof(Cleanup_Heading));
+ internal static string Cleanup_Help_Intro => Get(nameof(Cleanup_Help_Intro));
+ internal static string Cleanup_Help_SavedNote => Get(nameof(Cleanup_Help_SavedNote));
+ internal static string Cleanup_RefreshPreview => Get(nameof(Cleanup_RefreshPreview));
+ internal static string Cleanup_NoPreview => Get(nameof(Cleanup_NoPreview));
+ internal static string Cleanup_TotalStored => Get(nameof(Cleanup_TotalStored));
+ internal static string Cleanup_WillKeep => Get(nameof(Cleanup_WillKeep));
+ internal static string Cleanup_WillDelete => Get(nameof(Cleanup_WillDelete));
+ internal static string Cleanup_Breakdown => Get(nameof(Cleanup_Breakdown));
+ internal static string Cleanup_Marker_Keep => Get(nameof(Cleanup_Marker_Keep));
+ internal static string Cleanup_Marker_Delete => Get(nameof(Cleanup_Marker_Delete));
+ internal static string Cleanup_Apply_Label => Get(nameof(Cleanup_Apply_Label));
+ internal static string Cleanup_Apply_Tooltip => Get(nameof(Cleanup_Apply_Tooltip));
+ internal static string Cleanup_Running => Get(nameof(Cleanup_Running));
+ internal static string Cleanup_PreviewError => Get(nameof(Cleanup_PreviewError));
+ internal static string Cleanup_Success => Get(nameof(Cleanup_Success));
+ internal static string Cleanup_Error => Get(nameof(Cleanup_Error));
+
+ internal static string Retention_Heading => Get(nameof(Retention_Heading));
+ internal static string Retention_Enabled_Name => Get(nameof(Retention_Enabled_Name));
+ internal static string Retention_Enabled_Description => Get(nameof(Retention_Enabled_Description));
+ internal static string Retention_Default_Label => Get(nameof(Retention_Default_Label));
+ internal static string Retention_Default_Help => Get(nameof(Retention_Default_Help));
+ internal static string Retention_Reset_Spec => Get(nameof(Retention_Reset_Spec));
+ internal static string Retention_Clear_Overrides => Get(nameof(Retention_Clear_Overrides));
+ internal static string Retention_Tree_Heading => Get(nameof(Retention_Tree_Heading));
+ internal static string Retention_Tag_Override => Get(nameof(Retention_Tag_Override));
+ internal static string Retention_Tag_Spec => Get(nameof(Retention_Tag_Spec));
+ internal static string Retention_Tag_Global => Get(nameof(Retention_Tag_Global));
+ internal static string Retention_Reset_Button => Get(nameof(Retention_Reset_Button));
+ internal static string Retention_Apply_Label => Get(nameof(Retention_Apply_Label));
+ internal static string Retention_Apply_Tooltip => Get(nameof(Retention_Apply_Tooltip));
+ internal static string Retention_Running => Get(nameof(Retention_Running));
+ internal static string Retention_LastRun_Never => Get(nameof(Retention_LastRun_Never));
+ internal static string Retention_LastRun_At => Get(nameof(Retention_LastRun_At));
+ internal static string Retention_Success => Get(nameof(Retention_Success));
+ internal static string Retention_Error => Get(nameof(Retention_Error));
+
+ internal static string Migration_Notification_Title => Get(nameof(Migration_Notification_Title));
+ internal static string Migration_Notification_Content => Get(nameof(Migration_Notification_Content));
+}
diff --git a/ChatTwo/Resources/HellionStrings.de.resx b/ChatTwo/Resources/HellionStrings.de.resx
new file mode 100644
index 0000000..067db01
--- /dev/null
+++ b/ChatTwo/Resources/HellionStrings.de.resx
@@ -0,0 +1,180 @@
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Datenschutz
+
+
+ Datenschutz-Filter aktivieren
+
+
+ Wenn aktiviert, werden nur Nachrichten aus den erlaubten Kanälen in die Datenbank gespeichert. Beim Deaktivieren gilt wieder das Standard-Verhalten von ChatTwo, also alles außer Battle-Logs wird gespeichert.
+
+
+ Wähle aus, welche Kanäle in die lokale Datenbank gespeichert werden. Standard nach Datensparsamkeit: nur deine eigenen Konversationen. Über die Buttons unten kannst du eine Voreinstellung anwenden.
+
+
+ Datensparsamkeit (empfohlen)
+
+
+ Alle abwählen
+
+
+ Alle auswählen
+
+
+ Direktnachrichten
+
+
+ Gruppe & Allianz
+
+
+ Free Company
+
+
+ Linkshells
+
+
+ Cross-World-Linkshells
+
+
+ ExtraChat (verschlüsselt)
+
+
+ Öffentlicher Chat (Daten Dritter)
+
+
+ System & Spiel-Logs
+
+
+ Unbekannte Kanal-Typen speichern
+
+
+ Sicherheitsnetz für ChatTypes, die durch zukünftige FFXIV-Patches dazukommen und dem Plugin noch nicht bekannt sind. Standard ist AUS (Datensparsamkeit). Aktivieren, wenn du auch zukünftige Kanäle vollständig mitloggen willst.
+
+
+ Filter auf bestehende Datenbank anwenden
+
+
+ Der Datenschutz-Filter wirkt nur auf neue Nachrichten. Über das Aufräumen unten kannst du bereits gespeicherte Nachrichten nachträglich entfernen, die nicht zu deiner gespeicherten Whitelist passen.
+
+
+ Das Aufräumen nutzt deine GESPEICHERTE Whitelist (Plugin.Config), nicht ungespeicherte Änderungen oben. Klicke zuerst Speichern, wenn du deine aktuellen Änderungen anwenden willst.
+
+
+ Vorschau aktualisieren
+
+
+ Noch keine Vorschau. Klicke Aktualisieren, um die Auswirkung zu berechnen.
+
+
+ Gespeicherte Nachrichten gesamt: {0:N0}
+
+
+ Behalten: {0:N0}
+
+
+ Löschen: {0:N0}
+
+
+ Aufschlüsselung pro Kanal
+
+
+ [BEHALTEN]
+
+
+ [LÖSCHEN]
+
+
+ Aktuellen Filter auf Datenbank anwenden
+
+
+ Strg+Umschalt: Löscht {0:N0} Nachrichten unwiderruflich und führt danach VACUUM aus. Nicht rückgängig zu machen.
+
+
+ Aufräumen läuft im Hintergrund…
+
+
+ Vorschau konnte nicht berechnet werden, siehe /xllog
+
+
+ Aufräumen abgeschlossen, {0:N0} Nachrichten entfernt.
+
+
+ Aufräumen fehlgeschlagen, siehe /xllog
+
+
+ Aufbewahrung von Nachrichten
+
+
+ Nachrichten nach Kanal-Aufbewahrung automatisch löschen
+
+
+ Wenn aktiviert, werden Nachrichten älter als das eingestellte Fenster bei jedem Plugin-Start gelöscht (höchstens einmal pro 24 Stunden). Standard ist AUS, das Plugin löscht ohne deine ausdrückliche Zustimmung nichts.
+
+
+ Standard-Aufbewahrung (Tage, 0 = nie)
+
+
+ Gilt für Kanäle, die unten keine eigene Vorgabe haben.
+
+
+ Vorgaben auf Spec-Defaults setzen
+
+
+ Alle Vorgaben entfernen
+
+
+ Aufbewahrung pro Kanal
+
+
+ [eigen]
+
+
+ [spec]
+
+
+ [global]
+
+
+ zurück
+
+
+ Aufbewahrung jetzt anwenden
+
+
+ Strg+Umschalt: Führt die Aufbewahrungs-Bereinigung sofort mit der GESPEICHERTEN Vorgabe aus. Speichere deine Änderungen vorher.
+
+
+ Aufbewahrungs-Bereinigung läuft im Hintergrund…
+
+
+ Letzter Lauf: nie
+
+
+ Letzter Lauf: {0:yyyy-MM-dd HH:mm}
+
+
+ Aufbewahrungs-Bereinigung abgeschlossen, {0:N0} Nachrichten entfernt.
+
+
+ Aufbewahrungs-Bereinigung fehlgeschlagen, siehe /xllog
+
+
+ Hellion Chat
+
+
+ Datenschutz-Filter ist standardmäßig aktiviert. Einstellungen → Datenschutz zum Anpassen.
+
+
diff --git a/ChatTwo/Resources/HellionStrings.resx b/ChatTwo/Resources/HellionStrings.resx
new file mode 100644
index 0000000..c8a791d
--- /dev/null
+++ b/ChatTwo/Resources/HellionStrings.resx
@@ -0,0 +1,180 @@
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Privacy
+
+
+ Enable privacy filter
+
+
+ When enabled, only messages from whitelisted channels are persisted to the database. Disabling restores upstream ChatTwo behavior (everything except battle messages is stored).
+
+
+ Pick which channels are stored in the local database. Privacy-First default: only your own conversations. Use the buttons below to apply a preset.
+
+
+ Privacy-First (recommended)
+
+
+ Clear all
+
+
+ Select all
+
+
+ Direct Messages
+
+
+ Party & Alliance
+
+
+ Free Company
+
+
+ Linkshells
+
+
+ Cross-World Linkshells
+
+
+ ExtraChat (Encrypted)
+
+
+ Public Chat (third-party data)
+
+
+ System & Game Logs
+
+
+ Persist unknown channel types
+
+
+ Failsafe for ChatTypes added by future FFXIV patches that this plugin does not yet know about. Default OFF (Privacy-First). Turn ON if you want a complete log including future channels.
+
+
+ Apply filter to existing database
+
+
+ The privacy filter only applies to new messages. Use the cleanup below to retroactively remove already-stored messages that don't match your saved whitelist.
+
+
+ Cleanup uses your SAVED whitelist (Plugin.Config), not unsaved edits above. Click Save first if you want to apply your current edits.
+
+
+ Refresh preview
+
+
+ No preview yet. Click Refresh to compute the impact.
+
+
+ Total stored messages: {0:N0}
+
+
+ Will keep: {0:N0}
+
+
+ Will delete: {0:N0}
+
+
+ Per-channel breakdown
+
+
+ [KEEP]
+
+
+ [DELETE]
+
+
+ Apply current filter to database
+
+
+ Ctrl+Shift: Hard-deletes {0:N0} messages, then runs VACUUM. Cannot be undone.
+
+
+ Cleanup running in background…
+
+
+ Failed to compute cleanup preview, see /xllog
+
+
+ Privacy cleanup complete: {0:N0} messages removed.
+
+
+ Privacy cleanup failed, see /xllog
+
+
+ Message retention
+
+
+ Auto-delete messages after a per-channel retention window
+
+
+ When enabled, messages older than the configured window are deleted on every plugin start (at most once per 24 hours). Off by default — the plugin never deletes history without your explicit consent.
+
+
+ Default retention (days, 0 = never)
+
+
+ Applies to channels without an explicit override below.
+
+
+ Reset overrides to spec defaults
+
+
+ Clear all overrides
+
+
+ Per-channel retention overrides
+
+
+ [override]
+
+
+ [spec]
+
+
+ [global]
+
+
+ reset
+
+
+ Apply retention policy now
+
+
+ Ctrl+Shift: runs the retention sweep immediately using the SAVED policy. Save your changes first.
+
+
+ Retention sweep running in background…
+
+
+ Last run: never
+
+
+ Last run: {0:yyyy-MM-dd HH:mm}
+
+
+ Retention sweep complete: {0:N0} messages removed.
+
+
+ Retention sweep failed, see /xllog
+
+
+ Hellion Chat
+
+
+ Privacy filter activated by default. Settings → Privacy to adjust.
+
+
diff --git a/ChatTwo/Ui/SettingsTabs/Privacy.cs b/ChatTwo/Ui/SettingsTabs/Privacy.cs
index 2ae1fd4..c2eefca 100644
--- a/ChatTwo/Ui/SettingsTabs/Privacy.cs
+++ b/ChatTwo/Ui/SettingsTabs/Privacy.cs
@@ -1,5 +1,6 @@
using ChatTwo.Code;
using ChatTwo.Privacy;
+using ChatTwo.Resources;
using ChatTwo.Util;
using Dalamud.Interface.ImGuiNotification;
using Dalamud.Interface.Utility.Raii;
@@ -12,7 +13,7 @@ internal sealed class Privacy : ISettingsTab
private Plugin Plugin { get; }
private Configuration Mutable { get; }
- public string Name => "Privacy###tabs-privacy";
+ public string Name => HellionStrings.Privacy_Tab_Title + "###tabs-privacy";
internal Privacy(Plugin plugin, Configuration mutable)
{
@@ -20,26 +21,27 @@ internal sealed class Privacy : ISettingsTab
Mutable = mutable;
}
- // Channels grouped for the UI. Order = display order.
- private static readonly (string Heading, ChatType[] Types)[] Groups =
+ // (HeadingKey lookup, ChatType list). Heading is resolved per-frame so
+ // a runtime LanguageChanged call updates the labels immediately.
+ private static readonly (Func Heading, ChatType[] Types)[] Groups =
[
- ("Direct Messages", [ChatType.TellIncoming, ChatType.TellOutgoing]),
- ("Party & Alliance", [ChatType.Party, ChatType.CrossParty, ChatType.Alliance, ChatType.PvpTeam]),
- ("Free Company", [ChatType.FreeCompany, ChatType.FreeCompanyAnnouncement, ChatType.FreeCompanyLoginLogout]),
- ("Linkshells", [
+ (() => HellionStrings.Privacy_Group_DirectMessages, [ChatType.TellIncoming, ChatType.TellOutgoing]),
+ (() => HellionStrings.Privacy_Group_PartyAlliance, [ChatType.Party, ChatType.CrossParty, ChatType.Alliance, ChatType.PvpTeam]),
+ (() => HellionStrings.Privacy_Group_FreeCompany, [ChatType.FreeCompany, ChatType.FreeCompanyAnnouncement, ChatType.FreeCompanyLoginLogout]),
+ (() => HellionStrings.Privacy_Group_Linkshells, [
ChatType.Linkshell1, ChatType.Linkshell2, ChatType.Linkshell3, ChatType.Linkshell4,
ChatType.Linkshell5, ChatType.Linkshell6, ChatType.Linkshell7, ChatType.Linkshell8,
]),
- ("Cross-World Linkshells", [
+ (() => HellionStrings.Privacy_Group_CrossLinkshells, [
ChatType.CrossLinkshell1, ChatType.CrossLinkshell2, ChatType.CrossLinkshell3, ChatType.CrossLinkshell4,
ChatType.CrossLinkshell5, ChatType.CrossLinkshell6, ChatType.CrossLinkshell7, ChatType.CrossLinkshell8,
]),
- ("ExtraChat (Encrypted)", [
+ (() => HellionStrings.Privacy_Group_ExtraChat, [
ChatType.ExtraChatLinkshell1, ChatType.ExtraChatLinkshell2, ChatType.ExtraChatLinkshell3, ChatType.ExtraChatLinkshell4,
ChatType.ExtraChatLinkshell5, ChatType.ExtraChatLinkshell6, ChatType.ExtraChatLinkshell7, ChatType.ExtraChatLinkshell8,
]),
- ("Public Chat (third-party data)", [ChatType.Say, ChatType.Shout, ChatType.Yell, ChatType.NoviceNetwork, ChatType.CustomEmote, ChatType.StandardEmote]),
- ("System & Game Logs", [
+ (() => HellionStrings.Privacy_Group_PublicChat, [ChatType.Say, ChatType.Shout, ChatType.Yell, ChatType.NoviceNetwork, ChatType.CustomEmote, ChatType.StandardEmote]),
+ (() => HellionStrings.Privacy_Group_SystemLogs, [
ChatType.System, ChatType.Notice, ChatType.Urgent, ChatType.Echo,
ChatType.NpcDialogue, ChatType.NpcAnnouncement,
ChatType.LootNotice, ChatType.LootRoll, ChatType.RetainerSale,
@@ -47,9 +49,6 @@ internal sealed class Privacy : ISettingsTab
]),
];
- // Cleanup preview state. Held in the tab so the user can refresh and
- // inspect before confirming. Resets when the tab is reopened (acceptable —
- // a stale preview against a freshly-edited whitelist would be misleading).
private Dictionary? CleanupCounts;
private long CleanupKeepCount;
private long CleanupDeleteCount;
@@ -61,9 +60,8 @@ internal sealed class Privacy : ISettingsTab
{
ImGuiUtil.OptionCheckbox(
ref Mutable.PrivacyFilterEnabled,
- "Enable privacy filter",
- "When enabled, only messages from whitelisted channels are persisted to the database. " +
- "Disabling restores upstream ChatTwo behavior (everything except battle messages is stored).");
+ HellionStrings.Privacy_FilterEnabled_Name,
+ HellionStrings.Privacy_FilterEnabled_Description);
ImGui.Spacing();
ImGui.Separator();
@@ -71,22 +69,19 @@ internal sealed class Privacy : ISettingsTab
using (ImRaii.Disabled(!Mutable.PrivacyFilterEnabled))
{
- ImGuiUtil.HelpText(
- "Pick which channels are stored in the local database. " +
- "Privacy-First default: only your own conversations. " +
- "Use the buttons below to apply a preset.");
+ ImGuiUtil.HelpText(HellionStrings.Privacy_Whitelist_Help);
ImGui.Spacing();
- if (ImGui.Button("Privacy-First (recommended)"))
+ if (ImGui.Button(HellionStrings.Privacy_Preset_PrivacyFirst))
Mutable.PrivacyPersistChannels = [..PrivacyDefaults.PrivacyFirstWhitelist];
ImGui.SameLine();
- if (ImGui.Button("Clear all"))
+ if (ImGui.Button(HellionStrings.Privacy_Preset_ClearAll))
Mutable.PrivacyPersistChannels.Clear();
ImGui.SameLine();
- if (ImGui.Button("Select all"))
+ if (ImGui.Button(HellionStrings.Privacy_Preset_SelectAll))
foreach (var group in Groups)
foreach (var t in group.Types)
Mutable.PrivacyPersistChannels.Add(t);
@@ -97,7 +92,7 @@ internal sealed class Privacy : ISettingsTab
foreach (var (heading, types) in Groups)
{
- using var tree = ImRaii.TreeNode(heading);
+ using var tree = ImRaii.TreeNode(heading());
if (!tree.Success)
continue;
@@ -124,9 +119,8 @@ internal sealed class Privacy : ISettingsTab
ImGuiUtil.OptionCheckbox(
ref Mutable.PrivacyPersistUnknownChannels,
- "Persist unknown channel types",
- "Failsafe for ChatTypes added by future FFXIV patches that this plugin does not yet know about. " +
- "Default OFF (Privacy-First). Turn ON if you want a complete log including future channels.");
+ HellionStrings.Privacy_PersistUnknown_Name,
+ HellionStrings.Privacy_PersistUnknown_Description);
}
ImGui.Spacing();
@@ -144,45 +138,44 @@ internal sealed class Privacy : ISettingsTab
private void DrawRetentionSection()
{
- ImGui.TextUnformatted("Message retention");
+ ImGui.TextUnformatted(HellionStrings.Retention_Heading);
using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false))
{
ImGuiUtil.OptionCheckbox(
ref Mutable.RetentionEnabled,
- "Auto-delete messages after a per-channel retention window",
- "When enabled, messages older than the configured window are deleted on every plugin start (at most once per 24 hours). " +
- "Off by default — the plugin never deletes history without your explicit consent.");
+ HellionStrings.Retention_Enabled_Name,
+ HellionStrings.Retention_Enabled_Description);
using (ImRaii.Disabled(!Mutable.RetentionEnabled))
{
ImGui.Spacing();
var defaultDays = Mutable.RetentionDefaultDays;
- if (ImGui.InputInt("Default retention (days, 0 = never)", ref defaultDays))
+ if (ImGui.InputInt(HellionStrings.Retention_Default_Label, ref defaultDays))
Mutable.RetentionDefaultDays = Math.Max(0, defaultDays);
- ImGuiUtil.HelpText("Applies to channels without an explicit override below.");
+ ImGuiUtil.HelpText(HellionStrings.Retention_Default_Help);
ImGui.Spacing();
- if (ImGui.Button("Reset overrides to spec defaults"))
+ if (ImGui.Button(HellionStrings.Retention_Reset_Spec))
{
Mutable.RetentionPerChannelDays =
PrivacyDefaults.DefaultRetentionDays.ToDictionary(p => p.Key, p => p.Value);
}
ImGui.SameLine();
- if (ImGui.Button("Clear all overrides"))
+ if (ImGui.Button(HellionStrings.Retention_Clear_Overrides))
Mutable.RetentionPerChannelDays.Clear();
ImGui.Spacing();
- using (var tree = ImRaii.TreeNode("Per-channel retention overrides"))
+ using (var tree = ImRaii.TreeNode(HellionStrings.Retention_Tree_Heading))
{
if (tree.Success)
{
using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false))
foreach (var (heading, types) in Groups)
{
- using var subTree = ImRaii.TreeNode(heading);
+ using var subTree = ImRaii.TreeNode(heading());
if (!subTree.Success)
continue;
@@ -195,10 +188,10 @@ internal sealed class Privacy : ISettingsTab
days = hasSpecDefault ? specDays : Mutable.RetentionDefaultDays;
var tag = hasOverride
- ? "[override]"
+ ? HellionStrings.Retention_Tag_Override
: hasSpecDefault
- ? "[spec]"
- : "[global]";
+ ? HellionStrings.Retention_Tag_Spec
+ : HellionStrings.Retention_Tag_Global;
if (ImGui.InputInt($"{type} {tag}##retention-{(int)type}", ref days))
{
days = Math.Max(0, days);
@@ -208,7 +201,7 @@ internal sealed class Privacy : ISettingsTab
if (hasOverride)
{
ImGui.SameLine();
- if (ImGui.Button($"reset##retention-reset-{(int)type}"))
+ if (ImGui.Button($"{HellionStrings.Retention_Reset_Button}##retention-reset-{(int)type}"))
Mutable.RetentionPerChannelDays.Remove(type);
}
}
@@ -220,19 +213,18 @@ internal sealed class Privacy : ISettingsTab
using (ImRaii.Disabled(RetentionRunning))
{
- if (ImGuiUtil.CtrlShiftButton("Apply retention policy now",
- "Ctrl+Shift: runs the retention sweep immediately using the SAVED policy. Save your changes first."))
+ if (ImGuiUtil.CtrlShiftButton(HellionStrings.Retention_Apply_Label, HellionStrings.Retention_Apply_Tooltip))
StartRetentionRun();
}
if (RetentionRunning)
- ImGuiUtil.HelpText("Retention sweep running in background…");
+ ImGuiUtil.HelpText(HellionStrings.Retention_Running);
ImGui.Spacing();
var lastRun = Plugin.Config.RetentionLastRunAt;
ImGuiUtil.HelpText(lastRun == DateTimeOffset.MinValue
- ? "Last run: never"
- : $"Last run: {lastRun.ToLocalTime():yyyy-MM-dd HH:mm}");
+ ? HellionStrings.Retention_LastRun_Never
+ : string.Format(HellionStrings.Retention_LastRun_At, lastRun.ToLocalTime()));
}
}
}
@@ -265,12 +257,12 @@ internal sealed class Privacy : ISettingsTab
}).Wait();
}
- WrapperUtil.AddNotification($"Retention sweep complete: {deleted:N0} messages removed.", NotificationType.Success);
+ WrapperUtil.AddNotification(string.Format(HellionStrings.Retention_Success, deleted), NotificationType.Success);
}
catch (Exception e)
{
Plugin.Log.Error(e, "Manual retention run failed");
- WrapperUtil.AddNotification("Retention sweep failed, see /xllog", NotificationType.Error);
+ WrapperUtil.AddNotification(HellionStrings.Retention_Error, NotificationType.Error);
}
finally
{
@@ -281,37 +273,32 @@ internal sealed class Privacy : ISettingsTab
private void DrawCleanupSection()
{
- ImGui.TextUnformatted("Apply filter to existing database");
+ ImGui.TextUnformatted(HellionStrings.Cleanup_Heading);
using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false))
{
- ImGuiUtil.HelpText(
- "The privacy filter only applies to new messages. " +
- "Use the cleanup below to retroactively remove already-stored messages " +
- "that don't match your saved whitelist.");
- ImGuiUtil.HelpText(
- "Cleanup uses your SAVED whitelist (Plugin.Config), not unsaved edits above. " +
- "Click Save first if you want to apply your current edits.");
+ ImGuiUtil.HelpText(HellionStrings.Cleanup_Help_Intro);
+ ImGuiUtil.HelpText(HellionStrings.Cleanup_Help_SavedNote);
ImGui.Spacing();
using (ImRaii.Disabled(CleanupRunning))
{
- if (ImGui.Button("Refresh preview"))
+ if (ImGui.Button(HellionStrings.Cleanup_RefreshPreview))
RefreshCleanupPreview();
}
if (CleanupCounts is null)
{
- ImGuiUtil.HelpText("No preview yet. Click Refresh to compute the impact.");
+ ImGuiUtil.HelpText(HellionStrings.Cleanup_NoPreview);
return;
}
ImGui.Spacing();
- ImGuiUtil.HelpText($"Total stored messages: {CleanupKeepCount + CleanupDeleteCount:N0}");
- ImGuiUtil.HelpText($"Will keep: {CleanupKeepCount:N0}");
- ImGuiUtil.HelpText($"Will delete: {CleanupDeleteCount:N0}");
+ ImGuiUtil.HelpText(string.Format(HellionStrings.Cleanup_TotalStored, CleanupKeepCount + CleanupDeleteCount));
+ ImGuiUtil.HelpText(string.Format(HellionStrings.Cleanup_WillKeep, CleanupKeepCount));
+ ImGuiUtil.HelpText(string.Format(HellionStrings.Cleanup_WillDelete, CleanupDeleteCount));
- using (var tree = ImRaii.TreeNode("Per-channel breakdown"))
+ using (var tree = ImRaii.TreeNode(HellionStrings.Cleanup_Breakdown))
{
if (tree.Success)
{
@@ -322,7 +309,7 @@ internal sealed class Privacy : ISettingsTab
? ((ChatType)(ushort)chatType).ToString()
: $"Unknown({chatType})";
var keeps = WouldBeKept(chatType);
- var marker = keeps ? "[KEEP] " : "[DELETE]";
+ var marker = keeps ? HellionStrings.Cleanup_Marker_Keep : HellionStrings.Cleanup_Marker_Delete;
ImGuiUtil.HelpText($"{marker} {name} — {count:N0}");
}
}
@@ -332,13 +319,13 @@ internal sealed class Privacy : ISettingsTab
using (ImRaii.Disabled(CleanupRunning || CleanupDeleteCount == 0))
{
- if (ImGuiUtil.CtrlShiftButton("Apply current filter to database",
- $"Ctrl+Shift: Hard-deletes {CleanupDeleteCount:N0} messages, then runs VACUUM. Cannot be undone."))
+ if (ImGuiUtil.CtrlShiftButton(HellionStrings.Cleanup_Apply_Label,
+ string.Format(HellionStrings.Cleanup_Apply_Tooltip, CleanupDeleteCount)))
StartCleanup();
}
if (CleanupRunning)
- ImGuiUtil.HelpText("Cleanup running in background…");
+ ImGuiUtil.HelpText(HellionStrings.Cleanup_Running);
}
}
@@ -369,7 +356,7 @@ internal sealed class Privacy : ISettingsTab
catch (Exception e)
{
Plugin.Log.Error(e, "Failed to compute cleanup preview");
- WrapperUtil.AddNotification("Failed to compute cleanup preview, see /xllog", NotificationType.Error);
+ WrapperUtil.AddNotification(HellionStrings.Cleanup_PreviewError, NotificationType.Error);
}
}
@@ -394,12 +381,12 @@ internal sealed class Privacy : ISettingsTab
Plugin.MessageManager.FilterAllTabsAsync();
}).Wait();
- WrapperUtil.AddNotification($"Privacy cleanup complete: {deleted:N0} messages removed.", NotificationType.Success);
+ WrapperUtil.AddNotification(string.Format(HellionStrings.Cleanup_Success, deleted), NotificationType.Success);
}
catch (Exception e)
{
Plugin.Log.Error(e, "Privacy cleanup failed");
- WrapperUtil.AddNotification("Privacy cleanup failed, see /xllog", NotificationType.Error);
+ WrapperUtil.AddNotification(HellionStrings.Cleanup_Error, NotificationType.Error);
}
finally
{