Skip to content

Commit

Permalink
(fix) Add better support for loading multiple namespaces at once (#1132)
Browse files Browse the repository at this point in the history
  • Loading branch information
ibacher authored Aug 30, 2024
1 parent 7c66881 commit f04c8ac
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1259,11 +1259,13 @@ describe('translation overrides', () => {
});
Config.registerModuleWithConfigSystem('corge-module');
const translationOverrides = await Config.getTranslationOverrides('corge-module');
expect(translationOverrides).toStrictEqual({
en: {
'foo.bar': 'baz',
expect(translationOverrides).toStrictEqual([
{
en: {
'foo.bar': 'baz',
},
},
});
]);
Config.defineConfigSchema('corge-module', {
corges: { _default: false, _type: Type.Boolean },
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ export function getTranslationOverrides(
moduleName: string,
slotName?: string,
extensionId?: string,
): Promise<Record<string, Record<string, string>>> {
): Promise<Array<Record<string, Record<string, string>>>> {
const promises = [
new Promise<Record<string, Record<string, string>>>((resolve) => {
const configStore = getConfigStore(moduleName);
Expand Down Expand Up @@ -309,7 +309,7 @@ export function getTranslationOverrides(
);
}

return Promise.all(promises).then((results) => results.reduce((prev, current) => mergeDeepRight(prev, current), {}));
return Promise.all(promises);
}

/**
Expand Down
13 changes: 7 additions & 6 deletions packages/framework/esm-framework/docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -876,7 +876,7 @@ ___

#### Defined in

[packages/framework/esm-translations/src/index.ts:47](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-translations/src/index.ts#L47)
[packages/framework/esm-translations/src/index.ts:53](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-translations/src/index.ts#L53)

___

Expand Down Expand Up @@ -6470,15 +6470,15 @@ invalid key to this function will result in a type error.
| :------ | :------ | :------ |
| `key` | ``"error"`` \| ``"change"`` \| ``"close"`` \| ``"other"`` \| ``"actions"`` \| ``"address"`` \| ``"age"`` \| ``"cancel"`` \| ``"confirm"`` \| ``"contactAdministratorIfIssuePersists"`` \| ``"contactDetails"`` \| ``"errorCopy"`` \| ``"female"`` \| ``"hideDetails"`` \| ``"loading"`` \| ``"male"`` \| ``"patientIdentifierSticker"`` \| ``"patientLists"`` \| ``"print"`` \| ``"printError"`` \| ``"printErrorExplainer"`` \| ``"printIdentifierSticker"`` \| ``"printing"`` \| ``"relationships"`` \| ``"resetOverrides"`` \| ``"scriptLoadingFailed"`` \| ``"scriptLoadingError"`` \| ``"seeMoreLists"`` \| ``"sex"`` \| ``"showDetails"`` \| ``"unknown"`` \| ``"closeAllOpenedWorkspaces"`` \| ``"closingAllWorkspacesPromptBody"`` \| ``"closingAllWorkspacesPromptTitle"`` \| ``"discard"`` \| ``"hide"`` \| ``"maximize"`` \| ``"minimize"`` \| ``"openAnyway"`` \| ``"unsavedChangesInOpenedWorkspace"`` \| ``"unsavedChangesInWorkspace"`` \| ``"unsavedChangesTitleText"`` \| ``"workspaceHeader"`` \| ``"address1"`` \| ``"address2"`` \| ``"address3"`` \| ``"address4"`` \| ``"address5"`` \| ``"address6"`` \| ``"city"`` \| ``"cityVillage"`` \| ``"country"`` \| ``"countyDistrict"`` \| ``"postalCode"`` \| ``"state"`` \| ``"stateProvince"`` | - |
| `defaultText?` | `string` | - |
| `options?` | `object` | Object passed to the i18next `t` function. See https://www.i18next.com/translation-function/essentials#overview-options for more information. `ns` and `defaultValue` are already set and may not be used. |
| `options?` | `Omit`<`TOptions`<`StringMap`\>, ``"defaultValue"`` \| ``"ns"``\> | Object passed to the i18next `t` function. See https://www.i18next.com/translation-function/essentials#overview-options for more information. `ns` and `defaultValue` are already set and may not be used. |
#### Returns
`string`
#### Defined in
[packages/framework/esm-translations/src/index.ts:60](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-translations/src/index.ts#L60)
[packages/framework/esm-translations/src/index.ts:66](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-translations/src/index.ts#L66)
___
Expand All @@ -6497,7 +6497,8 @@ Translations within the current app should be accessed with the i18next API, usi
IMPORTANT: This function creates a hidden dependency on the module. Worse yet, it creates
a dependency specifically on that module's translation keys, which are often regarded as
"implementation details" and therefore may be volatile.
"implementation details" and therefore may be volatile. Also note that this function DOES NOT
load the module's translations if they have not already been loaded via `useTranslation`.
**This function should therefore be avoided when possible.**
#### Parameters
Expand All @@ -6507,7 +6508,7 @@ a dependency specifically on that module's translation keys, which are often reg
| `moduleName` | `string` | The module to get the translation from, e.g. '@openmrs/esm-login-app' |
| `key` | `string` | The i18next translation key |
| `fallback?` | `string` | Fallback text for if the lookup fails |
| `options?` | `object` | Options object passed to the i18next `t` function. See https://www.i18next.com/translation-function/essentials#overview-options for more information. `ns` and `defaultValue` are already set and may not be used. |
| `options?` | `Omit`<`TOptions`<`StringMap`\>, ``"defaultValue"`` \| ``"ns"``\> | Options object passed to the i18next `t` function. See https://www.i18next.com/translation-function/essentials#overview-options for more information. `ns` and `defaultValue` are already set and may not be used. |
#### Returns
Expand All @@ -6517,7 +6518,7 @@ The translated text as a string
#### Defined in
[packages/framework/esm-translations/src/index.ts:39](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-translations/src/index.ts#L39)
[packages/framework/esm-translations/src/index.ts:40](https://github.com/openmrs/openmrs-esm-core/blob/main/packages/framework/esm-translations/src/index.ts#L40)
___
Expand Down
18 changes: 14 additions & 4 deletions packages/framework/esm-translations/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** @module @category Translation */
import { coreTranslations } from './translations';
import _i18n, { i18n } from 'i18next';
import _i18n, { i18n, type TOptions } from 'i18next';

const i18n: typeof _i18n = (_i18n as unknown as { default: typeof _i18n }).default || _i18n;

Expand All @@ -26,7 +26,8 @@ i18n.on('initialized', function () {
*
* IMPORTANT: This function creates a hidden dependency on the module. Worse yet, it creates
* a dependency specifically on that module's translation keys, which are often regarded as
* "implementation details" and therefore may be volatile.
* "implementation details" and therefore may be volatile. Also note that this function DOES NOT
* load the module's translations if they have not already been loaded via `useTranslation`.
* **This function should therefore be avoided when possible.**
*
* @param moduleName The module to get the translation from, e.g. '@openmrs/esm-login-app'
Expand All @@ -36,7 +37,12 @@ i18n.on('initialized', function () {
* for more information. `ns` and `defaultValue` are already set and may not be used.
* @returns The translated text as a string
*/
export function translateFrom(moduleName: string, key: string, fallback?: string, options?: object) {
export function translateFrom(
moduleName: string,
key: string,
fallback?: string,
options?: Omit<TOptions, 'ns' | 'defaultValue'>,
) {
return i18n.t(key, {
ns: moduleName,
defaultValue: fallback,
Expand All @@ -57,7 +63,11 @@ export type CoreTranslationKey = keyof typeof coreTranslations;
* @param options Object passed to the i18next `t` function. See https://www.i18next.com/translation-function/essentials#overview-options
* for more information. `ns` and `defaultValue` are already set and may not be used.
*/
export function getCoreTranslation(key: CoreTranslationKey, defaultText?: string, options?: object): string {
export function getCoreTranslation(
key: CoreTranslationKey,
defaultText?: string,
options?: Omit<TOptions, 'ns' | 'defaultValue'>,
): string {
if (!coreTranslations[key]) {
console.error(`O3 Core Translations does not provide key '${key}'. The key itself is being rendered as text.`);
return key;
Expand Down
22 changes: 20 additions & 2 deletions packages/shell/esm-app-shell/src/locale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,28 @@ export function setupI18n() {
.then(([json, overrides]) => {
let translations = json ?? {};

if (language in overrides) {
translations = merge(translations, overrides[language]);
// if we have a slotName and extensionId, it means that we're only loading the namespace for that extension
// in that slot, but we _also_ process the base translations for the namespace and any top-level config overrides
// so here we also provide the translations for just the namespace before merging everything together
if (slotName && extensionId) {
if (overrides.length >= 1 && language in overrides[0]) {
window.i18next.addResourceBundle(
language,
ns,
merge(translations, overrides[0][language]),
true,
false,
);
} else {
window.i18next.addResourceBundle(language, ns, translations, true, false);
}
}

translations = merge(
translations,
overrides.filter((o) => language in o),
);

callback(null, translations);
})
.catch((err: Error) => {
Expand Down

0 comments on commit f04c8ac

Please sign in to comment.