diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index 6dfef6d1aeb..0b33cd6a185 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -88,8 +88,25 @@ export function _td(s: string): string { // eslint-disable-line @typescript-esli * */ const translateWithFallback = (text: string, options?: object): { translated?: string, isFallback?: boolean } => { const translated = counterpart.translate(text, { ...options, fallbackLocale: counterpart.getLocale() }); - if (!translated || /^missing translation:/.test(translated)) { + if (!translated || translated.startsWith("missing translation:")) { const fallbackTranslated = counterpart.translate(text, { ...options, locale: FALLBACK_LOCALE }); + if ((!fallbackTranslated || fallbackTranslated.startsWith("missing translation:")) + && process.env.NODE_ENV !== "development") { + // Even the translation via FALLBACK_LOCALE failed; this can happen if + // + // 1. The string isn't in the translations dictionary, usually because you're in develop + // and haven't run yarn i18n + // 2. Loading the translation resources over the network failed, which can happen due to + // to network or if the client tried to load a translation that's been removed from the + // server. + // + // At this point, its the lesser evil to show the untranslated text, which + // will be in English, so the user can still make out *something*, rather than an opaque + // "missing translation" error. + // + // Don't do this in develop so people remember to run yarn i18n. + return { translated: text, isFallback: true }; + } return { translated: fallbackTranslated, isFallback: true }; } return { translated }; diff --git a/test/components/views/settings/__snapshots__/KeyboardShortcut-test.tsx.snap b/test/components/views/settings/__snapshots__/KeyboardShortcut-test.tsx.snap index e4468c802f0..23062d79809 100644 --- a/test/components/views/settings/__snapshots__/KeyboardShortcut-test.tsx.snap +++ b/test/components/views/settings/__snapshots__/KeyboardShortcut-test.tsx.snap @@ -32,7 +32,7 @@ exports[`KeyboardShortcut doesn't render same modifier twice 1`] = ` > - missing translation: en|Ctrl + Ctrl + @@ -70,7 +70,7 @@ exports[`KeyboardShortcut doesn't render same modifier twice 2`] = ` > - missing translation: en|Ctrl + Ctrl + @@ -95,7 +95,7 @@ exports[`KeyboardShortcut renders alternative key name 1`] = ` > - missing translation: en|Page Down + Page Down + diff --git a/test/components/views/settings/tabs/user/__snapshots__/KeyboardUserSettingsTab-test.tsx.snap b/test/components/views/settings/tabs/user/__snapshots__/KeyboardUserSettingsTab-test.tsx.snap index caeea350f7b..71bab7f6129 100644 --- a/test/components/views/settings/tabs/user/__snapshots__/KeyboardUserSettingsTab-test.tsx.snap +++ b/test/components/views/settings/tabs/user/__snapshots__/KeyboardUserSettingsTab-test.tsx.snap @@ -8,7 +8,7 @@ exports[`KeyboardUserSettingsTab renders list of keyboard shortcuts 1`] = `
- missing translation: en|Keyboard + Keyboard
- missing translation: en|Composer + Composer
@@ -59,7 +59,7 @@ exports[`KeyboardUserSettingsTab renders list of keyboard shortcuts 1`] = ` > - missing translation: en|Ctrl + Ctrl + @@ -103,7 +103,7 @@ exports[`KeyboardUserSettingsTab renders list of keyboard shortcuts 1`] = ` > - missing translation: en|Ctrl + Ctrl + @@ -145,7 +145,7 @@ exports[`KeyboardUserSettingsTab renders list of keyboard shortcuts 1`] = `
- missing translation: en|Navigation + Navigation
@@ -173,7 +173,7 @@ exports[`KeyboardUserSettingsTab renders list of keyboard shortcuts 1`] = ` > - missing translation: en|Enter + Enter diff --git a/test/i18n-test/languageHandler-test.tsx b/test/i18n-test/languageHandler-test.tsx index 7013b9a03ae..9c15bfd3feb 100644 --- a/test/i18n-test/languageHandler-test.tsx +++ b/test/i18n-test/languageHandler-test.tsx @@ -27,6 +27,10 @@ import { import { stubClient } from '../test-utils'; describe('languageHandler', function() { + /* + See /__mocks__/browser-request.js/ for how we are stubbing out translations + to provide fixture data for these tests + */ const basicString = 'Rooms'; const selfClosingTagSub = 'Accept to continue:'; const textInTagSub = 'Upgrade to your own domain'; @@ -35,6 +39,7 @@ describe('languageHandler', function() { type TestCase = [string, string, Record, Record, TranslatedString]; const testCasesEn: TestCase[] = [ + // description of the test case, translationString, variables, tags, expected result ['translates a basic string', basicString, {}, undefined, 'Rooms'], [ 'handles plurals when count is 0', @@ -217,4 +222,17 @@ describe('languageHandler', function() { }); }); }); + + describe('when languages dont load', () => { + it('_t', async () => { + const STRING_NOT_IN_THE_DICTIONARY = "a string that isn't in the translations dictionary"; + expect(_t(STRING_NOT_IN_THE_DICTIONARY, {}, undefined)).toEqual(STRING_NOT_IN_THE_DICTIONARY); + }); + + it('_tDom', async () => { + const STRING_NOT_IN_THE_DICTIONARY = "a string that isn't in the translations dictionary"; + expect(_tDom(STRING_NOT_IN_THE_DICTIONARY, {}, undefined)).toEqual( + { STRING_NOT_IN_THE_DICTIONARY }); + }); + }); });