Skip to content

Administration

Multi-language support

The app ships with 11 languages: English, Español, Français, हिन्दी, বাংলা, العربية, اردو, Türkçe, Português, Bahasa Indonesia, and Tiếng Việt. Every user picks their own language independently — it's…

Last updated Aug 19, 2026 · 5 min read

The app ships with 11 languages: English, Español, Français, हिन्दी, বাংলা, العربية, اردو, Türkçe, Português, Bahasa Indonesia, and Tiếng Việt. Every user picks their own language independently — it's a per-user preference, not a tenant-wide or installation-wide setting.

Arabic and Urdu are right-to-left languages — the app mirrors the entire layout (dir="rtl") automatically when one of them is active, both on first server-rendered paint and on every client-side navigation.

Changing your own language

Go to Settings → Language and pick from the available options. This takes effect immediately and is remembered for that user on every future visit — no other user's language changes. The platform Landlord/Admin panel has its own equivalent Language page in its top nav, backed by a separate locale column on landlord_users (a distinct table/guard from tenant users — its own preference, independent of any tenant user's).

Behind the scenes, the language a page renders in is resolved in this order: the signed-in user's own saved preference, then the tenant's default (if the user hasn't set one), then the browser's Accept-Language header, then the app's configured default (English). The landlord panel follows the same order minus the tenant-default step (it has no tenant context of its own).

What's translated today

Coverage is comprehensive and spans both the frontend and the backend:

  • Every page component under resources/js/pages — CRM, Sales-to-Cash, Inventory, Accounting, HR, Settings, the landlord panel, onboarding, and auth — renders through vue-i18n. All 11 locale bundles carry the same 1,870 keys, kept in parity by convention (see below) rather than allowed to drift.
  • PDF exports (quotes, invoices, credit notes, purchase orders, stock transfers, payslips, and all six accounting reports) render through Laravel's own __() translator, using the tenant's configured locale for anything a customer receives (an invoice PDF is in the business's language regardless of which staff member's own UI happens to be in a different one) and the acting user's session locale for internal-use downloads.
  • Notifications and transactional emails (invoice sent, payment recorded, quote accepted, low stock, new lead, leave requests) render in each recipient's own saved locale automatically — App\Models\User implements Laravel's HasLocalePreference contract, so this needs no per-call wiring; Laravel's notification/mail pipeline picks it up on its own.

Two things are their own separate translation surface:

  • Laravel framework messages (validation errors like "The name field is required.", pagination labels, and password-reset mail) ship as PHP files under lang/{locale}/ for every supported locale — auth.php, pagination.php, passwords.php, and validation.php. Empty-form errors follow the active language the same way the rest of the UI does.
  • A tenant's own data (item names, party names, notes, and so on) is stored exactly as entered and is never auto-translated. If you need a single item to have a different display name per language, that's a different feature (database-level content translation) — the necessary package (spatie/laravel-translatable) is already installed but not wired into any model yet.

Adding a new language

  1. Copy resources/js/locales/en.json to resources/js/locales/{code}.json (e.g. de.json for German) and translate every value — keep every key exactly as-is. Verify parity before shipping: parse both files, flatten their keys through nested objects, and confirm the two key sets are identical (currently 1,870 keys) — a missing key silently falls back to English rather than erroring.
  2. Add the language to config/app.php's supported_locales array:
    'supported_locales' => [
        'en' => 'English',
        'es' => 'Español',
        'fr' => 'Français',
        'hi' => 'हिन्दी',
        'bn' => 'বাংলা',
        'ar' => 'العربية',
        'ur' => 'اردو',
        'tr' => 'Türkçe',
        'pt' => 'Português',
        'id' => 'Bahasa Indonesia',
        'vi' => 'Tiếng Việt',
        'de' => 'Deutsch', // new
    ],
    
  3. Add lang/{code}.json for backend-generated text — flash messages (e.g. "Profile updated."), PDF export labels, and notification/email copy. Copy lang/es.json as a template (396 keys) and translate every value, keeping every key exactly as-is; :placeholder tokens (Laravel's own syntax, distinct from the {placeholder} syntax in the frontend files from step 1) must be preserved verbatim. No longer just a handful of strings — skipping this file means every PDF export and notification for that language silently falls back to English even though the UI itself is translated.
  4. Copy lang/en/{auth,pagination,passwords,validation}.php to lang/{code}/ and translate those framework messages too — otherwise validation and password-reset emails stay in English.
  5. If the new language is written right-to-left (e.g. Hebrew, Persian), add its code to the RTL_LOCALES set in resources/js/lib/i18n.ts and to the dir check in resources/views/app.blade.php — see how ar/ur are wired for reference. No CSS logical-property rework is needed beyond that; the browser mirrors layout from the dir attribute.
  6. Run npm run build so the new bundle is picked up.

The new language now appears automatically on the Language settings page — no other code changes needed. It's loaded lazily (only fetched the first time a user actually selects it), so adding more languages doesn't add weight to everyone else's page loads.

← All Coravo – AI CRM & ERP Software for Growing Businesses documentation

We use cookies to understand how visitors use this site. Cookie Policy