PHP 怎么本地化

wen PHP项目 3

本文目录导读:

PHP 怎么本地化

  1. 使用 gettext 扩展(最标准)
  2. 使用数组/配置文件(简单方案)
  3. 使用 JSON 文件(推荐)
  4. 使用 Composer 库
  5. 完整的本地化实现示例
  6. 高级技巧
  7. 最佳实践建议

在 PHP 中实现本地化(i18n,即国际化)主要有以下几种方法,从简单到复杂:

使用 gettext 扩展(最标准)

安装配置

# Ubuntu/Debian
sudo apt-get install php-gettext gettext
# Windows 需要在 php.ini 中启用
extension=php_gettext.dll

实现示例

<?php
// 设置语言环境
$locale = 'zh_CN'; // 或者 'en_US', 'fr_FR' 等
putenv("LANG=$locale");
setlocale(LC_ALL, $locale);
// 指定翻译文件目录
bindtextdomain('messages', './locale');
bind_textdomain_codeset('messages', 'UTF-8');
textdomain('messages');
// 使用翻译函数
echo _("Hello World"); // 将根据语言环境显示翻译内容
echo gettext("Welcome"); // 同上

创建翻译文件

# 1. 创建 po 文件
xgettext -n -o locale/zh_CN/LC_MESSAGES/messages.po source.php
# 2. 编辑 po 文件添加翻译
# 3. 编译为 mo 文件
msgfmt -o locale/zh_CN/LC_MESSAGES/messages.mo messages.po

使用数组/配置文件(简单方案)

<?php
class Translator {
    private $lang = 'zh_CN';
    private $translations = [];
    public function __construct($lang = 'zh_CN') {
        $this->lang = $lang;
        $this->loadTranslations();
    }
    private function loadTranslations() {
        $file = "lang/" . $this->lang . ".php";
        if (file_exists($file)) {
            $this->translations = include $file;
        }
    }
    public function translate($key) {
        return isset($this->translations[$key]) 
            ? $this->translations[$key] : $key;
    }
    public function __call($name, $args) {
        if ($name === 't') {
            return $this->translate($args[0]);
        }
    }
}
// 语言文件 lang/zh_CN.php
return [
    'hello' => '你好',
    'welcome' => '欢迎',
    'goodbye' => '再见',
    // 带参数的情况
    'greeting' => '您好, %s!',
];
// 使用示例
$tr = new Translator('zh_CN');
echo $tr->t('hello'); // 输出: 你好
printf($tr->t('greeting'), '张三'); // 输出: 您好, 张三!

使用 JSON 文件(推荐)

<?php
class I18n {
    private static $instance = null;
    private $translations = [];
    private $lang;
    private function __construct($lang = 'zh') {
        $this->lang = $lang;
        $this->load();
    }
    public static function getInstance($lang = null) {
        if ($lang === null) {
            $lang = isset($_SESSION['lang']) ? $_SESSION['lang'] : 'zh';
        }
        if (self::$instance === null || self::$instance->lang !== $lang) {
            self::$instance = new self($lang);
        }
        return self::$instance;
    }
    private function load() {
        $file = "lang/{$this->lang}.json";
        if (file_exists($file)) {
            $this->translations = json_decode(file_get_contents($file), true);
        }
    }
    public function t($key, $params = []) {
        $text = isset($this->translations[$key]) 
            ? $this->translations[$key] : $key;
        foreach ($params as $k => $v) {
            $text = str_replace('{' . $k . '}', $v, $text);
        }
        return $text;
    }
    public function getLang() {
        return $this->lang;
    }
}
?>
<!-- lang/zh.json -->
{
    "hello": "你好",
    "welcome": "欢迎来到我们的网站",
    "greeting": "您好, {name}!",
    "cart_items": "购物车中有 {count} 件商品"
}
<!-- 使用示例 -->
<?php
$i18n = I18n::getInstance($_SESSION['lang']);
echo $i18n->t('hello'); // 你好
echo $i18n->t('greeting', ['name' => '张三']); // 您好, 张三!
echo $i18n->t('cart_items', ['count' => 3]); // 购物车中有 3 件商品
?>

使用 Composer 库

推荐几个流行的库:

# Symfony Translation 组件
composer require symfony/translation
# 或者使用 simpler 的 php-array-translator
composer require php-array-translator/translator

Symfony Translation 示例

<?php
require 'vendor/autoload.php';
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\Loader\ArrayLoader;
$translator = new Translator('zh_CN');
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', [
    'hello' => '你好',
    'welcome' => '欢迎访问'
], 'zh_CN');
echo $translator->trans('hello'); // 你好

完整的本地化实现示例

<?php
class Localization {
    private $lang;
    private $data;
    public function __construct() {
        $this->detectLanguage();
        $this->loadLanguageData();
    }
    private function detectLanguage() {
        // 1. 检查 URL 参数
        if (isset($_GET['lang'])) {
            $this->lang = $_GET['lang'];
            $_SESSION['lang'] = $this->lang;
        }
        // 2. 检查 Session
        elseif (isset($_SESSION['lang'])) {
            $this->lang = $_SESSION['lang'];
        }
        // 3. 检查 Cookie
        elseif (isset($_COOKIE['lang'])) {
            $this->lang = $_COOKIE['lang'];
        }
        // 4. 检查浏览器语言
        else {
            $browserLang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? 'en', 0, 2);
            $this->lang = in_array($browserLang, ['zh', 'en', 'fr']) ? $browserLang : 'en';
        }
    }
    private function loadLanguageData() {
        $file = __DIR__ . "/lang/{$this->lang}.json";
        $this->data = file_exists($file) ? 
            json_decode(file_get_contents($file), true) : [];
    }
    public function lang() {
        return $this->lang;
    }
    public function __invoke($key, $params = []) {
        $text = $this->data[$key] ?? $key;
        foreach ($params as $k => $v) {
            $text = str_replace('{' . $k . '}', $v, $text);
        }
        return $text;
    }
    // 添加语言切换方法
    public function switchLanguage($lang) {
        $_SESSION['lang'] = $lang;
        setcookie('lang', $lang, time() + 3600*24*30);
        $this->lang = $lang;
        $this->loadLanguageData();
    }
}
// 使用
$t = new Localization();
echo $t('hello');
echo $t('greeting', ['name' => 'John']);

高级技巧

复数形式处理

function plural($n, $forms) {
    // 英文复数规则
    if ($forms[1] && $n != 1) return $forms[1];
    // 中文没有复数形式
    return $forms[0];
}
// 使用
echo sprintf(plural($count, ['%d item', '%d items']), $count);

动态语言切换 HTML

<!-- 语言切换器 -->
<a href="?lang=zh">中文</a> | 
<a href="?lang=en">English</a> | 
<a href="?lang=fr">Français</a>

最佳实践建议

  1. 使用统一函数名:如 t()
  2. 分离语言文件:每个语言一个 JSON 文件
  3. 使用缓存:缓存加载的语言文件
  4. 错误处理:找不到翻译时返回原始键名
  5. 编码统一:使用 UTF-8 编码

选择哪种方案取决于项目需求:

  • 小型项目:使用 JSON 文件方案
  • 中型项目:使用 gettext
  • 大型企业:使用 Symfony 等成熟框架的组件

抱歉,评论功能暂时关闭!