Installation Add the package via Composer:
composer require bastsys/locale-bundle
Register the bundle in config/bundles.php (Symfony) or config/app.php (Laravel via Symfony bridge):
Bastsys\LocaleBundle\BastsysLocaleBundle::class => ['all' => true],
Configuration Publish the default config:
php artisan vendor:publish --provider="Bastsys\LocaleBundle\BastsysLocaleBundle" --tag="config"
Update config/locale.php (or equivalent) to define supported locales and default locale:
return [
'locales' => ['en', 'cs', 'de'],
'default_locale' => 'en',
];
First Use Case: Localized Entity Labels
Annotate a Doctrine entity (or Eloquent model via bridge) with Locale trait:
use Bastsys\LocaleBundle\Model\LocaleTrait;
class Product
{
use LocaleTrait;
// Fields...
}
Add a name field with locale prefix (e.g., name_en, name_cs).
Access translations dynamically:
$product->getName('cs'); // Returns Czech translation
Field Naming Convention
Use field_locale (e.g., title_en, description_cs) for multi-lingual fields.
Avoid manual locale handling; leverage the LocaleTrait setter/getter methods:
$product->setName('Smartphone', 'en');
$product->getName('cs'); // Auto-fetches Czech translation
Default Locale Fallback
Configure fallback locales in config/locale.php:
'fallback_locales' => ['en' => ['cs', 'de']],
Example: If name_cs is missing, it falls back to name_en.
Dynamic Locale Switching
Use middleware (Symfony) or Laravel’s AppServiceProvider to set the locale:
// Laravel (Symfony bridge)
public function boot()
{
$locale = request()->header('Accept-Language') ?? config('locale.default_locale');
app()->setLocale($locale);
}
LocaleType for locale-aware fields:
$builder->add('name', LocaleType::class, [
'locales' => ['en', 'cs'],
'default_locale' => 'en',
]);
FormBuilder to support locale fields:
Form::localeText('name', 'Product Name', ['locales' => ['en', 'cs']]);
$product->toArray(['locale' => 'cs']); // Returns ['name' => 'Chytrý telefon']
Use a custom JSON encoder or Laravel’s App\Transformers\ProductTransformer:
public function transform(Product $product)
{
return [
'name' => $product->getName(app()->getLocale()),
// ...
];
}
locale column to translation tables or use a single table with field_locale suffixes.
Example migration:
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name_en')->nullable();
$table->string('name_cs')->nullable();
// ...
});
Locale Key Conflicts
Avoid naming conflicts with existing fields (e.g., created_at_en). Use a consistent prefix like locale_ or _<locale>.
Fix: Rename fields to locale_name_en or use a dedicated table for translations.
Missing Fallback Logic
If fallback_locales isn’t configured, missing translations return null.
Fix: Set a default fallback in config/locale.php:
'fallback_locales' => ['*' => ['en']], // Fallback to English for all locales
Performance with Many Locales
Querying all locale fields (e.g., SELECT * FROM products) bloats results.
Fix: Use a query scope or select specific fields:
$product = Product::where('id', $id)
->withLocale('en', 'cs') // Load only needed locales
->first();
Doctrine vs. Eloquent The bundle is Doctrine-first. For Laravel/Eloquent:
laravel-doctrine or rewrite accessors.public function getNameAttribute($value)
{
return $this->getName(app()->getLocale());
}
\Log::debug('Active locales:', [
'current' => app()->getLocale(),
'fallbacks' => config('locale.fallback_locales'),
]);
field_locale pattern. Use:
$this->assertTrue($product->hasName('en')); // Checks if field exists
Custom Locale Providers
Override locale resolution by implementing LocaleProviderInterface:
class SessionLocaleProvider implements LocaleProviderInterface
{
public function getLocale(): string
{
return session('locale', config('locale.default_locale'));
}
}
Register in config/locale.php:
'locale_provider' => Bastsys\LocaleBundle\Provider\SessionLocaleProvider::class,
Dynamic Locale Fields
Extend LocaleTrait to support runtime locale additions:
// In a service or trait extension
public function addLocaleField(string $field, string $locale): void
{
$this->{$field . '_' . $locale} = $this->{$field} ?? null;
}
Event Listeners
Listen for locale.before_set and locale.after_get events to log or validate translations:
// config/services.php
'locale.listeners' => [
App\Listeners\LocaleLogger::class,
];
LocaleProvider:
$locale = Cache::remember('active_locale', 3600, fn() => app()->getLocale());
RequestStack for locale detection.LocaleProvider to use Laravel’s Request or Session.How can I help you explore Laravel packages today?