Skip to content

Adding Translations

VoodooLikesCoding edited this page Nov 9, 2025 · 1 revision

Adding Translations

Invio supports internationalization (i18n) with separate translation files for the frontend UI and backend invoice rendering. This guide explains how to add a new language to Invio.

Overview

Invio uses a two-part translation system:

  1. Frontend translations — UI labels, buttons, forms, and messages in the admin interface
  2. Backend translations — Invoice template text (headings, labels) that appear in rendered PDFs and HTML

Both systems use JSON files with key-value pairs. The frontend supports interpolation for dynamic values.

Supported Languages

Currently supported locales:

  • en — English (default)
  • nl — Dutch (Nederlands)

Adding a New Language

Step 1: Create Frontend Translation File

Create a new JSON file in frontend/i18n/locales/ named after your locale code (e.g., de.json for German, fr.json for French, es.json for Spanish).

Location: frontend/i18n/locales/<locale>.json

Template: Copy frontend/i18n/locales/en.json as your starting point.

Structure:

{
  "Dashboard": "Dashboard",
  "Invoices": "Invoices",
  "Settings": "Settings",
  "Save": "Save",
  "Cancel": "Cancel"
}

Interpolation: Some keys use {{variable}} syntax for dynamic values:

{
  "Invoice number already exists": "Invoice number already exists",
  "Export failed with status {{status}}": "Export failed with status {{status}}",
  "Discount {{percentage}}%": "Discount {{percentage}}%"
}

Keep the {{variable}} placeholders intact and translate around them.

Complete the translation:

  • Translate all ~220 keys from English to your target language
  • Preserve special characters and formatting
  • Keep technical terms (like "Ctrl+S") as-is or adapt to local conventions

Step 2: Create Backend Translation File

Create a matching JSON file in backend/src/i18n/locales/ with the same locale code.

Location: backend/src/i18n/locales/<locale>.json

Template: Copy backend/src/i18n/locales/en.json as your starting point.

Structure:

{
  "invoiceTitle": "Invoice",
  "invoiceNumberLabel": "Invoice Number",
  "dueDateLabel": "Due Date",
  "billToHeading": "BILL TO",
  "itemHeaderDescription": "Description",
  "subtotalLabel": "Subtotal",
  "totalLabel": "Total",
  "paymentInformationHeading": "Payment Information",
  "thankYouNote": "Thank you for your business!"
}

Complete the translation:

  • Translate all required keys (see REQUIRED_KEYS in backend/src/i18n/translations.ts)
  • These labels appear in invoice PDFs, so use professional invoice terminology
  • Keep formatting consistent (e.g., "BILL TO" vs "Bill To" — match your locale's convention)

Step 3: Register Frontend Locale

Edit frontend/i18n/mod.ts to import and register your new locale:

import enMessages from "./locales/en.json" with { type: "json" };
import nlMessages from "./locales/nl.json" with { type: "json" };
import deMessages from "./locales/de.json" with { type: "json" }; // Add this

const catalogs: Record<string, UiMessages> = {
  en: enMessages as UiMessages,
  nl: nlMessages as UiMessages,
  de: deMessages as UiMessages, // Add this
};

Step 4: Register Backend Locale

Edit backend/src/i18n/translations.ts to import and register your locale:

import enRaw from "./locales/en.json" with { type: "json" };
import nlRaw from "./locales/nl.json" with { type: "json" };
import deRaw from "./locales/de.json" with { type: "json" }; // Add this

// In the catalogs object:
const catalogs: Record<string, InvoiceLabels> = {
  en: validateAndNormalize(enRaw as Record<string, unknown>, "en"),
  nl: validateAndNormalize(nlRaw as Record<string, unknown>, "nl"),
  de: validateAndNormalize(deRaw as Record<string, unknown>, "de"), // Add this
};

Step 5: Test Your Translation

  1. Set locale in Settings:

    • Log into Invio admin
    • Navigate to Settings → Appearance
    • Select your new locale from the dropdown
    • Save changes
  2. Test frontend:

    • Navigate through all pages (Dashboard, Invoices, Customers, Settings)
    • Create/edit an invoice
    • Verify all labels are translated correctly
    • Check for missing keys (they'll display as the key itself)
  3. Test backend:

    • Create or edit an invoice
    • Click "Download PDF" or "View HTML"
    • Verify invoice labels use your translation
    • Check for proper formatting and professional appearance
  4. Test number/date formats:

    • In Settings → Appearance, set number format and date format
    • Create an invoice and verify currency and dates render correctly

Locale Selection Priority

Invio resolves the locale in this order:

  1. User-selected locale in Settings (stored in database)
  2. Locale from invoice data (if set)
  3. Browser/request locale (frontend only)
  4. Default (en)

Number and Date Formatting

In addition to translations, you can configure:

  • Number format: comma (1.234,56) or period (1,234.56)
  • Date format: Custom pattern using tokens like YYYY-MM-DD, DD/MM/YYYY, etc.

These are set in Settings → Appearance and stored separately from the locale.

Translation Tips

Frontend Keys to Pay Special Attention To

  • Form validation messages — Users see these on errors
  • Button labels — "Save", "Cancel", "Delete", "Publish", etc.
  • Status labels — "Draft", "Sent", "Paid", "Overdue", "Cancelled"
  • Placeholders — Input field hints like "e.g. INV-2025-001"
  • Help text — Longer descriptions in Settings

Backend Keys to Pay Special Attention To

  • Invoice headings — Professional invoice terminology
  • Table headers — Clear, concise column labels
  • Summary section — Financial terms like "Subtotal", "Tax", "Total"
  • Payment information — Banking and payment terms
  • Thank you note — Professional closing message

Cultural Considerations

  • Currency symbols — Respect local conventions ($1,000.00 vs €1.000,00)
  • Date formats — MM/DD/YYYY (US) vs DD/MM/YYYY (Europe) vs YYYY-MM-DD (ISO)
  • Formal vs informal — Some languages distinguish (Sie/du, vous/tu)
  • Address formats — Order of street, city, postal code varies by country

Quality Checklist

  • All keys from en.json are present
  • No untranslated English text remains
  • Interpolation variables ({{var}}) preserved
  • Professional tone for invoice labels
  • Tested in UI and PDFs
  • Number/date formats configured for locale
  • No grammar or spelling errors
  • Consistent terminology throughout

Contributing Your Translation

Once you've completed and tested your translation:

  1. Fork the Invio repository
  2. Add your translation files
  3. Update frontend/i18n/mod.ts and backend/src/i18n/translations.ts
  4. Test thoroughly
  5. Submit a Pull Request with:
    • Clear title: "Add [Language] translation"
    • Description of what was translated
    • Note any locale-specific considerations

Your contribution helps make Invio accessible to more users worldwide!

Maintenance

When Invio adds new features:

  • New keys may be added to en.json files
  • You'll need to add translations for these keys
  • Missing keys will fall back to English
  • Watch the repository for translation updates

Getting Help

  • Missing keys? Compare your translation to en.json
  • Formatting issues? Check the JSON syntax (commas, quotes)
  • Display problems? Verify locale code matches everywhere
  • Questions? Open an issue on GitHub with the i18n label

Need an example? Review the Dutch (nl) translations in:

  • frontend/i18n/locales/nl.json
  • backend/src/i18n/locales/nl.json

Clone this wiki locally