rivalex/lingua

Laravel package for multilingual management with database, Livewire UI and translation synchronization

Maintainers

Package info

github.com/rivalex/lingua

pkg:composer/rivalex/lingua

Fund package maintenance!

Alessandro Rivolta

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.0.0 2026-03-18 17:39 UTC

This package is auto-updated.

Last update: 2026-03-19 10:30:47 UTC


README

🌍 Lingua

The complete multilingual management system for Laravel

Latest Version on Packagist PHP Version Laravel Version License codecov Tests

Lingua brings database-driven translations to Laravel with a beautiful Livewire + Flux UI β€” install languages, manage translations, and sync everything with a single command.

Features Β· Installation Β· Configuration Β· Artisan Commands Β· Publishing Β· UI Guide Β· Architecture

✨ Features

Feature Description
Database-backed translations All translations stored in the database, editable instantly without deployments
Livewire UI Reactive, real-time language and translation management interface
Flux UI components Modern, accessible UI built with Livewire Flux
Bi-directional sync Push translations to the database or pull them back to local PHP/JSON files
Laravel Lang integration Install 70+ languages with one command, auto-updated via laravel-lang
Rich text support Translations can be plain text, HTML, or Markdown
Language selector Configurable sidebar, dropdown, or modal language switcher for users
Progress tracking Per-language completion percentage and missing-translation counts
RTL support First-class right-to-left language handling
Vendor translations Manage package translations alongside your own
Database-agnostic Full support for SQLite, MySQL, PostgreSQL, and SQL Server
Fully tested 150+ tests with Pest, covering commands, Livewire components, Blade components and helpers class

πŸ“¦ Requirements

  • PHP 8.4+
  • Laravel 12+
  • Livewire 4.1+
  • Livewire Flux 2.12+

πŸš€ Installation

1. Install via Composer

composer require rivalex/lingua

2. Run the interactive installer

php artisan lingua:install

The installer will:

  • Publish the configuration file to config/lingua.php
  • Publish and run the database migrations
  • Seed the database with your default language and its translations
  • Optionally star the repo on GitHub ⭐

That's it β€” Lingua is ready.

3. Access the UI

Page URL Route name
Languages your-app.test/lingua/languages lingua.languages
Translations your-app.test/lingua/translations/{locale?} lingua.translations

βš™οΈ Configuration

After installation, config/lingua.php gives you full control:

return [
    // Directory where local language files are stored
    'lang_dir' => lang_path(),

    // Application default locale
    'default_locale' => config('app.locale', 'en'),

    // Fallback locale when a translation is missing
    'fallback_locale' => config('app.fallback_locale', 'en'),

    // Middleware applied to Lingua's routes
    'middleware' => ['web'],

    // URL prefix for Lingua's management pages
    'routes_prefix' => 'lingua',

    // Session key used to store the active locale
    'session_variable' => 'locale',

    // Language selector widget settings
    'selector' => [
        'mode'       => 'sidebar',   // 'sidebar' | 'modal' | 'dropdown'
        'show_flags' => true,
    ],

    // Rich-text editor toolbar options
    'editor' => [
        'headings'      => false,
        'bold'          => true,
        'italic'        => true,
        'underline'     => true,
        'strikethrough' => false,
        'bullet'        => true,
        'ordered'       => true,
        'clear'         => true,
        // ... more options available
    ],
];

πŸ›  Artisan Commands

Lingua ships with a complete command suite for terminal-driven language and translation management.

Language management

Command Description
lingua:add {locale} Install a new language: downloads files, creates DB record, syncs translations
lingua:remove {locale} Remove a language: deletes files, cleans DB, reorders remaining languages
lingua:update-lang Update all installed language files via Laravel Lang, then re-sync to database
# Add Italian
php artisan lingua:add it

# Add Brazilian Portuguese
php artisan lingua:add pt_BR

# Remove French (the default language is protected)
php artisan lingua:remove fr

# Pull the latest translation strings from Laravel Lang and sync to DB
php artisan lingua:update-lang

