跳转到主要内容

什么是本地化

Laravel 的本地化功能提供了一种便捷方式来获取多种语言的翻译字符串,用于在应用中支持多语言。 翻译字符串有两种管理方式:
方式特点
PHP 文件例如 lang/ja/messages.php,采用键值数组。适合按功能整理(如校验错误消息)
JSON 文件例如 lang/ja.json,直接用翻译字符串作为键。适合翻译量大的应用
默认 Laravel 应用未包含 lang 目录。要自定义,请通过 lang:publish Artisan 命令发布。
php artisan lang:publish

Locale 配置

默认 Locale

应用默认语言在 config/app.phplocale 中配置,通常通过 .env 中的 APP_LOCALE 环境变量控制。
// config/app.php
'locale' => env('APP_LOCALE', 'en'),
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
# .env
APP_LOCALE=ja
APP_FALLBACK_LOCALE=en
fallback_locale 是指定语言无对应翻译时所使用的备用语言。

运行时修改 Locale

使用 App 门面的 setLocale() 方法可以按请求修改 locale。
use Illuminate\Support\Facades\App;

Route::get('/greeting/{locale}', function (string $locale) {
    if (! in_array($locale, ['en', 'ja', 'fr'])) {
        abort(400);
    }

    App::setLocale($locale);

    // ...
});

检查当前 Locale

use Illuminate\Support\Facades\App;

$locale = App::currentLocale();

if (App::isLocale('ja')) {
    // 日语时的处理
}

创建语言文件

PHP 文件形式

lang/{语言代码}/ 目录下创建 PHP 文件,返回键值数组。
/lang
    /en
        messages.php
    /ja
        messages.php
<?php

// lang/ja/messages.php

return [
    'welcome' => '欢迎使用本应用!',
    'goodbye' => '再见!',
];
存在地区差异的语言请按 ISO 15897 命名目录。例如英式英语应写为 en_GB 而不是 en-gb

JSON 形式

翻译字符串较多时推荐使用 JSON 形式。 在 lang/ 目录下创建以语言代码命名的 JSON 文件。
/lang
    en.json
    ja.json
将原始英文文本作为键。
{
    "Welcome to our application!": "欢迎使用本应用!",
    "I love programming.": "我热爱编程。",
    "Logout": "登出",
    "Dashboard": "仪表盘"
}
JSON 形式下英文原文本身就是键,因此英文默认展示可自动生效。没有翻译文件的语言会直接返回键(英文原文)。

