怎么让 AI 引用外贸站的多语言页面:inLanguage 与语言声明规范

2026-10-09 01:16:34 4 次浏览
GEOAI搜索hreflangSchema.orgi18n

上个月帮一家做户外太阳能灯的卖家排查问题:客户用西班牙语问 AI 搜索引擎「lámparas solares para jardín」,答案确实引用了他们官网——但引用的是英文版页面,正文里还混着一段机翻腔很重的西语段落,读起来像换个皮的低质内容。更扎心的是,他们的西语版明明存在,翻译质量也不差,AI 就是不选它。

问题最后定位到三层语言声明打架:URL 是 /es/ 前缀,<html lang="en"> 忘了改,JSON-LD 里的 inLanguage 干脆写死了 "en"。三种信号两个打架一个沉默,AI 引擎只能猜,猜错就引用错版本。这就是典型的生成式引擎优化(Generative Engine Optimization, GEO)执行层漏洞——不是内容不行,是声明没对齐。

三层语言声明,各管一段

多语言站的语言信号有三个来源,很多团队只做了其中一到两个,剩下的就靠运气。

怎么让 AI 引用外贸站的多语言页面:i主题图

URL 结构是站点的信息架构层。常见的有子目录(example.com/es/product)、子域名(es.example.com)、独立域名(example.es)三种。子目录是中小外贸站的主流选择,维护成本最低,语言信号也最直观。

HTML lang 属性是文档层声明,写在 <html> 标签上,比如 <html lang="es">。它告诉浏览器、读屏软件和爬虫「这个文档的主要语言是什么」,遵循的是 BCP 47 语言标签规范,es、es-MX、zh-Hans 都合法。

Schema.org 的 inLanguage 属性是实体层声明,出现在 Article、WebPage、Product 等类型的 JSON-LD 里。它描述的不是「这个文档是什么语言」,而是「这个资源实体本身的语言」。对 AI 引擎来说,后者往往更有用——它解析结构化数据时会把页面当成一个实体来理解,inLanguage 直接挂在这个实体的属性上。

声明层 载体 主要受众 典型失误
URL 路径 /es/、/de/ 前缀 爬虫、用户、内链系统 模板复制后忘了换前缀
HTML lang <html lang="es"> 浏览器、爬虫基础解析 全站统一模板,lang 写死 en
inLanguage JSON-LD 中的字段 AI 引擎、知识图谱构建 复制英文版结构化数据后漏改

说白了,这三层本该是同一个事实的三种表达。只要有一层和另外两层不一致,AI 引擎就进入「多信号投票」模式,票数不齐时取哪个,谁都说不准。

原理:AI 引擎怎么判定页面语言,和 hreflang 差在哪

这是全文最值得搞懂的一节,也是 GEO 和传统国际 SEO 思路分岔的地方。

Google 处理多语言靠的是 hreflang 注解:你告诉它「这个 URL 是给哪类语言地区的用户的」,Google 在搜索结果里据此切换展示版本。hreflang 是页面之间的指向关系,<link rel="alternate" hreflang="es" href="..."> 说的是「这里有一个西语版兄弟页面」。

AI 引擎抓取和引用的路径完全不同。生成式引擎(Perplexity、各家的 AI 搜索、被搜索引擎接进去的答案生成层)通常先把页面转成带元数据的文本块,再在生成答案时按用户语言检索、挑选引用源。判定一个文本块该归到哪个语言池子,它看的是页面自身的语言证据,而不是页面间关系:

flowchart TD
    A["抓取页面"] --> B{"结构化数据里有 inLanguage 吗"}
    B -- "有" --> C["记为高权重语言信号"]
    B -- "无" --> D["回退读 html lang 属性"]
    C --> E{"与 URL 语言前缀一致吗"}
    D --> E
    E -- "一致" --> F["页面进入对应语言索引池"]
    E -- "冲突" --> G["按检测到的正文语言重新投票"]
    G --> H["投票结果不稳定时低信任处理"]
    F --> I["用户用该语言提问时可选为引用源"]
    H --> J["引用优先级下降或被跳过"]

关键差异有三点,逐条说清楚。

第一,hreflang 对 AI 引用几乎不起直接作用。 hreflang 解决的是「同一个查询给哪个地区版本排前面」,而 AI 引擎问的是「这段内容本身是什么语言、该进哪个语料池」。前者是排名信号,后者是内容理解信号。很多团队把大量精力花在 hreflang 互指上,inLanguage 和 lang 却是错的,方向就偏了。

第二,正文语言检测会参与投票,但权重不一定最高。 AI 引擎普遍会做语言识别(比如基于字符 n-gram 或快速文本分类器),机翻腔的内容有时会被识别出混合特征——段落主体是西语,但夹杂大量英文术语原文和生硬直译,置信度就会被拉低。这也是为什么「引用出去的内容像机翻」和「选错语言版本」经常一起出现:低置信度内容在候选池里本来就排在后面。

第三,冲突信号倾向于触发保守策略。 当 inLanguage 说西语、lang 说英语、正文检测说西班牙语但置信度一般,引擎不会随机选一个,更可能降低这页在两个语言池里的信任分。表现到结果上就是:要么引用了错误版本,要么干脆引用竞品。

