Files
picpeak/frontend/i18next.config.ts
T
Paul Nothaft 5dbb43549c fix(i18n): make i18n:ci pass by fixing the extractor config
exit 1 -> exit 0.

Three findings, none of which matched the reported symptoms.

1. The two "unparseable .d.ts files" are not malformed. RestoreWizard.d.ts and
   BackupHistory.d.ts are valid declaration files sitting next to their .jsx
   implementations; i18next-cli feeds them to SWC as ordinary .ts modules with
   no ambient flag, where an uninitialised `const` is a hard syntax error. They
   should never have been scanned at all. Root cause is the input glob:
   i18next-cli passes `input` straight to `glob`, which does NOT honour
   `!`-prefixed negation inside the pattern list, so
   '!src/**/*.{test,spec,d}.{ts,tsx}' was a silent no-op and all four .d.ts
   files plus 57 test files were being scanned. Moved the exclusions to
   extract.ignore, where they take effect; the extracted key set is unchanged.

2. The "missing French keys" were not English-vs-French drift. The extractor
   wanted to add ~2771 keys to fr.json with value "" -- and src/i18n/config.ts
   does not set returnEmptyString, whose i18next default is true, so those
   empty strings would be returned as valid translations and render as blank
   UI rather than falling back to English. Filling nl/pt/ru/fr with ~11000
   empty strings would have been a worse regression than the failing check.
   The check was demanding parity for locales this project deliberately keeps
   partial, so `locales` is now ['en','de'] -- the two actually kept at parity.
   nl/pt/ru/fr join sl/es as hand-maintained partial locales on
   fallbackLng 'en'. No French was written.

3. de.json is a parity locale, and the extractor legitimately found 307 keys
   missing from both en and de (shipped t() calls never added to the locale
   files). Rather than accept 307 blank German strings these were written by
   hand: 105 are _one/_other variants derived from existing German bases with
   correct singular/plural, the rest translated against each section's register
   (Sie on admin/public-billing surfaces, du in the customer portal to match
   customer.quotes/customer.bills) reusing terms already established in de.json.
   Verified: 0 interpolation-placeholder mismatches between en and de across
   all 308 new keys, 0 empty and 0 key-shaped values remaining, and the diff is
   strictly additive (en +308, de +307, 0 removed, 0 changed).

removeUnusedKeys is now false, replacing the dead preservePatterns: []. It
wanted to delete ~355 live keys per locale across ~90 prefixes -- families
built at runtime (admin.activities.*, admin.notificationMessages.*,
projects.status.*) or held in constant tables the extractor cannot resolve
(AdminSidebar nameKey, CrmDevelopmentPage titleKey/descKey). Covering them
would need ~30 wildcards spanning most of the key space; disabling pruning is
the same behaviour, honestly stated, with the call sites named.

Refs testplan REPORT.md #22 (Part 1.3.03).
2026-09-01 17:07:07 +02:00

41 lines
1.6 KiB
TypeScript

import { defineConfig } from 'i18next-cli';
import { typescriptPlugin } from "./scripts/i18nextExtractionHelper";
export default defineConfig({
// Only the locales that are kept at full key parity are managed by the extractor.
// nl/pt/ru/fr/sl/es are deliberately partial and rely on `fallbackLng: 'en'`; letting
// the extractor own them would fill each file with ~2700 empty-string values, and
// i18next's default `returnEmptyString: true` renders those as blank UI instead of
// falling back to English.
locales: ['en', 'de'],
extract: {
input: ['src/**/*.{ts,tsx,js,jsx}'],
// `glob` (used by i18next-cli) ignores `!`-prefixed entries inside `input`,
// so exclusions have to live here or they are silently no-ops.
ignore: [
'src/**/*.{test,spec}.{ts,tsx,js,jsx}',
'src/**/__tests__/**',
'src/**/*.d.ts',
],
output: 'src/i18n/locales/{{language}}.json',
defaultNS: false,
primaryLanguage: 'en',
// Pruning is unsafe in this codebase: a large share of keys is never visible to the
// AST extractor because it is built at runtime — t(`admin.activities.${type}`),
// t(`admin.notificationMessages.${type}`), t(`projects.status.${status}`) — or held in
// constant tables the extractor does not resolve (AdminSidebar `nameKey`,
// CrmDevelopmentPage `titleKey`/`descKey`, the crmSettings toggle map). Enabling it
// deletes ~355 live keys per locale, so removal stays a manual decision.
removeUnusedKeys: false,
preserveContextVariants: true,
indentation: 2,
sort: false,
},
plugins: [typescriptPlugin(["./src/App.tsx"]) ]
});