PHP 与 JSON 的选择

  • 想按功能整理,例如校验错误信息
  • 覆盖 Laravel 内置翻译(如 validation.phpauth.php
  • 需要分层管理键
// lang/ja/validation.php
return [
    'required' => ':attribute 是必填项。',
    'email' => ':attribute 必须是有效的邮箱地址。',
];
  • UI 文案多,不想再费心命名键
  • 模板里直接写英文,其他语言通过翻译文件覆盖
  • 后续增加国际化需求
{{-- 在 Blade 模板里直接写英文 --}}
{{ __('Welcome to our application!') }}

获取翻译字符串

__() 辅助函数

最常用方式。PHP 文件形式下用 “文件名.键” 语法。
// PHP 文件形式:lang/ja/messages.php 中的 'welcome'
echo __('messages.welcome');
// => 欢迎使用本应用!

// JSON 形式:将翻译原文作为键
echo __('I love programming.');
// => 我热爱编程。
若不存在对应翻译,则原样返回键。
echo __('messages.not_exists');
// => messages.not_exists(键原样返回)

在 Blade 模板中使用

Blade 中使用 {{ __() }}
{{-- PHP 文件形式 --}}
<h1>{{ __('messages.welcome') }}</h1>

{{-- JSON 形式 --}}
<button>{{ __('Logout') }}</button>

{{-- @lang 指令(已不推荐,仅保留向后兼容) --}}
@lang('messages.welcome')
@lang 指令已不推荐。目前建议使用 {{ __() }}

占位符

翻译字符串中可以嵌入形如 :name 的占位符。
// lang/ja/messages.php
return [
    'welcome' => '欢迎你,:name!',
    'greet'   => '你好,:Name!',  // 首字母大写
    'shout'   => 'HEY :NAME!',      // 全部大写
];
__() 的第二个参数传入替换值数组:
echo __('messages.welcome', ['name' => '田中']);
// => 欢迎你,田中!

echo __('messages.greet', ['name' => 'taro']);
// => 你好,Taro!(Name 首字母大写)

echo __('messages.shout', ['name' => 'taro']);
// => HEY TARO!(NAME 全大写)
Blade 中同样可用:
<p>{{ __('messages.welcome', ['name' => $user->name]) }}</p>

复数

不同语言的复数规则不同。Laravel 使用 | 分隔单数与复数。

基本复数

// lang/ja/messages.php
return [
    'apples' => '有 1 个苹果|有多个苹果',
];
JSON 形式同理:
{
    "There is one apple|There are many apples": "有 1 个苹果|有多个苹果"
}
trans_choice() 传入数量:
echo trans_choice('messages.apples', 1);
// => 有 1 个苹果

echo trans_choice('messages.apples', 5);
// => 有多个苹果

指定范围的复数

也可指定更精确的范围:
'apples' => '{0} 没有苹果|[1,19] 有若干苹果|[20,*] 有很多苹果',
echo trans_choice('messages.apples', 0);
// => 没有苹果

echo trans_choice('messages.apples', 10);
// => 有若干苹果

echo trans_choice('messages.apples', 50);
// => 有很多苹果

复数中的占位符

:count 会展示数量。第 3 参数可传入额外替换值。
// lang/ja/messages.php
return [
    'minutes_ago' => '{1} :value 分钟前|[2,*] :value 分钟前',
    'items'       => '共 :count 项',
];
echo trans_choice('messages.minutes_ago', 5, ['value' => 5]);
// => 5 分钟前

echo trans_choice('messages.items', 3);
// => 共 3 项

覆盖包的语言文件

若第三方包自带语言文件,可以在 lang/vendor/{包名}/{语言}/ 下放置同名文件进行覆盖。 例如自定义 skyrim/hearthfire 包的英文消息:
lang/
└── vendor/
    └── hearthfire/
        └── en/
            └── messages.php
// lang/vendor/hearthfire/en/messages.php
return [
    'welcome' => '自定义消息',
    // 只定义需要覆盖的键,其他键会读原文件
];

实践示例:中英切换中间件

一个根据 URL 路径、Session 或用户设置自动切换 locale 的中间件示例:
1

创建中间件

php artisan make:middleware SetLocale
2

实现中间件

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Symfony\Component\HttpFoundation\Response;

class SetLocale
{
    public function handle(Request $request, Closure $next): Response
    {
        // 支持的 locale
        $supportedLocales = ['ja', 'en'];

        // Session 中已存则使用它
        $locale = $request->session()->get('locale');

        // 若无则参考浏览器的 Accept-Language
        if (! $locale) {
            $browserLocale = substr($request->getPreferredLanguage($supportedLocales) ?? 'ja', 0, 2);
            $locale = in_array($browserLocale, $supportedLocales) ? $browserLocale : 'ja';
        }

        App::setLocale($locale);

        return $next($request);
    }
}
3

注册中间件

bootstrap/app.php 中注册:
use App\Http\Middleware\SetLocale;

->withMiddleware(function (Middleware $middleware) {
    $middleware->append(SetLocale::class);
})
4

添加切换路由

// routes/web.php
Route::post('/locale/{locale}', function (string $locale) {
    if (! in_array($locale, ['ja', 'en'])) {
        abort(400);
    }

    session(['locale' => $locale]);

    return back();
})->name('locale.switch');
5

在 Blade 模板中添加切换按钮

<div>
    <form method="POST" action="{{ route('locale.switch', 'ja') }}">
        @csrf
        <button type="submit">日本語</button>
    </form>

    <form method="POST" action="{{ route('locale.switch', 'en') }}">
        @csrf
        <button type="submit">English</button>
    </form>
</div>

翻译文件结构示例

lang/
├── ja.json          # JSON(UI 文案)
├── en.json
├── ja/
│   └── validation.php   # PHP(校验相关)
└── en/
    └── validation.php
// lang/ja.json
{
    "Dashboard": "仪表盘",
    "Login": "登录",
    "Logout": "登出",
    "Welcome, :name!": "欢迎你,:name!",
    "Save": "保存",
    "Cancel": "取消",
    "Are you sure?": "确定吗?"
}
{{-- resources/views/layouts/app.blade.php --}}
<nav>
    <a href="{{ route('dashboard') }}">{{ __('Dashboard') }}</a>
    <span>{{ __('Welcome, :name!', ['name' => auth()->user()->name]) }}</span>

    <form method="POST" action="{{ route('logout') }}">
        @csrf
        <button type="submit">{{ __('Logout') }}</button>
    </form>
</nav>

小结

方式文件路径键示例获取方式
PHP 文件lang/ja/messages.php'welcome' => '...'__('messages.welcome')
JSONlang/ja.json"Welcome": "..."__('Welcome')
函数 / 方法用途
__('key')获取翻译字符串
trans('key')__() 等价
trans_choice('key', $count)获取复数翻译
App::setLocale('ja')按请求切换 locale
App::currentLocale()获取当前 locale
App::isLocale('ja')判断当前 locale
{{-- 基础 --}}
{{ __('messages.welcome') }}

{{-- 含占位符 --}}
{{ __('messages.welcome', ['name' => $user->name]) }}

{{-- 复数 --}}
{{ trans_choice('messages.apples', $count) }}
最后修改于 2026年7月13日