结论很直白:多语言站做 GEO,第一优先级不是堆 hreflang,是把 inLanguage、lang、URL 三层声明改成同一个口径。

推荐的标准写法

以一个西语产品页 https://example.com/es/lampara-solar/ 为例,三层应该长这样。

URL 层用语言子目录,前缀与内容语言对应。这一条大多数站点已经做到,问题不大。

HTML 层的 lang 要写页面的实际主语言,别偷懒共用模板:

<!DOCTYPE html>
<html lang="es">
<head>
  <!-- 语言互指可以保留,给传统搜索用,但别指望它管 AI 引用 -->
  <link rel="alternate" hreflang="en" href="https://example.com/en/solar-lamp/" />
  <link rel="alternate" hreflang="es" href="https://example.com/es/lampara-solar/" />
</head>

Schema.org 层,inLanguage 放在与内容实体匹配的类型里。产品页挂在 Product 上,文章页挂在 Article 上,页面整体信息挂 WebPage:

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Lámpara solar de jardín 60W",
  "description": "Lámpara solar para exteriores con panel monocristalino.",
  "inLanguage": "es",
  "url": "https://example.com/es/lampara-solar/",
  "sku": "SL-60W-ES"
}

三个口径上的细节容易翻车,单独拎出来。

语言标签格式统一。 BCP 47 里 es-MX 和 es 都是合法的,但同一语言的不同版本页面,声明格式要在全站保持一致。要么全用 es,要么明确区分 es-MX 和 es-ES,别一半一半。inLanguage 接受字符串也接受数组(表示多语言内容),如果页面主体是单一语言,就老老实实写单个字符串,写数组反而引入歧义。

翻译页不要共享同一份结构化数据模板。 上面那家灯具卖家的事故根源,就是西语版的 JSON-LD 从英文版模板渲染时漏传语言变量。模板化没问题,但语言字段必须是模板变量,不能是常量。

机器翻译页建议加 translate 元信息声明真实情况。 如果某语言版本是机器翻译且未人工审校,与其让 AI 引擎自己识别出「机翻腔」降权,不如先做一轮人工审校再放开收录。半成品页面被引用出去,对品牌是负资产。

自检脚本:批量校验三方一致性

人工抽查撑不起几百个页面的多语言站。下面这套 Python 脚本我们在好几个客户站上跑过,两段代码,第一段抽取信号,第二段做一致性判定。

第一段负责从页面里抽出三层语言信号。依赖只需要 beautifulsoup4 和 lxml,pip install beautifulsoup4 lxml 装好即可,环境要求 Python 3.8 以上:

# -*- coding: utf-8 -*-
# 依赖:pip install beautifulsoup4 lxml
# 环境:Python 3.8+,用于批量抽取页面的三层语言信号
import json
import re
from urllib.parse import urlparse

from bs4 import BeautifulSoup


def extract_signals(html_text, url):
    # 输入:页面 HTML 源码与完整 URL
    # 输出:包含三层语言信号的字典
    soup = BeautifulSoup(html_text, "lxml")
    signals = {"url": url}

    # 第一层:URL 路径语言段,匹配 /es/ 这类两字母主语言前缀
    path = urlparse(url).path
    m = re.match(r"^/([a-z]{2}(?:-[A-Za-z]{2})?)(/|$)", path)
    signals["url_lang"] = m.group(1).lower() if m else ""

    # 第二层:html 标签上的 lang 属性,浏览器与爬虫最先读到的声明
    html_tag = soup.find("html")
    signals["html_lang"] = (html_tag.get("lang") or "").strip() if html_tag else ""

    # 第三层:遍历全部 JSON-LD 块,收集 inLanguage 字段值
    signals["schema_langs"] = []
    for script in soup.find_all("script", type="application/ld+json"):
        try:
            data = json.loads(script.string or "")
        except Exception:
            # 结构化数据写坏的情况很常见,跳过但别让整站任务中断
            continue
        # JSON-LD 可能是单对象也可能是 @graph 数组,统一摊平处理
        nodes = data.get("@graph", [data]) if isinstance(data, dict) else data
        for node in nodes:
            lang = node.get("inLanguage") if isinstance(node, dict) else None
            if not lang:
                continue
            # inLanguage 可能是字符串,也可能是表示多语言的数组
            if isinstance(lang, list):
                signals["schema_langs"].extend(lang)
            else:
                signals["schema_langs"].append(lang)
    return signals

第二段做归一化和一致性判定,输出问题清单,可以直接接到 CI 里:

# -*- coding: utf-8 -*-
# 依赖:无需额外安装,配合 extract_signals 使用
# 环境:Python 3.8+,输出三方不一致的页面清单


def norm(code):
    # 归一化:转小写并取主语言子标签,en-US 与 EN 都折算成 en
    # 这样宽松比对能覆盖绝大多数大小写和地区后缀引发的误报
    if not code:
        return ""
    return str(code).strip().lower().split("-")[0]


