ThinkPHP 8多语言切换原来是这么用的,给项目加上国际化支持

2026-08-20 0 858

这几天公司一个老管理后台要加多语言,因为我们有几家海外客户,需要用英文界面。虽然后台之前是全中文的,但老板一句话,就得改。我翻开代码一看,所有页面都是硬编码的中文汉字,这要是一个个去替换,得改到猴年马月。后来想起ThinkPHP自带多语言功能,专门试了试,却发现官方文档写得比较零碎,自己折腾了大半天才把最简单的语言切换跑通。这里就把我的实践过程记录下来,顺便分享几个我自己绕过的坑,希望能帮你省点时间。

在开始之前,先弄明白ThinkPHP多语言解决的什么问题

简单说,就是给你的项目准备两份(或多份)语言文件,一份中文,一份英文。然后在项目的配置里开启多语言,之后你可以在模板里用lang()函数或者{:lang('key')}标签来输出翻译文本。系统会根据你当前的语言标识去对应语言包中取词条。

这样就把“画面显示的文字”和“程序逻辑”拆开了。你想让整站变成英文,不需要改动一行PHP,只要切换默认语言即可。

第一步:开启多语言配置

在TP8里,多语言默认是关闭的。你需要修改config/lang.php配置文件(可能位于config/lang.phpconfig/app.php,看你的版本)。我这里用的是TP8.0,配置文件是config/lang.php。最关键的是设置'lang_switch_on'为true,并设置默认语言。

// config/lang.php
return [
    // 默认语言
    'default_lang'    => 'zh-cn',
    // 多语言开关
    'lang_switch_on'  => true,
    // 允许的语言列表
    'allow_lang_list' => ['zh-cn', 'en-us'],
];

这里我用zh-cnen-us作为标识,你也可以用zhen,看团队习惯。

第二步:创建语言文件

TP的语言包放在app/lang/目录下,每个语言一个子目录。例如:

app
└── lang
    ├── zh-cn.php
    └── en-us.php

这里注意,语言文件名与default_lang一致。我创建了两个文件,里面返回一个数组,键是词条名,值是对应的译文。

zh-cn.php

<?php
return [
    'welcome' => '欢迎使用后台管理系统',
    'login'   => '登录',
    'logout'  => '退出',
    'user'    => '用户',
    'order'   => '订单',
    'settings' => '设置',
    'action'  => '操作',
    'status'  => '状态',
];

en-us.php

<?php
return [
    'welcome' => 'Welcome to Admin Panel',
    'login'   => 'Login',
    'logout'  => 'Logout',
    'user'    => 'User',
    'order'   => 'Order',
    'settings' => 'Settings',
    'action'  => 'Actions',
    'status'  => 'Status',
];

第三步:在模板中使用语言包

在后台的HTML模板中,把原来写死的文字用{:lang('word')}替换。比如原来的代码:

<h1>欢迎使用后台管理系统</h1>
<button>登录</button>

改成:

<h1>{:lang('welcome')}</h1>
<button>{:lang('login')}</button>

如果你在控制器里也要用,可以用lang('order')函数。比如在返回的JSON信息中,提示语就可以换成多语言。

return json(['msg' => lang('action_success')]);

不过我这里没定义action_success,你就理解这个意思。

第四步:实现语言切换

多语言的核心就是能够动态切换。ThinkPHP默认通过请求参数来切换语言。官方推荐的方式是在URL中带上l参数。例如?l=en-us。你可以在URL上手动加这个参数,框架会在请求开始时读取$_GET['l']并设置当前语言,前提是开启了lang_switch_on

为了让切换更友好,我在模板顶部加了一个语言下拉框,表单提交或跳转时带上l参数。下面是一个简单的示例:

<select onchange="location.href='?l='+this.value">
    <option value="zh-cn" {if $Think.get.l == 'en-us'}else{/if} selected??{/if}>中文</option>
    <option value="en-us">English</option>
</select>

这段代码里,我用了ThinkPHP模板引擎的语法,$Think.get.l可以获取到当前的l参数。如果存在就高亮选中,不然默认中文。

实际项目中,语言切换往往需要让整个页面都记住选择,我喜欢把语言写入cookie。你可以在公共控制器的初始化方法中读取并设置:

// 公共控制器的initialize方法
public function initialize()
{
    $lang = $this->request->cookie('lang');
    if ($lang) {
        thinkfacadeLang::setLangSet($lang);
    }
    parent::initialize();
}

然后在切换接口里动态写入cookie,再重定向回当前页。这里就不详细写控制器代码了,思路就是这样:获取语言参数,写入cookie,最后继续执行。

实战小案例:给一个订单列表页面加多语言

光说不练假把式。我拿后台的订单列表做了个简单的演示。假设页面输出表头和状态列。

控制器方法(简化版)

<?php
namespace appcontroller;

use thinkController;
use thinkfacadeView;

