Skip to content

OCPBUGS-27309: i18n missing keys error in devtools console#16497

Open
sg00dwin wants to merge 3 commits into
openshift:mainfrom
sg00dwin:OCPBUGS-27309-i18n-plugin-namespace-timing
Open

OCPBUGS-27309: i18n missing keys error in devtools console#16497
sg00dwin wants to merge 3 commits into
openshift:mainfrom
sg00dwin:OCPBUGS-27309-i18n-plugin-namespace-timing

Conversation

@sg00dwin
Copy link
Copy Markdown
Member

@sg00dwin sg00dwin commented May 26, 2026

Resolves i18n missing keys errors when ACM and MCE plugins are enabled.

Analysis / Root cause:

useTranslatedExtensions calls t() on extension properties containing keys like %plugin__acm~Home% before the corresponding plugin namespace (plugin__acm) has finished loading via HTTP. useTranslationExt() is called with no namespace argument, so useTranslation() only suspends on the default namespace (public) — i18next has no way to know plugin namespaces are needed until t() is actually called. When the namespace isn't loaded yet, missingKeyHandler fires a console.error() for every key on every render.

Solution description:

  1. extension-i18n.ts — Add getNamespacesFromExtensions() which walks extension properties using the existing deepForOwn + isTranslatableString pattern to collect unique i18n namespaces from translatable strings (e.g., plugin__acm from %plugin__acm~Home%).

  2. useTranslatedExtensions.ts — Extract namespaces from the extensions array and trigger i18n.loadNamespaces() via useEffect. Wrap t() in a safeT() guard that checks i18n.hasResourceBundle(lng, ns) synchronously before calling t(). For keys whose namespace bundle isn't available, safeT returns the key portion (e.g., "Home" from "plugin__acm~Home") — the same fallback text i18next would produce, but without triggering missingKeyHandler. Once namespaces finish loading, a state update causes safeT to re-create, which triggers re-translation with the real t().

  3. extension-i18n.spec.ts — Add 4 unit tests for getNamespacesFromExtensions covering namespace extraction, deduplication, and edge cases.

Screenshots / screen recording:
before
Screenshot 2026-05-26 at 3 17 05 PM

after
Screenshot 2026-05-26 at 3 19 08 PM

Test setup:

Run console with ACM and MCE dynamic plugins enabled:

./bin/bridge -plugins mce=http://localhost:3001 -plugins acm=http://localhost:3002 \
  --plugin-proxy='{"services":[{"consoleAPIPath":"/api/proxy/plugin/mce/console/","endpoint":"https://localhost:4000","authorize":true},{"consoleAPIPath":"/api/proxy/plugin/acm/console/","endpoint":"https://localhost:4000","authorize":true}]}'

Test scenarios:

  • Load console with ACM/MCE plugins enabled — verify no Missing i18n key errors for plugin namespace keys in browser console
  • Switch to the Fleet management perspective — verify nav items (Home, Welcome, Overview, Clusters, etc.) are correctly translated
  • Filter browser console for "missing" — verify no plugin namespace translation errors
  • Verify nav items render without visible flash of untranslated keys
  • Load console without dynamic plugins — verify no regressions in core console translation

Assisted by: Claude Code

Summary by CodeRabbit

  • New Features

    • Added automatic extraction of translation namespaces from extensions.
    • Translation loading now asynchronously ensures required namespaces are available before rendering translated content.
    • Improved translation resolution to gracefully fall back when namespace resources aren’t yet loaded.
  • Tests

    • Added tests covering namespace extraction, deduplication, and edge cases.

…n namespaces load

useTranslatedExtensions called t() before plugin namespaces (e.g.
plugin__acm, plugin__mce) finished loading via HTTP, triggering
missingKeyHandler console errors on every render.

Add getNamespacesFromExtensions() to extract unique i18n namespaces from
extension translatable strings. useTranslatedExtensions now loads those
namespaces via i18n.loadNamespaces() and wraps t() in a safeT() guard
that checks i18n.hasResourceBundle() synchronously — returning the key
portion as fallback for unloaded namespaces without triggering
missingKeyHandler. Once namespaces finish loading, a state update
triggers re-translation with the real t().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openshift-ci-robot openshift-ci-robot added jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels May 26, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@sg00dwin: This pull request references Jira Issue OCPBUGS-27309, which is invalid:

  • expected the bug to target the "5.0.0" version, but no target version was set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Analysis / Root cause:

