Skip to content

[Translator] Option to throw an exception instead of returning the message as is when the message is not found. #2185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Translator/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## 2.20.0

- Add `throwWhenNotFound` function to configure the behavior when a translation is not found.

## 2.19.0

- Add configuration to filter dumped translations by domain.
Expand Down
1 change: 1 addition & 0 deletions src/Translator/assets/dist/translator.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface Message<Translations extends TranslationsType, Locale extends L
}
export declare function setLocale(locale: LocaleType | null): void;
export declare function getLocale(): LocaleType;
export declare function throwWhenNotFound(enabled: boolean): void;
export declare function setLocaleFallbacks(localeFallbacks: Record<LocaleType, LocaleType>): void;
export declare function getLocaleFallbacks(): Record<LocaleType, LocaleType>;
export declare function trans<M extends Message<TranslationsType, LocaleType>, D extends DomainsOf<M>, P extends ParametersOf<M, D>>(...args: P extends NoParametersType ? [message: M, parameters?: P, domain?: RemoveIntlIcuSuffix<D>, locale?: LocaleOf<M>] : [message: M, parameters: P, domain?: RemoveIntlIcuSuffix<D>, locale?: LocaleOf<M>]): string;
9 changes: 8 additions & 1 deletion src/Translator/assets/dist/translator_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ function getPluralizationRule(number, locale) {

let _locale = null;
let _localeFallbacks = {};
let _throwWhenNotFound = false;
function setLocale(locale) {
_locale = locale;
}
Expand All @@ -229,6 +230,9 @@ function getLocale() {
document.documentElement.lang ||
'en');
}
function throwWhenNotFound(enabled) {
_throwWhenNotFound = enabled;
}
function setLocaleFallbacks(localeFallbacks) {
_localeFallbacks = localeFallbacks;
}
Expand Down Expand Up @@ -270,7 +274,10 @@ function trans(message, parameters = {}, domain = 'messages', locale = null) {
return format(translations[locale], parameters, locale);
}
}
if (_throwWhenNotFound) {
throw new Error(`No translation message found with id "${message.id}".`);
}
return message.id;
}

export { getLocale, getLocaleFallbacks, setLocale, setLocaleFallbacks, trans };
export { getLocale, getLocaleFallbacks, setLocale, setLocaleFallbacks, throwWhenNotFound, trans };
9 changes: 9 additions & 0 deletions src/Translator/assets/src/translator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { format } from './formatters/formatter';

let _locale: LocaleType | null = null;
let _localeFallbacks: Record<LocaleType, LocaleType> = {};
let _throwWhenNotFound = false;

export function setLocale(locale: LocaleType | null) {
_locale = locale;
Expand All @@ -52,6 +53,10 @@ export function getLocale(): LocaleType {
);
}

export function throwWhenNotFound(enabled: boolean): void {
_throwWhenNotFound = enabled;
}

export function setLocaleFallbacks(localeFallbacks: Record<LocaleType, LocaleType>): void {
_localeFallbacks = localeFallbacks;
}
Expand Down Expand Up @@ -162,5 +167,9 @@ export function trans<
}
}

if (_throwWhenNotFound) {
throw new Error(`No translation message found with id "${message.id}".`);
}

return message.id;
}
36 changes: 36 additions & 0 deletions src/Translator/assets/test/translator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import {
type NoParametersType,
setLocale,
setLocaleFallbacks,
throwWhenNotFound,
trans,
} from '../src/translator';

describe('Translator', () => {
beforeEach(() => {
setLocale(null);
setLocaleFallbacks({});
throwWhenNotFound(false);
document.documentElement.lang = '';
document.documentElement.removeAttribute('data-symfony-ux-translator-locale');
});
Expand Down Expand Up @@ -387,6 +389,40 @@ describe('Translator', () => {
);
});

test('missing message should return the message id when `throwWhenNotFound` is false', () => {
throwWhenNotFound(false);
setLocale('fr');

const MESSAGE_IN_ANOTHER_DOMAIN: Message<{ security: { parameters: NoParametersType } }, 'en'> = {
id: 'Invalid credentials.',
translations: {
messages: {
en: 'Invalid credentials.',
},
},
};

expect(trans(MESSAGE_IN_ANOTHER_DOMAIN)).toEqual('Invalid credentials.');
});

test('missing message should throw an error if `throwWhenNotFound` is true', () => {
throwWhenNotFound(true);
setLocale('fr');

const MESSAGE_IN_ANOTHER_DOMAIN: Message<{ security: { parameters: NoParametersType } }, 'en'> = {
id: 'Invalid credentials.',
translations: {
messages: {
en: 'Invalid credentials.',
},
},
};

expect(() => {
trans(MESSAGE_IN_ANOTHER_DOMAIN);
}).toThrow(`No translation message found with id "Invalid credentials.".`);
});

test('message from intl domain should be prioritized over its non-intl equivalent', () => {
const MESSAGE: Message<
{ 'messages+intl-icu': { parameters: NoParametersType }; messages: { parameters: NoParametersType } },
Expand Down
21 changes: 21 additions & 0 deletions src/Translator/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,27 @@ By default, the default locale is ``en`` (English) that you can configure throug
#. Or with ``<html data-symfony-ux-translator-locale="your-locale">`` attribute
#. Or with ``<html lang="your-locale">`` attribute

Detecting missing translations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

By default, the translator will return the translation key if the translation is missing.

You can change this behavior by calling ``throwWhenNotFound(true)``:

.. code-block:: diff

// assets/translator.js

- import { trans, getLocale, setLocale, setLocaleFallbacks } from '@symfony/ux-translator';
+ import { trans, getLocale, setLocale, setLocaleFallbacks, throwWhenNotFound } from '@symfony/ux-translator';
import { localeFallbacks } from '../var/translations/configuration';

setLocaleFallbacks(localeFallbacks);
+ throwWhenNotFound(true)

export { trans }
export * from '../var/translations';

Importing and using translations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down