[ { "id": "T001", "description": "en/msp/quotes.json exists and is valid JSON with component-scoped root keys (quotesTab, quoteForm, quoteDetail, quoteLineItems, quoteConversion, quoteApproval, quoteTemplates, quotePreview, templateEditor, templatesPage, common)", "implemented": true, "featureIds": ["F001"] }, { "id": "T002", "description": "validate-translations.cjs passes for msp/quotes namespace -- all 9 locales have identical key sets with no missing keys or empty values", "implemented": true, "featureIds": ["F001", "F014", "F016", "F017"] }, { "id": "T003", "description": "QuoteForm.tsx compiles with useTranslation('msp/quotes') -- no TypeScript errors, all form labels, workflow buttons, dialog text, validation messages, and status banners use t()", "implemented": true, "featureIds": ["F002"] }, { "id": "T004", "description": "QuoteForm.tsx has no remaining hardcoded English strings in JSX (grep for bare string literals in rendered output returns 0 matches, excluding technical values like CSS classes, element IDs, and route paths)", "implemented": true, "featureIds": ["F002"] }, { "id": "T005", "description": "QuoteDetail.tsx compiles with useTranslation('msp/quotes') -- no TypeScript errors, all section headings, field labels, action buttons, dialogs, banners, and activity log use t()", "implemented": true, "featureIds": ["F003"] }, { "id": "T006", "description": "QuoteDetail.tsx has no remaining hardcoded English strings in JSX", "implemented": true, "featureIds": ["F003"] }, { "id": "T007", "description": "QuotesTab.tsx compiles with useTranslation -- all sub-tab labels, column headers, action menu items, dialogs, and empty states use t()", "implemented": true, "featureIds": ["F004"] }, { "id": "T008", "description": "QuotesTab.tsx has no remaining hardcoded English strings in JSX", "implemented": true, "featureIds": ["F004"] }, { "id": "T009", "description": "QuoteDocumentTemplateEditor.tsx compiles with useTranslation -- all headings, tab labels, status labels, buttons, and error messages use t()", "implemented": true, "featureIds": ["F005"] }, { "id": "T010", "description": "QuoteDocumentTemplateEditor.tsx has no remaining hardcoded English strings in JSX", "implemented": true, "featureIds": ["F005"] }, { "id": "T011", "description": "QuoteLineItemsEditor.tsx compiles with useTranslation -- all table headers, checkbox labels, frequency options, discount panel labels, section labels, and empty states use t()", "implemented": true, "featureIds": ["F006"] }, { "id": "T012", "description": "QuoteLineItemsEditor.tsx has no remaining hardcoded English strings in JSX", "implemented": true, "featureIds": ["F006"] }, { "id": "T013", "description": "QuoteDocumentTemplatesPage.tsx compiles with useTranslation -- all page chrome, table columns, and action menu items use t()", "implemented": true, "featureIds": ["F007"] }, { "id": "T014", "description": "QuoteConversionDialog.tsx compiles with useTranslation -- all dialog text, mode labels/descriptions, item category headings, summary labels use t()", "implemented": true, "featureIds": ["F008"] }, { "id": "T015", "description": "QuoteApprovalDashboard.tsx compiles with useTranslation -- all headings, settings, filter labels, column headers, and empty states use t()", "implemented": true, "featureIds": ["F009"] }, { "id": "T016", "description": "QuoteTemplatesList.tsx compiles with useTranslation -- all list chrome, action menu items, empty state, and delete confirmation use t()", "implemented": true, "featureIds": ["F010"] }, { "id": "T017", "description": "QuotePreviewPanel.tsx compiles with useTranslation -- panel heading, button labels, empty/loading/error states use t()", "implemented": true, "featureIds": ["F011"] }, { "id": "T018", "description": "Currency formatting uses locale-aware formatter instead of hardcoded 'en-US' in all 5 affected components", "implemented": true, "featureIds": ["F012"] }, { "id": "T019", "description": "Date formatting uses locale-aware formatter instead of hardcoded .toLocaleDateString() in all 4 affected components", "implemented": true, "featureIds": ["F013"] }, { "id": "T030", "description": "The follow-on formatter cleanup outside F012/F013 is complete: QuoteForm.tsx uses useFormatters() for banner dates and quote totals, QuoteLineItemsEditor.tsx uses useFormatters() for inline money displays, and quoteLineItemDraft.ts no longer hardcodes `en-US` in `formatDraftQuoteMoney()`.", "implemented": true, "featureIds": ["F025"] }, { "id": "T020", "description": "Italian accent audit passes for it/msp/quotes.json -- all Italian translations use correct grave/acute accents (e.g. 'perche' must be 'perch\u00e9', 'piu' must be 'pi\u00f9')", "implemented": true, "featureIds": ["F015"] }, { "id": "T021", "description": "Pseudo-locale xx/msp/quotes.json shows '11111' fill patterns for visual QA -- all values are replaced with numeric fill", "implemented": true, "featureIds": ["F016"] }, { "id": "T022", "description": "Interpolation variables are preserved in all 9 locale files -- every t() call with variables (e.g. {{count}}, {{name}}) has matching variables in all translations", "implemented": true, "featureIds": ["F014", "F016", "F017"] }, { "id": "T023", "description": "ROUTE_NAMESPACES includes '/msp/quote-approvals' and '/msp/quote-document-templates' loading 'msp/quotes', and '/msp/billing' entry includes 'msp/quotes'", "implemented": true, "featureIds": ["F018"] }, { "id": "T024", "description": "npm run build succeeds with no TypeScript errors after all quote i18n wiring is complete", "implemented": true, "featureIds": ["F019"] }, { "id": "T025", "description": "QuoteLineItemsEditor.tsx markup badge and currency-mismatch tooltip use t() with {{value}}, {{costCurrency}}, and {{quoteCurrency}} interpolation -- no remaining hardcoded 'Markup unavailable', '% markup', or 'Markup can't be calculated...' literals in JSX, and the new keys exist under quoteLineItems.markup.* in all 9 locale files", "implemented": true, "featureIds": ["F020"] }, { "id": "T026", "description": "QuoteSendRecipientsField.tsx compiles with useTranslation('msp/quotes') -- trigger labels, search placeholder, empty states, kind badges, and Remove {{email}} aria-label all use t(); no remaining hardcoded English strings in JSX; quoteRecipients.* key group present in all 9 locale files", "implemented": true, "featureIds": ["F021"] }, { "id": "T027", "description": "msp/core.json in all 9 locales (en, fr, es, de, nl, it, pl, xx, yy) contains nav.billing.sections.quotes, nav.billing.quotes, nav.billing.quoteBusinessTemplates, and nav.billing.quoteLayouts under the existing nav.billing.* group. Visual smoke test: the MSP left sidebar's QUOTES section in xx renders '11111' for the section header and all three items instead of falling back to the raw English names in menuConfig.ts; in de the same entries render German translations", "implemented": true, "featureIds": ["F022"] }, { "id": "T029", "description": "The shared billing-frequency enum contract includes `weekly`: `packages/billing/src/constants/billing.ts` exposes it in `BILLING_FREQUENCY_VALUES` / `BILLING_FREQUENCY_LABEL_DEFAULTS`, and all 9 `features/billing.json` locale files contain `enums.billingFrequency.weekly` so weekly quote recurrence can be translated without regressing the existing option list.", "implemented": true, "featureIds": ["F024"] } ]