class Order extends Controller
{
    public function index()
    {
        $orders = [
            ['id'=>1, 'user'=>'张三', 'status'=>1],
            ['id'=>2, 'user'=>'李四', 'status'=>0],
        ];
        View::assign('orders', $orders);
        return View::fetch();
    }
}

模板文件(order/index.html)

<table>
    <thead>
        <tr>
            <th>{:lang('order')} ID</th>
            <th>{:lang('user')}</th>
            <th>{:lang('status')}</th>
            <th>{:lang('action')}</th>
        </tr>
    </thead>
    <tbody>
        {foreach $orders as $order}
        <tr>
            <td>{$order.id}</td>
            <td>{$order.user}</td>
            <td>
                {if $order.status == 1}
                    <span style="color: green">{:lang('paid')}</span>
                {else}
                    <span style="color: red">{:lang('unpaid')}</span>
                {/if}
            </td>
            <td>
                <a href="/order/edit?id={$order.id}" rel="external nofollow" >{:lang('edit')}</a>
                <a href="/order/delete?id={$order.id}" rel="external nofollow" >{:lang('delete')}</a>
            </td>
        </tr>
        {/foreach}
    </tbody>
</table>

这里我用了'paid''unpaid''edit''delete'这些词条,你没有定义的话页面会直接显示这些英文键名。为了演示完整,我把它们也加进语言包里:

// 中文增加
'paid'   => '已支付',
'unpaid' => '未支付',
'edit'   => '编辑',
'delete' => '删除',

// 英文增加
'paid'   => 'Paid',
'unpaid' => 'Unpaid',
'edit'   => 'Edit',
'delete' => 'Delete',

遇到的一些坑

坑一:语言文件位置放错了

我开始把语言文件直接放到config下面,结果一点效果都没有。TP8的语言包默认路径是app/lang,不是config。你还可以在lang.php配置里重新指定路径,但没必要除非你有特殊部署。

坑二:URL参数l不生效

如果你配置了'lang_switch_on' => true,但访问?l=en-us还是中文,可能是你没在公共控制器的initialize里设置,或者没使用Lang::load()加载语言包。在TP8中,请求参数l会自动被识别,但前提是你要开启allow_lang_list。我发现如果allow_lang_list没有包含en-us,则不会切换。

坑三:模板的lang函数被当成普通方法

在模板里使用{:lang('welcome')}时,如果前面的:没写,它就变成纯文本输出了。我上次就少写冒号,结果页面上直接显示“lang(‘welcome’)”。所以千万别漏了。

坑四:JS里的文字没法直接翻译

这种方法只适合模板输出的HTML。如果你在JS里写了alert('确定删除吗?'),那就无法直接通过语言包替换。解决思路是:在PHP端把语言包传给JS,或者用Ajax调用后端接口。我目前做的项目JS提示不多,所以暂时没做特殊处理,但如果你全站都靠JS弹窗,那得在模板中把语言包赋值到页面上。

例如在模板底部加一行:

<script>window.LANG = {!! json_encode(lang('confirm_delete')) !!};</script>

这样JS里就能用LANG.confirm_delete了。

更灵活的做法:使用变量而不是当前请求

如果你需要基于用户设置(比如用户在个人中心选择了英文,以后每次登录都是英文),那你得把语言标识存进用户表或缓存里,然后在登录后动态设置语言。

我一般是这样做的:在用户登录时,把他的语言偏好存到缓存,然后在全局中间件中读取并设置。

// 全局中间件 handle
public function handle($request, Closure $next)
{
    $userLang = $request->cookie('lang');
    if (!$userLang) {
        $userLang = 'zh-cn';
    }
    thinkfacadeLang::setLangSet($userLang);
    return $next($request);
}

最后一个小结

多语言并不是一个复杂功能,但它涉及配置、变量传递、模板处理等多个环节。用ThinkPHP 8的系统语言包功能,能省掉造轮子的时间。只要建立一个清晰的词条管理方式,后续加新语言也很简单——再写一个语言包就行。另外,除了词条,你还要考虑日期格式、货币单位、数字分隔符等,这些可能会比文字更麻烦,但那就是另一个话题了。

希望我这篇实战笔记对你有点用处,至少让你少走几个弯路。

ThinkPHP 8多语言切换原来是这么用的,给项目加上国际化支持
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

版权声明:
本站资源有的来自互联网收集整理,本站纯免费分享提供学习使用,如果侵犯了您的合法权益,请联系本站我们会及时删除。
本站资源仅供研究、学习交流之用,免费开源项目不代表完全可商用,若商业用途请先咨询开发企业能否商用,否则产生的一切后果将由下载用户自行承担。
原创板块未经允许不得转载,否则将追究法律责任。

淘吗网 thinkphp ThinkPHP 8多语言切换原来是这么用的,给项目加上国际化支持 https://www.taomawang.com/server/thinkphp/2574.html

常见问题

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务