从浏览器获取语言不适用于 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 传输状态。
我看到了两个您可以尝试的解决方案:
- You can remove the SSR transfer state。这样 Spartacus 每次都会 运行 您在浏览器中的逻辑。你可以这样做:
state: {
ssrTransfer: {
keys: { [SITE_CONTEXT_FEATURE]: false },
},
},
此解决方案并不理想,因为 SSR 页面将包含默认的 falback 语言,该语言可能不是用户正在使用的语言,因此页面可能会闪烁。
- 您可以在
LanguageService
中添加自定义逻辑,这将 运行 仅在服务器中使用 Accept-Language
header 来设置语言。这个header是浏览器设置的,让服务器知道用户想要什么语言。您可以阅读 this article,它提供了一个很好的示例,说明如何在 Angular 中使用此机制。该示例不在 Spartacus 中,但可以使用相同的逻辑。
最后一个想法,Spartacus siteContext
持久性将在 4.0 中更新以使用全局状态持久性机制。
我有一个多语言网站 ['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 传输状态。
我看到了两个您可以尝试的解决方案:
- You can remove the SSR transfer state。这样 Spartacus 每次都会 运行 您在浏览器中的逻辑。你可以这样做:
state: {
ssrTransfer: {
keys: { [SITE_CONTEXT_FEATURE]: false },
},
},
此解决方案并不理想,因为 SSR 页面将包含默认的 falback 语言,该语言可能不是用户正在使用的语言,因此页面可能会闪烁。
- 您可以在
LanguageService
中添加自定义逻辑,这将 运行 仅在服务器中使用Accept-Language
header 来设置语言。这个header是浏览器设置的,让服务器知道用户想要什么语言。您可以阅读 this article,它提供了一个很好的示例,说明如何在 Angular 中使用此机制。该示例不在 Spartacus 中,但可以使用相同的逻辑。
最后一个想法,Spartacus siteContext
持久性将在 4.0 中更新以使用全局状态持久性机制。