mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-22 23:16:46 +00:00
c9627af239
TREK's four channels (in-app, email, webhook, ntfy) were a closed set: notificationService.send() dispatched with four copy-pasted `if` blocks and no provider abstraction, so a fifth channel meant editing eight files by hand. A plugin could produce a notification via ctx.notify.send(), but never deliver one. A plugin now registers a channel with `hooks.notificationChannel` + `hook:notification-channel` on a plain `type: 'integration'` — not a new manifest type, so the TREK-Plugins registry schema and both its CI gates are untouched. Core refactor - New channel registry (services/notifications/): email/webhook/ntfy become ExternalChannel providers wrapping the EXISTING send functions — no delivery logic is rewritten, only relocated. In-app deliberately stays out: it writes typed rows with scope/target/callbacks, not a rendered title+body, the same line shared/ already draws with i18n/externalNotifications. - The event text is now rendered once per recipient instead of once per channel. - The channel set is open: NotifChannel becomes a string, the matrix is registry-derived, and the UI columns are server-driven. The DB column was already bare TEXT and the Zod contract already a string record — only the TypeScript and the two UIs were ever closed. The hook runs USERLESS. Every other hook is user-initiated, so actingUserId falls out of the request; a notification is host-initiated for an ARBITRARY recipient, so ctx.settings.get() would return undefined. The host resolves the recipient's decrypted scope:'user' settings itself and passes them as an argument. That is what lets a channel plugin be handed someone's push token WITHOUT being handed the right to read their trips as them. Enabling the plugin is the opt-in: a plugin channel is not gated on the admin's `notification_channels` list. A built-in always exists in code and needs an explicit switch; a plugin channel only exists because an admin enabled that plugin. (Nothing could write a `plugin:` id into that CSV anyway, and the admin toggle rebuilt it from three booleans, silently dropping anything else — so requiring a second opt-in meant the channel could never be turned on at all.) Also fixed, found while building this: - Plugin settings keys were unvalidated, so a field named `__proto__` or `constructor` resolved off Object.prototype: a REQUIRED field with such a name reported as configured for every user who had configured nothing — enough, for a channel, to be dispatched to everyone with no credentials. Keys are now constrained at install and the config blob is parsed null-prototype, so it is impossible even for an already-installed plugin. - A `select` field's options were cast straight through, so the obvious `["1","5"]` form rendered every dropdown entry BLANK (the client reads value/label). Now coerced, and malformed options are rejected. Also adds: operator-supplied egress hosts (a plugin talking to a self-hosted service can't name the operator's host at publish time, so an admin adds it post-install and the runtime re-spawns the child with the widened allow-list — only for a plugin that DECLARED operatorEgress, and only an admin, never a user); settings-page actions (a "Test connection" button, user-initiated so ctx.settings.get() returns the clicking user's own value); and a Gotify-shaped notification-channel template in the SDK. Verified end to end against a real Gotify container, not just in tests.
472 lines
31 KiB
TypeScript
472 lines
31 KiB
TypeScript
import type { TranslationStrings } from '../types';
|
||
|
||
const settings: TranslationStrings = {
|
||
'settings.title': '設定',
|
||
'settings.subtitle': '個人設定を管理',
|
||
'settings.tabs.display': '表示',
|
||
'settings.tabs.map': '地図',
|
||
'settings.tabs.notifications': '通知',
|
||
'settings.tabs.integrations': '連携',
|
||
'settings.plugins.oauth.connected': '接続済み',
|
||
'settings.plugins.oauth.notConnected': '未接続',
|
||
'settings.plugins.oauth.connect': '接続',
|
||
'settings.plugins.oauth.disconnect': '接続解除',
|
||
'settings.tabs.plugins': 'プラグイン',
|
||
'settings.plugins.title': 'プラグイン設定',
|
||
'settings.plugins.subtitle': '使用しているプラグインの個人設定(API キー、環境設定)。',
|
||
'settings.plugins.empty': '有効なプラグインはありません。',
|
||
'settings.plugins.saved': '設定を保存しました',
|
||
'settings.tabs.account': 'アカウント',
|
||
'settings.tabs.offline': 'オフライン',
|
||
'settings.tabs.about': '情報',
|
||
'settings.map': '地図',
|
||
'settings.mapTemplate': '地図テンプレート',
|
||
'settings.mapTemplatePlaceholder.select': 'テンプレートを選択…',
|
||
'settings.mapDefaultHint': '空欄の場合は OpenStreetMap(既定)を使用',
|
||
'settings.mapTemplatePlaceholder': 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||
'settings.mapHint': '地図タイルのURLテンプレート',
|
||
'settings.mapProvider': '地図プロバイダー',
|
||
'settings.mapProviderHint': '旅程プランナーと日記地図に影響します。Atlas は常に Leaflet を使用します。',
|
||
'settings.mapLeafletSubtitle': 'クラシックな2D、任意のラスタータイル',
|
||
'settings.mapMapboxSubtitle': 'ベクタータイル、3D建物・地形',
|
||
'settings.mapMapLibreSubtitle': 'OpenFreeMap ベクタータイル、トークン不要',
|
||
'settings.mapExperimental': '実験的',
|
||
'settings.mapMapboxToken': 'Mapbox アクセストークン',
|
||
'settings.mapMapboxTokenHint': 'mapbox.com の公開トークン(pk.*)',
|
||
'settings.mapMapboxTokenLink': 'mapbox.com → Access tokens',
|
||
'settings.mapStyle': '地図スタイル',
|
||
'settings.mapStylePlaceholder': 'Mapboxスタイルを選択',
|
||
'settings.mapStyleHint': 'プリセットまたは mapbox://styles/USER/ID のURL',
|
||
'settings.mapOpenFreeMapStylePlaceholder': 'OpenFreeMapスタイルを選択',
|
||
'settings.mapOpenFreeMapStyleHint':
|
||
'プリセットまたは OpenFreeMap スタイルのURL。OpenFreeMap スタイルはトークンなしで動作します。',
|
||
'settings.map3dBuildings': '3D建物・地形',
|
||
'settings.map3dHint': 'ピッチ+実際の3D押し出し表示。衛星含む全スタイルで動作。',
|
||
'settings.mapHighQuality': '高品質モード',
|
||
'settings.mapHighQualityHint': 'アンチエイリアス+地球投影で、より鮮明でリアルに表示。',
|
||
'settings.mapHighQualityWarning': '低性能デバイスではパフォーマンスに影響する場合があります。',
|
||
'settings.mapTipLabel': 'ヒント:',
|
||
'settings.mapTip': '右クリック+ドラッグで回転/傾き。中クリックで場所を追加(右クリックは回転用)。',
|
||
'settings.latitude': '緯度',
|
||
'settings.longitude': '経度',
|
||
'settings.saveMap': '地図を保存',
|
||
'settings.apiKeys': 'APIキー',
|
||
'settings.mapsKey': 'Google Maps APIキー',
|
||
'settings.mapsKeyHint': '場所検索用。Places API(新)が必要。console.cloud.google.com で取得',
|
||
'settings.weatherKey': 'OpenWeatherMap APIキー',
|
||
'settings.weatherKeyHint': '天気情報用。openweathermap.org/api で無料取得',
|
||
'settings.keyPlaceholder': 'キーを入力…',
|
||
'settings.configured': '設定済み',
|
||
'settings.saveKeys': 'キーを保存',
|
||
'settings.display': '表示',
|
||
'settings.colorMode': 'カラーモード',
|
||
'settings.light': 'ライト',
|
||
'settings.dark': 'ダーク',
|
||
'settings.auto': '自動',
|
||
'settings.language': '言語',
|
||
'settings.temperature': '温度単位',
|
||
'settings.distance': '距離単位',
|
||
'settings.timeFormat': '時刻形式',
|
||
'settings.bookingLabels': '予約ルートのラベル',
|
||
'settings.bookingLabelsHint': '地図に駅・空港名を表示。オフ時はアイコンのみ。',
|
||
'settings.blurBookingCodes': '予約コードをぼかす',
|
||
'settings.aiAlwaysRetry': 'Always retry booking imports with AI',
|
||
'settings.aiAlwaysRetryHint': 'When a file cannot be read by the standard parser, automatically retry it with AI.',
|
||
'settings.optimizeFromAccommodation': '宿泊先を起点にルートを最適化',
|
||
'settings.optimizeFromAccommodationHint':
|
||
'その日を最適化する際、朝に目覚める宿泊先を起点にし、その晩にチェックインする宿泊先を終点としてルートを組みます。',
|
||
'settings.notifications': '通知',
|
||
'settings.notifyTripInvite': '旅行の招待',
|
||
'settings.notifyBookingChange': '予約の変更',
|
||
'settings.notifyTripReminder': '旅行リマインダー',
|
||
'settings.notifyTodoDue': 'ToDoの期限',
|
||
'settings.notifyVacayInvite': 'Vacay fusion の招待',
|
||
'settings.notifyPhotosShared': '共有写真(Immich)',
|
||
'settings.notifyCollabMessage': 'チャットメッセージ(Collab)',
|
||
'settings.notifyPackingTagged': '持ち物リスト:割り当て',
|
||
'settings.notifyWebhook': 'Webhook通知',
|
||
'settings.notifyVersionAvailable': '新しいバージョン',
|
||
'settings.notificationPreferences.email': 'メール',
|
||
'settings.notificationPreferences.webhook': 'Webhook',
|
||
'settings.notificationPreferences.inapp': 'アプリ内',
|
||
'settings.notificationPreferences.notConfigured': 'まだ設定されていません — プラグインの設定で構成してください',
|
||
'settings.plugins.actions': 'アクション',
|
||
'settings.plugins.actions.confirm': 'このアクションを実行しますか?',
|
||
'settings.notificationPreferences.sendTest': 'テスト送信',
|
||
'settings.notificationPreferences.configure': '設定する',
|
||
'settings.notificationPreferences.testSuccess': 'テスト通知を送信しました。',
|
||
'settings.notificationPreferences.testFailed': 'テストに失敗しました。',
|
||
'settings.notificationPreferences.pluginConfigured': '設定済みです。認証情報はプラグインの設定ページで管理します。',
|
||
'settings.notificationPreferences.ntfy': 'Ntfy',
|
||
'settings.notificationPreferences.noChannels': '通知チャネルが未設定です。管理者に設定を依頼してください。',
|
||
'settings.webhookUrl.label': 'Webhook URL',
|
||
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
||
'settings.webhookUrl.hint': 'Discord、Slack、または独自のWebhook URLを入力してください。',
|
||
'settings.webhookUrl.saved': 'Webhook URLを保存しました',
|
||
'settings.webhookUrl.test': 'テスト',
|
||
'settings.webhookUrl.testSuccess': 'テストWebhookを送信しました',
|
||
'settings.webhookUrl.testFailed': 'テストWebhookに失敗しました',
|
||
'settings.ntfyUrl.topicLabel': 'Ntfy トピック',
|
||
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
||
'settings.ntfyUrl.serverLabel': 'Ntfy サーバーURL(任意)',
|
||
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
||
'settings.ntfyUrl.hint': 'ntfyトピックを入力してください。サーバー未入力時は管理者設定の既定値を使用します。',
|
||
'settings.ntfyUrl.tokenLabel': 'アクセストークン(任意)',
|
||
'settings.ntfyUrl.tokenHint': 'パスワード保護トピックに必要です。',
|
||
'settings.ntfyUrl.saved': 'Ntfy設定を保存しました',
|
||
'settings.ntfyUrl.test': 'テスト',
|
||
'settings.ntfyUrl.testSuccess': 'テスト通知を送信しました',
|
||
'settings.ntfyUrl.testFailed': 'テスト通知に失敗しました',
|
||
'settings.ntfyUrl.tokenCleared': 'アクセストークンを削除しました',
|
||
'settings.notificationsDisabled': '通知が未設定です。管理者に有効化を依頼してください。',
|
||
'settings.notificationsActive': '有効なチャネル',
|
||
'settings.notificationsManagedByAdmin': '通知イベントは管理者が設定します。',
|
||
'settings.on': 'オン',
|
||
'settings.off': 'オフ',
|
||
'settings.mcp.title': 'MCP設定',
|
||
'settings.mcp.endpoint': 'MCPエンドポイント',
|
||
'settings.mcp.clientConfig': 'クライアント設定',
|
||
'settings.mcp.clientConfigHint': '<your_token> を下のAPIトークンに置き換えてください。',
|
||
'settings.mcp.clientConfigHintOAuth':
|
||
'<your_client_id> と <your_client_secret> をOAuth 2.1の認証情報に置き換えてください。',
|
||
'settings.mcp.copy': 'コピー',
|
||
'settings.mcp.copied': 'コピーしました!',
|
||
'settings.mcp.apiTokens': 'APIトークン',
|
||
'settings.mcp.createToken': '新しいトークン',
|
||
'settings.mcp.noTokens': 'トークンがありません。作成してください。',
|
||
'settings.mcp.tokenCreatedAt': '作成日',
|
||
'settings.mcp.tokenUsedAt': '最終使用',
|
||
'settings.mcp.deleteTokenTitle': 'トークン削除',
|
||
'settings.mcp.deleteTokenMessage': 'このトークンは即時無効になります。',
|
||
'settings.mcp.modal.createTitle': 'APIトークン作成',
|
||
'settings.mcp.modal.tokenName': 'トークン名',
|
||
'settings.mcp.modal.tokenNamePlaceholder': '例:Claude Desktop',
|
||
'settings.mcp.modal.creating': '作成中…',
|
||
'settings.mcp.modal.create': '作成',
|
||
'settings.mcp.modal.createdTitle': 'トークン作成完了',
|
||
'settings.mcp.modal.createdWarning': '表示は一度きりです。今すぐ保存してください。',
|
||
'settings.mcp.modal.done': '完了',
|
||
'settings.mcp.toast.created': 'トークンを作成しました',
|
||
'settings.mcp.toast.createError': 'トークン作成に失敗しました',
|
||
'settings.mcp.toast.deleted': 'トークンを削除しました',
|
||
'settings.mcp.toast.deleteError': 'トークン削除に失敗しました',
|
||
'settings.mcp.apiTokensDeprecated': 'APIトークンは非推奨です。OAuth 2.1 クライアントを使用してください。',
|
||
'settings.oauth.clients': 'OAuth 2.1 クライアント',
|
||
'settings.oauth.clientsHint': '第三者アプリが接続できるよう登録します。',
|
||
'settings.oauth.createClient': '新規クライアント',
|
||
'settings.oauth.noClients': '登録されたクライアントはありません。',
|
||
'settings.oauth.clientId': 'クライアントID',
|
||
'settings.oauth.clientSecret': 'クライアントシークレット',
|
||
'settings.oauth.deleteClient': 'クライアント削除',
|
||
'settings.oauth.deleteClientMessage': 'このクライアントは完全に削除されます。',
|
||
'settings.oauth.rotateSecret': 'シークレット更新',
|
||
'settings.oauth.rotateSecretMessage': '新しいシークレットを生成します。',
|
||
'settings.oauth.rotateSecretConfirm': '更新',
|
||
'settings.oauth.rotateSecretConfirming': '更新中…',
|
||
'settings.oauth.rotateSecretDoneTitle': '新しいシークレット',
|
||
'settings.oauth.rotateSecretDoneWarning': '表示は一度きりです。今すぐ保存してください。',
|
||
'settings.oauth.activeSessions': '有効なセッション',
|
||
'settings.oauth.sessionScopes': 'スコープ',
|
||
'settings.oauth.sessionExpires': '有効期限',
|
||
'settings.oauth.revoke': '取り消し',
|
||
'settings.oauth.revokeSession': 'セッション取り消し',
|
||
'settings.oauth.revokeSessionMessage': 'このセッションのアクセスを即時無効にします。',
|
||
'settings.oauth.modal.createTitle': 'OAuthクライアント登録',
|
||
'settings.oauth.modal.presets': '簡単設定',
|
||
'settings.oauth.modal.clientName': 'アプリ名',
|
||
'settings.oauth.modal.clientNamePlaceholder': '例:Claude Web',
|
||
'settings.oauth.modal.redirectUris': 'リダイレクトURI',
|
||
'settings.oauth.modal.redirectUrisPlaceholder': 'https://your-app.com/callback',
|
||
'settings.oauth.modal.redirectUrisHint': '1行につき1つ。HTTPS必須。',
|
||
'settings.oauth.modal.scopes': '許可スコープ',
|
||
'settings.oauth.modal.scopesHint': 'list_trips と get_trip_summary は常に利用可能です。',
|
||
'settings.oauth.modal.selectAll': 'すべて選択',
|
||
'settings.oauth.modal.deselectAll': 'すべて解除',
|
||
'settings.oauth.modal.creating': '登録中…',
|
||
'settings.oauth.modal.create': '登録',
|
||
'settings.oauth.modal.createdTitle': '登録完了',
|
||
'settings.oauth.modal.createdWarning': 'シークレットは一度しか表示されません。',
|
||
'settings.oauth.toast.createError': '登録に失敗しました',
|
||
'settings.oauth.toast.deleted': 'クライアントを削除しました',
|
||
'settings.oauth.toast.deleteError': '削除に失敗しました',
|
||
'settings.oauth.toast.revoked': 'セッションを取り消しました',
|
||
'settings.oauth.toast.revokeError': '取り消しに失敗しました',
|
||
'settings.oauth.toast.rotateError': '更新に失敗しました',
|
||
'settings.account': 'アカウント',
|
||
'settings.about': '情報',
|
||
'settings.about.reportBug': '不具合報告',
|
||
'settings.about.reportBugHint': '問題を見つけたらお知らせください',
|
||
'settings.about.featureRequest': '機能リクエスト',
|
||
'settings.about.featureRequestHint': '新機能を提案',
|
||
'settings.about.wikiHint': 'ドキュメント・ガイド',
|
||
'settings.about.supporters.badge': '月額サポーター',
|
||
'settings.about.supporters.title': 'TREKの旅仲間',
|
||
'settings.about.supporters.subtitle': '皆さんの支援がTREKの未来を支えています。',
|
||
'settings.about.supporters.since': '{date}からサポート',
|
||
'settings.about.supporters.tierEmpty': '最初の一人に',
|
||
'settings.about.supporter.tier.noReturnTicket': '片道切符',
|
||
'settings.about.supporter.tier.lostLuggageVip': 'ロストラゲージVIP',
|
||
'settings.about.supporter.tier.businessClassDreamer': 'ビジネスクラスの夢',
|
||
'settings.about.supporter.tier.budgetTraveller': '節約トラベラー',
|
||
'settings.about.supporter.tier.hostelBunkmate': 'ホステル仲間',
|
||
'settings.about.description': 'TREKはセルフホスト型の旅行プランナーです。',
|
||
'settings.about.madeWith': 'Made with',
|
||
'settings.about.madeBy': 'by Maurice とオープンソースコミュニティ。',
|
||
'settings.username': 'ユーザー名',
|
||
'settings.email': 'メール',
|
||
'settings.role': '役割',
|
||
'settings.roleAdmin': '管理者',
|
||
'settings.oidcLinked': '連携先',
|
||
'settings.changePassword': 'パスワード変更',
|
||
'settings.currentPassword': '現在のパスワード',
|
||
'settings.currentPasswordRequired': '現在のパスワードが必要です',
|
||
'settings.newPassword': '新しいパスワード',
|
||
'settings.confirmPassword': '新しいパスワード(確認)',
|
||
'settings.updatePassword': 'パスワード更新',
|
||
'settings.passwordRequired': '現在と新しいパスワードを入力してください',
|
||
'settings.passwordTooShort': '8文字以上必要です',
|
||
'settings.passwordMismatch': 'パスワードが一致しません',
|
||
'settings.passwordWeak': '大文字・小文字・数字・記号を含めてください',
|
||
'settings.passwordChanged': 'パスワードを変更しました',
|
||
'settings.mustChangePassword': '続行するにはパスワード変更が必要です。',
|
||
'settings.deleteAccount': 'アカウント削除',
|
||
'settings.deleteAccountTitle': 'アカウントを削除しますか?',
|
||
'settings.deleteAccountWarning': 'すべてのデータが完全に削除されます。',
|
||
'settings.deleteAccountConfirm': '完全に削除',
|
||
'settings.deleteBlockedTitle': '削除できません',
|
||
'settings.deleteBlockedMessage': '唯一の管理者です。別のユーザーを管理者にしてください。',
|
||
'settings.roleUser': 'ユーザー',
|
||
'settings.saveProfile': 'プロフィールを保存',
|
||
'settings.toast.mapSaved': '地図設定を保存しました',
|
||
'settings.toast.keysSaved': 'APIキーを保存しました',
|
||
'settings.toast.displaySaved': '表示設定を保存しました',
|
||
'settings.toast.profileSaved': 'プロフィールを保存しました',
|
||
'settings.uploadAvatar': 'プロフィール画像をアップロード',
|
||
'settings.removeAvatar': 'プロフィール画像を削除',
|
||
'settings.avatarUploaded': 'プロフィール画像を更新しました',
|
||
'settings.avatarRemoved': 'プロフィール画像を削除しました',
|
||
'settings.avatarError': 'アップロードに失敗しました',
|
||
'settings.mfa.title': '二要素認証(2FA)',
|
||
'settings.mfa.description': 'サインイン時に追加の認証を行います。',
|
||
'settings.mfa.requiredByPolicy': '管理者により2FAが必須です。',
|
||
'settings.mfa.backupTitle': 'バックアップコード',
|
||
'settings.mfa.backupDescription': '認証アプリが使えない場合に使用します。',
|
||
'settings.mfa.backupWarning': '今すぐ保存してください。各コードは1回限りです。',
|
||
'settings.mfa.backupCopy': 'コードをコピー',
|
||
'settings.mfa.backupDownload': 'TXTでダウンロード',
|
||
'settings.mfa.backupPrint': '印刷 / PDF',
|
||
'settings.mfa.backupCopied': 'バックアップコードをコピーしました',
|
||
'settings.mfa.enabled': '2FAは有効です。',
|
||
'settings.mfa.disabled': '2FAは無効です。',
|
||
'settings.mfa.setup': '認証アプリを設定',
|
||
'settings.mfa.scanQr': 'QRコードをスキャンするか、手動で入力してください。',
|
||
'settings.mfa.secretLabel': 'シークレットキー(手動入力)',
|
||
'settings.mfa.codePlaceholder': '6桁コード',
|
||
'settings.mfa.enable': '2FAを有効化',
|
||
'settings.mfa.cancelSetup': 'キャンセル',
|
||
'settings.mfa.disableTitle': '2FAを無効化',
|
||
'settings.mfa.disableHint': 'パスワードと現在のコードを入力してください。',
|
||
'settings.mfa.disable': '2FAを無効化',
|
||
'settings.mfa.toastEnabled': '2FAを有効にしました',
|
||
'settings.mfa.toastDisabled': '2FAを無効にしました',
|
||
'settings.mfa.demoBlocked': 'デモモードでは利用できません',
|
||
'settings.oauth.modal.machineClient': 'マシンクライアント(ブラウザログインなし)',
|
||
'settings.oauth.modal.machineClientHint':
|
||
'client_credentials グラントを使用します — リダイレクト URI は不要です。トークンは client_id + client_secret を介して直接発行され、選択したスコープ内であなたとして動作します。',
|
||
'settings.oauth.modal.machineClientUsage':
|
||
'トークンを取得するには、grant_type=client_credentials、client_id、client_secret を指定して POST /oauth/token を呼び出します。ブラウザもリフレッシュトークンも不要です。',
|
||
'settings.oauth.badge.machine': 'マシン',
|
||
'settings.currency': 'Currency',
|
||
'settings.currencyHint': 'All amounts in Costs are converted to and shown in this currency.',
|
||
'settings.passkey.title': 'パスキー',
|
||
'settings.passkey.description':
|
||
'指紋、顔認証、PIN、またはハードウェアキーを使うパスキーで、より速く、フィッシングに強いサインインができます。パスワードはバックアップとして残ります。',
|
||
'settings.passkey.notConfigured':
|
||
'パスキーは有効ですが、このサーバーではまだ完全には設定されていません。管理者に WebAuthn ドメインの設定を依頼してください。',
|
||
'settings.passkey.add': 'パスキーを追加',
|
||
'settings.passkey.addTitle': 'パスキーを追加',
|
||
'settings.passkey.passwordPrompt': '現在のパスワードを確認し、デバイスの指示に従ってください。',
|
||
'settings.passkey.passwordRequired': '現在のパスワードが必要です。',
|
||
'settings.passkey.namePlaceholder': '名前(任意、例:"iPhone")',
|
||
'settings.passkey.addedToast': 'パスキーを追加しました',
|
||
'settings.passkey.added': '追加済み',
|
||
'settings.passkey.addError': 'パスキーを追加できませんでした',
|
||
'settings.passkey.cancelled': 'パスキーの設定をキャンセルしました',
|
||
'settings.passkey.deleted': 'パスキーを削除しました',
|
||
'settings.passkey.deleteConfirm': 'このパスキーを削除しますか?パスワードで確認してください。',
|
||
'settings.passkey.rename': '名前を変更',
|
||
'settings.passkey.defaultName': 'パスキー',
|
||
'settings.passkey.synced': '同期済み',
|
||
'settings.passkey.deviceBound': 'このデバイス',
|
||
'settings.passkey.lastUsed': '最終使用',
|
||
'settings.passkey.neverUsed': '未使用',
|
||
'settings.mapPoiPill': '地図でスポットを探す',
|
||
'settings.mapPoiPillHint':
|
||
'旅行の地図にカテゴリピルを表示して、OpenStreetMapから近くのレストランや宿泊施設などを見つけられます。',
|
||
'settings.airtrail.title': 'AirTrail',
|
||
'settings.airtrail.hint':
|
||
'セルフホストの AirTrail を接続して、フライトをインポート・同期します。AirTrail の「設定 → セキュリティ」で API キーを作成してください。',
|
||
'settings.airtrail.url': 'インスタンス URL',
|
||
'settings.airtrail.apiKey': 'API キー',
|
||
'settings.airtrail.apiKeyPlaceholder': 'Bearer API キー',
|
||
'settings.airtrail.apiKeyHint': 'AirTrail の「設定 → セキュリティ」で生成します。暗号化して保存されます。',
|
||
'settings.airtrail.allowInsecureTls': '自己署名証明書を許可する',
|
||
'settings.airtrail.allowInsecureTlsHint':
|
||
'自分のネットワーク内の信頼できるインスタンスの場合にのみ有効にしてください。',
|
||
'settings.airtrail.writeBack': '変更を AirTrail に書き戻す',
|
||
'settings.airtrail.writeBackHint':
|
||
'既定ではオフ: AirTrail が信頼できる情報源で、TREK は読み取りのみを行います。TREK で行った編集を AirTrail に書き戻すにはオンにします。',
|
||
'settings.airtrail.connected': '接続済み',
|
||
'settings.airtrail.notConnected': '未接続',
|
||
'settings.airtrail.toast.saved': 'AirTrail の接続を保存しました',
|
||
'settings.airtrail.toast.saveError': '接続を保存できませんでした',
|
||
'settings.airtrail.test.button': '接続をテスト',
|
||
'settings.airtrail.test.success': '接続成功 — {count} 件のフライトが見つかりました',
|
||
'settings.airtrail.test.failed': '接続に失敗しました',
|
||
'settings.aiParsing.title': 'AI解析',
|
||
'settings.aiParsing.hint':
|
||
'アップロードしたファイルから予約情報を抽出するために、自分のAIモデルを使用します。これは、管理者がインスタンス全体のモデルを設定していない場合にのみ適用されます。',
|
||
'settings.aiParsing.provider': 'プロバイダー',
|
||
'settings.aiParsing.providerLocal': 'ローカル (Ollama)',
|
||
'settings.aiParsing.providerOpenai': 'OpenAI',
|
||
'settings.aiParsing.providerAnthropic': 'Anthropic',
|
||
'settings.aiParsing.model': 'モデル',
|
||
'settings.aiParsing.baseUrl': 'ベースURL',
|
||
'settings.aiParsing.baseUrlHint': 'モデルの実行場所 — ローカルのOllamaサーバー、またはOpenAI互換のエンドポイント。',
|
||
'settings.aiParsing.apiKey': 'APIキー',
|
||
'settings.aiParsing.apiKeyHint': '暗号化して保存されます。現在のキーを保持する場合は空欄のままにしてください。',
|
||
'settings.aiParsing.multimodal': 'ドキュメントを画像として送信',
|
||
'settings.aiParsing.multimodalHint': '画像認識対応モデル向け — 抽出したテキストの代わりに元のPDFを送信します。',
|
||
'settings.aiParsing.toast.saved': 'AI設定を保存しました',
|
||
'settings.aiParsing.toast.saveError': 'AI設定を保存できませんでした',
|
||
'settings.tabs.appearance': 'Appearance',
|
||
'settings.appearance.theme': 'Theme',
|
||
'settings.appearance.scheme': 'Color scheme',
|
||
'settings.appearance.scheme.default': 'Default',
|
||
'settings.appearance.scheme.highContrast': 'High contrast',
|
||
'settings.appearance.scheme.indigo': 'Indigo',
|
||
'settings.appearance.scheme.teal': 'Teal',
|
||
'settings.appearance.scheme.rose': 'Rose',
|
||
'settings.appearance.scheme.amber': 'Amber',
|
||
'settings.appearance.scheme.violet': 'Violet',
|
||
'settings.appearance.scheme.custom': 'Custom',
|
||
'settings.appearance.customAccent': 'Custom accent',
|
||
'settings.appearance.contrastOk': 'Good contrast',
|
||
'settings.appearance.contrastLow': 'Low contrast',
|
||
'settings.appearance.readability': 'Readability',
|
||
'settings.appearance.transparency': 'Transparency',
|
||
'settings.appearance.transparencyHint':
|
||
'Glassy translucent surfaces. Turn off for solid, higher-contrast backgrounds.',
|
||
'settings.appearance.reduceMotion': 'Reduce motion',
|
||
'settings.appearance.reduceMotionHint': 'Minimize animations and transitions.',
|
||
'settings.appearance.density': 'Density',
|
||
'settings.appearance.comfortable': 'Comfortable',
|
||
'settings.appearance.compact': 'Compact',
|
||
'settings.appearance.textSize': 'Text size',
|
||
'settings.appearance.advancedTextSizes': 'Advanced text sizes',
|
||
'settings.appearance.hideAdvanced': 'Hide advanced',
|
||
'settings.appearance.tier.title': 'Titles',
|
||
'settings.appearance.tier.subtitle': 'Subtitles',
|
||
'settings.appearance.tier.body': 'Body',
|
||
'settings.appearance.tier.caption': 'Captions',
|
||
'settings.appearance.dashboardWidgets': 'Dashboard widgets',
|
||
'settings.appearance.dashboardWidgetsHint': 'Show or hide dashboard widgets independently on desktop and mobile.',
|
||
'settings.appearance.desktop': 'Desktop',
|
||
'settings.appearance.mobile': 'Mobile',
|
||
'settings.appearance.widget.sidebar': 'Right sidebar',
|
||
'settings.appearance.widget.currency': 'Currency',
|
||
'settings.appearance.widget.collections': 'コレクション',
|
||
'settings.appearance.widget.timezones': 'Timezones',
|
||
'settings.appearance.widget.upcomingReservations': 'Upcoming reservations',
|
||
'settings.appearance.widget.atlas': 'Atlas / countries',
|
||
'settings.appearance.widget.tripsTotal': 'Trips total',
|
||
'settings.appearance.widget.daysTraveled': 'Days traveled',
|
||
'settings.appearance.widget.distanceFlown': 'Distance flown',
|
||
'settings.appearance.reset': 'Reset to defaults',
|
||
'settings.appearance.group.belowHero': 'Below the hero',
|
||
'settings.appearance.group.bottomOfPage': 'Bottom of page',
|
||
'settings.appearance.sidebarHint': 'The whole right column. Turn off and the dashboard centers.',
|
||
'settings.appearance.densityHint':
|
||
'Compact tightens spacing and padding for a denser layout that fits more on screen.',
|
||
'settings.appearance.textSizeAll': 'Everything',
|
||
'settings.appearance.perSize': 'Adjust each size separately',
|
||
'settings.appearance.size.large': 'Large',
|
||
'settings.appearance.size.medium': 'Medium',
|
||
'settings.appearance.size.normal': 'Normal',
|
||
'settings.appearance.size.small': 'Small',
|
||
'settings.appearance.preview.large': 'Large heading',
|
||
'settings.appearance.preview.medium': 'Medium subtitle',
|
||
'settings.appearance.preview.normal': 'Normal body text',
|
||
'settings.appearance.preview.small': 'Small caption / address',
|
||
'settings.appearance.example.large': 'Headings, big numbers',
|
||
'settings.appearance.example.medium': 'Sub-headings',
|
||
'settings.appearance.example.normal': 'Place names, descriptions',
|
||
'settings.appearance.example.small': 'Addresses, labels',
|
||
'settings.appearance.experimental': 'Experimental',
|
||
'settings.general.languageRegion': 'Language & region',
|
||
'settings.general.travelMap': 'Travel & map',
|
||
|
||
// ── Offline (#1135)
|
||
'settings.offline.cache.title': 'オフラインキャッシュ',
|
||
'settings.offline.mode.title': 'オフラインモード',
|
||
'settings.offline.mode.force': 'オフラインモードを強制',
|
||
'settings.offline.mode.forceHint':
|
||
'キャッシュ済みのデータのみで作業し、変更はキューに保存します。オフにすると再接続して同期します。',
|
||
'settings.offline.mode.active': 'オフラインモードがオンです — 変更はキューに保存され、オフにすると同期されます。',
|
||
'settings.offline.prepare.title': 'オフラインの準備',
|
||
'settings.offline.prepare.hint':
|
||
'接続が切れる前に、必要なもの — 旅行データ、ドキュメント、地図タイル — をすべてダウンロードします。',
|
||
'settings.offline.prepare.button': 'オフライン用にダウンロード',
|
||
'settings.offline.prepare.running': 'ダウンロード中…',
|
||
'settings.offline.prepare.done': 'オフラインで利用できます',
|
||
'settings.offline.prepare.phase.trips': '旅行データ',
|
||
'settings.offline.prepare.phase.files': 'ドキュメント',
|
||
'settings.offline.prepare.phase.tiles': '地図タイル',
|
||
'settings.offline.resync': '今すぐ再同期',
|
||
'settings.offline.resyncing': '同期中…',
|
||
'settings.offline.storage.title': 'オフラインで保存する内容',
|
||
'settings.offline.storage.tiles': '地図タイルをオフラインで保存',
|
||
'settings.offline.storage.tilesHint':
|
||
'地図タイルは最も多くのストレージを使用します。これをオフにすると、旅行データとドキュメントのみをオフラインで保存します。',
|
||
'settings.offline.storage.tripsTitle': '旅行',
|
||
'settings.offline.storage.tripOn': 'オフラインで保存済み',
|
||
'settings.offline.storage.tripOff': '未保存',
|
||
'settings.offline.clear': 'キャッシュを消去',
|
||
'settings.offline.clearConfirm': 'すべてのオフライン旅行データを消去しますか?オンライン時にいつでも再同期できます。',
|
||
'settings.offline.stats.trips': 'キャッシュ済みの旅行',
|
||
'settings.offline.stats.pending': '保留中の変更',
|
||
'settings.offline.stats.failed': '失敗した変更',
|
||
'settings.offline.stats.conflicts': '競合',
|
||
'settings.offline.empty': 'キャッシュされた旅行はまだありません。インターネットに接続して同期してください。',
|
||
'settings.offline.loading': '読み込み中…',
|
||
'settings.offline.conflicts.title': '同期の競合',
|
||
'settings.offline.conflicts.hint':
|
||
'オフラインで行った変更が、サーバー上の新しい変更と競合しています。どちらのバージョンを保持するか選択してください。',
|
||
'settings.offline.conflicts.keepMine': '自分の変更を保持',
|
||
'settings.offline.conflicts.keepServer': 'サーバーの変更を保持',
|
||
'settings.offline.conflicts.mine': 'あなたのバージョン',
|
||
'settings.offline.conflicts.server': 'サーバーのバージョン',
|
||
'settings.offline.conflicts.item': '“{name}”への変更',
|
||
'settings.offline.conflicts.strategyTitle': '競合が発生したとき',
|
||
'settings.offline.conflicts.strategy.ask': '毎回確認する',
|
||
'settings.offline.conflicts.strategy.mine': '常に自分のバージョンを保持',
|
||
'settings.offline.conflicts.strategy.server': '常にサーバーのバージョンを保持',
|
||
'settings.offline.banner.offline': 'オフライン',
|
||
'settings.offline.banner.forced': 'オフラインモード',
|
||
'settings.offline.banner.queued': 'オフライン · {count} 件キュー',
|
||
'settings.offline.banner.syncing': '{count} 件を同期中…',
|
||
'settings.offline.banner.failed': '同期に失敗: {count}',
|
||
'settings.offline.banner.conflicts': '競合: {count}',
|
||
'settings.pluginActivity.title': 'プラグインのアクティビティ',
|
||
'settings.pluginActivity.description': 'プラグインがあなたに代わって行ったすべての操作を新しい順に表示します。',
|
||
'settings.pluginActivity.empty': 'プラグインのアクティビティはまだありません。',
|
||
'settings.pluginActivity.refresh': '更新',
|
||
'settings.pluginActivity.columns.plugin': 'プラグイン',
|
||
'settings.pluginActivity.columns.action': '操作',
|
||
'settings.pluginActivity.columns.resource': 'リソース',
|
||
'settings.pluginActivity.columns.when': '日時',
|
||
'settings.pluginActivity.columns.status': '結果',
|
||
};
|
||
|
||
export default settings;
|