useTranslatedExtensions calls t() on extension properties containing keys like %plugin__acm~Home% before the corresponding plugin namespace (plugin__acm) has finished loading via HTTP. useTranslationExt() is called with no namespace argument, so useTranslation() only suspends on the default namespace (public) — i18next has no way to know plugin namespaces are needed until t() is actually called. When the namespace isn't loaded yet, missingKeyHandler fires a console.error() for every key on every render.

Solution description:

  1. extension-i18n.ts — Add getNamespacesFromExtensions() which walks extension properties using the existing deepForOwn + isTranslatableString pattern to collect unique i18n namespaces from translatable strings (e.g., plugin__acm from %plugin__acm~Home%).

  2. useTranslatedExtensions.ts — Extract namespaces from the extensions array and trigger i18n.loadNamespaces() via useEffect. Wrap t() in a safeT() guard that checks i18n.hasResourceBundle(lng, ns) synchronously before calling t(). For keys whose namespace bundle isn't available, safeT returns the key portion (e.g., "Home" from "plugin__acm~Home") — the same fallback text i18next would produce, but without triggering missingKeyHandler. Once namespaces finish loading, a state update causes safeT to re-create, which triggers re-translation with the real t().

  3. extension-i18n.spec.ts — Add 4 unit tests for getNamespacesFromExtensions covering namespace extraction, deduplication, and edge cases.

Screenshots / screen recording:
before
Screenshot 2026-05-26 at 3 17 05 PM

after
Screenshot 2026-05-26 at 3 19 08 PM

Test setup:

Run console with ACM and MCE dynamic plugins enabled:

./bin/bridge -plugins mce=http://localhost:3001 -plugins acm=http://localhost:3002 \
 --plugin-proxy='{"services":[{"consoleAPIPath":"/api/proxy/plugin/mce/console/","endpoint":"https://localhost:4000","authorize":true},{"consoleAPIPath":"/api/proxy/plugin/acm/console/","endpoint":"https://localhost:4000","authorize":true}]}'

Test scenarios:

  • Load console with ACM/MCE plugins enabled — verify no Missing i18n key errors for plugin namespace keys in browser console
  • Switch to the Fleet management perspective — verify nav items (Home, Welcome, Overview, Clusters, etc.) are correctly translated
  • Filter browser console for "missing" — verify no plugin namespace translation errors
  • Verify nav items render without visible flash of untranslated keys
  • Load console without dynamic plugins — verify no regressions in core console translation

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci Bot requested review from TheRealJon and jhadvig May 26, 2026 19:23
@openshift-ci openshift-ci Bot added the component/sdk Related to console-plugin-sdk label May 26, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 4b336d08-2543-4925-9e5c-feeac67ff929

📥 Commits

Reviewing files that changed from the base of the PR and between b5af835 and b0270df.

📒 Files selected for processing (1)
  • frontend/packages/console-plugin-sdk/src/utils/useTranslatedExtensions.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/packages/console-plugin-sdk/src/utils/useTranslatedExtensions.ts

Walkthrough

Adds an i18n namespace separator and extraction helper, tests namespace extraction, and updates useTranslatedExtensions to async-load required namespaces and use a safe translation wrapper.

Changes

Dynamic i18n namespace loading for extensions

Layer / File(s) Summary
Namespace separation and extraction contract
frontend/packages/console-plugin-sdk/src/utils/extension-i18n.ts
NS_SEPARATOR constant ('~') is introduced, and getNamespacesFromExtensions<TExtension>() scans extensions for translatable %...% strings, derives unique namespaces by splitting on the separator, and returns them as a deduplicated array.
Async namespace loading in useTranslatedExtensions hook
frontend/packages/console-plugin-sdk/src/utils/useTranslatedExtensions.ts
Hook now computes required namespaces from extensions, asynchronously loads them via i18n.loadNamespaces, tracks readiness state, and uses a safeT wrapper that returns key fallbacks when resource bundles are not yet available; safeT is passed into translateExtension to produce translated extensions.
Namespace extraction test suite
frontend/packages/console-plugin-sdk/src/utils/__tests__/extension-i18n.spec.ts
Tests for getNamespacesFromExtensions validate unique namespace extraction from single and multiple extensions, return empty arrays when namespaces or translatable strings are absent, and confirm proper deduplication.

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels: lgtm, kind/i18n, verified

