The extracted file is uploaded to an external tool where translators provide texts in all the required languages.
A scheduled job extracts the translations from that external tool and uploads it to a storage available to the running app.
This means that the translated texts are never committed into the repository along with the code and we cannot use them in tests directly.
At the same time, we would not like to tie our component tests to a specific implementation of the translation (TranslatePipe / TranslateService). We would like to still just test that the component renders the translated text, not the key itself.
The current solution we use looks something like the following:
const TRANSLATED: Record<string, string> = {
'My text to translate': 'Mój przetłumaczony tekst'
};
describe('MyComponent', () => {
// ...
beforeEach(() => {
TestBed.configureTestingModule({
// ...
imports: [TranslateTestingModule.withTranslations({ pl: TRANSLATED }).withDefaultLanguage('pl')]
});
});
// ...
it("should show translated text", () => {
expect(allText()).toContain(TRANSLATED['My text to translate'])
});
// ...
});
While overall this works, there are at least a couple of serious pain points:
We need to repeat the keys in the test file and come up with some sort of translation for them. This is tedious and hurts when the texts need to change over time.
When the component for some reason does not translate the text we can get an unhelpful error message like Expected "A lot of text rendered by component along with My text to translate and other text" to contain "Mój przetłumaczony tekst". This does not quickly point to what exactly is wrong.
If the test itself has issues and the TRANSLATED object has missing / misaligned keys we get an ever worse error message like Expected "..." to contain undefined.
Describe the solution you'd like
I would like the testing tools to return a clearly identifiable text for whatever translation key it is asked for.
For example, for a key like "My translation key" it could return text like "Translation for 'My translation key'".
Ideally, when the key contains params, the values of those params would be included in the translation.
For example, if the component template contains 'My key with {{param1}} and {{param2}}' | translate: {param1: "foo", param2: "bar"}, the rendered text could be "Translation for 'My key with {{param1}} and {{param2}}' with parameters: {param1: "foo", param2: "bar"}".
If this is done, the test stub I included above could be simplified to:
describe('MyComponent', () => {
let translateService: TranslateService;
// ...
beforeEach(() => {
TestBed.configureTestingModule({
// ...
imports: [TranslateTestingModule]
});
translateService = TestBed.inject(TranslateService)
});
// ...
it('should show translated text', () => {
expect(allText()).toContain(translateService.instant("My text to translate"));
});
// ...
});
Or even:
import { translationPlaceholderFor, TranslateTestingModule } from "ngx-translate-testing";
describe('MyComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
// ...
imports: [TranslateTestingModule]
});
});
// ...
it('should show translated text', () => {
expect(allText()).toContain(translationPlaceholderFor('My text to translate'));
});
// ...
});
Describe alternatives you've considered
I have considered writing a function that accepts translation keys as an array of strings and returns a TRANSLATED object as in the first example. This would still require us to repeat each translation key in the test file at least twice and would not play nicely with keys that contain parameters.
Additional context
I think this could be introduced in a backwards compatible way. If somebody already imports TranslateTestingModule.withTranslations(...)... in their testing module, those translation could still be used instead of the new, placeholder ones. Alternatively, we could provide a separate method like TranslateTestingModule.withPlaceholderTranslations() to make the feature even more explicit and opt-in.
I am happy to provide a PR that would introduce this.
Is your feature request related to a problem? Please describe. We are using a following workflow to provide translations in the app:
This means that the translated texts are never committed into the repository along with the code and we cannot use them in tests directly.
At the same time, we would not like to tie our component tests to a specific implementation of the translation (
TranslatePipe
/TranslateService
). We would like to still just test that the component renders the translated text, not the key itself.The current solution we use looks something like the following:
While overall this works, there are at least a couple of serious pain points:
Expected "A lot of text rendered by component along with My text to translate and other text" to contain "Mój przetłumaczony tekst"
. This does not quickly point to what exactly is wrong.TRANSLATED
object has missing / misaligned keys we get an ever worse error message likeExpected "..." to contain undefined
.Describe the solution you'd like I would like the testing tools to return a clearly identifiable text for whatever translation key it is asked for. For example, for a key like "My translation key" it could return text like "Translation for 'My translation key'".
Ideally, when the key contains params, the values of those params would be included in the translation. For example, if the component template contains
'My key with {{param1}} and {{param2}}' | translate: {param1: "foo", param2: "bar"}
, the rendered text could be "Translation for 'My key with {{param1}} and {{param2}}' with parameters: {param1: "foo", param2: "bar"}".If this is done, the test stub I included above could be simplified to:
Or even:
Describe alternatives you've considered I have considered writing a function that accepts translation keys as an array of strings and returns a
TRANSLATED
object as in the first example. This would still require us to repeat each translation key in the test file at least twice and would not play nicely with keys that contain parameters.Additional context I think this could be introduced in a backwards compatible way. If somebody already imports
TranslateTestingModule.withTranslations(...)...
in their testing module, those translation could still be used instead of the new, placeholder ones. Alternatively, we could provide a separate method likeTranslateTestingModule.withPlaceholderTranslations()
to make the feature even more explicit and opt-in.I am happy to provide a PR that would introduce this.