i18n: close the admin translation coverage gaps
Recurring pattern of components and strings shipped without translation coverage, found across unrelated feature areas. +212 keys each to en.json and de.json, provably additive (flattened-key diff: removed=0, changed=0; formatting round-trips byte-identically). Genuinely un-wired components (grep -c useTranslation == 0), now wired: BulkArchiveModal (8 strings, count-pluralised), WebhookDeliveriesPage (27), CMSEditor's TipTap toolbar/link dialog/status bar/help modal (64). Hardcoded strings fixed in code: ImageSecurityTab's 4 spinbutton hints, ProjectsListPage's unlocalized status enum. Keys-only (component already calls t() correctly): General "Time format", Branding Social Media + Promotional Banner, Quotes detail/editor, cms.showInFooter. Two corrections to the report's attribution: - BlockLibraryPage was NOT un-wired -- it calls t() on every string with English defaults; all 32 contracts.blocks.* keys were simply absent from both locale files, so everything fell back to the JSX default. Same for ContractsListPage, where the report cited 3 missing keys and there are actually 9 (all 5 table column headers plus the pagination line). - CustomerDetailPage has full t() coverage; its single English "Contracts" was a missing customer.nav.contracts key behind a dynamic labelKey. Locale convention followed: i18next.config.ts manages en/de/nl/pt/ru/fr, but only en and de are kept at parity (5198/5200 keys); the rest are ~50% partial and rely on fallbackLng 'en'. Added to en + de only rather than inventing 212x6 unreviewable translations. Also added the 25 missing businessProfile.* keys (PDF-letterhead section, bank-accounts QR disclaimer). That component already calls t(), so those strings localize as soon as the keys exist; no wiring needed. Refs testplan REPORT.md #15a.
This commit is contained in:
@@ -159,7 +159,7 @@ export const ImageSecurityTab: React.FC = () => {
|
||||
onChange={(e) => handleChange('default_image_quality', parseInt(e.target.value) || 85)}
|
||||
className="w-full px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg bg-white dark:bg-neutral-800 text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||
/>
|
||||
<p className="text-xs text-neutral-500 dark:text-neutral-400 mt-1">1-100, higher = better quality</p>
|
||||
<p className="text-xs text-neutral-500 dark:text-neutral-400 mt-1">{t('settings.imageSecurity.imageQualityHelp', '1-100, higher = better quality')}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -174,7 +174,7 @@ export const ImageSecurityTab: React.FC = () => {
|
||||
onChange={(e) => handleChange('default_fragmentation_level', parseInt(e.target.value) || 3)}
|
||||
className="w-full px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg bg-white dark:bg-neutral-800 text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||
/>
|
||||
<p className="text-xs text-neutral-500 dark:text-neutral-400 mt-1">1-10, higher = more protection</p>
|
||||
<p className="text-xs text-neutral-500 dark:text-neutral-400 mt-1">{t('settings.imageSecurity.fragmentationLevelHelp', '1-10, higher = more protection')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -282,7 +282,7 @@ export const ImageSecurityTab: React.FC = () => {
|
||||
onChange={(e) => handleChange('suspicious_activity_threshold', parseInt(e.target.value) || 10)}
|
||||
className="w-full px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg bg-white dark:bg-neutral-800 text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||
/>
|
||||
<p className="text-xs text-neutral-500 dark:text-neutral-400 mt-1">Violations before flagging as suspicious</p>
|
||||
<p className="text-xs text-neutral-500 dark:text-neutral-400 mt-1">{t('settings.imageSecurity.suspiciousActivityThresholdHelp', 'Violations before flagging as suspicious')}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -297,7 +297,7 @@ export const ImageSecurityTab: React.FC = () => {
|
||||
onChange={(e) => handleChange('auto_block_threshold', parseInt(e.target.value) || 50)}
|
||||
className="w-full px-3 py-2 border border-neutral-300 dark:border-neutral-600 rounded-lg bg-white dark:bg-neutral-800 text-neutral-900 dark:text-neutral-100 focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||
/>
|
||||
<p className="text-xs text-neutral-500 dark:text-neutral-400 mt-1">Violations before auto-blocking IP</p>
|
||||
<p className="text-xs text-neutral-500 dark:text-neutral-400 mt-1">{t('settings.imageSecurity.autoBlockThresholdHelp', 'Violations before auto-blocking IP')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user