Suggested reviewers:

  • jhadvig
  • TheRealJon
🚥 Pre-merge checks | ✅ 14 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Test Structure And Quality ⚠️ Warning Tests lack meaningful assertion failure messages. All 22+ assertions use naked expect() without diagnostic messages per requirement #4. Add meaningful failure messages to assertions: expect(foo).toBe(bar, 'description of what should be true')
✅ Passed checks (14 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly references the bug identifier OCPBUGS-27309 and succinctly describes the primary issue being resolved: i18n missing keys errors in the browser console.
Description check ✅ Passed The description is comprehensive and follows the template structure. It includes analysis/root cause, solution description with detailed file-by-file changes, before/after screenshots, test setup instructions, verified test scenarios, and browser conformance section.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed All test names in extension-i18n.spec.ts are stable and deterministic, using static descriptive strings with no dynamic data, timestamps, UUIDs, pod/node names, IP addresses, or template literals.
Microshift Test Compatibility ✅ Passed No Ginkgo e2e tests added in this PR. Changes are to TypeScript unit tests and console SDK implementation files, which are not subject to MicroShift compatibility requirements.
Single Node Openshift (Sno) Test Compatibility ✅ Passed This PR adds only TypeScript/JavaScript unit tests (Jest) to the console plugin SDK, not Ginkgo Go e2e tests. SNO compatibility check is not applicable to this PR.
Topology-Aware Scheduling Compatibility ✅ Passed PR is a frontend console plugin SDK change (i18n utilities and tests), not deployment manifests, operator code, or controllers with scheduling constraints. Check is not applicable.
Ote Binary Stdout Contract ✅ Passed PR contains only TypeScript/JavaScript frontend code; OTE Binary Stdout Contract check applies only to Go test code communicating via JSON on stdout.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed PR contains TypeScript/Jest unit tests, not Ginkgo e2e tests. Custom check applies only to Ginkgo e2e tests; this check is not applicable to frontend unit tests.
No-Weak-Crypto ✅ Passed No weak cryptography, custom crypto implementations, or non-constant-time secret comparisons found; PR addresses i18n namespace timing, not cryptography.
Container-Privileges ✅ Passed The custom check for container privileges does not apply to this PR. The PR contains only TypeScript source code for i18n translation handling, not Kubernetes/container manifests or configurations.
No-Sensitive-Data-In-Logs ✅ Passed No logging statements or sensitive data exposure detected. Code handles only non-sensitive i18n namespace and translation key management with no console/logging calls.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@sg00dwin
Copy link
Copy Markdown
Member Author

/jira refresh

@openshift-ci-robot openshift-ci-robot added jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. and removed jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels May 26, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@sg00dwin: This pull request references Jira Issue OCPBUGS-27309, which is valid. The bug has been moved to the POST state.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state ASSIGNED, which is one of the valid states (NEW, ASSIGNED, POST)

No GitHub users were found matching the public email listed for the QA contact in Jira (yapei@redhat.com), skipping review request.

Details

In response to this:

/jira refresh

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@sg00dwin
Copy link
Copy Markdown
Member Author

/label tide/merge-method-squash

@openshift-ci openshift-ci Bot added the tide/merge-method-squash Denotes a PR that should be squashed by tide when it merges. label May 26, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@sg00dwin: This pull request references Jira Issue OCPBUGS-27309, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)

No GitHub users were found matching the public email listed for the QA contact in Jira (yapei@redhat.com), skipping review request.

Details

In response to this:

Analysis / Root cause:

useTranslatedExtensions calls t() on extension properties containing keys like %plugin__acm~Home% before the corresponding plugin namespace (plugin__acm) has finished loading via HTTP. useTranslationExt() is called with no namespace argument, so useTranslation() only suspends on the default namespace (public) — i18next has no way to know plugin namespaces are needed until t() is actually called. When the namespace isn't loaded yet, missingKeyHandler fires a console.error() for every key on every render.