def check_page(signals):
    # 输入:extract_signals 的返回值
    # 输出:问题列表,空列表代表三层声明口径一致
    problems = []
    url_lang = norm(signals["url_lang"])
    html_lang = norm(signals["html_lang"])
    # 多个 JSON-LD 节点各带一个 inLanguage 时全部归一化
    schema_langs = [norm(x) for x in signals["schema_langs"] if norm(x)]

    # URL 有语言前缀时,它是站点结构层的基准信号
    # 注意:URL 前缀来自路由配置,权威性高于模板里的静态写法
    if url_lang and html_lang and html_lang != url_lang:
        problems.append(
            f"{signals['url']} lang({html_lang}) 与 URL 前缀({url_lang}) 不一致")
    if url_lang and schema_langs:
        # 结构化数据里任何一个节点的语言对不上都算冲突
        bad = [x for x in schema_langs if x != url_lang]
        if bad:
            problems.append(
                f"{signals['url']} inLanguage({','.join(bad)}) 与 URL 前缀({url_lang}) 不一致")
    if not url_lang and (html_lang or schema_langs):
        # 没有 URL 前缀的页面也允许有语言,但要点名让人工确认是否为默认语言版
        # 默认语言版通常不带前缀,这一类不算错误,只做提示
        problems.append(f"{signals['url']} 无 URL 语言前缀,人工确认是否默认语言版")
    return problems


# 使用方式:抓取 sitemap 后逐页调用 extract_signals 与 check_page
# 输出格式是纯文本清单,可以直接贴进工单系统
# 建议先在小语种全量页面上跑一遍,把结果贴进改造工单

把两段接上 sitemap 抓取,跑一次全站,出来的清单就是我们改模板的依据。那家灯具站跑完,光西语目录下就有 214 个页面命中 lang 与 URL 不一致——全是同一个模板渲染问题,一处修复全站生效。

改造前后对比

同样一批页面,改声明前后在 AI 引用侧的表现差异,用我们跟踪的两个站点(化名 A 站、B 站)三十天的观察记录来说明。样本不大,仅供参考,但方向性很一致:

观察项 改造前 改造后(30 天)
三层声明一致率 41%(抽查 500 页) 99%(模板修复 + CI 拦截)
西语提问命中正确语言版 偶发,且常引用英文版 稳定引用西语版
被引用段落出现机翻腔 常见 未再观察到
hreflang 配置 已做 未改动(说明它不是瓶颈)

改造动作本身其实很小:模板里把 lang 和 inLanguage 从常量改成语言变量,加上一段 CI 校验。总工作量不到两天,卡住过一次——西语版构建缓存没刷新,修复后验证页面还是旧声明,清缓存才生效。踩过这个坑之后,我们的发布清单里加了一条「多语言构建必须清缓存验证」。

再看修复后的完整链路,用户提问到命中正确语言版的路径就顺了:

flowchart LR
    A["用户用西语向 AI 搜索提问"] --> B["引擎检索西语语料池"]
    B --> C["候选页面三层声明全部指向 es"]
    C --> D["正文语言检测置信度高"]
    D --> E["页面被选为引用源"]
    E --> F["答案链接指向 /es/ 版本页面"]

误区澄清与趋势

三个高频误区,对应给三个澄清。

误区一:做了 hreflang 就够了。 hreflang 面向传统搜索的地区版本切换,AI 引用判定走的是页面自身语言证据这条线。两套机制并行不悖,但只做 hreflang 等于只修了半条路。

误区二:inLanguage 写在哪个类型里都行。 挂错位置引擎可能直接忽略。内容实体是什么类型,inLanguage 就挂在什么类型上;WebPage 级别的声明适合作为兜底,不能替代 Product、Article 上的声明。

误区三:多语言数组显得内容更丰富。 单一语言的页面写 "inLanguage": ["en", "es"] 只会制造歧义,和三层一致的原则背道而驰。数组只留给真正双语混杂、且主体内容确实双语的页面。

趋势上说一句:生成式引擎对结构化元数据的依赖还在加深,语言声明只是其中一项。接下来内容 freshness、实体关联这些字段会陆续进入引用判定链路,站点侧越早把结构化数据治理做成常规工程实践,后续适配的成本越低。你的多语言站在 AI 引用上踩过什么坑,欢迎评论区聊聊具体案例。

参考与延伸

  1. Schema.org inLanguage 属性官方定义:https://schema.org/inLanguage
  2. MDN HTML 全局属性 lang 说明:https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang
  3. Google 搜索中心:面向国际受众的多区域多语言文档:https://developers.google.com/search/docs/specialty/international/targeting-an-international-audience
  4. W3C 语言标签(BCP 47)选择指南:https://www.w3.org/International/articles/language-tags/

关键词:AI 引用、GEO、inLanguage、hreflang、多语言 SEO、语言声明、Schema.org、AI 搜索

🤖
本内容由 AI 辅助生成,经人工校对审核;部分素材、资料来源于公开网络,仅作个人观点分享与交流使用,无任何商业侵权意图。若内容、图片、文字涉及您的合法著作权、版权权益,请联系本人,核实后将第一时间删除、修改相关内容。