Skip to content

Commit 1973286

Browse files
jackfranklinDevtools-frontend LUCI CQ
authored andcommitted
i18n: fall back to en-US for simple strings
This CL fixes an edge case where a UIString has had a placeholder removed. On Canary (where we do not have up to date translations in all locales), this caused an error. With this CL we will now catch this error and fall back to en-US. Bug: none Change-Id: Idfb05255227c3006dd5dd4b5c200073864b7bf25 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6054628 Reviewed-by: Simon Zünd <szuend@chromium.org> Commit-Queue: Jack Franklin <jacktfranklin@chromium.org>
1 parent 04da555 commit 1973286

File tree

2 files changed

+58
-3
lines changed

2 files changed

+58
-3
lines changed

front_end/core/i18n/i18n.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ describe('getLocalizedLanguageRegion', () => {
7979
describe('getFormatLocalizedString', () => {
8080
let i18nInstance: i18nRaw.I18n.I18n;
8181
beforeEach(() => {
82+
i18n.DevToolsLocale.DevToolsLocale.instance({
83+
create: true,
84+
data: {
85+
navigatorLanguage: 'en-US',
86+
settingLanguage: 'en-US',
87+
lookupClosestDevToolsLocale: () => 'en-US',
88+
},
89+
});
8290
i18nInstance = new i18nRaw.I18n.I18n(['en-US'], 'en-US');
8391
i18nInstance.registerLocaleData('en-US', {}); // Always fall back to UIStrings.
8492
});
@@ -118,6 +126,43 @@ describe('getFormatLocalizedString', () => {
118126
});
119127
});
120128

129+
describe('falling back when a locale errors', () => {
130+
it('reverts to using the UIStrings directly', async () => {
131+
i18n.DevToolsLocale.DevToolsLocale.instance({
132+
create: true,
133+
data: {
134+
// Create the locale and set en-GB to default. This test is going to
135+
// assert that when there is an error with the en-GB string that we
136+
// fallback.
137+
navigatorLanguage: 'en-GB',
138+
settingLanguage: 'en-GB',
139+
lookupClosestDevToolsLocale: () => 'en-GB',
140+
},
141+
});
142+
const i18nInstance = new i18nRaw.I18n.I18n(['en-GB', 'en-US'], 'en-US');
143+
144+
// Recreate the bug that can happen in Canary: the en-US translation is up
145+
// to date (no PH1 placeholder), but the en-GB translation is out of date.
146+
// We expect that in this instance we should fallback to en-US.
147+
i18nInstance.registerLocaleData('en-US', {
148+
'test.ts | placeholder': {message: 'US: hello world'},
149+
});
150+
// Register the (outdated) en-GB string.
151+
i18nInstance.registerLocaleData('en-GB', {
152+
'test.ts | placeholder': {message: 'GB: hello {PH1}'},
153+
});
154+
155+
const uiStrings = {placeholder: 'US: hello world'};
156+
const registeredStrings = i18nInstance.registerFileStrings('test.ts', uiStrings);
157+
158+
// We should see "hello world" because we don't pass the placeholder value,
159+
// and that means the en-GB translations are invalid, and we fallback to
160+
// the UIStrings.
161+
const output = i18n.i18n.getLocalizedString(registeredStrings, uiStrings.placeholder);
162+
assert.strictEqual(output, 'US: hello world');
163+
});
164+
});
165+
121166
describe('fetchAndRegisterLocaleData', () => {
122167
let fetchStub: sinon.SinonStub;
123168

front_end/third_party/i18n/localized-string-set.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,19 @@ export class LocalizedStringSet {
9494
}
9595

9696
const formatter = this.getMessageFormatterFor(message);
97-
const translatedString = formatter.format() as string;
98-
this.cachedSimpleStrings.set(message, translatedString);
99-
return translatedString;
97+
try {
98+
const translatedString = formatter.format() as string;
99+
this.cachedSimpleStrings.set(message, translatedString);
100+
return translatedString;
101+
} catch (e) {
102+
// The message could have been updated and use different placeholders then
103+
// the translation. This is a rare edge case so it's fine to create a temporary
104+
// IntlMessageFormat and fall back to the UIStrings message.
105+
const formatter = new IntlMessageFormat.IntlMessageFormat(message, this.localeForFormatter, undefined, {ignoreTag: true});
106+
const translatedString = formatter.format() as string;
107+
this.cachedSimpleStrings.set(message, translatedString);
108+
return translatedString;
109+
}
100110
}
101111

102112
private getFormattedLocalizedString(message: string, values: Values): string {

0 commit comments

Comments
 (0)