I have a website with multi language ['de', 'fr', 'it', 'en']
Current behaviour:
When I enter example.com without a previous session I am redirected to example.com/de (first value in the array)
Wanted behaviour:
I want to be redirected to the browser's language I have (in case there is none in session)
I have extended the service LanguageService to override the initialize() function as follows:
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);
}
}
}
Helpers:
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;
}
Constructor:
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;
}
On CSR everything works as expected but when in SSR I always go to the default language.
(Because on server side there is no browser's language. I assume.)
How can I force this code be executed at the client side? or what can I do to accomplish this?
By default the Spartacus siteContext
will always default to the SSR transfer state if it is present before running the browser language logic.
I can see two solutions you could try:
state: {
ssrTransfer: {
keys: { [SITE_CONTEXT_FEATURE]: false },
},
},
This solution is not ideal because the SSR page will contain the default falback language which might not be the one the user is using so the page might flicker.
LanguageService
that will run only in the server and use the Accept-Language
header to set the language. This header is set by the browser to let the server know what language the user wants. You can read this article which provides a great example on how to use this mechanism in Angular. The example is not in Spartacus but the same logic can be used.One final thought, the Spartacus siteContext
persistence will be updated in 4.0 to use the global state persistence mechanism.