feat(i18n): load every extension's own namespace + facade lookup (T-462)
Foundation for routing hardcoded UI labels through the catalog (D-21). Two enablers: - ExtensionManager now eagerly loads each activated extension's own-id catalog namespace, not just the namespaces of localized tabs. An extension's id IS its catalog namespace (ClideExtension.t), so labels resolve through the catalog even for extensions that contribute no tab; a missing catalog file loads as an empty map, so it's harmless. - ClideSettings.i18n gains string()/interpolated() lookups so widget call sites route through the one D-101 facade (like theme/fonts) instead of each re-deriving ClideKernel.of(context).i18n. No user-visible change yet — placeholders equal the en_US catalog values; the per-extension label migrations follow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -162,11 +162,14 @@ class ExtensionManager extends ChangeNotifier {
|
||||
_applyContribution(c);
|
||||
applied.add(c);
|
||||
}
|
||||
// Eagerly load the i18n catalog for any localized tab this extension
|
||||
// contributes, so its title resolves without a "namespace not
|
||||
// registered" warning — and without the namespace having to be listed
|
||||
// by hand at boot (T-155).
|
||||
// Eagerly load the i18n catalogs this extension needs so its labels
|
||||
// resolve through the catalog (D-21) instead of falling back to inline
|
||||
// English placeholders — without listing namespaces by hand at boot
|
||||
// (T-155, T-462). An extension's own id IS its catalog namespace (see
|
||||
// [ClideExtension.t]); a missing catalog file loads as an empty map, so
|
||||
// this is harmless for extensions that ship none.
|
||||
for (final ns in {
|
||||
id,
|
||||
for (final c in ext.contributions)
|
||||
if (c is TabContribution && c.i18nNamespace != null) c.i18nNamespace!,
|
||||
}) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:clide/kernel/src/facade.dart' show ClideKernel;
|
||||
import 'package:clide/kernel/src/i18n/i18n.dart' show I18n;
|
||||
import 'package:clide/kernel/src/i18n/i18n.dart' show I18n, I18nReplacer;
|
||||
import 'package:clide/kernel/src/theme/controller.dart' show ClideTheme, ClideThemeData;
|
||||
import 'package:clide/widgets/src/typography.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@@ -45,6 +45,16 @@ class _I18n {
|
||||
|
||||
/// The i18n service for [context] — delegates to the kernel `I18n` service.
|
||||
I18n of(BuildContext context) => ClideKernel.of(context).i18n;
|
||||
|
||||
/// Resolve a catalog string through the live i18n service (D-21) — the
|
||||
/// uniform widget-facing lookup (T-462). [placeholder] is the inline English
|
||||
/// fallback rendered until/unless the catalog covers the key.
|
||||
String string(BuildContext context, String key, {required String namespace, String? placeholder}) =>
|
||||
of(context).string(key, namespace: namespace, placeholder: placeholder);
|
||||
|
||||
/// [string] with `replaceAll` interpolation per replacer (templated labels).
|
||||
String interpolated(BuildContext context, String key, {required String namespace, String? placeholder, List<I18nReplacer> replacers = const []}) =>
|
||||
of(context).interpolated(key, namespace: namespace, placeholder: placeholder, replacers: replacers);
|
||||
}
|
||||
|
||||
/// Root-provided InheritedWidget carrying the live font families (D-101). The
|
||||
|
||||
Reference in New Issue
Block a user