amendozaaguiar/laravel-lat-es
Laravel Lat-ES adds Latin American Spanish localization to Laravel applications, with ready-to-use translation files for validation, authentication, password reset, and pagination messages. Simply set your app locale to es to deliver polished Spanish-language interfaces faster.
Install
composer require amendozaaguiar/laravel-lat-es
Publish the translation files
The package ships lang/es/*.php files. Publish them into your app so they're editable:
php artisan vendor:publish --tag=laravel-lat-es
# or, if the package doesn't define tags:
php artisan vendor:publish --provider="Amendozaaguiar\LaravelLatEs\LaravelLatEsServiceProvider"
Confirm the files landed in your Laravel version's lang path:
lang/es/resources/lang/es/You should see auth.php, pagination.php, passwords.php, validation.php, and likely json-style files.
Point the app at Spanish
In .env:
APP_LOCALE=es
APP_FALLBACK_LOCALE=en
Or in config/app.php:
'locale' => 'es',
First use case: open any form with validation (login, registration, a FormRequest) and submit invalid data. Error messages like "El campo correo electrónico es obligatorio." should now appear instead of the English defaults. That's the fastest end-to-end smoke test that the package is wired correctly.
Where to look first
config/app.php → locale and fallback_locale.lang/es/validation.php — this is 90% of what users actually see.Publish once, commit to VCS
Treat published translations as first-class app code. Commit lang/es/ so every environment (CI, staging, prod) has identical strings and you can review copy changes in PRs. Don't rely on re-publishing in deploy scripts.
Override only what you need
You don't have to fork the whole file. Laravel merges your app's lang/es/validation.php with the package's, so you can copy just the keys you want to change:
// lang/es/validation.php
return [
'required' => 'El campo :attribute es obligatorio.',
'email' => 'Introduce una dirección de correo válida.',
// everything else falls back to the package
];
This keeps upgrades painless — pull a new package version, and your overrides survive.
Custom attribute names (the highest-impact tweak)
Default messages read "El campo name es obligatorio." Fix the field names once:
// lang/es/validation.php
'attributes' => [
'name' => 'nombre',
'email' => 'correo electrónico',
'password' => 'contraseña',
],
Or per-request in a FormRequest:
public function attributes(): array
{
return ['email' => 'correo electrónico'];
}
Localized validation in FormRequests
No extra wiring is needed — Laravel resolves messages against app()->getLocale(). Just make sure the request runs under es. If you support multiple locales, use a middleware that sets locale from the session or Accept-Language header:
public function handle($request, Closure $next)
{
app()->setLocale($request->user()?->locale ?? config('app.locale'));
return $next($request);
}
JSON translations for UI strings
The package's PHP files cover framework strings (auth, validation, pagination, passwords). Your own UI copy should live as JSON:
// lang/es.json
{
"Welcome back": "Bienvenido de nuevo",
"Save changes": "Guardar cambios"
}
Use __('Welcome back') in Blade, or @lang('Welcome back'). Keep framework strings in the PHP files and app strings in JSON — mixing them makes overrides confusing.
Pagination and auth out of the box
Once published, {{ $users->links() }} renders "Anterior / Siguiente" and failed logins return "Estas credenciales no coinciden con nuestros registros." Verify both — they're commonly forgotten and are visible to end users.
Testing translations
Assert against translation keys rather than literal Spanish strings so copy edits don't break tests:
$response->assertSessionHasErrors(['email']);
// not: assertSee('correo electrónico')
If you must assert strings, use __('validation.required', ['attribute' => 'email']) so the test follows whatever locale resolves.
Locale code must match the directory exactly. APP_LOCALE=es_ES or es_MX will not resolve lang/es/ — Laravel looks for lang/es_ES/ and silently falls back to fallback_locale. If messages stay English, this is the first thing to check. Use plain es, or copy the es directory to es_MX and tweak regionalisms.
The lang directory moved in Laravel 9. If you're upgrading an older app, translations may be published to resources/lang/es while Laravel now reads lang/es. Publishing "succeeds" but messages stay English. Confirm with app()->langPath().
Clear caches after publishing or editing. Config values like locale are cached by php artisan config:cache, and compiled views cache @lang output:
php artisan optimize:clear
# or targeted:
php artisan config:clear && php artisan view:clear
In production deploys, re-run php artisan config:cache after changing APP_LOCALE.
vendor:publish will overwrite (or skip) your edits. By default Laravel won't overwrite existing files; --force will, wiping your customizations. Never run --force in a deploy script once you've customized translations. If a new package version needs a key you don't have, diff the vendor copy:
diff vendor/amendozaaguiar/laravel-lat-es/lang/es/validation.php lang/es/validation.php
Never edit vendor/. Re-running composer update silently reverts everything. All edits belong in lang/.
Fallback behavior masks missing keys. fallback_locale=en means any key the package doesn't cover shows English rather than an error — easy to miss in QA. Temporarily set APP_FALLBACK_LOCALE=es (or check lang/en for parity) to surface gaps.
Tú vs. usted is a product decision. Community Spanish translation files vary — some use informal "Introduce tu correo", others formal "Introduzca su correo". Pick one and grep the published files for consistency; mixed register looks unpolished to native speakers. Same for regional vocabulary (ordenador vs. computadora, contraseña vs. clave).
Translation packages age quietly. Check the repo's compatibility matrix against your Laravel version before upgrading the framework. If the package lags, you can usually keep your committed lang/es/ files after removing the dependency — they're just PHP arrays with no runtime coupling. That's a clean escape hatch and worth knowing before adoption.
Pagination keys are easy to orphan. If you override pagination.php, keep the previous/next keys exactly as named; renaming them produces blank buttons with no error.
Extension points are limited by design. There's no service provider logic worth hooking — it's a file-publishing package. Your extension points are (a) per-key overrides in lang/es/, (b) attributes for field names, and (c) __() JSON files for app copy. If you need dynamic or database-backed translations, layer a package like spatie/laravel-translation-loader on top rather than trying to bend this one.
How can I help you explore Laravel packages today?