visual-game.js 43.5 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
export default {
  appName: 'voko.world',
  productBrandSub: 'あなたのkosmoが呼んでいる。',
  mobileCredit: { title: 'マイクレジット', buyCredits: 'クレジット購入', history: 'クレジット履歴', purchaseHistory: '購入履歴', usageHistory: '利用履歴', emptyHistory: '履歴はありません。', loadMore: 'さらに読み込む', balanceAfter: '残高:{points}', pending: '処理中', paid: '支払い済み', canceled: 'キャンセル済み', failed: '失敗', refunded: '返金済み', disputed: '異議申立中', autoReload: '自動リロード', bonusCredits: 'ボーナスクレジット', buyNow: '今すぐ購入', lowBalance: '残高不足', enabled: '有効', whenBelow: '残高が次を下回ったら', choosePack: 'リロードパックを選択', consent: '残高がしきい値に達した際、選択したパックを自動購入することを許可します。', terms: '利用規約', continueSecurely: '安全に続行', save: '設定を保存', disable: '自動リロードをオフ', setupComplete: '支払い方法を保存し、自動リロードを有効にしました。', setupCanceled: '設定をキャンセルしました。', actionRequired: '前回のリロードに失敗しました。支払い方法を再設定してください。', howTitle: '自動リロードの仕組み', howBalance: '残高がしきい値以下になると、選択したパックを購入します。', howSecure: '支払い情報は Stripe が安全に保存し、Voko はカード番号を保存しません。', howCancel: 'いつでも停止できます。過去の購入は返金されません。' },
  nav: { play: 'プレイ', notes: '手掛かり', state: '状態', editor: '編集' },
  scenario: { title: 'シナリオ', available: 'シナリオ', assetManifest: '素材一覧' },
  character: { title: 'キャラクター', start: '開始', current: '現在のキャラクター' },
  stage: { empty: 'シナリオとキャラクターを選択', turn: 'ターン {turn}', ending: 'エンディング', transcript: '記録' },
  composer: { act: '行動', say: '発言', placeholder: '行動または発言を入力' },
  actions: { refresh: '更新', start: '開始', home: 'ホーム', backHome: '戻る', newRun: '再開', send: '送信', save: '保存', compile: 'コンパイル', publish: '公開', rollback: 'ロールバック', upload: 'アップロード', select: '選択', endingText: 'エンディング文', load: '読み込む', backToGame: '戻る', cancel: 'キャンセル', confirm: '確認' },
  account: {
    signIn: 'ログイン',
    signedIn: 'ログイン中',
    signedOut: 'ログアウトしました',
    sessionExpired: 'セッションの有効期限が切れました。もう一度ログインしてください。',
    logoutFailed: 'ログアウトに失敗しました。もう一度お試しください。',
    registered: '登録完了',
    email: 'メール',
    emailPlaceholder: 'メールアドレス',
    password: 'パスワード',
    passwordPlaceholder: 'パスワードを入力',
    confirmPassword: 'パスワード確認',
    confirmPasswordPlaceholder: 'もう一度入力',
    verificationCode: '確認コード',
    verificationCodePlaceholder: '6 桁のメール確認コード',
    inviteToken: '招待コード',
    inviteTokenPlaceholder: '8 文字の招待コードを入力',
    sendCode: 'コード送信',
    resendCode: '再送信',
    codeSent: '確認コードを送信しました。メールを確認してください。',
    codeRequired: 'メール確認コードを入力してください。',
    inviteInvalid: '有効な 8 文字の招待コードを入力してください。',
    emailRequired: '先にメールを入力してください。',
    emailInvalid: '有効なメールアドレスを入力してください。',
    passwordRequired: '先にパスワードを入力してください。',
    confirmPasswordRequired: '先に確認用パスワードを入力してください。',
    loginFieldsRequired: 'メールアドレスとパスワードを入力してください。',
    inviteEmailMismatch: 'このメールアドレスは招待コードに紐づく申請メールと一致しません。',
    passwordMismatch: 'パスワードが一致しません。',
    createAccount: 'アカウント作成',
    hasAccount: 'アカウントをお持ちですか?',
    noAccount: 'アカウントはまだありませんか?',
    termsHint: '続行すると、このメールが本人所有であることを確認し、進行、注文、ポイント保存に同意します。',
    login: 'ログイン',
    register: '登録',
    reset: 'リセット',
    forgotPassword: 'パスワードをお忘れですか?',
    resetPassword: 'パスワードをリセット',
    resetTitle: 'パスワードをリセット',
    resetBody: 'メール確認コードを入力して新しいパスワードを設定します。既存セッションはすべて無効になります。',
    resetCodeSent: 'リセット用コードを送信しました。メールを確認してください。',
    resetFieldsRequired: 'メールアドレス、確認コード、新しいパスワード、確認用パスワードを入力してください。',
    passwordResetDone: 'パスワードをリセットしました。新しいパスワードでログインしてください。',
    logout: 'ログアウト',
    logoutAll: 'すべての端末からログアウト',
    credits: 'ポイント',
    buy: 'ポイント購入',
    billing: '請求',
    promptTitle: 'ログインまたは登録して開始',
    promptBody: '進行、セーブ、エンディング、ポイント、注文をアカウントに保存し、別の端末でも続行できます。',
    signedInBody: '進行、セーブ、ポイントはデータベースに保存されます。',
    registerAndStart: '登録して役を選ぶ',
    guestStart: 'ゲストで試す',
    savedHint: 'ログインすると進行とセーブを自動保存',
    currentAccount: '現在のアカウント',
    saveKicker: 'アカウント保存',
    saveTitle: '進行と注文を保存',
    loginTitle: 'ログイン',
    loginBody: 'ログイン後、この端末のゲスト進行を可能な範囲で統合します。',
    registerTitle: 'アカウント作成',
    registerBody: '招待コードとメールの所有を確認してからアカウントを作成します。登録後は自動ログインし、100 ポイントを付与して端末進行を統合します。',
    openBilling: 'ポイントと注文を見る',
    mergePending: 'この端末のゲスト進行を統合中…',
    mergeSuccess: '端末データを統合しました:{details}。',
    mergeSeparator: '、',
    mergeRuns: '{count} 件の対局',
    mergeTurns: '{count} 件のターン',
    mergeProgress: '{count} 件の進行',
    mergeSaveSlots: '{count} 件のセーブ',
    mergeEndingRecords: '{count} 件のエンディング',
    mergeEvents: '{count} 件のイベント',
    mergeAgentCalls: '{count} 件の AI 呼び出し',
    mergeBillingLedger: '{count} 件のポイント履歴',
    mergeBillingUnlocks: '{count} 件の有料解放',
    mergeBillingFreeQuota: '{count} 件の無料枠',
    mergePaymentOrders: '{count} 件の注文',
    mergeEmpty: '統合できる端末進行はありません。',
    mergeFailed: 'ログイン済みですが、端末進行はまだ統合されていません。後で更新してください。',
  },
  billing: {
    title: 'ポイントと注文',
    subtitle: '残高、購入、履歴、注文はデータベースから読み込みます。',
    guestSubtitle: 'ゲストはポイントパックを確認できます。購入、残高、注文、履歴にはログインが必要です。',
    balance: '現在の残高',
    products: 'ポイントパック',
    ledger: 'ポイント履歴',
    orders: '注文',
    refresh: '請求情報を更新',
    testModeTitle: 'Stripe テスト環境',
    testModeBody: 'テスト決済を使用するため、実際の請求は発生しません。',
    testPurchase: 'テスト購入',
    buy: '{points} ポイントを購入',
    checkoutReady: '決済リンクを作成しました。',
    openCheckout: '決済ページを開く',
    selectedPack: '選択中',
    selectedProduct: '{title} を選択しました。残高に {points} ポイントが追加されます。',
    signInToBuy: 'ログインして購入',
    readyToBuy: 'ポイントを購入できます',
    readyToBuyBody: 'ポイントパックを選び、決済へ進みます。確認前の注文は処理中になります。',
    checkoutPending: '決済ページへ移動中…',
    checkoutReturnedSuccess: 'アプリに戻りました。残高と注文を更新しています。反映は注文状態に従います。',
    checkoutReturnedCancel: '決済はキャンセルまたは未完了です。反映は確認されていません。',
    signInHint: 'ログインすると残高、注文、履歴を確認できます。',
    emptyProducts: 'ポイントパックはありません。',
    emptyLedger: '履歴はありません。',
    emptyOrders: '注文はありません。',
    productFallback: 'ポイントパック',
    points: '{points} ポイント',
    price: '{amount} {currency}',
    ledgerAmount: '{amount} ポイント',
    orderStatus: '状態 {status}',
    orderStatusPending: '処理中',
    orderStatusPaid: '支払い済み',
    orderStatusRefunded: '返金済み',
    orderStatusDisputed: '異議申し立て中',
    orderStatusUnknown: '状態不明',
    ledgerReasonSignupGift: '登録特典',
    ledgerReasonCheckout: 'ポイント購入',
    ledgerReasonRefund: '注文返金',
    ledgerReasonChargeback: 'チャージバック取り消し',
    ledgerReasonUnlock: 'コンテンツ解放',
    paywallTitle: '有料解放',
    paywallTarget: '対象',
    paywallReason: '課金理由',
    paywallGenericReason: 'この内容を続けるにはポイントが必要です。',
    paywallFreeContinue: '無料枠が残っています。続行できます。',
    paywallInsufficient: 'ポイントが不足しています。先に購入してください。',
    paywallPrice: '必要ポイント',
    paywallFreeQuota: '残り無料枠',
    paywallBalance: '利用可能残高',
  },
  endings: {
    title: 'エンディング図鑑',
    unlocked: '解放済み',
    locked: '未解放',
    collected: '{count}/{total} 収集済み',
    lockedHint: '対応するエンディングに到達すると解放されます。',
  },
  saves: {
    title: 'セーブ',
    progress: '現在の進行',
    activeRun: '現在のゲーム',
    slot: 'スロット {slotNo}',
    savedRun: '保存済み進行',
    emptySlot: '空きスロット',
    emptyHint: '現在の run を保存すると再読み込み後も復帰できます。',
    saveHere: '保存',
    overwrite: '上書き保存',
    restore: '読み込み',
    delete: '削除',
    saved: 'セーブしました。',
    restored: 'セーブを読み込みました。',
    deleted: 'セーブを削除しました。',
    conflict: '既存のセーブがあります。この復元地点を上書きする前に確認してください。',
    restoreConfirm: '読み込むと現在のゲームはこのセーブ地点に切り替わります。',
    deleteConfirm: '削除したセーブ地点は復元できません。',
    noRunHint: '保存できる現在の run がありません。先に開始または再開してください。',
  },
  map: {
    title: 'マップ',
    current: '現在地',
    route: '移動可能',
    routes: '移動可能な場所',
    locked: '未解放',
    moveTo: '{location}へ移動',
    objects: '調査できる対象',
    inspect: '調査',
    inspected: '調査済み',
    inspectObject: '{object}を調べる',
  },
  videoCenter: {
    eyebrow: 'プレイヤー記録',
    title: '映像センター',
    backHome: '戻る',
    chooseScenario: 'シナリオ選択',
    allScenarios: 'すべてのシナリオ',
    searchScenario: 'シナリオを検索',
    scenarioPaintedSkin: '画皮',
    scenarioGuian: '帰安県失心事件',
    nowPlaying: '再生中',
    player: 'プレイヤー',
    views: '視聴回数',
    ending: '結末',
    duration: '時間',
    libraryEyebrow: '同じシナリオの映像',
    allVideos: 'すべての映像',
    sort: '映像の並び順',
    recommended: 'おすすめ',
    latest: '最新',
    videoMeta: '{player} · {date}',
    emptyTitle: 'プレイヤー映像はまだありません',
    emptyText: 'このシナリオには公開されたプレイ映像がありません。',
    viewAll: 'すべてのプレイヤー映像を見る',
    discoverStories: '他の人の選択を見る',
    backPrevious: '前のページへ', aiSummary: 'AI概要:', endingCount: '種類の結末', publicSeriesCount: '公開シリーズ', totalPlays: '総再生', seriesList: 'プレイヤーシリーズ', completed: '完結', updating: '第{count}話まで · 連載中', seriesMetrics: '全{episodes}話 · ▶ {plays} · ♥ {likes}', watchSeries: 'このシリーズを見る', playOwnSeries: '自分のシリーズを作る', minutes: '{count}分', share: '共有', shareCopied: 'リンクをコピーしました', shareFailed: '共有できませんでした', like: 'いいね', liked: 'いいね済み', save: '保存', saved: '保存済み', storyHighlight: '物語の見どころ', startPlay: 'プレイして結末を書き換える', episodeList: 'エピソード', episodeTotal: '全{count}話', episodeTitle: '第{count}話 · {title}',
  },
  runHistory: {
    eyebrow: '個人プレイ記録',
    title: '自分の対局',
    allRuns: 'すべての対局',
    count: '{count} 件',
    empty: 'プレイ記録はまだありません。対局を始めるとここに表示されます。',
    loadFailed: '読み込み失敗:{error}',
    noTime: '時刻不明',
    statusActive: '進行中',
    statusCompleted: '終了',
    videoNone: '動画なし',
    videoQueued: '動画待機中',
    videoRunning: '動画生成中',
    videoReady: '動画準備完了',
    videoFailed: '動画失敗',
    videoRetry: '再生成',
    untitledEnding: 'エンディング未到達',
    meta: '{scenario} · ターン {turn} · {date}',
    openRun: '対局を開く',
    openNotes: 'ノート',
    watchVideo: '動画を見る',
  },
  mobileProfile: { title: 'マイ', settings: '設定', content: 'コンテンツ', benefits: '特典', creator: 'クリエイター', support: 'お問い合わせ・サポート', contact: 'カスタマーサポート', terms: '利用規約', privacy: 'プライバシーポリシー', social: 'ソーシャルメディア' },
  profileEditor: { editProfile: 'プロフィールを編集', nameSection: 'プロフィール名', nameHint: 'ゲームや動画に表示される名前です。', name: '名前', saveName: '名前を保存', nameRequired: '名前を入力してください。', nameSaved: '名前を更新しました。', passwordSection: 'パスワードを変更', passwordHint: 'メールに届く認証コードで本人確認を行います。', email: 'メール', verificationCode: 'メール認証コード', sendCode: 'コードを送信', codeSent: '認証コードをメールに送信しました。', newPassword: '新しいパスワード', confirmPassword: '新しいパスワードを確認', savePassword: 'パスワードを更新', passwordRequirements: '認証コードと8文字以上の新しいパスワードを入力してください。', passwordMismatch: 'パスワードが一致しません。', passwordSaved: 'パスワードを更新しました。' },
  myGames: { recent: '最近プレイした作品', popular: '人気のストーリー', emptyRecent: '最近プレイしたストーリーがここに表示されます。', loadError: 'ゲームを読み込めませんでした。もう一度お試しください。' },
  storyDetail: { title: 'ストーリー情報', description: 'ストーリー紹介', episodes: '{count} エピソード', endings: '{count} エンディング', by: '作者:{name}', lastUpdate: '最終更新', newPlay: '新しくプレイ', notFound: 'ストーリーが見つかりません。', loadError: 'ストーリーを読み込めませんでした。' },
  accountCenter: { loadFailed: '個人センターを読み込めませんでした', loadTimeout: 'リクエストがタイムアウトしました。接続を確認して再試行してください。', title: 'マイページ', eyebrow: 'プレイヤープロフィール', runs: 'マイゲーム', videos: '動画コレクション', favorites: 'お気に入り', watchSeason: 'このシーズンを見る', emptyGames: 'まだゲームを開始していません。', emptyVideos: '生成された動画はまだありません。', emptyFavorites: 'お気に入りの動画はありません。', lastPlayed: '最終プレイ · {date}', currentTurn: '進行中 · ターン {turn}', noActiveRun: '進行中のプレイはありません', endingsUnlocked: 'エンディング {unlocked}/{total}', runsPlayed: '累計 {count} 回', continueGame: 'ゲームを続ける', startGame: 'ゲームを始める', viewHistory: '履歴を見る', levelProgress: '{played}/{total} ステージをプレイ', viewSeasonDetails: 'シーズン詳細を見る', hideSeasonDetails: 'シーズン詳細を閉じる', levelInProgress: '進行中', levelCompleted: '完了', endingLabel: '到達したエンディング', cluesLabel: '獲得した手がかり', clueCount: '手がかり {count} 件', viewRunRecords: 'ゲーム記録を見る', runRecordSummary: '手がかり {clues} 件 · エンディング {ending} 件', noEnding: 'まだエンディングに到達していません', noClues: '手がかりはまだありません', seasonDetailsLoadFailed: 'シーズン詳細を読み込めませんでした。再試行してください。', public: '公開', private: '自分のみ', deleteVideo: '動画を削除', confirmDelete: '削除を確認', signInTitle: 'ログインしてください', signInBody: 'ログインするとゲーム進行と動画を管理できます。' },
  visual: {
    eyebrow: 'TRPG Visual',
    chooseScript: 'シナリオ選択',
    actTitle: '第{count}幕 · {title}',
    actLocked: '{title}は未解放です',
    actSealed: '前幕未完',
    toBeContinued: '続く',
    finishPreviousAct: '前幕の結末に到達すると解放',
    revealAfterAct: '第{count}幕を完了すると明らかになります',
    moreScripts: 'その他のステージ',
    comingSoon: '近日公開',
    watchScriptVideo: 'シナリオ映像を見る',
    scenarioKicker: 'シナリオ',
    hiddenTitle: '田又',
    revealedTitle: '画皮',
    objectives: '現在の目標',
    playHistory: 'プレイ記録',
    objectiveLabel: 'ミッション目標',
    close: '閉じる',
    noObjectives: '進行中のタスクはありません。',
    taskProgress: '手順 {done}/{total}',
    entryKicker: 'ゲーム開始',
    entryTitle: '今夜、部屋に入る',
    emptyScenarioEyebrow: 'シナリオ未公開',
    emptyScenarioTitle: 'プレイ可能なシナリオがありません',
    emptyScenarioText: 'サーバーから公開済みシナリオが返りません。更新するか公開状態を確認してください。',
    emptyScenarioActionTitle: '公開待ち',
    emptyScenarioActionText: '実データなしでローカルの仮シナリオは開始しません。',
    continueTitle: '前回の続き',
    entryBody: '先に役を選んで旧屋へ入ります。',
    chooseCharacter: 'キャラクター選択',
    enterStory: '物語へ進む',
    back: '戻る',
    skip: 'スキップ',
    editor: 'エディター',
    debugPage: 'デバッグ',
    state: '状態',
    settings: '設定',
    language: '言語',
    languageUnavailable: 'このレベルには、選択した言語の翻訳がまだありません。',
    turnVideoMatching: 'スマートCGマッチング',
    turnVideoMatchingHint: 'オンにすると類似する場面からこのターンのCGを探します。オフでは完全一致のCGのみ再生します。',
    turnVideoMatchingOn: 'オン',
    turnVideoMatchingOff: 'オフ',
    exitGame: 'ゲームを終了',
    exitGameHint: '現在のプレイを離れ、シナリオ選択へ戻ります。',
    saveAndExit: '保存して終了',
    exitWithoutSaving: '保存せず終了',
    notes: 'ノート',
    saves: 'セーブ',
    continueRun: '続きから',
    balanceEntry: '残高 {credits}',
    endingCollection: 'エンディング図鑑',
    narrator: '語り手',
    npcName: '屋内の女',
    npcLine: '「{line}」',
    notStarted: '未開始',
    startHint: '開始を押して古屋に入る。',
    debug: '数値デバッグ',
    debugOnly: 'デバッグ用',
    waiting: '待機中。',
    modeAct: '行動',
    modeSay: '発言',
    inputMethod: '入力方法',
    textInputMode: 'テキスト',
    voiceInputMode: '音声',
    choiceGroupLabel: '選択肢',
    inputPlaceholder: '例:銅鏡を持ち、彼女と壁の絵に向ける。',
    mobileInputPlaceholder: 'セリフや行動を入力…',
    voiceStart: '音声入力を開始',
    voiceStop: '音声入力を停止',
    voiceListening: '聞き取り中…',
    voiceRecognizing: '認識中…',
    voiceUnsupported: 'このブラウザは音声入力に対応していません',
    voicePermissionDenied: 'マイクを使用できません。ブラウザの権限を確認してください',
    voiceMicrophoneUnavailable: '使用可能なマイクが見つかりません',
    voiceNoSpeech: '音声を認識できませんでした。もう一度お試しください',
    voiceNoAudioCaptured: 'マイクの音声を取得できませんでした。ブラウザの権限を確認してください',
    voiceRecognitionFailed: '音声認識に失敗しました。もう一度お試しください',
    voiceHoldToTalk: '押して話す',
    voicePreparing: 'マイクを準備中…',
    voiceShortcutLabel: 'ショートカット',
    voiceReleaseSend: '離して送信',
    voiceSlideCancel: '上にスライドしてキャンセル',
    voiceReleaseCancel: '離してキャンセル',
    voiceUnderstanding: '指示を理解しています…',
    ending: 'エンディング',
    endingLabel: 'エンディング',
    endingLine: 'エンディング:{title}\n{description}',
    endingSummary: '結末まとめ',
    endingPoem: '定場詩',
    endingFallbackPoem: '……',
    endingBackgroundLoadFailed: 'エンディング画面を読み込めませんでした。再読み込みしてください。',
    recordSeal: '案',
    recordTitle: '捕吏記録',
    recordKicker: '県衙文書',
    recordMeta: '雨夜の後',
    continue: '続ける',
    enterNextEpisode: '次の章へ',
    viewCurrentSeasonStory: '今季のストーリーを見る',
    played: '再生済み',
    nextPage: '次ページ',
    statusCreating: '物語を準備しています...',
    statusStarted: '開始しました。発言か行動を入力してください。',
    statusHistoryRun: '過去の run を表示中です。続きはサーバー進行に従います。',
    statusKp: 'KP が判定中...',
    statusDone: 'ターン完了。',
    contentFiltered: 'この行動は描写できません。別の方法を試してください。',
    turnFailed: 'このステップを完了できませんでした。もう一度お試しください。',
    audioFailed: '音声の再生に失敗しました。もう一度お試しください。',
    actionRejected: 'その行動はまだ成立しません。別の方法を試してください。',
    statusEnded: 'ゲーム終了。',
    statusEndingText: '結末文を生成中...',
    statusEndingLocked: 'エンディングが確定しました。移行中...',
    statusNpcAction: 'NPC が行動を試みています。KP 判定待ち...',
    statusNpcDone: 'NPC が応答しました。',
    clueGained: '手掛かり入手',
    landscapeTitle: '端末を横向きにしてください',
    landscapeBody: 'シーンとCGをすべて表示するため、横向きでプレイしてください。',
    stats: {
      suspicion: '疑念',
      charm: '魅惑',
      fear: '恐怖',
    },
    guide: {
      label: 'ガイド',
      skip: 'スキップ',
      next: '次へ',
      done: '了解',
      optionsTitle: '直接選択',
      optionsText: 'NPC の反応後、下に二つの候補が出ます。「発言」か「行動」を選べます。',
      keyboardTitle: 'キーボード入力に切り替える',
      keyboardText: '初期設定は音声入力です。キーボードボタンを押すと、発言や行動を直接入力できます。',
      inputTitle: '「発言 / 行動」を選ぶ',
      inputText: '入力前に「発言」か「行動」を選びます。どちらも KP が判定します。',
      notesTitle: 'ノート確認',
      notesText: '右側のノートには発見した手掛かりと解放済みエンディングが記録されます。',
      goalTitle: '生き残る',
      goalText: 'これは会話だけではありません。彼女の言葉を聞き、部屋と異常も観察してください。',
      videoTitle: 'ストーリーを完成させると、この冒険があなただけの映像になります',
      videoExampleLabel: 'サンプル動画',
      videoExampleNotice: 'この動画はサンプルであり、あなたのプレイから生成される内容ではありません。',
      videoLoading: 'サンプル動画を読み込み中…',
      videoUnavailable: 'このストーリーにはまだサンプル動画がありません。',
      videoDone: '私のストーリーを始める',
    },
    openingOptions: {
      say: 'すみません、勝手に入るつもりはありませんでした。外に何かがいて追われていました。',
      act: '声を低くして、扉、窓、灯、彼女の位置を確認する。',
    },
  },
  panels: { clues: '手掛かり', conclusions: '結論', info: '情報', inventory: '所持品', events: 'イベント', stats: '能力値', flags: 'フラグ', objects: 'オブジェクト', npcs: 'NPC', endingRecords: '解放済みエンディング' },
  standalone: {
    summary: '概要',
    availableClues: '入手可能な手掛かり',
    recentTurns: '最近のターン',
    audit: {
      title: 'AI 監査',
      subtitle: 'KP、NPC、エンディング、TTS 呼び出しのコストと失敗記録。',
      totalCalls: '呼び出し',
      failedCalls: '失敗',
      tokens: '入力/出力 token',
      cost: 'コスト',
      roles: 'ロール別集計',
      models: 'モデル別集計',
      recentCalls: '最近の呼び出し',
      empty: 'AI 呼び出し記録はありません。',
      calls: '{count} 回',
      tokenPair: 'token {tokens}',
    },
    state: {
      title: '状態可視化',
      waiting: 'RunState の読み込み待ち。',
      noRun: 'runId がありません。ゲーム画面から開くか、runId を入力してください。',
      loading: '{runId} を読み込み中...',
      loaded: '{runId} を読み込みました',
    },
    notes: {
      title: 'ノート',
      waiting: 'ノートを読み込み中。',
      noRun: '現在のセーブがありません。先にゲームを開始または再開してください。',
      loading: '{runId} を読み込み中...',
      loaded: '{runId} を読み込みました',
      unavailable: 'このゲームのノートは現在読み込めません。',
      emptyClues: '手掛かりはまだありません',
      emptyConclusions: '結論はまだありません',
      emptyEndings: 'エンディングはまだありません',
      tabs: 'ノート分類',
      list: '項目リスト',
      detail: '項目詳細',
      locked: '未解放',
      lockedHint: 'このエンディングはまだ記録されていません。',
      recorded: '記録済み',
      importance: { minor: '副次', major: '重要', critical: '核心' },
      relatedClues: '関連する手掛かり',
      noRelatedClues: 'この結論を支える手掛かりはまだ見つかっていません。',
    },
  },
  editor: {
    title: 'シナリオ編集',
    pack: 'パック',
    section: 'セクション',
    raw: 'JSON',
    structured: '構造化編集',
    debugJson: 'デバッグ JSON',
    item: '項目',
    noStructuredFields: 'このセクションには直接編集できる構造化フィールドがまだありません。',
    updated: '保存済み',
    assetUploaded: 'アセットをドラフトに追加済み',
    compiled: 'ドラフトをコンパイル済み',
    published: 'バージョンを公開済み',
    rolledBack: 'バージョンをロールバック済み',
    versions: 'バージョン',
    assets: 'アセット索引',
    current: '現在',
    currentVersion: '現在のバージョン',
    noPublishedVersion: '未公開',
    noVersions: 'まだバージョンがありません。先にドラフトをコンパイルしてください。',
    noAssets: 'まだアセット索引がありません。先にマニフェストをコンパイルしてください。',
    noFilteredAssets: '条件に一致するアセットはありません。',
    assetSearch: '検索',
    assetSearchPlaceholder: 'タグ、ファイル、objectKey',
    assetTypeFilter: '種類',
    assetSourceFilter: 'ソース',
    assetFilterAll: 'すべて',
    assetFilterResult: '{shown}/{total}',
    assetSource: {
      uploaded: 'アップロード済み',
      static: '静的ファイル',
      missing: '参照なし',
    },
    uploadFile: 'ファイル',
    uploadTag: 'タグ',
    uploadTagPlaceholder: 'opening_cg',
    uploadType: '種類',
    noUploadFile: 'ファイル未選択',
  },
  waitingList: {
    eyebrow: '先行アクセス',
    apply: '体験を申し込む',
    useInvite: '招待コードを使う',
    invitedRegister: '招待済みですか?アカウント作成',
    title: 'ゲームサーバーの waiting list に参加',
    body: 'メールと用途を残すと、運営が管理画面から招待リンクを発行します。',
    displayName: '名前',
    displayNamePlaceholder: '任意',
    useCase: '用途',
    useCaseOptional: '用途(任意)',
    useCasePlaceholder: 'チームテスト、作者トライアル、イベント',
    useCaseRequired: '用途を入力してください。',
    consent: 'この waiting list の招待と製品メールを受け取ることに同意します。',
    join: '参加する',
    joined: '申請を受け付けました。メール通知をお待ちください。',
    joinedTitle: '申請済み',
    changeEmail: '別のメールを使う',
    accountAlreadyRegistered: 'このメールアドレスは登録済みです。ログインしてください。',
    emailRequired: 'メールアドレスが必要です。',
    consentRequired: '参加前にメール送信への同意が必要です。',
    inviteEyebrow: '招待',
    inviteTitle: 'voko.world アカウントを作成',
    inviteBody: 'この招待はメールアドレスに紐づいています。パスワードを設定して登録を完了してください。',
    inviteMissing: '招待 token がありません。',
    inviteEnterCode: '受け取った 8 文字の招待コードを入力してアカウントを作成します。',
    inviteValidate: '招待コードを確認',
    inviteReenter: '招待コードを再入力',
    inviteInvalid: '招待が無効または期限切れです。',
    codeSent: '確認コードを送信しました。',
    passwordMismatch: 'パスワードが一致しません。',
    acceptInvite: 'アカウント登録',
  },
  landing: { officialVideo: '公式動画を見る', officialVideoEyebrow: 'VOKO について', officialVideoTitle: 'あなたの世界が呼んでいます。', officialVideoBody: '自分の世界を作り、再びあなたを呼ぶ物語をプレイし、すべての瞬間を見たくなる映像として共有しましょう。', homeLabel: 'voko.world ホーム', navHome: 'Home', navScripts: '物語', navVideos: '動画', featuredStories: '注目の物語', featuredStoriesEyebrow: 'プレイ開始', endingCount: 'エンディング {count} 個', allStories: 'すべての物語', dramaTitle: 'ドラマ', brandSub: 'インタラクティブストーリー', navLabel: 'メインナビ', navStories: 'ゲーム', navGallery: 'ギャラリー', eyebrow: 'AI ビジュアルロールプレイ', loadError: '読み込みに失敗しました。', retry: '再読み込み', emptyGames: '公開中のゲームはありません。', scenarioFallback: '選択でこの物語を変えましょう。', publicVideos: 'プレイヤー動画', publicGames: '公開ゲーム', watchDrama: 'ドラマを見る', enterPlay: 'プレイする', comingSoon: '近日公開', carouselLabel: 'ゲームカルーセル', previousGame: '前のゲーム', nextGame: '次のゲーム', showcaseTitle: 'プレイヤーが作った物語', showcaseBody: '他のプレイヤーの結末を見て、自分の物語を作りましょう。', searchLabel: '物語を検索', searchPlaceholder: 'ゲーム名で検索', sortLabel: '並び順', latest: '最新', popular: '人気', videoCount: '{count} 本の動画', levelCount: '全{count}関', levelNumber: '第{count}関', singleLevel: '単独シナリオ', publicGame: '公開ゲーム', noSearchResults: '一致する物語がありません', clearSearch: '検索をクリア', finalEyebrow: 'あなたの物語が待っています', finalTitle: '誰になりますか?', finalBody: '世界へ足を踏み入れ、最初の一言を。', begin: '旅を始める', footer: '© 2026 voko.world', earlyAccess: '先行アクセス', footerSocial: 'コミュニティ', footerLegal: '規約と連絡先', privacy: 'プライバシーポリシー', terms: '利用規約', contact: '連絡先メール' },
  landingCarousel: { introEyebrow: '生成ドラマゲーム', introSummary: '短いドラマを見て役に入り、選択で物語を変えましょう。', dramaEyebrow: '注目ドラマ {count}', controls: 'ホームカルーセル', goToSlide: 'スライド {count} へ' },
  landingCinema: { navHome: 'ホーム', navDramas: 'ゲーム', navPlayerStories: 'ドラマ', navMy: 'マイ', featuredDramas: 'ゲーム', playerStories: 'ドラマ' },
  searchPage: { placeholder: 'ストーリー、ドラマ、アカウントを検索', popular: '人気の検索', history: '最近の検索', clearHistory: 'クリア', resultTypes: '検索結果の種類', all: 'すべて', accounts: 'アカウント', accountStats: '作品 {titles} 件 · 再生 {plays} 回' },
  landingIntro: { title: 'voko.world', apply: '体験を申し込む', watchVideo: '動画を見る', start: 'ゲームを始める', continue: 'ゲームを続ける', viewJourney: 'プレイ履歴', continueProgress: 'シーズン {season}  {scenario}', storyLine: 'ストーリーライン', viewMore: 'さらに見る' },
  storyTree: {
    eyebrow: 'シーズンライン',
    subtitle: '1本のラインが1シーズン、各ノードが1ステージを表します。',
    root: 'ドラマ',
    branch: '分岐',
    active: '進行中',
    completed: '完了',
    locked: '未到達',
    empty: '表示できるシーズンラインはまだありません。',
    loadError: 'シーズンラインを読み込めませんでした。',
    navigation: 'シーズン範囲',
    range: 'シーズン {first}–{last} · 全 {total}',
    newer: '前のグループ',
    older: '次のグループ',
    startPlaying: 'プレイ開始',
    turnProgress: '第 {turn} ターン',
    continuePlaying: 'プレイを続ける',
    playLog: 'プレイ記録',
    seasonEnding: 'シーズンの結末',
    currentSeason: '現在のシーズン',
    logLoadError: 'プレイ記録を読み込めません。',
    logEmpty: 'このシーズンにはまだプレイ履歴がありません。',
    turnNumber: '第 {turn} ターン',
    playerSaid: 'あなたの発言',
    playerDid: 'あなたの行動',
    storyOpening: '物語の始まり',
    turnVideos: '一致した動画',
    playActionVideo: 'アクション動画',
    playPlayerVideo: 'プレイヤー動画',
    playNpcVideo: 'NPC 動画',
    replayTurn: 'リプレイ',
    replayTurnTitle: '第 {turn} ターンの再生',
    replayProgress: '{current}/{total} クリップ',
    actionSegment: 'アクション',
    playerSpeechSegment: 'プレイヤー発言',
    npcSpeechSegment: 'NPC 発言',
    pauseReplay: '一時停止',
    continueReplay: '続ける',
    restartReplay: '最初から再生',
    exportReplay: '全編を書き出す',
    replayQueued: '待機中',
    replayExporting: '書き出し中',
    playFullReplay: '全編を再生',
    retryReplayExport: '再書き出し',
    downloadReplay: 'MP4 をダウンロード',
    downloadSegment: 'このクリップをダウンロード',
    downloadTurn: 'このターン全体をダウンロード',
    turnExporting: 'ターン動画を書き出し中',
    turnExportError: 'ターン動画の書き出しに失敗しました。',
    segmentExporting: 'クリップを書き出し中',
    segmentExportError: 'クリップの書き出しに失敗しました。',
    fullReplayTitle: '{title} · 全編再生',
    replayExportError: '全編の書き出しに失敗しました。',
    videoLoadError: '動画を読み込めませんでした。',
    tools: 'ストーリーラインの検索・絞り込み・並べ替え',
    search: '検索',
    searchPlaceholder: 'ステージ、結末、最近の行動を検索',
    filter: '状態',
    filterAll: 'すべて',
    filterInProgress: '進行中',
    filterCompleted: '完了',
    sort: '並べ替え',
    sortRecent: '最近プレイした順',
    sortSeasonDesc: 'シーズン降順',
    sortSeasonAsc: 'シーズン昇順',
    resultCount: '全 {count} シーズン',
    noResults: '条件に一致するストーリーラインはありません。',
    canvasHint: 'キャンバスをドラッグまたはスクロールして右側のステージを表示',
    canvasLabel: '横方向に移動できるストーリーツリーキャンバス',
    storySwitch: '作品',
  },
  storyTreeCurrentSeasonHint: '最新の進行',
  storyTreeViewDetails: 'シーズン {number} の詳細を見る',
  storyTreeDelete: { action: '分岐を削除', confirm: 'シーズン {number} とそこから派生した分岐を削除しますか?この操作は取り消せません。', deleting: '削除中…', error: '分岐を削除できませんでした。' },
  storyTreeVideoUnavailable: '映像はありません',
  storyTreeFork: { action: 'ここからやり直す', confirm: '第 {turn} ターンから新しいストーリー分岐を作成します。現在のプレイ記録は変更されません。', failed: '新しいストーリー分岐を作成できませんでした。', creating: '作成中…' },
  runVideoGeneration: { title: 'フル動画を生成', description: 'このプレイからフル動画を生成します。確定後にポイントを消費し、生成失敗時は自動返還されます。', generate: '動画を生成', regenerate: '再生成', retry: 'もう一度生成', queued: '生成待ち', running: '生成中', price: '必要ポイント', balance: '現在の残高', balanceAfter: '消費後の残高' },
  landingShowcase: { title: 'それぞれの物語', body: 'ほかのプレイヤーが辿った運命を見届け、物語に入り、あなただけの結末を描きましょう。' },
  landingMetrics: { playCount: '再生数', likeCount: 'いいね数' },
  landingCard: { level: 'エピソード', searchPlaceholder: '物語・動画・プレイヤーを探す', scriptFilter: 'ドラマ', scriptAll: 'すべてのドラマ', playerVideoCount: '公開動画 {count} 本', publishedAt: '公開日', publishedAll: 'すべて', publishedToday: '今日', publishedWeek: '過去 7 日', publishedMonth: '過去 30 日', expandSynopsis: '展開', collapseSynopsis: '閉じる' },
  playerPage: { loadError: 'プレイヤーの動画を読み込めませんでした。', notFound: 'プレイヤーが見つからないか、公開動画がありません。', searchPlaceholder: '作品・ステージ・シーズン名を検索' },
  season: { choose: 'シーズンを選択', chooseBody: 'このエピソードは選択したシーズンの物語に続きます。', number: 'シーズン {number}', empty: '続けるには、いずれかのシーズンで前のエピソードを完了してください。' },
  status: { loading: '読み込み中', empty: 'データなし', error: '読み込み失敗', streaming: '進行中' },
  storiesPage: { tags: 'ストーリータグ', allTags: 'すべて', swipeForNextStory: '上にスワイプして次の物語へ' },
  creator: { nav: '制作', queued: '処理待ち', attachmentTypeError: 'TXT、PDF、Word、PNG、JPG、WEBP のいずれか1ファイルを選択してください。', attachmentSizeError: '添付ファイルは10 MB以下にしてください。', attachmentReadError: '添付ファイルを読み取れませんでした。', generationFailed: '生成失敗', reviewRejected: '審査否認', published: '公開済み', archived: 'アーカイブ', composerTitle: '今日はどんな世界をつくりますか?', submitIdea: 'アイデアを送信', examplesNote: '公開済みゲームをレイアウト例として表示しています。', exampleStatus: '公開例', projectsEyebrow: 'Visual Game Creator', projectsTitle: 'マイゲーム', projectsBody: '制作したゲームと生成・審査状況を管理します。', newGame: '新しいゲームを作成', draftStatus: '下書き', continueEditing: '編集を続ける', generatedScopes: '件の生成内容', emptyTitle: '最初のゲームを作成', emptyBody: 'アイデアや脚本、世界観から遊べるゲームを作りましょう。', eyebrow: 'Visual Game Creator', title: '物語を、遊べる世界へ', subtitle: 'アイデアや脚本、世界観を共有してください。ゲーム設計、素材制作、検証、審査申請まで自動で進みます。', stepIdea: 'アイデア', stepGenerate: '生成', stepReview: '審査', ideaTitle: 'ゲームを説明する', ideaBody: '自然な言葉で入力できます。JSONの知識は不要です。', ideaLabel: 'アイデアまたは脚本', ideaHint: '世界、人物、対立、望む体験を含めてください。', ideaPlaceholder: '旅人が嵐の夜に宿で目覚めると、全員が昨夜を違って記憶していた……', ideaError: '20文字以上入力してください。', languageLabel: 'ゲーム言語', languages: { zh: '中国語', en: '英語', ja: '日本語', ko: '韓国語' }, scopeTitle: '生成する内容', scopeStory: '物語とレベル', scopeStoryBody: '人物、任務、状態、結末', scopeVisuals: 'ビジュアル', scopeVisualsBody: '人物、背景、小道具、動画', scopeVoice: '音声', scopeVoiceBody: 'プレイヤー、NPC、結末', scopeError: '1つ以上選択してください。', assetsTitle: '参考素材', assetsBody: '任意。人物や世界の一貫性を高めます。', uploadAction: '参考ファイルを追加', uploadHint: '1ファイル · TXT、PDF、Word、PNG、JPG、WEBP · 最大10 MB', supportedTitle: '対応素材', supportedBody: '人物・背景・小道具・画風画像、脚本、文書、動画、音声。', removeFile: '{name} を削除', saved: '下書きを保存しました。', draftNote: '初版はローカル下書き保存に対応します。', save: '下書きを保存' },
  labels: { scenario: 'シナリオ', asset: '素材', mode: 'モード', phase: 'フェーズ', location: '場所', noRun: '未開始', none: 'なし' },
}