You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The #2340 extraction codemod swept API route paths and one filesystem path into the locale files as if they were display copy. They now sit in all seven locales as translatable values:
python3 - <<'PY'import json,glob,osfor f in sorted(glob.glob('apps/web/src/locales/en/*.json')): d=json.load(open(f)) def walk(o,p=''): if isinstance(o,dict): for k,v in o.items(): walk(v,f"{p}.{k}" if p else k) elif isinstance(o,str) and o.startswith('/') and len(o)>4 and ' ' not in o: print(os.path.basename(f), p, repr(o)) walk(d)PY
Why this is a bug and not just untidy
Nothing is broken today, because every locale happens to carry the verbatim English value. It works by luck. The failure mode is that a translator — human or machine — localizes one of these entries, and the feature breaks only in that locale, at runtime, with no test or type error to catch it. /etc/ssh/sshd_config is especially inviting to "translate".
deviceGroupsPage.deviceGroups was the live one: DeviceGroupsPage.tsx built its group-create POST URL from t("deviceGroupsPage.deviceGroups"). That call site is already being fixed in #3423, which inlines the literal and removes that key from all seven locales.
Remaining work
The other seven entries have no call sites — the codemod left them behind as dead keys after the URLs were inlined back. So this is cleanup plus one judgement call:
complianceTab.etcSshSshdConfigdoes have a live call site (ComplianceTab.tsx:948) where it renders as display text — an example path in help copy. It should be a literal in the component, not a translatable string.
Related: #2649 (same codemod, different symptom — humanized key names replacing English copy), #3423 (fixes the one live route key), #3424 (same codemod, different symptom — a sentence split into four unspaced JSX expressions).
Description
The #2340 extraction codemod swept API route paths and one filesystem path into the locale files as if they were display copy. They now sit in all seven locales as translatable values:
devices.json→deviceGroupsPage.deviceGroups/device-groupspolicies.json→configurationPolicies.configPolicyCreatePage.configurationPolicies2/configuration-policiespolicies.json→configurationPolicies.configPolicyDetailPage.configurationPolicies2/configuration-policiespolicies.json→configurationPolicies.featureTabs.automationTab.scriptsLimit200/scripts?limit=200policies.json→configurationPolicies.featureTabs.automationTab.alertsChannelsLimit200/alerts/channels?limit=200policies.json→configurationPolicies.featureTabs.automationTab.softwareCatalogLimit100/software/catalog?limit=100policies.json→software.builtinPackageDetail.integrations/integrationspolicies.json→configurationPolicies.featureTabs.complianceTab.etcSshSshdConfig/etc/ssh/sshd_configEnumerate them with:
Why this is a bug and not just untidy
Nothing is broken today, because every locale happens to carry the verbatim English value. It works by luck. The failure mode is that a translator — human or machine — localizes one of these entries, and the feature breaks only in that locale, at runtime, with no test or type error to catch it.
/etc/ssh/sshd_configis especially inviting to "translate".deviceGroupsPage.deviceGroupswas the live one:DeviceGroupsPage.tsxbuilt its group-createPOSTURL fromt("deviceGroupsPage.deviceGroups"). That call site is already being fixed in #3423, which inlines the literal and removes that key from all seven locales.Remaining work
The other seven entries have no call sites — the codemod left them behind as dead keys after the URLs were inlined back. So this is cleanup plus one judgement call:
complianceTab.etcSshSshdConfigdoes have a live call site (ComplianceTab.tsx:948) where it renders as display text — an example path in help copy. It should be a literal in the component, not a translatable string.enlocale value matches^/[a-z0-9-]+(excluding legitimately-translatable unit suffixes likeperMonth: "/mo",perYear: "/yr"). That makes this class mechanical instead of a future grep. This is the same shape of defect as i18n: #2340 extraction replaced English copy with humanized key names across all five locales #2649 and would have caught both.Affected files
apps/web/src/locales/*/policies.json(7 locales)apps/web/src/locales/*/devices.json(7 locales — handled by fix(groups): accept a null filterConditions on create and stop dropping static deviceIds (#3159) #3423)apps/web/src/components/configurationPolicies/featureTabs/ComplianceTab.tsx:948Related: #2649 (same codemod, different symptom — humanized key names replacing English copy), #3423 (fixes the one live route key), #3424 (same codemod, different symptom — a sentence split into four unspaced JSX expressions).
Reported By: internal Playwright UI QA sweep 2026-08-11, evidence in
docs/testing/FEATURE_TEST_LOG.md.