Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Lang Publisher Laravel Package

andrey-helldar/laravel-lang-publisher

Publishes Laravel localization files with a single Artisan command. It pulls translations from the laravel-lang project, lets you choose locales, and keeps your app's lang directory in sync, making it easy to add or refresh language files in Laravel projects.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package into an application that already has a lang/ directory (or let the package create it):
    composer require laravel-lang/lang --dev
    
    The package ships translations rather than runtime behaviour, so it is safe to keep in require-dev for most apps — but keep it in require if you generate/refresh locales during deploy.
  2. Publish the config and inspect it first. This is the file you will touch most often:
    php artisan vendor:publish --provider="LaravelLang\Lang\ServiceProvider"
    
    Look at config/lang-publisher.php (aliases/excludes, presets, source, path). Almost every "why didn't my file get written?" question is answered here.
  3. First real use case: add one locale and see exactly what lands on disk before doing a bulk add.
    php artisan lang:add fr
    
    You should now have lang/fr/ (validation, auth, passwords, pagination, JSON) plus entries in lang/fr.json. Open lang/fr/validation.php and confirm the file is the published copy, not a symlink into vendor/.
  4. Sanity-check at runtime with app()->setLocale('fr') and __('validation.required') — that closes the loop from artisan command to actual output.

Implementation Patterns

Locale-per-request via middleware. Resolve the locale once and set it early; don't scatter App::setLocale() calls through controllers.

// app/Http/Middleware/SetLocale.php
public function handle($request, Closure $next)
{
    $locale = $request->getPreferredLanguage(config('app.supported_locales'));
    app()->setLocale($locale ?? config('app.locale'));
    return $next($request);
}

Add locales at deploy time, not by hand. Treat locale generation as a build step so every environment is identical:

php artisan lang:add de es it --force

Wire this into your deploy script after composer install and before config:cache, and commit the resulting lang/ tree only if you intend to edit the files.

Keep your own overrides in a separate layer. Rather than editing published files (which the next update will stomp on), override individual keys in lang/{locale}/custom.php or in your app's own validation.php additions and merge them via a service provider. This survives lang:update cleanly.

Use the attribute/JSON helpers for user-facing messages. Validation keys like attributes.email and the JSON file are the two places developers actually read translations day-to-day; set them once per locale and reference them from Form Requests rather than hardcoding strings in rules.

Test the locale path, not just the happy path. A cheap, high-value pattern:

public function test_validation_message_is_localised(): void
{
    $this->withHeader('Accept-Language', 'de')
        ->post('/register', [])
        ->assertJsonPath('errors.email.0', __('validation.required', ['attribute' => 'E-Mail'], 'de'));
}

Bulk operations go through the package, not cp. Use lang:update to refresh existing locales after a package bump and the add/remove commands for adding and pruning locales — they respect the exclude list and avoid leaving orphaned directories like lang/pt_BR when you meant pt-BR.

Gotchas and Tips

  • Published files shadow vendor files. Once lang/fr/validation.php exists, Laravel reads it and never the package copy. After a package upgrade your translations are silently stale. Run php artisan lang:update (and --force where appropriate) as part of the upgrade checklist, or keep the files gitignored and regenerate on build.
  • Locale code format is a real footgun. The package and Laravel both care whether you use pt_BR, pt-BR, or pt. Pick one convention for config('app.locale'), your Accept-Language parsing, and the directory names, and enforce it in a test — mismatches produce a silent fallback to English, not an error.
  • JSON translations are exact-string keys. __('Welcome back') and __('Welcome back ') are different keys. If a string in a Blade template changes by one character, the translation silently disappears. Prefer named keys (__('auth.welcome_back')) over literal sentence keys for anything you will edit.
  • --force is destructive. It overwrites local edits in already-published locales. On a team, agree on whether lang/ is generated (gitignored, always --force) or curated (committed, --force only in CI with a clean diff check).
  • Cache and config ordering. php artisan config:cache before generating locales can pin a stale path/locale value; run locale commands first, then cache. If new translations don't appear, php artisan optimize:clear before debugging anything else.
  • Laravel 13 support (16.8.0). This release adds Laravel 13 compatibility in the source package. If you are on Laravel 12 or below, nothing changes for you and no migration is required. If you are moving an app to Laravel 13, upgrade this package in the same commit as the framework bump, then run lang:update and re-verify the lang/ diff — Laravel 13 changed several default validation/auth strings, so an update can legitimately rewrite a lot of keys. Check your composer.json constraint allows the new major before bumping.
  • Debugging checklist, in order: (1) does the file exist under lang/{locale}/? (2) is the locale string exactly what app()->getLocale() returns? (3) does the key match, including nested dot notation? (4) has config been cached? This resolves nearly every "translation isn't showing" report.
  • Extension points: the package's config aliases/excludes and presets are the supported way to customise what gets generated — prefer them over post-processing files in a shell script, which will break on the next release of the command signatures.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names