Solution description:

  1. extension-i18n.ts — Add getNamespacesFromExtensions() which walks extension properties using the existing deepForOwn + isTranslatableString pattern to collect unique i18n namespaces from translatable strings (e.g., plugin__acm from %plugin__acm~Home%).

  2. useTranslatedExtensions.ts — Extract namespaces from the extensions array and trigger i18n.loadNamespaces() via useEffect. Wrap t() in a safeT() guard that checks i18n.hasResourceBundle(lng, ns) synchronously before calling t(). For keys whose namespace bundle isn't available, safeT returns the key portion (e.g., "Home" from "plugin__acm~Home") — the same fallback text i18next would produce, but without triggering missingKeyHandler. Once namespaces finish loading, a state update causes safeT to re-create, which triggers re-translation with the real t().

  3. extension-i18n.spec.ts — Add 4 unit tests for getNamespacesFromExtensions covering namespace extraction, deduplication, and edge cases.

Screenshots / screen recording:
before
Screenshot 2026-05-26 at 3 17 05 PM

after
Screenshot 2026-05-26 at 3 19 08 PM

Test setup:

Run console with ACM and MCE dynamic plugins enabled:

./bin/bridge -plugins mce=http://localhost:3001 -plugins acm=http://localhost:3002 \
 --plugin-proxy='{"services":[{"consoleAPIPath":"/api/proxy/plugin/mce/console/","endpoint":"https://localhost:4000","authorize":true},{"consoleAPIPath":"/api/proxy/plugin/acm/console/","endpoint":"https://localhost:4000","authorize":true}]}'

Test scenarios:

  • Load console with ACM/MCE plugins enabled — verify no Missing i18n key errors for plugin namespace keys in browser console
  • Switch to the Fleet management perspective — verify nav items (Home, Welcome, Overview, Clusters, etc.) are correctly translated
  • Filter browser console for "missing" — verify no plugin namespace translation errors
  • Verify nav items render without visible flash of untranslated keys
  • Load console without dynamic plugins — verify no regressions in core console translation

Summary by CodeRabbit

Release Notes

  • New Features

  • Added helper function for extracting translation namespaces from extensions.

  • Enhanced translation loading to asynchronously load required namespaces before rendering.

  • Improved translation key handling to gracefully manage loading states.

  • Tests

  • Added comprehensive test coverage for namespace extraction, including edge cases and deduplication.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@sg00dwin sg00dwin changed the title OCPBUGS-27309: i18n plugin namespace timing OCPBUGS-27309: i18n missing keys error in devtools console May 26, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@sg00dwin: This pull request references Jira Issue OCPBUGS-27309, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)

No GitHub users were found matching the public email listed for the QA contact in Jira (yapei@redhat.com), skipping review request.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Analysis / Root cause:

useTranslatedExtensions calls t() on extension properties containing keys like %plugin__acm~Home% before the corresponding plugin namespace (plugin__acm) has finished loading via HTTP. useTranslationExt() is called with no namespace argument, so useTranslation() only suspends on the default namespace (public) — i18next has no way to know plugin namespaces are needed until t() is actually called. When the namespace isn't loaded yet, missingKeyHandler fires a console.error() for every key on every render.

Solution description:

  1. extension-i18n.ts — Add getNamespacesFromExtensions() which walks extension properties using the existing deepForOwn + isTranslatableString pattern to collect unique i18n namespaces from translatable strings (e.g., plugin__acm from %plugin__acm~Home%).

  2. useTranslatedExtensions.ts — Extract namespaces from the extensions array and trigger i18n.loadNamespaces() via useEffect. Wrap t() in a safeT() guard that checks i18n.hasResourceBundle(lng, ns) synchronously before calling t(). For keys whose namespace bundle isn't available, safeT returns the key portion (e.g., "Home" from "plugin__acm~Home") — the same fallback text i18next would produce, but without triggering missingKeyHandler. Once namespaces finish loading, a state update causes safeT to re-create, which triggers re-translation with the real t().

  3. extension-i18n.spec.ts — Add 4 unit tests for getNamespacesFromExtensions covering namespace extraction, deduplication, and edge cases.

Screenshots / screen recording:
before
Screenshot 2026-05-26 at 3 17 05 PM

after
Screenshot 2026-05-26 at 3 19 08 PM

Test setup:

Run console with ACM and MCE dynamic plugins enabled:

./bin/bridge -plugins mce=http://localhost:3001 -plugins acm=http://localhost:3002 \
 --plugin-proxy='{"services":[{"consoleAPIPath":"/api/proxy/plugin/mce/console/","endpoint":"https://localhost:4000","authorize":true},{"consoleAPIPath":"/api/proxy/plugin/acm/console/","endpoint":"https://localhost:4000","authorize":true}]}'

