Easy i18n localization for Laravel 4, an useful tool to combine with Laravel localization classes.
Add Laravel Localization to your composer.json
file.
"mcamara/laravel-localization": "0.13.*"
Run composer install
to get the latest version of the package.
It's recommended that you use Composer, however you can download and install from this repository.
Laravel Localization comes with a service provider for Laravel 4. You'll need to add it to your composer.json
as mentioned in the above steps, then register the service provider with your application.
Open app/config/app.php
and find the providers
key. Add LaravelLocalizationServiceProvider
to the array.
...
'Mcamara\LaravelLocalization\LaravelLocalizationServiceProvider'
...
You can also add an alias to the list of class aliases in the same app.php
...
'LaravelLocalization' => 'Mcamara\LaravelLocalization\Facades\LaravelLocalization'
...
To finish, publish the configuration file using the command php artisan config:publish mcamara/laravel-localization
in your laravel root path. This will create the following file app/config/packages/mcamara/laravel-localization/config.php
, containing the most common setting options.
Laravel Localization uses the URL given for the request. In order to achieve this purpose, a group should be added into the routes.php file. It will filter all pages that must be localized.
// app/routes.php
Route::group(array('prefix' => LaravelLocalization::setLocale()), function()
{
/** ADD ALL LOCALIZED ROUTES INSIDE THIS GROUP **/
Route::get('/', function()
{
return View::make('hello');
});
Route::get('test',function(){
return View::make('test');
});
});
/** OTHER PAGES THAT SHOULD NOT BE LOCALIZED **/
Once this group is added to the routes file, a user can access all locales added into 'supportedLocales' ('en' and 'es' by default, look at the config section to change that option). For example, a user can now access to two different locales, using the following addresses:
http://url-to-laravel/en
http://url-to-laravel/es
http://url-to-laravel
If the locale is not present in the url or it is not defined in 'supportedLocales', the system will use the application default locale or the user's browser default locale (if defined in config file).
Once the locale is defined, the locale variable will be stored in a session, so it is not necessary to write the /lang/ section in the url after defining it once, using the last known locale for the user. If the user accesses to a different locale this session value would be changed, translating any other page he visits with the last chosen locale.
Templates files and all locale files should follow the Lang class.
Moreover, this package includes a filter to redirect all "non-localized" routes to a "localized" one (thanks to Sangar82).
So, if a user accesses to http://url-to-laravel/test and the system have this filter active and 'en' as a current locale for this user, it would redirect (301) him automatically to http://url-to-laravel/en/test. This is mainly used to avoid duplicate content and improve SEO performance.
// app/routes.php
Route::group(
array(
'prefix' => LaravelLocalization::setLocale(),
'before' => 'LaravelLocalizationRedirectFilter' // LaravelLocalization filter
),
function()
{
/** ADD ALL LOCALIZED ROUTES INSIDE THIS GROUP **/
Route::get('/', function()
{
return View::make('hello');
});
Route::get('test',function(){
return View::make('test');
});
});
/** OTHER PAGES THAT SHOULD NOT BE LOCALIZED **/
In order to active it, you just have to attach this filter to the routes you want to be accessible localized.
If you want to hide the default locale but always show other locales in the url, switch the 'hideDefaultLocaleInURL' config value to true. Once it's true, if the default locale is en (english) all URLs containing /en/ would be redirected to the same url without this fragment '/' but maintaining the locale as en (English).
IMPORTANT - When hideDefaultLocaleInURL is set to true, the unlocalized root is treated as the applications default locale app.locale
. Because of this language negotiation using the Accept-Language header will NEVER occur when hideDefaultLocaleInURL is true.
This package comes with some useful functions, like:
/**
* It returns an URL without locale (if it has it)
*
* @param string $url URL to clean, if false, current url would be taken
*
* @return string URL with no locale in path
*/
public function getNonLocalizedURL($url = null)
//Should be called in a view like this:
{{ LaravelLocalization::getNonLocalizedURL(optional string $url) }}
It returns a URL clean of any localization.
/**
* Returns an URL adapted to $locale
*
* @param string $locale Locale to adapt
* @param string $url URL to adapt. If not passed, the current url would be taken
*
* @throws UnsupportedLocaleException
*
* @return string URL translated
*/
public function getLocalizedURL($locale, $url = null)
//Should be called in a view like this:
{{ LaravelLocalization::getLocalizedURL(string $locale, optional string $url) }}
or
/**
* Returns an URL adapted to $locale or current locale
*
* @param string $url URL to adapt. If not passed, the current url would be taken.
* @param string|boolean $locale Locale to adapt, false to remove locale
*
* @throws UnsupportedLocaleException
*
* @return string URL translated
*/
public function localizeURL($url, $locale = null)
It returns a URL localized to the desired locale.
/**
* Returns an URL adapted to the route name and the locale given
*
* @param string $locale Locale to adapt
* @param string $transKeyName Translation key name of the url to adapt
* @param array $attributes Attributes for the route (only needed if transKeyName needs them)
*
* @return string|boolean URL translated
*/
public function getURLFromRouteNameTranslated($locale, $transKeyName = null, $attributes = array())
//Should be called in a view like this:
{{ LaravelLocalization::getURLFromRouteNameTranslated(string $locale, optional string $transKeyName, optional array $attributes) }}
It returns a route, localized to the desired locale using the locale passed. If the translation key does not exist in the locale given, this function will return false.
/**
* Return an array of all supported Locales
*
* @return array
*/
public function getSupportedLocales()
//Should be called like this:
{{ LaravelLocalization::getSupportedLocales() }}
This function will return all supported locales and their properties as an array.
/**
* Set and return current locale
*
* @param string $locale Locale to set the App to (optional)
*
* @return string Returns locale (if route has any) or null (if route does not have a locale)
*/
public function setLocale($locale = null)
//Should be called in a view like this:
{{ LaravelLocalization::setLocale(optional string $locale) }}
This function will change the application's current locale. If the locale is not passed, the locale will be determined via a cookie (if stored previously), the session (if stored previously), browser Accept-Language header or the default application locale (depending on your config file).
The function have to be called in the prefix of any route that should be translated (see Filters sections for further information).
/**
* Returns current locale name
*
* @return string current locale name
*/
public function getCurrentLocaleName()
//Should be called in a view like this:
{{ LaravelLocalization::getCurrentLocaleName() }}
This function will return current locale name as string (English/Spanish/Arabic/ ..etc).
/**
* Returns current locale direction
*
* @return string current locale direction
*/
public function getCurrentLocaleDirection()
//Should be called in a view like this:
{{ LaravelLocalization::getCurrentLocaleDirection() }}
This function will return current locale direction as string (ltr/rtl).
/**
* Returns current locale script
*
* @return string current locale script
*/
public function getCurrentLocaleScript()
//Should be called in a view like this:
{{ LaravelLocalization::getCurrentLocaleScript() }}
This function will return the ISO 15924 code for the current locale script as a string; "Latn", "Cyrl", "Arab", etc.
If you're supporting multiple locales in your project your going to want to provide the users with a way to change language. Below is a simple example of blade template code you can use to create your own language selector.
<ul class="language_bar_chooser">
@foreach(LaravelLocalization::getSupportedLocales() as $localeCode => $properties)
<li>
<a rel="alternate" hreflang="{{$localeCode}}" href="{{LaravelLocalization::getLocalizedURL($localeCode) }}">
{{{ $properties['native'] }}}
</a>
</li>
@endforeach
</ul>
New in version 0.5
You can adapt your URLs depending on the language you want to show them. For example, http://url/en/about and http://url/es/acerca (acerca is about in spanish) or http://url/en/view/5 and http://url/es/ver/5 (view == ver in spanish) would be redirected to the same controller using the proper filter and setting up the translation files as follows:
// app/routes.php
Route::group(
array(
'prefix' => LaravelLocalization::setLocale(),
'before' => 'LaravelLocalizationRoutes' // Route translate filter
),
function()
{
/** ADD ALL LOCALIZED ROUTES INSIDE THIS GROUP **/
Route::get('/', function()
{
// This routes is useless to translate
return View::make('hello');
});
Route::get(LaravelLocalization::transRoute('routes.about'),function(){
return View::make('about');
});
Route::get(LaravelLocalization::transRoute('routes.view'),function($id){
return View::make('view',array('id'=>$id));
});
});
/** OTHER PAGES THAT SHOULD NOT BE LOCALIZED **/
In the routes file you just have to add the LaravelLocalizationRoutes
filter and the LaravelLocalization::transRoute
function to every route you want to translate using the translation key.
Tip: If you want to use this filter with other filters (like LaravelLocalizationRedirectFilter
) you just have to join them in the Laravel way, using | (eg: 'before' => 'LaravelLocalizationRoutes|LaravelLocalizationRedirectFilter'
)
Then you have to create the translation files and add there every key you want to translate. I suggest you to create a routes.php file inside your app/lang/language_abbreviation folder. For the previous example, I have created two translations files, these two files would look like:
// app/lang/en/routes.php
return array(
"about" => "about",
"view" => "view/{id}", //we add a route parameter
// other translated routes
);
// app/lang/es/routes.php
return array(
"about" => "acerca",
"view" => "ver/{id}", //we add a route parameter
// other translated routes
);
Once files are saved, you can access to http://url/en/about , http://url/es/acerca , http://url/en/view/5 and http://url/es/ver/5 without any problem. The getLanguageBar function would work as desired and it will translate the routes to all translated languages (don't forget to add any new route to the translation file).
You can capture the URL parameters during translation if you wish to translate them too. To do so, just create an event listener for the routes.translation
event like so :
Event::listen('routes.translation', function($locale, $attributes)
{
// Do your magic
return $attributes;
});
Be sure to pass the locale and the attributes as parameters for your closure. You can also use Event Subscribers, see : http://laravel.com/docs/events#event-subscribers
By default only english and spanish are allowed but it can be changed using config.php file that is located at app/config/packages/mcamara/laravel-localization/config.php
. If this file does not exist, use the following artisan command php artisan config:publish mcamara/laravel-localization
in order to create it.
This file have some interesting configuration settings (as the allowed locales or browser language detection, among others) feel free to play with it, all variables are self-explained.
View changelog here -> changelog
Laravel Localization is an open-sourced laravel package licensed under the MIT license