diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f967e608..76b0c78a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -49,7 +49,7 @@ jobs:
uses: actions/checkout@v7
- name: Setup .NET 10
- uses: actions/setup-dotnet@v5
+ uses: actions/setup-dotnet@v6
with:
dotnet-version: '10.0.x'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 56aff85c..0b59e591 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,18 @@
All notable changes to Chromatics are documented here.
+## 4.3.31
+
+- Added support for FFXIV patch 7.55.
+- Lighting no longer stops for the rest of the session when a single game-data read fails. Chromatics now retries, and reconnects to the game if the failures persist.
+
+## 4.3.29
+
+- Added a Black layer type, available as both a base layer and a dynamic layer.
+- Layers saved for a disabled or disconnected device can now be copied to another device.
+- New setting under Settings → General: lower the RGB refresh rate while FFXIV is not running. With the setting off, your configured refresh rate now applies in every state.
+- Fixed the update prompt showing the newest version's heading twice in its changelog.
+
## 4.3.24
- **New:** Nanoleaf smart-light support (Beta). Covers the panel family (Shapes, Canvas, Elements, Lines, Aurora) and other controllers that speak the Nanoleaf OpenAPI. Enable it from Settings → Device Providers and pair each controller with a one-time button press; effects render across the panels at their real physical positions. Layer assignments stay with their panels if you add or remove panels from the wall later. Essentials bulbs and strips are not supported.
diff --git a/Chromatics.Tests/Chromatics.Tests.csproj b/Chromatics.Tests/Chromatics.Tests.csproj
index 9cff5172..53d68223 100644
--- a/Chromatics.Tests/Chromatics.Tests.csproj
+++ b/Chromatics.Tests/Chromatics.Tests.csproj
@@ -38,7 +38,7 @@
-
+
diff --git a/Chromatics.Tests/Helpers/LayerCopierTests.cs b/Chromatics.Tests/Helpers/LayerCopierTests.cs
new file mode 100644
index 00000000..d881113a
--- /dev/null
+++ b/Chromatics.Tests/Helpers/LayerCopierTests.cs
@@ -0,0 +1,80 @@
+using Chromatics.Helpers;
+using RGB.NET.Core;
+
+namespace Chromatics.Tests.Helpers;
+
+// Pins the default LedId mapping used when copying layers from a device
+// that is disabled or no longer connected: the layer's own LedId set
+// stands in for the missing device, so these rules decide where each key
+// lands on the destination before the user touches the override dropdowns.
+public class LayerCopierTests
+{
+ [Fact]
+ public void KeyboardPair_MapsIdentity_OnlyWhereDestinationHasTheKey()
+ {
+ var used = new[] { LedId.Keyboard_A, LedId.Keyboard_B, LedId.Keyboard_NumLock };
+ var destIds = new List { LedId.Keyboard_A, LedId.Keyboard_B }; // no numpad
+
+ var map = LayerCopier.ComputeDefaultMappingForLayer(
+ used, RGBDeviceType.Keyboard, RGBDeviceType.Keyboard, destIds);
+
+ Assert.Equal(LedId.Keyboard_A, map[LedId.Keyboard_A]);
+ Assert.Equal(LedId.Keyboard_B, map[LedId.Keyboard_B]);
+ // Keyboard pairs never fall back positionally: a missing key is
+ // dropped so it can't land on an unrelated physical key.
+ Assert.False(map.ContainsKey(LedId.Keyboard_NumLock));
+ }
+
+ [Fact]
+ public void NonKeyboard_ExactIdMatchWins()
+ {
+ var used = new[] { LedId.Custom1, LedId.Custom2 };
+ var destIds = new List { LedId.Custom1, LedId.Custom2, LedId.Custom3 };
+
+ var map = LayerCopier.ComputeDefaultMappingForLayer(
+ used, RGBDeviceType.LedStripe, RGBDeviceType.LedStripe, destIds);
+
+ Assert.Equal(LedId.Custom1, map[LedId.Custom1]);
+ Assert.Equal(LedId.Custom2, map[LedId.Custom2]);
+ }
+
+ [Fact]
+ public void NonKeyboard_OrdinalFallback_WhenIdsDoNotOverlap()
+ {
+ // Source painted Custom5..Custom7; destination only has Custom1..Custom3.
+ var used = new[] { LedId.Custom5, LedId.Custom6, LedId.Custom7 };
+ var destIds = new List { LedId.Custom1, LedId.Custom2, LedId.Custom3 };
+
+ var map = LayerCopier.ComputeDefaultMappingForLayer(
+ used, RGBDeviceType.LedStripe, RGBDeviceType.Mouse, destIds);
+
+ Assert.Equal(LedId.Custom1, map[LedId.Custom5]);
+ Assert.Equal(LedId.Custom2, map[LedId.Custom6]);
+ Assert.Equal(LedId.Custom3, map[LedId.Custom7]);
+ }
+
+ [Fact]
+ public void NonKeyboard_SourceLargerThanDestination_DropsTheTail()
+ {
+ var used = new[] { LedId.Custom5, LedId.Custom6, LedId.Custom7 };
+ var destIds = new List { LedId.Custom1 };
+
+ var map = LayerCopier.ComputeDefaultMappingForLayer(
+ used, RGBDeviceType.LedStripe, RGBDeviceType.LedStripe, destIds);
+
+ Assert.Equal(LedId.Custom1, map[LedId.Custom5]);
+ Assert.False(map.ContainsKey(LedId.Custom6));
+ Assert.False(map.ContainsKey(LedId.Custom7));
+ }
+
+ [Fact]
+ public void EmptyOrMissingInputs_ReturnEmptyMap()
+ {
+ Assert.Empty(LayerCopier.ComputeDefaultMappingForLayer(
+ Array.Empty(), RGBDeviceType.Keyboard, RGBDeviceType.Keyboard, new List { LedId.Keyboard_A }));
+ Assert.Empty(LayerCopier.ComputeDefaultMappingForLayer(
+ null, RGBDeviceType.Keyboard, RGBDeviceType.Keyboard, new List()));
+ Assert.Empty(LayerCopier.ComputeDefaultMappingForLayer(
+ new[] { LedId.Keyboard_A }, RGBDeviceType.Keyboard, RGBDeviceType.Keyboard, null));
+ }
+}
diff --git a/Chromatics.Tests/Helpers/UpdateNotesTests.cs b/Chromatics.Tests/Helpers/UpdateNotesTests.cs
new file mode 100644
index 00000000..f370b39b
--- /dev/null
+++ b/Chromatics.Tests/Helpers/UpdateNotesTests.cs
@@ -0,0 +1,100 @@
+using Chromatics.Helpers;
+
+namespace Chromatics.Tests.Helpers;
+
+// Pins the release-notes trimming behind the update dialog. Notes embedded
+// by older publishes start with their own version heading and carry every
+// older changelog section; the dialog adds its own heading per release, so
+// rendering them raw doubled the version line and repeated old sections.
+public class UpdateNotesTests
+{
+ [Fact]
+ public void OldFormatNotes_ReduceToOwnBullets()
+ {
+ var notes = "## 4.3.26\n\n- New feature one.\n- Fix two.\n\n## 4.3.24\n\n- Old bullet.\n";
+
+ var trimmed = UpdateService.TrimNotesToOwnSection(notes, "4.3.26");
+
+ Assert.Equal("- New feature one.\n- Fix two.", trimmed.Replace("\r\n", "\n"));
+ }
+
+ [Fact]
+ public void NewFormatNotes_BulletsOnly_PassThroughUnchanged()
+ {
+ var notes = "- New feature one.\n- Fix two.";
+
+ var trimmed = UpdateService.TrimNotesToOwnSection(notes, "4.3.26");
+
+ Assert.Equal(notes, trimmed.Replace("\r\n", "\n"));
+ }
+
+ [Theory]
+ [InlineData("## 4.3.26.0\n\n- Bullet.")]
+ [InlineData("## [4.3.26]\n\n- Bullet.")]
+ [InlineData("## v4.3.26\n\n- Bullet.")]
+ [InlineData("## 4.3.26 - 2026-07-07\n\n- Bullet.")]
+ public void HeadingVariants_AreAllStripped(string notes)
+ {
+ var trimmed = UpdateService.TrimNotesToOwnSection(notes, "4.3.26");
+
+ Assert.Equal("- Bullet.", trimmed);
+ }
+
+ [Fact]
+ public void DifferentVersionHeading_IsNotStripped_ButLaterSectionsAreCut()
+ {
+ // A mislabelled asset should not lose its first line; only the
+ // trailing sections get cut.
+ var notes = "- Bullet without heading.\n\n## 4.3.20\n\n- Old.";
+
+ var trimmed = UpdateService.TrimNotesToOwnSection(notes, "4.3.26");
+
+ Assert.Equal("- Bullet without heading.", trimmed.Replace("\r\n", "\n"));
+ }
+
+ [Fact]
+ public void EmptyOrWhitespaceNotes_ReturnEmpty()
+ {
+ Assert.Equal(string.Empty, UpdateService.TrimNotesToOwnSection("", "4.3.26"));
+ Assert.Equal(string.Empty, UpdateService.TrimNotesToOwnSection(" ", "4.3.26"));
+ Assert.Equal(string.Empty, UpdateService.TrimNotesToOwnSection(null, "4.3.26"));
+ }
+
+ [Fact]
+ public void VersionPrefix_DoesNotStripALongerVersionsHeading()
+ {
+ // "4.3.2" is a numeric prefix of "4.3.26" - the heading must
+ // survive so another release's bullets are never adopted.
+ var notes = "## 4.3.26\n\n- Bullet from 4.3.26.";
+
+ var trimmed = UpdateService.TrimNotesToOwnSection(notes, "4.3.2");
+
+ Assert.StartsWith("## 4.3.26", trimmed);
+ Assert.Contains("- Bullet from 4.3.26.", trimmed);
+ }
+
+ [Fact]
+ public void WrongLeadingHeading_KeepsItsSection_InsteadOfWipingToEmpty()
+ {
+ // A mislabelled feed asset: the heading names a different version.
+ // The entry must keep that heading and its bullets; only sections
+ // after it get cut.
+ var notes = "## 4.3.30\n\n- Bullet A.\n\n## 4.3.29\n\n- Bullet B.";
+
+ var trimmed = UpdateService.TrimNotesToOwnSection(notes, "4.3.29");
+
+ Assert.StartsWith("## 4.3.30", trimmed.Replace("\r\n", "\n"));
+ Assert.Contains("- Bullet A.", trimmed);
+ Assert.DoesNotContain("- Bullet B.", trimmed);
+ }
+
+ [Fact]
+ public void LeadingHorizontalRule_IsStripped()
+ {
+ var notes = "---\n\n- Bullet.";
+
+ var trimmed = UpdateService.TrimNotesToOwnSection(notes, "4.3.26");
+
+ Assert.Equal("- Bullet.", trimmed);
+ }
+}
diff --git a/Chromatics/Chromatics.csproj b/Chromatics/Chromatics.csproj
index 16e67a91..7e22007b 100644
--- a/Chromatics/Chromatics.csproj
+++ b/Chromatics/Chromatics.csproj
@@ -10,7 +10,7 @@
net10.0-windows10.0.19041.010.0.17763.0Chromatics.Program
- 4.3.24.0
+ 4.3.31.0Danielle Thompson
-
+
+
+
+
@@ -48,7 +56,7 @@
diff --git a/Chromatics/Views/Dialogs/UpdateDialog.axaml.cs b/Chromatics/Views/Dialogs/UpdateDialog.axaml.cs
index 476155fc..b16352e9 100644
--- a/Chromatics/Views/Dialogs/UpdateDialog.axaml.cs
+++ b/Chromatics/Views/Dialogs/UpdateDialog.axaml.cs
@@ -69,12 +69,20 @@ void AddIfNotes(Velopack.SemanticVersion? v, string? notes)
var sb = new StringBuilder();
for (int i = 0; i < versions.Count; i++)
{
- if (i > 0) sb.AppendLine().AppendLine("---").AppendLine();
+ // TrimNotesToOwnSection keeps each entry to its own bullets:
+ // notes from older publishes carry their own version heading
+ // plus every older section, which doubled the version line
+ // and repeated content across entries.
+ var body = UpdateService.TrimNotesToOwnSection(
+ versions[i].Notes, versions[i].Version.ToString());
+ if (string.IsNullOrWhiteSpace(body)) continue;
+
+ if (sb.Length > 0) sb.AppendLine().AppendLine("---").AppendLine();
sb.Append("## ").AppendLine(versions[i].Version.ToString());
sb.AppendLine();
- sb.AppendLine(versions[i].Notes.Trim());
+ sb.AppendLine(body);
}
- return sb.ToString();
+ return sb.Length > 0 ? sb.ToString() : "(No release notes provided.)";
}
private async void OnInstall(object sender, RoutedEventArgs e)
diff --git a/Chromatics/Views/NanoleafAdoptionDialog.axaml b/Chromatics/Views/NanoleafAdoptionDialog.axaml
index 2ec6afef..30bb2c54 100644
--- a/Chromatics/Views/NanoleafAdoptionDialog.axaml
+++ b/Chromatics/Views/NanoleafAdoptionDialog.axaml
@@ -70,7 +70,7 @@
+
diff --git a/Chromatics/locale/de.json b/Chromatics/locale/de.json
index fff64880..b45f50d9 100644
--- a/Chromatics/locale/de.json
+++ b/Chromatics/locale/de.json
@@ -1001,5 +1001,15 @@
"[BETA] Enable/disable Nanoleaf smart-light support. Pairs Nanoleaf controllers (Shapes, Canvas, Elements, Lines, Aurora) over your LAN - each controller needs a one-time button-press pairing. Essentials bulbs and strips are not supported. Default: Disabled": "[BETA] Nanoleaf-Smart-Light-Unterstützung aktivieren/deaktivieren. Koppelt Nanoleaf-Controller (Shapes, Canvas, Elements, Lines, Aurora) über Ihr LAN – jeder Controller erfordert eine einmalige Kopplung per Tastendruck. Essentials-Lampen und -Lightstrips werden nicht unterstützt. Standard: Deaktiviert",
"Pairing failed. Try again.": "Kopplung fehlgeschlagen. Versuchen Sie es erneut.",
"Pair": "Koppeln",
- "Remove": "Entfernen"
+ "Remove": "Entfernen",
+ "Lower the RGB refresh rate while FFXIV is not running.": "Die RGB-Aktualisierungsrate verringern, während FFXIV nicht läuft.",
+ "The configured refresh rate resumes when Chromatics attaches to FFXIV. Default: Enabled": "Die konfigurierte Aktualisierungsrate wird wiederhergestellt, wenn Chromatics sich mit FFXIV verbindet. Standard: Aktiviert",
+ "Hide devices that are disabled or not connected.": "Geräte ausblenden, die deaktiviert oder nicht verbunden sind.",
+ "not connected": "nicht verbunden",
+ "disabled": "deaktiviert",
+ "This device is not connected. Its saved layers can still be copied.": "Dieses Gerät ist nicht verbunden. Seine gespeicherten Ebenen können weiterhin kopiert werden.",
+ "This device is disabled on the Mappings tab. Its saved layers can still be copied.": "Dieses Gerät ist auf der Registerkarte „Zuordnungen“ deaktiviert. Seine gespeicherten Ebenen können weiterhin kopiert werden.",
+ "Black": "Schwarz",
+ "Sets the entire base layer to black. Keys stay dark unless a higher layer paints over them.": "Setzt die gesamte Basisebene auf Schwarz. Tasten bleiben dunkel, sofern sie nicht von einer höheren Ebene übermalt werden.",
+ "Sets the selected keys to black.": "Setzt die ausgewählten Tasten auf Schwarz."
}
\ No newline at end of file
diff --git a/Chromatics/locale/en.json b/Chromatics/locale/en.json
index b1dfab5b..62cdff5a 100644
--- a/Chromatics/locale/en.json
+++ b/Chromatics/locale/en.json
@@ -1016,5 +1016,15 @@
"Remove": "Remove",
"Paired - {0} panels": "Paired - {0} panels",
"Nanoleaf (Beta)": "Nanoleaf (Beta)",
- "[BETA] Enable/disable Nanoleaf smart-light support. Pairs Nanoleaf controllers (Shapes, Canvas, Elements, Lines, Aurora) over your LAN - each controller needs a one-time button-press pairing. Essentials bulbs and strips are not supported. Default: Disabled": "[BETA] Enable/disable Nanoleaf smart-light support. Pairs Nanoleaf controllers (Shapes, Canvas, Elements, Lines, Aurora) over your LAN - each controller needs a one-time button-press pairing. Essentials bulbs and strips are not supported. Default: Disabled"
+ "[BETA] Enable/disable Nanoleaf smart-light support. Pairs Nanoleaf controllers (Shapes, Canvas, Elements, Lines, Aurora) over your LAN - each controller needs a one-time button-press pairing. Essentials bulbs and strips are not supported. Default: Disabled": "[BETA] Enable/disable Nanoleaf smart-light support. Pairs Nanoleaf controllers (Shapes, Canvas, Elements, Lines, Aurora) over your LAN - each controller needs a one-time button-press pairing. Essentials bulbs and strips are not supported. Default: Disabled",
+ "Lower the RGB refresh rate while FFXIV is not running.": "Lower the RGB refresh rate while FFXIV is not running.",
+ "The configured refresh rate resumes when Chromatics attaches to FFXIV. Default: Enabled": "The configured refresh rate resumes when Chromatics attaches to FFXIV. Default: Enabled",
+ "Hide devices that are disabled or not connected.": "Hide devices that are disabled or not connected.",
+ "not connected": "not connected",
+ "disabled": "disabled",
+ "This device is not connected. Its saved layers can still be copied.": "This device is not connected. Its saved layers can still be copied.",
+ "This device is disabled on the Mappings tab. Its saved layers can still be copied.": "This device is disabled on the Mappings tab. Its saved layers can still be copied.",
+ "Black": "Black",
+ "Sets the entire base layer to black. Keys stay dark unless a higher layer paints over them.": "Sets the entire base layer to black. Keys stay dark unless a higher layer paints over them.",
+ "Sets the selected keys to black.": "Sets the selected keys to black."
}
\ No newline at end of file
diff --git a/Chromatics/locale/es.json b/Chromatics/locale/es.json
index 1950bf28..e02792a6 100644
--- a/Chromatics/locale/es.json
+++ b/Chromatics/locale/es.json
@@ -1000,6 +1000,16 @@
"Nanoleaf (Beta)": "Nanoleaf (Beta)",
"[BETA] Enable/disable Nanoleaf smart-light support. Pairs Nanoleaf controllers (Shapes, Canvas, Elements, Lines, Aurora) over your LAN - each controller needs a one-time button-press pairing. Essentials bulbs and strips are not supported. Default: Disabled": "[BETA] Activa o desactiva la compatibilidad con luces inteligentes Nanoleaf. Empareja controladores Nanoleaf (Shapes, Canvas, Elements, Lines, Aurora) a través de tu red LAN; cada controlador requiere emparejarse una sola vez pulsando un botón. Las bombillas y tiras Essentials no son compatibles. Valor predeterminado: desactivado",
"Pairing failed. Try again.": "No se pudo emparejar. Inténtalo de nuevo.",
- "Pair": "Par",
- "Remove": "Eliminar"
+ "Pair": "Emparejar",
+ "Remove": "Eliminar",
+ "Lower the RGB refresh rate while FFXIV is not running.": "Reduce la frecuencia de actualización RGB mientras FFXIV no se esté ejecutando.",
+ "The configured refresh rate resumes when Chromatics attaches to FFXIV. Default: Enabled": "La frecuencia de actualización configurada se reanuda cuando Chromatics se conecta a FFXIV. Predeterminado: activado",
+ "Hide devices that are disabled or not connected.": "Oculta los dispositivos que estén desactivados o no conectados.",
+ "not connected": "no conectado",
+ "disabled": "desactivado",
+ "This device is not connected. Its saved layers can still be copied.": "Este dispositivo no está conectado. Sus capas guardadas aún se pueden copiar.",
+ "This device is disabled on the Mappings tab. Its saved layers can still be copied.": "Este dispositivo está desactivado en la pestaña Asignaciones. Sus capas guardadas aún se pueden copiar.",
+ "Black": "Negro",
+ "Sets the entire base layer to black. Keys stay dark unless a higher layer paints over them.": "Establece toda la capa base en negro. Las teclas permanecen oscuras a menos que una capa superior pinte sobre ellas.",
+ "Sets the selected keys to black.": "Establece las teclas seleccionadas en negro."
}
\ No newline at end of file
diff --git a/Chromatics/locale/fr.json b/Chromatics/locale/fr.json
index edf37dab..82d0ac40 100644
--- a/Chromatics/locale/fr.json
+++ b/Chromatics/locale/fr.json
@@ -1000,6 +1000,16 @@
"Nanoleaf (Beta)": "Nanoleaf (bêta)",
"[BETA] Enable/disable Nanoleaf smart-light support. Pairs Nanoleaf controllers (Shapes, Canvas, Elements, Lines, Aurora) over your LAN - each controller needs a one-time button-press pairing. Essentials bulbs and strips are not supported. Default: Disabled": "[BÊTA] Active/désactive la prise en charge des éclairages connectés Nanoleaf. Associe les contrôleurs Nanoleaf (Shapes, Canvas, Elements, Lines, Aurora) via votre réseau local ; chaque contrôleur nécessite une association unique par pression sur un bouton. Les ampoules et rubans Essentials ne sont pas pris en charge. Valeur par défaut : désactivé",
"Pairing failed. Try again.": "Échec de l’appairage. Réessayez.",
- "Pair": "Paire",
- "Remove": "Supprimer"
+ "Pair": "Appairer",
+ "Remove": "Supprimer",
+ "Lower the RGB refresh rate while FFXIV is not running.": "Réduire le taux de rafraîchissement RVB lorsque FFXIV n’est pas en cours d’exécution.",
+ "The configured refresh rate resumes when Chromatics attaches to FFXIV. Default: Enabled": "Le taux de rafraîchissement configuré reprend lorsque Chromatics se connecte à FFXIV. Par défaut : activé",
+ "Hide devices that are disabled or not connected.": "Masquer les périphériques désactivés ou non connectés.",
+ "not connected": "non connecté",
+ "disabled": "désactivé",
+ "This device is not connected. Its saved layers can still be copied.": "Ce périphérique n’est pas connecté. Ses calques enregistrés peuvent toujours être copiés.",
+ "This device is disabled on the Mappings tab. Its saved layers can still be copied.": "Ce périphérique est désactivé dans l’onglet Mappages. Ses calques enregistrés peuvent toujours être copiés.",
+ "Black": "Noir",
+ "Sets the entire base layer to black. Keys stay dark unless a higher layer paints over them.": "Définit toute la couche de base en noir. Les touches restent sombres sauf si une couche supérieure les recouvre.",
+ "Sets the selected keys to black.": "Définit les touches sélectionnées en noir."
}
\ No newline at end of file
diff --git a/Chromatics/locale/ja.json b/Chromatics/locale/ja.json
index 7fd05e93..b947edcf 100644
--- a/Chromatics/locale/ja.json
+++ b/Chromatics/locale/ja.json
@@ -1001,6 +1001,16 @@
"Nanoleaf (Beta)": "Nanoleaf(ベータ)",
"[BETA] Enable/disable Nanoleaf smart-light support. Pairs Nanoleaf controllers (Shapes, Canvas, Elements, Lines, Aurora) over your LAN - each controller needs a one-time button-press pairing. Essentials bulbs and strips are not supported. Default: Disabled": "[ベータ] Nanoleaf スマートライトのサポートを有効/無効にします。LAN 経由で Nanoleaf コントローラー(Shapes、Canvas、Elements、Lines、Aurora)をペアリングします。各コントローラーでは初回のみボタン押下によるペアリングが必要です。Essentials の電球およびライトストリップには対応していません。デフォルト: 無効",
"Pairing failed. Try again.": "ペアリングに失敗しました。もう一度お試しください。",
- "Pair": "ペア",
- "Remove": "削除"
+ "Pair": "ペアリング",
+ "Remove": "削除",
+ "Lower the RGB refresh rate while FFXIV is not running.": "FFXIVが実行されていない間、RGBのリフレッシュレートを下げます。",
+ "The configured refresh rate resumes when Chromatics attaches to FFXIV. Default: Enabled": "ChromaticsがFFXIVに接続すると、設定されたリフレッシュレートに戻ります。デフォルト:有効",
+ "Hide devices that are disabled or not connected.": "無効化されている、または接続されていないデバイスを非表示にします。",
+ "not connected": "未接続",
+ "disabled": "無効",
+ "This device is not connected. Its saved layers can still be copied.": "このデバイスは接続されていません。保存済みのレイヤーは引き続きコピーできます。",
+ "This device is disabled on the Mappings tab. Its saved layers can still be copied.": "このデバイスは「マッピング」タブで無効化されています。保存済みのレイヤーは引き続きコピーできます。",
+ "Black": "黒",
+ "Sets the entire base layer to black. Keys stay dark unless a higher layer paints over them.": "ベースレイヤー全体を黒に設定します。上位のレイヤーで上書きされない限り、キーは暗いままになります。",
+ "Sets the selected keys to black.": "選択したキーを黒に設定します。"
}
\ No newline at end of file
diff --git a/Chromatics/locale/ko.json b/Chromatics/locale/ko.json
index a1062640..6ddadec0 100644
--- a/Chromatics/locale/ko.json
+++ b/Chromatics/locale/ko.json
@@ -1002,5 +1002,15 @@
"[BETA] Enable/disable Nanoleaf smart-light support. Pairs Nanoleaf controllers (Shapes, Canvas, Elements, Lines, Aurora) over your LAN - each controller needs a one-time button-press pairing. Essentials bulbs and strips are not supported. Default: Disabled": "[베타] Nanoleaf 스마트 조명 지원을 활성화/비활성화합니다. LAN을 통해 Nanoleaf 컨트롤러(Shapes, Canvas, Elements, Lines, Aurora)를 페어링합니다. 각 컨트롤러는 한 번의 버튼 누름 페어링이 필요합니다. Essentials 전구 및 스트립은 지원되지 않습니다. 기본값: 비활성화",
"Pairing failed. Try again.": "페어링에 실패했습니다. 다시 시도하세요.",
"Pair": "페어링",
- "Remove": "제거"
+ "Remove": "제거",
+ "Lower the RGB refresh rate while FFXIV is not running.": "FFXIV가 실행 중이 아닐 때 RGB 새로 고침 빈도를 낮춥니다.",
+ "The configured refresh rate resumes when Chromatics attaches to FFXIV. Default: Enabled": "Chromatics가 FFXIV에 연결되면 설정된 새로 고침 빈도로 돌아갑니다. 기본값: 활성화됨",
+ "Hide devices that are disabled or not connected.": "비활성화되었거나 연결되지 않은 장치를 숨깁니다.",
+ "not connected": "연결되지 않음",
+ "disabled": "비활성화됨",
+ "This device is not connected. Its saved layers can still be copied.": "이 장치는 연결되어 있지 않습니다. 저장된 레이어는 계속 복사할 수 있습니다.",
+ "This device is disabled on the Mappings tab. Its saved layers can still be copied.": "이 장치는 매핑 탭에서 비활성화되어 있습니다. 저장된 레이어는 계속 복사할 수 있습니다.",
+ "Black": "검정",
+ "Sets the entire base layer to black. Keys stay dark unless a higher layer paints over them.": "전체 기본 레이어를 검은색으로 설정합니다. 상위 레이어가 그 위에 칠하지 않는 한 키는 어두운 상태로 유지됩니다.",
+ "Sets the selected keys to black.": "선택한 키를 검은색으로 설정합니다."
}
\ No newline at end of file
diff --git a/Chromatics/locale/zh_CN.json b/Chromatics/locale/zh_CN.json
index 5378197d..7d443864 100644
--- a/Chromatics/locale/zh_CN.json
+++ b/Chromatics/locale/zh_CN.json
@@ -1001,5 +1001,15 @@
"[BETA] Enable/disable Nanoleaf smart-light support. Pairs Nanoleaf controllers (Shapes, Canvas, Elements, Lines, Aurora) over your LAN - each controller needs a one-time button-press pairing. Essentials bulbs and strips are not supported. Default: Disabled": "[BETA] 启用/禁用 Nanoleaf 智能灯支持。通过局域网配对 Nanoleaf 控制器(Shapes、Canvas、Elements、Lines、Aurora)——每个控制器都需要一次性按键配对。不支持 Essentials 灯泡和灯带。默认:禁用",
"Pairing failed. Try again.": "配对失败。请重试。",
"Pair": "配对",
- "Remove": "删除"
+ "Remove": "删除",
+ "Lower the RGB refresh rate while FFXIV is not running.": "在 FFXIV 未运行时降低 RGB 刷新率。",
+ "The configured refresh rate resumes when Chromatics attaches to FFXIV. Default: Enabled": "当 Chromatics 连接到 FFXIV 时,将恢复已配置的刷新率。默认:已启用",
+ "Hide devices that are disabled or not connected.": "隐藏已禁用或未连接的设备。",
+ "not connected": "未连接",
+ "disabled": "已禁用",
+ "This device is not connected. Its saved layers can still be copied.": "此设备未连接。仍可复制其已保存的图层。",
+ "This device is disabled on the Mappings tab. Its saved layers can still be copied.": "此设备已在“映射”选项卡中禁用。仍可复制其已保存的图层。",
+ "Black": "黑色",
+ "Sets the entire base layer to black. Keys stay dark unless a higher layer paints over them.": "将整个基础层设置为黑色。除非更高层覆盖绘制,否则按键会保持暗色。",
+ "Sets the selected keys to black.": "将选定的按键设置为黑色。"
}
\ No newline at end of file