import React from 'react'; import { _t, _tDom, TranslatedString, setLanguage, setMissingEntryGenerator, substitute, } from '../../src/languageHandler'; import { stubClient } from '../test-utils'; describe('languageHandler', function() { const basicString = 'Rooms'; const selfClosingTagSub = 'Accept to continue:'; const textInTagSub = 'Upgrade to your own domain'; const plurals = 'and %(count)s others...'; const variableSub = 'You are now ignoring %(userId)s'; type TestCase = [string, string, Record, Record, TranslatedString]; const testCasesEn: TestCase[] = [ ['translates a basic string', basicString, {}, undefined, 'Rooms'], [ 'handles plurals when count is 0', plurals, { count: 0 }, undefined, 'and 0 others...', ], [ 'handles plurals when count is 1', plurals, { count: 1 }, undefined, 'and one other...', ], [ 'handles plurals when count is not 1', plurals, { count: 2 }, undefined, 'and 2 others...', ], [ 'handles simple variable substitution', variableSub, { userId: 'foo' }, undefined, 'You are now ignoring foo', ], [ 'handles simple tag substitution', selfClosingTagSub, {}, { 'policyLink': () => 'foo' }, 'Accept foo to continue:', ], ['handles text in tags', textInTagSub, {}, { 'a': (sub) => `x${sub}x` }, 'xUpgradex to your own domain'], [ 'handles variable substitution with React function component', variableSub, { userId: () => foo }, undefined, // eslint-disable-next-line react/jsx-key You are now ignoring foo, ], [ 'handles variable substitution with react node', variableSub, { userId: foo }, undefined, // eslint-disable-next-line react/jsx-key You are now ignoring foo, ], [ 'handles tag substitution with React function component', selfClosingTagSub, {}, { 'policyLink': () => foo }, // eslint-disable-next-line react/jsx-key Accept foo to continue:, ], ]; describe('when translations exist in language', () => { beforeEach(function(done) { stubClient(); setLanguage('en').then(done); setMissingEntryGenerator(key => key.split("|", 2)[1]); }); it('translates a string to german', function(done) { setLanguage('de').then(function() { const translated = _t(basicString); expect(translated).toBe('Räume'); }).then(done); }); it.each(testCasesEn)("%s", async (_d, translationString, variables, tags, result) => { expect(_t(translationString, variables, tags)).toEqual(result); }); it('replacements in the wrong order', function() { const text = '%(var1)s %(var2)s'; expect(_t(text, { var2: 'val2', var1: 'val1' })).toBe('val1 val2'); }); it('multiple replacements of the same variable', function() { const text = '%(var1)s %(var1)s'; expect(substitute(text, { var1: 'val1' })).toBe('val1 val1'); }); it('multiple replacements of the same tag', function() { const text = 'Click here to join the discussion! or here'; expect(substitute(text, {}, { 'a': (sub) => `x${sub}x` })) .toBe('xClick herex to join the discussion! xor herex'); }); }); describe('for a non-en language', () => { beforeEach(async () => { stubClient(); await setLanguage('lv'); // counterpart doesnt expose any way to restore default config // missingEntryGenerator is mocked in the root setup file // reset to default here const counterpartDefaultMissingEntryGen = function(key) { return 'missing translation: ' + key; }; setMissingEntryGenerator(counterpartDefaultMissingEntryGen); }); // mocked lv has only `"Uploading %(filename)s and %(count)s others|one"` const lvExistingPlural = 'Uploading %(filename)s and %(count)s others'; const lvNonExistingPlural = '%(spaceName)s and %(count)s others'; describe('pluralization', () => { const pluralCases = [ [ 'falls back when plural string exists but not for for count', lvExistingPlural, { count: 2, filename: 'test.txt' }, undefined, 'Uploading test.txt and 2 others', ], [ 'falls back when plural string does not exists at all', lvNonExistingPlural, { count: 2, spaceName: 'test' }, undefined, 'test and 2 others', ], ] as TestCase[]; describe('_t', () => { it('translated correctly when plural string exists for count', () => { expect(_t( lvExistingPlural, { count: 1, filename: 'test.txt' }, undefined)).toEqual('Качване на test.txt и 1 друг'); }); it.each(pluralCases)( "%s", async (_d, translationString, variables, tags, result) => { expect(_t(translationString, variables, tags)).toEqual(result); }, ); }); describe('_tDom()', () => { it('translated correctly when plural string exists for count', () => { expect(_tDom( lvExistingPlural, { count: 1, filename: 'test.txt' }, undefined)).toEqual('Качване на test.txt и 1 друг'); }); it.each(pluralCases)( "%s and translates with fallback locale, attributes fallback locale", async (_d, translationString, variables, tags, result) => { expect(_tDom(translationString, variables, tags)).toEqual({ result }); }, ); }); }); describe('when a translation string does not exist in active language', () => { describe('_t', () => { it.each(testCasesEn)( "%s and translates with fallback locale", async (_d, translationString, variables, tags, result) => { expect(_t(translationString, variables, tags)).toEqual(result); }, ); }); describe('_tDom()', () => { it.each(testCasesEn)( "%s and translates with fallback locale, attributes fallback locale", async (_d, translationString, variables, tags, result) => { expect(_tDom(translationString, variables, tags)).toEqual({ result }); }, ); }); }); }); });