Translation sync

Command Description
lingua:sync-to-database Import all local PHP/JSON translation files into the database
lingua:sync-to-local Export all database translations back to local PHP/JSON files
# Populate the database from existing lang/ files (e.g. after a fresh install)
php artisan lingua:sync-to-database

# Write database translations to lang/ files (e.g. for version control or deployment)
php artisan lingua:sync-to-local

Install command

# Interactive first-time setup wizard
php artisan lingua:install

πŸ“€ Publishing

Lingua ships several publishable groups so you can override only what you need.

Publish everything at once

php artisan vendor:publish --provider="Rivalex\Lingua\LinguaServiceProvider"

Publish individual tags

lingua-config

Publishes the configuration file to config/lingua.php.

php artisan vendor:publish --tag="lingua-config"

Use this when you want to customise routes, middleware, the language selector mode, the rich-text editor toolbar, or any other package option. The file is well-commented and safe to edit β€” Lingua reads it on every request.

lingua-migrations

Publishes the database migrations to database/migrations/.

php artisan vendor:publish --tag="lingua-migrations"

Use this when you need to modify the languages or language_lines table schema β€” for example to add indexes, change column types, or integrate with an existing translations table. After publishing, run php artisan migrate as normal.

Note: The lingua:install wizard publishes and runs the migrations automatically. Only publish manually if you need to customise the schema before running them.

lingua-translations

Publishes the package's own UI translation strings to lang/vendor/lingua/.

php artisan vendor:publish --tag="lingua-translations"

This exposes all the labels, headings, buttons, and messages used in the Lingua UI (e.g. lingua::lingua.languages.title, lingua::lingua.translations.save). Override any string to translate the interface into your application's language or to adapt the wording to your project's style.

The published files follow the standard Laravel vendor translation structure:

lang/
└── vendor/
    └── lingua/
        └── en/
            └── lingua.php

lingua-views

Publishes all Blade and Livewire views to resources/views/vendor/lingua/.

php artisan vendor:publish --tag="lingua-views"

Use this to customise the look and layout of the Languages page, Translations page, individual translation rows, modals, or the language selector component. Laravel will use your published views instead of the package's defaults.

The full view tree is:

resources/views/vendor/lingua/
β”œβ”€β”€ components/               # Blade anonymous components
β”‚   β”œβ”€β”€ autocomplete.blade.php
β”‚   β”œβ”€β”€ clipboard.blade.php
β”‚   β”œβ”€β”€ editor.blade.php
β”‚   β”œβ”€β”€ language-flag.blade.php
β”‚   β”œβ”€β”€ menu-group.blade.php
β”‚   └── message.blade.php
└── livewire/                 # Livewire component views
    β”œβ”€β”€ languages.blade.php
    β”œβ”€β”€ language-selector.blade.php
    β”œβ”€β”€ translations.blade.php
    └── translation/
        β”œβ”€β”€ create.blade.php
        β”œβ”€β”€ delete.blade.php
        β”œβ”€β”€ row.blade.php
        └── update.blade.php

Tip: Only publish views you intend to change. Unpublished views are served directly from the package and will receive upstream updates automatically.

lingua-assets

Publishes the compiled CSS and JavaScript assets to public/vendor/lingua/.

php artisan vendor:publish --tag="lingua-assets"

This is required only if you serve assets from public/ rather than loading them via Vite or a CDN. Re-run this command after every Lingua upgrade to keep the assets in sync with the package version.

Re-publishing after upgrades

After updating Lingua via Composer, re-publish any assets that may have changed:

# Force-overwrite previously published assets
php artisan vendor:publish --tag="lingua-assets" --force
php artisan vendor:publish --tag="lingua-translations" --force

The --force flag overwrites existing files. Omit it for views and config so your local customisations are not lost.

πŸ–₯ UI Guide

Languages page β€” /lingua/languages

The languages page is your control center for installed locales.

