Spartacus Storefront Multisite I18n с серверной частью
Мы столкнулись с некоторыми проблемами при настройке нашего MultiSite Spartacus при выполнении I18n.
Мы хотели бы иметь разные переводы для каждого сайта, поэтому мы помещаем их в API, который может возвращать сообщения в зависимости от baseSite, например:
backend.org/baseSiteX/messages?group=common
Но установка Спартака не позволяет нам пройти baseSite? Мы можем пройти{{lng}}
а также{{ns}}
, но не baseSite.
См. Https://sap.github.io/spartacus-docs/i18n/#lazy-loading Мы могли бы сделать это, переопределивi18nextInit
, но я не знаю, как этого добиться.В документации говорится, что вы можете использовать
crossOrigin: true
в конфигурации, но это, похоже, не работает. Проверка типов говорит, что она не поддерживается, но все еще показывает проблемы с CORS.
Есть у кого-нибудь идеи по поводу этих проблем?
3 ответа
В настоящее время в конфигурации поддерживаются только язык {{lng}} и имя блока {{ns}} в качестве динамических параметров.
Для достижения своей цели можно реализовать кастомный Спартак.
CONFIG_INITIALIZER
чтобы заполнить ваш
i18n.backend.loadPath
config на основе значения из
BaseSiteService.getActive()
:
@Injectable({ providedIn: 'root' })
export class I18nBackendPathConfigInitializer implements ConfigInitializer {
readonly scopes = ['i18n.backend.loadPath']; // declare config key that you will resolve
readonly configFactory = () => this.resolveConfig().toPromise();
constructor(protected baseSiteService: BaseSiteService) {}
protected resolveConfig(): Observable<I18nConfig> {
return this.baseSiteService.getActive().pipe(
take(1),
map((baseSite) => ({
i18n: {
backend: {
// initialize your i18n backend path using the basesite value:
loadPath: `https://backend.org/${baseSite}/messages?lang={{lng}}&group={{ns}}`,
},
},
}))
);
}
}
и укажите его в своем модуле (например, в app.module):
@NgModule({
providers: [
{
provide: CONFIG_INITIALIZER,
useExisting: I18nBackendPathConfigInitializer,
multi: true,
},
],
/* ... */
})
Примечание: в приведенном выше решении предполагается, что активный базовый сайт устанавливается только один раз при запуске приложения (что по умолчанию имеет место в Spartacus).
@krzysztof-platis мы реализовали это предложение, похоже, оно работало в Spartacus 4.x локально и в CCV2, с новой версией 5.2 оно, похоже, больше не работает.. (ни локально, ни CCV2, пока нет URL-адреса occ определяется в файле среды)
наш инициализатор конфигурации:
export class CustomI18nConfigInitializer extends I18nConfigInitializer {
readonly scopes = ['i18n.backend.loadPath']; // declare config key that you will resolve
readonly configFactory = () => this.resolveConfig().toPromise();
constructor(
protected configInit: ConfigInitializerService,
private occEndpoints: OccEndpointsService,
private baseSiteService: BaseSiteService
) {
super(configInit);
}
protected resolveConfig(): Observable<I18nConfig> {
return this.baseSiteService.getActive().pipe(
take(1),
map(() => {
// eslint-disable-next-line no-console
console.log('i18n config initializer, load path: ' + this.occEndpoints.buildUrl('i18n'));
return {
i18n: {
backend: {
loadPath: this.occEndpoints.buildUrl('i18n'),
},
},
} as Config;
})
);
}
}
наш модуль приложения:
providers: [
{
provide: CONFIG_INITIALIZER,
useExisting: CustomI18nConfigInitializer,
multi: true,
},
],
наша фабрика конфигурации i18n:
export function i18nConfigFactory(): I18nConfig {
const prefix = environment.occ.prefix ?? '';
const baseUrl = environment.occ.baseUrl ?? '';
const url = `${baseUrl}${prefix}<site-id>/i18n/{{lng}}/{{ns}}`;
// eslint-disable-next-line no-console
console.log('i18n config factory, base url: ' + baseUrl);
return {
i18n: {
backend: {
// value get's replaced in the CustomI18nConfigInitializer with the proper OCC url since we need the base site id in the url
loadPath: url,
},
chunks: {
...translationChunksConfig,
cart: [...cartBaseTranslationChunksConfig.cart],
checkout: [...checkoutTranslationChunksConfig.checkout, 'checkoutGuest', 'checkoutShipping'],
order: [...orderTranslationChunksConfig.order],
storeFinder: [...storeFinderTranslationChunksConfig.storeFinder],
userAccount: [...userAccountTranslationChunksConfig.userAccount],
userProfile: [...userProfileTranslationChunksConfig.userProfile],
},
fallbackLang: 'de',
},
};
}
Является ли идея иметь как AND, так иi18nConfigInitializer
или мне следует использовать только один из них?
Я пытался не использовать фабрику конфигурации и полностью использовать инициализатор динамической конфигурации, но тогда кажется, что Спартак думает, что переводы будут предоставлены внутри приложения, а не будут загружаться лениво.
Если я просто используюi18nConfig
с заполнителемloadPath
значение, я получаю 404. Поэтому мне кажется, что логика инициализатора динамической конфигурации запускается слишком поздно после того, как переводы уже загружены.
Есть идеи?
Я могу подтвердить, что после обновления Spartacus до версии 5.x серверная часть Dynami i18n loadPath больше не работает :(
У нас немного другой подход, но так же, как и для @user2477219, он перестал работать :(
const initializeBackendUrl = (meta: Meta) => {
const backendUrlFromEnvConfig = environment.backend.occ.baseUrl; // local
const backendUrlFromMetaTag = meta.getTag('name=occ-backend-base-url').content; // ccv2
const backendUrlToUse = backendUrlFromEnvConfig ? backendUrlFromEnvConfig : backendUrlFromMetaTag; // env config has priority
const baseUrl = backendUrlToUse.replace('https://int-', 'https://');
i18Backend.loadPath = baseUrl + '/rest/v2/customerPortal/translations/{{ns}}.json';
return {
backend: {
occ: {
baseUrl: baseUrl,
},
},
};
};
const occConfig: OccConfig = {
backend: {
occ: {
prefix: '/rest/v2/',
},
},
};
provideConfigFactory(initializeBackendUrl, [Meta]),
provideConfig({
backend: occConfig.backend,
i18n: {
backend: i18Backend,
chunks: {
...translationChunksConfig,
custom: ['tok'],
},
fallbackLang: 'en',
},
});