Skip to content

Commit

Permalink
Merge pull request #4112 from easyops-cn/nlicro/MONITOR-8335
Browse files Browse the repository at this point in the history
feat(): support userConfig.settings.locales
  • Loading branch information
weareoutman authored Apr 22, 2024
2 parents 20711ac + 942e9cc commit fddb454
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 33 deletions.
86 changes: 86 additions & 0 deletions packages/brick-container/src/loadBootstrapData.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { jest, describe, test, expect } from "@jest/globals";
import { i18n } from "@next-core/i18n";
import { http } from "@next-core/http";
import {
BootstrapStandaloneApi_runtimeStandalone,
Expand All @@ -9,6 +10,9 @@ import { RuntimeApi_runtimeMicroAppStandalone } from "@next-api-sdk/micro-app-st
import { fulfilStoryboard, loadBootstrapData } from "./loadBootstrapData.js";
import { registerMocks } from "./mocks.js";

i18n.init({
fallbackLng: "en",
});
jest.mock("@next-core/http");
jest.mock("@next-api-sdk/api-gateway-sdk");
jest.mock("@next-api-sdk/micro-app-standalone-sdk");
Expand Down Expand Up @@ -181,6 +185,43 @@ jest.spyOn(http, "get").mockImplementation(async (url) => {
},
],
};
case "bootstrap.app-h.json":
return {
brickPackages: [],
storyboards: [
{
app: {
id: "app-h",
name: "App H",
locales: {
zh: { name: "应用 H" },
en: { name: "Application H" },
},
defaultConfig: {
defaultConf: 7,
},
userConfig: {
userConf: 8,
settings: {
locales: {
zh: { name: "应用 H 别名" },
en: { name: "Application H Alias" },
},
},
},
},
},
],
settings: {
featureFlags: {
"bootstrap-flag": true,
},
misc: {
bootstrapMisc: 1,
},
homepage: "/bootstrap/homepage",
},
};
case "bootstrap-union.cmdb.abg.json":
return {
brickPackages: [],
Expand Down Expand Up @@ -220,6 +261,7 @@ jest.spyOn(http, "get").mockImplementation(async (url) => {
],
};
case "sa-static/app-a/versions/1.88.0/webroot/conf.yaml":
case "sa-static/app-h/versions/1.88.0/webroot/conf.yaml":
return "";
case "app-b/conf.yaml":
return `
Expand Down Expand Up @@ -307,6 +349,7 @@ describe("loadBootstrapData", () => {
app: {
id: "app-a",
name: "App A",
localeName: "Application A",
locales: {
zh: { name: "应用 A" },
en: { name: "Application A" },
Expand Down Expand Up @@ -412,6 +455,7 @@ describe("loadBootstrapData", () => {
config: { runtimeUserConf: 9 },
homepage: "/app-g",
id: "app-g",
localeName: "Application G",
locales: { en: { name: "Application G" }, zh: { name: "应用 G" } },
name: "App G",
userConfig: { runtimeUserConf: 9 },
Expand Down Expand Up @@ -442,6 +486,7 @@ describe("loadBootstrapData", () => {
config: { runtimeUserConf: 9 },
homepage: "/app-a",
id: "app-a",
localeName: "Application A",
locales: { en: { name: "Application A" }, zh: { name: "应用 A" } },
name: "App A",
userConfig: { runtimeUserConf: 9 },
Expand Down Expand Up @@ -537,6 +582,7 @@ describe("loadBootstrapData", () => {
config: { runtimeUserConf: 9 },
homepage: "/app-g",
id: "app-g",
localeName: "Application G",
locales: { en: { name: "Application G" }, zh: { name: "应用 G" } },
name: "App G",
userConfig: { runtimeUserConf: 9 },
Expand Down Expand Up @@ -567,6 +613,7 @@ describe("loadBootstrapData", () => {
config: { runtimeUserConf: 9 },
homepage: "/app-a",
id: "app-a",
localeName: "Application A",
locales: { en: { name: "Application A" }, zh: { name: "应用 A" } },
name: "App A",
userConfig: { runtimeUserConf: 9 },
Expand Down Expand Up @@ -752,6 +799,7 @@ describe("loadBootstrapData", () => {
app: {
id: "app-a",
name: "App A",
localeName: "App A",
userConfig: {
userConf: 42,
},
Expand All @@ -762,4 +810,42 @@ describe("loadBootstrapData", () => {
routes: [],
});
});

test("standalone with locales", async () => {
window.STANDALONE_MICRO_APPS = true;
window.BOOTSTRAP_FILE = "bootstrap.app-h.json";
window.APP_ROOT = "sa-static/app-h/versions/1.88.0/webroot/";
const promise = loadBootstrapData();
const data = await promise;
await fulfilStoryboard(data.storyboards[0]);

expect(data.storyboards[0]).toEqual({
app: {
id: "app-h",
name: "App H",
locales: { zh: { name: "应用 H" }, en: { name: "Application H" } },
defaultConfig: { defaultConf: 7 },
userConfig: {
userConf: 8,
settings: {
locales: {
zh: { name: "应用 H 别名" },
en: { name: "Application H Alias" },
},
},
},
config: {
defaultConf: 7,
userConf: 8,
settings: {
locales: {
zh: { name: "应用 H 别名" },
en: { name: "Application H Alias" },
},
},
},
localeName: "Application H Alias",
},
});
});
});
24 changes: 24 additions & 0 deletions packages/brick-container/src/loadBootstrapData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { JSON_SCHEMA, safeLoad } from "js-yaml";
import { RuntimeApi_runtimeMicroAppStandalone } from "@next-api-sdk/micro-app-standalone-sdk";
import { imagesFactory } from "./images.js";
import { registerMocks } from "./mocks.js";
import { i18n } from "@next-core/i18n";

interface StandaloneConf {
/** The same as `auth.bootstrap.sys_settings` in api gateway conf. */
Expand Down Expand Up @@ -273,13 +274,35 @@ export async function fulfilStoryboard(storyboard: RuntimeStoryboard) {

fixStoryboardImgSrc(storyboard);
initializeAppConfig(storyboard.app);
initializeAppLocales(storyboard.app);
registerMocks(storyboard.meta?.mocks);
}

function initializeAppConfig(app: MicroApp) {
app.config = deepFreeze(merge({}, app.defaultConfig, app.userConfig));
}

function initializeAppLocales(app: MicroApp) {
const locales =
(app.config?.settings as BootstrapSettings)?.locales ?? app.locales;
if (locales) {
// Prefix to avoid conflict between brick package's i18n namespace.
const ns = `tmp/${app.id}`;
// Support any languages in `app.locales`.
Object.entries(locales).forEach(([lang, resources]) => {
i18n.addResourceBundle(lang, ns, resources);
});
// Use `app.name` as the fallback `app.localeName`.
app.localeName = i18n.getFixedT(null, ns)("name", app.name) as string;
// Remove the temporary i18n resource bundles.
Object.keys(locales).forEach((lang) => {
i18n.removeResourceBundle(lang, ns);
});
} else {
app.localeName = app.name;
}
}

// function initializeInjectMenus(menus: MenuRawData[] | undefined) {
function initializeInjectMenus(menus: any[] | undefined) {
if (!Array.isArray(menus)) {
Expand All @@ -288,6 +311,7 @@ function initializeInjectMenus(menus: any[] | undefined) {
for (const menu of menus) {
if (menu.overrideApp) {
initializeAppConfig(menu.overrideApp);
initializeAppLocales(menu.overrideApp);
}
}
}
Expand Down
16 changes: 3 additions & 13 deletions packages/runtime/src/internal/Runtime.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ window.scrollTo = jest.fn();
const getBootstrapData = (options?: {
templates?: boolean;
settings?: boolean;
locales?: boolean;
}): BootstrapData => ({
storyboards: [
{
Expand All @@ -44,13 +43,6 @@ const getBootstrapData = (options?: {
},
},
},
locales: options?.locales
? {
en: {
name: "Application A",
},
}
: undefined,
},
routes: [
{
Expand All @@ -60,7 +52,7 @@ const getBootstrapData = (options?: {
{
brick: "div",
properties: {
textContent: "<% `I'm homepage of ${APP.localeName}` %>",
textContent: "<% `I'm homepage of ${APP.name}` %>",
},
},
],
Expand Down Expand Up @@ -615,9 +607,7 @@ describe("Runtime", () => {
});