Available actions:

  • Add a language β€” choose from 70+ locales; files are installed and translations synced automatically
  • Remove a language β€” confirmation modal prevents accidental deletion; the default language is protected
  • Set the default language β€” one click sets the new application default
  • Reorder languages β€” drag-and-drop to control display order across the UI
  • Sync to database β€” import all local lang/ files into the database
  • Sync to local β€” export database translations back to lang/ files
  • Update via Laravel Lang β€” pull the latest strings from upstream laravel-lang packages

Each language row shows the completion percentage and a count of missing translations so you can prioritise your translation effort.

Translations page β€” /lingua/translations/{locale?}

Manage individual translation strings with a filterable, paginated table.

Available actions:

  • Search by key, group, or value
  • Filter by locale, group, or translation type (text / HTML / Markdown)
  • Show only missing translations for a locale to focus your translation work
  • Create new custom translation entries
  • Edit any string inline β€” the rich-text editor activates automatically for HTML and Markdown types
  • Delete translations globally or for a specific locale only
  • Copy the translation key to clipboard with one click

Language selector component

Embed a language switcher anywhere in your Blade layouts:

<livewire:lingua::language-selector />

Control the display mode via config or inline props:

{{-- sidebar (default), dropdown, or modal --}}
<livewire:lingua::language-selector mode="dropdown" :show-flags="false" />

Note: To show or hide the language flags, set the lingua.show_flags config option to true or false. Alternatively, use the :show-flags prop to override the config setting for a specific instance.

πŸ— Architecture

How translations are stored

Lingua stores translations in the language_lines table, extending Spatie's laravel-translation-loader. Each row holds all locales in a single JSON text column, eliminating the need for per-locale rows:

group       | key          | text
------------|--------------|--------------------------------------------------------------
validation  | required     | {"en": "The :attribute field is required.", "it": "..."}
single      | Welcome      | {"en": "Welcome", "fr": "Bienvenue", "de": "Willkommen"}

This design allows instant locale switching at runtime without additional queries per language.

Translation types

Each string is classified automatically during sync:

Type Use case Auto-detected when…
text Plain strings, labels, messages Default
html Rich content with HTML markup String contains HTML tags
markdown Markdown-formatted content String parses as Markdown

The type drives which editor is shown in the Translations UI.

Bi-directional sync

lang/en/*.php       ─┐
lang/en.json         β”‚  lingua:sync-to-database β†’  language_lines (DB)
lang/it/*.php        β”‚
lang/it.json        ──
lang/vendor/…        β”‚  ← lingua:sync-to-local
                    β”€β”˜
  • sync-to-database β€” reads every locale file (core + vendor packages) and upserts rows in language_lines, auto-creating languages records for any new locales discovered.
  • sync-to-local β€” reads every row in language_lines and writes locale-specific PHP/JSON files back to lang/, including vendor subdirectories.

Translation loading at runtime

Lingua registers a custom LinguaManager as the Laravel translation loader. At runtime it merges:

  1. File-based translations from lang/
  2. Database translations via Spatie's Db loader

Database translations take precedence, enabling live overrides without touching source files.

Locale middleware

LinguaMiddleware is automatically appended to the web middleware group on boot. It:

  1. Reads the active locale from the session (lingua.session_variable)
  2. Falls back to the database default language
  3. Calls app()->setLocale() and stores the locale in the session for the next request

πŸ§ͺ Testing

# Run the full test suite
composer test

# Run with coverage report
composer test-coverage

The suite uses Pest and covers:

  • All 5 Artisan commands β€” happy paths and error handling
  • All Livewire components β€” rendering, interactions, and event dispatching
  • Bi-directional sync operations
  • All blade components
  • Helper functions

🀝 Contributing

Contributions are welcome! Please open an issue first to discuss your proposed change, then submit a PR. Run composer lint before pushing.

πŸ“„ License

The MIT License (MIT). Please see LICENSE.md for more information.

Built with ❀️ by Alessandro Rivolta

Powered by Laravel Β· Livewire Β· Flux Β· Laravel Lang Β· Spatie