PHPackages                             rdcstarr/laravel-multilanguage - 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. rdcstarr/laravel-multilanguage

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

rdcstarr/laravel-multilanguage
==============================

A simple multilanguage package for Laravel with metadata support.

v1.2.2(7mo ago)021MITPHPPHP ^8.0

Since Sep 17Pushed 7mo agoCompare

[ Source](https://github.com/rdcstarr/laravel-multilanguage)[ Packagist](https://packagist.org/packages/rdcstarr/laravel-multilanguage)[ Docs](https://github.com/rdcstarr/laravel-multilanguage)[ RSS](/packages/rdcstarr-laravel-multilanguage/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (12)Versions (23)Used By (0)

Laravel Multilanguage
=====================

[](#laravel-multilanguage)

[![Latest Version on Packagist](https://camo.githubusercontent.com/f28686181a6bb05331c2d53d518ddb73f8189e7b6f7f4ff8344e420f5a598de0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f72646373746172722f6c61726176656c2d6d756c74696c616e67756167652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/rdcstarr/laravel-multilanguage)[![Tests](https://camo.githubusercontent.com/de54c3192233bbc34587afaaa1f3c7cf919f92f04f2e6375b3818469475918bb/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f72646373746172722f6c61726176656c2d6d756c74696c616e67756167652f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/rdcstarr/laravel-multilanguage/actions)[![Code Style](https://camo.githubusercontent.com/8c6ab896614b5a11cd2894f4a7ed7d4d618b7457432634d3690a54e40316f95c/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f72646373746172722f6c61726176656c2d6d756c74696c616e67756167652f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/rdcstarr/laravel-multilanguage/actions)[![Downloads](https://camo.githubusercontent.com/ba461607748e55836bfb41b8dc627285084325d516279f1e82ebfe1167cb1698/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f72646373746172722f6c61726176656c2d6d756c74696c616e67756167652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/rdcstarr/laravel-multilanguage)

> Elegant package for managing **multilanguage locale data** in Laravel — with intelligent per‑language caching and a fluent API.

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

[](#-features)

- 🌍 **Multiple languages** – easily switch &amp; manage localized content
- 🔑 **Key-value locale data** – structured, namespaced keys per language
- ⚡ **Smart cache** – per-language forever cache with auto invalidation
- 📦 **Batch operations** – set or fetch many keys at once
- 🔄 **Fluent API** – expressive chaining ( `localedata()->lang('en')->set(...)` )
- 🧩 **Blade directives** – simple templating helpers &amp; conditionals
- 🗄️ **Clean schema** – normalized tables with FK constraints

📦 Installation
--------------

[](#-installation)

Install via Composer:

```
composer require rdcstarr/laravel-multilanguage
```

1. (Optional) Publish migration files: ```
    php artisan vendor:publish --provider="Rdcstarr\Multilanguage\MultilanguageServiceProvider"
    ```
2. Run migrations: ```
    php artisan migrate
    ```
3. (Recommended) Use the install command (runs migrations &amp; seeds default languages): ```
    php artisan multilanguage:install
    ```

Default seeded languages: English (en), Romanian (ro), French (fr).

🛠️ Artisan Commands
-------------------

[](#️-artisan-commands)

#### Install package (migrations + seed languages)

[](#install-package-migrations--seed-languages)

```
php artisan multilanguage:install [--force]
```

- --force : Skip interactive confirmation.

🔑 Usage
-------

[](#-usage)

### Set Values

[](#set-values)

```
// Single key per language
localedata()->lang('en')->set('site.title', 'Welcome to our website');
localedata()->lang('ro')->set('site.title', 'Bine ai venit pe site-ul nostru');

// Batch (multiple keys)
localedata()->lang('en')->setMany([
    'nav.home'        => 'Home',
    'nav.about'       => 'About',
    'nav.contact'     => 'Contact',
    'site.description'=> 'Best website ever',
]);
```

### Get Values

[](#get-values)

```
$title = localedata()->lang('en')->get('site.title');
$titleWithDefault = localedata()->lang('es')->get('site.title', 'Default Title');

// Multiple
$navigation = localedata()->lang('en')->getMany(['nav.home', 'nav.about', 'nav.contact']);

// All for a language
$allEnglish = localedata()->lang('en')->all();

// Current app locale (app()->getLocale())
$localized = localedata()->get('site.title', 'Fallback');
```

### Working with Languages

[](#working-with-languages)

```
use Rdcstarr\Multilanguage\Models\Language;

// Create a language
Language::create([
    'name' => 'Spanish',
    'code' => 'es',
    'flag' => '🇪🇸'
]);

// Retrieve
$languages = Language::all();
$english   = Language::where('code', 'en')->first();

// Seed multiple values dynamically
foreach (['en','ro','fr','es'] as $lang) {
    localedata()->lang($lang)->set("demo.message", "Message for {$lang}");
}
```

### Facade

[](#facade)

```
use Rdcstarr\Multilanguage\Facades\LocaleData;

LocaleData::lang('en')->set('app.name', 'My App');
LocaleData::lang('ro')->set('app.name', 'Aplicația Mea');
$appName = LocaleData::lang('en')->get('app.name');
```

### Helper

[](#helper)

```
// Manager instance
localedata(); // same as app('localedata')

// Direct access (current locale)
$title = localedata('site.title', 'Default Title');
```

### Extra Operations

[](#extra-operations)

```
localedata()->lang('en')->has('site.title');          // existence
localedata()->lang('en')->forget('old.unused.key');   // delete one
localedata()->lang('en')->flushCache();               // clear cache for one language
localedata()->flushAllCache();                        // clear cache for all languages
```

🎨 Blade Directives
------------------

[](#-blade-directives)

```
{{-- Current locale value (with optional default) --}}
@localedata('site.title', 'Default Title')

{{-- Specific language --}}
@localedataForLang('"en"', '"site.title"', '"Default"')

{{-- Conditional (current locale) --}}
@hasLocaledata('site.title')
    {{ localedata('site.title') }}
@endhasLocaledata

{{-- Conditional (specific language) --}}
@hasLocaledataForLang('"ro"', '"site.title"')
    {{ localedata()->lang('ro')->get('site.title') }}
@endhasLocaledataForLang
```

### Placeholders

[](#placeholders)

```
// welcome.user => "Hello :NAME, your :type_plural are ready! :message_limit";
$result = localedata()->get('welcome.user')->placeholders([
    'name' => 'john doe',
    'type' => 'order',
    'message' => 'This is a very long message that will be truncated at 50 characters automatically',
]);
// Result: "Hello JOHN DOE, your orders are ready! This is a very long message that will be truncat..."
```

💡 Examples
----------

[](#-examples)

### Website Content

[](#website-content)

```
localedata()->lang('en')->setMany([
  'home.hero.title'    => 'Welcome to Our Platform',
  'home.hero.subtitle' => 'The best solution for your business',
]);
localedata()->lang('ro')->setMany([
  'home.hero.title'    => 'Bine ai venit pe Platforma Noastră',
  'home.hero.subtitle' => 'Cea mai bună soluție pentru afacerea ta',
]);
```

### SEO Meta

[](#seo-meta)

```
localedata()->lang('en')->setMany([
  'seo.home.title' => 'Home - Best Platform Ever',
  'seo.home.description' => 'Discover our amazing platform features',
]);
{{ localedata()->get('seo.' . request()->route()->getName() . '.title', 'Default') }}
```

### User Personalization

[](#user-personalization)

```
$userId = auth()->id();
localedata()->lang('en')->setMany([
  "user.{$userId}.welcome" => 'Welcome back!',
]);
localedata()->lang('ro')->setMany([
  "user.{$userId}.welcome" => 'Bine ai revenit!',
]);
```

### Product Catalog

[](#product-catalog)

```
$productId = 123;
localedata()->lang('en')->setMany([
  "product.{$productId}.name" => 'Premium Laptop',
  "product.{$productId}.description" => 'High-performance laptop',
]);
```

🎯 Placeholders
--------------

[](#-placeholders)

The package includes powerful placeholder support with default date/time placeholders and the ability to add custom ones.

### Default Placeholders (Available Automatically)

[](#default-placeholders-available-automatically)

**Date &amp; Time:**

- `:year` - 2025
- `:month` - 10
- `:month_name` - October
- `:month_short` - Oct
- `:day` - 20
- `:day_name` - Monday
- `:day_short` - Mon
- `:quarter` - 4
- `:hour` - 14 (24h)
- `:hour_12` - 2 (12h)
- `:minute` - 30
- `:second` - 45
- `:am_pm` - AM/PM
- `:am_pm_lower` - am/pm

**Complete Formats:**

- `:date` - 2025-10-20
- `:date_formatted` - 20/10/2025
- `:date_us` - 10/20/2025
- `:time` - 14:30:45
- `:time_short` - 14:30
- `:datetime` - 2025-10-20 14:30:45
- `:timestamp` - Unix timestamp
- `:iso` - 2025-10-20T14:30:45+00:00
- `:ago` - "1 second ago" (human readable)

**App Info:**

- `:app_name` - Application name from config
- `:app_env` - Environment (production, local, etc.)
- `:app_url` - Application URL

**Other:**

- `:week` - Week number
- `:day_of_year` - Day of year (1-365)
- `:days_in_month` - Days in current month
- `:timezone` - UTC

### Usage in Translations

[](#usage-in-translations)

```
localedata()->set('footer.copyright', '© :year :app_name. All rights reserved.');
// Output: © 2025 My App. All rights reserved.

localedata()->set('report.generated', 'Generated on :date at :time_short');
// Output: Generated on 2025-10-20 at 14:30

localedata()->set('greetings.time', 'It is :time, :day_name :month_name :day, :year');
// Output: It is 14:30:45, Monday October 20, 2025
```

### Custom Placeholders

[](#custom-placeholders)

#### Method 1: Config File (Recommended for static values)

[](#method-1-config-file-recommended-for-static-values)

Publish config:

```
php artisan vendor:publish --tag=multilanguage-config
```

Edit `config/multilanguage.php`:

```
return [
    'placeholders' => [
        'company_name' => env('COMPANY_NAME', 'My Company'),
        'support_email' => 'support@example.com',
        'support_phone' => '+40 123 456 789',
        'copyright_year' => date('Y'),
        'vat_number' => 'RO12345678',
    ],
];
```

**Usage:**

```
localedata()->set('footer.copyright', '© :copyright_year :company_name. All rights reserved.');
localedata()->set('contact.info', 'Contact us at :support_email or call :support_phone');
```

#### Method 2: In AppServiceProvider (For dynamic values)

[](#method-2-in-appserviceprovider-for-dynamic-values)

```
use Rdcstarr\Multilanguage\LocaleDataPlaceholders;
use App\Models\User;

public function boot()
{
    // Set multiple placeholders at once
    LocaleDataPlaceholders::setCustomPlaceholders([
        'total_users' => User::count(),
        'active_users' => User::where('active', true)->count(),
        'latest_post' => Post::latest()->first()?->title,
        'site_status' => Cache::get('site_status', 'online'),
    ]);

    // Or add individually
    LocaleDataPlaceholders::addCustomPlaceholder('active_sessions', Session::where('active', true)->count());
}
```

**Usage:**

```
localedata()->set('dashboard.stats', 'Platform Stats: :total_users users, :active_users active');
// Output: Platform Stats: 1,234 users, 567 active
```

#### Method 3: Helper Function

[](#method-3-helper-function)

```
// Single placeholder
set_placeholder('username', 'John Doe');

// Multiple placeholders
set_placeholder([
    'product_name' => 'Super Widget',
    'product_price' => '$99.99',
]);
```

#### Method 4: Runtime (Context-specific)

[](#method-4-runtime-context-specific)

```
// In controller
public function show(User $user)
{
    $greeting = localedata()->get('user.welcome', '', [
        'username' => $user->name,
        'last_login' => $user->last_login_at->diffForHumans(),
    ]);

    return view('profile', compact('greeting'));
}
```

**Translation:**

```
localedata()->set('user.welcome', 'Hello :Username! Last seen: :last_login');
// Output: Hello John Doe! Last seen: 2 hours ago
```

### Placeholder Transformations

[](#placeholder-transformations)

All placeholders (custom and default) support automatic transformations:

```
set_placeholder('company_name', 'my company');

// Available transformations:
:company_name           // my company
:Company_name           // My company (ucfirst)
:COMPANY_NAME           // MY COMPANY (uppercase)
:company_name_camel     // myCompany
:company_name_studly    // MyCompany
:company_name_snake     // my_company
:company_name_kebab     // my-company
:company_name_slug      // my-company
:company_name_plural    // my companies
:company_name_singular  // my company
:company_name_upper     // MY COMPANY
:company_name_lower     // my company
:company_name_title     // My Company
```

### Placeholder Priority

[](#placeholder-priority)

Placeholders are applied in the following order (last one overrides):

1. **Default placeholders** (date, time, app info)
2. **Config placeholders** (`config/multilanguage.php`)
3. **Custom static placeholders** (`LocaleDataPlaceholders::setCustomPlaceholders()`)
4. **Runtime placeholders** (parameter in `get()` method)

### Safe Placeholder Usage with User Input

[](#safe-placeholder-usage-with-user-input)

⚠️ **Important:** When using placeholders with user-generated content, always escape the input to prevent unwanted placeholder replacement.

#### The Problem

[](#the-problem)

```
// User searches for ":year"
$query = ':year';

// Translation
localedata()->set('search.meta_title', 'Search results for: :query');

// Without escaping
$title = localedata()->get('search.meta_title')->placeholders(['query' => $query]);
// Output: "Search results for: 2025" ❌ WRONG! :year in query was replaced
```

#### The Solution: Use `escape_placeholders()`

[](#the-solution-use-escape_placeholders)

```
// In Controller
public function search(Request $request)
{
    $query = $request->input('q');

    // ESCAPE user query
    $safeQuery = escape_placeholders($query);

    $title = localedata()->get('search.meta_title')->placeholders([
        'query' => $safeQuery
    ]);

    return view('search.results', compact('title', 'query'));
}
```

**Now it works correctly:**

```
$userInput = ':year in review';
$safe = escape_placeholders($userInput);

$title = localedata()->get('search.meta_title')->placeholders(['query' => $safe]);
// Output: "Search results for: :year in review" ✅ CORRECT!
```

#### When to Escape

[](#when-to-escape)

**✅ ALWAYS escape for:**

- User input (search queries, comments, usernames)
- User-generated titles/descriptions
- Any user-provided data in placeholders

**❌ NO need to escape for:**

- Admin-controlled database values
- Code constants
- System-calculated values (counters, dates)
- Default placeholders (`:year`, `:app_name`, etc.)

#### Alternative Escape Methods

[](#alternative-escape-methods)

```
// Method 1: Helper function (recommended)
$safe = escape_placeholders($userInput);

// Method 2: Static method
use Rdcstarr\Multilanguage\LocaleDataPlaceholders;
$safe = LocaleDataPlaceholders::escape($userInput);

// Method 3: Facade
use Rdcstarr\Multilanguage\Facades\Placeholders;
$safe = Placeholders::escape($userInput);
```

#### Practical Examples

[](#practical-examples)

**Search Results:**

```
Route::get('/search', function (Request $request) {
    $query = escape_placeholders($request->input('q'));

    $title = localedata()->get('search.meta_title')->placeholders([
        'query' => $query, // Safe!
    ]);

    return view('search', compact('title'));
});
```

**User Profile:**

```
public function show(User $user)
{
    $metaTitle = localedata()->get('profile.meta_title')->placeholders([
        'username' => escape_placeholders($user->name), // Escape username
        // :app_name and :year are safe (default placeholders)
    ]);

    return view('profile.show', compact('user', 'metaTitle'));
}
```

**Comment System:**

```
public function store(Request $request, Post $post)
{
    $notification = localedata()->get('comment.notification')->placeholders([
        'username' => escape_placeholders(auth()->user()->name),
        'comment_preview' => escape_placeholders(Str::limit($request->content, 50)),
    ]);
}
```

For more details on safe placeholder usage, see the **Safe Placeholder Usage with User Input** section above.

### Real-World Examples

[](#real-world-examples)

#### Footer Copyright

[](#footer-copyright)

```
// Config
'placeholders' => [
    'company_name' => 'Acme Corporation',
    'year' => date('Y'),
],

// Translation
localedata()->set('footer.text', '© :year :company_name. Made with ❤️ in Romania');
// Output: © 2025 Acme Corporation. Made with ❤️ in Romania
```

#### Live Statistics

[](#live-statistics)

```
// AppServiceProvider
LocaleDataPlaceholders::setCustomPlaceholders([
    'total_users' => Cache::remember('stats.users', 3600, fn() => User::count()),
    'total_posts' => Cache::remember('stats.posts', 3600, fn() => Post::count()),
    'total_comments' => Cache::remember('stats.comments', 3600, fn() => Comment::count()),
]);

// Translation
localedata()->set('stats.overview', 'We have :total_users users who created :total_posts posts with :total_comments comments!');
```

#### Personalized Messages

[](#personalized-messages)

```
// In controller
$message = localedata()->get('user.welcome', '', [
    'username' => auth()->user()->name,
    'unread_count' => auth()->user()->unreadNotifications()->count(),
]);

// Translation
localedata()->set('user.welcome', 'Welcome back, :Username! You have :unread_count new notifications.');
// Output: Welcome back, John! You have 5 new notifications.
```

#### Product Catalog

[](#product-catalog-1)

```
// AppServiceProvider
$productId = 123;
LocaleDataPlaceholders::setCustomPlaceholders([
    'site_name' => config('app.name'),
    'total_products' => Product::count(),
]);

// Translation
localedata()->set('home.hero', 'Welcome to :site_name! We have :total_products amazing products.');
```

#### Email Subject

[](#email-subject)

```
// Mailable
public function build()
{
    $userName = escape_placeholders($this->user->name);

    return $this->subject(
        localedata()->get('email.welcome.subject')->placeholders([
            'username' => $userName,
        ])
    );
}

// Translation
localedata()->set('email.welcome.subject', 'Welcome :username! Your account on :app_name');
```

### Closure Support

[](#closure-support)

For complex logic, use Closures:

```
LocaleDataPlaceholders::addCustomPlaceholder('dynamic_greeting', function($content) {
    $hour = now()->hour;
    if ($hour < 12) return "Good morning, $content";
    if ($hour < 18) return "Good afternoon, $content";
    return "Good evening, $content";
});

// In translation with XML tag
localedata()->set('greeting', ':username, welcome to our site!');
```

### Debugging Placeholders

[](#debugging-placeholders)

```
// View all custom placeholders
$custom = LocaleDataPlaceholders::getCustomPlaceholders();
dd($custom);

// Clear custom placeholders (useful in tests)
LocaleDataPlaceholders::clearCustomPlaceholders();
```

### Best Practices

[](#best-practices)

1. **Use config for static values** (company name, contact info)
2. **Use static placeholders for cached values** (user counts, statistics)
3. **Use runtime placeholders for context-specific data** (user names, IDs)
4. **Cache expensive queries** when using in placeholders
5. **Always escape user input** before using in placeholders
6. **Test transformations** to find the best fit for your use case

⚡ Performance
-------------

[](#-performance)

- Per-language cache buckets
- Forever cache via rememberForever
- Automatic invalidation on writes / deletes
- Minimal queries (one load per language as needed)
- Batch write operations

🧪 Testing
---------

[](#-testing)

```
composer test
```

📖 Resources
-----------

[](#-resources)

- [Changelog](CHANGELOG.md) for more information on what has changed recently. ✍️

👥 Credits
---------

[](#-credits)

- [Rdcstarr](https://github.com/rdcstarr) 🙌

📜 License
---------

[](#-license)

- [License](LICENSE.md) for more information. ⚖️

###  Health Score

34

—

LowBetter than 75% of packages

Maintenance64

Regular maintenance activity

Popularity6

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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

Every ~3 days

Recently: every ~9 days

Total

22

Last Release

220d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/42062586?v=4)[rdcstarr](/maintainers/rdcstarr)[@rdcstarr](https://github.com/rdcstarr)

---

Top Contributors

[![rdcstarr](https://avatars.githubusercontent.com/u/42062586?v=4)](https://github.com/rdcstarr "rdcstarr (25 commits)")

---

Tags

laravelmetadatamultilanguagelaravel multilanguageRdcstarr

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/rdcstarr-laravel-multilanguage/health.svg)

```
[![Health](https://phpackages.com/badges/rdcstarr-laravel-multilanguage/health.svg)](https://phpackages.com/packages/rdcstarr-laravel-multilanguage)
```

###  Alternatives

[spatie/laravel-permission

Permission handling for Laravel 12 and up

12.9k102.4M1.4k](/packages/spatie-laravel-permission)[spatie/laravel-pdf

Create PDFs in Laravel apps

1.0k4.8M47](/packages/spatie-laravel-pdf)[dedoc/scramble

Automatic generation of API documentation for Laravel applications.

2.1k11.2M100](/packages/dedoc-scramble)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

816333.3k3](/packages/defstudio-telegraph)[spatie/laravel-passkeys

Use passkeys in your Laravel app

471890.7k39](/packages/spatie-laravel-passkeys)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.6k](/packages/rawilk-profile-filament-plugin)

PHPackages © 2026

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