12/08/2018, 16:26

How to use multiple locales in your Laravel website

Laravel mặc định hỗ trợ một ngôn ngữ hiển thị trên trang web là en, bài viết này mình sẽ đưa ra các bước thực hiện việc thêm các ngôn ngữ khác cho trang web một cách dễ dàng. Mỗi ngôn ngữ sẽ có một url kiểu như: domain.com/{locale} Các bạn chỉ cần copy và chạy thử vì code khá dễ hiểu. Mở ...

Laravel mặc định hỗ trợ một ngôn ngữ hiển thị trên trang web là en, bài viết này mình sẽ đưa ra các bước thực hiện việc thêm các ngôn ngữ khác cho trang web một cách dễ dàng. Mỗi ngôn ngữ sẽ có một url kiểu như: domain.com/{locale} Các bạn chỉ cần copy và chạy thử vì code khá dễ hiểu.

Mở config/app.php và thêm dòng dưới đây vào ngay dưới dòng 'locale' => 'en',:

'locales' => explode(',', env('APP_LOCALES', 'id,my,th')),

Đoạn code trên mình sẽ lấy giá trị của APP_LOCALES khai báo trong file .env, nếu không có giá trị thì sẽ lấy giá trị default là 'id,my,th' đại diện cho 3 ngôn ngữ mình muốn sử dụng là Indonesia, Malaysia, Thailand.

Ngoài ra, trong file app.php này còn khai báo thêm 1 biến 'fallback_locale' => 'en',, nó chính là ngôn ngữ mặc định trả về nếu một chuỗi chưa được dịch trong locale của bạn.

Bước tiếp theo là thêm prefix cho routes của bạn, nghĩa là thêm tiền tố locale cho url trong trang web của bạn. Để làm được việc này thì bạn cần phải thay đổi method map bên trong app/Providers/RouteServiceProvider.php như sau:

<?php

namespace AppProviders;

use IlluminateSupportFacadesRoute;
use IlluminateHttpRequest;
use IlluminateFoundationSupportProvidersRouteServiceProvider as ServiceProvider;

class RouteServiceProvider extends ServiceProvider
{
    //...

    /**
     * Define the routes for the application.
     *
     * @return void
     */
    public function map(Request $request)
    {
        $this->mapApiRoutes();

        $this->mapWebRoutes($request);

        //
    }

    /**
     * Define the "web" routes for the application.
     *
     * These routes all receive session state, CSRF protection, etc.
     *
     * @return void
     */
    protected function mapWebRoutes(Request $request)
    {
        $locale = $request->segment(1); 
        $locale = strtolower($locale); 
        //kiểm tra locale đó có nằm trong mảng locales đã khai báo
        if ($locale && in_array($locale, config('app.locales'))) { 
            $this->app->setLocale($locale); //set đúng locale đó
        }

        Route::middleware('web')
             ->namespace($this->namespace)
             ->prefix('{locale}') //thêm tiền tố locale cho url
             ->group(base_path('routes/web.php'));
    }
   //...
}

Tạo file Locale.php trong middleware bằng dòng lệnh sau:

php artisan make:middleware Locale

Rồi các bạn mở file đó trong app/Http/Middleware/Locale.php:

<?php

namespace AppHttpMiddleware;

use Closure;
use IlluminateContractsFoundationApplication;

class Locale
{
    private $app;

    public function __construct(Application $app)
    {
        $this->app = $app;
    }


    /**
     * Handle an incoming request.
     *
     * @param  IlluminateHttpRequest  $request
     * @param  Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // Make sure current locale exists.
        $locale = $request->segment(1);
        $locale = strtolower($locale);

        if (!in_array($locale, config('app.locales'))) {
            return abort(404);
        }

        $this->app->setLocale($locale);

        return $next($request);
    }
}

Và để middleware này hoạt động trên tất cả các requests thì ta phải add nó vào trong thuộc tính $routeMiddleware bên trong app/Http/Kernel.php:

protected $routeMiddleware = [
        'auth' => IlluminateAuthMiddlewareAuthenticate::class,
        'auth.basic' => IlluminateAuthMiddlewareAuthenticateWithBasicAuth::class,
        'bindings' => IlluminateRoutingMiddlewareSubstituteBindings::class,
        'can' => IlluminateAuthMiddlewareAuthorize::class,
        'guest' => AppHttpMiddlewareRedirectIfAuthenticated::class,
        'throttle' => IlluminateRoutingMiddlewareThrottleRequests::class,
        'checkType' => AppHttpMiddlewareCheckType::class,
        'locale' => AppHttpMiddlewareLocale::class,
    ];

Chỉ cần 3 bước trên là các bạn đã tạo xong multiple locales rồi đó. Giờ chúng ta thử tạo các string để test trên từng ngôn ngữ xem nó có hoạt động đúng như ta mong muốn hay chưa nhé. Mình thử thêm 1 folder ngôn ngữ id như dưới đây

/resources
    /lang
        /en
            messages.php
        /id
            messages.php

en/messages.php:

<?php

return [
	'hello' => 'Hello',
];

id/messages.php:

<?php

return [
	'hello' => 'Halo',
];

Rồi thử cho hiển thị trên view welcome.blade.php:

{{ trans('messages.hello') }}

Tiếp đến các bạn nhập link: localhost/id và localhost/en để xem có gì khác biệt nhé.

Đối với những trang web có lượng dịch lớn, việc định nghĩa những short key như trên dễ bị trùng hay gây ra nhầm lẫn khi lấy chúng, vì lý do này, Laravel cũng cung cấp hỗ trợ xác định chuỗi dịch bằng cách sử dụng bản dịch "mặc định" của chuỗi làm khoá. Các file dịch sẽ không phải là các file php thông thường nữa mà nó sẽ là các file json, với key là cụm từ tham chiếu, value là cụm từ ứng với ngôn ngữ bạn cần dịch.

Ví dụ bạn cần tạo 1 file id.json để chuyển ngôn ngữ sang tiếng Indo: id.json:

{
    "I love programming.": "Me encanta programar."
}

Lúc đó trong file .blade bạn sẽ gọi nó ra bằng cách: {{ __('I love programming.') }} hoặc @lang('I love programming.').

Bạn cũng có thể truyền thêm các tham số vào trong text cần dịch thì bạn chỉ cần làm như sau: id.json:

{
    "hello" : "Halo :name",
}

Sau đó ngoài .blade bạn sẽ truyền thêm tham số vào khi gọi nó {{ __('hello', ['name' => 'Trang'] }}

Nhưng nhược điểm của phương pháp này là chỉ có thể dịch ở dạng key: value, value chỉ có thể là 1 chuỗi chứ không thể là một object. Còn với cách tạo folder trans cho từng nước thì có thể khai báo dạng key: value mà value có thể là 1 mảng và bạn có thể dễ dàng tham chiếu tới nó như dưới đây: en/messages.php:

return [
	'button' => [
        'create' => 'Create',
        'update' => 'Update',
    ],
];

Trong file .blade chỉ cần lấy {{ trans('messages.button.create') }} là được.Tùy từng mục đích sử dụng mà các bạn có thể chọn 1 trong 2 cách trên.

Bài viết của mình đến đây là kết thúc. Cảm ơn các bạn đã theo dõi!

  1. https://laravel.com/docs/5.5/localization
  2. https://laracasts.com/discuss/channels/tips/example-on-how-to-use-multiple-locales-in-your-laravel-5-website
0