diff --git a/libs/transloco/src/lib/resolve-loader.ts b/libs/transloco/src/lib/resolve-loader.ts index b2899be0..5c064eb8 100644 --- a/libs/transloco/src/lib/resolve-loader.ts +++ b/libs/transloco/src/lib/resolve-loader.ts @@ -1,6 +1,10 @@ import { TranslocoLoader, TranslocoLoaderData } from './transloco.loader'; import { InlineLoader } from './types'; import { isFunction } from './helpers'; +import { + formatTranslocoError, + TranslocoErrorCode, +} from './transloco-error-code'; interface Options { inlineLoader?: InlineLoader; @@ -15,7 +19,15 @@ export function resolveLoader(options: Options) { if (inlineLoader) { const pathLoader = inlineLoader[path]; if (isFunction(pathLoader) === false) { - throw `You're using an inline loader but didn't provide a loader for ${path}`; + let message: string; + if (typeof ngDevMode !== 'undefined' && ngDevMode) { + message = `You're using an inline loader but didn't provide a loader for ${path}`; + } else { + message = formatTranslocoError( + TranslocoErrorCode.NoLoaderProvidedForPath, + ); + } + throw new Error(message); } return inlineLoader[path]().then((res) => diff --git a/libs/transloco/src/lib/tests/default-missing-handler.spec.ts b/libs/transloco/src/lib/tests/default-missing-handler.spec.ts index 2ad21c9e..79e3036d 100644 --- a/libs/transloco/src/lib/tests/default-missing-handler.spec.ts +++ b/libs/transloco/src/lib/tests/default-missing-handler.spec.ts @@ -22,7 +22,11 @@ describe('TranslocoMissingHandler', () => { }); it('should not notify a warning message for production mode', () => { + // @ts-expect-error does not exist on `typeof globalThis`. + globalThis.ngDevMode = false; assertLog({ prodMode: true }, false); + // @ts-expect-error does not exist on `typeof globalThis`. + globalThis.ngDevMode = true; }); it('should not notify a warning message when logMissingKey is false', () => { diff --git a/libs/transloco/src/lib/transloco-error-code.ts b/libs/transloco/src/lib/transloco-error-code.ts new file mode 100644 index 00000000..fdd635e4 --- /dev/null +++ b/libs/transloco/src/lib/transloco-error-code.ts @@ -0,0 +1,12 @@ +export const enum TranslocoErrorCode { + NoLoaderProvidedForPath = 1, + FunctionalTranspilerInvalidSyntax, + UnableToLoadTranslation, + NoFallbackLanguageProvided, +} + +export function formatTranslocoError(code: TranslocoErrorCode) { + // Prints a message with an error code to notify the user that something is + // wrong. This might also be logged in production, but without the full message. + return `[transloco]:${code}`; +} diff --git a/libs/transloco/src/lib/transloco-fallback-strategy.ts b/libs/transloco/src/lib/transloco-fallback-strategy.ts index 52649169..0f509ba5 100644 --- a/libs/transloco/src/lib/transloco-fallback-strategy.ts +++ b/libs/transloco/src/lib/transloco-fallback-strategy.ts @@ -1,6 +1,10 @@ import { Inject, Injectable, InjectionToken } from '@angular/core'; import { TRANSLOCO_CONFIG, TranslocoConfig } from './transloco.config'; +import { + formatTranslocoError, + TranslocoErrorCode, +} from './transloco-error-code'; export const TRANSLOCO_FALLBACK_STRATEGY = new InjectionToken( @@ -20,9 +24,16 @@ export class DefaultFallbackStrategy implements TranslocoFallbackStrategy { getNextLangs() { const fallbackLang = this.userConfig.fallbackLang; if (!fallbackLang) { - throw new Error( - 'When using the default fallback, a fallback language must be provided in the config!', - ); + let message: string; + if (typeof ngDevMode !== 'undefined' && ngDevMode) { + message = + 'When using the default fallback, a fallback language must be provided in the config!'; + } else { + message = formatTranslocoError( + TranslocoErrorCode.NoFallbackLanguageProvided, + ); + } + throw new Error(message); } return Array.isArray(fallbackLang) ? fallbackLang : [fallbackLang]; diff --git a/libs/transloco/src/lib/transloco-missing-handler.ts b/libs/transloco/src/lib/transloco-missing-handler.ts index 7bee2a0b..d03f03ae 100644 --- a/libs/transloco/src/lib/transloco-missing-handler.ts +++ b/libs/transloco/src/lib/transloco-missing-handler.ts @@ -21,9 +21,11 @@ export interface TranslocoMissingHandler { @Injectable() export class DefaultMissingHandler implements TranslocoMissingHandler { handle(key: string, config: TranslocoConfig) { - if (config.missingHandler.logMissingKey && !config.prodMode) { - const msg = `Missing translation for '${key}'`; - console.warn(`%c ${msg}`, 'font-size: 12px; color: red'); + if (typeof ngDevMode !== 'undefined' && ngDevMode) { + if (config.missingHandler.logMissingKey) { + const msg = `Missing translation for '${key}'`; + console.warn(`%c ${msg}`, 'font-size: 12px; color: red'); + } } return key; diff --git a/libs/transloco/src/lib/transloco.config.ts b/libs/transloco/src/lib/transloco.config.ts index a75ee34e..f588ede5 100644 --- a/libs/transloco/src/lib/transloco.config.ts +++ b/libs/transloco/src/lib/transloco.config.ts @@ -5,6 +5,7 @@ import { AvailableLangs } from './types'; export interface TranslocoConfig { defaultLang: string; reRenderOnLangChange: boolean; + /** @deprecated */ prodMode: boolean; fallbackLang?: string | string[]; failedRetries: number; diff --git a/libs/transloco/src/lib/transloco.service.ts b/libs/transloco/src/lib/transloco.service.ts index 40856cf9..8ab6b614 100644 --- a/libs/transloco/src/lib/transloco.service.ts +++ b/libs/transloco/src/lib/transloco.service.ts @@ -71,6 +71,10 @@ import { } from './shared'; import { getFallbacksLoaders } from './get-fallbacks-loaders'; import { resolveLoader } from './resolve-loader'; +import { + formatTranslocoError, + TranslocoErrorCode, +} from './transloco-error-code'; let service: TranslocoService; @@ -234,7 +238,7 @@ export class TranslocoService implements OnDestroy { this.handleSuccess(path, translation); }), catchError((error) => { - if (!this.config.prodMode) { + if (typeof ngDevMode !== 'undefined' && ngDevMode) { console.error(`Error while trying to load "${path}"`, error); } @@ -762,12 +766,19 @@ export class TranslocoService implements OnDestroy { const isFallbackLang = nextLang === splitted[splitted.length - 1]; if (!nextLang || isFallbackLang) { - let msg = `Unable to load translation and all the fallback languages`; - if (splitted.length > 1) { - msg += `, did you misspelled the scope name?`; + let message: string; + if (typeof ngDevMode !== 'undefined' && ngDevMode) { + message = `Unable to load translation and all the fallback languages`; + if (splitted.length > 1) { + message += `, did you misspelled the scope name?`; + } + } else { + message = formatTranslocoError( + TranslocoErrorCode.UnableToLoadTranslation, + ); } - throw new Error(msg); + throw new Error(message); } let resolveLang = nextLang; diff --git a/libs/transloco/src/lib/transloco.transpiler.ts b/libs/transloco/src/lib/transloco.transpiler.ts index 59bbbffb..b7289ac6 100644 --- a/libs/transloco/src/lib/transloco.transpiler.ts +++ b/libs/transloco/src/lib/transloco.transpiler.ts @@ -7,6 +7,10 @@ import { TRANSLOCO_CONFIG, TranslocoConfig, } from './transloco.config'; +import { + formatTranslocoError, + TranslocoErrorCode, +} from './transloco-error-code'; export const TRANSLOCO_TRANSPILER = new InjectionToken( typeof ngDevMode !== 'undefined' && ngDevMode ? 'TRANSLOCO_TRANSPILER' : '', @@ -164,6 +168,8 @@ export function getFunctionArgs(argsString: string): string[] { return args; } +const functionalCallRegExp = /\[\[\s*(\w+)\((.*?)\)\s*]]/g; + @Injectable() export class FunctionalTranspiler extends DefaultTranspiler @@ -175,7 +181,7 @@ export class FunctionalTranspiler let transpiled = value; if (isString(value)) { transpiled = value.replace( - /\[\[\s*(\w+)\((.*?)\)\s*]]/g, + functionalCallRegExp, (match: string, functionName: string, args: string) => { try { const func: TranslocoTranspilerFunction = @@ -183,11 +189,19 @@ export class FunctionalTranspiler return func.transpile(...getFunctionArgs(args)); } catch (e: unknown) { - let message = `There is an error in: '${value}'. + let message: string; + if (typeof ngDevMode !== 'undefined' && ngDevMode) { + message = `There is an error in: '${value}'. Check that the you used the right syntax in your translation and that the implementation of ${functionName} is correct.`; - if ((e as Error).message.includes('NullInjectorError')) { - message = `You are using the '${functionName}' function in your translation but no provider was found!`; + if ((e as Error).message.includes('NullInjectorError')) { + message = `You are using the '${functionName}' function in your translation but no provider was found!`; + } + } else { + message = formatTranslocoError( + TranslocoErrorCode.FunctionalTranspilerInvalidSyntax, + ); } + throw new Error(message); } },