Skip to main content

Overview

Cashify supports multiple languages through Laravel’s built-in localization features. Currently, the application includes full translations for:
  • English (en) - Default language
  • Bulgarian (bg) - Bulgarian translations

Configuration

Application Locale Settings

Locale configuration is managed in config/app.php and can be overridden via environment variables:
config/app.php
return [
    'locale' => env('APP_LOCALE', 'en'),
    'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
    'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
];

Environment Variables

Set the default locale in your .env file:
.env
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_LOCALE
string
default:"en"
The default locale for the application. Determines which language is displayed by default.
APP_FALLBACK_LOCALE
string
default:"en"
The fallback locale used when a translation is missing in the current locale.

Language Files

Translation files are stored in the lang/ directory, organized by locale:
lang/
├── en/
│   ├── auth.php
│   ├── pagination.php
│   ├── passwords.php
│   └── validation.php
└── bg/
    ├── auth.php
    ├── pagination.php
    ├── passwords.php
    └── validation.php

Authentication Messages

Authentication error messages are localized:
<?php

return [
    'failed' => 'These credentials do not match our records.',
    'password' => 'The provided password is incorrect.',
    'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
];

Validation Messages

Validation error messages are fully translated:
<?php

return [
    'required' => 'The :attribute field is required.',
    'email' => 'The :attribute must be a valid email address.',
    'unique' => 'The :attribute has already been taken.',
    'confirmed' => 'The :attribute confirmation does not match.',
    // ... more validation rules
];

Password Reset Messages

<?php

return [
    'reset' => 'Your password has been reset.',
    'sent' => 'We have emailed your password reset link.',
    'throttled' => 'Please wait before retrying.',
    'token' => 'This password reset token is invalid.',
    'user' => "We can't find a user with that email address.",
];

Pagination Messages

<?php

return [
    'previous' => '&laquo; Previous',
    'next' => 'Next &raquo;',
];

Runtime Locale Switching

Cashify implements runtime locale switching using session-based storage.

SetLocale Middleware

The SetLocale middleware applies the user’s selected locale:
app/Http/Middleware/SetLocale.php
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class SetLocale
{
    /**
     * Handle an incoming request.
     */
    public function handle(Request $request, Closure $next): Response
    {
        if (session()->has('locale')) {
            app()->setLocale(session('locale'));
        }

        return $next($request);
    }
}

Register Middleware

Register the middleware in your application’s middleware stack:
bootstrap/app.php
use App\Http\Middleware\SetLocale;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->web(append: [
            SetLocale::class,
        ]);
    })
    ->create();

Switching Locale

Create a route and controller to switch locales:
routes/web.php
Route::post('/locale', function (Request $request) {
    $locale = $request->input('locale');
    
    if (in_array($locale, ['en', 'bg'])) {
        session(['locale' => $locale]);
    }
    
    return redirect()->back();
})->name('locale.switch');

Frontend Language Switcher

Add a language switcher to your layout:
resources/views/components/locale-switcher.blade.php
<form method="POST" action="{{ route('locale.switch') }}">
    @csrf
    <select name="locale" onchange="this.form.submit()" 
            class="border rounded px-3 py-2">
        <option value="en" {{ app()->getLocale() === 'en' ? 'selected' : '' }}>
            English
        </option>
        <option value="bg" {{ app()->getLocale() === 'bg' ? 'selected' : '' }}>
            Български
        </option>
    </select>
</form>

Using Translations in Code

In Blade Templates

Use the __() helper or @lang directive:
<!-- Using the __() helper -->
<h1>{{ __('Welcome to Cashify') }}</h1>

<!-- Using @lang directive -->
<p>@lang('auth.failed')</p>

<!-- With parameters -->
<p>{{ __('auth.throttle', ['seconds' => 60]) }}</p>

In Controllers

Use the __() helper function:
public function store(Request $request)
{
    // Validation with translated messages happens automatically
    $request->validate([
        'email' => 'required|email',
        'password' => 'required',
    ]);
    
    // Custom translated flash message
    return redirect()->back()->with('success', __('Profile updated successfully'));
}

