902b3ee986
The ROT/RUT payout feature shipped in #1380 with all 44 of its strings written into the invoice_editor namespace, while RotRutPayoutDialog and the invoices page both read useTranslations('invoices'). next-intl falls back to rendering the key path, so production showed literal "invoices.rot_rut_payout_title" text where every label should be, and the header button read "invoices.rot_rut_payout_action". Move the keys to the invoices namespace, textually rather than through a JSON round trip: the message files contain duplicate keys that JSON.parse/stringify would silently drop. Three other dialogs had the same namespace mismatch and are fixed the same way, by adding the strings they reference to the namespace they read from (TemplateBookDialog reads bookkeeping, Correction/StrikeLines read journal_detail). Add i18n/__tests__/message-keys.test.ts, which resolves every literal t() key in app/, components/ and extensions/ against both locales. next-intl has no build-time check and degrades by rendering the key path, so this class of bug reaches users silently otherwise. Also gate the payout action. Begäran om utbetalning (Lag 2009:194 8 §) only concerns companies selling ROT/RUT-eligible work to consumers, so the header button now appears only when the company has invoiced a deduction or has opted into ROT/RUT in tax settings. The flag comes from the company_settings row the page already fetches for ore_rounding, so there is no extra request. ?rot-rut=1 still opens the dialog. Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>