Test scenarios:

  • Load console with ACM/MCE plugins enabled — verify no Missing i18n key errors for plugin namespace keys in browser console
  • Switch to the Fleet management perspective — verify nav items (Home, Welcome, Overview, Clusters, etc.) are correctly translated
  • Filter browser console for "missing" — verify no plugin namespace translation errors
  • Verify nav items render without visible flash of untranslated keys
  • Load console without dynamic plugins — verify no regressions in core console translation

Assisted by: Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

  • Added helper function for extracting translation namespaces from extensions.

  • Enhanced translation loading to asynchronously load required namespaces before rendering.

  • Improved translation key handling to gracefully manage loading states.

  • Tests

  • Added comprehensive test coverage for namespace extraction, including edge cases and deduplication.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
frontend/packages/console-plugin-sdk/src/utils/extension-i18n.ts (1)

7-7: ⚡ Quick win

Export NS_SEPARATOR and reuse it across translation utilities.

NS_SEPARATOR is redefined in another file (useTranslatedExtensions.ts, Line 12). Keeping one source of truth prevents parsing drift between namespace extraction and runtime translation checks.

♻️ Proposed change
-const NS_SEPARATOR = '~';
+export const NS_SEPARATOR = '~';

And in useTranslatedExtensions.ts:

 import {
   getNamespacesFromExtensions,
   getTranslationKey,
   isTranslatableString,
+  NS_SEPARATOR,
   translateExtension,
 } from './extension-i18n';
 
-const NS_SEPARATOR = '~';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/packages/console-plugin-sdk/src/utils/extension-i18n.ts` at line 7,
NS_SEPARATOR is defined locally but also redefined elsewhere; export the single
source constant from extension-i18n.ts and consume it elsewhere to avoid drift:
change the const NS_SEPARATOR in extension-i18n.ts to an exported constant
(export const NS_SEPARATOR) and remove the duplicate definition in
useTranslatedExtensions.ts, importing NS_SEPARATOR from the extension-i18n
module instead; update any references in functions that parse namespaces or
perform translation checks (e.g., where namespace extraction or runtime
translation checks occur) to use the imported NS_SEPARATOR.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@frontend/packages/console-plugin-sdk/src/utils/extension-i18n.ts`:
- Line 7: NS_SEPARATOR is defined locally but also redefined elsewhere; export
the single source constant from extension-i18n.ts and consume it elsewhere to
avoid drift: change the const NS_SEPARATOR in extension-i18n.ts to an exported
constant (export const NS_SEPARATOR) and remove the duplicate definition in
useTranslatedExtensions.ts, importing NS_SEPARATOR from the extension-i18n
module instead; update any references in functions that parse namespaces or
perform translation checks (e.g., where namespace extraction or runtime
translation checks occur) to use the imported NS_SEPARATOR.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 4fb98e94-a766-488a-b206-bbb4dd2a2ce3

📥 Commits

Reviewing files that changed from the base of the PR and between 013358f and 63a15fd.

📒 Files selected for processing (3)
  • frontend/packages/console-plugin-sdk/src/utils/__tests__/extension-i18n.spec.ts
  • frontend/packages/console-plugin-sdk/src/utils/extension-i18n.ts
  • frontend/packages/console-plugin-sdk/src/utils/useTranslatedExtensions.ts

@jhadvig
Copy link
Copy Markdown
Member

jhadvig commented May 26, 2026

/retest

@sg00dwin
Copy link
Copy Markdown
Member Author

/test frontend

Remove the namespacesReady guard on the hasResourceBundle check so it
runs unconditionally. This handles both the timing race (namespace not
loaded yet) and genuinely missing keys (namespace loaded but key absent)
without triggering missingKeyHandler.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sg00dwin sg00dwin force-pushed the OCPBUGS-27309-i18n-plugin-namespace-timing branch from 63a15fd to b5af835 Compare May 27, 2026 18:51
@sg00dwin
Copy link
Copy Markdown
Member Author

/retest-required

1 similar comment
@sg00dwin
Copy link
Copy Markdown
Member Author

/retest-required

@sg00dwin
Copy link
Copy Markdown
Member Author

sg00dwin commented Jun 3, 2026

/test e2e-playwright

Comment thread frontend/packages/console-plugin-sdk/src/utils/useTranslatedExtensions.ts Outdated
Copy link
Copy Markdown
Contributor

