auto-load extension i18n catalogs; add the missing tab-title ones

Five builtins (tickets, decisions, git, pql, problems) declared a
localized tab title but shipped no catalog and weren't in the hand-kept
preload list, so each logged "namespace not registered" on boot.
ExtensionManager now loads the i18n namespace of every localized
TabContribution when its extension activates — no manual list edit for a
new tab — and the five missing en_US catalogs are added.

T-155.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-23 16:49:56 +02:00
co-authored by Claude Opus 4.7
parent e5fa6302d3
commit 2fd911d01d
11 changed files with 91 additions and 1 deletions
+2 -1
View File
@@ -18,6 +18,7 @@ class KernelFixture {
static Future<KernelFixture> create({
List<ThemeDefinition>? bundledThemes,
Map<String, Map<Locale, Map<String, Object?>>>? i18nCatalogs,
List<String>? preloadNamespaces,
Locale? initialLocale,
Locale defaultLocale = const Locale('en', 'US'),
}) async {
@@ -29,7 +30,7 @@ class KernelFixture {
appDir: tempDir,
bundledThemes: themes,
i18nLoader: InMemoryCatalogLoader(catalogs),
preloadNamespaces: catalogs.keys.toList(),
preloadNamespaces: preloadNamespaces ?? catalogs.keys.toList(),
defaultLocale: defaultLocale,
initialLocale: initialLocale,
daemonClientFactory: (log, events, _) {
@@ -105,6 +105,48 @@ void main() {
);
});
test('activating an extension auto-loads its localized tab namespace (T-155)', () async {
final local = await KernelFixture.create(
i18nCatalogs: {
'ext.localized': {
const Locale('en', 'US'): {
'tab.title': {'translation': 'Localized'},
},
},
},
preloadNamespaces: const [], // loadable, but not preloaded at boot
);
addTearDown(local.dispose);
// Not registered yet → string() falls back to the placeholder.
expect(
local.services.i18n.string('tab.title', namespace: 'ext.localized', placeholder: 'fallback'),
'fallback',
);
local.services.extensions.register(_Ext(
id: 'ext.localized',
contributions: [
TabContribution(
id: 'ext.localized.view',
slot: Slots.workspace,
title: 'Fallback',
titleKey: 'tab.title',
i18nNamespace: 'ext.localized',
build: (_) => const SizedBox.shrink(),
),
],
));
await local.services.extensions.activateAll();
// Activation auto-loaded the catalog → resolves, no "namespace not
// registered" warning.
expect(
local.services.i18n.string('tab.title', namespace: 'ext.localized', placeholder: 'fallback'),
'Localized',
);
});
test('deactivate removes contributions from the registry', () async {
f.services.extensions.register(_Ext(
id: 'ephemeral',