test("basic page", async () => {
createRuntime().initialize(
getBootstrapData({ settings: true, locales: true })
);
createRuntime().initialize(getBootstrapData({ settings: true }));
getHistory().push("/app-a");
expect(window.DISABLE_REACT_FLUSH_SYNC).toBeFalsy();
await getRuntime().bootstrap();
Expand All @@ -631,7 +621,7 @@ describe("Runtime", () => {
id="main-mount-point"
>
<div>
I'm homepage of Application A
I'm homepage of App A
</div>
</div>,
<div
Expand Down
20 changes: 0 additions & 20 deletions packages/runtime/src/internal/Runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,26 +305,6 @@ export class Runtime {
}

function normalizeBootstrapData(data: BootstrapData) {
if (Array.isArray(data.storyboards)) {
for (const { app } of data.storyboards) {
if (app.locales) {
// Prefix to avoid conflict between brick package's i18n namespace.
const ns = `tmp/${app.id}`;
// Support any languages in `app.locales`.
Object.entries(app.locales).forEach(([lang, resources]) => {
i18n.addResourceBundle(lang, ns, resources);
});
// Use `app.name` as the fallback `app.localeName`.
app.localeName = i18n.getFixedT(null, ns)("name", app.name) as string;
// Remove the temporary i18n resource bundles.
Object.keys(app.locales).forEach((lang) => {
i18n.removeResourceBundle(lang, ns);
});
} else {
app.localeName = app.name;
}
}
}
if (isObject(data.settings)) {
deepFreeze(data.settings);
}
Expand Down

0 comments on commit fddb454

Please sign in to comment.