如何在SAP Spartacus中为多语言多basestore站点添加hreflang标签
SAP Spartacus多站点hreflang标签实现方案
标准实现方案
Spartacus原生没有内置hreflang标签的专属处理能力,官方推荐的标准扩展方案如下:
- 扩展原生
PageMeta接口,新增alternateLinks字段,用来存储所有alternate链接的hreflang属性值、对应页面URL - 自定义全局的hreflang解析器,实现
PageMetaResolver接口,设置最高优先级:- 解析阶段获取当前站点下所有可用的语言、以及所有有权限的站点组合
- 根据当前页面的路由路径,按照
/国家码/语言码/页面路径的规则拼接所有对应语言/站点版本的URL,同时生成x-default对应的无上下文前缀路径 - 识别当前页面类型,购物车、结算页直接返回空的
alternateLinks,跳过标签生成
- 单独实现hreflang管理服务,负责DOM层面的link标签增删
注入document动态生成标签的合理性
这是目前的最优解,原因如下:
- 基于Angular官方提供的
DOCUMENT令牌注入的方式,天然兼容客户端渲染和服务端渲染(SSR)环境,不会出现服务端无法访问document对象的报错 - 可以实现标签的全生命周期管控,每次更新前清空旧标签,避免出现重复、失效的hreflang标签
- 操作量级极小,仅涉及个位数DOM节点的增删,不会产生可感知的性能损耗
标签更新的触发时机
优先在路由切换完成后触发更新,同时额外监听站点、语言上下文的变化事件触发更新:
- 路由切换完成时当前页面的最终路径才会确定,此时生成的各版本URL准确性最高,不会出现路径不匹配的问题
- 额外监听上下文切换是为了覆盖用户不跳转路由、仅切换站点/语言的场景,此时页面路径会同步更新,也需要重新生成hreflang标签
核心代码示例
// hreflang管理服务核心逻辑 import { DOCUMENT } from '@angular/common'; import { Inject, Injectable } from '@angular/core'; import { PageMetaService, RoutingService, LanguageService, BaseSiteService } from '@spartacus/core'; import { take, filter } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class HreflangService { private readonly HREFLANG_SELECTOR = 'link[rel="alternate"][hreflang]'; constructor( @Inject(DOCUMENT) private doc: Document, private pageMetaService: PageMetaService, private routingService: RoutingService, private languageService: LanguageService, private baseSiteService: BaseSiteService ) {} // 在AppModule初始化时调用该方法 init(): void { // 监听路由跳转完成 this.routingService.isNavigating() .pipe(filter(navigating => !navigating)) .subscribe(() => this.updateTags()); // 监听语言/站点切换 this.languageService.getActive().subscribe(() => this.updateTags()); this.baseSiteService.getActive().subscribe(() => this.updateTags()); } private updateTags(): void { // 清空旧标签 this.doc.querySelectorAll(this.HREFLANG_SELECTOR).forEach(el => el.remove()); // 读取页面元数据中的alternate链接配置 this.pageMetaService.getMeta().pipe(take(1)).subscribe(meta => { const links = meta?.alternateLinks || []; links.forEach(({ hreflang, href }) => { const linkEl = this.doc.createElement('link'); linkEl.rel = 'alternate'; linkEl.hreflang = hreflang; linkEl.href = href; this.doc.head.appendChild(linkEl); }); }); } }
内容的提问来源于stack exchange,提问作者andreasbecker.de
相关产品推荐
相关产品推荐

