Yii 1.1 提供了完整的國際化 (I18N) 支援,涵蓋訊息翻譯、日期時間格式化、數字貨幣本地化三大核心領域。本文系統講解 Yii::t() 訊息翻譯流程、CLocale 區域數據應用、CDateFormatter/CNumberFormatter 格式化實戰,助你構建面向全球用戶的多語言應用。
I18N 相關類位於 framework/i18n/:
i18n/ ├── CChoiceFormat.php # 複數形式選擇 ├── CDateFormatter.php # 日期時間格式化 ├── CDbMessageSource.php # 數據庫訊息源 ├── CGettextMessageSource.php # Gettext 訊息源 ├── CLocale.php # 區域數據核心 ├── CMessageSource.php # 訊息源基類 ├── CNumberFormatter.php # 數字貨幣格式化 ├── CPhpMessageSource.php # PHP 陣列訊息源 (默認) ├── data/ # 內建區域數據 (600+ 文件) │ ├── en_us.php │ ├── zh_cn.php │ └── ... └── gettext/ # Gettext 解析器
// 視圖/控制器/模型中
echo Yii::t('app', 'Welcome, {username}!', ['{username}' => $user->name]);
// 類別: app, 訊息: Welcome, {username}!, 參數: 陣列替換
// protected/config/main.php
'components' => [
'messages' => [
'class' => 'CPhpMessageSource',
'basePath' => 'protected/messages', // 訊息文件根目錄
// 'cachingDuration' => 3600, // 生產環境啟用緩存
],
],
配置文件 protected/messages/config.php:
return [
'sourcePath' => dirname(__FILE__) . DIRECTORY_SEPARATOR . '..',
'messagePath' => dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'messages',
'languages' => ['zh_cn', 'en_us', 'ja_jp'],
'fileTypes' => ['php'],
'overwrite' => true,
'exclude' => [
'.git', '.svn', 'yiilite.php', 'yiit.php',
'/i18n/data', '/messages', '/vendors', '/web/js',
],
'translator' => 'Yii::t',
];
執行提取:
php yiic message protected/messages/config.php
生成文件結構:
protected/messages/
├── zh_cn/
│ ├── app.php
│ └── login_message.php
├── en_us/
│ └── ...
└── ja_jp/
└── ...
// protected/messages/zh_cn/app.php
return [
'Welcome, {username}!' => '歡迎,{username}!',
'Login' => '登錄',
'Logout' => '退出',
];
// protected/messages/zh_cn/login_message.php
return [
'username' => '用戶名',
'password' => '密碼',
];
// 入口腳本 index.php (根據域名/Session/用戶偏好動態設置) Yii::app()->language = 'zh_cn'; // 或 en_us, ja_jp // 配置文件默認語言 'language' => 'zh_cn', 'sourceLanguage' => 'en_us', // 源代碼編寫語言
// 訊息定義 (管道符分隔單複數形式)
$message = '{n} 條記錄|{n} 條記錄'; // 中文無單複數區別
// 英文
$message = '{n} record|{n} records';
// 使用
echo Yii::t('app', $message, ['{n}' => 1]); // 1 條記錄 / 1 record
echo Yii::t('app', $message, ['{n}' => 5]); // 5 條記錄 / 5 records
$formatter = new CDateFormatter(Yii::app()->locale);
// 預定義風格: FULL, LONG, MEDIUM, SHORT
echo $formatter->format('yyyy-MM-dd HH:mm:ss', time()); // 自定義格式
echo $formatter->formatDateTime(time(), 'medium', 'short'); // 2016年3月15日 14:30
echo $formatter->formatDateTime(time(), 'full', 'full'); // 2016年3月15日 星期二 14:30:45 CST
// 解析字符串為時間戳
$timestamp = $formatter->parse('2016-03-15 14:30:00', 'yyyy-MM-dd HH:mm:ss');
| 符號 | 含義 | 示例 |
|---|---|---|
| y | 年 | yy=16, yyyy=2016 |
| M | 月 | M=3, MM=03, MMM=三月, MMMM=三月 |
| d | 日 | d=5, dd=05 |
| E | 星期 | EEE=週二, EEEE=星期二 |
| H | 小時 (0-23) | HH=14 |
| h | 小時 (1-12) | hh=02 |
| m | 分 | mm=30 |
| s | 秒 | ss=45 |
| z | 時區 | CST, GMT+08:00 |
$formatter = new CNumberFormatter(Yii::app()->locale);
// 數字格式化
echo $formatter->format('#,##0.00', 1234567.89); // 1,234,567.89
echo $formatter->format('#,##0.###', 1234.5); // 1,234.5
echo $formatter->formatPercentage(0.1234); // 12%
// 貨幣格式化
echo $formatter->formatCurrency(12345.67, 'CNY'); // ¥12,345.67
echo $formatter->formatCurrency(12345.67, 'USD'); // $12,345.67
echo $formatter->formatCurrency(12345.67, 'EUR'); // €12,345.67
// 科學記數法
echo $formatter->format('#E0', 1234567); // 1.23E6
$currencies = ['CNY', 'USD', 'EUR', 'JPY', 'GBP', 'HKD', 'TWD'];
foreach ($currencies as $cur) {
echo $cur . ': ' . $formatter->formatCurrency(100, $cur) . "\n";
}
// CNY: ¥100.00
// USD: $100.00
// EUR: €100.00
// JPY: ¥100
// GBP: £100.00
// HKD: HK$100.00
// TWD: NT$100.00
$locale = CLocale::getInstance('zh_cn'); // 或 Yii::app()->locale
// 獲取區域信息
echo $locale->getName(); // Chinese (Simplified, China)
echo $locale->getLanguage(); // zh
echo $locale->getCountry(); // CN
echo $locale->getNumberSymbols(); // 所有數字符號 (小數點、分組分隔符等)
echo $locale->getMonthNames(); // 月份名稱陣列
echo $locale->getWeekDayNames(); // 星期名稱陣列
// 日期時間格式模式
echo $locale->getDateFormat('medium'); // yyyy年M月d日
echo $locale->getTimeFormat('short'); // ah:mm
echo $locale->getDateTimeFormat('medium'); // yyyy年M月d日 ah:mm
// 貨幣信息
echo $locale->getCurrencySymbol('CNY'); // ¥
echo $locale->getCurrencyDisplayName('CNY'); // 人民幣
// components/LanguageSelector.php
class LanguageSelector extends CBehavior {
public function attach($owner) {
$owner->attachEventHandler('onBeginRequest', [$this, 'detectLanguage']);
}
public function detectLanguage() {
$app = Yii::app();
// 1. Session 優先
if ($lang = $app->session->get('language')) {
$app->language = $lang;
return;
}
// 2. 瀏覽器 Accept-Language
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$prefs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
foreach ($prefs as $pref) {
$code = strtolower(substr($pref, 0, 2));
if (in_array($code, ['zh', 'en', 'ja'])) {
$app->language = $code . '_' . strtoupper($code);
break;
}
}
}
// 3. 默認
$app->language = $app->language ?: 'zh_cn';
}
}
// 配置掛載
'behaviors' => ['languageSelector' => 'LanguageSelector']
views/ ├── site/ │ ├── index.php # 默認 (sourceLanguage) │ ├── index.zh_cn.php # 中文版 │ └── index.en_us.php # 英文版
Yii 會自動根據 language 載入對應視圖,無需在控制器邏輯中判斷。
-- 方案 A: 字段冗餘 (簡單、查詢快)
CREATE TABLE post (
id INT PRIMARY KEY,
title_zh_cn VARCHAR(255),
title_en_us VARCHAR(255),
body_zh_cn TEXT,
body_en_us TEXT
);
-- 方案 B: 獨立翻譯表 (規範、擴展性強)
CREATE TABLE post (id INT PRIMARY KEY, created_at INT);
CREATE TABLE post_i18n (
post_id INT, language VARCHAR(10), title VARCHAR(255), body TEXT,
PRIMARY KEY (post_id, language)
);
Yii 1.1 的 I18N 體系設計經典且實用:Yii::t() + PHP 陣列訊息源構建輕量翻譯流程,CLocale 封裝 600+ 區域數據,CDateFormatter/CNumberFormatter 提供專業級格式化能力。掌握「提取 → 翻譯 → 格式化」三板斧,即可將應用推向全球用戶。現代框架 (Yii 2, Laravel) 在此基礎上引入了 ICU、Gettext 等業界標準,核心思想一脈相承。