generator-mico-cli 0.2.29 → 0.2.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -7
- package/generators/micro-react/README.md +34 -0
- package/generators/micro-react/index.js +19 -1
- package/generators/micro-react/templates/CICD/start_dev.sh +11 -0
- package/generators/micro-react/templates/CICD/start_local.sh +9 -0
- package/generators/micro-react/templates/CICD/start_prod.sh +13 -0
- package/generators/micro-react/templates/CICD/start_test.sh +11 -0
- package/generators/micro-react/templates/apps/layout/config/config.dev.ts +29 -3
- package/generators/micro-react/templates/apps/layout/config/config.prod.development.ts +10 -0
- package/generators/micro-react/templates/apps/layout/config/config.prod.testing.ts +10 -0
- package/generators/micro-react/templates/apps/layout/config/config.prod.ts +12 -0
- package/generators/micro-react/templates/apps/layout/config/config.ts +0 -15
- package/generators/micro-react/templates/apps/layout/docs/arch-/346/227/245/345/277/227/344/270/216/345/270/270/351/207/217.md +16 -8
- package/generators/micro-react/templates/apps/layout/docs/feat-/346/236/204/345/273/272define/344/270/216/345/205/215/350/256/244/350/257/201/345/210/235/345/247/213/346/200/201.md +49 -3
- package/generators/micro-react/templates/apps/layout/docs/feature-/345/233/275/351/231/205/345/214/226.md +121 -0
- package/generators/micro-react/templates/apps/layout/docs/feature-/345/276/256/345/211/215/347/253/257/346/250/241/345/274/217.md +8 -0
- package/generators/micro-react/templates/apps/layout/docs/feature-/350/217/234/345/215/225/346/235/203/351/231/220/346/216/247/345/210/266.md +3 -1
- package/generators/micro-react/templates/apps/layout/docs/feature-/350/267/257/347/224/261/346/235/203/351/231/220/346/227/245/345/277/227.md +4 -4
- package/generators/micro-react/templates/apps/layout/mock/menus.ts +14 -0
- package/generators/micro-react/templates/apps/layout/mock/pages.ts +22 -2
- package/generators/micro-react/templates/apps/layout/package.json +3 -2
- package/generators/micro-react/templates/apps/layout/src/app.tsx +68 -9
- package/generators/micro-react/templates/apps/layout/src/common/auth/auth-check-path.ts +14 -0
- package/generators/micro-react/templates/apps/layout/src/common/auth/index.ts +4 -0
- package/generators/micro-react/templates/apps/layout/src/common/auth/tenant.ts +25 -0
- package/generators/micro-react/templates/apps/layout/src/common/auth/type.ts +28 -2
- package/generators/micro-react/templates/apps/layout/src/common/intl/formatLayoutMessage.ts +30 -0
- package/generators/micro-react/templates/apps/layout/src/common/intl/index.ts +6 -0
- package/generators/micro-react/templates/apps/layout/src/common/intl/intlRuntime.ts +14 -0
- package/generators/micro-react/templates/apps/layout/src/common/intl/localeMapping.ts +30 -0
- package/generators/micro-react/templates/apps/layout/src/common/intl/types.ts +14 -0
- package/generators/micro-react/templates/apps/layout/src/common/intl/useLayoutIntl.ts +40 -0
- package/generators/micro-react/templates/apps/layout/src/common/logger.ts +50 -18
- package/generators/micro-react/templates/apps/layout/src/common/menu/types.ts +27 -0
- package/generators/micro-react/templates/apps/layout/src/common/micro/types.ts +23 -0
- package/generators/micro-react/templates/apps/layout/src/common/request/sso.ts +82 -20
- package/generators/micro-react/templates/apps/layout/src/common/request/token-refresh.ts +2 -0
- package/generators/micro-react/templates/apps/layout/src/components/MicroAppLoader/index.tsx +28 -6
- package/generators/micro-react/templates/apps/layout/src/components/RightContent/TenantDropdown.tsx +76 -0
- package/generators/micro-react/templates/apps/layout/src/components/RightContent/index.ts +1 -0
- package/generators/micro-react/templates/apps/layout/src/components/RightContent/tenant-dropdown.less +48 -0
- package/generators/micro-react/templates/apps/layout/src/constants/index.ts +1 -0
- package/generators/micro-react/templates/apps/layout/src/hooks/index.ts +1 -0
- package/generators/micro-react/templates/apps/layout/src/hooks/useMenuState.ts +18 -0
- package/generators/micro-react/templates/apps/layout/src/hooks/useTenant.ts +41 -0
- package/generators/micro-react/templates/apps/layout/src/layouts/components/header/index.tsx +4 -1
- package/generators/micro-react/templates/apps/layout/src/layouts/components/menu/index.tsx +18 -6
- package/generators/micro-react/templates/apps/layout/src/locales/en-US.ts +11 -0
- package/generators/micro-react/templates/apps/layout/src/locales/zh-CN.ts +10 -0
- package/generators/micro-react/templates/apps/layout/src/pages/Home/index.less +27 -0
- package/generators/micro-react/templates/apps/layout/src/pages/Home/index.tsx +108 -12
- package/generators/micro-react/templates/apps/layout/src/requestErrorConfig.ts +2 -1
- package/generators/micro-react/templates/apps/layout/src/services/user.ts +53 -2
- package/generators/micro-react/templates/apps/layout/typings.d.ts +16 -0
- package/generators/micro-react/templates/docs/package-shared.md +189 -0
- package/generators/micro-react/templates/package.json +1 -1
- package/generators/micro-react/templates/packages/common-intl/README.md +3 -1
- package/generators/micro-react/templates/packages/common-intl/package.json +1 -1
- package/generators/micro-react/templates/packages/common-intl/src/index.ts +4 -2
- package/generators/micro-react/templates/packages/common-intl/src/intl.ts +104 -8
- package/generators/micro-react/templates/packages/common-intl/src/umiLocaleBridge.ts +101 -0
- package/generators/micro-react/templates/packages/shared/README.md +120 -0
- package/generators/micro-react/templates/packages/shared/package.json +26 -0
- package/generators/micro-react/templates/packages/shared/services/common/index.ts +43 -0
- package/generators/micro-react/templates/packages/shared/services/index.ts +21 -0
- package/generators/micro-react/templates/packages/shared/services/request.ts +43 -0
- package/generators/micro-react/templates/packages/shared/timezone/index.ts +228 -0
- package/generators/micro-react/templates/packages/shared/tsconfig.json +20 -0
- package/generators/micro-react/templates/scripts/apply-sentry-plugin.ts +6 -1
- package/generators/micro-react/templates/turbo.json +9 -1
- package/generators/subapp-react/README.md +43 -0
- package/generators/subapp-react/index.js +2 -0
- package/generators/subapp-react/templates/homepage/README.md +5 -1
- package/generators/subapp-react/templates/homepage/config/config.dev.ts +20 -0
- package/generators/subapp-react/templates/homepage/config/config.ts +10 -15
- package/generators/subapp-react/templates/homepage/docs/feature-/345/233/275/351/231/205/345/214/226.md +124 -0
- package/generators/subapp-react/templates/homepage/package.json +2 -1
- package/generators/subapp-react/templates/homepage/src/app.tsx +100 -5
- package/generators/subapp-react/templates/homepage/src/common/intl/index.ts +15 -0
- package/generators/subapp-react/templates/homepage/src/common/intl/intlRuntime.ts +14 -0
- package/generators/subapp-react/templates/homepage/src/common/intl/localeMapping.ts +24 -0
- package/generators/subapp-react/templates/homepage/src/common/intl/subappIntlConfig.ts +28 -0
- package/generators/subapp-react/templates/homepage/src/common/intl/subappLocale.ts +18 -0
- package/generators/subapp-react/templates/homepage/src/common/intl/subappOwnIntl.ts +63 -0
- package/generators/subapp-react/templates/homepage/src/common/intl/types.ts +14 -0
- package/generators/subapp-react/templates/homepage/src/common/intl/useSubappIntl.ts +61 -0
- package/generators/subapp-react/templates/homepage/src/common/locale.ts +80 -0
- package/generators/subapp-react/templates/homepage/src/common/logger.ts +50 -18
- package/generators/subapp-react/templates/homepage/src/common/mainApp.ts +2 -0
- package/generators/subapp-react/templates/homepage/src/locales/en-US.ts +6 -0
- package/generators/subapp-react/templates/homepage/src/locales/zh-CN.ts +6 -0
- package/generators/subapp-react/templates/homepage/src/pages/index.less +10 -0
- package/generators/subapp-react/templates/homepage/src/pages/index.tsx +51 -0
- package/generators/subapp-react/templates/homepage/typings.d.ts +12 -0
- package/generators/subapp-umd/README.md +37 -0
- package/package.json +1 -1
|
@@ -168,6 +168,8 @@ module.exports = class extends Generator {
|
|
|
168
168
|
const templateData = {
|
|
169
169
|
appName: this.appName,
|
|
170
170
|
AppName: this.appNamePascal,
|
|
171
|
+
// 用于 MFSU mfName 等需要合法 JS 标识符的场景(不允许 `-`)
|
|
172
|
+
appNameSnake: this.appName.replace(/-/g, '_'),
|
|
171
173
|
packageScope: this.packageScope,
|
|
172
174
|
devPort: this.devPort,
|
|
173
175
|
micoUiVersion: `^${micoUiVer}`,
|
|
@@ -64,7 +64,7 @@ PORT=8001
|
|
|
64
64
|
│ ├── app.tsx # Umi 运行时配置
|
|
65
65
|
│ ├── assets/ # 静态资源
|
|
66
66
|
│ ├── common/ # 公共模块
|
|
67
|
-
│ │ ├── logger.ts #
|
|
67
|
+
│ │ ├── logger.ts # 日志工具(与 layout 一致:生产首屏 `?debug=1` 可开全量 log/info/warn)
|
|
68
68
|
│ │ ├── mainApp.ts # 主应用通信
|
|
69
69
|
│ │ └── request.ts # 请求封装
|
|
70
70
|
│ ├── pages/ # 页面组件
|
|
@@ -75,6 +75,10 @@ PORT=8001
|
|
|
75
75
|
└── tsconfig.json
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
+
## 日志(logger)
|
|
79
|
+
|
|
80
|
+
与 monorepo 内 **layout** 的 `src/common/logger.ts` 规则对齐:生产默认静默 `log`/`info`/`warn`,`error` 仍输出;首屏 URL 带 **`?debug=1`**(或 `debug=true` / `yes`)可在模块加载时打开全量日志。详见主应用文档 `apps/layout/docs/arch-日志与常量.md`(生成项目后路径以仓库为准)。
|
|
81
|
+
|
|
78
82
|
## 微前端配置
|
|
79
83
|
|
|
80
84
|
本应用作为 qiankun 子应用运行,关键配置:
|
|
@@ -61,6 +61,26 @@ const config: ReturnType<typeof defineConfig> = {
|
|
|
61
61
|
// @mico-platform/ui 基础样式(使用运行时解析的最新版本号,避免 latest 标签)
|
|
62
62
|
`https://cdn-portal.micoplatform.com/portal-center/mico-ui/${MICO_UI_VERSION}/ui/dist/css/mico-ui.min.css`,
|
|
63
63
|
],
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @name MFSU 配置
|
|
67
|
+
* @description
|
|
68
|
+
* - mfName: 唯一名隔离微前端 runtime,避免多应用共存时 MFSU 容器冲突
|
|
69
|
+
* - exclude:
|
|
70
|
+
* - `@mico-platform/theme`:theme 子路径解析
|
|
71
|
+
* - `@mico-platform/ui`:尽量与主应用一起编译
|
|
72
|
+
* - `<%= packageScope %>/*`:workspace 包走 webpack 编译,开发态可在 DevTools 直接定位到 packages/* 源码
|
|
73
|
+
* - shared: React 单例,确保 MFSU 预打包里的组件(如 UI 库)与应用共用同一份 React,否则 useContext 报 null
|
|
74
|
+
* @doc https://umijs.org/docs/api/config#mfsu
|
|
75
|
+
*/
|
|
76
|
+
mfsu: {
|
|
77
|
+
mfName: 'mf_<%= appNameSnake %>',
|
|
78
|
+
exclude: ['@mico-platform/theme', '@mico-platform/ui', /^<%= packageScope %>\//],
|
|
79
|
+
shared: {
|
|
80
|
+
react: { singleton: true },
|
|
81
|
+
'react-dom': { singleton: true },
|
|
82
|
+
},
|
|
83
|
+
},
|
|
64
84
|
};
|
|
65
85
|
|
|
66
86
|
export default defineConfig(config);
|
|
@@ -76,6 +76,16 @@ const config: ReturnType<typeof defineConfig> = {
|
|
|
76
76
|
*/
|
|
77
77
|
layout: false,
|
|
78
78
|
|
|
79
|
+
/**
|
|
80
|
+
* @name 国际化插件(与 layout 一致;intl 未命中 key 时读 src/locales)
|
|
81
|
+
* @doc https://umijs.org/docs/max/i18n
|
|
82
|
+
*/
|
|
83
|
+
locale: {
|
|
84
|
+
default: 'zh-CN',
|
|
85
|
+
antd: false,
|
|
86
|
+
baseNavigator: false,
|
|
87
|
+
},
|
|
88
|
+
|
|
79
89
|
/**
|
|
80
90
|
* @name 其他配置
|
|
81
91
|
*/
|
|
@@ -108,21 +118,6 @@ const config: ReturnType<typeof defineConfig> = {
|
|
|
108
118
|
* @description 使用 @mico-platform/ui 的 babel preset,实现组件与图标的按需加载
|
|
109
119
|
*/
|
|
110
120
|
extraBabelPresets: ['@mico-platform/ui/babel-preset'],
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* @name MFSU 配置
|
|
114
|
-
* @description
|
|
115
|
-
* - exclude: theme 子路径解析;ui 尽量与主应用一起编译
|
|
116
|
-
* - shared: React 单例,确保 MFSU 预打包里的组件(如 UI 库)与应用共用同一份 React,否则 useContext 报 null
|
|
117
|
-
* @doc https://umijs.org/docs/guides/mfsu
|
|
118
|
-
*/
|
|
119
|
-
mfsu: {
|
|
120
|
-
exclude: ['@mico-platform/theme', '@mico-platform/ui'],
|
|
121
|
-
shared: {
|
|
122
|
-
react: { singleton: true },
|
|
123
|
-
'react-dom': { singleton: true },
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
121
|
};
|
|
127
122
|
|
|
128
123
|
export default defineConfig(config);
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# 国际化(common-intl 与 Umi 兜底)
|
|
2
|
+
|
|
3
|
+
> 创建时间:2026-04-07
|
|
4
|
+
|
|
5
|
+
## 功能概述
|
|
6
|
+
|
|
7
|
+
子应用通过 **`<%= packageScope %>/common-intl`**(生产环境常与主应用 **externals 共享**)拉取中台文案;**未命中 key** 时回落到 **Umi `src/locales`**。可选在工程内配置 **独立 `initIntl`**(独立 tag / IndexedDB),与主应用默认实例隔离。语言与主应用对齐:qiankun 下优先主应用注入的 `locale`,否则与 layout 相同的 URL / `umi_locale` / 浏览器规则(见 `getSubappCurrentLocale`)。
|
|
8
|
+
|
|
9
|
+
## 技术方案
|
|
10
|
+
|
|
11
|
+
### 技术栈
|
|
12
|
+
|
|
13
|
+
- Umi Max `locale` 插件 + `src/locales/zh-CN.ts`、`en-US.ts`
|
|
14
|
+
- `<%= packageScope %>/common-intl`:`configureLocale`、`i18n`、`fetchMultilingualData`、`initIntl`(独立实例时)
|
|
15
|
+
- 统一入口:`useSubappIntl`(合并逻辑对齐主应用 `useLayoutIntl`)
|
|
16
|
+
|
|
17
|
+
### 核心实现
|
|
18
|
+
|
|
19
|
+
1. **`app.tsx`**:最早调用 `configureLocale`,使包内 `getLocale`/`setLocale` 与 `getSubappCurrentLocale` 一致;导出 Umi 运行时 `locale.getLocale`;在 `render` 中按条件调用中台 `fetchMultilingualData`(默认 tag 与可选的独立 intl 实例并行)。
|
|
20
|
+
2. **`useSubappIntl`**:若 `subappIntlConfig` 有效则优先 **独立实例** `i18n`;否则在未启用中台时仅用 Umi,启用时优先包内 **`i18n`**;与 `defaultMessage` 比较后决定是否采用 Umi 译文。
|
|
21
|
+
3. **`subappIntlConfig.ts`**:默认返回 `undefined`;返回含 **`tag`、`app_name`** 的对象即启用独立 intl(见 `subappOwnIntl.ts` 内 `initIntl`)。
|
|
22
|
+
|
|
23
|
+
## 文件清单
|
|
24
|
+
|
|
25
|
+
### 新增 / 模块目录
|
|
26
|
+
|
|
27
|
+
| 文件路径 | 说明 |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| `src/common/intl/subappIntlConfig.ts` | 独立 intl 配置入口 `getSubappIntlInitOptions()` |
|
|
30
|
+
| `src/common/intl/subappOwnIntl.ts` | 条件 `initIntl`、独立 `fetchMultilingualData` |
|
|
31
|
+
| `src/common/intl/useSubappIntl.ts` | 页面统一 Hook |
|
|
32
|
+
| `src/common/intl/intlRuntime.ts` | `isCommonIntlEnabled`(`window.__MICO_CONFIG__.intl` / `commonIntl`) |
|
|
33
|
+
| `src/common/intl/types.ts` | `IMicoConfigCommonIntl` |
|
|
34
|
+
| `src/common/intl/index.ts` | 对外导出 |
|
|
35
|
+
| `src/common/intl/localeMapping.ts` | Umi locale ↔ `ILang`(模板已存在) |
|
|
36
|
+
| `src/common/intl/subappLocale.ts` | 当前 Umi 风格 locale(模板已存在) |
|
|
37
|
+
| `src/locales/zh-CN.ts` | Umi 兜底文案 |
|
|
38
|
+
| `src/locales/en-US.ts` | Umi 兜底文案 |
|
|
39
|
+
|
|
40
|
+
### 修改
|
|
41
|
+
|
|
42
|
+
| 文件路径 | 说明 |
|
|
43
|
+
| --- | --- |
|
|
44
|
+
| `config/config.ts` | 开启 `locale` 插件 |
|
|
45
|
+
| `src/app.tsx` | `configureLocale`、`export const locale`、`render` 预拉取 |
|
|
46
|
+
| `src/pages/index.tsx` | 国际化示例区(可选参考) |
|
|
47
|
+
| `typings.d.ts` | `__MICO_CONFIG__.intl` / `commonIntl` 类型 |
|
|
48
|
+
|
|
49
|
+
## API / 组件接口
|
|
50
|
+
|
|
51
|
+
### `useSubappIntl`
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
const {
|
|
55
|
+
formatMessage, // 与 layout useLayoutIntl 相同签名
|
|
56
|
+
commonIntlEnabled, // 是否启用中台(有效 tag + app_name)
|
|
57
|
+
locale, // 当前 Umi 风格 locale 字符串
|
|
58
|
+
subappOwnIntl, // 是否启用子应用独立 initIntl
|
|
59
|
+
subappOwnIntlTag, // 独立 tag(未启用时为 undefined)
|
|
60
|
+
} = useSubappIntl();
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**参数说明**:无入参;`formatMessage` 第二参数为插值对象,与 `useIntl().formatMessage` 一致。
|
|
64
|
+
|
|
65
|
+
### `getSubappIntlInitOptions`
|
|
66
|
+
|
|
67
|
+
返回 `undefined` 表示使用包默认实例;返回 `ISubappIntlInitOptions` 时需至少包含 **`tag`**、**`app_name`**,可选 **`indexedDBParams`**(与 `packages/common-intl` README 一致)。
|
|
68
|
+
|
|
69
|
+
## 使用示例
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import { useSubappIntl } from '@/common/intl';
|
|
73
|
+
|
|
74
|
+
export default function Page() {
|
|
75
|
+
const { formatMessage, commonIntlEnabled, locale, subappOwnIntl, subappOwnIntlTag } =
|
|
76
|
+
useSubappIntl();
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<p>
|
|
80
|
+
{formatMessage(
|
|
81
|
+
{ id: 'page.subapp.home.title', defaultMessage: '标题' },
|
|
82
|
+
)}
|
|
83
|
+
</p>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
独立 intl(节选,`subappIntlConfig.ts`):
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
export function getSubappIntlInitOptions() {
|
|
92
|
+
return {
|
|
93
|
+
tag: 'my_subapp_tag',
|
|
94
|
+
app_name: 'middle',
|
|
95
|
+
indexedDBParams: { dbName: 'my_subapp_i18n_db' },
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
启用独立 tag 且生产仍使用 `externals` 指向主应用 `CommonIntl` 时,需评估与上游 **多实例 / 单例** 语义是否冲突,详见 **`generators/micro-react/templates/packages/common-intl/README.md`**「不同 tag」。
|
|
101
|
+
|
|
102
|
+
## 设计决策
|
|
103
|
+
|
|
104
|
+
| 决策点 | 选择 | 理由 |
|
|
105
|
+
| --- | --- | --- |
|
|
106
|
+
| 统一 Hook | `useSubappIntl` 对齐 `useLayoutIntl` | 与主应用行为一致,intl 与 Umi 兜底规则可维护 |
|
|
107
|
+
| 独立 intl 配置 | 单一入口 `getSubappIntlInitOptions` | 默认关闭,按需开启,避免误初始化 |
|
|
108
|
+
| 预拉取 | `render` 内并行 fetch 默认 tag + 独立实例 | 首屏前尽量拉齐中台数据,失败仍渲染 |
|
|
109
|
+
|
|
110
|
+
## 已知限制与待改进
|
|
111
|
+
|
|
112
|
+
- 独立 intl 与 **externals 共享同一 `common-intl` 运行时** 时的边界行为以 **上游包** 为准;若需完全隔离,可能需调整打包策略(见 common-intl README)。
|
|
113
|
+
- `LOCALE_REQUEST_URL` 未配置时,行为依赖上游 `fetchMultilingualData` 实现。
|
|
114
|
+
|
|
115
|
+
## 注意事项
|
|
116
|
+
|
|
117
|
+
- 主应用通过 qiankun 注入的 **`locale`** 会参与 `getSubappCurrentLocale`;独立运行依赖本地存储与 URL。
|
|
118
|
+
- 中台未配置时 **`commonIntlEnabled`** 为 `false`,页面仅走 Umi `locales`。
|
|
119
|
+
|
|
120
|
+
## 相关文档
|
|
121
|
+
|
|
122
|
+
- [packages/common-intl README](../../../../micro-react/templates/packages/common-intl/README.md)
|
|
123
|
+
- [子应用国际化(CLI 仓库总览)](../../../../../docs/feat-subapp-国际化翻译.md)
|
|
124
|
+
- [Layout 国际化](../../../../../docs/feat-layout-国际化翻译.md)
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"@umijs/max": "^4.4.8",
|
|
21
21
|
"react": "^18.2.0",
|
|
22
22
|
"react-dom": "^18.2.0",
|
|
23
|
-
"<%= packageScope %>/common-intl": "workspace:*"
|
|
23
|
+
"<%= packageScope %>/common-intl": "workspace:*",
|
|
24
|
+
"<%= packageScope %>/shared": "workspace:*"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
|
26
27
|
"@mico-platform/ui": "<%= micoUiVersion %>",
|
|
@@ -7,18 +7,113 @@
|
|
|
7
7
|
* 自定义函数请放在 @/common/mainApp.ts 中
|
|
8
8
|
*
|
|
9
9
|
* 国际化使用:
|
|
10
|
-
* 子应用默认共享主应用的 intl
|
|
10
|
+
* 子应用默认共享主应用的 intl(同 tag),直接导入即可:
|
|
11
11
|
* import { intl } from '<%= packageScope %>/common-intl';
|
|
12
12
|
* intl.common_hello();
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* 独立 intl:在 `src/common/intl/subappIntlConfig.ts` 填写 `getSubappIntlInitOptions()`;
|
|
14
|
+
* 页面统一用 `useSubappIntl`(intl 优先,未命中走子应用 Umi locales)。
|
|
15
|
+
*
|
|
16
|
+
* common-intl 的 getLocale/setLocale 与 Umi locale / 主应用 props.locale 对齐:入口调用 configureLocale(见下)。
|
|
15
17
|
*/
|
|
16
18
|
|
|
17
|
-
import
|
|
19
|
+
import {
|
|
20
|
+
configureLocale,
|
|
21
|
+
fetchMultilingualData,
|
|
22
|
+
type ILang,
|
|
23
|
+
} from '<%= packageScope %>/common-intl';
|
|
24
|
+
import { Message } from '@mico-platform/ui';
|
|
25
|
+
import type { ReactNode } from 'react';
|
|
18
26
|
import { history } from '@umijs/max';
|
|
19
27
|
import { SentryErrorBoundary } from '@common-web/sentry';
|
|
20
28
|
import { appLogger } from './common/logger';
|
|
29
|
+
import { configureRequest } from '<%= packageScope %>/shared/services';
|
|
21
30
|
import { type IMicroAppProps, setMainAppProps } from './common/mainApp';
|
|
31
|
+
import { request } from './common/request';
|
|
32
|
+
import { setLocaleToStorage } from './common/locale';
|
|
33
|
+
import {
|
|
34
|
+
getSubappOwnFetchMultilingualData,
|
|
35
|
+
ilangToUmiLocale,
|
|
36
|
+
isCommonIntlEnabled,
|
|
37
|
+
umiLocaleToILang,
|
|
38
|
+
} from './common/intl';
|
|
39
|
+
import { getSubappCurrentLocale } from './common/intl/subappLocale';
|
|
40
|
+
|
|
41
|
+
// 子应用:将本地 request(自动桥接主应用 / 独立 umi)注入 shared 包,供共享服务层(getRequest)使用
|
|
42
|
+
// 注意:模块顶层注入,request 函数引用稳定;运行期由 request 内部根据是否处于 qiankun 选用 main / umi
|
|
43
|
+
configureRequest(request as <T = unknown>(url: string, options?: Record<string, unknown>) => Promise<T>);
|
|
44
|
+
|
|
45
|
+
// 子应用:common-intl initIntl 与 Umi `umi_locale` / 主应用注入 locale 对齐(与 layout app.tsx 同理)
|
|
46
|
+
configureLocale({
|
|
47
|
+
getLocale: () => umiLocaleToILang(getSubappCurrentLocale()),
|
|
48
|
+
setLocale: (lang: ILang) => {
|
|
49
|
+
setLocaleToStorage(ilangToUmiLocale(lang));
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @name 运行时国际化(Umi locale 插件)
|
|
55
|
+
* @see https://umijs.org/docs/max/i18n#%E8%BF%90%E8%A1%8C%E6%97%B6%E9%85%8D%E7%BD%AE
|
|
56
|
+
*/
|
|
57
|
+
export const locale = {
|
|
58
|
+
getLocale() {
|
|
59
|
+
return getSubappCurrentLocale();
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 中台文案预加载:默认 tag 与(可选)子应用独立 intl tag 并行拉取,失败仍渲染。
|
|
65
|
+
* @see generators/micro-react/templates/apps/layout/src/app.tsx render
|
|
66
|
+
*/
|
|
67
|
+
export function render(oldRender: () => void): void {
|
|
68
|
+
const ownFetch = getSubappOwnFetchMultilingualData();
|
|
69
|
+
const tasks: Promise<unknown>[] = [];
|
|
70
|
+
|
|
71
|
+
if (isCommonIntlEnabled()) {
|
|
72
|
+
tasks.push(
|
|
73
|
+
fetchMultilingualData({
|
|
74
|
+
requestInstance: request as (
|
|
75
|
+
url: string,
|
|
76
|
+
options?: unknown,
|
|
77
|
+
) => Promise<unknown>,
|
|
78
|
+
messageInstance: {
|
|
79
|
+
error: Message.error,
|
|
80
|
+
warning: Message.warning,
|
|
81
|
+
},
|
|
82
|
+
lang: umiLocaleToILang(getSubappCurrentLocale()) as ILang,
|
|
83
|
+
localeRequestUrl: process.env.LOCALE_REQUEST_URL,
|
|
84
|
+
}),
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (ownFetch) {
|
|
89
|
+
tasks.push(
|
|
90
|
+
ownFetch({
|
|
91
|
+
requestInstance: request as (
|
|
92
|
+
url: string,
|
|
93
|
+
options?: unknown,
|
|
94
|
+
) => Promise<unknown>,
|
|
95
|
+
messageInstance: {
|
|
96
|
+
error: Message.error,
|
|
97
|
+
warning: Message.warning,
|
|
98
|
+
},
|
|
99
|
+
lang: umiLocaleToILang(getSubappCurrentLocale()) as ILang,
|
|
100
|
+
localeRequestUrl: process.env.LOCALE_REQUEST_URL,
|
|
101
|
+
}),
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (tasks.length === 0) {
|
|
106
|
+
oldRender();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
Promise.all(tasks)
|
|
111
|
+
.then(() => oldRender())
|
|
112
|
+
.catch((error: Error) => {
|
|
113
|
+
console.error('获取多语言文案失败', error);
|
|
114
|
+
oldRender();
|
|
115
|
+
});
|
|
116
|
+
}
|
|
22
117
|
|
|
23
118
|
/** 与 layout parser.findRouteByPath 一致:根路径 "/" 保持不变 */
|
|
24
119
|
function stripTrailingSlash(path: string): string {
|
|
@@ -110,6 +205,6 @@ export async function getInitialState() {
|
|
|
110
205
|
};
|
|
111
206
|
}
|
|
112
207
|
|
|
113
|
-
export function rootContainer(container:
|
|
208
|
+
export function rootContainer(container: ReactNode) {
|
|
114
209
|
return <SentryErrorBoundary>{container}</SentryErrorBoundary>;
|
|
115
210
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { isCommonIntlEnabled, getCommonIntlConfig } from './intlRuntime';
|
|
2
|
+
export type { IMicoConfigCommonIntl } from './types';
|
|
3
|
+
export {
|
|
4
|
+
getSubappIntlInitOptions,
|
|
5
|
+
type ISubappIntlInitOptions,
|
|
6
|
+
} from './subappIntlConfig';
|
|
7
|
+
export {
|
|
8
|
+
getSubappOwnFetchMultilingualData,
|
|
9
|
+
getSubappOwnI18n,
|
|
10
|
+
getSubappOwnIntlTag,
|
|
11
|
+
isSubappOwnIntlEnabled,
|
|
12
|
+
} from './subappOwnIntl';
|
|
13
|
+
export { useSubappIntl } from './useSubappIntl';
|
|
14
|
+
export { ilangToUmiLocale, umiLocaleToILang } from './localeMapping';
|
|
15
|
+
export { getSubappCurrentLocale } from './subappLocale';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IMicoConfigCommonIntl } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 是否启用多语言中台拉取:以 __MICO_CONFIG__.intl 或 commonIntl 含有效 tag、app_name 为准
|
|
5
|
+
*/
|
|
6
|
+
export function isCommonIntlEnabled(): boolean {
|
|
7
|
+
const c = getCommonIntlConfig();
|
|
8
|
+
return !!(c?.tag && c?.app_name);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function getCommonIntlConfig(): IMicoConfigCommonIntl | undefined {
|
|
12
|
+
const w = window.__MICO_CONFIG__;
|
|
13
|
+
return w?.intl ?? w?.commonIntl;
|
|
14
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { LANG, type ILang } from '<%= packageScope %>/common-intl';
|
|
2
|
+
import type { SupportedLocale } from '@/common/locale';
|
|
3
|
+
import { LOCALE } from '@/common/locale';
|
|
4
|
+
|
|
5
|
+
/** 与 packages/common-intl/src/umiLocaleBridge.ts、layout localeMapping 保持一致 */
|
|
6
|
+
const UMI_TO_ILANG: Record<SupportedLocale, ILang> = {
|
|
7
|
+
[LOCALE.ZH_CN]: LANG.ZH_CN,
|
|
8
|
+
[LOCALE.EN_US]: LANG.EN,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function umiLocaleToILang(locale: SupportedLocale): ILang {
|
|
12
|
+
return UMI_TO_ILANG[locale] ?? LANG.EN;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const ILANG_TO_UMI: Partial<Record<ILang, SupportedLocale>> = {
|
|
16
|
+
[LANG.ZH_CN]: LOCALE.ZH_CN,
|
|
17
|
+
[LANG.EN]: LOCALE.EN_US,
|
|
18
|
+
[LANG.AR]: LOCALE.EN_US,
|
|
19
|
+
[LANG.TR]: LOCALE.EN_US,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function ilangToUmiLocale(lang: ILang): SupportedLocale {
|
|
23
|
+
return ILANG_TO_UMI[lang] ?? LOCALE.EN_US;
|
|
24
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 子应用独立 intl(与主应用不同 tag / 独立 IndexedDB)时,在此返回 initIntl 参数。
|
|
3
|
+
* 默认 `undefined`:使用 <%= packageScope %>/common-intl 包内默认实例(与主应用 externals 共享)。
|
|
4
|
+
*
|
|
5
|
+
* 启用方式:返回含有效 `tag`、`app_name` 的对象(与 packages/common-intl README 一致)。
|
|
6
|
+
*/
|
|
7
|
+
export interface ISubappIntlInitOptions {
|
|
8
|
+
tag: string;
|
|
9
|
+
app_name: string;
|
|
10
|
+
indexedDBParams?: {
|
|
11
|
+
dbName?: string;
|
|
12
|
+
dbVersion?: number;
|
|
13
|
+
storeName?: string;
|
|
14
|
+
keyPathKey?: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getSubappIntlInitOptions():
|
|
19
|
+
| ISubappIntlInitOptions
|
|
20
|
+
| undefined {
|
|
21
|
+
return undefined;
|
|
22
|
+
// 如果需要启用独立 intl,请取消注释并修改 tag 和 app_name
|
|
23
|
+
// return {
|
|
24
|
+
// tag: 'cs_fe_mobile',
|
|
25
|
+
// app_name: 'middle',
|
|
26
|
+
// indexedDBParams: { dbName: 'mico_cs_mobile_i18n_db' },
|
|
27
|
+
// };
|
|
28
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { getCurrentLocale, type SupportedLocale, SUPPORTED_LOCALES } from '@/common/locale';
|
|
2
|
+
import { getMainAppProps } from '@/common/mainApp';
|
|
3
|
+
|
|
4
|
+
function isSupportedLocale(value: string | undefined): value is SupportedLocale {
|
|
5
|
+
return !!value && (SUPPORTED_LOCALES as readonly string[]).includes(value);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 子应用当前 Umi 风格 locale:qiankun 下优先主应用 MicroAppLoader 注入的 `locale`,
|
|
10
|
+
* 否则与主应用相同规则(URL / umi_locale / 浏览器)。
|
|
11
|
+
*/
|
|
12
|
+
export function getSubappCurrentLocale(): SupportedLocale {
|
|
13
|
+
const fromMain = getMainAppProps()?.locale;
|
|
14
|
+
if (isSupportedLocale(fromMain)) {
|
|
15
|
+
return fromMain;
|
|
16
|
+
}
|
|
17
|
+
return getCurrentLocale();
|
|
18
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { initIntl, type ILang } from '<%= packageScope %>/common-intl';
|
|
2
|
+
import { setLocaleToStorage } from '@/common/locale';
|
|
3
|
+
import { getSubappIntlInitOptions } from './subappIntlConfig';
|
|
4
|
+
import { ilangToUmiLocale, umiLocaleToILang } from './localeMapping';
|
|
5
|
+
import { getSubappCurrentLocale } from './subappLocale';
|
|
6
|
+
|
|
7
|
+
type TI18nFn = (opts: {
|
|
8
|
+
key: string;
|
|
9
|
+
defaultMessage: string;
|
|
10
|
+
interpolations?: (string | number | boolean)[];
|
|
11
|
+
}) => string;
|
|
12
|
+
|
|
13
|
+
type TFetchFn = (params: {
|
|
14
|
+
requestInstance: (url: string, options?: unknown) => Promise<unknown>;
|
|
15
|
+
messageInstance: { error: (msg: string) => void; warning: (msg: string) => void };
|
|
16
|
+
lang: ILang;
|
|
17
|
+
localeRequestUrl?: string;
|
|
18
|
+
}) => Promise<unknown>;
|
|
19
|
+
|
|
20
|
+
function createSubappOwnIntl(): {
|
|
21
|
+
i18nFn: TI18nFn | null;
|
|
22
|
+
fetchFn: TFetchFn | null;
|
|
23
|
+
tag: string | undefined;
|
|
24
|
+
} {
|
|
25
|
+
const opts = getSubappIntlInitOptions();
|
|
26
|
+
if (!opts?.tag || !opts.app_name) {
|
|
27
|
+
return { i18nFn: null, fetchFn: null, tag: undefined };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const { fetchMultilingualData, i18n } = initIntl({
|
|
31
|
+
...opts,
|
|
32
|
+
getLocale: () => umiLocaleToILang(getSubappCurrentLocale()),
|
|
33
|
+
setLocale: (lang: ILang) => {
|
|
34
|
+
setLocaleToStorage(ilangToUmiLocale(lang));
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
i18nFn: i18n as TI18nFn,
|
|
40
|
+
fetchFn: fetchMultilingualData as TFetchFn,
|
|
41
|
+
tag: opts.tag,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const subappOwnIntlRuntime = createSubappOwnIntl();
|
|
46
|
+
|
|
47
|
+
export function isSubappOwnIntlEnabled(): boolean {
|
|
48
|
+
return subappOwnIntlRuntime.i18nFn != null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getSubappOwnIntlTag(): string | undefined {
|
|
52
|
+
return subappOwnIntlRuntime.tag;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** 独立 intl 实例的 i18n;未配置时为 `null` */
|
|
56
|
+
export function getSubappOwnI18n(): TI18nFn | null {
|
|
57
|
+
return subappOwnIntlRuntime.i18nFn;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** 与默认 tag 的 fetch 相同入参;未配置独立 intl 时为 `null` */
|
|
61
|
+
export function getSubappOwnFetchMultilingualData(): TFetchFn | null {
|
|
62
|
+
return subappOwnIntlRuntime.fetchFn;
|
|
63
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 运行时 common-intl 配置(见 window.__MICO_CONFIG__.intl,兼容 commonIntl)
|
|
3
|
+
*/
|
|
4
|
+
export interface IMicoConfigCommonIntl {
|
|
5
|
+
/** 多语言中台 tag */
|
|
6
|
+
tag: string;
|
|
7
|
+
app_name: string;
|
|
8
|
+
indexedDBParams?: {
|
|
9
|
+
dbName?: string;
|
|
10
|
+
dbVersion?: number;
|
|
11
|
+
storeName?: string;
|
|
12
|
+
keyPathKey?: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { i18n } from '<%= packageScope %>/common-intl';
|
|
2
|
+
import { useIntl } from '@umijs/max';
|
|
3
|
+
import { getSubappCurrentLocale } from './subappLocale';
|
|
4
|
+
import { isCommonIntlEnabled } from './intlRuntime';
|
|
5
|
+
import { getSubappOwnI18n, isSubappOwnIntlEnabled, getSubappOwnIntlTag } from './subappOwnIntl';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 子应用统一国际化 Hook:
|
|
9
|
+
* - 配置了 {@link getSubappIntlInitOptions} 时:优先独立 intl 实例的 `i18n`,无命中再 Umi
|
|
10
|
+
* - 否则与 layout `useLayoutIntl` 一致:未启用 commonIntl 时仅 Umi;启用后包内 `i18n` 优先,无命中再 Umi
|
|
11
|
+
*/
|
|
12
|
+
export function useSubappIntl() {
|
|
13
|
+
const umiIntl = useIntl();
|
|
14
|
+
const commonIntlEnabled = isCommonIntlEnabled();
|
|
15
|
+
const locale = getSubappCurrentLocale();
|
|
16
|
+
const subappOwnIntl = isSubappOwnIntlEnabled();
|
|
17
|
+
const ownI18n = getSubappOwnI18n();
|
|
18
|
+
const subappOwnIntlTag = getSubappOwnIntlTag();
|
|
19
|
+
|
|
20
|
+
const formatMessage = (
|
|
21
|
+
descriptor: { id: string; defaultMessage?: string },
|
|
22
|
+
values?: Record<string, string | number | boolean | Date | null | undefined>,
|
|
23
|
+
): string => {
|
|
24
|
+
const dm = descriptor.defaultMessage ?? descriptor.id;
|
|
25
|
+
const fromUmi = umiIntl.formatMessage(descriptor, values);
|
|
26
|
+
|
|
27
|
+
if (subappOwnIntl && ownI18n) {
|
|
28
|
+
const fromOwn = ownI18n({
|
|
29
|
+
key: descriptor.id,
|
|
30
|
+
defaultMessage: dm,
|
|
31
|
+
});
|
|
32
|
+
if (fromOwn === dm && fromUmi !== fromOwn) {
|
|
33
|
+
return fromUmi;
|
|
34
|
+
}
|
|
35
|
+
return fromOwn;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!commonIntlEnabled) {
|
|
39
|
+
return fromUmi;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const fromIntl = i18n({
|
|
43
|
+
key: descriptor.id,
|
|
44
|
+
defaultMessage: dm,
|
|
45
|
+
});
|
|
46
|
+
if (fromIntl === dm && fromUmi !== fromIntl) {
|
|
47
|
+
return fromUmi;
|
|
48
|
+
}
|
|
49
|
+
return fromIntl;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
commonIntlEnabled,
|
|
54
|
+
formatMessage,
|
|
55
|
+
locale,
|
|
56
|
+
/** 是否启用子应用内独立 initIntl 配置 */
|
|
57
|
+
subappOwnIntl,
|
|
58
|
+
/** 独立 intl 的 tag(仅 subappOwnIntl 为 true 时有值) */
|
|
59
|
+
subappOwnIntlTag,
|
|
60
|
+
};
|
|
61
|
+
}
|