@fsgreco fsgreco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jun 3, 2026
@sg00dwin
Copy link
Copy Markdown
Member Author

sg00dwin commented Jun 3, 2026

/verified by @sg00dwin (see screenshots)

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Jun 3, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@sg00dwin: This PR has been marked as verified by @sg00dwin (see screenshots).

Details

In response to this:

/verified by @sg00dwin (see screenshots)

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

…tensions.ts

Co-authored-by: Santiago Greco <22715417+fsgreco@users.noreply.github.com>
@openshift-ci-robot openshift-ci-robot removed the verified Signifies that the PR passed pre-merge verification criteria label Jun 3, 2026
@openshift-ci openshift-ci Bot removed the lgtm Indicates that a PR is ready to be merged. label Jun 3, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

@sg00dwin: This pull request references Jira Issue OCPBUGS-27309, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)

No GitHub users were found matching the public email listed for the QA contact in Jira (yapei@redhat.com), skipping review request.

Details

In response to this:

Resolves i18n missing keys errors when ACM and MCE plugins are enabled.

Analysis / Root cause:

useTranslatedExtensions calls t() on extension properties containing keys like %plugin__acm~Home% before the corresponding plugin namespace (plugin__acm) has finished loading via HTTP. useTranslationExt() is called with no namespace argument, so useTranslation() only suspends on the default namespace (public) — i18next has no way to know plugin namespaces are needed until t() is actually called. When the namespace isn't loaded yet, missingKeyHandler fires a console.error() for every key on every render.

Solution description:

  1. extension-i18n.ts — Add getNamespacesFromExtensions() which walks extension properties using the existing deepForOwn + isTranslatableString pattern to collect unique i18n namespaces from translatable strings (e.g., plugin__acm from %plugin__acm~Home%).

  2. useTranslatedExtensions.ts — Extract namespaces from the extensions array and trigger i18n.loadNamespaces() via useEffect. Wrap t() in a safeT() guard that checks i18n.hasResourceBundle(lng, ns) synchronously before calling t(). For keys whose namespace bundle isn't available, safeT returns the key portion (e.g., "Home" from "plugin__acm~Home") — the same fallback text i18next would produce, but without triggering missingKeyHandler. Once namespaces finish loading, a state update causes safeT to re-create, which triggers re-translation with the real t().

  3. extension-i18n.spec.ts — Add 4 unit tests for getNamespacesFromExtensions covering namespace extraction, deduplication, and edge cases.

Screenshots / screen recording:
before
Screenshot 2026-05-26 at 3 17 05 PM

after
Screenshot 2026-05-26 at 3 19 08 PM

Test setup:

Run console with ACM and MCE dynamic plugins enabled:

./bin/bridge -plugins mce=http://localhost:3001 -plugins acm=http://localhost:3002 \
 --plugin-proxy='{"services":[{"consoleAPIPath":"/api/proxy/plugin/mce/console/","endpoint":"https://localhost:4000","authorize":true},{"consoleAPIPath":"/api/proxy/plugin/acm/console/","endpoint":"https://localhost:4000","authorize":true}]}'

Test scenarios:

  • Load console with ACM/MCE plugins enabled — verify no Missing i18n key errors for plugin namespace keys in browser console
  • Switch to the Fleet management perspective — verify nav items (Home, Welcome, Overview, Clusters, etc.) are correctly translated
  • Filter browser console for "missing" — verify no plugin namespace translation errors
  • Verify nav items render without visible flash of untranslated keys
  • Load console without dynamic plugins — verify no regressions in core console translation

Assisted by: Claude Code

Summary by CodeRabbit

  • New Features

  • Added automatic extraction of translation namespaces from extensions.

  • Translation loading now asynchronously ensures required namespaces are available before rendering translated content.

  • Improved translation resolution to gracefully fall back when namespace resources aren’t yet loaded.

  • Tests

  • Added tests covering namespace extraction, deduplication, and edge cases.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Jun 3, 2026

@sg00dwin: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@fsgreco
Copy link
Copy Markdown
Contributor

fsgreco commented Jun 4, 2026

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jun 4, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Jun 4, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: fsgreco, sg00dwin
Once this PR has been reviewed and has the lgtm label, please assign jhadvig for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/sdk Related to console-plugin-sdk jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. tide/merge-method-squash Denotes a PR that should be squashed by tide when it merges.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants