从浏览器获取语言不适用于 SSR

Getting language from browser doesn't work with SSR

我有一个多语言网站 ['de', 'fr', 'it', 'en']

当前行为:

When I enter example.com without a previous session I am redirected to example.com/de (first value in the array)

通缉行为:

I want to be redirected to the browser's language I have (in case there is none in session)

我已扩展服务 LanguageService 以覆盖 initialize() 函数,如下所示:

initialize(): void {
    let value;
    this.getActive()
        .subscribe((val) => (value = val))
        .unsubscribe();
    if (value) {
        // don't initialize, if there is already a value (i.e. retrieved from route or transferred from SSR)
        return;
    }


    const languages = this.getLanguages();
    const sessionLanguage = this.sessionStorageCustom && this.sessionStorageCustom.getItem('language');

    if (sessionLanguage && languages?.includes(sessionLanguage)) {
        this.setActive(sessionLanguage);
    } else {
        const browserLanguage = this.getBrowserLanguage();
        if (browserLanguage && languages?.includes(browserLanguage)) {
            this.setActive(browserLanguage);
        }
    }
}

助手:

private getLanguages(): string[] | null {
    let languages = this.siteContextParamsService.getParamValues('language');

    // Removing English from options
    languages = languages.filter((l) => !(l.toLowerCase() === 'en'));

    if (languages) return languages;
    return null;
}

private getBrowserLanguage(): string | null {
    let language = this.winRef.nativeWindow?.navigator.language;
    if (language) {
        language = language.slice(0, 2);
        return language;
    }
    return null;
}

构造函数:

private sessionStorageCustom: Storage | undefined;

constructor(
    protected store: Store<StateWithSiteContext>,
    protected winRef: WindowRef,
    protected config: SiteContextConfig,
    protected siteContextParamsService: SiteContextParamsService
) {
    super(store, winRef, config);

    // cannot use default variable because it's private
    this.sessionStorageCustom = winRef.sessionStorage;
}

在 CSR 上,一切都按预期工作,但在 SSR 中,我总是使用默认语言。

(因为在服务器端没有浏览器的语言。我假设。)

如何强制在客户端执行此代码?或者我该怎么做才能做到这一点?

默认情况下,如果 Spartacus siteContext 在 运行 浏览器语言逻辑之前存在,则它始终默认为 SSR 传输状态。

我看到了两个您可以尝试的解决方案:

  1. You can remove the SSR transfer state。这样 Spartacus 每次都会 运行 您在浏览器中的逻辑。你可以这样做:
      state: {
        ssrTransfer: {
          keys: { [SITE_CONTEXT_FEATURE]: false },
        },
      },

此解决方案并不理想,因为 SSR 页面将包含默认的 falback 语言,该语言可能不是用户正在使用的语言,因此页面可能会闪烁。

  1. 您可以在 LanguageService 中添加自定义逻辑,这将 运行 仅在服务器中使用 Accept-Language header 来设置语言。这个header是浏览器设置的,让服务器知道用户想要什么语言。您可以阅读 this article,它提供了一个很好的示例,说明如何在 Angular 中使用此机制。该示例不在 Spartacus 中,但可以使用相同的逻辑。

最后一个想法,Spartacus siteContext 持久性将在 4.0 中更新以使用全局状态持久性机制。