如何用PHP实现API国际化功能,返回多语言错误消息?
- 内容介绍
- 文章标签
- 相关推荐
本文共计804个文字,预计阅读时间需要4分钟。
PHP API 返回结果处理:
Locale 必须在验证/响应前就设好,不能等进控制器才动
很多开发者把 App::setLocale() 或 Lang::setLang() 放在控制器方法开头,但此时验证器(如 Laravel 的 FormRequest 或 ThinkPHP 的 Validate::check())可能已初始化完毕,错误消息早已按默认语言生成。结果就是:你设了中文,但验证失败提示还是英文。
- Laravel:必须在中间件(如
LocaleMiddleware)中调用App::setLocale(),且该中间件要排在ValidateRequests之前 - ThinkPHP:
Lang::setLang()必须在app()->initialize()后、任何验证逻辑前执行;CLI 场景下还得手动Lang::load()对应语言文件 - 原生 PHP:若用
gettext,setlocale()和bindtextdomain()必须在第一次调用gettext()前完成,且不能被后续请求覆盖
错误码 → 语言键的映射不能靠猜,必须显式维护
框架不会自动把 'invalid_request' 这种 OAuth2 错误码,映射到 lang/zh-CN/errors.php 里的同名键。你得自己建一张表,告诉程序“这个错误码对应哪个翻译键”。
- OAuth2-Server:重写
OAuthServerException::unsupportedGrantType(),让它不返回固定字符串,而是调用Lang::get('unsupported_grant_type') - ThinkPHP:在
config/error_code.php里定义['invalid_request' => 'invalid_request'],再用lang($error_config[$code] ?? $code) - google-api-php-client:自建
MessageTranslator类,构造时传入当前语言,translate($errorCode)方法查lang/zh.php数组 - 键名大小写、下划线、中英文混用必须统一——
'user_not_found'和'userNotFound'是两个键,少一个语言包就静默回退原码
JSON 输出前必须清理数据,否则中文变 null 或乱码
json_encode() 对非 UTF-8 字符串极其敏感。数据库字段是 GBK、日志读出来带 BOM、甚至前端传了带 emoji 的参数——这些都会让 json_encode() 返回 false,最终响应为空或结构错乱。
立即学习“PHP免费学习笔记(深入)”;
- 永远加标志位:
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE) - 对所有输入值做预处理:
mb_convert_encoding($str, 'UTF-8', 'auto'),别信“数据库设了 utf8mb4 就万事大吉” - 检查
json_encode()返回值,if ($json === false) { error_log(json_last_error_msg()); },别默默吞掉 - HTTP header 必须显式设置:
header('Content-Type: application/json; charset=utf-8'),否则某些旧版 iOS WebView 会解析失败
最常被忽略的点是:语言切换不是“设一次永久生效”,而是“每次请求都要重置+校验”。哪怕用了中间件,也要确认它是否被正确注册到 api 组、是否在跨域预检(OPTIONS)请求中被跳过、以及是否在队列任务或 WebSocket 长连接里彻底失效。
本文共计804个文字,预计阅读时间需要4分钟。
PHP API 返回结果处理:
Locale 必须在验证/响应前就设好,不能等进控制器才动
很多开发者把 App::setLocale() 或 Lang::setLang() 放在控制器方法开头,但此时验证器(如 Laravel 的 FormRequest 或 ThinkPHP 的 Validate::check())可能已初始化完毕,错误消息早已按默认语言生成。结果就是:你设了中文,但验证失败提示还是英文。
- Laravel:必须在中间件(如
LocaleMiddleware)中调用App::setLocale(),且该中间件要排在ValidateRequests之前 - ThinkPHP:
Lang::setLang()必须在app()->initialize()后、任何验证逻辑前执行;CLI 场景下还得手动Lang::load()对应语言文件 - 原生 PHP:若用
gettext,setlocale()和bindtextdomain()必须在第一次调用gettext()前完成,且不能被后续请求覆盖
错误码 → 语言键的映射不能靠猜,必须显式维护
框架不会自动把 'invalid_request' 这种 OAuth2 错误码,映射到 lang/zh-CN/errors.php 里的同名键。你得自己建一张表,告诉程序“这个错误码对应哪个翻译键”。
- OAuth2-Server:重写
OAuthServerException::unsupportedGrantType(),让它不返回固定字符串,而是调用Lang::get('unsupported_grant_type') - ThinkPHP:在
config/error_code.php里定义['invalid_request' => 'invalid_request'],再用lang($error_config[$code] ?? $code) - google-api-php-client:自建
MessageTranslator类,构造时传入当前语言,translate($errorCode)方法查lang/zh.php数组 - 键名大小写、下划线、中英文混用必须统一——
'user_not_found'和'userNotFound'是两个键,少一个语言包就静默回退原码
JSON 输出前必须清理数据,否则中文变 null 或乱码
json_encode() 对非 UTF-8 字符串极其敏感。数据库字段是 GBK、日志读出来带 BOM、甚至前端传了带 emoji 的参数——这些都会让 json_encode() 返回 false,最终响应为空或结构错乱。
立即学习“PHP免费学习笔记(深入)”;
- 永远加标志位:
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE) - 对所有输入值做预处理:
mb_convert_encoding($str, 'UTF-8', 'auto'),别信“数据库设了 utf8mb4 就万事大吉” - 检查
json_encode()返回值,if ($json === false) { error_log(json_last_error_msg()); },别默默吞掉 - HTTP header 必须显式设置:
header('Content-Type: application/json; charset=utf-8'),否则某些旧版 iOS WebView 会解析失败
最常被忽略的点是:语言切换不是“设一次永久生效”,而是“每次请求都要重置+校验”。哪怕用了中间件,也要确认它是否被正确注册到 api 组、是否在跨域预检(OPTIONS)请求中被跳过、以及是否在队列任务或 WebSocket 长连接里彻底失效。

