Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "openstack-uicore-foundation",
"version": "5.0.60",
"version": "5.0.62",
"description": "ui reactjs components for openstack marketing site",
"main": "lib/openstack-uicore-foundation.js",
"scripts": {
Expand Down
50 changes: 50 additions & 0 deletions src/i18n/__tests__/i18n.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import en from "../en.json";
import zh from "../zh.json";

const loadI18n = async (language) => {
jest.resetModules();
jest.doMock("../../utils/methods", () => ({
getCurrentUserLanguage: () => language
}));
const T = (await import("i18n-react")).default;
const i18n = await import("../i18n");
return { T, ...i18n };
};

describe("i18n lib translations", () => {
afterEach(() => {
jest.dontMock("../../utils/methods");
});

it("uses the matching bundle when the key is translated", async () => {
const { T } = await loadI18n("zh-CN");
expect(T.translate("general.save")).toBe(zh.general.save);
});

it("falls back to English for keys missing from a partial bundle", async () => {
const { T } = await loadI18n("zh-CN");
// zh.json only translates errors/general, so this would otherwise render
// the raw key
expect(T.translate("sponsor_order_grid.code")).toBe(
en.sponsor_order_grid.code
);
});

it("falls back to English for unsupported languages", async () => {
const { T } = await loadI18n("fr-FR");
expect(T.translate("general.save")).toBe(en.general.save);
expect(T.translate("sponsor_order_grid.code")).toBe(
en.sponsor_order_grid.code
);
});

it("lets consumer texts win but keeps the lib fallbacks in setAppTexts", async () => {
const { T, setAppTexts } = await loadI18n("zh-CN");
setAppTexts({ sponsor_order_grid: { code: "Custom Code" } });
expect(T.translate("sponsor_order_grid.code")).toBe("Custom Code");
expect(T.translate("sponsor_order_grid.type")).toBe(
en.sponsor_order_grid.type
);
expect(T.translate("general.save")).toBe(zh.general.save);
});
});
23 changes: 15 additions & 8 deletions src/i18n/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,19 @@ if (language.length > 2) {
language = language.split("_")[0];
}

try {
T.setTexts(resources[language]);
} catch (e) {
T.setTexts(resources['en']);
}
/**
* Returns the lib translations for the given language, deep-merged on top of
* English. Non english bundles are partial (they only translate a subset of the
* keys), so without this merge any key missing from them would be rendered as
* the raw key (i18n-react returns the key itself when it is not found).
* Unsupported languages fall back to English entirely.
*
* @param {string} lang
* @returns {object}
*/
const getLibTexts = (lang) => merge({}, resources['en'], resources[lang] || {});

T.setTexts(getLibTexts(language));

/**
* Call this instead of T.setTexts() in consumer apps.
Expand All @@ -37,6 +45,5 @@ try {
* @param {object} customTexts - your app's translation object
*/
export const setAppTexts = (customTexts = {}) => {
const libTexts = resources[language] || resources['en'];
T.setTexts(merge({}, libTexts, customTexts));
};
T.setTexts(merge({}, getLibTexts(language), customTexts));
};
Loading