HTTP_ACCEPT_LANGUAGE 標頭。en, zh-CN, zh-TW) 供模板/翻譯系統使用。<?php
class UserLang {
private $name = 'userlang';
private $expire = 2592000; // 30 天
private $default = 'zh-CN';
private $supported = ['en', 'zh-CN', 'zh-TW'];
public function __construct(array $config = []) {
$this->name = $config['name'] ?? $this->name;
$this->expire = $config['expire'] ?? $this->expire;
$this->default = $config['default'] ?? $this->default;
$this->supported = $config['supported'] ?? $this->supported;
}
public function get() {
// 1. Cookie
if (isset($_COOKIE[$this->name])) {
$lang = $_COOKIE[$this->name];
if (in_array($lang, $this->supported)) return $lang;
}
// 2. Accept-Language
$accept = $this->getAcceptLanguage();
if ($accept) return $accept;
// 3. Default
return $this->default;
}
public function set($lang) {
if (!in_array($lang, $this->supported)) return false;
setcookie($this->name, $lang, time() + $this->expire, '/', '', false, true); // HttpOnly, Secure (需 HTTPS)
return true;
}
private function getAcceptLanguage() {
if (empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) return null;
$langs = [];
foreach (explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $part) {
$part = trim($part);
$q = 1.0;
if (preg_match('/(.*);\s*q=([0-9.]+)/', $part, $m)) {
$part = $m[1]; $q = (float)$m[2];
}
$code = strtolower(substr($part, 0, 2)); // 取語言代碼
// 映射到支援列表 (簡單示例)
$map = ['zh' => 'zh-CN', 'en' => 'en'];
if (isset($map[$code]) && in_array($map[$code], $this->supported)) {
$langs[$map[$code]] = $q;
}
}
if (!$langs) return null;
arsort($langs);
return array_key_first($langs);
}
}
<?php
require 'UserLang.class.php';
$lang = new UserLang(['supported' => ['en','zh-CN','zh-TW','ja']]);
// 顯示語言切換連結
$current = $lang->get();
echo "當前語言: $current <br>";
foreach (['en','zh-CN','zh-TW','ja'] as $l) {
echo "<a href='?lang=$l'>$l</a> ";
}
// 處理切換
if (isset($_GET['lang'])) {
$lang->set($_GET['lang']);
header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?'));
exit;
}
// 載入對應翻譯檔
$trans = include "lang/{$current}.php";
echo $trans['welcome'];
標頭範例:zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7
, 分割,每段可含 ;q=權重 (預設 1.0)。zh, en) 映射至支援列表。setcookie 設定 HttpOnly=true、Secure=true (僅 HTTPS)、SameSite=Lax。include 任意檔案 (LFI)。symfony/translation, gettext) 管理翻譯資源。UserLang 以 Cookie 優先、Accept-Language 回退、白名單驗證的策略,提供輕量級多語言偵測與切換能力。核心邏輯 <30 行,易於整合至任何 PHP 專案,為後續翻譯系統奠定基礎。