From 209c7ff7d2a0a65ea58d1c7d270692c99fb7958f Mon Sep 17 00:00:00 2001 From: Baobhan Sith <80159437+Heavrnl@users.noreply.github.com> Date: Sat, 26 Apr 2025 10:02:34 +0800 Subject: [PATCH] update --- packages/backend/src/i18n.ts | 35 +++++++++-- .../backend/src/locales/jp/notifications.json | 62 +++++++++++++++++++ 2 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 packages/backend/src/locales/jp/notifications.json diff --git a/packages/backend/src/i18n.ts b/packages/backend/src/i18n.ts index 4e5d3a0..cbf30ea 100644 --- a/packages/backend/src/i18n.ts +++ b/packages/backend/src/i18n.ts @@ -1,24 +1,48 @@ import i18next from 'i18next'; import Backend from 'i18next-fs-backend'; import path from 'path'; +import fs from 'fs'; // 导入 fs 模块 -// 定义支持的语言 -export const supportedLngs = ['en', 'zh']; +// --- 动态确定支持的语言 --- +const localesDir = path.join(__dirname, 'locales'); +let dynamicSupportedLngs: string[] = []; +try { + // 同步读取 locales 目录下的所有条目 + const entries = fs.readdirSync(localesDir, { withFileTypes: true }); + // 过滤出目录,并将目录名作为支持的语言代码 + dynamicSupportedLngs = entries + .filter(dirent => dirent.isDirectory()) + .map(dirent => dirent.name); + console.log('[i18next] Dynamically detected languages:', dynamicSupportedLngs); +} catch (err) { + console.error('[i18next] Error reading locales directory:', err); + // 如果读取目录失败,可以回退到默认值或抛出错误 + dynamicSupportedLngs = ['en']; // 至少包含默认语言作为回退 +} + +// 确保默认语言在支持列表中,如果目录扫描失败则添加 export const defaultLng = 'en'; +if (!dynamicSupportedLngs.includes(defaultLng)) { + dynamicSupportedLngs.push(defaultLng); + console.warn(`[i18next] Default language '${defaultLng}' not found in detected directories, adding it to supported list.`); +} +export const supportedLngs = dynamicSupportedLngs; // 导出动态获取的列表 +// --- 结束动态确定 --- + i18next .use(Backend) .init({ debug: process.env.NODE_ENV === 'development', // Enable debug logging in dev - supportedLngs, + supportedLngs: supportedLngs, // 使用动态获取的列表 fallbackLng: defaultLng, // lng: defaultLng, // Remove explicit lng setting here, let it be determined later or by detector - preload: supportedLngs, // Preload all supported languages + preload: supportedLngs, // 使用动态获取的列表进行预加载 ns: ['notifications'], // 命名空间,用于组织翻译 defaultNS: 'notifications', backend: { // path where resources get loaded from - loadPath: path.join(__dirname, 'locales/{{lng}}/{{ns}}.json'), + loadPath: path.join(localesDir, '{{lng}}/{{ns}}.json'), // 直接使用 localesDir }, interpolation: { escapeValue: false, // Not needed for react apps @@ -30,6 +54,7 @@ i18next console.log('[i18next] Initialization complete. Loaded languages:', Object.keys(i18next.store.data)); // console.log('[i18next] Example translation (en):', t('testNotification.subject', { lng: 'en' })); // Optional test // console.log('[i18next] Example translation (zh):', t('testNotification.subject', { lng: 'zh' })); // Optional test + // console.log('[i18next] Example translation (jp):', t('testNotification.subject', { lng: 'jp' })); // Optional test for newly added lang }); export default i18next; diff --git a/packages/backend/src/locales/jp/notifications.json b/packages/backend/src/locales/jp/notifications.json new file mode 100644 index 0000000..7c5e4f4 --- /dev/null +++ b/packages/backend/src/locales/jp/notifications.json @@ -0,0 +1,62 @@ +{ + "testNotification": { + "subject": "星枢ターミナル テスト通知 ({eventDisplay})", + "email": { + "body": "これは、星枢ターミナルからのイベント'{{eventDisplay}}'に関するテストメールです。\n\nこのメールを受信した場合、SMTP 設定は正常に機能しています。\n\nタイムスタンプ: {{timestamp}}", + "bodyHtml": "

これは、星枢ターミナルからのイベント'{{eventDisplay}}'に関するテストメールです。

このメールを受信した場合、SMTP 設定は正常に機能しています。

タイムスタンプ: {{timestamp}}

" + }, + "webhook": { + "detailsMessage": "これは星枢ターミナルからのテスト通知 (Webhook - i18n) です。 イベント:'{{eventDisplay}}'。" + }, + "telegram": { + "detailsMessage": "これは星枢ターミナルからのテスト通知 (Telegram - i18n) です。 イベント:'{{eventDisplay}}'。", + "bodyTemplate": "*星枢ターミナル テスト通知*\nイベント: `{eventDisplay}`\nタイムスタンプ: {timestamp}\n詳細:\n```\n{details}\n```" + } + }, + "eventDisplay": { + "LOGIN_SUCCESS": "ログイン成功", + "LOGIN_FAILURE": "ログイン失敗", + "LOGOUT": "ログアウト", + "PASSWORD_CHANGED": "パスワード変更", + "2FA_ENABLED": "2段階認証有効", + "2FA_DISABLED": "2段階認証無効", + "PASSKEY_REGISTERED": "パスキー登録", + "PASSKEY_DELETED": "パスキー削除", + "CONNECTION_CREATED": "接続を作成しました", + "CONNECTION_UPDATED": "接続を更新しました", + "CONNECTION_DELETED": "接続を削除しました", + "CONNECTION_TESTED": "接続をテストしました", + "CONNECTIONS_IMPORTED": "接続をインポートしました", + "CONNECTIONS_EXPORTED": "接続をエクスポートしました", + "PROXY_CREATED": "プロキシを作成しました", + "PROXY_UPDATED": "プロキシを更新しました", + "PROXY_DELETED": "プロキシを削除しました", + "TAG_CREATED": "タグを作成しました", + "TAG_UPDATED": "タグを更新しました", + "TAG_DELETED": "タグを削除しました", + "SETTINGS_UPDATED": "設定を更新しました", + "IP_WHITELIST_UPDATED": "IP ホワイトリストを更新しました", + "NOTIFICATION_SETTING_CREATED": "通知設定を作成しました", + "NOTIFICATION_SETTING_UPDATED": "通知設定を更新しました", + "NOTIFICATION_SETTING_DELETED": "通知設定を削除しました", + "SFTP_ACTION": "SFTP 操作", + "SSH_CONNECT_SUCCESS": "SSH 接続成功", + "SSH_CONNECT_FAILURE": "SSH 接続失敗", + "SSH_SHELL_FAILURE": "SSH Shell オープン失敗", + "SERVER_STARTED": "サーバー起動", + "SERVER_ERROR": "サーバーエラー", + "DATABASE_MIGRATION": "データベース移行", + "ADMIN_SETUP_COMPLETE": "初期管理者設定完了" + }, + "eventBody": { + "SETTINGS_UPDATED": "イベント: {{eventDisplay}}\nタイムスタンプ: {{timestamp}}\n詳細:\n{{details}}" + }, + "connection": { + "testSuccess": "接続 '{{name}}' のテストに成功しました!", + "testFailed": "接続 '{{name}}' のテストに失敗しました: {{error}}" + }, + "settings": { + "ipWhitelistUpdated": "IP ホワイトリストを更新しました。", + "updated": "設定を更新しました。" + } + } \ No newline at end of file