@qlover/create-app 0.10.1 → 0.10.3
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/CHANGELOG.md +178 -0
- package/dist/configs/_common/.github/workflows/general-check.yml +1 -1
- package/dist/configs/_common/.github/workflows/release.yml +2 -2
- package/dist/index.cjs +4 -4
- package/dist/index.js +4 -4
- package/dist/templates/next-app/config/IOCIdentifier.ts +2 -2
- package/dist/templates/next-app/config/Identifier/common/common.ts +14 -0
- package/dist/templates/next-app/config/Identifier/pages/index.ts +1 -0
- package/dist/templates/next-app/config/Identifier/pages/page.about.ts +20 -0
- package/dist/templates/next-app/config/common.ts +1 -1
- package/dist/templates/next-app/config/cookies.ts +23 -0
- package/dist/templates/next-app/config/i18n/AboutI18n.ts +14 -0
- package/dist/templates/next-app/config/i18n/i18nConfig.ts +3 -1
- package/dist/templates/next-app/config/i18n/index.ts +1 -0
- package/dist/templates/next-app/config/i18n/loginI18n.ts +8 -0
- package/dist/templates/next-app/config/theme.ts +4 -0
- package/dist/templates/next-app/eslint.config.mjs +9 -2
- package/dist/templates/next-app/next.config.ts +1 -0
- package/dist/templates/next-app/package.json +17 -6
- package/dist/templates/next-app/public/locales/en.json +5 -0
- package/dist/templates/next-app/public/locales/zh.json +5 -0
- package/dist/templates/next-app/src/app/[locale]/admin/AdminI18nProvider.tsx +37 -0
- package/dist/templates/next-app/src/app/[locale]/admin/layout.tsx +30 -6
- package/dist/templates/next-app/src/app/[locale]/admin/locales/page.tsx +1 -1
- package/dist/templates/next-app/src/app/[locale]/layout.tsx +47 -10
- package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +1 -1
- package/dist/templates/next-app/src/app/[locale]/login/page.tsx +22 -10
- package/dist/templates/next-app/src/app/[locale]/page.tsx +23 -8
- package/dist/templates/next-app/src/app/[locale]/register/page.tsx +21 -9
- package/dist/templates/next-app/src/app/api/admin/locales/create/route.ts +7 -28
- package/dist/templates/next-app/src/app/api/admin/locales/import/route.ts +7 -34
- package/dist/templates/next-app/src/app/api/admin/locales/route.ts +12 -34
- package/dist/templates/next-app/src/app/api/admin/locales/update/route.ts +7 -26
- package/dist/templates/next-app/src/app/api/admin/users/route.ts +14 -33
- package/dist/templates/next-app/src/app/api/locales/json/route.ts +13 -25
- package/dist/templates/next-app/src/app/api/user/login/route.ts +6 -46
- package/dist/templates/next-app/src/app/api/user/logout/route.ts +5 -24
- package/dist/templates/next-app/src/app/api/user/register/route.ts +6 -45
- package/dist/templates/next-app/src/app/manifest.ts +16 -0
- package/dist/templates/next-app/src/app/robots.txt +2 -0
- package/dist/templates/next-app/src/base/cases/AdminPageManager.ts +3 -3
- package/dist/templates/next-app/src/base/cases/AppConfig.ts +14 -13
- package/dist/templates/next-app/src/base/cases/Datetime.ts +3 -3
- package/dist/templates/next-app/src/base/cases/DialogErrorPlugin.ts +8 -2
- package/dist/templates/next-app/src/base/cases/DialogHandler.ts +30 -4
- package/dist/templates/next-app/src/base/cases/InversifyContainer.ts +16 -4
- package/dist/templates/next-app/src/base/cases/NavigateBridge.ts +20 -4
- package/dist/templates/next-app/src/base/cases/RequestEncryptPlugin.ts +8 -2
- package/dist/templates/next-app/src/base/cases/ResourceState.ts +3 -3
- package/dist/templates/next-app/src/base/cases/RouterService.ts +28 -10
- package/dist/templates/next-app/src/base/cases/StringEncryptor.ts +14 -2
- package/dist/templates/next-app/src/base/cases/TranslateI18nInterface.ts +1 -1
- package/dist/templates/next-app/src/base/cases/UserServiceApi.ts +20 -5
- package/dist/templates/next-app/src/base/cases/ZodColumnBuilder.ts +31 -8
- package/dist/templates/next-app/src/base/port/AdminLayoutInterface.ts +4 -1
- package/dist/templates/next-app/src/base/port/AppApiInterface.ts +22 -0
- package/dist/templates/next-app/src/base/port/I18nServiceInterface.ts +27 -7
- package/dist/templates/next-app/src/base/port/IOCInterface.ts +9 -0
- package/dist/templates/next-app/src/base/services/AdminPageEvent.ts +1 -1
- package/dist/templates/next-app/src/base/services/AdminPageScheduler.ts +3 -3
- package/dist/templates/next-app/src/base/services/I18nService.ts +20 -10
- package/dist/templates/next-app/src/base/services/ResourceService.ts +32 -11
- package/dist/templates/next-app/src/base/services/UserService.ts +12 -3
- package/dist/templates/next-app/src/base/services/adminApi/AdminLocalesApi.ts +9 -6
- package/dist/templates/next-app/src/base/services/adminApi/AdminUserApi.ts +20 -5
- package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +21 -4
- package/dist/templates/next-app/src/base/services/appApi/AppUserApi.ts +12 -3
- package/dist/templates/next-app/src/base/services/appApi/AppUserApiBootstrap.ts +10 -2
- package/dist/templates/next-app/src/base/types/{PageProps.ts → AppPageRouter.ts} +4 -1
- package/dist/templates/next-app/src/base/types/PagesRouter.ts +9 -0
- package/dist/templates/next-app/src/core/bootstraps/BootstrapClient.ts +20 -6
- package/dist/templates/next-app/src/core/bootstraps/BootstrapServer.ts +27 -9
- package/dist/templates/next-app/src/core/bootstraps/BootstrapsRegistry.ts +6 -4
- package/dist/templates/next-app/src/core/clientIoc/ClientIOC.ts +39 -9
- package/dist/templates/next-app/src/core/clientIoc/ClientIOCRegister.ts +9 -2
- package/dist/templates/next-app/src/core/serverIoc/ServerIOC.ts +37 -10
- package/dist/templates/next-app/src/core/serverIoc/ServerIOCRegister.ts +9 -2
- package/dist/templates/next-app/src/i18n/loadMessages.ts +103 -0
- package/dist/templates/next-app/src/i18n/request.ts +3 -22
- package/dist/templates/next-app/src/pages/[locale]/about.tsx +61 -0
- package/dist/templates/next-app/src/pages/_app.tsx +50 -0
- package/dist/templates/next-app/src/pages/_document.tsx +13 -0
- package/dist/templates/next-app/src/{middleware.ts → proxy.ts} +2 -1
- package/dist/templates/next-app/src/server/AppErrorApi.ts +1 -1
- package/dist/templates/next-app/src/server/AppPageRouteParams.ts +107 -0
- package/dist/templates/next-app/src/server/AppSuccessApi.ts +1 -1
- package/dist/templates/next-app/src/server/NextApiServer.ts +62 -0
- package/dist/templates/next-app/src/server/PagesRouteParams.ts +146 -0
- package/dist/templates/next-app/src/server/PasswordEncrypt.ts +8 -2
- package/dist/templates/next-app/src/server/ServerAuth.ts +20 -5
- package/dist/templates/next-app/src/server/{sqlBridges/SupabaseBridge.ts → SupabaseBridge.ts} +50 -8
- package/dist/templates/next-app/src/server/UserCredentialToken.ts +8 -2
- package/dist/templates/next-app/src/server/controllers/AdminLocalesController.ts +86 -0
- package/dist/templates/next-app/src/server/controllers/AdminUserController.ts +42 -0
- package/dist/templates/next-app/src/server/controllers/LocalesController.ts +36 -0
- package/dist/templates/next-app/src/server/controllers/UserController.ts +86 -0
- package/dist/templates/next-app/src/server/port/AIControllerInterface.ts +8 -0
- package/dist/templates/next-app/src/server/port/AdminLocalesControllerInterface.ts +21 -0
- package/dist/templates/next-app/src/server/port/AdminUserControllerInterface.ts +11 -0
- package/dist/templates/next-app/src/server/port/LocalesControllerInterface.ts +10 -0
- package/dist/templates/next-app/src/server/port/{ParamsHandlerInterface.ts → RouteParamsnHandlerInterface.ts} +9 -2
- package/dist/templates/next-app/src/server/port/ServerInterface.ts +2 -2
- package/dist/templates/next-app/src/server/port/UserControllerInerface.ts +8 -0
- package/dist/templates/next-app/src/server/port/UserServiceInterface.ts +1 -1
- package/dist/templates/next-app/src/server/port/ValidatorInterface.ts +2 -2
- package/dist/templates/next-app/src/server/repositorys/LocalesRepository.ts +31 -9
- package/dist/templates/next-app/src/server/repositorys/UserRepository.ts +15 -6
- package/dist/templates/next-app/src/server/services/AIService.ts +3 -1
- package/dist/templates/next-app/src/server/services/AdminAuthPlugin.ts +5 -2
- package/dist/templates/next-app/src/{base → server}/services/AdminLocalesService.ts +2 -2
- package/dist/templates/next-app/src/server/services/ApiLocaleService.ts +29 -14
- package/dist/templates/next-app/src/server/services/ApiUserService.ts +6 -3
- package/dist/templates/next-app/src/server/services/UserService.ts +12 -3
- package/dist/templates/next-app/src/server/validators/LocalesValidator.ts +24 -7
- package/dist/templates/next-app/src/server/validators/LoginValidator.ts +17 -5
- package/dist/templates/next-app/src/server/validators/PaginationValidator.ts +17 -11
- package/dist/templates/next-app/src/styles/css/antd-themes/_common/_default.css +0 -44
- package/dist/templates/next-app/src/styles/css/antd-themes/_common/dark.css +0 -44
- package/dist/templates/next-app/src/styles/css/antd-themes/_common/pink.css +0 -44
- package/dist/templates/next-app/src/styles/css/index.css +1 -1
- package/dist/templates/next-app/src/styles/css/scrollbar.css +34 -0
- package/dist/templates/next-app/src/uikit/components/AdminLayout.tsx +34 -11
- package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +69 -39
- package/dist/templates/next-app/src/uikit/components/ClientRootProvider.tsx +64 -0
- package/dist/templates/next-app/src/uikit/components/ClinetRenderProvider.tsx +42 -0
- package/dist/templates/next-app/src/uikit/components/IOCProvider.tsx +34 -0
- package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportEvent.ts +7 -1
- package/dist/templates/next-app/src/uikit/components-app/AppBridge.tsx +17 -0
- package/dist/templates/next-app/src/uikit/components-app/AppRoutePage.tsx +112 -0
- package/dist/templates/next-app/src/uikit/{components → components-app}/LanguageSwitcher.tsx +15 -19
- package/dist/templates/next-app/src/uikit/{components → components-app}/ThemeSwitcher.tsx +53 -52
- package/dist/templates/next-app/src/uikit/components-pages/LanguageSwitcher.tsx +98 -0
- package/dist/templates/next-app/src/uikit/components-pages/PagesRoutePage.tsx +93 -0
- package/dist/templates/next-app/src/uikit/context/IOCContext.ts +16 -4
- package/dist/templates/next-app/src/uikit/hook/useStrictEffect.ts +32 -0
- package/dist/templates/next-app/tsconfig.json +3 -2
- package/dist/templates/react-app/__tests__/__mocks__/BootstrapTest.ts +3 -1
- package/dist/templates/react-app/__tests__/__mocks__/MockAppConfig.ts +19 -19
- package/dist/templates/react-app/__tests__/__mocks__/MockDialogHandler.ts +8 -8
- package/dist/templates/react-app/__tests__/__mocks__/MockLogger.ts +9 -9
- package/dist/templates/react-app/__tests__/__mocks__/components/TestBootstrapsProvider.tsx +1 -1
- package/dist/templates/react-app/__tests__/__mocks__/i18nextHttpBackend.ts +5 -5
- package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOC.ts +9 -5
- package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOCRegister.ts +8 -4
- package/dist/templates/react-app/__tests__/src/base/cases/I18nKeyErrorPlugin.test.ts +4 -4
- package/dist/templates/react-app/__tests__/src/base/cases/InversifyContainer.test.ts +5 -5
- package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapClient.test.ts +3 -3
- package/dist/templates/react-app/__tests__/src/uikit/components/chatMessage/ChatRoot.test.tsx +1 -1
- package/dist/templates/react-app/docs/en/components/chat-message-component.md +35 -29
- package/dist/templates/react-app/docs/en/components/chat-message-refactor.md +18 -5
- package/dist/templates/react-app/docs/en/components/message-base-list-component.md +11 -12
- package/dist/templates/react-app/docs/en/request.md +1 -3
- package/dist/templates/react-app/docs/zh/components/chat-message-component.md +35 -29
- package/dist/templates/react-app/docs/zh/components/chat-message-refactor.md +18 -5
- package/dist/templates/react-app/docs/zh/components/message-base-list-component.md +11 -12
- package/dist/templates/react-app/docs/zh/request.md +1 -3
- package/dist/templates/react-app/eslint.config.mjs +10 -5
- package/dist/templates/react-app/src/App.tsx +1 -1
- package/dist/templates/react-app/src/base/apis/feApi/FeApi.ts +2 -2
- package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +14 -11
- package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +10 -16
- package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +12 -10
- package/dist/templates/react-app/src/base/cases/AppConfig.ts +19 -19
- package/dist/templates/react-app/src/base/cases/DialogHandler.ts +28 -5
- package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +5 -2
- package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +16 -4
- package/dist/templates/react-app/src/base/cases/PublicAssetsPath.ts +1 -1
- package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +6 -3
- package/dist/templates/react-app/src/base/cases/RequestLogger.ts +17 -8
- package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +4 -6
- package/dist/templates/react-app/src/base/cases/ResourceState.ts +3 -3
- package/dist/templates/react-app/src/base/cases/RouterLoader.ts +3 -3
- package/dist/templates/react-app/src/base/cases/TranslateI18nInterface.ts +1 -1
- package/dist/templates/react-app/src/base/port/ExecutorPageBridgeInterface.ts +2 -2
- package/dist/templates/react-app/src/base/port/IOCInterface.ts +4 -2
- package/dist/templates/react-app/src/base/port/JSONStoragePageBridgeInterface.ts +5 -5
- package/dist/templates/react-app/src/base/port/RequestPageBridgeInterface.ts +7 -7
- package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +8 -8
- package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +4 -2
- package/dist/templates/react-app/src/base/services/BaseLayoutService.ts +3 -3
- package/dist/templates/react-app/src/base/services/I18nService.ts +24 -13
- package/dist/templates/react-app/src/base/services/IdentifierService.ts +21 -26
- package/dist/templates/react-app/src/base/services/RouteService.ts +8 -8
- package/dist/templates/react-app/src/base/services/UserBootstrap.ts +2 -2
- package/dist/templates/react-app/src/base/services/UserGatewayPlugin.ts +9 -5
- package/dist/templates/react-app/src/base/services/UserService.ts +10 -4
- package/dist/templates/react-app/src/core/bootstraps/BootstrapClient.ts +3 -1
- package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +5 -2
- package/dist/templates/react-app/src/core/clientIoc/ClientIOC.ts +11 -4
- package/dist/templates/react-app/src/core/clientIoc/ClientIOCRegister.ts +5 -4
- package/dist/templates/react-app/src/pages/base/Layout.tsx +1 -1
- package/dist/templates/react-app/src/styles/css/antd-themes/_common/_default.css +0 -44
- package/dist/templates/react-app/src/styles/css/antd-themes/_common/dark.css +0 -44
- package/dist/templates/react-app/src/styles/css/antd-themes/_common/pink.css +0 -44
- package/dist/templates/react-app/src/styles/css/index.css +1 -1
- package/dist/templates/react-app/src/styles/css/scrollbar.css +34 -0
- package/dist/templates/react-app/src/uikit/bridges/ExecutorPageBridge.ts +2 -2
- package/dist/templates/react-app/src/uikit/bridges/JSONStoragePageBridge.ts +4 -4
- package/dist/templates/react-app/src/uikit/bridges/NavigateBridge.ts +8 -2
- package/dist/templates/react-app/src/uikit/bridges/RequestPageBridge.ts +6 -6
- package/dist/templates/react-app/src/uikit/components/AppRouterProvider.tsx +1 -1
- package/dist/templates/react-app/src/uikit/components/BootstrapsProvider.tsx +1 -3
- package/dist/templates/react-app/src/uikit/components/MessageBaseList.tsx +4 -1
- package/dist/templates/react-app/src/uikit/components/chatMessage/ChatMessageBridge.ts +39 -16
- package/dist/templates/react-app/src/uikit/components/chatMessage/MessageApi.ts +4 -2
- package/package.json +3 -3
- package/dist/templates/next-app/src/server/PageParams.ts +0 -66
- package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +0 -80
- package/dist/templates/next-app/src/uikit/components/BaseLayout.tsx +0 -65
- package/dist/templates/next-app/src/uikit/components/ComboProvider.tsx +0 -58
- package/dist/templates/next-app/src/uikit/components/NextIntlProvider.tsx +0 -21
- package/dist/templates/react-app/makes/eslint-utils.mjs +0 -195
- /package/dist/templates/next-app/{src/app/[locale] → public}/favicon.ico +0 -0
- /package/dist/templates/next-app/src/uikit/{components → components-app}/LogoutButton.tsx +0 -0
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from '@qlover/corekit-bridge';
|
|
6
6
|
import { Logger, ConsoleHandler, TimestampFormatter } from '@qlover/logger';
|
|
7
7
|
import type { IocRegisterOptions } from '@/base/port/IOCInterface';
|
|
8
|
-
import { SupabaseBridge } from '@/server/
|
|
8
|
+
import { SupabaseBridge } from '@/server/SupabaseBridge';
|
|
9
9
|
import { IOCIdentifier as I } from '@config/IOCIdentifier';
|
|
10
10
|
|
|
11
11
|
export class ServerIOCRegister implements IOCRegisterInterface<
|
|
@@ -19,6 +19,7 @@ export class ServerIOCRegister implements IOCRegisterInterface<
|
|
|
19
19
|
*
|
|
20
20
|
* 一般用于注册全局
|
|
21
21
|
*
|
|
22
|
+
* @override
|
|
22
23
|
* @param ioc - IOC container
|
|
23
24
|
*/
|
|
24
25
|
protected registerGlobals(ioc: IOCContainerInterface): void {
|
|
@@ -45,16 +46,22 @@ export class ServerIOCRegister implements IOCRegisterInterface<
|
|
|
45
46
|
);
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
/**
|
|
50
|
+
* @override
|
|
51
|
+
*/
|
|
48
52
|
protected registerImplement(ioc: IOCContainerInterface): void {
|
|
49
53
|
ioc.bind(I.DBBridgeInterface, ioc.get(SupabaseBridge));
|
|
50
54
|
}
|
|
51
55
|
|
|
56
|
+
/**
|
|
57
|
+
* @override
|
|
58
|
+
*/
|
|
52
59
|
protected registerCommon(_ioc: IOCContainerInterface): void {}
|
|
53
60
|
|
|
54
61
|
/**
|
|
55
62
|
* @override
|
|
56
63
|
*/
|
|
57
|
-
register(
|
|
64
|
+
public register(
|
|
58
65
|
ioc: IOCContainerInterface,
|
|
59
66
|
_manager: IOCManagerInterface<IOCContainerInterface>
|
|
60
67
|
): void {
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { useApiLocales } from '@config/common';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 加载 i18n 消息的公共方法
|
|
5
|
+
* 支持从 API 加载或从 JSON 文件加载
|
|
6
|
+
*
|
|
7
|
+
* @param locale - 要加载的语言代码
|
|
8
|
+
* @param namespace - 可选的命名空间(单个字符串或字符串数组),如果提供则只返回该命名空间下的消息,保留命名空间前缀
|
|
9
|
+
* @returns Promise<Record<string, string>> 返回翻译消息对象
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* // 加载所有消息
|
|
14
|
+
* const allMessages = await loadMessages('en');
|
|
15
|
+
*
|
|
16
|
+
* // 加载单个命名空间
|
|
17
|
+
* const commonMessages = await loadMessages('en', 'common');
|
|
18
|
+
*
|
|
19
|
+
* // 加载多个命名空间
|
|
20
|
+
* const messages = await loadMessages('en', ['common', 'page_home']);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export async function loadMessages(
|
|
24
|
+
locale: string,
|
|
25
|
+
namespace?: string | string[]
|
|
26
|
+
): Promise<Record<string, string>> {
|
|
27
|
+
let allMessages: Record<string, string>;
|
|
28
|
+
|
|
29
|
+
// 如果配置了使用 API 加载本地化数据
|
|
30
|
+
if (useApiLocales) {
|
|
31
|
+
try {
|
|
32
|
+
const app_host = process.env.APP_HOST;
|
|
33
|
+
const localeUrl = `${app_host}/api/locales/json?locale=${locale}`;
|
|
34
|
+
const response = await fetch(localeUrl);
|
|
35
|
+
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Failed to fetch locale from API: ${response.statusText}`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
allMessages = await response.json();
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.warn(`Failed to load locale from API for ${locale}`, error);
|
|
45
|
+
// 如果 API 加载失败,继续尝试从文件加载
|
|
46
|
+
allMessages = (await import(`../../public/locales/${locale}.json`))
|
|
47
|
+
.default;
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
allMessages = (await import(`../../public/locales/${locale}.json`)).default;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 如果指定了命名空间,进行过滤
|
|
54
|
+
return filterMessagesByNamespace(allMessages, namespace);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 根据命名空间过滤消息,保留命名空间前缀
|
|
59
|
+
*
|
|
60
|
+
* @param messages - 所有消息对象
|
|
61
|
+
* @param namespace - 可选的命名空间(单个字符串或字符串数组),如果提供则只返回该命名空间下的消息,保留命名空间前缀
|
|
62
|
+
* @returns 过滤后的消息对象
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* const allMessages = { "common:save": "Save", "common:cancel": "Cancel", "page_home:title": "Home" };
|
|
67
|
+
*
|
|
68
|
+
* // 单个命名空间
|
|
69
|
+
* const commonMessages = filterMessagesByNamespace(allMessages, "common");
|
|
70
|
+
* // 返回: { "common:save": "Save", "common:cancel": "Cancel" }
|
|
71
|
+
*
|
|
72
|
+
* // 多个命名空间
|
|
73
|
+
* const messages = filterMessagesByNamespace(allMessages, ["common", "page_home"]);
|
|
74
|
+
* // 返回: { "common:save": "Save", "common:cancel": "Cancel", "page_home:title": "Home" }
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export function filterMessagesByNamespace(
|
|
78
|
+
messages: Record<string, string>,
|
|
79
|
+
namespace?: string | string[]
|
|
80
|
+
): Record<string, string> {
|
|
81
|
+
// 如果没有指定命名空间,返回所有消息
|
|
82
|
+
if (!namespace) {
|
|
83
|
+
return messages;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 将单个字符串转换为数组,统一处理
|
|
87
|
+
const namespaces = Array.isArray(namespace) ? namespace : [namespace];
|
|
88
|
+
const filteredMessages: Record<string, string> = {};
|
|
89
|
+
|
|
90
|
+
// 遍历所有命名空间
|
|
91
|
+
for (const ns of namespaces) {
|
|
92
|
+
const namespacePrefix = `${ns}:`;
|
|
93
|
+
|
|
94
|
+
for (const [key, value] of Object.entries(messages)) {
|
|
95
|
+
if (key.startsWith(namespacePrefix)) {
|
|
96
|
+
// 保留完整的键名(包括命名空间前缀)
|
|
97
|
+
filteredMessages[key] = value;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return filteredMessages;
|
|
103
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/i18n/request.ts
|
|
2
2
|
|
|
3
3
|
import { getRequestConfig } from 'next-intl/server';
|
|
4
|
-
import {
|
|
4
|
+
import { loadMessages } from './loadMessages';
|
|
5
5
|
import { routing, type Locale } from './routing';
|
|
6
6
|
|
|
7
7
|
// Export a function to configure next-intl on each request (server-side)
|
|
@@ -14,30 +14,11 @@ export default getRequestConfig(async ({ requestLocale }) => {
|
|
|
14
14
|
locale = routing.defaultLocale;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
if (useApiLocales) {
|
|
19
|
-
const app_host = process.env.APP_HOST;
|
|
20
|
-
const localeUrl = `${app_host}/api/locales/json?locale=${locale}`;
|
|
21
|
-
const response = await fetch(localeUrl);
|
|
22
|
-
const data = await response.json();
|
|
23
|
-
return {
|
|
24
|
-
locale,
|
|
25
|
-
messages: data,
|
|
26
|
-
// 将 MISSING_MESSAGE 错误转换为警告
|
|
27
|
-
onError: (error) => {
|
|
28
|
-
if (error.message.includes('MISSING_MESSAGE')) {
|
|
29
|
-
console.warn(`[i18n] Missing translation: ${error.message}`);
|
|
30
|
-
return error.message; // 返回 key 作为 fallback 文本
|
|
31
|
-
}
|
|
32
|
-
throw error; // 其他错误仍然抛出
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
}
|
|
17
|
+
const messages = await loadMessages(locale);
|
|
36
18
|
|
|
37
|
-
// Dynamically import the translation messages for the selected locale
|
|
38
19
|
return {
|
|
39
20
|
locale,
|
|
40
|
-
messages
|
|
21
|
+
messages,
|
|
41
22
|
// 将 MISSING_MESSAGE 错误转换为警告
|
|
42
23
|
onError: (error) => {
|
|
43
24
|
if (error.message.includes('MISSING_MESSAGE')) {
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { PagesRouteParams } from '@/server/PagesRouteParams';
|
|
3
|
+
import type { PagesRouteParamsType } from '@/server/PagesRouteParams';
|
|
4
|
+
import { ClientSeo } from '@/uikit/components/ClientSeo';
|
|
5
|
+
import { PagesRoutePage } from '@/uikit/components-pages/PagesRoutePage';
|
|
6
|
+
import { useI18nInterface } from '@/uikit/hook/useI18nInterface';
|
|
7
|
+
import { aboutI18n, i18nConfig } from '@config/i18n';
|
|
8
|
+
import { COMMON_ADMIN_TITLE } from '@config/Identifier';
|
|
9
|
+
import type { GetStaticPropsContext } from 'next';
|
|
10
|
+
|
|
11
|
+
interface AboutProps {
|
|
12
|
+
messages: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const namespace = 'page_about';
|
|
16
|
+
|
|
17
|
+
export default function About({}: AboutProps) {
|
|
18
|
+
const i18nInterface = useMemo(() => {
|
|
19
|
+
return {
|
|
20
|
+
...aboutI18n,
|
|
21
|
+
adminTitle: COMMON_ADMIN_TITLE
|
|
22
|
+
};
|
|
23
|
+
}, []);
|
|
24
|
+
const seoMetadata = useI18nInterface(i18nInterface);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<PagesRoutePage
|
|
28
|
+
data-testid="AboutPage"
|
|
29
|
+
tt={{ title: seoMetadata.title, adminTitle: seoMetadata.adminTitle }}
|
|
30
|
+
showAdminButton={false}
|
|
31
|
+
>
|
|
32
|
+
<ClientSeo i18nInterface={seoMetadata} />
|
|
33
|
+
<div data-testid="About" className="bg-primary h-screen">
|
|
34
|
+
{seoMetadata.title}
|
|
35
|
+
</div>
|
|
36
|
+
</PagesRoutePage>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function getStaticProps({
|
|
41
|
+
params
|
|
42
|
+
}: GetStaticPropsContext<PagesRouteParamsType>) {
|
|
43
|
+
const pageParams = new PagesRouteParams(params);
|
|
44
|
+
|
|
45
|
+
const messages = await pageParams.getI18nMessages(namespace);
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
props: {
|
|
49
|
+
messages
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function getStaticPaths() {
|
|
55
|
+
return {
|
|
56
|
+
paths: i18nConfig.supportedLngs.map((locale) => ({
|
|
57
|
+
params: { locale }
|
|
58
|
+
})),
|
|
59
|
+
fallback: false
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import dynamic from 'next/dynamic';
|
|
2
|
+
import { withRouter } from 'next/router';
|
|
3
|
+
import { NextIntlClientProvider } from 'next-intl';
|
|
4
|
+
import '@/styles/css/index.css';
|
|
5
|
+
import type { PagesRouterProps } from '@/base/types/PagesRouter';
|
|
6
|
+
import { BootstrapsProvider } from '@/uikit/components/BootstrapsProvider';
|
|
7
|
+
import { IOCProvider } from '@/uikit/components/IOCProvider';
|
|
8
|
+
import { i18nConfig } from '@config/i18n';
|
|
9
|
+
import { themeConfig } from '@config/theme';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 动态导入 ClientRootProvider,禁用 SSR,确保只在客户端渲染
|
|
13
|
+
*
|
|
14
|
+
* 为什么需要禁用 SSR?
|
|
15
|
+
* 1. ClientRootProvider 内部使用了 AntdRegistry(来自 @ant-design/nextjs-registry),
|
|
16
|
+
* 该组件主要针对 App Router 设计,在 Pages Router 的 SSR 环境中可能存在兼容性问题
|
|
17
|
+
* 2. ClientRootProvider 使用了 useIOC() hook,该 hook 在服务端渲染时可能无法正常工作
|
|
18
|
+
* 3. ThemeProvider 和 AntdThemeProvider 可能依赖浏览器 API(如 localStorage、window 等),
|
|
19
|
+
* 在服务端渲染时会导致错误或页面一直处于加载状态
|
|
20
|
+
*
|
|
21
|
+
* 通过在 Pages Router 中使用 dynamic import 并设置 ssr: false,
|
|
22
|
+
* 可以确保 ClientRootProvider 只在客户端渲染,避免 SSR 相关的问题
|
|
23
|
+
*/
|
|
24
|
+
const ClientRootProvider = dynamic(
|
|
25
|
+
() =>
|
|
26
|
+
import('@/uikit/components/ClientRootProvider').then(
|
|
27
|
+
(mod) => mod.ClientRootProvider
|
|
28
|
+
),
|
|
29
|
+
{
|
|
30
|
+
ssr: false
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
function App({ Component, pageProps, router }: PagesRouterProps) {
|
|
35
|
+
const locale = (router.query.locale as string) || i18nConfig.fallbackLng;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<IOCProvider>
|
|
39
|
+
<NextIntlClientProvider locale={locale} messages={pageProps.messages}>
|
|
40
|
+
<BootstrapsProvider>
|
|
41
|
+
<ClientRootProvider themeConfig={themeConfig}>
|
|
42
|
+
<Component {...pageProps} />
|
|
43
|
+
</ClientRootProvider>
|
|
44
|
+
</BootstrapsProvider>
|
|
45
|
+
</NextIntlClientProvider>
|
|
46
|
+
</IOCProvider>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default withRouter(App);
|
|
@@ -20,6 +20,7 @@ export const config = {
|
|
|
20
20
|
// - Next.js internals (_next/*)
|
|
21
21
|
// - Static files (*.svg, *.png, *.jpg, *.jpeg, *.gif, *.ico)
|
|
22
22
|
// - Other static assets and special files
|
|
23
|
-
|
|
23
|
+
// - Manifest file (manifest.webmanifest)
|
|
24
|
+
'/((?!api|_next|.*\\.(?:svg|png|jpg|jpeg|gif|ico)|favicon.ico|sitemap.xml|sitemap-0.xml|manifest.webmanifest).*)'
|
|
24
25
|
]
|
|
25
26
|
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { cookies } from 'next/headers';
|
|
2
|
+
import { notFound } from 'next/navigation';
|
|
3
|
+
import { getMessages, getTranslations } from 'next-intl/server';
|
|
4
|
+
import { TranslateI18nInterface } from '@/base/cases/TranslateI18nInterface';
|
|
5
|
+
import { filterMessagesByNamespace } from '@/i18n/loadMessages';
|
|
6
|
+
import { i18nConfig } from '@config/i18n';
|
|
7
|
+
import type { LocaleType, PageI18nInterface } from '@config/i18n';
|
|
8
|
+
import { themeConfig } from '@config/theme';
|
|
9
|
+
import type { RouteParamsnHandlerInterface } from './port/RouteParamsnHandlerInterface';
|
|
10
|
+
|
|
11
|
+
export interface PageWithParams {
|
|
12
|
+
params?: Promise<PageParamsType>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface PageParamsType {
|
|
16
|
+
locale?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 用于 src/app/page 路由的参数管理工具
|
|
21
|
+
*/
|
|
22
|
+
export class AppPageRouteParams<
|
|
23
|
+
T extends PageParamsType
|
|
24
|
+
> implements RouteParamsnHandlerInterface {
|
|
25
|
+
private locale: string | null;
|
|
26
|
+
|
|
27
|
+
constructor(protected readonly params: T) {
|
|
28
|
+
this.locale = this.params.locale || i18nConfig.fallbackLng;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @override
|
|
33
|
+
*/
|
|
34
|
+
public getLocale(defaultLocale?: string): string {
|
|
35
|
+
if (this.locale) {
|
|
36
|
+
return this.locale;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
this.locale = this.params.locale || defaultLocale || i18nConfig.fallbackLng;
|
|
40
|
+
|
|
41
|
+
return this.locale;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @override
|
|
46
|
+
*/
|
|
47
|
+
public getI18nWithNotFound(): string {
|
|
48
|
+
const locale = this.getLocale();
|
|
49
|
+
|
|
50
|
+
if (!i18nConfig.supportedLngs.includes(locale as LocaleType)) {
|
|
51
|
+
notFound();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return locale;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 获取 i18n 消息
|
|
59
|
+
* 使用 next-intl 的 getMessages 加载消息
|
|
60
|
+
*
|
|
61
|
+
* @override
|
|
62
|
+
* @param namespace - 可选的命名空间(单个字符串或字符串数组),会与默认命名空间 ['common', 'api'] 合并
|
|
63
|
+
* @returns Promise<Record<string, string>> 返回翻译消息对象
|
|
64
|
+
*/
|
|
65
|
+
public async getI18nMessages(
|
|
66
|
+
namespace?: string | string[]
|
|
67
|
+
): Promise<Record<string, string>> {
|
|
68
|
+
const locale = this.getLocale();
|
|
69
|
+
const messages = await getMessages({ locale });
|
|
70
|
+
// 将默认命名空间和用户提供的命名空间合并
|
|
71
|
+
const defaultNamespaces = [...i18nConfig.defaultNamespaces];
|
|
72
|
+
const userNamespaces = namespace
|
|
73
|
+
? Array.isArray(namespace)
|
|
74
|
+
? namespace
|
|
75
|
+
: [namespace]
|
|
76
|
+
: [];
|
|
77
|
+
// 合并并去重
|
|
78
|
+
const namespaces = [...new Set([...defaultNamespaces, ...userNamespaces])];
|
|
79
|
+
return filterMessagesByNamespace(messages, namespaces);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @override
|
|
84
|
+
*/
|
|
85
|
+
public async getI18nInterface<T extends PageI18nInterface>(
|
|
86
|
+
i18nInterface: T,
|
|
87
|
+
_namespace?: string
|
|
88
|
+
): Promise<T> {
|
|
89
|
+
const t = await getTranslations({
|
|
90
|
+
locale: this.getLocale()
|
|
91
|
+
// namespace: namespace
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return TranslateI18nInterface.translate<T>(i18nInterface, t);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @override
|
|
99
|
+
*/
|
|
100
|
+
public async getTheme(): Promise<string> {
|
|
101
|
+
const cookieStore = await cookies();
|
|
102
|
+
return (
|
|
103
|
+
cookieStore.get(themeConfig.storageKey)?.value ||
|
|
104
|
+
themeConfig.supportedThemes[0]
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AppApiSuccessInterface } from '@/base/port/AppApiInterface';
|
|
2
2
|
|
|
3
3
|
export class AppSuccessApi<T = unknown> implements AppApiSuccessInterface<T> {
|
|
4
|
-
readonly success = true;
|
|
4
|
+
public readonly success = true;
|
|
5
5
|
|
|
6
6
|
constructor(public readonly data?: T) {}
|
|
7
7
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ExecutorError } from '@qlover/fe-corekit';
|
|
2
|
+
import { NextResponse } from 'next/server';
|
|
3
|
+
import {
|
|
4
|
+
isAppApiErrorInterface,
|
|
5
|
+
isAppApiSuccessInterface,
|
|
6
|
+
type AppApiResult
|
|
7
|
+
} from '@/base/port/AppApiInterface';
|
|
8
|
+
import type { BootstrapServerContextValue } from '@/core/bootstraps/BootstrapServer';
|
|
9
|
+
import { BootstrapServer } from '@/core/bootstraps/BootstrapServer';
|
|
10
|
+
import { AppErrorApi } from './AppErrorApi';
|
|
11
|
+
import { AppSuccessApi } from './AppSuccessApi';
|
|
12
|
+
import type { PromiseTask } from '@qlover/fe-corekit';
|
|
13
|
+
|
|
14
|
+
export class NextApiServer extends BootstrapServer {
|
|
15
|
+
/**
|
|
16
|
+
* @override
|
|
17
|
+
*/
|
|
18
|
+
protected isAppApiResult(result: unknown): result is AppApiResult {
|
|
19
|
+
return isAppApiSuccessInterface(result) || isAppApiErrorInterface(result);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @override
|
|
24
|
+
*/
|
|
25
|
+
public async run<Result>(
|
|
26
|
+
task?: PromiseTask<Result | AppApiResult, BootstrapServerContextValue>
|
|
27
|
+
): Promise<AppApiResult> {
|
|
28
|
+
const result = await this.execNoError(task);
|
|
29
|
+
|
|
30
|
+
// Is result is AppApiResult, return it directly
|
|
31
|
+
if (this.isAppApiResult(result)) {
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// If result is ExecutorError, return AppErrorApi
|
|
36
|
+
if (result instanceof ExecutorError) {
|
|
37
|
+
return new AppErrorApi(result.id, result.message);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// If result is Error, return AppErrorApi
|
|
41
|
+
if (result instanceof Error) {
|
|
42
|
+
return new AppErrorApi('SERVER_ERROR', result.message);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return new AppSuccessApi(result);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @override
|
|
50
|
+
*/
|
|
51
|
+
public async runWithJson<Result>(
|
|
52
|
+
task?: PromiseTask<Result | AppApiResult, BootstrapServerContextValue>
|
|
53
|
+
): Promise<NextResponse> {
|
|
54
|
+
const result = await this.run(task);
|
|
55
|
+
|
|
56
|
+
if (!result.success) {
|
|
57
|
+
return NextResponse.json(result, { status: 400 });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return NextResponse.json(result);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { TranslateI18nInterface } from '@/base/cases/TranslateI18nInterface';
|
|
2
|
+
import { loadMessages } from '@/i18n/loadMessages';
|
|
3
|
+
import { i18nConfig } from '@config/i18n';
|
|
4
|
+
import type { LocaleType, PageI18nInterface } from '@config/i18n';
|
|
5
|
+
import { themeConfig } from '@config/theme';
|
|
6
|
+
import type { RouteParamsnHandlerInterface } from './port/RouteParamsnHandlerInterface';
|
|
7
|
+
import type { useTranslations } from 'next-intl';
|
|
8
|
+
import type { ParsedUrlQuery } from 'querystring';
|
|
9
|
+
|
|
10
|
+
export interface PagesRouteParamsType extends ParsedUrlQuery {
|
|
11
|
+
locale?: string | string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 用于 src/pages/** 路由的参数管理工具
|
|
16
|
+
*
|
|
17
|
+
* ⚠️ 注意:此类仅在服务器端使用(getStaticProps、getServerSideProps 中)
|
|
18
|
+
* 此类直接从 JSON 文件加载翻译消息,不依赖 next-intl/server,因此可以在 pages 目录中安全使用
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* export async function getStaticProps({ params }: GetStaticPropsContext<PagesRouteParamsType>) {
|
|
23
|
+
* const pageParams = new PagesRouteParams(params);
|
|
24
|
+
* const messages = await pageParams.getI18nMessages();
|
|
25
|
+
* return { props: { messages } };
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export class PagesRouteParams implements RouteParamsnHandlerInterface {
|
|
30
|
+
private locale: string | null;
|
|
31
|
+
|
|
32
|
+
constructor(protected readonly params: PagesRouteParamsType = {}) {
|
|
33
|
+
const localeParam = Array.isArray(this.params.locale)
|
|
34
|
+
? this.params.locale[0]
|
|
35
|
+
: this.params.locale;
|
|
36
|
+
this.locale = localeParam || i18nConfig.fallbackLng;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @override
|
|
41
|
+
*/
|
|
42
|
+
public getLocale(defaultLocale?: string): string {
|
|
43
|
+
if (this.locale) {
|
|
44
|
+
return this.locale;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const localeParam = Array.isArray(this.params.locale)
|
|
48
|
+
? this.params.locale[0]
|
|
49
|
+
: this.params.locale;
|
|
50
|
+
this.locale = localeParam || defaultLocale || i18nConfig.fallbackLng;
|
|
51
|
+
|
|
52
|
+
return this.locale;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 获取 locale,如果 locale 不支持则抛出错误
|
|
57
|
+
* 注意:在 pages 目录中,应该在 getStaticProps/getServerSideProps 中返回 { notFound: true } 来处理不支持的 locale
|
|
58
|
+
*
|
|
59
|
+
* @override
|
|
60
|
+
* @returns 支持的 locale 字符串
|
|
61
|
+
* @throws 如果 locale 不支持
|
|
62
|
+
*/
|
|
63
|
+
public getI18nWithNotFound(): string {
|
|
64
|
+
const locale = this.getLocale();
|
|
65
|
+
|
|
66
|
+
if (!i18nConfig.supportedLngs.includes(locale as LocaleType)) {
|
|
67
|
+
// 在 pages 目录中,应该返回 { notFound: true } 而不是调用 notFound()
|
|
68
|
+
// 这里抛出错误,由调用方在 getStaticProps/getServerSideProps 中处理
|
|
69
|
+
throw new Error(`Unsupported locale: ${locale}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return locale;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 获取 i18n 消息
|
|
77
|
+
* 使用公共方法加载消息,支持从 API 加载或动态导入 JSON 文件
|
|
78
|
+
* 不依赖 next-intl/server,适用于 getStaticProps/getServerSideProps
|
|
79
|
+
*
|
|
80
|
+
* @override
|
|
81
|
+
* @param namespace - 可选的命名空间(单个字符串或字符串数组),会与默认命名空间 ['common', 'api'] 合并
|
|
82
|
+
* @returns Promise<Record<string, string>> 返回翻译消息对象
|
|
83
|
+
*/
|
|
84
|
+
public async getI18nMessages(
|
|
85
|
+
namespace?: string | string[]
|
|
86
|
+
): Promise<Record<string, string>> {
|
|
87
|
+
const locale = this.getLocale();
|
|
88
|
+
// 将默认命名空间和用户提供的命名空间合并
|
|
89
|
+
const defaultNamespaces = [...i18nConfig.defaultNamespaces];
|
|
90
|
+
const userNamespaces = namespace
|
|
91
|
+
? Array.isArray(namespace)
|
|
92
|
+
? namespace
|
|
93
|
+
: [namespace]
|
|
94
|
+
: [];
|
|
95
|
+
// 合并并去重
|
|
96
|
+
const namespaces = [...new Set([...defaultNamespaces, ...userNamespaces])];
|
|
97
|
+
return loadMessages(locale, namespaces);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 获取翻译后的 i18n 接口
|
|
102
|
+
* 创建一个简单的翻译函数,基于加载的 messages
|
|
103
|
+
|
|
104
|
+
* @override
|
|
105
|
+
*/
|
|
106
|
+
public async getI18nInterface<T extends PageI18nInterface>(
|
|
107
|
+
i18nInterface: T,
|
|
108
|
+
namespace?: string
|
|
109
|
+
): Promise<T> {
|
|
110
|
+
const messages = await this.getI18nMessages(namespace);
|
|
111
|
+
|
|
112
|
+
// 创建一个简单的翻译函数
|
|
113
|
+
const t = (
|
|
114
|
+
key: string,
|
|
115
|
+
params?: Record<string, string | number | Date>
|
|
116
|
+
) => {
|
|
117
|
+
const fullKey = namespace ? `${namespace}:${key}` : key;
|
|
118
|
+
|
|
119
|
+
let message = messages[fullKey] || messages[key] || key;
|
|
120
|
+
|
|
121
|
+
// 简单的参数替换
|
|
122
|
+
if (params) {
|
|
123
|
+
Object.entries(params).forEach(([paramKey, paramValue]) => {
|
|
124
|
+
message = message.replace(
|
|
125
|
+
new RegExp(`\\{${paramKey}\\}`, 'g'),
|
|
126
|
+
String(paramValue)
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return message;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
return TranslateI18nInterface.translate<T>(
|
|
135
|
+
i18nInterface,
|
|
136
|
+
t as ReturnType<typeof useTranslations>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @override
|
|
142
|
+
*/
|
|
143
|
+
public getTheme(): string {
|
|
144
|
+
return themeConfig.defaultTheme;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -2,11 +2,17 @@ import crypto from 'crypto';
|
|
|
2
2
|
import type { Encryptor } from '@qlover/fe-corekit';
|
|
3
3
|
|
|
4
4
|
export class PasswordEncrypt implements Encryptor<string, string> {
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* @override
|
|
7
|
+
*/
|
|
8
|
+
public encrypt(password: string): string {
|
|
6
9
|
return crypto.createHash('md5').update(password).digest('hex');
|
|
7
10
|
}
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
/**
|
|
13
|
+
* @override
|
|
14
|
+
*/
|
|
15
|
+
public decrypt(): string {
|
|
10
16
|
throw new Error('Md5Encrypt is not decryptable');
|
|
11
17
|
}
|
|
12
18
|
}
|