Skip to content

Commit

Permalink
feat: HMR for translations (#2795)
Browse files Browse the repository at this point in the history
* feat: HMR for translations

* make HMR for translations work

* try adding some tests

* scope request url to language and chunks

---------

Co-authored-by: Sascha Ißbrücker <[email protected]>
  • Loading branch information
Artur- and sissbruecker authored Oct 16, 2024
1 parent 9bafcb7 commit 9017296
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 0 deletions.
35 changes: 35 additions & 0 deletions packages/ts/react-i18n/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ export class I18n {
`The Hilla I18n API is currently considered experimental and may change in the future. To use it you need to explicitly enable it in Copilot or by adding com.vaadin.experimental.hillaI18n=true to vaadin-featureflags.properties`,
);
}
// @ts-expect-error import.meta.hot does not have TS definitions
if (import.meta.hot) {
// @ts-expect-error import.meta.hot does not have TS definitions
// eslint-disable-next-line
import.meta.hot.on('translations-update', () => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.reloadTranslations();
});
}
}

/**
Expand Down Expand Up @@ -182,6 +191,32 @@ export class I18n {
});
}

/**
* Reloads all translations for the current language. This method should only
* be used for HMR in development mode.
*/
private async reloadTranslations() {
const currentLanguage = this.#language.value;
if (!currentLanguage) {
return;
}

let translationsResult: TranslationsResult;
try {
translationsResult = await this.#backend.loadTranslations(currentLanguage);
} catch (e) {
console.error(`Failed to reload translations for language: ${currentLanguage}`, e);
return;
}

// Update all signals together to avoid triggering side effects multiple times
batch(() => {
this.#translations.value = translationsResult.translations;
this.#resolvedLanguage.value = translationsResult.resolvedLanguage;
this.#formatCache = new FormatCache(currentLanguage);
});
}

/**
* Returns a translated string for the given translation key. The key should
* match a key in the loaded translations. If no translation is found for the
Expand Down
56 changes: 56 additions & 0 deletions packages/ts/react-i18n/test/i18n.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,62 @@ describe('@vaadin/hilla-react-i18n', () => {
expect(i18n.translate('param.time', { value: sampleDate })).to.equal('Value: 22:33:44');
});
});

describe('hmr', () => {
async function triggerHmrEvent() {
// @ts-expect-error import.meta.hot does not have TS definitions
// eslint-disable-next-line
import.meta.hot.hmrClient.notifyListeners('translations-update');
// No promise to wait for, just delay the next test step a bit
await new Promise((resolve) => {
setTimeout(resolve, 10);
});
}

it('should not update translations if not initialized', async () => {
expect(i18n.translate('addresses.form.city.label')).to.equal('addresses.form.city.label');
await triggerHmrEvent();
expect(i18n.translate('addresses.form.city.label')).to.equal('addresses.form.city.label');
});

it('should update translations on HMR event', async () => {
await i18n.configure({ language: 'en-US' });
expect(i18n.translate('addresses.form.city.label')).to.equal('City');

fetchMock
.resetHistory()
.reset()
.get('./?v-r=i18n&langtag=en-US', {
body: {
'addresses.form.city.label': 'City updated',
},
status: 200,
headers: { 'X-Vaadin-Retrieved-Locale': 'und' },
});

await triggerHmrEvent();

expect(i18n.translate('addresses.form.city.label')).to.equal('City updated');
});

it('should update resolved language on HMR event', async () => {
await i18n.configure({ language: 'en-US' });
expect(i18n.resolvedLanguage.value).to.equal('und');

fetchMock
.resetHistory()
.reset()
.get('*', {
body: {},
status: 200,
headers: { 'X-Vaadin-Retrieved-Locale': 'en' },
});

await triggerHmrEvent();

expect(i18n.resolvedLanguage.value).to.equal('en');
});
});
});

describe('FormatCache', () => {
Expand Down

0 comments on commit 9017296

Please sign in to comment.