PHP 怎么PHP L10n

wen PHP项目 2

本文目录导读:

PHP 怎么PHP L10n

  1. 使用 gettext 扩展(最常用)
  2. 使用数组/JSON 文件(简单方案)
  3. 使用国际化框架
  4. 自动检测语言
  5. 最佳实践建议
  6. 目录结构参考

在 PHP 中进行本地化(L10n,Localization)有几种不同的方式,从简单的内置函数到完整的框架解决方案,以下是详细的指南:

使用 gettext 扩展(最常用)

安装和启用

# Ubuntu/Debian
sudo apt-get install php-gettext php-intl
# CentOS/RHEL
sudo yum install php-gettext php-intl

基本用法

<?php
// 设置语言环境
$locale = 'zh_CN.UTF-8'; // 中文
// $locale = 'en_US.UTF-8'; // 英文
putenv("LC_ALL=$locale");
setlocale(LC_ALL, $locale);
// 指定文本域(domain)
$domain = 'messages';
bindtextdomain($domain, './locale');
bind_textdomain_codeset($domain, 'UTF-8');
textdomain($domain);
// 翻译字符串
echo gettext("Hello World");
// 或简写
echo _("Hello World");
// 复数形式
echo ngettext("item", "items", $count);
?>

创建翻译文件

  1. 创建 POT 文件(模板文件):

    xgettext -n -o messages.pot *.php
  2. 生成 PO 文件(每种语言一个):

    msginit -i messages.pot -o locale/zh_CN/LC_MESSAGES/messages.po -l zh_CN.UTF-8
  3. 翻译 PO 文件,然后编译为 MO 文件:

    msgfmt messages.po -o messages.mo

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

语言文件结构

// lang/en.php
return [
    'welcome' => 'Welcome to our site',
    'goodbye' => 'Goodbye',
    'items' => 'You have {count} items',
];
// lang/zh.php
return [
    'welcome' => '欢迎来到我们的网站',
    'goodbye' => '再见',
    'items' => '您有 {count} 个项目',
];

加载和使用

<?php
class Translator {
    private $translations = [];
    public function __construct($locale) {
        $file = __DIR__ . "/lang/{$locale}.php";
        if (file_exists($file)) {
            $this->translations = require $file;
        }
    }
    public function translate($key, $params = []) {
        $text = $this->translations[$key] ?? $key;
        // 替换参数
        foreach ($params as $param => $value) {
            $text = str_replace("{{$param}}", $value, $text);
        }
        return $text;
    }
}
// 使用
$t = new Translator('zh');
echo $t->translate('welcome');
echo $t->translate('items', ['count' => 5]);
?>

使用国际化框架

Symfony Translation 组件

composer require symfony/translation
<?php
use Symfony\Component\Translation\Translator;
use Symfony\Component\Translation\Loader\ArrayLoader;
use Symfony\Component\Translation\Loader\YamlFileLoader;
$translator = new Translator('zh');
$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', [
    'hello' => '你好',
    'items' => '%count% 个项目',
], 'zh');
echo $translator->trans('hello');
echo $translator->trans('items', ['%count%' => 3]);
?>

Laravel 的本地化

// resources/lang/zh/messages.php
return [
    'welcome' => '欢迎',
];
// 使用
echo trans('messages.welcome');
// 或
echo __('messages.welcome');
// 带参数
echo trans('messages.welcome_user', ['name' => '张三']);
// 复数
echo trans_choice('messages.apples', 10);

自动检测语言

<?php
function detectLocale() {
    // 1. 检查 session
    if (isset($_SESSION['locale'])) {
        return $_SESSION['locale'];
    }
    // 2. 检查 cookie
    if (isset($_COOKIE['locale'])) {
        return $_COOKIE['locale'];
    }
    // 3. 从浏览器头检测
    if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
        $languages = array_map('trim', explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']));
        foreach ($languages as $lang) {
            $lang = substr($lang, 0, 2);
            if (in_array($lang, ['zh', 'en', 'ja', 'ko'])) {
                return $lang;
            }
        }
    }
    // 4. 默认语言
    return 'zh';
}
// 切换语言
function setLocale($locale) {
    $_SESSION['locale'] = $locale;
    setcookie('locale', $locale, time() + 3600 * 24 * 30);
}
?>

最佳实践建议

完整示例类

<?php
class I18n {
    private static $instance = null;
    private $locale = 'en';
    private $translator;
    private $translations = [];
    private function __construct() {}
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
            self::$instance->init();
        }
        return self::$instance;
    }
    private function init() {
        $this->locale = $this->detectLocale();
        // 选择翻译方式
        if (extension_loaded('gettext')) {
            $this->initGettext();
        } else {
            $this->loadArrays();
        }
    }
    private function detectLocale() {
        // 实现语言检测逻辑
        return 'zh';
    }
    private function initGettext() {
        $locale = $this->locale . '.UTF-8';
        putenv("LC_ALL=$locale");
        setlocale(LC_ALL, $locale);
        bindtextdomain('messages', __DIR__ . '/locale');
        bind_textdomain_codeset('messages', 'UTF-8');
        textdomain('messages');
    }
    private function loadArrays() {
        $file = __DIR__ . "/lang/{$this->locale}.php";
        if (file_exists($file)) {
            $this->translations = require $file;
        }
    }
    public function translate($key, $params = []) {
        if (extension_loaded('gettext')) {
            $text = gettext($key);
        } else {
            $text = $this->translations[$key] ?? $key;
        }
        foreach ($params as $param => $value) {
            $text = str_replace("{{$param}}", $value, $text);
        }
        return $text;
    }
    public function locale() {
        return $this->locale;
    }
}
// 使用
I18n::getInstance()->translate('welcome');
?>

目录结构参考

project/
├── lang/
│   ├── en.php
│   ├── zh.php
│   └── ja.php
├── locale/
│   ├── en_US/
│   │   └── LC_MESSAGES/
│   │       └── messages.mo
│   └── zh_CN/
│       └── LC_MESSAGES/
│           └── messages.mo
├── scripts/
│   ├── update-po.sh
│   └── compile-mo.sh
└── src/
    └── I18n.php

选择哪种方案取决于:

  • 项目规模:大项目推荐 gettext 或框架方案
  • 部署环境:检查 gettext 扩展是否可用
  • 翻译频率:需要频繁修改时使用数组方案更方便
  • 团队工作流:考虑使用 Poedit 或 Weblate 等工具

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