|
|
@@ -1,17 +1,31 @@
|
|
|
import { Injectable, OnModuleInit } from '@nestjs/common';
|
|
|
import { Handler, Request } from 'express';
|
|
|
+import * as fs from 'fs';
|
|
|
import { GraphQLError } from 'graphql';
|
|
|
import i18next, { TFunction } from 'i18next';
|
|
|
import i18nextMiddleware from 'i18next-express-middleware';
|
|
|
+import Backend from 'i18next-fs-backend';
|
|
|
import ICU from 'i18next-icu';
|
|
|
-import Backend from 'i18next-node-fs-backend';
|
|
|
import path from 'path';
|
|
|
|
|
|
import { GraphQLErrorResult } from '../common/error/error-result';
|
|
|
+import { Logger } from '../config';
|
|
|
import { ConfigService } from '../config/config.service';
|
|
|
|
|
|
import { I18nError } from './i18n-error';
|
|
|
|
|
|
+/**
|
|
|
+ * @description
|
|
|
+ * I18n resources used for translations
|
|
|
+ *
|
|
|
+ * @docsCategory Translation
|
|
|
+ */
|
|
|
+export interface VendureTranslationResources {
|
|
|
+ error: any;
|
|
|
+ errorResult: any;
|
|
|
+ message: any;
|
|
|
+}
|
|
|
+
|
|
|
export interface I18nRequest extends Request {
|
|
|
t: TFunction;
|
|
|
}
|
|
|
@@ -21,11 +35,19 @@ export interface I18nRequest extends Request {
|
|
|
* The `i18next-express-middleware` middleware detects the client's preferred language based on
|
|
|
* the `Accept-Language` header or "lang" query param and adds language-specific translation
|
|
|
* functions to the Express request / response objects.
|
|
|
+ * @docsCategory Translation
|
|
|
*/
|
|
|
@Injectable()
|
|
|
export class I18nService implements OnModuleInit {
|
|
|
+ /**
|
|
|
+ * @internal
|
|
|
+ * @param configService
|
|
|
+ */
|
|
|
constructor(private configService: ConfigService) {}
|
|
|
|
|
|
+ /**
|
|
|
+ * @internal
|
|
|
+ */
|
|
|
onModuleInit() {
|
|
|
return i18next
|
|
|
.use(i18nextMiddleware.LanguageDetector)
|
|
|
@@ -35,7 +57,7 @@ export class I18nService implements OnModuleInit {
|
|
|
preload: ['en', 'de'],
|
|
|
fallbackLng: 'en',
|
|
|
detection: {
|
|
|
- lookupQuerystring: 'lang',
|
|
|
+ lookupQuerystring: 'languageCode',
|
|
|
},
|
|
|
backend: {
|
|
|
loadPath: path.join(__dirname, 'messages/{{lng}}.json'),
|
|
|
@@ -44,12 +66,44 @@ export class I18nService implements OnModuleInit {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * @internal
|
|
|
+ */
|
|
|
handle(): Handler {
|
|
|
return i18nextMiddleware.handle(i18next);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * @description
|
|
|
+ * Add a I18n translation by json file
|
|
|
+ *
|
|
|
+ * @param langKey language key of the I18n translation file
|
|
|
+ * @param filePath path to the I18n translation file
|
|
|
+ */
|
|
|
+ addTranslationFile(langKey: string, filePath: string): void {
|
|
|
+ try {
|
|
|
+ const rawData = fs.readFileSync(filePath);
|
|
|
+ const resources = JSON.parse(rawData.toString('utf-8'));
|
|
|
+ this.addTranslation(langKey, resources);
|
|
|
+ } catch (err) {
|
|
|
+ Logger.error(`Could not load resources file ${filePath}`, `I18nService`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @description
|
|
|
+ * Add a I18n translation (key-value) resource
|
|
|
+ *
|
|
|
+ * @param langKey language key of the I18n translation file
|
|
|
+ * @param resources key-value translations
|
|
|
+ */
|
|
|
+ addTranslation(langKey: string, resources: VendureTranslationResources | any): void {
|
|
|
+ i18next.addResourceBundle(langKey, 'translation', resources, true, true);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Translates the originalError if it is an instance of I18nError.
|
|
|
+ * @internal
|
|
|
*/
|
|
|
translateError(req: I18nRequest, error: GraphQLError) {
|
|
|
const originalError = error.originalError;
|
|
|
@@ -73,6 +127,7 @@ export class I18nService implements OnModuleInit {
|
|
|
|
|
|
/**
|
|
|
* Translates the message of an ErrorResult
|
|
|
+ * @internal
|
|
|
*/
|
|
|
translateErrorResult(req: I18nRequest, error: GraphQLErrorResult) {
|
|
|
const t: TFunction = req.t;
|