Đa ngôn ngữ(Localization-L10n) trong ứng dụng web với Laravel
Bài đăng này đã không được cập nhật trong 3 năm
Chào các bạn chủ để tìm hiểu phần này của mình sẽ là về chủ đề đa ngôn ngữ trong xây dựng ứng dụng ứng dụng web với framwork Larvel hay còn gọi là L10N (Localization)
Web đa ngôn ngữ là gì?
Web đã ngôn ngữ là web mà mình có thể xem dưới nhiều loại ngôn ngữ khác nhau, phù hợp với bản ngữ của mình và ngôn ngữ hiển thị của trang web do người dùng lựa chọn. Đa ngôn ngữ ở đây theo mình hiểu không có nghĩa là tại mỗi thể hiện của trang web bạn hiển thị cho người dùng với đồng thời nhiều ngôn ngữ khác nhau mà với tùy chọn ngôn ngữ của người dùng thì trang web sẽ phải hiện thị với đúng ngữ ngôn ngữ đó.
Mình có thể ví dụ ra một website đa ngôn ngữ ví dụ như wiki khá nổi tiếng rồi chắc chúng ta đều rõ hay như viblo.asia nơi bạn có thể tùy chọn 3 ngôn ngữ khác nhau như tiếng Anh, Nhật hay Việt.
Ví dụ trực quan việc chuyển đổi giữa các ngôn ngữ như sau
Với cùng nội dung thể hiện cần chuyển đổi giữa các ngôn ngữ hợp lý theo tùy chọn của người dùng.
Việc xây dựng web đa ngôn ngữ làm cho ứng dụng web của chúng ta sẽ không giới hạn phạm vi của người dùng với một ngôn ngữ cụ thể nào cả, làm cho ứng dụng trở nên chuyên nghiệp và thuận tiện cho người dùng
Localization trong laravel
Vấn Localization trong Laravel được giải quyết bằng việc là mình sẽ sử dụng array files được lưu trữ bên trong đường dẫn app/lang
.
Files ngôn ngữ cho từng ngôn ngữ cụ thể sẽ được lưu trong thư mục con của nó ví dụ
/app
/lang
/en
label.php
/vn
/label.php
Một file ngôn sẽ trả về một mảng key-value
label.php
<?php
return array(
'login' => 'Login',
'register' => 'Register,
);
-
Việc lựa chọn
key
ở đây cần phải cẩn thận do nếu mình sử dụng value tương ứng với key mà key trong files ngôn ngữ không tồn tại thì giá trị này vẫn được trả về. Mà laravel sẽ không tự động chuyển sang ngôn ngữ dự phòng (fallback language) -
Default language sẽ được được set trong
app/config/app.php
. Ngôn ngữ sẽ được ứng dụng web của mình hiển thị được định nghĩa thông quaApp::setLocale('vn');
- Ví dụ mình muốn ngôn ngữ web của mình là tiếng Việt mình đặt tùy chọn là
vn
-
Giờ mình có thể truy vấn từng dòng dữ liệu trong language files thông qua sử dụng hàm get của class Lang được cung cấp bởi Laravel. Tham số truyền vào hàm get này gồm có 2 phần: thứ nhất đó là tên của files lang ví dụ như
label
mà mình đã ví dụ ở trên, phần thứ hai có thể coi là phần mở rộng đó làkey
tại dòng được truy vấn tớiecho Lang::get('label.login);
Kết quả mình sẽ thu được đó là: Login
-
Mình cũng có thể sử dụng trực tiếp phương thức trans để get giá trị của key trong language file. trans() thương đương Lang::get()
-
key
có thể chỉ truy vấn tới mộtvalue
hoặc cũng có thể là một mảng và lúc này trong mảng lại chứa cáckey
vàvalue
ở cấp thấp hơn cho mình truy vấn. Ví dụ trong file label.php'title' => [ 'login' => 'Login page', 'register' => 'Register page', ]
-
Giờ mình sẽ truy vấn thằng 'Login page' như sau
trans('label.title.login');
-
-
Mình có thể linh đông nội dung được truy vấn ra thay vì chỉ là những đoạn text cố định bằng cách truyền vào các giá trị thay thế của riêng mình
//messages.php <?php return array( 'welcome' => 'Welcome, :username' ); ?>
-
Giá trị thay thê này sẽ được truyền vào trong hàm get hoặc trans với tham số thứ 2 dưới dạng
mảng
. Vớikey
là tên của giá trị cần thay thế vàvalue
là nội dung mình muốn thay thế vào đótrans('messages.welcome', ['username' => $username]);
-
Ví dụ biến $usename = 'Duy' thì mình sẽ nhận được 'Welcome, Duy'
-
-
Mình có một vấn đề nho nhỏ khi gặp phải đó là khi hiển thị đếm số lượng comment cho một bài viết thì mình có thể dùng
trans(comment, ['num' => $num]);
-
Tuy nhiên dù là giá trị $num của mình có là 1 hay 10 thì nội dung mình thu được cũng chỉ là
1 comment
hay10 comment
. Vấn đề này sẽ được giải quyết khi mình sử dụng "pipe" character:<?php return array( 'comment' => ':num comment|:num comments' ); ?>
-
Mình sẽ sử dụng Lang::choice() để truy vấn với dạng dữ liệu này
echo Lang::choice('messages.comment', $numComment, ['num' => $numComment]);
-
Mình sẽ nhận được kết quá là '1 comment' nếu $numComment = 1 và comment sẽ được replace bởi comments nếu $numComment khác 1.
-
Mình cũng có thể tùy chỉnh hiển thị theo giá trị mà mình truyền vào thay vì chỉ có 1 và khác 1 như sau
'comment' => '{0} There are none|[1,19] There are some|[20,Inf] There are many'
-
Mình đã có được cái nhìn tổng quát và các hàm cơ bản mà thường làm việc với Translator trong Laravel rồi. Giờ chúng ta sẽ cùng đi vào một bài toán cụ thể
Mình muốn tạo 1 trang đơn giản với các thành phần nội dung mang tính giới thiệu ví dụ như login, register, login form đơn giản mà mình có thể chuyển đổi qua lại giữa ngôn ngữ ví dụ như tiếng Việt(đăng nhập) hoặc tiếng Anh(Login) chẳng hạn
-
Mình sẽ tạo một app laravel mới.
-
Trong resources/lang tạo 2 folder là vn và en
-
Trong en và vn cùng tạo 2 files với tên label.php
//en/label.php <?php return [ 'laravel' => 'Laravel', 'login' => 'Login', 'register' => 'Register', 'doc' => 'Documentation', 'new' => 'News', 'email' => 'E-Mail Address', 'password' => 'Password', 'remember_me' => 'Remember Me', 'forgot_password' => 'Forgot Your Password?', 'lang' => [ 'en' => 'English', 'vi' => 'Tiếng Việt', 'jp' => '日本語', ], ];
-
Và
//vn/label.php <?php return [ 'laravel' => 'Laravel', 'login' => 'Đăng nhập', 'register' => 'Đăng ký', 'doc' => 'Tài liệu tham khảo', 'new' => 'Tin tức', 'email' => 'Địa chỉ email', 'password' => 'Mật khẩu', 'remember_me' => 'Ghi nhớ đăng nhập', 'forgot_password' => 'Quên mật khẩu', 'lang' => [ 'en' => 'English', 'vi' => 'Tiếng Việt', 'jp' => '日本語', ], ];
-
-
Mình sử dụng
php artisan make:auth
được hỗ trợ bởi Laravel để tạo ra các route và control, view đơn giản với việc đăng nhập đăng ký -
Đây sẽ là view trong trang home:
<body> <div class="flex-center position-ref full-height"> @if (Route::has('login')) <div class="top-right links"> <form action="{{ route('switchLang') }}" class="form-lang" method="post"> <select name="locale" onchange='this.form.submit();'> <option value="en">{{ trans('label.lang.en') }}</option> <option value="vi"{{ Lang::locale() === 'vi' ? 'selected' : '' }}>{{ trans('label.lang.vi') }}</option> <option value="jp"{{ Lang::locale() === 'jp' ? 'selected' : '' }}>{{ trans('label.lang.jp') }}</option> </select> {{ csrf_field() }} </form> <a href="{{ url('/login') }}">{{ Lang::get('label.login') }}</a> <a href="{{ url('/register') }}">{{ Lang::get('label.register') }}</a> </div> @endif <div class="content"> <div class="title m-b-md"> {{ trans('label.laravel') }} </div> <div class="links"> <a href="https://laravel.com/docs">{{ trans('label.doc') }}</a> <a href="https://laravel-news.com">{{ trans('label.new') }}</a> </div> </div> </div> </body>
-
Phần form select được sử dụng để người dùng có thể tùy chọn switch ngôn ngữ hiển thị
-
Ý tưởng ở đây là mình sẽ sử dụng middleware để handle các request đến với ứng dụng của mình trước khi được đưa vào xử lý trong controller.
-
Mình sẽ tạo một class middlware là Locale.php
<?php namespace App\Http\Middleware; use Closure; use Lang; use Session; class Locale { public function handle($request, Closure $next) { if (!Session::has('locale')) { Session::put('locale', config('app.locale')); } Lang::setLocale(Session::get('locale')); return $next($request); } }
-
Khai báo middleware trong app/Http/Kernel.php
// protected $routeMiddleware protected $routeMiddleware = [ //... 'localization' => \App\Http\Middleware\Locale::class, ];
-
Khi một request được gửi tới mình sẽ kiểm tra giá trị locale có được set trong Session chưa? Nếu có rồi thì sử dụng hàm setLocale của class Lang để lựa chọn ngôn ngữ mà mình sẽ sử dụng. Ở đây ngôn ngữ mặc định của mình là tiếng Anh (en) được khai báo trong config/app.php
-
-
Bây giờ mình sẽ sử dụng tới phần tùy chọn ngôn ngữ mà đã nói trong view phía trên. Tạo class LangController để xử lý phần này
// LangController.php <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Session; class LangController extends Controller { public function postLang(Request $request) { Session::set('locale', $request->locale); return redirect()->back(); } }
-
Tạo route
//route.php Route::group(['middleware' => 'localization', 'prefix' => Session::get('locale')], function() { Auth::routes(); Route::get('/home', 'HomeController@index'); Route::post('/lang', [ 'as' => 'switchLang', 'uses' => 'LangController@postLang', ]); Route::get('/', function () { return view('welcome'); }); });
- Ở đây mình sử dụng middleware là localization, các request tới nhẫn url trong group này sẽ được xử lý với middlewear mà mình đã viết ở phần trên
Kết quả thu được
Kết luận
-
Mong là bài viết của mình có hữu ích với mọi người
-
Cảm ơn vì đã dành thời gian đọc hết bài viết của mình. Mọi chia sẻ và góp ý các bạn bình luận cho mình tìm hiểu với nhé.
All rights reserved