语言前缀必须置于URL路径最前端,如https://example.com/en/blog/post;需通过正则安全提取、封装函数生成语义化链接,并配合严格匹配的hreflang标签,四者缺一不可。

URL里语言前缀必须放在路径最前面
SEO要求语言标识紧贴域名,比如 https://example.com/en/blog/post 而不是 https://example.com/blog/en/post 或带查询参数的 ?lang=zh。搜索引擎把路径开头的语言段当作站点语言信号,中间或参数形式基本不识别。
常见错误是用 $_GET['lang'] 动态切换模板,结果所有语言共用同一套 URL,被当成重复内容降权。
- Apache 用户必须在
.htaccess或虚拟主机配置里提前捕获第一级路径,如^/(en|zh|ja)/(.*)$ - Nginx 用户需在
server块里用location ~ ^/(en|zh|ja)/匹配,并重写为带环境变量的入口(如index.php?lang=$1&path=$2) - PHP 脚本启动时就要从
$_SERVER['REQUEST_URI']解析出语言码,不能等路由解析完再判断
用 $_SERVER['REQUEST_URI'] 安全提取语言前缀
别信 parse_url() 后取 path 再 explode('/', ...) —— 遇到双斜杠、编码字符或空格会错位。直接正则更稳:
$lang = 'en'; // 默认
if (preg_match('@^/([a-z]{2}|zh-CN|en-US|ja-JP)(?=/|$)@i', $_SERVER['REQUEST_URI'], $m)) {
$lang = strtolower($m[1]);
}
注意点:
立即学习“PHP免费学习笔记(深入)”;
- 必须用
@作分隔符,避免斜杠转义混乱 -
(?=/|$)确保匹配的是完整路径段,防止/entry被误认成en - 大小写不敏感但存储统一用小写,避免
ZH和zh被当两种语言 - 如果项目支持区域变体(如
zh-TW),正则要扩展,但注意 Google 对区域码支持有限,优先用zh主语言码
生成语义化链接时别硬拼字符串
手动拼 "<a href="https://www.php.cn/link/170c68abc717c9b5ab7eeb1ead16cf98">"</a> 看似简单,实际埋雷:语言切换时漏改当前路径、多级目录下相对路径错乱、URL 编码没处理。
正确做法是封装一个函数,把「当前路径段」和「目标语言」作为输入:
function lang_url($target_lang, $path = null) {
$current_path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$segments = array_filter(explode('/', trim($current_path, '/')));
array_shift($segments); // 去掉第一个语言段
$actual_path = $path ?? implode('/', $segments);
return '/' . $target_lang . '/' . ltrim($actual_path, '/');
}
使用示例:
- 当前在
/zh/about,想生成英文版链接:lang_url('en', 'about')→/en/about - 在
/en/blog/my-post,切换语言到日文:lang_url('ja')→/ja/blog/my-post - 传入的
$path必须已做rawurlencode(),函数内部不负责编码
hreflang 标签必须动态输出且严格对应
只靠 URL 前缀不够,Google 还要看 <link rel="alternate" hreflang="...">。每个页面都要输出所有语言版本的链接,包括自己。
容易踩的坑:
- hreflang 值必须和 URL 前缀一致,
zh-CN就不能对应/zh/,得是/zh-CN/ - 漏掉
x-default,尤其首页,应指向用户首选语言或默认语言页 - 用绝对 URL,别写
/en/...,要写https://example.com/en/...,否则跨子域或协议时失效 - PHP 输出时检查
$lang是否在白名单里,避免被注入恶意 hreflang 值
事情说清了就结束:语言前缀位置、解析方式、链接生成逻辑、hreflang 四者必须咬合,差一环,SEO 就归零。











