指南:hreflang 与多语言

django-seo-suite 与 Django 的 i18n_patterns 集成,在页面和站点地图中生成一致的 hreflang 备选链接。两者都以同一份 LANGUAGES 配置为唯一数据源。


工作原理

build_hreflang_alternates 会对 settings.LANGUAGES 中的每种语言调用 Django 的 translate_url,生成一个由 HreflangAlt(lang, absolute_url) 命名元组组成的列表。把这个列表传给 SeoMetadata.partial(hreflang=...),{% seo_hreflang %} 标签就会渲染出 <link rel="alternate" hreflang="..."> 元素。


配置

确认 URL 配置使用了 i18n_patterns:

# urls.py
from django.conf.urls.i18n import i18n_patterns
from django.urls import path

urlpatterns = i18n_patterns(
    path("articles/<slug:slug>/", ArticleDetail.as_view(), name="article-detail"),
    path("articles/", ArticleList.as_view(), name="article-list"),
)

在 settings 中设置 LANGUAGES 和 LANGUAGE_CODE:

LANGUAGES = [
    ("en", "English"),
    ("fr", "French"),
    ("de", "German"),
]
LANGUAGE_CODE = "en"
USE_I18N = True

在详情视图中添加 hreflang

from django.views.generic import DetailView
from seo_suite.mixins import SeoViewMixin
from seo_suite.hreflang import build_hreflang_alternates
from seo_suite.metadata import SeoMetadata

from .models import Article


class ArticleDetail(SeoViewMixin, DetailView):
    model = Article

    def get_seo_metadata(self, context=None):
        alternates = build_hreflang_alternates(
            self.request.path,
            self.request,
        )
        return SeoMetadata.partial(hreflang=alternates)

当请求路径为 /en/articles/my-article/,且 LANGUAGES = [("en", …), ("fr", …)]、LANGUAGE_CODE = "en" 时,输出如下:

<link rel="alternate" hreflang="en" href="https://example.com/en/articles/my-article/">
<link rel="alternate" hreflang="fr" href="https://example.com/fr/articles/my-article/">
<link rel="alternate" hreflang="x-default" href="https://example.com/en/articles/my-article/">

控制 x-default

当 SEO_SUITE["HREFLANG_X_DEFAULT"] 为 True(默认值)时,会自动添加 x-default 备选链接,指向 settings.LANGUAGE_CODE 对应语言的 URL。

全局禁用:

SEO_SUITE = {
    "HREFLANG_X_DEFAULT": False,
}

仅在单次调用中禁用:

alternates = build_hreflang_alternates(
    self.request.path,
    self.request,
    include_x_default=False,
)

自定义语言列表

传入 languages 参数即可限制或重新排序备选链接:

alternates = build_hreflang_alternates(
    self.request.path,
    self.request,
    languages=["en", "fr"],  # only these two, regardless of LANGUAGES
)

在列表视图中添加 hreflang

from django.views.generic import ListView
from seo_suite.mixins import SeoListViewMixin
from seo_suite.hreflang import build_hreflang_alternates
from seo_suite.metadata import SeoMetadata


class ArticleList(SeoListViewMixin, ListView):
    model = Article
    seo_title = "Articles"

    def get_seo_metadata(self, context=None):
        alternates = build_hreflang_alternates(self.request.path, self.request)
        return SeoMetadata.partial(hreflang=alternates)

Note

hreflang 是 整体替换 字段:只要优先级更高的层提供了 hreflang 列表, 就会完全替换低优先级层的列表。每个页面只在一个层(通常是视图)设置 hreflang。


模板渲染

{% seo_head %} 会自动渲染 hreflang。它内部使用的标签是 {% seo_hreflang %},也可以单独使用:

{% load seo_suite %}
<head>
  {% seo_hreflang %}
</head>

站点地图中的 hreflang

要在站点地图中输出 hreflang,请将 Django 内置的站点地图 i18n 支持与 SeoSitemap 配合使用。完整示例见站点地图指南。