feat(i18n): i18n key fields on command + settings contributions (T-462)

Lets manifest labels (command-palette/menu titles, settings labels) localize,
not just displayed widget strings. Adds optional titleKey/i18nNamespace to
CommandContribution and labelKey/helpKey/titleKey + a category i18nNamespace to
the settings schema. The command palette and menu bar now resolve titles via a
shared localizedCommandTitle helper — and the palette's fuzzy search matches
the localized title too (PaletteController.titleResolver). No behaviour change
until the per-extension keys + catalog entries land (placeholder == English).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-19 09:44:35 +02:00
co-authored by Claude Opus 4.8
parent 33a8a74240
commit 198c8b18b5
9 changed files with 91 additions and 11 deletions
+16 -1
View File
@@ -1,9 +1,22 @@
import 'package:clide/extension/src/contribution.dart' show CommandContribution;
import 'package:clide/kernel/kernel.dart';
import 'package:clide/widgets/src/clide_settings.dart';
import 'package:clide/widgets/src/clide_text.dart';
import 'package:clide/widgets/src/typography.dart';
import 'package:flutter/widgets.dart';
/// The localized display title for a command (T-462): resolves [titleKey] in
/// [i18nNamespace] when both are set, else the English title (then id). Shared
/// by the command palette and the menu bar so both localize identically.
String localizedCommandTitle(BuildContext context, CommandContribution cmd) {
final k = cmd.titleKey;
final ns = cmd.i18nNamespace;
if (k != null && ns != null) {
return ClideSettings.i18n.string(context, k, namespace: ns, placeholder: cmd.title ?? cmd.command);
}
return cmd.title ?? cmd.command;
}
class ClidePalette extends StatefulWidget {
const ClidePalette({super.key});
@@ -109,6 +122,8 @@ class _ClidePaletteState extends State<ClidePalette> {
listenable: kernel.palette,
builder: (ctx, _) {
if (!kernel.palette.isOpen) return const SizedBox.shrink();
// Localize titles for both the fuzzy filter and the rendered rows (T-462).
kernel.palette.titleResolver = (cmd) => localizedCommandTitle(ctx, cmd);
final filtered = kernel.palette.filtered();
final selected = kernel.palette.selectedIndex;
return Positioned(
@@ -164,7 +179,7 @@ class _ClidePaletteState extends State<ClidePalette> {
final key = _itemKeys.putIfAbsent(i, () => GlobalKey());
return _PaletteItem(
key: key,
title: cmd.title ?? cmd.command,
title: localizedCommandTitle(ctx, cmd),
command: cmd.command,
binding: cmd.defaultBinding,
highlighted: i == selected,