ngx-translate-multi-http-loader :以下翻译文件出了点​​问题

ngx-translate-multi-http-loader : Something went wrong for the following translation file

我使用这个库 ngx-translate-multi-http-loader 来为我的 ionic 5 应用程序加载多语言文件。

我没有任何错误,但翻译不工作。

然后我在TranslateModule.forRoot({})里面添加了defaultLanguage: 'en',结果出现了下面的错误信息

Something went wrong for the following translation file: ./assets/i18n/en.json
Database not created. Must call create() first

我花了很多时间来弄清楚如何修复它,但在互联网上找不到任何帮助。

错误

This topic 给我指出了正确的方向。基本上,我们用来导入翻译文件所需的加载程序

export function HttpLoaderFactory(httpClient: HttpClient) {
  return new MultiTranslateHttpLoader(httpClient, [
    { prefix: './assets/i18n/', suffix: '.json' },
    { prefix: `./assets/i18n/${APP_CONFIG.appType}/`, suffix: '.json' },
  ])
}

是直接导入到app.module.ts @ngModule

TranslateModule.forRoot({
  loader: {
    provide: TranslateLoader,
    useFactory: HttpLoaderFactory,
    deps: [HttpClient],
  },
}),

如果您发现这个 post,这肯定意味着您在您的应用程序中使用 HttpInterceptor,它确实从离子存储(或任何其他服务)请求数据以应用请求的特定逻辑 -> 比如说,你想向请求添加一个令牌。

让我们举个例子


@Injectable()
export class AuthHttpInterceptor implements HttpInterceptor {
  constructor(private _storage: Storage) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {

    // Clone the request to add the new header.
    let authReq: any
    return from(this.getToken()).pipe(
      switchMap((token) => {
        if (!req.headers.get('Authorization'))
          authReq = req.clone({
            headers: req.headers.set('Authorization', `Bearer ${token}`),
          })
        else authReq = req.clone()

        //send the newly created request
        return next.handle(authReq).pipe(
          retry(1),
          catchError((err, caught) => {

            const error = (err && err.error && err.error.message) || err.statusText
            return throwError(error)
          }) as any,
        )
      }),
    )
  }

  getToken(): Observable<any> {
    const token$ = new Observable((observer) => {
      this._storage.get('token').then(async (token) => {
        if (token) {
          observer.next(token)
        } else {
          observer.next(ORGANISATION_TOKEN)
        }
      })
    })

    return token$
  }
}

然后,因为 ngx-translate-multi-http-loader 正在请求使用 angular 默认值 http class 的翻译文件,您将通过此 http 拦截器。但是 _storage 还没有实例化。这导致 Database not created. Must call create() first 使我们的请求在 Something went wrong for the following translation file: ./assets/i18n/en.json

中失败

修复

对于那个特定的请求,我们必须忽略这个拦截器。

为此目的:

  1. 你可以用 httpBackend -> here an explanation 来完成。 但它不会工作,因为您不会在 http 调用之前实例化您的服务。

  2. 您必须添加一个特定的 header,告诉您的 HttpInterceptor 忽略该请求并让它通过而不进行进一步调查。 谢谢JohnrSharpe

export const InterceptorSkipHeader = 'X-Skip-Interceptor'

@Injectable()
export class UsHttpInterceptor implements HttpInterceptor {
  constructor(private _storage: Storage, private _statusService: MegaphoneStatusService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<any> {
    if (req.headers.has(InterceptorSkipHeader)) {
      const headers = req.headers.delete(InterceptorSkipHeader)
      return next.handle(req.clone({ headers }))
    }

   //... Intercept

因为能够将 header 传递给 ngx-translate-multi-http-loader,嗯..你不能。因为图书馆不接受,但是复制起来并不复杂。

// core.ngx-loader.ts

import { HttpClient, HttpHeaders } from '@angular/common/http'
import { TranslateLoader } from '@ngx-translate/core'
import merge from 'deepmerge'
import { forkJoin, Observable, of } from 'rxjs'
import { catchError, map } from 'rxjs/operators'
import { InterceptorSkipHeader } from '../http.interceptor'

export class MultiTranslateHttpLoader implements TranslateLoader {
  constructor(
    private http: HttpClient,
    private resources: {
      prefix: string
      suffix: string
    }[],
  ) {}

  public getTranslation(lang: string): Observable<any> {
    const headers = new HttpHeaders().set(InterceptorSkipHeader, '') // <-- Our Skip interceptor

    const requests = this.resources.map((resource) => {
      const path = resource.prefix + lang + resource.suffix

      return this.http.get(path, { headers }).pipe( // <-- We add the header into the request
        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) => merge.all(response)))
  }
}

你来了。