PHPackages                             rivalex/lingua - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Localization &amp; i18n](/categories/localization)
4. /
5. rivalex/lingua

ActiveLibrary[Localization &amp; i18n](/categories/localization)

rivalex/lingua
==============

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

v1.0.0(1mo ago)21↓100%MITPHPPHP ^8.4CI passing

Since Mar 18Pushed 1mo agoCompare

[ Source](https://github.com/rivalex/lingua)[ Packagist](https://packagist.org/packages/rivalex/lingua)[ Docs](https://github.com/rivalex/lingua)[ GitHub Sponsors]()[ RSS](/packages/rivalex-lingua/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (3)Dependencies (17)Versions (2)Used By (0)

[![Lingua Logo](resources/images/logoLinguaHorizzontal.svg)](https://rivalex.github.io/lingua-docs/)---

### **The complete multilingual management system for Laravel**

[](#the-complete-multilingual-management-system-for-laravel)

[![Latest Version on Packagist](https://camo.githubusercontent.com/1ef683950c2052b60afe207e30e0794085f533620ee28b3435774c08172e5f67/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f726976616c65782f6c696e6775612e737667)](https://packagist.org/packages/rivalex/lingua)[![PHP Version](https://camo.githubusercontent.com/80c4564163cef31b2a66baaeb95a5bf4a418bcb5242a5ae707b94c2f4811e742/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e342532422d626c7565)](https://php.net)[![Laravel Version](https://camo.githubusercontent.com/e1f6a4c2d81a26c7350d3e5a170429baa581879e90aee82c222d49176489402a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d31312d2d31332d6f72616e6765)](https://laravel.com)[![License](https://camo.githubusercontent.com/a454d9426c957a4e3ec9a8a5a4501f99b6511a43583f0d3a16fdccf578b847f7/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f726976616c65782f6c696e677561)](LICENSE.md)[![codecov](https://camo.githubusercontent.com/e191a984b3777a5a84b8a2b0c71ee2205f2b7cc4ef67bd2d59c243505966ac69/68747470733a2f2f636f6465636f762e696f2f6769746875622f726976616c65782f6c696e6775612f6272616e63682f6d61696e2f67726170682f62616467652e7376673f746f6b656e3d39524b52423841594436)](https://codecov.io/github/rivalex/lingua)[![Tests](https://github.com/rivalex/lingua/actions/workflows/run-tests.yml/badge.svg)](https://github.com/rivalex/lingua/actions/workflows/run-tests.yml)

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](#-features) · [Installation](#-installation) · [Configuration](#-configuration) · [Artisan Commands](#-artisan-commands) · [Publishing](#-publishing) · [UI Guide](#-ui-guide) · [Facade](#-lingua-facade) · [Architecture](#-architecture)

---

[Official Documentation](https://rivalex.github.io/lingua-docs/)
----------------------------------------------------------------

[](#official-documentation)

---

✨ Features
----------

[](#-features)

FeatureDescription**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**Lingua Facade**Fluent programmatic API for reading, writing, and managing languages and translations**Fully tested**150+ tests with Pest, covering commands, Livewire components, Blade components, helpers, and the Lingua facade---

📦 Requirements
--------------

[](#-requirements)

- PHP **8.2+**
- Laravel **11 | 12 | 13**
- Livewire **4.0+**
- Livewire Flux **2.0+**

---

🚀 Installation
--------------

[](#-installation)

### 1. Install via Composer

[](#1-install-via-composer)

```
composer require rivalex/lingua
```

### 2. Run the interactive installer

[](#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

[](#3-access-the-ui)

PageURLRoute nameLanguages`your-app.test/lingua/languages``lingua.languages`Translations`your-app.test/lingua/translations/{locale?}``lingua.translations`---

⚙️ Configuration
----------------

[](#️-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
------------------

[](#-artisan-commands)

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

### Language management

[](#language-management)

CommandDescription`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

[](#translation-sync)

CommandDescription`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

[](#install-command)

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

---

📤 Publishing
------------

[](#-publishing)

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

### Publish everything at once

[](#publish-everything-at-once)

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

### Publish individual tags

[](#publish-individual-tags)

#### `lingua-config`

[](#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`

[](#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`

[](#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`

[](#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`

[](#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

[](#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
----------

[](#-ui-guide)

### Languages page — `/lingua/languages`

[](#languages-page--lingualanguages)

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?}`

[](#translations-page--linguatranslationslocale)

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

### RTL / LTR text direction

[](#rtl--ltr-text-direction)

Some languages (Arabic, Hebrew, Persian, Urdu, …) are written right-to-left. Lingua stores the text direction for every installed language and exposes it via `Lingua::getDirection()`. To support RTL layouts correctly you need to propagate the direction to the root `` tag so that the browser, CSS, and screen readers all behave correctly.

Add `dir` and `lang` attributes to the `` element in your main Blade layout:

```
{{-- resources/views/layouts/app.blade.php --}}

```

`Lingua::getDirection()` returns `'rtl'` for right-to-left languages and `'ltr'` for all others. It uses the **current application locale** by default, so it automatically follows every locale switch without any extra code.

You can also pass an explicit locale when you need the direction outside of the current request context:

```
{{-- e.g. inside a per-language preview or email template --}}

```

#### Tailwind CSS

[](#tailwind-css)

If your project uses Tailwind CSS, the `dir` attribute on `` activates Tailwind's built-in `rtl:` variant automatically — no additional configuration required:

```
…
…
```

#### CSS logical properties (recommended)

[](#css-logical-properties-recommended)

For new layouts, prefer CSS logical properties over directional ones so the browser handles the flip for you:

```
/* Instead of: padding-left / padding-right */
padding-inline-start:

1
rem

; /* left in LTR, right in RTL */
padding-inline-end:

1
rem

;

/* Instead of: border-left */
border-inline-start:

1
px solid

;
```

#### Checking direction in Blade

[](#checking-direction-in-blade)

```
@if (Lingua::getDirection() === 'rtl')
    {{-- RTL-specific markup or classes --}}
@endif
```

> **Note:** `Lingua::getDirection()` defaults to `'ltr'` if the locale is not found in the database, so it is always safe to call even before any language is installed.

---

### Language selector component

[](#language-selector-component)

Embed a language switcher anywhere in your Blade layouts:

```

```

Control the display mode via config or inline props:

```
{{-- sidebar (default), dropdown, or modal --}}

```

> **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.

---

💎 Lingua Facade
---------------

[](#-lingua-facade)

Lingua ships a static `Lingua` facade that gives you programmatic access to language and translation data from anywhere in your application.

### Locale helpers

[](#locale-helpers)

```
use Rivalex\Lingua\Facades\Lingua;

// Current application locale (mirrors app()->getLocale())
Lingua::getLocale();          // 'en'

// Locale marked as default in the database
Lingua::getDefaultLocale();   // 'en'

// Check whether a locale is the default
Lingua::isDefaultLocale();          // true  — uses current app locale
Lingua::isDefaultLocale('fr');      // false

// Check whether a locale is installed
Lingua::hasLocale('fr');      // true / false

// Change the default locale (persisted in the database)
Lingua::setDefaultLocale('fr');
```

### Language metadata

[](#language-metadata)

```
// English display name for a locale
Lingua::getLocaleName();          // 'English'  — uses current locale
Lingua::getLocaleName('fr');      // 'French'

// Native name
Lingua::getLocaleNative();        // 'English'
Lingua::getLocaleNative('ar');    // 'العربية'

// Text direction
Lingua::getDirection();           // 'ltr'
Lingua::getDirection('ar');       // 'rtl'
```

### Language collections

[](#language-collections)

```
// All installed languages (Eloquent Collection)
Lingua::languages();

// All languages with completion statistics
// Each model includes: total_strings, translated_strings, missing_strings, completion_percentage
Lingua::languagesWithStatistics();
```

### Translation statistics

[](#translation-statistics)

```
// Stats for a specific locale (or current locale if omitted)
Lingua::getLocaleStats('fr');
// [
//   'total'      => 1240,
//   'translated' => 980,
//   'missing'    => 260,
//   'percentage' => 79.03,
// ]
```

### Reading translations

[](#reading-translations)

```
// All locale variants for a key (returns ?array)
Lingua::getTranslations('welcome');
// ['en' => 'Welcome', 'fr' => 'Bienvenue', 'de' => 'Willkommen']

// Single locale value (empty string if missing)
Lingua::getTranslation('welcome');           // uses current locale
Lingua::getTranslation('welcome', 'fr');     // 'Bienvenue'

// All translations for a group, optionally filtered to a locale
Lingua::getTranslationByGroup('validation');
Lingua::getTranslationByGroup('validation', 'fr'); // only rows that have a French value

// Raw Eloquent collection
Lingua::translations();
```

### Writing &amp; deleting translations

[](#writing--deleting-translations)

```
// Set a translation value (creates or updates; uses current locale if omitted)
Lingua::setTranslation('welcome', 'Bienvenue', 'fr');
Lingua::setTranslation('welcome', 'Welcome');          // current locale

// Remove a locale's value from a translation key
// If the locale is the default, the entire record is deleted
Lingua::forgetTranslation('welcome', 'fr');
Lingua::forgetTranslation('welcome');                  // current locale
```

### Language lifecycle

[](#language-lifecycle)

```
// Install language files for a locale via laravel-lang (lang:add)
Lingua::addLanguage('fr');

// Remove language files for a locale via laravel-lang (lang:rm --force)
Lingua::removeLanguage('fr');
```

> **Note:** `addLanguage()` and `removeLanguage()` only manage language files on disk. Database records (Language model) and translation rows are handled separately — use the Artisan commands `lingua:add` / `lingua:remove` for a fully orchestrated operation that covers files, DB records, and sync in one step.

### Sync

[](#sync)

```
// Import all local lang/ files into the database
Lingua::syncToDatabase();

// Export all database translations to local lang/ files
Lingua::syncToLocal();
```

---

🏗 Architecture
--------------

[](#-architecture)

### How translations are stored

[](#how-translations-are-stored)

Lingua stores translations in the `language_lines` table, extending Spatie's [laravel-translation-loader](https://github.com/spatie/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

[](#translation-types)

Each string is classified automatically during sync:

TypeUse caseAuto-detected when…`text`Plain strings, labels, messagesDefault`html`Rich content with HTML markupString contains HTML tags`markdown`Markdown-formatted contentString parses as MarkdownThe type drives which editor is shown in the Translations UI.

### Bi-directional sync

[](#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

[](#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

[](#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
---------

[](#-testing)

```
# Run the full test suite
composer test

# Run with coverage report
composer test-coverage
```

The suite uses [Pest](https://pestphp.com) 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
--------------

[](#-contributing)

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

---

📄 License
---------

[](#-license)

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

---

Built with ❤️ by [Alessandro Rivolta](https://github.com/rivalex)

Powered by [Laravel](https://laravel.com) · [Livewire](https://livewire.laravel.com) · [Flux](https://fluxui.dev) · [Laravel Lang](https://laravel-lang.com) · [Spatie](https://spatie.be)

###  Health Score

41

—

FairBetter than 89% of packages

Maintenance91

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 87% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

53d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/b5c3130d9237407ef79b7512e965bf56275c61a1930739113046af35f580f539?d=identicon)[rivalex](/maintainers/rivalex)

---

Top Contributors

[![rivalex](https://avatars.githubusercontent.com/u/580591?v=4)](https://github.com/rivalex "rivalex (47 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (4 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (3 commits)")

---

Tags

laravellocalizationi18nlanguagetranslationmultilinguallaravel-packagelivewirelocaletranslation-management

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/rivalex-lingua/health.svg)

```
[![Health](https://phpackages.com/badges/rivalex-lingua/health.svg)](https://phpackages.com/packages/rivalex-lingua)
```

###  Alternatives

[tractorcow/silverstripe-fluent

Simple localisation for Silverstripe

92421.6k26](/packages/tractorcow-silverstripe-fluent)[codezero/laravel-localized-routes

A convenient way to set up, manage and use localized routes in a Laravel app.

543638.1k4](/packages/codezero-laravel-localized-routes)[jayesh/laravel-gemini-translator

An interactive command to extract and generate Laravel translations using Gemini AI.

691.7k1](/packages/jayesh-laravel-gemini-translator)[longman/laravel-multilang

Package to integrate multi language (multi locale) functionality in Laravel 5.x

5514.4k1](/packages/longman-laravel-multilang)[smousss/laravel-globalize

Make Laravel projects translatable in a matter of seconds!

2266.3k](/packages/smousss-laravel-globalize)[awes-io/localization-helper

Package for convenient work with Laravel's localization features

3527.1k4](/packages/awes-io-localization-helper)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
