transloco
transloco copied to clipboard
Bug(transloco): Can't translate with scope/alias inside a data provider (ResolveFn)
Is there an existing issue for this?
- [X] I have searched the existing issues
Which Transloco package(s) are the source of the bug?
Transloco
Is this a regression?
Yes
Current behavior
Translating with a scope/alias inside a data provider (https://angular.io/api/router/ResolveFn) can break future translations with same alias
Example, using the data propriver below in lazy-scope-alias.routes.ts
of transloco-playground
const translationFn: (key: string) => ResolveFn<Translation> = (key: string) => () => {
const translocoService = inject(TranslocoService);
return translocoService.selectTranslate(key,undefined,{ scope: 'lazy-scope-alias', alias: 'myScopeAlias' })
}
export const LAZY_SCOPE_ALIAS_ROUTES: Route = {
path: 'lazy-scope-alias',
loadComponent: () =>
import('./lazy-scope-alias.component').then(
(LazyScopeAliasComponent) => LazyScopeAliasComponent
),
providers: [
provideTranslocoLoadingTpl(
`<span id="default-loading-template">Loading template...</span>`
),
],
resolve: {
title: translationFn('title')
}
};
Will cause
transloco-missing-handler.ts:22 Missing translation for 'myScopeAlias.title'
âšī¸ The issue no longer occurs if scope mapping is provided in transloco config âšī¸
provideTransloco({
config: {
prodMode: !isDevMode(),
availableLangs: [
{ id: 'en', label: 'English' },
{ id: 'es', label: 'Spanish' },
],
reRenderOnLangChange: true,
fallbackLang: 'es',
defaultLang: 'en',
missingHandler: {
useFallbackTranslation: false,
},
scopeMapping: {
'lazy-scope-alias': 'myScopeAlias',
}
// interpolation: ['<<<', '>>>']
} as unknown as Partial<TranslocoConfig>,
loader: TranslocoHttpLoader,
}),
Expected behavior
Translations can still be made after using an alias inside a data provider
Please provide a link to a minimal reproduction of the bug, if you won't provide a link the issue won't be handled.
https://codesandbox.io/s/ngneat-transloco-forked-r6fgjs?file=/src/app/lazy-scope-alias/lazy-scope-alias.routes.ts
Transloco Config
No response
Please provide the environment you discovered this bug in
Transloco:
Angular:
Node:
Package Manager: npm
OS:
Browser
No response
Additional context
No response
I would like to make a pull request for this bug
No
@guillerot I think this is an issue with the selectTranslate
signature as the only property that's used from the ScopeProvider
is the scope
which is used to load any scope dependencies.
But I do agree that the scenario that your provided should work I just think the solution should be related to the scope registration flow, what happens is:
selectTranslate ==> load scope ==> loaded ==> set aliased scope
But there is no alias provided since it's resolved at the component level using the ScopeResolver which registers the aliases from the scope provider
@guillerot After digging into this, there are 2 things that need to be done:
- Scopes should self-register the alias when provided, currently they are set by something called the scope resolver.
- There is no way to support this scenario with the current API, WDYT about allowing the users to set a scope alias via the service? another alternative is to bring back the
scopeMapping
config property. I need to think which way is preferred, but generally speaking, it would be best if I have found a way to manage this without the user managing this by hand.
@shaharkazaz I would say having a TranslocoService with self-registered scopes could be great (less hackish than scopeMapping managed by user)
I didn't go deep into the transloco code. But based on namespace doc, could it possible when calling selectTranslate with a TranslocoScope to get this behaviour :
- if scope is the only one provided : register the scope with a camel case alias if not already registered
- if alias is the only one provided: use it if registration has been made before
- if scope and alias are provided together : register the scope with this alias
- Would it be wrong to have multiple aliases for the same scope ?
- Or should it overwrite the existing registration ?
@guillerot The main issue with that suggestion is that it's not the selectTranslate
's job to register scopes, I feel that it's giving that method responsibility that it should have.
Not sure I understand all your cases, can you share code examples before I respond? just to make sure I understood them correctly đ
Sorry, I got a bit lost in my suggestions. One source of the issue here is the TranslocoService cache. An observable of the translation made without the scope mapped key is stored.
A (dirty?) solution could be to force set of translation even if cached when the scope is mapped
...
private isMappedScope(scope: string): boolean {
const { scopeMapping = {} } = this.config;
return !!scopeMapping[scope];
}
load(path: string, options: LoadOptions = {}): Observable<Translation> {
const cached = this.cache.get(path);
if (cached) {
const isMappedScope = this._isLangScoped(path) && this.isMappedScope(getScopeFromLang(path));
if(isMappedScope) { // an other condition should be used to avoid setting this translation each time load is called
cached.subscribe((translation) => this.setTranslation(translation, path, { emitChange: false }));
}
return cached;
}
...