本文
本文介紹如何使用 Lexicon 客戶端套件,獲取 Lexicon 服務端的語系資源,並生成 Laravel 使用的語系檔,最終實現網站的在地化(localization)。
環境
- Ubuntu 18.04.1 LTS
- PHP 7.4
- Laradock
建立專案
建立一個新的專案。
1
| laravel new lexicon-domo
|
安裝套件
安裝 Lexicon 的客戶端套件。
1
| composer require memochou1993/lexicon-api-laravel-client
|
環境變數
修改 .env
檔,設置 Lexicon 服務端的網址,以及向服務端存取資源的 API 金鑰。
1 2
| LEXICON_HOST=https://lexicon.epoch.tw LEXICON_API_KEY=<API_TOKEN>
|
指令
修改 app/Console/Kernel.php
檔,以註冊 Lexicon 客戶端的指令。
1 2 3 4 5 6 7 8 9 10
| use MemoChou1993\Lexicon\Console\ClearCommand; use MemoChou1993\Lexicon\Console\SyncCommand;
class Kernel extends ConsoleKernel { protected $commands = [ ClearCommand::class, SyncCommand::class, ]; }
|
如果要獲取服務端的語系資源,並生成本地的語系檔,執行以下指令。
1
| php artisan lexicon:sync
|
如果要清除本地的語系檔,執行以下指令。
1
| php artisan lexicon:clear
|
控制器
新增一個 DemoController
控制器。
1
| php artisan make:controller DemoController
|
修改 DemoController
控制器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| namespace App\Http\Controllers;
use Illuminate\Contracts\View\View; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Artisan; use MemoChou1993\Lexicon\Console\ClearCommand; use MemoChou1993\Lexicon\Console\SyncCommand;
class DemoController extends Controller {
public function __invoke(Request $request, string $language = 'en') { if (! in_array($language, ['en', 'zh'])) { return redirect()->route('demo'); }
App::setLocale($language);
if ($request->input('sync')) { Artisan::call(SyncCommand::class);
return redirect()->route('demo', ['language' => $language]); }
if ($request->input('clear')) { Artisan::call(ClearCommand::class);
return redirect()->route('demo', ['language' => $language]); }
$file = sprintf('%s/%s.php', lang_path($language), config('lexicon.filename'));
$keys = [];
if (file_exists($file)) { $keys = include $file;
if ($request->input('dump')) { dd(file_get_contents($file)); } }
return view('demo', [ 'language' => $language, 'keys' => $keys, ]); } }
|
路由
新增一個路由。
1 2 3
| use App\Http\Controllers\DemoController;
Route::get('/{language?}', DemoController::class)->name('demo');
|
視圖
在 resources/views
資料夾新增 demo.blade.php
檔。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
| <!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{{ ___('project.name') }}</title> <link rel="icon" href="icon.png"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> </head> <body> <nav class="navbar navbar-dark bg-dark"> <a class="navbar-brand" href="{{ config('app.url') }}/{{ $language }}"> {{ ___('project.name') }} </a> <div> @if($language == 'en') <button onclick="location.href='/en'" class="btn btn-sm bg-light ml-1"> EN </button> <button onclick="location.href='/zh'" class="btn btn-sm btn-outline-light ml-1"> ZH </button> @endif @if($language == 'zh') <button onclick="location.href='/en'" class="btn btn-sm btn-outline-light ml-1"> EN </button> <button onclick="location.href='/zh'" class="btn btn-sm bg-light ml-1"> ZH </button> @endif </div> </nav> <div class="container mb-5"> <div class="mt-4"> <div class="card bg-light"> <div class="card-body"> <span class="mr-2"> <button onclick="location.href='/{{ $language }}?sync=true'" class="btn btn-sm btn-info my-1 my-md-0" id="sync"> {{ ___('action.sync') }} </button> </span> <span class="mr-2"> <button onclick="location.href='/{{ $language }}?clear=true'" class="btn btn-sm btn-danger my-1 my-md-0" id="clear"> {{ ___('action.clear') }} </button> </span> @if(count($keys)) <span class="mr-2"> <button onclick="window.open('/{{ $language }}?dump=true')" class="btn btn-sm btn-secondary my-1 my-md-0"> {{ ___('action.dump') }} </button> </span> @endif </div> </div> </div> <div class="my-4" id="table"> @if(count($keys)) <table class="table table-bordered table-responsive-sm bg-light"> <thead> <tr class="text-center"> <th>{{ ___('table.header.code_in_blade_template') }}</th> <th>{{ ___('table.header.translation') }}</th> <th>{{ ___('table.header.code_in_language_file') }}</th> </tr> </thead> <tbody> @foreach($keys as $key => $value) @if($language == 'en') <tr> <td> ___('{{ $key }}') </td> <td> {{ ___($key) }} </td> <td rowspan="2"> '{{ $key }}' => '{{ $value }}', </td> </tr> <tr> <td> ___('{{ $key }}', 2) </td> <td> {{ ___($key, 2) }} </td> </tr> @endif @if($language == 'zh') <tr> <td> ___('{{ $key }}') </td> <td> {{ ___($key) }} </td> <td> '{{ $key }}' => '{{ $value }}', </td> </tr> @endif @endforeach </tbody> </table> @endif </div> <div class="my-5 text-center" id="loading" hidden> <h5 class="py-5" id="message"></h5> <div style="width: 4rem; height: 4rem;" class="spinner-grow text-warning" role="status"> <span class="sr-only">Loading...</span> </div> </div> </div> </body> </html>
<script> document.getElementById('sync').addEventListener('click', () => { document.getElementById('table').hidden = true; document.getElementById('loading').hidden = false; document.getElementById('message').innerHTML = 'Generating language files...'; });
document.getElementById('clear').addEventListener('click', () => { document.getElementById('table').hidden = true; document.getElementById('loading').hidden = false; document.getElementById('message').innerHTML = 'Deleting language files...'; }); </script>
<style> body { font-family: 'Microsoft Jhenghei', sans-serif; font-size: 0.75rem; }
#table > table { table-layout: fixed; }
#table > table > tbody > tr > td { vertical-align: middle; } </style>
|
權限
由於 Lexicon 客戶端套件會將語系檔存放至 resources/lang
資料夾中,因此還需要修改資料夾的權限。
1
| chown laradock:www-data -R resources/lang
|
線上展示
程式碼