Angular - NgxTranslate - 条件下缺少翻译处理程序

Angular - NgxTranslate - Missing Translation Handler on condition

我创建了一个丢失的翻译处理程序,它在外部 api 中查找翻译,如果找不到,则 returns 原始密钥。

export class MyMissingTranslationHandler implements MissingTranslationHandler {
        constructor(public injector: Injector) {}
    
        handle(params: MissingTranslationHandlerParams): string {
            const result = ApiCallToFindTheKey(params.key)
            return result ? result : params.key;
        }
    }

我还有一些 json 翻译文件(用于静态应用程序翻译),这些文件也是通过 api 调用请求的。

export class MultiTranslateHttpLoader implements TranslateLoader {
    constructor(private http: HttpClient) {}

    public getTranslation(lang: string): Observable<any> {
        const resources: string[] = [
            '_global.json',
            ...
        ];

        const requests = resources.map(resource => {
            const path = 'i18n/' + lang + '/' + resource;
            return this.http.get(path).pipe(
                catchError(res => {
                    console.error(res.message);
                    return of({});
                })
            );
        });
        return forkJoin(requests).pipe(map(response => merge.all(response)));
    }
}

翻译管道配置为使用这些json文件,如果找不到翻译,它就会落入我丢失的翻译处理程序.

export function HttpLoaderFactory(http: HttpClient): TranslateLoader {
        return new MultiTranslateHttpLoader(http);
    }

    @NgModule({
        imports: [
            TranslateModule.forRoot({
                defaultLanguage: 'fr',
                loader: {
                    provide: TranslateLoader,
                    useFactory: HttpLoaderFactory,
                    deps: [HttpClient]
                },
                missingTranslationHandler: {
                    provide: MissingTranslationHandler,
                    useClass: MyMissingTranslationHandler
                }
            }),
            ...
        ]

有时,json 文件花费的时间有点太长,| translate pipe 认为翻译不存在并去查找丢失的翻译处理程序,而不是等待 json 文件加载。

所以翻译的结果是缺少的翻译处理程序 returns 而不是真正的翻译。 如何让翻译管道等待 json 文件加载然后翻译? 我考虑过使用某种 flag 但是不知道有没有更优雅的方案

根据@KanishkAn 的建议,我使用 APP_INITIALIZER。

/**
 * Application won't load until the translations have been downloaded
 */
export function initializeTranslations(translationLoadedService: TranslationLoadedService): () => Promise<void> {
    return async (): Promise<void> => {
        return new Promise(resolve => {
            translationLoadedService.loaded$().subscribe(() => resolve());
        });
    };
}

@NgModule({
    imports: [
        TranslateModule.forRoot({
            defaultLanguage: 'fr',
            loader: {
                provide: TranslateLoader,
                useFactory: HttpLoaderFactory,
                deps: [HttpClient, TranslationLoadedService]
            },
            missingTranslationHandler: {
                provide: MissingTranslationHandler,
                useClass: MyMissingTranslationHandler
            }
        }),
        ...
    ],
    exports: [TranslateModule],
    providers: [
        ...,
        { provide: APP_INITIALIZER, useFactory: initializeTranslations, deps: [TranslationLoadedService], multi: true }
    ],
    entryComponents: ... ,
    declarations: ...
})

我创建了一个中间服务,它将在加载所有翻译后解析承诺。

@Injectable({
    providedIn: 'root'
})
export class TranslationLoadedService {
    private translationLoaded: Subject<void> = new Subject<void>();

    loaded$(): Subject<void> {
        return this.translationLoaded;
    }
}

因此,一旦我下载了所有翻译,我就会通知订阅者。

export class MultiTranslateHttpLoader implements TranslateLoader {
    constructor(private http: HttpClient, private translationLoaded: TranslationLoadedService) {}

    public getTranslation(lang: string): Observable<any> {
        const resources: string[] = [
            '_global.json',
            ...
        ];

        const requests = resources.map(resource => {
            const path = 'i18n/' + lang + '/' + resource;
            return this.http.get(path).pipe(
                catchError(res => {
                    console.error('Something went wrong for the following translation file:', path);
                    console.error(res.message);
                    return of({});
                })
            );
        });
        return forkJoin(requests).pipe(
            map(response => {
                **this.translationLoaded.loaded$().next();**
                return merge.all(response);
            })
        );
    }
}