In JavaScript

For frontend translations, you can expose Laravel translations to JavaScript:
<script>
    window.translations = @json([
        'save' => __('Save'),
        'cancel' => __('Cancel'),
        'delete_confirm' => __('Are you sure you want to delete this?'),
    ]);
</script>

Adding a New Language

To add support for a new language:
1

Create Language Directory

Create a new directory under lang/ with the locale code:
mkdir lang/es  # For Spanish
2

Copy Translation Files

Copy the English translation files as a template:
cp lang/en/*.php lang/es/
3

Translate Messages

Edit each file and translate the messages:
lang/es/auth.php
return [
    'failed' => 'Estas credenciales no coinciden con nuestros registros.',
    'password' => 'La contraseña proporcionada es incorrecta.',
    'throttle' => 'Demasiados intentos de inicio de sesión. Por favor intente de nuevo en :seconds segundos.',
];
4

Update Locale Switcher

Add the new language to your locale switcher:
<option value="es" {{ app()->getLocale() === 'es' ? 'selected' : '' }}>
    Español
</option>
5

Update Validation

Update your locale validation to include the new language:
if (in_array($locale, ['en', 'bg', 'es'])) {
    session(['locale' => $locale]);
}

Translation Best Practices

Use Translation Keys

Avoid hardcoding text in your views:
<button>Save Changes</button>

Organize Translation Files

Group related translations into logical files:
lang/
├── en/
│   ├── auth.php          # Authentication messages
│   ├── transactions.php  # Transaction-related messages
│   ├── accounts.php      # Account-related messages
│   ├── categories.php    # Category-related messages
│   └── common.php        # Common UI messages

Use Placeholders

Use placeholders for dynamic content:
lang/en/transactions.php
return [
    'created' => 'Transaction created successfully.',
    'updated' => 'Transaction updated successfully.',
    'deleted' => 'Transaction deleted successfully.',
    'amount_format' => 'Amount: :amount :currency',
];
Usage:
__('transactions.amount_format', [
    'amount' => number_format($amount, 2),
    'currency' => 'USD'
])

Pluralization

Laravel supports pluralization in translations:
lang/en/transactions.php
return [
    'count' => '{0} No transactions|{1} One transaction|[2,*] :count transactions',
];
Usage:
trans_choice('transactions.count', $count)

Available Locales

Cashify currently includes:

English (en)

Default language with complete translations

Bulgarian (bg)

Full Bulgarian translations available

Testing Localization

Test your translations with different locales:
tests/Feature/LocalizationTest.php
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class LocalizationTest extends TestCase
{
    public function test_authentication_messages_are_translated()
    {
        app()->setLocale('bg');
        
        $response = $this->post('/login', [
            'email' => '[email protected]',
            'password' => 'wrong',
        ]);
        
        $response->assertSessionHasErrors();
        $this->assertEquals('bg', app()->getLocale());
    }
    
    public function test_locale_persists_in_session()
    {
        $this->post('/locale', ['locale' => 'bg']);
        
        $this->assertEquals('bg', session('locale'));
    }
}

Caching Translations

For better performance in production, cache your translations:
# Cache translations
php artisan lang:publish
php artisan optimize

# Clear translation cache
php artisan optimize:clear

Common Translation Strings

Here are commonly used translation strings you may need:
lang/en/common.php
return [
    'save' => 'Save',
    'cancel' => 'Cancel',
    'delete' => 'Delete',
    'edit' => 'Edit',
    'create' => 'Create',
    'update' => 'Update',
    'search' => 'Search',
    'filter' => 'Filter',
    'actions' => 'Actions',
    'confirm_delete' => 'Are you sure you want to delete this?',
    'success' => 'Operation completed successfully.',
    'error' => 'An error occurred. Please try again.',
];

Next Steps

Environment Variables

Configure locale-related environment variables

Authentication

Localized authentication messages

Build docs developers (and LLMs) love