diff --git a/CHANGELOG.md b/CHANGELOG.md
index 776fb43d..aac28243 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -50,6 +50,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* **Idle auto-pull** when paused/stopped for 30+ seconds on a single-server queue (active = playback): polls every 10s and applies server changes.
* **Push** now sends only tracks owned by the playback server (fixes mixed-server queues). Switching browse servers flushes the old server's queue slice without auto-pull.
+### Japanese translation
+
+**By [@Soli0222](https://github.com/Soli0222), PR [#1134](https://github.com/Psychotoxical/psysonic/pull/1134)**
+
+* Full Japanese (日本語) UI translation — selectable from the language picker on the Settings and Login screens.
+
## Changed
diff --git a/README.md b/README.md
index cde4cfcd..22399c70 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ Psysonic is built primarily for **Navidrome** and also works with **Gonic**, **A
-**Available languages:** English, German, Spanish, French, Norwegian Bokmål, Dutch, Romanian, Russian and Chinese.
+**Available languages:** English, German, Spanish, French, Norwegian Bokmål, Dutch, Romanian, Russian, Chinese and Japanese.
More translations are added over time.
diff --git a/WHATS_NEW.md b/WHATS_NEW.md
index 3d87cbac..24d1e0d1 100644
--- a/WHATS_NEW.md
+++ b/WHATS_NEW.md
@@ -30,6 +30,10 @@ Within each section, order by **user impact** (most noticeable first) — not PR
- Settings are grouped into clear, labelled panels so related options sit together — less hunting around. The **Native Hi-Res Playback** option now explains in plain language what it actually does.
- **Normalization** and **Track transitions** are now their own sections under **Settings → Audio**, and the queue options (display mode, toolbar, and Play-Next order) are gathered into one **Queue Settings** group under **Personalisation**.
+### Japanese — now in your language
+
+- Psysonic is now available in **Japanese (日本語)** — pick it from the language menu on the **Settings** and **Login** screens.
+
## Fixed
### Playback and audio
diff --git a/src/components/settings/SystemTab.tsx b/src/components/settings/SystemTab.tsx
index fa5afc22..bee9ca5f 100644
--- a/src/components/settings/SystemTab.tsx
+++ b/src/components/settings/SystemTab.tsx
@@ -72,6 +72,7 @@ export function SystemTab() {
{ value: 'ru', label: t('settings.languageRu') },
{ value: 'zh', label: t('settings.languageZh') },
{ value: 'ro', label: t('settings.languageRo') },
+ { value: 'ja', label: t('settings.languageJa') },
]}
/>
diff --git a/src/config/settingsCredits.ts b/src/config/settingsCredits.ts
index 8b213065..e483fc6b 100644
--- a/src/config/settingsCredits.ts
+++ b/src/config/settingsCredits.ts
@@ -393,6 +393,13 @@ const CONTRIBUTOR_ENTRIES = [
'Linux auto-install script — fix curl | sudo bash URL capture bug (PR #1079)',
],
},
+ {
+ github: 'Soli0222',
+ since: '1.49.0',
+ contributions: [
+ 'Japanese (ja) full UI translation (PR #1134)',
+ ],
+ },
] as const;
// PR number of a contributor's first listed contribution, used as the
diff --git a/src/i18n.ts b/src/i18n.ts
index cf190d83..9f6981cc 100644
--- a/src/i18n.ts
+++ b/src/i18n.ts
@@ -9,6 +9,7 @@ import { ruTranslation } from './locales/ru';
import { nlTranslation } from './locales/nl';
import { esTranslation } from './locales/es';
import { roTranslation } from './locales/ro';
+import { jaTranslation } from './locales/ja';
const savedLanguage = localStorage.getItem('psysonic_language') || 'en';
@@ -25,6 +26,7 @@ i18n
nb: { translation: nbTranslation },
ru: { translation: ruTranslation },
ro: { translation: roTranslation },
+ ja: { translation: jaTranslation },
},
lng: savedLanguage,
fallbackLng: 'en',
diff --git a/src/locales/de/settings.ts b/src/locales/de/settings.ts
index e21261fd..a805ef45 100644
--- a/src/locales/de/settings.ts
+++ b/src/locales/de/settings.ts
@@ -10,6 +10,7 @@ export const settings = {
languageRu: 'Русский',
languageZh: '中文',
languageRo: 'Română',
+ languageJa: '日本語',
font: 'Schriftart',
fontHintOpenDyslexic: 'Legasthenie-freundlich · keine Chinesisch-Unterstützung',
theme: 'Design',
diff --git a/src/locales/en/settings.ts b/src/locales/en/settings.ts
index 3db3f6de..b7c4fce4 100644
--- a/src/locales/en/settings.ts
+++ b/src/locales/en/settings.ts
@@ -10,6 +10,7 @@ export const settings = {
languageRu: 'Русский',
languageZh: '中文',
languageRo: 'Română',
+ languageJa: '日本語',
font: 'Font',
fontHintOpenDyslexic: 'Dyslexia-friendly · no Chinese support',
theme: 'Theme',
diff --git a/src/locales/es/settings.ts b/src/locales/es/settings.ts
index 842c33d7..0618e31e 100644
--- a/src/locales/es/settings.ts
+++ b/src/locales/es/settings.ts
@@ -10,6 +10,7 @@ export const settings = {
languageRu: 'Русский',
languageZh: '中文',
languageRo: 'Română',
+ languageJa: '日本語',
font: 'Fuente',
fontHintOpenDyslexic: 'Compatible con dislexia · sin soporte para chino',
theme: 'Tema',
diff --git a/src/locales/fr/settings.ts b/src/locales/fr/settings.ts
index 3732b68e..19708c5d 100644
--- a/src/locales/fr/settings.ts
+++ b/src/locales/fr/settings.ts
@@ -10,6 +10,7 @@ export const settings = {
languageRu: 'Русский',
languageZh: '中文',
languageRo: 'Română',
+ languageJa: '日本語',
font: 'Police',
fontHintOpenDyslexic: 'Adapté à la dyslexie · sans prise en charge du chinois',
theme: 'Thème',
diff --git a/src/locales/ja/albumDetail.ts b/src/locales/ja/albumDetail.ts
new file mode 100644
index 00000000..0e33ecfe
--- /dev/null
+++ b/src/locales/ja/albumDetail.ts
@@ -0,0 +1,55 @@
+export const albumDetail = {
+ back: '戻る',
+ orbitDoubleClickHint: 'ダブルクリックでこのトラックを Orbit キューに追加',
+ playAll: 'すべて再生',
+ shareAlbum: 'アルバムを共有',
+ enqueue: 'キューに追加',
+ enqueueTooltip: 'アルバム全体をキューに追加',
+ artistBio: 'アーティスト紹介',
+ download: 'ダウンロード (ZIP)',
+ playTooltip: 'このアルバムを再生',
+ artistBioTooltip: 'アーティストの紹介を読む',
+ downloadTooltip: 'このアルバムを ZIP としてダウンロード',
+ downloading: '読み込み中…',
+ cacheOffline: 'オフラインで利用可能にする',
+ offlineCached: 'オフラインで利用可能',
+ offlineQueued: 'キュー内',
+ offlineDownloading: 'キャッシュ中… ({{n}}/{{total}})',
+ removeOffline: 'オフラインキャッシュを削除',
+ removeFromOfflineQueue: 'オフラインキューから削除',
+ offlineStorageFull: 'オフラインストレージがいっぱいです (上限: {{mb}} MB)。オフラインライブラリからアルバムを削除するか、設定で上限を増やしてください。',
+ offlineStorageGoToLibrary: 'オフラインライブラリ',
+ offlineStorageGoToSettings: '設定',
+ favoriteAdd: 'お気に入りに追加',
+ favoriteRemove: 'お気に入りから削除',
+ favorite: 'お気に入り',
+ noBio: '紹介文はありません。',
+ moreByArtist: '{{artist}} の他の作品',
+ tracksCount: '{{n}} 曲',
+ goToArtist: '{{artist}} へ移動',
+ moreLabelAlbums: '{{label}} の他のアルバム',
+ trackTitle: 'タイトル',
+ trackAlbum: 'アルバム',
+ trackArtist: 'アーティスト',
+ trackGenre: 'ジャンル',
+ trackPlayCount: '再生数',
+ trackLastPlayed: '最終再生',
+ trackBpm: 'BPM',
+ trackFormat: '形式',
+ trackFavorite: 'お気に入り',
+ trackRating: '評価',
+ trackDuration: '長さ',
+ trackTotal: '合計',
+ columns: '列',
+ resetColumns: '既定に戻す',
+ notFound: 'アルバムが見つかりません。',
+ bioModal: 'アーティスト紹介',
+ bioClose: '閉じる',
+ ratingLabel: '評価',
+ enlargeCover: '拡大',
+ filterSongs: '曲を絞り込み…',
+ sortNatural: '自然順',
+ sortByTitle: 'A-Z (タイトル)',
+ sortByArtist: 'A-Z (アーティスト)',
+ sortByAlbum: 'A-Z (アルバム)',
+};
diff --git a/src/locales/ja/albums.ts b/src/locales/ja/albums.ts
new file mode 100644
index 00000000..7f3b9b49
--- /dev/null
+++ b/src/locales/ja/albums.ts
@@ -0,0 +1,41 @@
+export const albums = {
+ title: 'すべてのアルバム',
+ sortByName: 'A-Z (アルバム)',
+ sortByArtist: 'A-Z (アーティスト)',
+ sortByArtistYear: 'アーティスト → 年',
+ sortNewest: '新しい順',
+ sortRandom: 'ランダム',
+ yearFrom: '開始',
+ yearTo: '終了',
+ yearFilterClear: '年の絞り込みを解除',
+ yearFilterLabel: '年',
+ sortTooltip: '並び順を変更',
+ yearFilterTooltip: 'リリース年で絞り込み',
+ compilationLabel: 'コンピレーション',
+ compilationOnly: 'コンピレーションのみ',
+ compilationHide: 'コンピレーションを非表示',
+ compilationTooltipAll: 'すべてのアルバム · クリック: コンピレーションのみ',
+ compilationTooltipOnly: 'コンピレーションのみ · クリック: コンピレーションを非表示',
+ compilationTooltipHide: 'コンピレーション非表示 · クリック: すべて表示',
+ losslessLabel: 'ロスレス',
+ losslessTooltipOn: 'ロスレスアルバムのみ · クリックですべて表示',
+ losslessTooltipOff: 'ロスレスアルバムのみ表示',
+ select: '複数選択',
+ startSelect: '複数選択を有効化',
+ cancelSelect: 'キャンセル',
+ selectionCount: '{{count}} 件選択中',
+ downloadZips: 'ZIP をダウンロード',
+ addOffline: 'オフラインに追加',
+ enqueueSelected_one: 'キューに追加 ({{count}})',
+ enqueueSelected_other: 'キューに追加 ({{count}})',
+ enqueueQueued_one: '{{count}} 枚のアルバムをキューに追加しました',
+ enqueueQueued_other: '{{count}} 枚のアルバムをキューに追加しました',
+ downloadingZip: '{{current}}/{{total}} をダウンロード中: {{name}}',
+ downloadZipDone: '{{count}} 個の ZIP をダウンロードしました',
+ downloadZipFailed: '{{name}} のダウンロードに失敗しました',
+ offlineQueuing: '{{count}} 枚のアルバムをオフライン用にキューへ追加中…',
+ offlineFailed: '{{name}} をオフラインに追加できませんでした',
+ noFavorites: '現在のフィルターに一致するお気に入りアルバムはありません。',
+ noCompilations: '現在のフィルターに一致するコンピレーションはありません。',
+ noMatchingFilters: '現在のフィルターに一致するアルバムはありません。',
+};
diff --git a/src/locales/ja/artistDetail.ts b/src/locales/ja/artistDetail.ts
new file mode 100644
index 00000000..25d227b2
--- /dev/null
+++ b/src/locales/ja/artistDetail.ts
@@ -0,0 +1,52 @@
+export const artistDetail = {
+ back: '戻る',
+ albums: 'アルバム',
+ album: 'アルバム',
+ playAll: 'すべて再生',
+ shareArtist: 'アーティストを共有',
+ shuffle: 'シャッフル',
+ radio: 'ラジオ',
+ lastfmTooltip: 'このアーティストを Last.fm で開く',
+ wikipediaTooltip: 'このアーティストを Wikipedia で開く',
+ playAllTooltip: 'ディスコグラフィ全体を再生',
+ shuffleTooltip: 'ディスコグラフィ全体をシャッフル',
+ radioTooltip: 'このアーティストをもとにラジオを開始',
+ loading: '読み込み中…',
+ noRadio: 'このアーティストの類似トラックは見つかりませんでした。',
+ notFound: 'アーティストが見つかりません。',
+ albumsBy: '{{name}} のアルバム',
+ albumsByLossless: '{{name}} のロスレスアルバム',
+ sortYearToggleAria: 'リリース種別ごとのアルバム年順を切り替え',
+ sortYearDesc: '年、新しい順',
+ sortYearAsc: '年、古い順',
+ topTracks: '人気トラック',
+ topTracksLossless: 'ロスレストラック',
+ noAlbums: 'アルバムが見つかりません。',
+ trackTitle: 'タイトル',
+ trackAlbum: 'アルバム',
+ trackDuration: '長さ',
+ favoriteAdd: 'お気に入りに追加',
+ favoriteRemove: 'お気に入りから削除',
+ favorite: 'お気に入り',
+ albumCount_one: '{{count}} 枚のアルバム',
+ albumCount_other: '{{count}} 枚のアルバム',
+ openedInBrowser: 'ブラウザーで開きました',
+ featuredOn: '参加作品',
+ similarArtists: '類似アーティスト',
+ cacheOffline: 'ディスコグラフィをオフライン保存',
+ offlineCached: 'ディスコグラフィをキャッシュ済み',
+ offlineQueued: 'キュー内',
+ offlineDownloading: 'キャッシュ中… ({{done}}/{{total}} アルバム)',
+ uploadImage: 'アーティスト画像をアップロード',
+ uploadImageError: '画像のアップロードに失敗しました',
+ releaseTypes: {
+ album: 'アルバム',
+ ep: 'EP',
+ single: 'シングル',
+ compilation: 'コンピレーション',
+ live: 'ライブ',
+ soundtrack: 'サウンドトラック',
+ remix: 'リミックス',
+ other: 'その他',
+ },
+};
diff --git a/src/locales/ja/artists.ts b/src/locales/ja/artists.ts
new file mode 100644
index 00000000..be45f7d8
--- /dev/null
+++ b/src/locales/ja/artists.ts
@@ -0,0 +1,19 @@
+export const artists = {
+ title: 'アーティスト',
+ search: '検索…',
+ all: 'すべて',
+ other: 'その他',
+ gridView: 'グリッド表示',
+ listView: 'リスト表示',
+ imagesOn: 'アーティスト画像オン: ネットワークとシステム負荷が増える場合があります',
+ imagesOff: 'アーティスト画像オフ: イニシャルのみ表示',
+ loadMore: 'さらに読み込む',
+ notFound: 'アーティストが見つかりません。',
+ albumCount_one: '{{count}} 枚のアルバム',
+ albumCount_other: '{{count}} 枚のアルバム',
+ selectionCount: '{{count}} 件選択中',
+ select: '複数選択',
+ startSelect: '複数選択を有効化',
+ cancelSelect: 'キャンセル',
+ addToPlaylist: 'プレイリストに追加',
+};
diff --git a/src/locales/ja/changelog.ts b/src/locales/ja/changelog.ts
new file mode 100644
index 00000000..73cf5ab1
--- /dev/null
+++ b/src/locales/ja/changelog.ts
@@ -0,0 +1,5 @@
+export const changelog = {
+ modalTitle: '新機能',
+ dontShowAgain: '今後表示しない',
+ close: '了解',
+};
diff --git a/src/locales/ja/common.ts b/src/locales/ja/common.ts
new file mode 100644
index 00000000..c5e76d15
--- /dev/null
+++ b/src/locales/ja/common.ts
@@ -0,0 +1,70 @@
+export const common = {
+ albums: 'アルバム',
+ album: 'アルバム',
+ loading: '読み込み中…',
+ loadingMore: '読み込み中…',
+ loadingPlaylists: 'プレイリストを読み込み中…',
+ noAlbums: 'アルバムが見つかりません。',
+ downloading: 'ダウンロード中…',
+ downloadZip: 'ダウンロード (ZIP)',
+ back: '戻る',
+ backToTop: '先頭へ戻る',
+ cancel: 'キャンセル',
+ close: '閉じる',
+ save: '保存',
+ delete: '削除',
+ use: '使用',
+ add: '追加',
+ new: '新規',
+ active: '有効',
+ download: 'ダウンロード',
+ chooseDownloadFolder: 'ダウンロードフォルダーを選択',
+ noFolderSelected: 'フォルダーが選択されていません',
+ rememberDownloadFolder: 'このフォルダーを記憶',
+ filterGenre: 'ジャンルフィルター',
+ filterGenreTooltip: 'ジャンルで絞り込み',
+ filterSearchGenres: 'ジャンルを検索…',
+ filterNoGenres: '一致するジャンルはありません',
+ filterClear: 'クリア',
+ favorites: 'お気に入り',
+ favoritesTooltipOff: 'お気に入りのみ表示',
+ favoritesTooltipOn: 'すべて表示',
+ play: '再生',
+ addToQueue: 'キューに追加',
+ bulkSelected: '{{count}} 件選択中',
+ clearSelection: '選択を解除',
+ bulkAddToPlaylist: 'プレイリストに追加',
+ bulkRemoveFromPlaylist: 'プレイリストから削除',
+ bulkClear: '選択を解除',
+ updaterAvailable: 'アップデートがあります',
+ updaterVersion: 'v{{version}} が利用可能です',
+ updaterWebsite: 'Web サイト',
+ updaterModalTitle: '新しいバージョンがあります',
+ updaterChangelog: '新機能',
+ updaterDownloadBtn: '今すぐダウンロード',
+ updaterSkipBtn: 'このバージョンをスキップ',
+ updaterRemindBtn: '後で通知',
+ updaterDone: 'ダウンロード完了',
+ updaterShowFolder: 'フォルダーに表示',
+ updaterInstallHint: 'Psysonic を閉じて、インストーラーを手動で実行してください。',
+ updaterAurHint: 'AUR からアップデートをインストール:',
+ updaterErrorMsg: 'ダウンロードに失敗しました',
+ updaterRetryBtn: '再試行',
+ updaterInstallNow: '今すぐインストール',
+ updaterMacReadyTitle: 'インストール準備完了',
+ updaterMacReady: 'アップデートはダウンロード、検証、適用までその場で行われます。DMG は不要です。完了後にアプリが自動で再起動します。',
+ updaterTrustNotarized: 'Apple による公証済み',
+ updaterTrustSignature: '署名を検証済み',
+ updaterMacDoneTitle: 'アップデートをインストールしました',
+ updaterRestartingIn: '{{n}} 秒後に再起動…',
+ updaterRestarting: '再起動中…',
+ updaterRestartNow: '今すぐ再起動',
+ durationHoursMinutes: '{{hours}} 時間 {{minutes}} 分',
+ durationMinutesOnly: '{{minutes}} 分',
+ updaterOpenGitHub: 'GitHub で開く',
+ filters: 'フィルター',
+ more: 'さらに',
+ yearRange: '年の範囲',
+ clearAll: 'すべてクリア',
+ libraryEmpty: 'ライブラリは空です。',
+};
diff --git a/src/locales/ja/composerDetail.ts b/src/locales/ja/composerDetail.ts
new file mode 100644
index 00000000..bfd54109
--- /dev/null
+++ b/src/locales/ja/composerDetail.ts
@@ -0,0 +1,11 @@
+export const composerDetail = {
+ back: '戻る',
+ notFound: '作曲者が見つかりません。',
+ about: 'この作曲者について',
+ works: '作品',
+ noWorks: '作品が見つかりません。',
+ workCount_one: '{{count}} 作品',
+ workCount_other: '{{count}} 作品',
+ shareComposer: '作曲者を共有',
+ unknownComposer: '作曲者',
+};
diff --git a/src/locales/ja/composers.ts b/src/locales/ja/composers.ts
new file mode 100644
index 00000000..60190cec
--- /dev/null
+++ b/src/locales/ja/composers.ts
@@ -0,0 +1,10 @@
+export const composers = {
+ title: '作曲者',
+ search: '検索…',
+ notFound: '作曲者が見つかりません。',
+ unsupported: '作曲者でのブラウズには Navidrome 0.55 以降が必要です。',
+ loadFailed: '作曲者を読み込めませんでした。',
+ retry: '再試行',
+ involvedIn_one: '{{count}} 枚のアルバムに関与',
+ involvedIn_other: '{{count}} 枚のアルバムに関与',
+};
diff --git a/src/locales/ja/connection.ts b/src/locales/ja/connection.ts
new file mode 100644
index 00000000..70afc442
--- /dev/null
+++ b/src/locales/ja/connection.ts
@@ -0,0 +1,46 @@
+export const connection = {
+ connected: '接続済み',
+ connectedTo: '{{server}} に接続済み',
+ disconnected: '未接続',
+ disconnectedFrom: '{{server}} に到達できません。クリックして設定を確認',
+ checking: '接続中…',
+ extern: '外部',
+ offlineTitle: 'サーバー接続なし',
+ offlineSubtitle: '{{server}} に到達できません。ネットワークまたはサーバーを確認してください。',
+ offlineModeBanner: 'オフラインモード: ローカルキャッシュから再生中',
+ offlineNoCacheBanner: 'サーバー接続なし: {{server}} に到達できません',
+ offlineLibraryTitle: 'オフラインライブラリ',
+ offlineLibraryDiskLabel: 'ディスク上',
+ offlineLibraryDiskUsage: 'ディスク上: {{size}}',
+ offlineLibraryDiskUsageLoading: 'ディスク上: …',
+ offlineLibraryDiskTierLibrary: 'オフラインライブラリ (media/library): {{size}}',
+ offlineLibraryDiskTierFavorites: 'お気に入り (media/favorites): {{size}}',
+ offlineLibraryEmpty: 'まだキャッシュ済みアルバムはありません。オンラインにしてアルバムを開き、「オフラインで利用可能にする」をクリックしてください。',
+ offlinePlaybackUnavailable: 'このアルバムのローカルファイルが見つからないか、インデックスされていません。',
+ offlineCachedOnServer: '{{server}} 上',
+ offlineAlbumCount: '{{n}} 枚のアルバム',
+ offlineAlbumCount_plural: '{{n}} 枚のアルバム',
+ offlineFilterAll: 'すべて',
+ offlineFilterAlbums: 'アルバム',
+ offlineFilterPlaylists: 'プレイリスト',
+ offlineFilterArtists: 'ディスコグラフィ',
+ offlineCacheQueueTitle: 'キューキャッシュ',
+ offlineCacheQueueSubtitle: 'media/cache に {{n}} 曲。シャッフルして再生',
+ offlineCacheQueuePlayAria: 'キャッシュ済みトラックをすべてシャッフル再生',
+ offlineFavoritesQueueTitle: 'お気に入り',
+ offlineFavoritesQueuePlayAria: 'オフライン保存済みのお気に入りをすべてシャッフル再生',
+ retry: '再試行',
+ serverSettings: 'サーバー設定',
+ switchServerTitle: 'サーバーを切り替え',
+ switchServerHint: 'クリックして別の保存済みサーバーを選択します。',
+ manageServers: 'サーバーを管理…',
+ switchFailed: '切り替えできませんでした。サーバーに到達できません。',
+ queueSynced: 'キューはサーバーと同期済みです',
+ queuePullHint: 'クリックして {{server}} から再生キューを取得',
+ queueLocalEditHint: '再生キューがローカルで変更されました。自動同期を一時停止中です。クリックしてサーバーから取得します。',
+ queuePulling: '再生キューを取得中…',
+ queuePullSuccess: 'サーバーから再生キューを更新しました',
+ queuePullEmpty: 'サーバーの再生キューは空です',
+ queuePullFailed: 'サーバーから再生キューを取得できませんでした',
+ queuePullAria: 'サーバーから再生キューを同期',
+};
diff --git a/src/locales/ja/contextMenu.ts b/src/locales/ja/contextMenu.ts
new file mode 100644
index 00000000..91872cdf
--- /dev/null
+++ b/src/locales/ja/contextMenu.ts
@@ -0,0 +1,33 @@
+export const contextMenu = {
+ playNow: '今すぐ再生',
+ playNext: '次に再生',
+ addToQueue: 'キューに追加',
+ enqueueAlbum: 'アルバムをキューに追加',
+ enqueueAlbums_one: '{{count}} 枚のアルバムをキューに追加',
+ enqueueAlbums_other: '{{count}} 枚のアルバムをキューに追加',
+ startRadio: 'ラジオを開始',
+ instantMix: 'インスタントミックス',
+ instantMixFailed: 'インスタントミックスを作成できませんでした。サーバーまたはプラグインのエラーです。',
+ cliMixNeedsTrack: '何も再生されていません。先に再生を開始してから、もう一度ミックスコマンドを実行してください。',
+ networkLove: '{{provider}} で Love',
+ networkUnlove: '{{provider}} の Love を解除',
+ favorite: 'お気に入り',
+ favoriteArtist: 'アーティストをお気に入り',
+ favoriteAlbum: 'アルバムをお気に入り',
+ unfavorite: 'お気に入りから削除',
+ unfavoriteArtist: 'アーティストをお気に入りから削除',
+ unfavoriteAlbum: 'アルバムをお気に入りから削除',
+ removeFromQueue: 'キューから削除',
+ removeFromPlaylist: 'プレイリストから削除',
+ openAlbum: 'アルバムを開く',
+ goToArtist: 'アーティストへ移動',
+ download: 'ダウンロード (ZIP)',
+ addToPlaylist: 'プレイリストに追加',
+ selectedPlaylists: '{{count}} 個のプレイリストを選択中',
+ selectedAlbums: '{{count}} 枚のアルバムを選択中',
+ selectedArtists: '{{count}} 人のアーティストを選択中',
+ songInfo: '曲情報',
+ shareLink: '共有リンクをコピー',
+ shareCopied: '共有リンクをクリップボードにコピーしました。',
+ shareCopyFailed: 'クリップボードにコピーできませんでした。',
+};
diff --git a/src/locales/ja/deviceSync.ts b/src/locales/ja/deviceSync.ts
new file mode 100644
index 00000000..04c3f28e
--- /dev/null
+++ b/src/locales/ja/deviceSync.ts
@@ -0,0 +1,80 @@
+export const deviceSync = {
+ title: 'デバイス同期',
+ targetFolder: '同期先フォルダー',
+ noFolderChosen: 'フォルダーが選択されていません',
+ selectDrive: 'ドライブを選択…',
+ refreshDrives: 'ドライブを更新',
+ noDrivesDetected: 'リムーバブルドライブが検出されません',
+ browseManual: '手動で参照…',
+ free: '空き',
+ notMountedVolume: '同期先がマウント済みボリューム上にありません。ドライブが取り外された可能性があります。',
+ chooseFolder: '選択…',
+ targetDevice: '対象デバイス',
+ schemaLabel: '命名方式',
+ schemaHint: 'OS 間で安定して同期するための固定方式です。プレイリストはアルバムトラックを参照する .m3u8 として書き込まれ、デバイス上で重複しません。',
+ migrateButton: '既存ファイルを再整理…',
+ migrateTooltip: 'デバイス上の既存ファイルを、新しい方式へリネームします (旧ファイル名テンプレートから)。',
+ migrateTitle: '既存ファイルを再整理',
+ migrateLoading: '既存ファイルを解析中…',
+ migrateNothingToDo: '既存ファイルはすべて新しい方式に一致しています。作業はありません。',
+ migrateNoTemplate: 'デバイス上に旧ファイル名テンプレートが見つかりません。移行は、カスタムテンプレート対応版の Psysonic で同期したスティックにのみ適用されます。',
+ migrateFilesToRename: 'ファイルをリネーム予定',
+ migrateUnchanged: '{{n}} ファイルはすでに正しいパスです',
+ migrateCollisions: '{{n}} ファイルは自動でリネームできません (複数トラックが同じ同期先になります)。そのまま残し、次回同期で正しい場所へ再ダウンロードします。',
+ migratePreviewNote: '旧テンプレート: {{tpl}}',
+ migrateExecuting: 'ファイルをリネーム中…',
+ migrateSuccess: '{{n}} ファイルをリネームしました',
+ migrateFailed: '{{n}} 件のリネームに失敗しました',
+ migrateShowErrors: 'エラーを表示',
+ migrateStart: 'リネームを開始',
+ onDevice: 'デバイスマネージャー',
+ addSources: '追加…',
+ colName: '名前',
+ colType: '種類',
+ colStatus: '状態',
+ syncResult: '{{done}} 転送済み、{{skipped}} は最新 (合計 {{total}})',
+ deleteFromDevice: '削除対象にする ({{count}})',
+ confirmDelete: 'デバイスから {{count}} 件を削除しますか?対象: {{names}}',
+ deleteComplete: '{{count}} 件をデバイスから削除しました。',
+ manifestImported: 'デバイスマニフェストから {{count}} 個のソースをインポートしました。',
+ selectedSources: '選択中のソース',
+ noSourcesSelected: 'ソースが選択されていません。ブラウザー内の項目をクリックして追加してください。',
+ clearAll: 'すべてクリア',
+ tabPlaylists: 'プレイリスト',
+ tabAlbums: 'アルバム',
+ tabArtists: 'アーティスト',
+ searchPlaceholder: '検索…',
+ syncButton: 'デバイスへ同期',
+ actionTransfer: 'デバイスへ転送',
+ actionDelete: 'デバイスから削除',
+ actionApplyAll: 'すべての変更を適用',
+ cancel: 'キャンセル',
+ noTargetDir: '先に同期先フォルダーを選択してください。',
+ noSources: '少なくとも 1 つのソースを選択してください。',
+ noTracks: '選択したソースにトラックが見つかりません。',
+ fetchError: 'サーバーからトラックを取得できませんでした。',
+ syncComplete: '同期が完了しました。',
+ dismiss: '閉じる',
+ cancelSync: 'キャンセル',
+ syncCancelled: '同期をキャンセルしました ({{done}} / {{total}} 転送済み)。',
+ statusSynced: '同期済み',
+ statusPending: '保留中',
+ statusDeletion: '削除',
+ markForDeletion: '削除対象にする',
+ undoDeletion: '削除を取り消す',
+ removeSource: '削除',
+ syncInBackground: '同期をバックグラウンドで開始しました。別の画面へ移動できます。',
+ syncInProgress: '{{done}} / {{total}} トラック…',
+ scanningDevice: 'デバイスをスキャン中…',
+ syncSummary: '同期サマリー',
+ calculating: '必要な転送量を計算中…',
+ filesToAdd: '追加するファイル:',
+ filesToDelete: '削除するファイル:',
+ netChange: '差し引き変更:',
+ availableSpace: '利用可能なディスク容量:',
+ spaceWarning: '警告: 対象デバイスの報告容量が不足しています。',
+ proceed: '同期を続行',
+ notEnoughSpace: '物理ディスク容量が不足しています!',
+ liveSearch: 'ライブ',
+ randomAlbumsLabel: 'ランダムアルバム',
+};
diff --git a/src/locales/ja/entityRating.ts b/src/locales/ja/entityRating.ts
new file mode 100644
index 00000000..b58b35f5
--- /dev/null
+++ b/src/locales/ja/entityRating.ts
@@ -0,0 +1,9 @@
+export const entityRating = {
+ albumShort: 'アルバム評価',
+ artistShort: 'アーティスト評価',
+ albumAriaLabel: 'アルバム評価',
+ artistAriaLabel: 'アーティスト評価',
+ selectedArtistsRatingAriaLabel: '選択中の {{count}} 人のアーティストの星評価',
+ selectedAlbumsRatingAriaLabel: '選択中の {{count}} 枚のアルバムの星評価',
+ saveFailed: '評価を保存できませんでした。',
+};
diff --git a/src/locales/ja/favorites.ts b/src/locales/ja/favorites.ts
new file mode 100644
index 00000000..aad81230
--- /dev/null
+++ b/src/locales/ja/favorites.ts
@@ -0,0 +1,24 @@
+export const favorites = {
+ title: 'お気に入り',
+ empty: 'まだお気に入りは保存されていません。',
+ artists: 'アーティスト',
+ albums: 'アルバム',
+ songs: '曲',
+ enqueueAll: 'すべてキューに追加',
+ playAll: 'すべて再生',
+ removeSong: 'お気に入りから削除',
+ stations: 'ラジオ局',
+ showingFiltered: '{{total}} 件中 {{filtered}} 件を表示 ({{artist}})',
+ showingCount: '{{total}} 件中 {{filtered}} 件を表示',
+ clearArtistFilter: 'アーティストフィルターを解除',
+ noFilterResults: '選択したフィルターに一致する結果はありません。',
+ allArtists: 'すべてのアーティスト',
+ topArtists: 'お気に入り数の多いアーティスト',
+ topArtistsSongCount_one: '{{count}} 曲',
+ topArtistsSongCount_other: '{{count}} 曲',
+ offlineTooltip: 'お気に入りをオフライン再生用に保存',
+ offlineJobName: 'お気に入り',
+ offlineSemaphoreSyncing: 'お気に入りを同期中… {{saved}} / {{total}}',
+ offlineSemaphoreSynced: 'すべてのお気に入りをオフライン再生用に保存しました',
+ offlineSemaphoreError: '同期エラーです。一部のトラックを保存できませんでした',
+};
diff --git a/src/locales/ja/folderBrowser.ts b/src/locales/ja/folderBrowser.ts
new file mode 100644
index 00000000..e8506ad3
--- /dev/null
+++ b/src/locales/ja/folderBrowser.ts
@@ -0,0 +1,4 @@
+export const folderBrowser = {
+ empty: '空のフォルダー',
+ error: '読み込みに失敗しました',
+};
diff --git a/src/locales/ja/genres.ts b/src/locales/ja/genres.ts
new file mode 100644
index 00000000..ebba407d
--- /dev/null
+++ b/src/locales/ja/genres.ts
@@ -0,0 +1,15 @@
+export const genres = {
+ title: 'ジャンル',
+ genreCount: 'ジャンル',
+ albumCount_one: '{{count}} 枚のアルバム',
+ albumCount_other: '{{count}} 枚のアルバム',
+ loading: 'ジャンルを読み込み中…',
+ empty: 'ジャンルが見つかりません。',
+ albumsLoading: 'アルバムを読み込み中…',
+ albumsEmpty: 'このジャンルのアルバムは見つかりません。',
+ loadMore: 'さらに読み込む',
+ back: '戻る',
+ playTooltip: '再生 (長押しでシャッフル)',
+ shuffle: 'シャッフル',
+ addToQueue: 'キューに追加',
+};
diff --git a/src/locales/ja/help.ts b/src/locales/ja/help.ts
new file mode 100644
index 00000000..667b42d7
--- /dev/null
+++ b/src/locales/ja/help.ts
@@ -0,0 +1,115 @@
+export const help = {
+ title: 'ヘルプ',
+ searchPlaceholder: 'ヘルプを検索…',
+ noResults: '一致するトピックはありません。別の検索語を試してください。',
+ // ── Section 1: Getting Started ─────────────────────────────────────────
+ s1: 'はじめに',
+ q1: 'どのサーバーに対応していますか?',
+ a1: 'Psysonic はまず Navidrome 向けに作られており、Subsonic 互換です。Gonic、Airsonic、LMS などの Subsonic API サーバーでも動作します。一部の高度な機能 (評価、スマートプレイリスト、マジック文字列共有、ユーザー管理) には Navidrome が必要です。',
+ q2: 'サーバーを追加するには?',
+ a2: '設定 → サーバー → サーバーを追加。URL (例: http://192.168.1.100:4533)、ユーザー名、パスワードを入力します。Psysonic は保存前に接続をテストします。失敗した場合は何も保存されません。サーバーはいくつでも追加でき、ヘッダーからいつでも切り替えられます。有効にできるのは一度に 1 つです。',
+ q3: 'UI の簡単な見方は?',
+ a3: '左のサイドバーで移動、中央が Mainstage / 各ページ、下がプレイヤーバー、右がキューパネルです (右上ヘッダーの Now-Playing インジケーター横から切り替え)。上部の検索バーはライブラリ全体を検索します。"Now Playing" には同じ Navidrome サーバー上の他ユーザーが今聴いているものが表示されます。',
+ // ── Section 2: Playback & Queue ────────────────────────────────────────
+ s2: '再生とキュー',
+ q4: 'キューの使い方は?',
+ a4: '右上ヘッダーからキューパネルを開きます。行をドラッグして並べ替え、外へドロップして削除できます。キューツールバーからシャッフル、キューのプレイリスト保存、トラックへのジャンプもできます。パネル外へ行をドラッグすると別の場所への転送としてドロップできます。',
+ q5: 'ギャップレスとクロスフェードの違いは?',
+ a5: 'ギャップレスは次のトラックを先にバッファし、曲間の無音をゼロにします (ライブアルバムや DJ ミックス向き)。クロスフェードは現在のトラックをフェードアウトしながら次を 1-10 秒でフェードインします (シャッフルミックス向き)。同時には使えません。一方を有効にするともう一方は無効になります。設定 → オーディオで調整できます。',
+ q6: '無限キューとは?',
+ a6: 'キューが尽き、リピートがオフのとき、Psysonic はライブラリから類似 / ランダムトラックを静かに追加し、再生を止めません。自動追加トラックは "自動追加" の区切りの下に表示されます。キューヘッダーの無限アイコンで切り替えられ、設定 → キューで自動追加をジャンルに制限できます。',
+ q7: '複数選択と Shift クリック範囲選択は?',
+ a7: 'アルバム / 新着リリース / ランダムアルバム / プレイリストで "選択" を有効化します。項目をクリックして切り替え、Shift を押しながら別の項目をクリックすると、表示順でその間すべてを選択します。Shift クリックは直前にクリックしたアンカーから拡張されます。グリッド上部のツールバーでキュー、ダウンロード、削除などの一括操作ができます。',
+ q8: 'キーボードショートカットとグローバルホットキーは?',
+ a8: '既定のアプリ内キー: Space = 再生 / 一時停止、Esc = フルスクリーン / モーダルを閉じる、F1 = ショートカット早見表。設定 → 入力でアプリ内操作をすべて再割り当てできます (Ctrl+Shift+P のようなコードも可)。また、Psysonic がバックグラウンドや最小化中でも動くシステム全体のグローバルショートカットを設定できます。メディアキー (再生/一時停止、次、前) は全プラットフォームで動作します。',
+ // ── Section 3: Audio Tools ─────────────────────────────────────────────
+ s3: 'オーディオツール',
+ q9: 'Replay Gain のモードは?',
+ a9: '設定 → オーディオ → Replay Gain。トラックモードは各曲を目標レベルに正規化します。アルバムモードはアルバム内の音量カーブを保ちます。自動モードは、キューが単一アルバム由来かどうかでトラックまたはアルバムを選びます。Replay Gain タグがないトラックは設定可能なプリアンプへフォールバックします。',
+ q10: 'Smart Loudness Normalization (LUFS) とは?',
+ a10: '設定 → オーディオにある Replay Gain の現代的な代替です。Psysonic は各トラックを LUFS / EBU R128 で解析して結果を保存するため、Replay Gain タグのない曲も含め、ライブラリ全体の音量がそろいます。コールドキャッシュ解析はバックグラウンドで動作し、約 1 分間 35-40% CPU を使った後 0 へ戻ります。目標ラウドネス (既定 -10 LUFS) を一度設定してください。',
+ q11: 'EQ と AutoEQ は?',
+ a11: '10 バンドのパラメトリック EQ は 設定 → オーディオ → イコライザー にあり、手動バンドとプリセットを使えます。隣の AutoEQ は AutoEQ データベースからヘッドホンモデルの測定補正プロファイルを取得し、自動でバンドへ適用します。ヘッドホンを選ぶと、EQ が正しいカーブに切り替わります。',
+ q12: '音声出力デバイスを切り替えるには?',
+ a12: '設定 → オーディオ → 出力デバイス。Psysonic は利用可能な出力を一覧し、選択すると即座に切り替えます。更新ボタンは起動後に接続したデバイスを再スキャンします。Linux の "sysdefault" のような ALSA 名は読みやすいよう自動で整理されます。',
+ q13: 'Hot Cache とは?',
+ a13: 'Hot Cache は現在のトラックと次の数曲を RAM とディスクへ先読みし、バッファなしで再生を開始します。低速または遠隔のサーバーで特に有用です。サイズ上限に達すると古い項目が削除されます。サイズとデバウンス遅延 (素早いスキップで過剰取得しないため) は 設定 → オーディオ で調整できます。',
+ // ── Section 4: Library & Discovery ─────────────────────────────────────
+ s4: 'ライブラリと発見',
+ q14: '評価と「スキップで 1★」の仕組みは?',
+ a14: 'Psysonic は OpenSubsonic (Navidrome 0.53 以降) 経由で 1-5 星評価に対応します。曲はトラックリスト、右クリックメニュー、プレイヤーバーのアーティスト名の下で評価できます。アルバムはアルバムページ、アーティストはアーティストページで評価できます。スキップで 1★ (設定 → ライブラリ → 評価) は、設定した回数だけ連続スキップした後に自動で 1 星を付けます。同じパネルでランダムミックスなどの生成ミックス用に最小評価フィルターを設定できます。',
+ q15: 'フォルダー、ジャンル、トラックの探し方は?',
+ a15: 'フォルダーブラウザー (サイドバー) はサーバーの音楽ディレクトリを Miller カラム形式でたどります。フォルダーをクリックして深掘りし、トラックまたはフォルダーの再生アイコンで再生 / キュー追加できます。ジャンルはトラック数でスケールするタグクラウド表示です。ジャンルをクリックすると開きます。トラックは列ソート可能な仮想リストとライブ検索を備えたフラットなライブラリハブです。',
+ q16: '検索と詳細検索は?',
+ a16: 'ヘッダー検索バーは入力に応じて、アーティスト、アルバム、トラックを高速ライブ検索します。詳細検索 (サイドバー) では、年、ジャンル、評価、形式、チャンネル、サンプルレート、BPM、ムードで絞り込み、条件を組み合わせられます。任意の結果を右クリックすると、アプリ内の他の場所と同じコンテキストメニューを使えます。',
+ q17: 'ミックス (ランダム / ジャンル / スーパージャンル / Lucky) とは?',
+ a17: 'ランダムミックスはライブラリからランダムなトラックのプレイリストを作ります。キーワードフィルターはジャンル / タイトル / アルバム部分一致でオーディオブック、コメディなどを除外します。スーパージャンルミックスはライブラリを大まかなスタイル (Rock, Metal, Electronic, Jazz, Classical など) にまとめ、選んだスタイルから集中したミックスを作ります。Lucky Mix は再生履歴、評価、AudioMuse-AI の類似トラックからワンクリックで即席プレイリストを組みます。',
+ q18: '統計ページは?',
+ a18: '統計 (サイドバー) にはトップアーティスト、トップアルバム、トップトラック、ジャンル内訳、時間ごとのリスニング時間、複数音楽フォルダーがある場合のライブラリ別範囲が表示されます。いくつかの表示は共有可能なカード画像としてエクスポートできます。',
+ q19: 'アルバムを ZIP としてダウンロードするには?',
+ a19: 'アルバムページ → "ダウンロード (ZIP)"。サーバーが先にアルバムを圧縮します。大きなアルバムやロスレスアルバム (FLAC / WAV) では、ZIP 完了後に転送が始まってから進捗バーが出ます。これは正常です。',
+ // ── Section 5: Lyrics ──────────────────────────────────────────────────
+ s5: '歌詞',
+ q20: '歌詞はどこから来ますか?',
+ a20: '3 つのソースがあり、設定 → 歌詞で構成できます。Navidrome サーバー (埋め込み / OpenSubsonic 歌詞)、LRCLIB (コミュニティ提供の同期歌詞)、NetEase Cloud Music (アジア圏 + 国際音楽の大きなカタログ)。各ソースは有効 / 無効にでき、ドラッグで順序を変更できます。',
+ q21: '再生中に歌詞を見るには?',
+ a21: 'プレイヤーバーのマイクアイコンをクリックすると、キューパネル内の歌詞タブが開きます。同期歌詞は自動スクロールし、クリックでシークできます。プレーンテキスト歌詞は静的ブロックとしてスクロールします。プレイヤーバーのアートワークからフルスクリーンプレイヤーを切り替えると、メッシュ状の背景で歌詞を大きく表示できます。',
+ // ── Section 6: Sharing & Social ────────────────────────────────────────
+ s6: '共有とソーシャル',
+ q22: 'マジック文字列とは?',
+ a22: 'マジック文字列は、第三者サーバーなしで Psysonic ユーザー間の共有を行う短いコピー&ペースト用トークンです。サーバー招待文字列は友人を Navidrome へワンペーストで参加させられます。アルバム / アーティスト / キューのマジック文字列は、相手のインストール済み Psysonic で同じアルバム / アーティスト / キューを開きます。共有メニューから生成し、検索バーへ貼り付けて使用します。',
+ q23: 'Orbit とは?',
+ a23: 'Orbit は同期リスニングです。ホストがトラックを再生し、すべてのゲストが同期して聴き、ゲストはホストがキューへ承認できる曲を提案できます。ヘッダーの Orbit ボタンからセッションを開始し、招待リンクを共有すると、他の人は任意の Psysonic インストールから参加できます。再生 (スキップ、シーク、キュー) はホストが管理し、ゲストにはリアルタイム表示と提案欄が提供されます。セッションは一時的で、ホストが閉じると終了します。',
+ q24: 'Now Playing ドロップダウンとは?',
+ a24: '右上ヘッダーのブロードキャストアイコンは、Navidrome サーバー上の他ユーザーが現在聴いているものを表示し、10 秒ごとに更新します。自分の項目は一時停止した瞬間に消えます。サーバーごとなので、別のアクティブサーバー上のユーザーは表示されません。',
+ // ── Section 7: Personalization ─────────────────────────────────────────
+ s7: 'パーソナライズ',
+ q25: 'テーマとテーマスケジューラーは?',
+ a25: '設定 → 外観 → テーマ では 8 グループ 60 個以上のテーマを選べます (Psysonic、Mediaplayer、Operating Systems、Games、Movies、Series、Social Media、Open Source Classics。Catppuccin / Nord / Gruvbox / Nightfox / Dracula など)。テーマ自動切り替えでは昼テーマ + 夜テーマと開始時刻を設定し、Psysonic が自動で切り替えます。',
+ q26: 'サイドバー、ホーム、アーティストページをカスタマイズできますか?',
+ a26: 'はい。設定 → パーソナライズで変更できます。サイドバーカスタマイザーではナビ項目を好きな順にドラッグし、使わないものを隠せます。ホームカスタマイザーでは Mainstage の各レール (Hero、Recent、Discover、Recently Played、Starred など) を切り替えます。アーティストページカスタマイザーではセクション (Top Songs、Albums、Singles、Compilations、Similar Artists など) の順序を変え、見ないものを非表示にできます。',
+ q27: 'ミニプレイヤーとは?',
+ a27: 'カバーアート、再生操作、コンパクトなキューを備えた小さなフローティングウィンドウです。プレイヤーバーのミニプレイヤーアイコン、またはキーボードショートカットから開けます。ウィンドウはセッション間で位置とサイズを記憶します。Windows では起動時にミニ WebView が事前作成されるため即座に開きます。Linux / macOS では 設定 → 外観 → ミニプレイヤーをプリロード から有効にします。',
+ q28: 'フローティングプレイヤーバーとは?',
+ a28: '下端から切り離した任意のプレイヤーバー形式 (設定 → 外観) です。テーマ付き背景、アクセント枠、角丸アルバムアート、中央揃えの音量セクションを備えます。縦長モニターやコンパクトテーマで便利です。',
+ q29: 'ホバー時のトラックプレビューとは?',
+ a29: 'トラック行にホバーし、カバー上の小さなプレビューボタンをクリックするか、右クリックメニューからプレビューを起動します。Psysonic は同じ Rust オーディオエンジンで最初の約 15 秒をストリーミングするため、ラウドネス正規化が適用されます。まだ聴いたことのないアルバムをざっと確認するのに便利です。',
+ q30: 'スリープタイマーは?',
+ a30: 'プレイヤーバーの月アイコンをクリックするとスリープタイマーが開きます。時間 (または "現在のトラックの終わり") を選ぶと、Psysonic は最後にフェードアウトして一時停止します。タイマー中はボタンに円形リングとカウントダウンが表示されます。',
+ q31: 'UI 倍率、フォント、シークバー形式は?',
+ a31: '設定 → 外観で、インターフェース倍率 (システムフォントサイズに影響せず 80-125%)、フォント (IBM Plex Mono、Fira Code、Geist、Golos Text など 10 種の UI フォント)、シークバー形式 (解析済み Waveform / 決定的 pseudowave / Line & Dot / Bar / Thick Bar / Segmented / Neon Glow / Pulse Wave / Particle Trail / Liquid Fill / Retro Tape) を変更できます。',
+ // ── Section 8: Power User ──────────────────────────────────────────────
+ s8: 'パワーユーザー',
+ q32: 'CLI のプレイヤー操作は?',
+ a32: 'Psysonic バイナリはリモコンとしても動作します。例: psysonic --player play / pause / next / prev、--player volume 75、--player seek 15、--player shuffle、--player repeat off|all|one、--player rating 1-5。サーバー、音声デバイス、ライブラリの切り替え、Instant Mix の起動、アーティスト / アルバム / トラック検索もできます。完全な一覧は psysonic --player --help を実行してください。bash と zsh 向け補完は psysonic completions で利用できます。',
+ q33: 'スマートプレイリスト (Navidrome) とは?',
+ a33: 'スマートプレイリストは Navidrome 側でルールにより定義される動的プレイリストです (genre = Rock AND year > 2020 など)。Psysonic のプレイリストページでは、視覚的なルールエディターで作成、編集、削除できます。Psysonic はそのために Navidrome ネイティブ API と通信します。アプリ内の他の場所では通常のプレイリストのように動作し、ライブラリ変更に応じて自動更新されます。',
+ q34: '設定のバックアップと復元は?',
+ a34: '設定 → ストレージ → バックアップと復元 で、サーバープロファイル、テーマ、キーバインドなどの設定を単一 JSON ファイルへエクスポートできます。別のマシンや再インストール後にそのファイルをインポートすると、すべてを一度に復元できます。サーバーパスワードも含まれるため、ファイルは非公開で保管してください。',
+ q35: 'すべてのオープンソースライセンスはどこで見られますか?',
+ a35: '設定 → システム → オープンソースライセンス。完全な依存関係一覧 (cargo crate と npm パッケージ) は、同梱ライセンス本文とともにビルドに含まれます。項目をクリックすると全文を表示できます。上部の厳選ハイライトには、ユーザーが認識しやすいライブラリ (Tauri、React、rodio、symphonia など) が表示されます。',
+ // ── Section 9: Offline & Sync ──────────────────────────────────────────
+ s9: 'オフラインと同期',
+ q36: 'オフラインモードでアルバムやプレイリストをキャッシュするには?',
+ a36: '任意のアルバムまたはプレイリストを開き、ヘッダーのダウンロードアイコンをクリックします。Psysonic は各トラックをローカルにキャッシュするため、ネットワーク呼び出しなしでディスクから再生できます。オフラインライブラリページ (サイドバー) にはキャッシュ済み項目がすべて表示され、進行中の状況を示し、ダウンロード完了後に現れるゴミ箱アイコンで削除できます。',
+ q37: 'オフラインストレージ上限は?',
+ a37: '設定 → ライブラリ → オフライン で最大キャッシュサイズを設定できます。上限に達すると、アルバムページのダウンロードボタンに警告バナーが表示されます。空き容量を作るには、オフラインライブラリページからアルバムまたはプレイリストを削除してください。',
+ q38: 'デバイス同期で USB / SD へ音楽をコピーできますか?',
+ a38: 'デバイス同期 (サイドバー) は、アルバム、プレイリスト、またはアーティスト全体を外部ドライブへコピーし、他のデバイスでオフライン再生できるようにします。同期先フォルダーを選び、ブラウザータブからソースを選択し、"デバイスへ転送" をクリックします。Psysonic はマニフェスト (psysonic-sync.json) を書き込むため、別 OS や別ファイル名テンプレートで Device Sync を再度開いても、すでに存在するファイルを把握できます。テンプレートは {artist} / {album} / {title} / {track_number} / {disc_number} / {year} トークンに対応し、/ はフォルダー区切りとして使えます。',
+ // ── Section 10: Integrations & Troubleshooting ─────────────────────────
+ s10: '連携とトラブルシューティング',
+ q39: 'Scrobbling: Last.fm、ListenBrainz、Maloja などは使えますか?',
+ a39: '設定 → 連携 → Music Network。1 つ以上の scrobble サービス (Last.fm、Libre.fm、Rocksky、ListenBrainz、Maloja、または任意の GNU FM 互換サーバー) に接続できます。Navidrome 側の設定は不要です。scrobbling が有効な接続済みサービスはすべて再生を受け取ります。マスターの "Scrobble を有効化" スイッチで全体の送信をオン/オフします。トラックの 50% を聴いた後に scrobble が送信され、対応サービスでは開始時に now-playing ping が送信されます。1 つのサービスをプライマリにします。お気に入りトラック、類似アーティスト、再生統計はそこから読み取られます。ヒント: Navidrome サーバーがすでにサービス (例: Maloja) へ scrobble している場合、同じサービスをここでも接続しないでください。重複 scrobble になります。',
+ q40: 'Discord Rich Presence は?',
+ a40: '設定 → 連携 → Discord で現在のトラックを Discord プロフィールに表示します。アプリアイコン、サーバーのカバーアート (getAlbumInfo2 経由。公開到達可能なサーバーが必要)、Apple Music カバーから選べます。表示文字列 (details、state、tooltip) はトークンテンプレートでカスタマイズできます。',
+ q41: 'Bandsintown ツアー日程は?',
+ a41: '設定 → 連携 → Now-Playing Info でオプトインします。すると Now Playing ページの Now Playing タブに、再生中アーティストの今後のツアー日程が Bandsintown widget API 経由で表示されます。既定ではオフで、有効にするまでリクエストは行われません。',
+ q42: 'インターネットラジオでライブストリームを再生できますか?',
+ a42: 'インターネットラジオ (サイドバー) は、Navidrome サーバーに保存された任意のライブストリームを再生します (ラジオ局は Navidrome 管理 UI から追加)。再生はブラウザーの HTML5 オーディオエンジンを通るため、ほとんどの EQ / Replay Gain / Loudness 設定はラジオには適用されませんが、ICY メタデータ (現在の曲名) は表示されます。MP3、AAC、OGG Vorbis、多くの HLS ストリームに対応します。コーデック対応はプラットフォームに依存します。',
+ q43: '接続テストに失敗します。どうすればいいですか?',
+ a43: 'ポートを含む URL を再確認してください (例: http://192.168.1.100:4533)。ローカルネットワークでは、証明書がないため https:// より http:// が動くことがあります。ファイアウォールがポートを遮断していないこと、ユーザー名とパスワードが正しいことを確認してください。サーバーがリバースプロキシの背後にある場合は、原因切り分けのため直接 URL を先に試してください。',
+ q44: 'カバーアートやアーティスト画像の読み込みが遅いです。',
+ a44: '画像は初回表示時にサーバーから取得され、その後 30 日間ローカルにキャッシュされます。サーバーストレージが遅い場合、ページの初回表示には少し時間がかかることがあります。以後の表示は即時です。Hot Cache はトラックにも効きますが、画像キャッシュは独立しています。',
+ q45: 'Linux で黒画面や音が出ない場合は?',
+ a45: 'Linux の黒画面は通常、グラフィックまたは WebView 表示の問題です。Wayland を使っている場合は X11 セッションを試すか、起動前に GDK_BACKEND=x11 と EGL_PLATFORM=x11 を設定してください。音声については PipeWire または PulseAudio が動作していることを確認してください。スリープや復帰後に音が止まる場合は、Psysonic を完全に終了して開き直してください。',
+};
diff --git a/src/locales/ja/hero.ts b/src/locales/ja/hero.ts
new file mode 100644
index 00000000..a315a166
--- /dev/null
+++ b/src/locales/ja/hero.ts
@@ -0,0 +1,9 @@
+export const hero = {
+ eyebrow: '注目アルバム',
+ playAlbum: 'アルバムを再生',
+ playAlbumTooltip: 'アルバムを再生 (長押しでシャッフル)',
+ enqueue: 'キューに追加',
+ enqueueTooltip: 'アルバム全体をキューに追加',
+ previousAlbum: '前のアルバム',
+ nextAlbum: '次のアルバム',
+};
diff --git a/src/locales/ja/home.ts b/src/locales/ja/home.ts
new file mode 100644
index 00000000..4c430e40
--- /dev/null
+++ b/src/locales/ja/home.ts
@@ -0,0 +1,21 @@
+export const home = {
+ hero: '注目',
+ starred: '個人のお気に入り',
+ mostPlayed: 'よく再生',
+ recentlyPlayed: '最近再生',
+ losslessAlbums: 'ロスレスアルバム',
+ discover: '発見',
+ discoverSongs: '曲を発見',
+ loadMore: 'さらに読み込む',
+ discoverMore: 'さらに発見',
+ discoverArtists: 'アーティストを発見',
+ discoverArtistsMore: 'すべてのアーティスト',
+ becauseYouLike: '最近聴いた音楽から…',
+ becauseYouLikeFor: '{{artist}} を聴いたあなたへ',
+ similarTo: '{{artist}} に類似',
+ becauseYouLikeTracks_one: '{{count}} 曲',
+ becauseYouLikeTracks_other: '{{count}} 曲',
+ mainstageEmptyTitle: 'Mainstage は空です',
+ mainstageEmptyBody: 'すべてのセクションがオフになっています。セクションを再度オンにするか、サイドバーから Mainstage を非表示にしてください。',
+ mainstageEmptyCta: 'パーソナライズ設定を開く'
+};
diff --git a/src/locales/ja/index.ts b/src/locales/ja/index.ts
new file mode 100644
index 00000000..af7402bb
--- /dev/null
+++ b/src/locales/ja/index.ts
@@ -0,0 +1,95 @@
+import { sidebar } from './sidebar';
+import { home } from './home';
+import { hero } from './hero';
+import { search } from './search';
+import { nowPlaying } from './nowPlaying';
+import { contextMenu } from './contextMenu';
+import { sharePaste } from './sharePaste';
+import { albumDetail } from './albumDetail';
+import { entityRating } from './entityRating';
+import { artistDetail } from './artistDetail';
+import { favorites } from './favorites';
+import { randomLanding } from './randomLanding';
+import { randomAlbums } from './randomAlbums';
+import { genres } from './genres';
+import { randomMix } from './randomMix';
+import { luckyMix } from './luckyMix';
+import { albums } from './albums';
+import { tracks } from './tracks';
+import { artists } from './artists';
+import { composers } from './composers';
+import { composerDetail } from './composerDetail';
+import { login } from './login';
+import { connection } from './connection';
+import { common } from './common';
+import { settings } from './settings';
+import { changelog } from './changelog';
+import { whatsNew } from './whatsNew';
+import { musicNetwork } from './musicNetwork';
+import { help } from './help';
+import { queue } from './queue';
+import { miniPlayer } from './miniPlayer';
+import { statistics } from './statistics';
+import { player } from './player';
+import { nowPlayingInfo } from './nowPlayingInfo';
+import { songInfo } from './songInfo';
+import { playlists } from './playlists';
+import { smartPlaylists } from './smartPlaylists';
+import { mostPlayed } from './mostPlayed';
+import { losslessAlbums } from './losslessAlbums';
+import { radio } from './radio';
+import { folderBrowser } from './folderBrowser';
+import { deviceSync } from './deviceSync';
+import { orbit } from './orbit';
+import { tray } from './tray';
+import { licenses } from './licenses';
+import { migration } from './migration';
+
+export const jaTranslation = {
+ sidebar,
+ home,
+ hero,
+ search,
+ nowPlaying,
+ contextMenu,
+ sharePaste,
+ albumDetail,
+ entityRating,
+ artistDetail,
+ favorites,
+ randomLanding,
+ randomAlbums,
+ genres,
+ randomMix,
+ luckyMix,
+ albums,
+ tracks,
+ artists,
+ composers,
+ composerDetail,
+ login,
+ connection,
+ common,
+ settings,
+ changelog,
+ whatsNew,
+ musicNetwork,
+ help,
+ queue,
+ miniPlayer,
+ statistics,
+ player,
+ nowPlayingInfo,
+ songInfo,
+ playlists,
+ smartPlaylists,
+ mostPlayed,
+ losslessAlbums,
+ radio,
+ folderBrowser,
+ deviceSync,
+ orbit,
+ tray,
+ licenses,
+ migration,
+};
diff --git a/src/locales/ja/licenses.ts b/src/locales/ja/licenses.ts
new file mode 100644
index 00000000..59e9a260
--- /dev/null
+++ b/src/locales/ja/licenses.ts
@@ -0,0 +1,13 @@
+export const licenses = {
+ title: 'オープンソースライセンス',
+ intro: 'Psysonic はオープンソースソフトウェアを利用して構築されています。以下の一覧には、アプリに同梱されるすべての依存関係と、そのバージョン、ライセンス、完全なライセンス本文が表示されます。',
+ highlights: '主要な依存関係',
+ searchPlaceholder: '名前、バージョン、ライセンスで検索…',
+ noResults: '一致する項目はありません。',
+ loading: 'ライセンスを読み込み中…',
+ loadError: 'ライセンスデータを読み込めませんでした。',
+ noLicenseText: 'この依存関係のライセンス本文は同梱されていません。',
+ viewSource: 'ソースを表示',
+ totalLine: '{{total}} 個の依存関係: cargo {{cargo}}、npm {{npm}}',
+ generatedAt: '最終生成 {{date}}',
+};
diff --git a/src/locales/ja/login.ts b/src/locales/ja/login.ts
new file mode 100644
index 00000000..be584043
--- /dev/null
+++ b/src/locales/ja/login.ts
@@ -0,0 +1,22 @@
+export const login = {
+ subtitle: 'Navidrome デスクトッププレイヤー',
+ serverName: 'サーバー名 (任意)',
+ serverNamePlaceholder: 'My Navidrome',
+ serverUrl: 'サーバー URL',
+ serverUrlPlaceholder: '192.168.1.100:4533 または https://music.example.com',
+ username: 'ユーザー名',
+ usernamePlaceholder: 'admin',
+ password: 'パスワード',
+ showPassword: 'パスワードを表示',
+ hidePassword: 'パスワードを隠す',
+ connect: '接続',
+ connecting: '接続中…',
+ connected: '接続しました!',
+ error: '接続に失敗しました。入力内容を確認してください。',
+ urlRequired: 'サーバー URL を入力してください。',
+ savedServers: '保存済みサーバー',
+ addNew: 'または新しいサーバーを追加',
+ orMagicString: 'またはマジック文字列',
+ magicStringPlaceholder: '共有文字列を貼り付け (psysonic1-…)',
+ magicStringInvalid: '無効または読み取れないマジック文字列です。',
+};
diff --git a/src/locales/ja/losslessAlbums.ts b/src/locales/ja/losslessAlbums.ts
new file mode 100644
index 00000000..6325719e
--- /dev/null
+++ b/src/locales/ja/losslessAlbums.ts
@@ -0,0 +1,7 @@
+export const losslessAlbums = {
+ empty: 'このライブラリにはまだロスレスアルバムがありません。',
+ unsupported: 'このサーバーはロスレスアルバムを検出するために必要なメタデータを公開していません。',
+ slowFetchHint: '他のアルバムページより読み込みに時間がかかります。Psysonic が曲カタログ全体を音質で走査します。',
+ modeBanner: 'ロスレスモード: FLAC、WAV などのロスレス形式のみ表示中。',
+ modeBannerExit: 'すべての形式を表示',
+};
diff --git a/src/locales/ja/luckyMix.ts b/src/locales/ja/luckyMix.ts
new file mode 100644
index 00000000..dee8f5a7
--- /dev/null
+++ b/src/locales/ja/luckyMix.ts
@@ -0,0 +1,6 @@
+export const luckyMix = {
+ done: 'Lucky Mix の準備完了: {{count}} 曲',
+ failed: 'Lucky Mix を作成できませんでした。もう一度お試しください。',
+ unavailable: 'このサーバーでは Lucky Mix を利用できません。',
+ cancelTooltip: 'Lucky Mix の作成をキャンセル',
+};
diff --git a/src/locales/ja/migration.ts b/src/locales/ja/migration.ts
new file mode 100644
index 00000000..472de44d
--- /dev/null
+++ b/src/locales/ja/migration.ts
@@ -0,0 +1,15 @@
+export const migration = {
+ preparing: 'データ更新を準備中…',
+ preparingBody: 'ライブラリと解析キャッシュを確認中…',
+ migrating: 'データを移行中',
+ working: '処理中…',
+ skippedRows: '削除済みサーバーの行はスキップされました。切り替え成功後に古いバックアップ DB が削除されます。',
+ failed: '移行に失敗しました',
+ retry: '再試行',
+ copyDetails: '詳細をコピー',
+ complete: '更新完了',
+ completeRows: '{{count}} 行を移行しました',
+ genreTagsTitle: 'ジャンルインデックスを更新中…',
+ genreTagsBody: 'ブラウズとフィルター用にジャンルをインデックスしています。アップグレード後に一度だけ実行されます。',
+ genreTagsFailed: 'ジャンルインデックスの更新に失敗しました',
+};
diff --git a/src/locales/ja/miniPlayer.ts b/src/locales/ja/miniPlayer.ts
new file mode 100644
index 00000000..48e7f2b0
--- /dev/null
+++ b/src/locales/ja/miniPlayer.ts
@@ -0,0 +1,9 @@
+export const miniPlayer = {
+ showQueue: 'キューを表示',
+ hideQueue: 'キューを非表示',
+ pinOnTop: '常に手前に表示',
+ pinOff: '固定を解除',
+ openMainWindow: 'メインウィンドウを開く',
+ close: '閉じる',
+ emptyQueue: 'キューは空です',
+};
diff --git a/src/locales/ja/mostPlayed.ts b/src/locales/ja/mostPlayed.ts
new file mode 100644
index 00000000..c7040037
--- /dev/null
+++ b/src/locales/ja/mostPlayed.ts
@@ -0,0 +1,13 @@
+export const mostPlayed = {
+ title: 'よく再生',
+ topArtists: 'トップアーティスト',
+ topAlbums: 'トップアルバム',
+ plays: '{{n}} 回再生',
+ sortMost: '再生数が多い順',
+ sortLeast: '再生数が少ない順',
+ loadMore: 'さらにアルバムを読み込む',
+ noData: 'まだ再生データがありません。聴き始めましょう!',
+ noArtists: 'すべてのアーティストがフィルターで除外されています。',
+ filterCompilations: 'コンピレーションアーティストを非表示 (Various Artists、Soundtracks など)',
+ filterCompilationsShort: 'コンピレーションを非表示',
+};
diff --git a/src/locales/ja/musicNetwork.ts b/src/locales/ja/musicNetwork.ts
new file mode 100644
index 00000000..a437ea0a
--- /dev/null
+++ b/src/locales/ja/musicNetwork.ts
@@ -0,0 +1,55 @@
+export const musicNetwork = {
+ title: 'Music Network',
+ desc: '再生履歴を 1 つ以上のサービスへ scrobble します。Love、類似アーティスト、再生統計は選択したプライマリから取得します。',
+ masterToggle: 'Scrobble を有効化',
+ masterToggleDesc: '接続済みサービスすべてへ再生を送信するマスタースイッチです。',
+ addService: 'サービスを追加',
+ connect: '接続',
+ connecting: '接続中…',
+ disconnect: '切断',
+ scrobbleHere: 'ここへ scrobble',
+ primaryLabel: 'プライマリサービス',
+ primaryDesc: 'お気に入りトラック (❤)、類似アーティスト、再生統計はここから取得します。scrobble は有効なすべてのサービスへ送信されます。',
+ primaryNone: 'なし',
+ statusConnected: '接続済み',
+ statusError: '再接続が必要',
+ scrobbles: '{{n}} scrobble',
+ memberSince: '{{year}} 年から利用',
+ connectFailed: '接続できませんでした。もう一度お試しください。',
+ connectProbeFailed: '{{provider}} に接続しましたが、検証できませんでした: {{message}}',
+ fieldRequired: '{{field}} は必須です。',
+ malojaProxyWarning: 'Maloja サーバーが scrobble を Last.fm へ転送している可能性があります。重複を避けるため、どちらか一方の scrobble を無効にしてください。',
+ presets: {
+ lastfm: { desc: '元祖 scrobble サービス。Love、類似アーティスト、統計に対応。' },
+ librefm: { desc: 'Last.fm 互換の Libre.fm によるオープンソース scrobble。' },
+ rocksky: { desc: 'AT Protocol 上の scrobble 専用送信先。' },
+ listenbrainz: { desc: 'MetaBrainz によるオープンなリスニング履歴。scrobble 送信先。' },
+ malojaNative: { desc: 'セルフホストの scrobble サーバー (ネイティブ API)。' },
+ malojaCompat: { desc: 'Audioscrobbler (GNU FM) API 経由のセルフホスト Maloja。' },
+ malojaListenbrainz: { desc: 'ListenBrainz 互換 API 経由のセルフホスト Maloja。' },
+ koito: { desc: 'ListenBrainz 互換 API 経由のセルフホスト再生履歴トラッカー。' },
+ customGnufm: { desc: '任意のセルフホスト GNU FM / Last.fm 互換インスタンス。' },
+ },
+ fields: {
+ lbToken: 'ユーザートークン',
+ malojaUrl: 'サーバー URL',
+ malojaKey: 'API キー',
+ koitoUrl: 'サーバー URL',
+ koitoToken: 'API キー',
+ koitoTokenHelp: 'Koito の Settings → API Keys で API キーを生成し、ここへ貼り付けます。',
+ rockskySessionKey: 'セッションキー',
+ rockskySessionKeyHelp: 'Rocksky はこのキーを CLI 経由でのみ発行します:\n1. npx -y @rocksky/cli@latest login your-handle\n2. cat ~/.rocksky/token.json\n3. "token" の値をここへ貼り付けます。',
+ gnufmUrl: 'サーバー URL',
+ apiKey: 'API キー',
+ apiSecret: '共有シークレット',
+ },
+ errors: {
+ AUTH_SESSION_INVALID: 'セッションの期限が切れました。設定で再接続してください。',
+ AUTH_TIMEOUT: '認可がタイムアウトしました。もう一度お試しください。',
+ PROBE_FAILED: 'このサービスではこの機能を利用できません。',
+ CAPABILITY_UNSUPPORTED: 'このサービスはその機能に対応していません。',
+ NETWORK: 'ネットワークエラーです。接続または URL を確認してください。',
+ MALOJA_BAD_KEY: 'Maloja API キーが無効です。',
+ CUSTOM_URL_INVALID: 'サーバー URL に到達できません。',
+ },
+};
diff --git a/src/locales/ja/nowPlaying.ts b/src/locales/ja/nowPlaying.ts
new file mode 100644
index 00000000..3044709a
--- /dev/null
+++ b/src/locales/ja/nowPlaying.ts
@@ -0,0 +1,48 @@
+export const nowPlaying = {
+ tooltip: '聴いているユーザー',
+ title: '聴いているユーザー',
+ loading: '読み込み中…',
+ nobody: '現在聴いている人はいません。',
+ presence: {
+ playing: '再生中',
+ paused: '一時停止',
+ idle: '待機中',
+ },
+ nothingPlaying: 'まだ何も再生されていません。曲を開始しましょう!',
+ aboutArtist: 'アーティストについて',
+ fromAlbum: 'このアルバムから',
+ viewAlbum: 'アルバムを表示',
+ goToArtist: 'アーティストへ移動',
+ readMore: '続きを読む',
+ showLess: '折りたたむ',
+ genreInfo: 'ジャンル',
+ trackInfo: 'トラック情報',
+ topSongs: 'このアーティストでよく再生',
+ topSongsCredit: '{{name}} の人気トラック',
+ trackPosition: 'トラック {{pos}}',
+ playsCount_one: '{{count}} 回再生',
+ playsCount_other: '{{count}} 回再生',
+ releasedYearsAgo_one: '{{count}} 年前',
+ releasedYearsAgo_other: '{{count}} 年前',
+ discography: 'ディスコグラフィ',
+ thisTrack: 'このトラック',
+ thisArtist: 'このアーティスト',
+ listeners: 'リスナー',
+ scrobbles: 'scrobble',
+ yourScrobbles: 'あなた',
+ listenersN: '{{n}} リスナー',
+ scrobblesN: '{{n}} scrobble',
+ playsByYouN: 'あなたが {{n}} 回再生',
+ rgTrackTooltip: 'ReplayGain (トラック)',
+ rgAlbumTooltip: 'ReplayGain (アルバム)',
+ rgAutoTooltip: 'ReplayGain (自動)',
+ showMoreTracks: 'さらに {{count}} 件表示',
+ showLessTracks: '折りたたむ',
+ hideCard: 'カードを非表示',
+ layoutMenu: 'レイアウト',
+ visibleCards: '表示中のカード',
+ hiddenCards: '非表示のカード',
+ noHiddenCards: '非表示のカードはありません',
+ resetLayout: 'レイアウトをリセット',
+ emptyColumn: 'ここにカードをドロップ',
+};
diff --git a/src/locales/ja/nowPlayingInfo.ts b/src/locales/ja/nowPlayingInfo.ts
new file mode 100644
index 00000000..c53fd7c2
--- /dev/null
+++ b/src/locales/ja/nowPlayingInfo.ts
@@ -0,0 +1,24 @@
+export const nowPlayingInfo = {
+ tab: '情報',
+ empty: '何か再生すると情報が表示されます',
+ artist: 'アーティスト',
+ songInfo: '曲情報',
+ onTour: 'ツアー中',
+ noTourEvents: '今後の公演はありません',
+ tourLoading: '読み込み中…',
+ poweredByBandsintown: 'ツアーデータ提供: Bandsintown',
+ bioReadMore: '続きを読む',
+ bioReadLess: '折りたたむ',
+ showMoreTours_one: 'さらに {{count}} 件表示',
+ showMoreTours_other: 'さらに {{count}} 件表示',
+ showLessTours: '折りたたむ',
+ enableBandsintownPrompt: '今後のツアー日程を表示しますか?',
+ enableBandsintownPromptDesc: '任意です。公開 Bandsintown API から現在のアーティストの公演情報を読み込みます。',
+ enableBandsintownPrivacy: '有効にすると、ツアー日程取得のため現在再生中のアーティスト名が Bandsintown API に送信されます。アカウント情報や個人データはデバイス外へ送信されません。',
+ enableBandsintownAction: '有効化',
+ role: {
+ artist: 'アーティスト',
+ albumArtist: 'アルバムアーティスト',
+ composer: '作曲者',
+ },
+};
diff --git a/src/locales/ja/orbit.ts b/src/locales/ja/orbit.ts
new file mode 100644
index 00000000..78795bbe
--- /dev/null
+++ b/src/locales/ja/orbit.ts
@@ -0,0 +1,200 @@
+export const orbit = {
+ triggerLabel: 'Orbit',
+ triggerTooltip: '共有リスニングセッションを開始するか参加します',
+ launchCreate: 'セッションを作成',
+ launchJoin: 'セッションに参加',
+ launchHelp: '仕組みを見る',
+ launchHelpSoon: '近日対応',
+ joinModalTitle: 'Orbit セッションに参加',
+ joinModalSub: 'ホストから送られた招待リンクを貼り付けてください。',
+ joinModalLinkLabel: '招待リンク',
+ joinModalLinkPlaceholder: 'psysonic2-…',
+ joinModalLinkHelper: '有効な Orbit リンクなら使用できます。現在サインインしているサーバーを指している必要があります。',
+ joinModalPasteTooltip: 'クリップボードから貼り付け',
+ joinModalSubmit: '参加',
+ joinModalBusy: '参加中…',
+ joinErrEmpty: '招待リンクを貼り付けてください。',
+ joinErrInvalid: 'Orbit 招待リンクではないようです。',
+ closeAria: '閉じる',
+ heroTitlePrefix: '一緒に聴く',
+ heroTitleBrand: 'Orbit',
+ heroSub: 'セッションを開始すると、{{server}}上の他のユーザーが一緒に聴き、トラックを提案できます。',
+ fallbackServer: 'このサーバー',
+ tipLan: '現在、ホームネットワーク用アドレスで接続しています。ネットワーク外のゲストは参加できません。開始前に設定で公開サーバーアドレスへ切り替えてください。',
+ tipRemote: '自宅ネットワーク外のゲストが参加するには、サーバーアドレスが公開到達可能である必要があります。内部専用サーバーの場合は開始前に切り替えてください。',
+ labelName: 'セッション名',
+ namePlaceholder: 'Velvet Orbit',
+ reshuffleTooltip: '新しい提案',
+ reshuffleAria: '新しい名前を提案',
+ helperName: 'ゲストに表示されるセッション名です。そのままでも、自分で入力してもかまいません。',
+ labelMax: '最大ゲスト数',
+ helperMax: 'ホスト自身は含めず、参加するゲスト数だけを制限します。',
+ labelLink: '招待リンク',
+ tooltipCopied: 'コピーしました',
+ tooltipCopy: 'コピー',
+ ariaCopyLink: '招待リンクをコピー',
+ helperLink: 'このリンクをゲストへ送ってください。ゲストは Psysonic のどこでも Ctrl+V で貼り付けられます。',
+ labelClearQueue: '先に自分のキューをクリア',
+ helperClearQueue: '空の新しいキューでセッションを開始します。オフの場合、すでにキューにあるトラックが残り、ゲストにも共有されます。',
+ btnCancel: 'キャンセル',
+ btnStarting: '開始中…',
+ btnStart: 'Orbit を開始',
+ btnCopyAndStart: 'リンクをコピーして開始',
+ errNameRequired: 'セッション名を入力してください。',
+ errStartFailed: '開始できませんでした。',
+ hostLabel: 'ホスト: {{name}}',
+ participantsTooltip: '参加者',
+ settingsTooltip: 'セッション設定',
+ shareTooltip: '招待リンクを共有',
+ shuffleLabel: 'キュー再シャッフルまで',
+ catchUpLabel: '追いつく',
+ catchUpTooltip: 'ホストの現在位置へジャンプ',
+ hostAway: 'ホストはオフライン',
+ hostOnline: 'ホストはオンライン',
+ endTooltip: 'セッションを終了',
+ leaveTooltip: 'セッションを退出',
+ helpTooltip: 'Orbit の仕組み',
+ diag: {
+ openTooltip: '診断: コピー可能なイベントログ',
+ title: 'Orbit 診断',
+ role: '役割',
+ hostTrack: 'ホストのトラック ID',
+ hostPos: 'ホスト位置',
+ guestTrack: '自分のトラック ID',
+ guestPos: '自分の位置',
+ drift: 'ずれ',
+ stateAge: '状態の経過時間',
+ eventLog: 'イベントログ ({{count}})',
+ copyLabel: 'コピー',
+ copyTooltip: 'ログをクリップボードへコピー',
+ clearLabel: 'クリア',
+ clearTooltip: 'バッファを消去',
+ empty: 'まだイベントはありません。Orbit が同期するとイベントが表示されます。',
+ hint: '問題を再現する前にこれを開き、コピーをクリックしてバグ報告へ貼り付けてください。',
+ copied: '{{count}} 行のイベントをコピーしました',
+ copyFailed: 'クリップボードにコピーできませんでした',
+ cleared: 'バッファをクリアしました',
+ },
+ helpTitle: 'Orbit の仕組み',
+ helpIntro: 'Orbit は Psysonic を共有リスニングルームにします。ホストが音楽を選び、ゲストは同期して聴きながらトラックを提案できます。',
+ helpHostOnly: '(ホスト)',
+ helpSec1Title: 'Orbit とは?',
+ helpSec1Body: '一緒に聴くためのモードです。ホストが再生を操作し、ゲストがそこへ同期します。すべて自分の Navidrome サーバー上のプレイリストを通じて動作し、外部インフラは使いません。',
+ helpSec2Title: 'ホストとゲスト',
+ helpSec2Body: 'ホストは再生操作 (再生 / 一時停止 / スキップ / シーク) とセッション終了を制御します。ゲストはホストの再生に追従し、トラックを提案し、いつでも退出または再参加できます。参加者を強制退出またはBANできるのはホストだけです。',
+ helpSec2WarnHead: '重要: 別々のアカウントが必要です。',
+ helpSec2WarnBody: '各参加者には自分専用の Navidrome アカウントが必要です。ホストとゲストが同じユーザーでサインインすると投稿が衝突し、ホストはゲストの提案を見られません。',
+ helpSec3Title: '開始と招待',
+ helpSec3Body: '"Orbit" ボタン → セッションを作成、と進むと、開始モーダルにコピー可能な招待リンクが表示されます。現在のキューをクリアするかも選べます。好きな方法でそのリンクを共有してください。セッション中は上部のセッションバーにある共有ボタンでいつでもリンクを再コピーできます。',
+ helpSec4Title: '参加',
+ helpSec4Body: 'Psysonic のどこでも Ctrl+V / Cmd+V で招待リンクを貼り付けると、参加確認が自動で表示されます。または "Orbit" → セッションに参加、と進んで入力欄へ貼り付けます。リンク先サーバーのアカウントを持っていれば、Psysonic が切り替えます。そのサーバーに複数アカウントがある場合は、使用するアカウントを選ぶメニューが表示されます。',
+ helpSec5Title: 'トラック提案',
+ helpSec5Body: '任意の曲リストで、行をダブルクリックするか、右クリック → "Orbit セッションに追加" を選びます。シングルクリックではアルバム全体を共有キューへ入れず、ヒントだけを表示します。これは仕様です。"すべて再生" や "アルバムを再生" のような明示的な一括操作は先に確認し、その後に追加します (置き換えはしません)。',
+ helpSec6Title: '共有キュー',
+ helpSec6Body: 'キューにはホストの次のトラックが表示され、全員に見えます。一括追加は常に末尾へ追加されるため、ゲストの提案は失われません。自動シャッフルは定期的にキューを並べ替えます (設定可能: 1 / 5 / 10 / 15 / 30 分)。再生がホストからずれた場合、セッションバーの "追いつく" ボタンでホストの現在位置へ戻れます。',
+ helpSec7Title: '承認',
+ helpSec7Body: '既定では、ゲストの提案は手動承認が必要です。キューパネル上部の "承認待ち" ストリップに表示され、承認 / 却下できます。セッション設定で自動承認をオンにすると、すべてすぐキューへ入ります。',
+ helpSec8Title: '参加者と設定',
+ helpSec8Body: 'セッションバーの設定アイコンから、シャッフル間隔、自動承認、"今すぐシャッフル" ショートカットを開けます。参加者数をクリックすると接続中の人を確認できます。強制退出 (リンクから再参加可能) またはBAN (セッション中は再参加不可) が可能です。ゲストも参加者一覧を見られますが、読み取り専用です。',
+ helpSec9Title: 'セッション終了',
+ helpSec9Body: 'ホストが X を押して確認すると、セッションは全員に対して閉じられ、サーバー上のプレイリストは自動で片付けられます。ゲストが X を押すと、そのゲストだけ退出し、セッションは続きます。ホストが 5 分間応答しない場合、ゲストは通知付きで自動退出します。その範囲内の短い再接続は表示されません。',
+ participantsInviteLabel: '招待リンク',
+ participantsCountLabel: 'セッション内 {{count}} 人',
+ participantsHost: 'ホスト',
+ participantsEmpty: 'まだゲストはいません',
+ participantsKickTooltip: 'セッションから削除',
+ participantsKickAria: '{{user}} を削除',
+ participantsRemoveTooltip: 'セッションから削除',
+ participantsRemoveAria: '{{user}} をこのセッションから削除',
+ participantsBanTooltip: 'BAN',
+ participantsBanAria: '{{user}} をBAN',
+ participantsMuteTooltip: '提案をミュート',
+ participantsUnmuteTooltip: '提案を許可',
+ participantsMuteAria: '{{user}} からの提案をミュート',
+ participantsUnmuteAria: '{{user}} からの提案を許可',
+ confirmRemoveTitle: 'セッションから削除しますか?',
+ confirmRemoveBody: '{{user}} はセッションから外されますが、招待リンクから再参加できます。',
+ confirmRemoveConfirm: '削除',
+ confirmBanTitle: 'BANしますか?',
+ confirmBanBody: '{{user}} はこのセッションから削除され、再参加できなくなります。セッションが続く間は取り消せません。',
+ confirmBanConfirm: 'BAN',
+ confirmCancel: 'キャンセル',
+ confirmJoinTitle: 'Orbit セッションに参加しますか?',
+ confirmJoinBody: '{{host}} が "{{name}}" に招待しています。参加しますか?',
+ confirmJoinConfirm: '参加',
+ confirmLeaveTitle: 'セッションを退出しますか?',
+ confirmLeaveBody: '"{{name}}" から退出しますか?{{host}} の招待リンクからいつでも再参加できます。',
+ confirmLeaveConfirm: '退出',
+ confirmEndTitle: '全員のセッションを終了しますか?',
+ confirmEndBody: '"{{name}}" はすべての参加者に対して閉じられます。セッションのプレイリストは自動で片付けられます。',
+ confirmEndConfirm: 'セッションを終了',
+ invalidLinkTitle: '招待リンクはもう有効ではありません',
+ invalidLinkBody: 'この Orbit セッションは存在しないか、すでに終了しています。ホストに新しい招待リンクを依頼してください。',
+ settingsTitle: 'セッション設定',
+ settingAutoApprove: '提案を自動承認',
+ settingAutoApproveHint: 'ゲストの提案が即座にキューへ入ります。オフの場合、後で確認できるようセッション一覧に残ります。',
+ settingAutoShuffle: '自動再シャッフル',
+ settingAutoShuffleHint: '次のキューを定期的に Fisher-Yates シャッフルします。オフの場合、手動で並べ替えたときだけ順序が変わります。',
+ settingShuffleInterval: '再シャッフル間隔',
+ settingShuffleIntervalHint: 'セッション中、次のキューをどの頻度で再シャッフルするかです。',
+ suggestBlockedMuted: 'ホストがこのセッションであなたからの提案をミュートしました。提案はオフです。',
+ settingShuffleIntervalValue_one: '{{count}} 分',
+ settingShuffleIntervalValue_other: '{{count}} 分',
+ settingShuffleNow: '今すぐシャッフル',
+ toastSuggested: '{{user}} が "{{title}}" を提案しました',
+ toastSuggestedMany: 'キューに {{count}} 件の新しい提案',
+ toastShuffled: 'キューをシャッフルしました',
+ toastJoined: 'セッションに参加しました',
+ toastLoginFirst: 'セッション参加前にログインしてください',
+ toastSwitchServer: '先に {{url}} へ切り替えてから、もう一度貼り付けてください',
+ toastNoAccountForServer: '{{url}} へのアクセス権がありません。ホストに招待を依頼してください。',
+ toastSwitchFailed: '{{url}} へ切り替えられませんでした',
+ accountPickerTitle: 'どのアカウントを使いますか?',
+ accountPickerSub: '{{url}} に複数のアカウントがあります。セッションに参加するアカウントを選んでください。',
+ toastJoinFail: 'セッションに参加できませんでした',
+ joinErrNotFound: 'セッションが見つかりません',
+ joinErrEnded: 'セッションは終了しました',
+ joinErrFull: 'セッションは満員です',
+ joinErrKicked: 'このセッションには再参加できません',
+ joinErrNoUser: '有効なサーバーがありません',
+ joinErrServerError: '参加できませんでした',
+ ctxAddToSession: 'Orbit セッションに追加',
+ ctxSuggestedToast: 'セッションへ提案しました',
+ ctxSuggestFailed: '提案できませんでした。セッションに参加していません',
+ ctxAddToSessionHost: 'Orbit セッションに追加',
+ ctxAddedHostToast: 'セッションへ追加しました',
+ ctxAddHostFailed: 'セッションへ追加できませんでした',
+ bulkConfirmTitle: '選択した項目をすべて Orbit キューへ追加しますか?',
+ bulkConfirmBody: '共有キューへ {{count}} 曲を一度に追加します。ゲストにはかなり多い量です。続行しますか?',
+ bulkConfirmYes: 'すべて追加',
+ bulkConfirmNo: 'キャンセル',
+ guestLive: 'ライブ',
+ guestPlaying: '再生中',
+ guestPaused: '一時停止',
+ guestLoading: '読み込み中…',
+ guestSuggestions: '提案',
+ guestUpNext: '次に再生',
+ guestUpNextEmpty: 'キューは空です。トラックのコンテキストメニューから "Orbit セッションに追加" を選んで提案できます。',
+ guestPendingTitle: 'ホスト待ち',
+ guestPendingHint: '提案済みです。ホストが取り込むとキューに表示されます。',
+ approvalTitle: '承認待ち',
+ approvalFrom: '{{user}} からの提案',
+ approvalAccept: '承認',
+ approvalDecline: '却下',
+ guestUpNextMore: '+ ホストのキューにさらに {{count}} 件',
+ guestSubmitter: '{{user}} より',
+ queueAddedByHost: 'ホストが追加',
+ queueAddedByYou: 'あなたが追加',
+ queueAddedByUser: '{{user}} が追加',
+ guestEmpty: '提案はまだありません。トラックのコンテキストメニューから "Orbit セッションに追加" を選んでください。',
+ guestFooter: '再生はホストが制御しています。ゲストはリストを変更できません。',
+ exitKickedTitle: 'セッションからBANされました',
+ exitRemovedTitle: 'セッションから削除されました',
+ exitEndedTitle: 'ホストがセッションを終了しました',
+ exitHostTimeoutTitle: 'ホストが応答していません',
+ exitHostTimeoutBody: '{{host}} からしばらく更新が送られてこないため、この端末で "{{name}}" を閉じました。招待リンクからいつでも再参加できます。',
+ exitKickedBody: '{{host}} が "{{name}}" であなたをBANしました。再参加はできません。',
+ exitRemovedBody: '{{host}} が "{{name}}" からあなたを削除しました。招待リンクからいつでも再参加できます。',
+ exitEndedBody: '"{{name}}" は終了しました。',
+ exitOk: 'OK',
+};
diff --git a/src/locales/ja/player.ts b/src/locales/ja/player.ts
new file mode 100644
index 00000000..d0e29d44
--- /dev/null
+++ b/src/locales/ja/player.ts
@@ -0,0 +1,69 @@
+export const player = {
+ regionLabel: 'ミュージックプレイヤー',
+ openFullscreen: 'フルスクリーンプレイヤーを開く',
+ fullscreen: 'フルスクリーンプレイヤー',
+ closeFullscreen: 'フルスクリーンを閉じる',
+ closeTooltip: '閉じる (Esc)',
+ noTitle: 'タイトルなし',
+ stop: '停止',
+ prev: '前のトラック',
+ play: '再生',
+ pause: '一時停止',
+ autoDjMixing: 'AutoDJ: ミックス中',
+ autoDjPreparing: 'AutoDJ: 次のトラックを準備中',
+ bufferingStream: 'サーバーからトラックを読み込み中',
+ previewActive: 'プレビュー再生中',
+ previewLabel: 'プレビュー',
+ delayModalTitle: 'タイマー',
+ delayPauseSection: '一時停止まで',
+ delayStartSection: '開始まで',
+ delayPreviewPause: '一時停止時刻',
+ delayPreviewStart: '開始時刻',
+ delaySchedulePause: '一時停止を予約',
+ delayScheduleStart: '開始を予約',
+ delayCancelPause: '一時停止タイマーをキャンセル',
+ delayCancelStart: '開始タイマーをキャンセル',
+ delayInactivePause: '何か再生中のときのみ利用できます。',
+ delayInactiveStart: 'トラックまたはラジオが読み込まれ、一時停止中のとき利用できます。',
+ delayCustomMinutes: 'カスタム遅延 (分)',
+ delayCustomPlaceholder: '例: 2.5',
+ closeDelayModal: '閉じる',
+ delayIn: 'あと',
+ delayFmtSec: '{{n}} 秒',
+ delayFmtMin: '{{n}} 分',
+ delayFmtHr: '{{n}} 時間',
+ delayCancel: 'キャンセル',
+ delayApply: '適用',
+ next: '次のトラック',
+ repeat: 'リピート',
+ repeatOff: 'オフ',
+ repeatAll: 'すべて',
+ repeatOne: '1 曲',
+ progress: '曲の進行',
+ volume: '音量',
+ mute: 'ミュート',
+ unmute: 'ミュート解除',
+ toggleQueue: 'キューを切り替え',
+ collapseQueueResize: 'キューを折りたたんでリサイズ',
+ moreOptions: 'その他のオプション',
+ equalizer: 'イコライザー',
+ playbackRate: '再生速度',
+ miniPlayer: 'ミニプレイヤー',
+ lyrics: '歌詞',
+ fsNowPlaying: '再生中…',
+ fsTrackPosition: 'トラック {{current}} / {{total}}',
+ fsNext: '次',
+ fsUpNext: '次に再生',
+ fsQueueEmpty: 'キューは空です。',
+ shuffle: 'シャッフル',
+ fsLyricsToggle: 'フルスクリーンで歌詞',
+ lyricsLoading: '歌詞を読み込み中…',
+ lyricsNotFound: 'このトラックの歌詞は見つかりません',
+ lyricsNoSources: '歌詞ソースが選択されていません。設定 → 歌詞で有効にしてください',
+ lyricsSourceServer: 'ソース: サーバー',
+ lyricsSourceLrclib: 'ソース: LRCLIB',
+ lyricsSourceNetease: 'ソース: Netease',
+ lyricsSourceLyricsplus: 'ソース: YouLyPlus',
+ showDuration: '長さを表示',
+ showRemainingTime: '残り時間を表示',
+};
diff --git a/src/locales/ja/playlists.ts b/src/locales/ja/playlists.ts
new file mode 100644
index 00000000..9c12ce2a
--- /dev/null
+++ b/src/locales/ja/playlists.ts
@@ -0,0 +1,122 @@
+export const playlists = {
+ title: 'プレイリスト',
+ newPlaylist: '新規プレイリスト',
+ unnamed: '名前のないプレイリスト',
+ createName: 'プレイリスト名…',
+ create: '作成',
+ cancel: 'キャンセル',
+ empty: 'プレイリストはまだありません。',
+ emptyPlaylist: 'このプレイリストは空です。',
+ addFirstSong: '最初の曲を追加',
+ notFound: 'プレイリストが見つかりません。',
+ songs_one: '{{count}} 曲',
+ songs_other: '{{count}} 曲',
+ playAll: 'すべて再生',
+ playTooltip: 'プレイリストを再生',
+ shuffle: 'シャッフル',
+ addToQueue: 'キューに追加',
+ back: 'プレイリストへ戻る',
+ deletePlaylist: '削除',
+ confirmDelete: 'もう一度クリックして確認',
+ removeSong: 'プレイリストから削除',
+ addSongs: '曲を追加',
+ addSongsTooltip: 'ライブラリを検索してトラックを追加',
+ searchPlaceholder: 'ライブラリを検索…',
+ noResults: '結果はありません。',
+ suggestions: 'おすすめの曲',
+ noSuggestions: '利用できるおすすめはありません。',
+ titleBadge: 'プレイリスト',
+ refreshSuggestions: '新しいおすすめ',
+ addSong: 'プレイリストに追加',
+ preview: 'プレビュー (30 秒)',
+ previewStop: 'プレビューを停止',
+ playNextSuggestion: '次に再生',
+ suggestionsHint: '行をダブルクリックしてプレイリストに追加',
+ addSelected: '選択項目を追加',
+ cacheOffline: 'プレイリストをオフラインキャッシュ',
+ offlineCached: 'プレイリストをキャッシュ済み',
+ removeOffline: 'オフラインキャッシュから削除',
+ offlineDownloading: 'キャッシュ中… ({{done}}/{{total}} アルバム)',
+ publicLabel: '公開',
+ privateLabel: '非公開',
+ editMeta: 'プレイリストを編集',
+ editNamePlaceholder: 'プレイリスト名…',
+ editCommentPlaceholder: '説明を追加…',
+ editPublic: '公開プレイリスト',
+ editSave: '保存',
+ editCancel: 'キャンセル',
+ changeCover: 'カバー画像を変更',
+ changeCoverLabel: '写真を変更',
+ removeCover: '写真を削除',
+ coverUpdated: 'カバーを更新しました',
+ metaSaved: 'プレイリストを更新しました',
+ downloadZip: 'ダウンロード (ZIP)',
+ // Toast notifications for multi-select
+ addSuccess: '{{count}} 曲を {{playlist}} に追加しました',
+ addPartial: '{{added}} 曲を追加、{{skipped}} 曲をスキップ (重複)',
+ addAllSkipped: 'すべてスキップしました ({{count}} 件の重複)',
+ addedAsDuplicates: '{{count}} 曲を {{playlist}} に追加しました (重複として)',
+ duplicateConfirmTitle: 'すでにプレイリストにあります',
+ duplicateConfirmMessage: '{{count}} 曲すべてがすでに "{{playlist}}" にあります。重複としてもう一度追加しますか?',
+ duplicateConfirmAction: 'それでも追加',
+ addError: '曲の追加中にエラー',
+ createAndAddSuccess: 'プレイリスト "{{playlist}}" を作成し、{{count}} 曲を追加しました',
+ createError: 'プレイリストの作成中にエラー',
+ deleteSuccess: '{{count}} 個のプレイリストを削除しました',
+ deleteFailed: '{{name}} の削除中にエラー',
+ deleteSelected: '選択項目を削除',
+ deleteSelectedPartial: '選択中のプレイリストのうち {{total}} 個中 {{n}} 個だけ削除できます (他は別ユーザーのものです)。',
+ mergeSuccess: '{{count}} 曲を {{playlist}} に統合しました',
+ mergeNoNewSongs: '追加する新しい曲はありません',
+ mergeError: 'プレイリストの統合中にエラー',
+ mergeInto: '統合先',
+ selectionCount: '{{count}} 件選択中',
+ select: '選択',
+ startSelect: '選択を有効化',
+ cancelSelect: 'キャンセル',
+ loadingAlbums: '{{count}} 枚のアルバムを解決中…',
+ loadingArtists: '{{count}} 人のアーティストを解決中…',
+ myPlaylists: '自分のプレイリスト',
+ noOtherPlaylists: '他に利用できるプレイリストはありません',
+ addToPlaylistSuccess: '{{count}} 曲を {{playlist}} に追加しました',
+ addToPlaylistNoNew: '{{playlist}} に追加する新しい曲はありません',
+ addToPlaylistError: 'プレイリストへの追加中にエラー',
+ removeSuccess: '曲をプレイリストから削除しました',
+ removeError: '曲をプレイリストから削除中にエラー',
+ importCSV: 'CSV をインポート',
+ importCSVTooltip: 'Spotify CSV からインポート',
+ csvImportReport: 'CSV インポートレポート',
+ csvImportTotal: '合計',
+ csvImportAdded: '追加済み',
+ csvImportDuplicates: '重複',
+ csvImportNotFound: '未検出',
+ csvImportNetworkErrors: 'ネットワークエラー',
+ csvImportDuplicatesTitle: '重複トラック (すでにプレイリストに存在):',
+ csvImportNotFoundTitle: '見つからなかったトラック:',
+ csvImportNetworkErrorsTitle: 'ネットワークエラー (再インポートで解消する場合があります):',
+ csvImportDownloadReport: 'レポートをダウンロード',
+ csvImportClose: '閉じる',
+ csvImportNoValidTracks: 'CSV ファイルに有効なトラックが見つかりません',
+ csvImportFailed: 'CSV ファイルのインポートに失敗しました',
+ csvImportToast: '{{added}} 件追加、{{notFound}} 件未検出、{{duplicates}} 件重複',
+ csvImportDownloadSuccess: 'レポートをダウンロードしました',
+ csvImportDownloadError: 'レポートのダウンロードに失敗しました',
+ // Playlist folders (local, per-server organisation layer)
+ folders: {
+ newFolder: '新規フォルダー',
+ namePlaceholder: 'フォルダー名…',
+ create: '作成',
+ rename: '名前を変更',
+ delete: 'フォルダーを削除',
+ ungrouped: '未分類',
+ moveToFolder: 'フォルダーへ移動',
+ removeFromFolder: 'フォルダーから削除',
+ expandFolder: 'フォルダーを展開',
+ collapseFolder: 'フォルダーを折りたたむ',
+ groupByFolders: 'フォルダーでグループ化',
+ count_one: '{{count}} 個のプレイリスト',
+ count_other: '{{count}} 個のプレイリスト',
+ localOnlyNotice:
+ 'フォルダーはこのデバイス上の Psysonic にのみ保存されます。Navidrome と Subsonic API にはプレイリストフォルダーのネイティブ対応がないため、この構造はサーバーには保存されず、他のデバイスやアプリとも同期されません。',
+ },
+};
diff --git a/src/locales/ja/queue.ts b/src/locales/ja/queue.ts
new file mode 100644
index 00000000..9087d3ab
--- /dev/null
+++ b/src/locales/ja/queue.ts
@@ -0,0 +1,64 @@
+export const queue = {
+ title: 'キュー',
+ modePlaylist: 'プレイリスト',
+ modeTimeline: 'タイムライン',
+ upNext: '次に再生',
+ history: '履歴',
+ noUpcoming: '次のトラックはありません。',
+ savePlaylist: 'プレイリストを保存',
+ updatePlaylist: 'プレイリストを更新',
+ filterPlaylists: 'プレイリストを絞り込み…',
+ playlistName: 'プレイリスト名',
+ cancel: 'キャンセル',
+ save: '保存',
+ loadPlaylist: 'プレイリストを読み込む',
+ loading: '読み込み中…',
+ noPlaylists: 'プレイリストが見つかりません。',
+ load: 'キューを置換して再生',
+ appendToQueue: 'キューに追加',
+ delete: '削除',
+ deleteConfirm: 'プレイリスト "{{name}}" を削除しますか?',
+ clear: 'キューをクリア',
+ shuffle: 'キューをシャッフル',
+ gapless: 'ギャップレス',
+ crossfade: 'クロスフェード',
+ autoDj: 'AutoDJ',
+ infiniteQueue: '無限キュー',
+ playlist: 'プレイリスト',
+ autoAdded: '自動追加',
+ radioAdded: 'ラジオ',
+ hide: '非表示',
+ hideNowPlaying: 'Now Playing情報を非表示',
+ showNowPlaying: 'Now Playing情報を表示',
+ close: '閉じる',
+ nextTracks: '次のトラック',
+ shareQueue: 'キューの共有リンクをコピー',
+ shareQueueEmpty: 'キューは空です。共有できるトラックはありません。',
+ emptyQueue: 'キューは空です。',
+ crossServerEnqueueBlocked: '別サーバーのトラックは現在のキューへ追加できません。先にキューを再生し終えるかクリアしてください。',
+ trackSingular: '曲',
+ trackPlural: '曲',
+ showRemaining: '残り時間を表示',
+ showTotal: '合計時間を表示',
+ showEta: '終了予定時刻を表示',
+ replayGain: 'ReplayGain',
+ rgTrack: 'T {{db}} dB',
+ rgAlbum: 'A {{db}} dB',
+ rgPeak: 'Peak {{pk}}',
+ sourceOffline: 'オフラインライブラリから再生中',
+ sourceHot: 'キャッシュから再生中',
+ sourceStream: 'ネットワークストリームから再生中',
+ clearCachedLoudnessWaveform: 'キャッシュ済みのラウドネスと波形をクリアし、このトラックを再解析',
+ recalculatingLoudnessWaveform: 'このトラックのラウドネスと波形を再計算中…',
+ bpm: '{{bpm}} BPM',
+ moods: {
+ happy: 'ハッピー',
+ excited: '高揚感',
+ calm: '穏やか',
+ peaceful: '静か',
+ angry: '怒り',
+ tense: '緊張',
+ sad: '悲しい',
+ melancholic: 'メランコリック',
+ },
+};
diff --git a/src/locales/ja/radio.ts b/src/locales/ja/radio.ts
new file mode 100644
index 00000000..552e857d
--- /dev/null
+++ b/src/locales/ja/radio.ts
@@ -0,0 +1,37 @@
+export const radio = {
+ title: 'インターネットラジオ',
+ empty: 'ラジオ局が設定されていません。',
+ addStation: 'ラジオ局を追加',
+ editStation: '編集',
+ playStation: 'ラジオ局を再生',
+ stopStation: 'ラジオ局を停止',
+ deleteStation: 'ラジオ局を削除',
+ confirmDelete: 'もう一度クリックして確認',
+ stationName: 'ラジオ局名…',
+ streamUrl: 'ストリーム URL…',
+ homepageUrl: 'ホームページ URL (任意)',
+ save: '保存',
+ cancel: 'キャンセル',
+ live: 'LIVE',
+ liveStream: 'インターネットラジオ',
+ openHomepage: 'ホームページを開く',
+ changeCoverLabel: 'カバーを変更',
+ removeCover: 'カバーを削除',
+ browseDirectory: 'ディレクトリを検索',
+ directoryPlaceholder: 'ラジオ局を検索…',
+ noResults: 'ラジオ局が見つかりません。',
+ stationAdded: 'ラジオ局を追加しました',
+ filterAll: 'すべて',
+ filterFavorites: 'お気に入り',
+ sortManual: '手動',
+ sortAZ: 'A → Z',
+ sortZA: 'Z → A',
+ sortNewest: '新しい順',
+ favorite: 'お気に入りに追加',
+ unfavorite: 'お気に入りから削除',
+ noFavorites: 'お気に入りのラジオ局はありません。',
+ listenerCount_one: '{{count}} リスナー',
+ listenerCount_other: '{{count}} リスナー',
+ recentlyPlayed: '最近再生',
+ upNext: '次に再生',
+};
diff --git a/src/locales/ja/randomAlbums.ts b/src/locales/ja/randomAlbums.ts
new file mode 100644
index 00000000..d766b19a
--- /dev/null
+++ b/src/locales/ja/randomAlbums.ts
@@ -0,0 +1,4 @@
+export const randomAlbums = {
+ title: 'ランダムアルバム',
+ refresh: '更新',
+};
diff --git a/src/locales/ja/randomLanding.ts b/src/locales/ja/randomLanding.ts
new file mode 100644
index 00000000..df167d8e
--- /dev/null
+++ b/src/locales/ja/randomLanding.ts
@@ -0,0 +1,9 @@
+export const randomLanding = {
+ title: 'ミックスを作成',
+ mixByTracks: 'トラックでミックス',
+ mixByTracksDesc: 'ライブラリ全体からランダムにトラックを選択',
+ mixByAlbums: 'アルバムでミックス',
+ mixByAlbumsDesc: '次の発見に向けたランダムなアルバム選択',
+ mixByLucky: 'Lucky Mix',
+ mixByLuckyDesc: 'トップアーティスト、アルバム、評価から作るスマートな即席ミックス',
+};
diff --git a/src/locales/ja/randomMix.ts b/src/locales/ja/randomMix.ts
new file mode 100644
index 00000000..ed59a8d6
--- /dev/null
+++ b/src/locales/ja/randomMix.ts
@@ -0,0 +1,40 @@
+export const randomMix = {
+ title: 'ランダムミックス',
+ remix: 'リミックス',
+ remixTooltip: '新しいランダム曲を読み込む',
+ remixGenre: '{{genre}} をリミックス',
+ remixTooltipGenre: '新しい {{genre}} の曲を読み込む',
+ playAll: 'すべて再生',
+ trackTitle: 'タイトル',
+ trackArtist: 'アーティスト',
+ trackAlbum: 'アルバム',
+ trackFavorite: 'お気に入り',
+ trackDuration: '長さ',
+ favoriteAdd: 'お気に入りに追加',
+ favoriteRemove: 'お気に入りから削除',
+ play: '再生',
+ trackGenre: 'ジャンル',
+ mixSettingsHeader: 'ミックス設定',
+ exclusionsHeader: '除外',
+ filterPanelInexactSizeNote: 'ミックスサイズは目安です。サーバーのランダム候補が不足すると、大きな指定ではユニークなトラック数が少なくなる場合があります。',
+ mixSize: 'プレイリストサイズ',
+ excludeAudiobooks: 'オーディオブックとラジオ劇を除外',
+ excludeAudiobooksDesc: 'ジャンル、タイトル、アルバム、アーティストにキーワードを照合します。例: Hörbuch, Audiobook, Spoken Word, …',
+ genreBlocked: 'キーワードで除外済み',
+ genreAddedToBlacklist: 'フィルターリストに追加しました',
+ genreAlreadyBlocked: 'すでに除外済み',
+ artistBlocked: 'アーティストを除外済み',
+ artistAddedToBlacklist: 'アーティストをフィルターリストに追加しました',
+ artistClickHint: 'クリックしてこのアーティストを除外',
+ blacklistToggle: 'キーワードフィルター',
+ genreMixTitle: 'ジャンルミックス',
+ genreMixDesc: '曲数上位 20 ジャンル。クリックしてランダムミックスを読み込み',
+ genreMixAll: 'すべての曲',
+ genreMixLoadMore: 'さらに 10 件読み込む',
+ genreMixNoGenres: 'サーバーにジャンルが見つかりません。',
+ noSongsMatchFilters: '現在のフィルターに一致する曲はありません。キーワード除外を外すか、ミックス設定を変更してください。',
+ shuffleGenres: '別のジャンルを表示',
+ filterPanelTitle: 'フィルター',
+ filterPanelDesc: '下のトラックリストでジャンルタグまたはアーティスト名をクリックすると、今後のミックスから除外できます。',
+ genreClickHint: 'ジャンルタグをクリックして\nフィルターキーワードとして追加します。\nジャンル、タイトル、アルバム、アーティストに一致します。',
+};
diff --git a/src/locales/ja/search.ts b/src/locales/ja/search.ts
new file mode 100644
index 00000000..76df453d
--- /dev/null
+++ b/src/locales/ja/search.ts
@@ -0,0 +1,87 @@
+export const search = {
+ placeholder: 'アーティスト、アルバム、曲を検索…',
+ noResults: '"{{query}}" の結果はありません',
+ artists: 'アーティスト',
+ albums: 'アルバム',
+ songs: '曲',
+ clearLabel: '検索をクリア',
+ addedToQueueToast: '"{{title}}" をキューに追加しました',
+ title: '検索',
+ resultsFor: '"{{query}}" の検索結果',
+ album: 'アルバム',
+ advanced: '詳細検索',
+ localIndexBadge: 'ローカルインデックス',
+ localIndexBadgeTooltip: 'このデバイス上のローカルライブラリインデックスからの結果',
+ networkSearchBadge: 'サーバー検索',
+ networkSearchBadgeTooltip: '接続中サーバーのライブ検索からの結果',
+ liveSearchFailed: '検索に失敗しました。もう一度お試しください',
+ advancedSearchTerm: '検索語',
+ advancedSearchPlaceholder: 'タイトル、アルバム、アーティスト…',
+ advancedGenre: 'ジャンル',
+ advancedAllGenres: 'すべてのジャンル',
+ advancedYear: '年',
+ advancedYearFrom: '開始',
+ advancedYearTo: '終了',
+ advancedBpm: 'BPM',
+ advancedBpmClear: 'BPM フィルターを解除',
+ advancedLossless: '形式',
+ advancedLosslessOnly: 'ロスレスのみ',
+ bpmSourceTag: 'ファイルタグ由来の BPM',
+ bpmSourceAnalysis: '音声解析由来の BPM',
+ advancedMoodGroup: 'ムード',
+ advancedAllMoods: 'すべてのムード',
+ advancedMoodLocalNote: 'ローカルライブラリインデックスとトラック解析が必要です',
+ scopeRowLabel: '検索範囲:',
+ scopeAllTooltip: 'すべてを検索',
+ scopeArtistsChipTooltip: '結果をアーティストに限定',
+ scopeAlbumsChipTooltip: '結果をアルバムに限定',
+ scopeSongsChipTooltip: '結果を曲に限定',
+ advancedAll: 'すべて',
+ advancedSearch: '検索',
+ advancedEmpty: '検索語を入力するか、フィルターを選択して開始してください。',
+ advancedNoResults: '結果が見つかりません。',
+ advancedGenreNote: 'このジャンルから曲をランダムに選択します。',
+ recentSearches: '最近の検索',
+ browse: 'ブラウズ',
+ emptyHint: '何を聴きますか?',
+ scopeArtistsPlaceholder: 'アーティストを検索…',
+ scopeArtistsBadgeTooltip: 'クリックして削除',
+ scopeArtistsGhostTooltip: 'クリックしてこのページだけで検索',
+ scopeAlbumsPlaceholder: 'アルバムを検索…',
+ scopeAlbumsBadgeTooltip: 'クリックして削除',
+ scopeAlbumsGhostTooltip: 'クリックしてこのページだけで検索',
+ scopeNewReleasesPlaceholder: '新着リリースを検索…',
+ scopeNewReleasesBadgeTooltip: 'クリックして削除',
+ scopeNewReleasesGhostTooltip: 'クリックしてこのページだけで検索',
+ scopeTracksPlaceholder: 'タイトル、アーティスト、アルバムでトラックを検索…',
+ scopeTracksBadgeTooltip: 'クリックして削除',
+ scopeTracksGhostTooltip: 'クリックしてこのページだけで検索',
+ scopeComposersPlaceholder: '作曲者を検索…',
+ scopeComposersBadgeTooltip: 'クリックして削除',
+ scopeComposersGhostTooltip: 'クリックしてこのページだけで検索',
+ genres: 'ジャンル',
+ shareLink: '共有リンク',
+ shareTrackTitle: '共有トラック',
+ shareQueueTitle_one: '共有キュー ({{count}} 曲)',
+ shareQueueTitle_other: '共有キュー ({{count}} 曲)',
+ shareQueueAction: 'キューに追加',
+ shareQueueing: 'キューに追加中…',
+ shareQueued_one: '{{count}} 曲の共有トラックをキューに追加しました',
+ shareQueued_other: '{{count}} 曲の共有トラックをキューに追加しました',
+ shareQueuedPartial: '{{total}} 曲中 {{queued}} 曲をキューに追加しました ({{skipped}} 曲は見つかりませんでした)。',
+ shareUnsupportedTitle: 'この共有リンクはここでは使用できません',
+ shareUnsupportedSub: 'トラック、アルバム、アーティスト、作曲者、またはキューの共有リンクを使用してください。',
+ shareFromServer: '{{server}} から',
+ shareQueuePreview: 'トラックをプレビュー',
+ shareQueuePreviewLoading: 'トラックを読み込み中…',
+ shareQueuePreviewEmpty: 'このリンクのトラックはサーバー上で見つかりませんでした。',
+ shareQueuePreviewSkipped: '{{total}} 曲中 {{skipped}} 曲はこのサーバーで見つかりませんでした。',
+ moodGroups: {
+ joy: '喜び',
+ sadness: '悲しみ',
+ dance: 'ダンス',
+ work: '作業',
+ romance: 'ロマンス',
+ anger: '怒り',
+ },
+};
diff --git a/src/locales/ja/settings.ts b/src/locales/ja/settings.ts
new file mode 100644
index 00000000..366b9276
--- /dev/null
+++ b/src/locales/ja/settings.ts
@@ -0,0 +1,708 @@
+export const settings = {
+ title: '設定',
+ language: '言語',
+ languageEn: 'English',
+ languageDe: 'Deutsch',
+ languageEs: 'Español',
+ languageFr: 'Français',
+ languageNl: 'Nederlands',
+ languageNb: 'Norsk',
+ languageRu: 'Русский',
+ languageZh: '中文',
+ languageRo: 'Română',
+ languageJa: '日本語',
+ font: 'フォント',
+ fontHintOpenDyslexic: 'ディスレクシアに配慮 · 中国語非対応',
+ theme: 'テーマ',
+ appearance: '外観',
+ servers: 'サーバー',
+ serverName: 'サーバー名',
+ serverUrl: 'サーバー URL',
+ serverUrlPlaceholder: '192.168.1.100:4533 または https://music.example.com',
+ serverAlternateUrl: '2 つ目のアドレス (任意)',
+ serverAlternateUrlPlaceholderPublic: 'https://music.example.com',
+ serverAlternateUrlPlaceholderLocal: '192.168.1.100:4533',
+ serverAlternateUrlHintAddPublic: '自宅ネットワーク外からアクセスするための公開アドレスを追加できます。',
+ serverAlternateUrlHintAddLocal: '自宅で高速接続するためのローカルアドレスを追加できます。',
+ serverBothLanError: '両方のアドレスがローカルです。片方だけにするか、公開アドレスを追加してください。',
+ dualAddressVerifying: '両方のアドレスが同じサーバーを指しているか確認中…',
+ dualAddressMismatch: '2 つのアドレスが別々のサーバーを指しています。スペルを確認して再試行してください。',
+ dualAddressInsufficient: '両方のアドレスが同じサーバーか確認できませんでした。続行するには片方のアドレスを削除してください。',
+ dualAddressUnreachable: '{{host}} に到達できませんでした。アドレスとネットワークを確認してから再試行してください。',
+ urlRemigrationTitle: 'ライブラリデータを移動しますか?',
+ urlRemigrationMessage: 'アドレスを変更すると、すべてのライブラリ、解析、カバーキャッシュデータが {{oldKey}} から {{newKey}} へ移動されます。これは元に戻せません。',
+ urlRemigrationConfirm: 'データを移動',
+ urlRemigrationProgress: 'ライブラリデータを移動中…',
+ urlRemigrationFailureInspect: '移動対象を確認できませんでした。もう一度試すか、デバッグログを開いてください。',
+ urlRemigrationFailureRun: 'ライブラリデータの移動に失敗しました。保存済みデータは変更されていません。もう一度お試しください。',
+ urlRemigrationFailureCoverRename: 'ライブラリデータは移動されましたが、カバーファイルをリネームできませんでした。カバーは次回アクセス時に再構築されます。',
+ shareUsesLocalUrl: '共有リンクでローカルアドレスを使用',
+ shareUsesLocalUrlDesc: 'Orbit 招待とライブラリ共有に影響します。既定: 公開アドレス。',
+ serverUsername: 'ユーザー名',
+ serverPassword: 'パスワード',
+ addServer: 'サーバーを追加',
+ addServerTitle: '新しいサーバーを追加',
+ editServer: '編集',
+ editServerTitle: 'サーバーを編集',
+ useServer: '使用',
+ deleteServer: '削除',
+ noServers: '保存済みサーバーはありません。',
+ serverActive: '有効',
+ serverVersionUnknown: 'サーバーバージョン不明',
+ confirmDeleteServer: 'サーバー "{{name}}" を削除しますか?',
+ confirmDeleteServerLibrary: 'このサーバーのローカルライブラリインデックスも削除しますか?オフライン利用のためキャッシュを残す場合はキャンセルしてください。',
+ serverConnecting: '接続中…',
+ serverConnected: '接続しました!',
+ serverFailed: '接続に失敗しました。',
+ testBtn: '接続をテスト',
+ testingBtn: 'テスト中…',
+ serverCompatible: 'Navidrome 向けに作られています。他の Subsonic 互換サーバー (Gonic, Airsonic, …) でも動作する場合がありますが、Psysonic は多くの Navidrome 固有 API エンドポイントを使うため機能が制限されることがあります。',
+ userMgmtTitle: 'ユーザー管理',
+ userMgmtDesc: 'このサーバーのユーザーを管理します。管理者権限が必要です。',
+ userMgmtNoAdmin: 'このサーバーでユーザーを管理するには管理者権限が必要です。',
+ userMgmtLoadError: 'ユーザーの読み込みに失敗しました。',
+ userMgmtLoadFriendly: 'サーバーが応答しませんでした。一時的なことが多いです。',
+ userMgmtRetry: '再試行',
+ userMgmtEmpty: 'ユーザーが見つかりません。',
+ userMgmtYouBadge: 'あなた',
+ userMgmtAdminBadge: '管理者',
+ userMgmtAddUser: 'ユーザーを追加',
+ userMgmtAddUserTitle: '新しいユーザーを追加',
+ userMgmtEditUserTitle: 'ユーザーを編集',
+ userMgmtUsername: 'ユーザー名',
+ userMgmtName: '表示名',
+ userMgmtEmail: 'メール',
+ userMgmtPassword: 'パスワード',
+ userMgmtPasswordEditHint: '更新する場合は新しいパスワードを入力してください。',
+ userMgmtRoleAdmin: '管理者',
+ userMgmtLibraries: 'ライブラリ',
+ userMgmtLibrariesAdminHint: '管理者ユーザーは自動的にすべてのライブラリへアクセスできます。',
+ userMgmtLibrariesEmpty: 'このサーバーに利用可能なライブラリはありません。',
+ userMgmtLibrariesValidation: '少なくとも 1 つのライブラリを選択してください。',
+ userMgmtLibrariesUpdateError: 'ユーザーは保存されましたが、ライブラリ割り当てに失敗しました',
+ userMgmtNoLibraries: '割り当て済みライブラリなし',
+ userMgmtNeverSeen: 'なし',
+ userMgmtSave: '保存',
+ userMgmtCancel: 'キャンセル',
+ userMgmtDelete: '削除',
+ userMgmtEdit: '編集',
+ userMgmtConfirmDelete: 'ユーザー "{{username}}" を削除しますか?これは元に戻せません。',
+ userMgmtCreateError: 'ユーザーを作成できませんでした。',
+ userMgmtUpdateError: 'ユーザーを更新できませんでした。',
+ userMgmtDeleteError: 'ユーザーを削除できませんでした。',
+ userMgmtCreated: 'ユーザーを作成しました。',
+ userMgmtUpdated: 'ユーザーを更新しました。',
+ userMgmtDeleted: 'ユーザーを削除しました。',
+ userMgmtValidationMissing: 'ユーザー名、表示名、パスワードは必須です。',
+ userMgmtValidationMissingIdentity: 'ユーザー名と表示名は必須です。',
+ userMgmtMagicStringGenerate: 'マジック文字列を生成',
+ userMgmtSaveAndMagicString: '保存してマジック文字列を取得',
+ userMgmtMagicStringPasswordNavHint:
+ 'Navidrome はこのユーザーのパスワードを保存します。現在のものと異なる場合、サーバーはログインパスワードを更新します。',
+ userMgmtMagicStringPlaintextWarning:
+ 'マジック文字列は慎重に共有してください。暗号化されていないパスワードが含まれます (エンコードは暗号化ではありません)。完全な文字列を持つ人は誰でもこのユーザーとしてサインインできます。',
+ userMgmtMagicStringCopied: 'マジック文字列をクリップボードにコピーしました。',
+ userMgmtMagicStringCopyFailed: 'クリップボードにコピーできませんでした。',
+ userMgmtMagicStringLoginFailed: 'パスワード確認に失敗しました。認証情報を検証できませんでした。',
+ userMgmtMagicStringModalTitle: 'マジック文字列を生成',
+ userMgmtMagicStringModalDesc: '"{{username}}" の Subsonic パスワードを入力してください。コピーされるマジック文字列に含まれます。',
+ userMgmtMagicStringModalConfirm: '文字列をコピー',
+ audiomuseTitle: 'AudioMuse-AI (Navidrome)',
+ audiomuseBadge: 'AudioMuse-AI',
+ audiomuseDesc:
+ 'このサーバーに AudioMuse-AI Navidrome プラグイン が設定されている場合にオンにしてください。トラックからのインスタントミックスを有効化し、アーティストページでは Last.fm の代わりにサーバー側の類似アーティストを使います。',
+ audiomuseStatusActive: '有効',
+ audiomuseStatusChecking: '確認中…',
+ audiomuseStatusNotDetected: '検出されません',
+ audiomuseStatusProbeFailed: '確認に失敗',
+ audiomuseIssueHint:
+ '最近インスタントミックスに失敗しました。Navidrome プラグインと AudioMuse API を確認してください。サーバーが類似アーティストを返さない場合は Last.fm にフォールバックします。',
+ connected: '接続済み',
+ failed: '失敗',
+ eqTitle: 'イコライザー',
+ eqEnabled: 'イコライザーを有効化',
+ eqPreset: 'プリセット',
+ eqPresetCustom: 'カスタム',
+ eqPresetBuiltin: '内蔵プリセット',
+ eqPresetCustomGroup: '自分のプリセット',
+ eqSavePreset: 'プリセットとして保存',
+ eqPresetName: 'プリセット名…',
+ eqDeletePreset: 'プリセットを削除',
+ eqResetBands: 'フラットに戻す',
+ eqPreGain: 'プリアンプ',
+ eqResetPreGain: 'プリアンプをリセット',
+ eqAutoEqTitle: 'AutoEQ ヘッドホン検索',
+ eqAutoEqPlaceholder: 'ヘッドホン / IEM モデルを検索…',
+ eqAutoEqSearching: '検索中…',
+ eqAutoEqNoResults: '結果が見つかりません',
+ eqAutoEqError: '検索に失敗しました',
+ eqAutoEqRateLimit: 'GitHub のレート制限に達しました。1 分後に再試行してください',
+ eqAutoEqFetchError: 'EQ プロファイルを取得できませんでした',
+ behavior: 'アプリ動作',
+ groupTray: 'トレイ',
+ groupLinuxRendering: 'Linux レンダリング',
+ groupClock: '時計',
+ groupDisplay: '表示',
+ groupWindow: 'ウィンドウ',
+ cacheTitle: '最大ストレージサイズ',
+ cacheDesc: 'カバーアートとアーティスト画像のブラウザー内キャッシュ (IndexedDB)。空き容量が少なくなると、古い項目が自動的に削除されます。',
+ cacheUsedImages: '画像:',
+ cacheUsedOffline: 'オフライントラック:',
+ cacheUsedHot: 'ディスク上のサイズ:',
+ hotCacheTrackCount: 'キャッシュ内トラック:',
+ cacheMaxLabel: '最大サイズ',
+ imageCacheScopeLabel: '範囲',
+ imageCacheSubTitle: 'ブラウザー内プレビュー',
+ coverDiskCacheSubTitle: 'ディスク上カバーキャッシュ',
+ coverCacheStrategyTitle: 'カバーアートキャッシュ',
+ coverCacheStrategyDesc: 'サーバーごとに戦略を選べます。Lazy は必要時にカバーを読み込みます。Aggressive は必要時読み込みに加えて、追加のバックグラウンドプリロードを行います。',
+ coverCacheStrategyLabel: '戦略',
+ coverCacheStrategyServerLabel: 'サーバー',
+ coverCacheStrategyProgressLabel: 'キャッシュ',
+ coverCacheStrategyActionsLabel: '操作',
+ coverCacheStrategyLazy: 'Lazy',
+ coverCacheStrategyLazyDesc: '必要になったときだけカバーを読み込みます。',
+ coverCacheStrategyAggressive: 'Aggressive',
+ coverCacheStrategyAggressiveDesc: 'Lazy の動作に加えて、追加のバックグラウンドプリロードを行います。',
+ coverCacheStrategyDiskUsage: 'ディスク上: {{size}}',
+ coverCacheStrategyProgressValue: '{{percent}}% ({{done}}/{{total}}) · {{size}}',
+ coverCacheStrategyClearAction: 'カバーキャッシュをクリア',
+ coverCacheStrategyClearTitle: 'カバーキャッシュをクリアしますか?',
+ coverCacheStrategyClearDesc: '{{server}} のキャッシュ済みカバー画像をすべて削除します。必要になったとき再ダウンロードされます。',
+ coverCacheStrategyClearConfirm: 'クリア',
+ coverCacheStrategyClearCancel: 'キャンセル',
+ coverCacheStrategyClearSuccess: 'このサーバーのカバーキャッシュをクリアしました。',
+ coverCacheStrategyClearError: 'カバーキャッシュをクリアできませんでした。',
+ coverCacheStrategyServerRemoved: '削除済みサーバー',
+ cacheClearBtn: 'キャッシュをクリア',
+ cacheClearWarning: 'ブラウザー内ストレージから、キャッシュ済みのカバー画像とアーティスト画像をすべて削除します。必要になったとき再ダウンロードされます。',
+ cacheClearConfirm: '画像キャッシュをクリア',
+ cacheClearCancel: 'キャンセル',
+ waveformCacheCleared: '波形キャッシュをクリアしました ({{count}} 行)。',
+ waveformCacheClearFailed: '波形キャッシュをクリアできませんでした。',
+ storageTabTitle: 'オフラインとキャッシュ',
+ mediaDirTitle: 'メディアフォルダー',
+ mediaDirDesc: 'ローカル再生のルートフォルダー。オフラインライブラリは library/、キュープリフェッチは cache/ を使います。',
+ mediaDirDefault: '既定 (アプリデータ)',
+ mediaDirChange: 'フォルダーを変更',
+ mediaDirClear: '既定に戻す',
+ mediaDirHint: '新しいダウンロードはこの場所を使います。既存ファイルは削除されるまで元のパスに残ります。',
+ offlineStorageTitle: 'オフラインライブラリストレージ',
+ offlineDirTitle: 'オフラインライブラリ (アプリ内)',
+ offlineDirDesc: 'Psysonic 内でオフライン利用可能にしたトラックの保存場所です。',
+ offlineDirDefault: '既定 (アプリデータ)',
+ offlineDirChange: 'ディレクトリを変更',
+ offlineDirClear: '既定に戻す',
+ offlineDirHint: '新しいダウンロードはこの場所を使います。既存のダウンロードは元のパスに残ります。',
+ hotCacheTitle: 'ホット再生キャッシュ',
+ hotCacheDisclaimer: '次に来るキュートラックを先読みし、直前のものを保持します。有効にすると、ディスク容量とネットワークを使用します。',
+ hotCacheDirDefault: '既定 (アプリデータ)',
+ hotCacheDirChange: 'フォルダーを変更',
+ hotCacheDirClear: '既定に戻す',
+ hotCacheDirHint: 'フォルダーを変更するとアプリ内インデックスはリセットされます。ディスク上の既存ファイルは削除するまで残ります。',
+ hotCacheEnabled: 'ホット再生キャッシュを有効化',
+ hotCacheMaxMb: '最大キャッシュサイズ',
+ hotCacheDebounce: 'キュー変更デバウンス',
+ hotCacheDebounceImmediate: '即時',
+ hotCacheDebounceSeconds: '{{n}} 秒',
+ hotCacheClearBtn: 'ホットキャッシュをクリア',
+ audioOutputDevice: '音声出力デバイス',
+ audioOutputDeviceDesc: 'Psysonic が再生に使う音声デバイスを選択します。変更は即時反映され、現在のトラックを再起動します。',
+ audioOutputDeviceDefault: 'システム既定',
+ audioOutputDeviceRefresh: 'デバイス一覧を更新',
+ audioOutputDeviceOsDefaultNow: '現在のシステム出力',
+ audioOutputDeviceListError: '音声デバイス一覧を読み込めませんでした。',
+ audioOutputDeviceNotInCurrentList: '現在の一覧にありません',
+ hiResTitle: 'ネイティブ Hi-Res 再生',
+ hiResEnabled: 'ネイティブ Hi-Res 再生を有効化',
+ hiResDesc: 'すべてを 44.1 kHz にリサンプリングせず、各トラックを元のサンプルレートで再生し、ファイルに合わせて音声デバイスを切り替えます (88.2 kHz 以上)。高サンプルレートをハードウェアとネットワークが安定して扱える場合のみ有効にしてください。',
+ showArtistImages: 'アーティスト画像を表示',
+ showArtistImagesDesc: 'アーティスト一覧でアーティスト画像を読み込んで表示します。大規模ライブラリでサーバーディスク I/O とネットワーク負荷を減らすため、既定では無効です。',
+ showOrbitTrigger: 'ヘッダーに "Orbit" を表示',
+ showOrbitTriggerDesc: '共有リスニングセッションを開始するか参加するためのトップバー操作です。Orbit を使わない場合は非表示にできます。ここで再度オンにできます。',
+ showTrayIcon: 'トレイアイコンを表示',
+ showTrayIconDesc: 'システム通知領域 / メニューバーに Psysonic アイコンを表示します。',
+ minimizeToTray: 'トレイへ最小化',
+ minimizeToTrayDesc: 'ウィンドウを閉じたとき、終了せずにシステムトレイで Psysonic を実行し続けます。',
+ clockFormat: '時計形式',
+ clockFormatDesc: 'キューの終了予定時刻とスリープタイマーのプレビューに使う時計表示です。',
+ clockFormatAuto: '自動 (システムロケール)',
+ clockFormatTwentyFour: '24 時間',
+ clockFormatTwelve: '12 時間 (AM/PM)',
+ preloadMiniPlayer: 'ミニプレイヤーをプリロード',
+ preloadMiniPlayerDesc: 'アプリ起動時にバックグラウンドでミニプレイヤーウィンドウを構築し、初回表示時に即座に内容を表示します。少しメモリを追加で使います。',
+ discordRichPresence: 'Discord Rich Presence',
+ discordRichPresenceDesc: '現在再生中のトラックを Discord プロフィールに表示します。Discord が起動している必要があります。',
+ discordRichPresenceNotice: '注意: これは Psysonic 内蔵の Discord Rich Presence です。公式 Navidrome Discord Rich Presence プラグインを使いたい場合は、これをオフのままにして、このページ下部の "Now Playing に表示" を有効にしてください。',
+ useCustomTitlebar: 'カスタムタイトルバー',
+ useCustomTitlebarDesc: 'システムタイトルバーを、アプリテーマに合う内蔵タイトルバーへ置き換えます。無効にするとネイティブ GNOME/GTK タイトルバーを使います。',
+ windowButtonStyle: 'ウィンドウボタン',
+ windowButtonStyleDesc: '最小化、最大化、閉じるボタンの見た目を選びます。',
+ windowButtonsDots: 'ドット',
+ windowButtonsDotsGlyph: 'ドット + アイコン',
+ windowButtonsFlat: 'フラット',
+ windowButtonsPill: 'ピル',
+ windowButtonsOutline: 'アウトライン',
+ windowButtonsGlyph: 'ミニマル',
+ showMinimizeButton: '最小化ボタンを表示',
+ showMinimizeButtonDesc: 'オフにすると、最大化と閉じるボタンだけを表示します。',
+ linuxWebkitSmoothScroll: 'スムーズホイール (Linux)',
+ linuxWebkitSmoothScrollDesc: 'オン: 慣性スクロール。オフ: GTK 風の行単位スクロール。',
+ linuxWebkitInputForceRepaint: 'フォーカス時に入力欄を再描画 (Linux)',
+ linuxWebkitInputForceRepaintDesc: 'クリック時にテキストフィールドが固まる WebKitGTK 2.50.x 向けの回避策です。フォーカス時に検索アイコンが一瞬ちらつきます。',
+ linuxWaylandTextRender: 'Wayland テキストレンダリング (Linux)',
+ linuxWaylandTextRenderDesc:
+ 'UI のフォントスムージングは即時更新されます。WebKit ハードウェアアクセラレーション (sharp / GPU プリセット) は保存され、次回起動時に適用されます。ライブ変更は一部環境で WebKitGTK を固めることがあります。',
+ linuxWaylandTextRenderBalanced: 'バランス',
+ linuxWaylandTextRenderSharp: 'シャープ (CPU に優しい)',
+ linuxWaylandTextRenderGpu: 'GPU 優先',
+ linuxWaylandTextRenderMinimal: '最小 (既定 CSS スムージング)',
+ discordCoverTitle: 'カバーアートのソース',
+ discordCoverDesc: 'Discord プロフィールに表示するアルバムアートの取得元です。',
+ discordCoverNone: 'なし (アプリアイコンのみ)',
+ discordCoverServer: 'サーバー (アルバム情報経由)',
+ discordCoverApple: 'Apple Music',
+ discordOptions: 'Discord 詳細オプション',
+ discordTemplates: 'カスタムテキストテンプレート',
+ discordTemplatesDesc: 'Discord プロフィールに表示する情報をカスタマイズします。変数: {title}, {artist}, {album}',
+ discordTemplateDetails: '主行 (details)',
+ discordTemplateState: '副行 (state)',
+ discordTemplateLargeText: 'アルバムツールチップ (largeText)',
+ discordTemplateName: 'ユーザー一覧行 (name)',
+ nowPlayingEnabled: 'Now Playing に表示',
+ nowPlayingEnabledDesc: '現在再生中のトラックをサーバーのライブリスナー表示へ送信します。再生データ送信を止めるには無効にしてください。',
+ nowPlayingPluginNote: '公式 Navidrome Discord Rich Presence プラグインを使う場合に必要です。',
+ enableBandsintown: 'Bandsintown ツアー日程',
+ enableBandsintownDesc: 'Info タブに現在のアーティストの今後の公演を表示します。データは公開 Bandsintown API から取得されます。',
+ lyricsServerFirst: 'サーバー歌詞を優先',
+ lyricsServerFirstDesc: 'LRCLIB に問い合わせる前に、サーバー提供の歌詞 (埋め込みタグ、サイドカーファイル) を確認します。LRCLIB を先に使うには無効にしてください。',
+ enableNeteaselyrics: 'Netease Cloud Music 歌詞',
+ enableNeteaselyricsDesc: 'サーバーと LRCLIB の両方が何も返さない場合の最後の歌詞ソースとして Netease Cloud Music を使います。アジア圏と国際音楽に強いです。',
+ lyricsSourcesTitle: '歌詞ソース',
+ lyricsSourcesDesc: '歌詞を問い合わせるソースと順序を選びます。ドラッグで並べ替えできます。無効なソースは完全にスキップされます。',
+ lyricsSourceServer: 'サーバー',
+ lyricsSourceLrclib: 'LRCLIB',
+ lyricsSourceNetease: 'Netease Cloud Music',
+ lyricsYouLyPlus: 'YouLyPlus (カラオケ)',
+ lyricsYouLyPlusDesc: 'コミュニティバックエンド (Apple Music, Spotify, Musixmatch, QQ) から単語単位の同期を取得します。最初に試行され、下の有効ソースはフォールバックとして動作します。',
+ lyricsSourcesFallbackHint: 'YouLyPlus が見つからない場合のフォールバックとして使用します。ドラッグで並べ替えできます。',
+ lyricsSourcesPrimaryHint: 'この順序で試行します。ドラッグで並べ替えできます。すべてオフ = 歌詞無効。',
+ lyricsStaticOnly: '歌詞を静的テキストのみで表示',
+ lyricsStaticOnlyDesc: '同期歌詞を自動スクロールなし、単語ハイライトなしで表示します。',
+ downloadsTitle: 'ZIP エクスポートとアーカイブ',
+ downloadsFolderDesc: 'アルバムを ZIP ファイルとしてコンピューターへダウンロードする保存先フォルダーです。',
+ downloadsDefault: '既定のダウンロードフォルダー',
+ pickFolder: '選択',
+ pickFolderTitle: 'ダウンロードフォルダーを選択',
+ clearFolder: 'ダウンロードフォルダーをクリア',
+ logout: 'ログアウト',
+ aboutTitle: 'Psysonic について',
+ aboutDesc: 'Navidrome 向けに作られた現代的なデスクトップ音楽プレイヤーです。Subsonic API と Navidrome 固有拡張を利用します。Tauri v2 とネイティブ Rust オーディオエンジン上に構築され、軽量で高速ながら、波形シークバー、同期歌詞、Last.fm 連携、10 バンド EQ、クロスフェード、ギャップレス再生、Replay Gain、ジャンルブラウズ、多数のテーマなどを備えています。',
+ aboutLicense: 'ライセンス',
+ aboutLicenseText: 'GNU GPL v3。同じライセンスのもとで自由に使用、変更、配布できます。',
+ aboutRepo: 'GitHub のソースコード',
+ aboutVersion: 'バージョン',
+ aboutBuiltWith: 'Tauri · React · TypeScript · Rust/rodio で構築',
+ aboutMaintainersLabel: 'メンテナー',
+ aboutReleaseNotesLabel: 'リリースノート',
+ aboutReleaseNotesLink: 'このバージョンの新機能を開く',
+ aboutContributorsLabel: 'コントリビューター',
+ showChangelogOnUpdate: '更新時に「新機能」を表示',
+ showChangelogOnUpdateDesc: '更新後、Now Playing の上に控えめな変更履歴バナーを表示します。クリックでリリースノートを開き、X で閉じます。',
+ libraryGridMaxColumnsTitle: 'ライブラリカードグリッド',
+ libraryGridMaxColumnsPerfHint: '値を大きくすると 1 行に多くのタイルを詰められますが、非常に大きなライブラリや遅いデバイスではレイアウトと描画負荷が増えます。',
+ libraryGridMaxColumnsRangeLabel: '最大列数 ({{min}}-{{max}})',
+ libraryGridMaxColumnsDesc: 'アルバム、アーティスト、プレイリスト、ラジオ、オフラインなど、カードベースのライブラリ表示に適用されます。小さい値ではタイルが大きくなり、通常は CPU に優しくなります。',
+ libraryIndexTitle: 'ローカルライブラリインデックス (プレビュー)',
+ libraryIndexDesc: '各サーバーのトラックデータベースをローカルに保持し、ブラウズと検索を高速化し、オフラインでも動作させます。初回同期は設定済みサーバーごとに実行され、オフラインサーバーは自動で再試行されます。',
+ libraryIndexDeltaHint: 'バックグラウンド差分同期はバインド済みサーバーを 30 秒ごとに確認し、期限が来たら実行します。通常はライブラリサイズと負荷により 5-45 分ごとです。',
+ libraryIndexEnable: 'ローカルライブラリインデックスを有効化',
+ libraryIndexEnableAllDesc: '設定済みサーバーすべてをバックグラウンドでインデックスし同期します。',
+ libraryIndexNoServer: '先にサーバーを追加してください。',
+ libraryIndexServerListTitle: 'インデックス対象サーバー',
+ libraryIndexAllExcluded: 'すべてのサーバーが同期から除外されています。インデックスを再度有効にするか、サーバーを追加してください。',
+ libraryIndexServerOffline: 'サーバーはオフラインです。同期を延期',
+ libraryIndexServerSyncing: '同期中…',
+ libraryIndexFullResync: '完全再同期',
+ libraryIndexDeltaSync: '差分同期',
+ libraryIndexExcludeServer: '同期から除外',
+ libraryIndexExcludingServer: '除外中…',
+ libraryIndexExcludedTitle: '同期から除外中',
+ libraryIndexIncludeServer: '再度含める',
+ libraryIndexIncludingServer: '追加中…',
+ libraryIndexStatus: '状態',
+ libraryIndexStatusIdle: '待機中',
+ libraryIndexStatusProbing: 'サーバー確認中…',
+ libraryIndexStatusInitial: '初回同期中…',
+ libraryIndexStatusReady: '準備完了 ({{count}} トラック)',
+ libraryIndexStatusError: 'エラー。ログを確認',
+ libraryIndexProgressIngest: '{{count}} トラックをインデックス中…',
+ libraryIndexProgressVerify: '{{checked}} 件を検証 ({{deleted}} 件削除)',
+ libraryIndexSyncNow: '今すぐ同期',
+ libraryIndexVerify: 'ライブラリ整合性を検証',
+ libraryIndexCancel: 'キャンセル',
+ libraryIndexAutoReconcile: '件数減少時に自動照合',
+ libraryIndexAutoReconcileDesc: 'サーバーが想定より少ない件数を報告したとき、削除済みトラックを自動確認します。',
+ libraryIndexSyncError: 'ライブラリ同期に失敗しました: {{error}}',
+ libraryIndexBindError: 'インデックスを有効にできませんでした: {{error}}',
+ analyticsStrategyTitle: '解析戦略',
+ analyticsStrategyDesc: 'ライブラリの解析方式を選びます。',
+ analyticsStrategyLabel: '戦略',
+ analyticsStrategyLazy: 'Lazy',
+ analyticsStrategyLazyDesc: 'トラックを再生するかホット/オフラインキャッシュに入ったときだけ解析します。CPU とネットワーク使用を最小化します。',
+ analyticsStrategyAdvanced: 'Aggressive',
+ analyticsStrategyAdvancedDesc: 'より積極的なバックグラウンドスキャンです。完了すると全トラックの BPM に加え、ラウドネスと波形が即時読み込みされます。',
+ analyticsStrategyPriorityTitle: '解析優先度 (常に適用)',
+ analyticsStrategyPriorityHigh: '1. 現在再生中: まずダウンロード + 解析 (再生バイト、ラウドネスバックフィル、必要時 HTTP)。',
+ analyticsStrategyPriorityMiddle: '2. 次に再生: キューの次 ~5 トラックとホットキャッシュ近傍。可能ならキャッシュ/ダウンロード済みバイトから解析し、不足時のみ HTTP バックフィル。',
+ analyticsStrategyPriorityLow: '3. ライブラリ一括 (Aggressive のみ): 末尾の自動バックグラウンドキュー。空キューを待たずウォーターマーク (~3× workers) で補充。',
+ analyticsStrategyServerLabel: 'サーバー',
+ analyticsStrategyProgressLabel: '解析進捗:',
+ analyticsStrategyProgressValue: '{{percent}}% ({{done}}/{{total}})',
+ analyticsStrategyActionsLabel: '操作',
+ analyticsStrategyParallelismLabel: '並列ワーカー',
+ analyticsStrategyParallelismValue: '{{n}} スレッド',
+ analyticsStrategyParallelismDesc: '同時にダウンロードして解析するトラック数 (HTTP + CPU)。値を大きくするとライブラリ追いつきは速くなりますが、ネットワークと CPU を多く使います。',
+ analyticsStrategyAdvancedWarning: 'Aggressive はライブラリ一括処理がバックグラウンドで動く間、CPU とネットワーク帯域を多く使います。',
+ analyticsStrategyServerRemoved: '削除済みサーバー',
+ analyticsStrategyClearAction: '解析をクリア',
+ analyticsStrategyClearTitle: '解析をクリアしますか?',
+ analyticsStrategyClearDesc: '{{server}} の解析をクリアすると、キャッシュ済み波形とラウドネスが削除されます。後でこのサーバーを再追加すると、長い再インデックスが必要になる場合があります。',
+ analyticsStrategyClearCancel: 'キャンセル',
+ analyticsStrategyClearConfirm: '解析をクリア',
+ analyticsStrategyClearSuccess: '削除済みサーバーの解析をクリアしました。',
+ analyticsStrategyClearError: '削除済みサーバーの解析をクリアできませんでした。',
+ analyticsStrategyProgressEmptyAfterFailed: '100% (0/0、失敗トラックにより停止)',
+ analyticsFailedTracksOpenTitle: '失敗トラック: {{count}}',
+ analyticsFailedTracksTitle: '解析失敗トラック: {{server}}',
+ analyticsFailedTracksDesc: 'これらのトラックはデコード/補強に繰り返し失敗し、自動バックグラウンド解析から除外されています。',
+ analyticsFailedTracksLoading: '失敗トラック一覧を読み込み中…',
+ analyticsFailedTracksEmpty: 'このサーバーに失敗トラックはありません。',
+ analyticsFailedTracksClose: '閉じる',
+ analyticsFailedTracksExport: '一覧をエクスポート',
+ analyticsFailedTracksExportSuccess: '失敗トラック一覧をエクスポートしました ({{count}})。',
+ analyticsFailedTracksExportError: '失敗トラック一覧をエクスポートできませんでした。',
+ analyticsFailedTracksRescan: '失敗トラックを再スキャン',
+ analyticsFailedTracksRescanSuccess: '{{count}} 件の失敗トラックの再スキャンを予約しました。',
+ analyticsFailedTracksRescanError: '失敗トラックを再スキャンできませんでした。',
+ analyticsFailedTracksLoadError: '失敗トラックを読み込めませんでした。',
+ randomMixTitle: 'ランダムミックスのブラックリスト',
+ luckyMixMenuTitle: 'Lucky Mix をメニューに表示',
+ luckyMixMenuDesc: 'Build a Mix 内と、分割ナビゲーションがオンのときの独立メニュー項目として Lucky Mix を有効にします。アクティブサーバーで AudioMuse が有効な場合のみ表示されます。',
+ randomMixBlacklistTitle: 'カスタムフィルターキーワード',
+ randomMixBlacklistDesc: 'キーワードがジャンル、タイトル、アルバム、アーティストのいずれかに一致すると曲を除外します (上のチェックボックスがオンのとき有効)。',
+ randomMixBlacklistPlaceholder: 'キーワードを追加…',
+ randomMixBlacklistAdd: '追加',
+ randomMixBlacklistEmpty: 'カスタムキーワードはまだ追加されていません。',
+ randomMixHardcodedTitle: '内蔵キーワード (チェックボックスがオンのとき有効)',
+ tabAudio: 'オーディオ',
+ tabStorage: 'オフラインとキャッシュ',
+ tabAppearance: '外観',
+ tabThemes: 'テーマ',
+ themesYourThemesTitle: 'あなたのテーマ',
+ themesCvdTooltip: '色覚バリアフリー: 2 型色覚、1 型色覚、3 型色覚',
+ themeAnimationWarning: 'このテーマは、環境によって CPU 使用率を上げる可能性のあるアニメーションを使用しています (Nvidia/Linux またはコンポジット無効時)。',
+ themeStoreTitle: 'テーマストア',
+ themeStoreSubmitText: '自作テーマがありますか?コミュニティと共有しましょう。詳細はテーマリポジトリにあります。',
+ themeStoreSubmitLink: 'テーマリポジトリを開く',
+ themeStoreNetworkNotice: 'テーマストアはカタログとプレビューを GitHub から読み込みます。個人データは送信されません。',
+ themeStoreStatsNotice: '最終変更日は 1 日 1 回更新されます (04:17 UTC 前後)。',
+ themeStoreSearchPlaceholder: 'テーマを検索…',
+ themeStoreFilterMode: 'モードで絞り込み',
+ themeStoreModeAll: 'すべて',
+ themeStoreModeDark: 'ダーク',
+ themeStoreModeLight: 'ライト',
+ themeStoreRefresh: '更新',
+ themeStoreLoading: 'テーマを読み込み中…',
+ themeStoreError: 'テーマストアを読み込めませんでした。接続を確認してください。',
+ themeStoreRetry: '再試行',
+ themeStoreOfflineTitle: 'テーマストアはオフラインです',
+ themeStoreEmpty: 'フィルターに一致するテーマはありません。',
+ themeStoreActive: '有効',
+ themeStoreEnlarge: 'プレビューを拡大',
+ themeStoreSortNewest: '新しい順',
+ themeStoreSortName: 'アルファベット順',
+ themeStoreAnimAll: 'すべて',
+ themeStoreAnimAnimated: 'アニメーション',
+ themeStoreAnimStatic: '静的',
+ themeStoreByAuthor: '{{author}} 作',
+ themeStoreLastChanged: '最終変更',
+ themeMigrationNoticeTitle: 'テーマはストアへ移動しました',
+ themeMigrationNoticeBody: '{{themes}} はアプリに同梱されなくなりました。テーマストア (設定 → テーマ) から再インストールするか、別のテーマを選んでください。',
+ themeMigrationNoticeOpen: 'テーマストアを開く',
+ themeStoreOffline: '最後にキャッシュしたカタログを表示しています。オフラインのようです。',
+ themeStoreInstall: 'インストール',
+ themeStoreInstalling: 'インストール中…',
+ themeStoreApply: '適用',
+ themeStoreUpdate: '更新',
+ themeStoreUpdating: '更新中…',
+ themeStoreUninstall: 'アンインストール',
+ themeStoreInstallFailed: 'インストールに失敗しました',
+ themeStorePagePrev: '前のページ',
+ themeStorePageNext: '次のページ',
+ themeStorePageStatus: '{{page}} / {{total}} ページ',
+ themeImportTitle: 'テーマをインポート',
+ themeImportButton: 'テーマをインポート…',
+ themeImporting: 'インポート中…',
+ themeImportHint: '.zip としてパッケージされたテーマを読み込みます (manifest.json + theme.css)。',
+ themeImportSuccess: '"{{name}}" をインポートしました。',
+ themeImportErrorTitle: 'このテーマはインポートできませんでした',
+ themeImportErrorBody: 'Psysonic のテーマ形式と一致しません。別バージョン向けに作られたか、ファイルが不完全な可能性があります。正しい .zip を選んだか確認するか、テーマ作者に問い合わせてください。',
+ themeImportErrorDetails: '技術的詳細',
+ themeImportConfirmTitle: 'テーマをインストールしますか?',
+ themeImportConfirmBody: '{{author}} 作 "{{name}}" をインストールしますか?',
+ themeImportConfirmRisk: 'インポートしたテーマはレビューされていません。信頼できるテーマだけをインストールしてください。',
+ tabLibrary: 'ライブラリ',
+ tabServers: 'サーバー',
+ tabLyrics: '歌詞',
+ tabPersonalisation: 'パーソナライズ',
+ tabIntegrations: '連携',
+ inputKeybindingsTitle: 'キーボードショートカット',
+ aboutContributorsCount_one: '{{count}} 件の貢献',
+ aboutContributorsCount_other: '{{count}} 件の貢献',
+ searchPlaceholder: '設定を検索…',
+ searchNoResults: '検索に一致する設定はありません。',
+ integrationsPrivacyTitle: 'プライバシー通知',
+ integrationsPrivacyBody: 'このタブのすべての連携は オプトイン であり、有効化すると外部サービスまたは Navidrome サーバーへデータを送信します。Last.fm は再生履歴を受け取り、Discord は現在再生中のトラックをプロフィールに表示し、Bandsintown はツアー日程取得のためアーティストごとに問い合わせ、Now-Playing 共有は現在のトラックを Navidrome サーバー上の他ユーザーへ公開します。不要な場合は、該当セクションを無効のままにしてください。',
+ homeCustomizerTitle: 'Mainstage',
+ queueSettingsTitle: 'キュー設定',
+ queueModeTitle: 'キュー表示モード',
+ queueModeQueueSub: '今後のトラックのみ表示します。現在のトラックはヘッダーに残り、再生済みになるとリストから外れます。',
+ queueModePlaylistSub: 'キュー全体をリストに残し、現在のトラックを上部で強調表示します。再生済みトラックも残ります。',
+ queueModeTimelineSub: '現在のトラックを中央に置き、上に再生履歴、下に今後のトラック (シャッフル順) を表示します。',
+ queueToolbarTitle: 'キューツールバー',
+ queueToolbarReset: '既定に戻す',
+ queueToolbarSeparator: '区切り',
+ sidebarTitle: 'サイドバー',
+ sidebarReset: '既定に戻す',
+ artistLayoutTitle: 'アーティストページのセクション',
+ artistLayoutDesc: 'ドラッグで並べ替え、切り替えでアーティストページの個別セクションを非表示にできます。データのないセクションは自動的にスキップされます。',
+ artistLayoutReset: '既定に戻す',
+ artistLayoutBio: 'アーティスト紹介',
+ artistLayoutTopTracks: '人気トラック',
+ artistLayoutSimilar: '類似アーティスト',
+ artistLayoutAlbums: 'アルバム',
+ artistLayoutFeatured: '参加作品',
+ playlistLayoutTitle: 'プレイリストページのレイアウト',
+ playlistLayoutDesc: 'プレイリストページ上の個別要素を表示または非表示にします。',
+ playlistLayoutReset: '既定に戻す',
+ playerBarTitle: 'プレイヤーバー',
+ playerBarReset: '既定に戻す',
+ playerBarStarRating: '星評価',
+ playerBarFavorite: 'お気に入り (ハート)',
+ playerBarLastfmLove: 'Love ボタン',
+ playerBarPlaybackRate: '再生速度',
+ playerBarEqualizer: 'イコライザー',
+ playerBarMiniPlayer: 'ミニプレイヤー',
+ playbackRateTitle: '再生速度',
+ playbackRateEnabled: '再生速度を有効化',
+ playbackRateEnabledDesc: 'すべてのトラックに対してグローバルに速度を変更します。ラジオやプレビューには適用されません。',
+ playbackRateStrategy: '戦略',
+ playbackRateStrategySpeed: '速度',
+ playbackRateStrategyVarispeed: 'バリスピード',
+ playbackRateStrategyVarispeedSemitones: '半音',
+ playbackRateStrategyPreserve: 'ピッチシフト',
+ playbackRateStrategySpeedTip: 'テンポを変更し、ピッチは自動補正されます。',
+ playbackRateStrategyVarispeedTip: 'テープのように速度とピッチが一緒に動きます。ピッチは速度に追従します: 12 × log2(speed)。',
+ playbackRateStrategyVarispeedSemitonesTip: 'バリスピードを半音単位で直接指定します。速度 = 2^(st/12)。',
+ playbackRateStrategyPreserveTip: '調整可能なテンポに手動ピッチオフセット (±12 st) を加えます。',
+ playbackRateSpeed: '速度',
+ playbackRatePitch: 'ピッチ',
+ playbackRateDerivedPitch: '速度からのピッチシフト: {{value}}',
+ playbackRateDerivedSpeed: '半音からの速度: {{value}}',
+ playbackRateFineStep: '細かい調整',
+ playbackRateFineStepDesc: 'スライダーの刻みを小さくします: 速度は 0.01×、ピッチは 0.01 st。',
+ playbackRateAutoPitch: 'ピッチは自動補正されます。',
+ playbackRateHint: 'Speed はピッチを自然に保ちます。Varispeed は速度に合わせてピッチも変えます。Varispeed (半音) はそのピッチ変化を半音単位で直接指定します。Pitch shift は手動オフセットを追加します。Varispeed より CPU を多く使います。ラジオ、プレビュー、Orbit には使われません。',
+ playbackRateNeutral: '1.0× でピッチオフセットなしの場合、通常再生です。',
+ playbackRateOrbitPaused: 'Orbit セッション中は適用されません。同期のため再生は 1.0× のままです。',
+ playbackRateOrbitPausedShort: 'Orbit: 同期のため 1.0×。',
+ advancedMode: '詳細',
+ advancedModeTooltip: 'すべての設定タブで詳細オプションを表示します。Psysonic メンテナーの設計思想を必ずしも反映しないコミュニティ貢献も含まれます。',
+ advancedBadge: '詳細',
+ sidebarDrag: 'ドラッグで並べ替え',
+ sidebarFixed: '常に表示',
+ nowPlayingTopTitle: 'Now Playing を上部に',
+ nowPlayingTopDesc: '"Now Playing" 項目をサイドバー下部ではなく上部に固定します。',
+ randomNavSplitTitle: 'ミックスナビゲーションを分割',
+ randomNavSplitDesc: '"ミックスを作成" ハブの代わりに、"ランダムミックス"、"ランダムアルバム"、"Lucky Mix" を個別のサイドバー項目として表示します。',
+ tabInput: '入力',
+ tabUsers: 'ユーザー',
+ tabSystem: 'システム',
+ loggingTitle: 'ログ',
+ loggingModeDesc: 'ターミナル内のバックエンドログ詳細度を制御します。',
+ loggingModeOff: 'オフ',
+ loggingModeNormal: '通常',
+ loggingModeDebug: 'デバッグ',
+ loggingExport: 'ログをエクスポート',
+ loggingExportSuccess: 'ログをエクスポートしました ({{count}} 行)。',
+ loggingExportError: 'ログをエクスポートできませんでした。',
+ ratingsSectionTitle: '評価',
+ ratingsSkipStarTitle: 'スキップで 1 つ星',
+ ratingsSkipStarDesc:
+ '連続して何度かスキップした後、トラックを 1★ に設定します。まだ評価されていないトラックのみ対象です。',
+ ratingsSkipStarThresholdLabel: 'スキップ',
+ ratingsMixFilterTitle: '評価で絞り込み',
+ ratingsMixFilterDesc:
+ '{{mix}} と {{albums}} で低評価項目を絞り込みます。選択中の星をもう一度クリックするとしきい値をオフにします。',
+ ratingsMixMinSong: '曲',
+ ratingsMixMinAlbum: 'アルバム',
+ ratingsMixMinArtist: 'アーティスト',
+ ratingsMixMinThresholdAria: '最小星数: {{label}}',
+ backupTitle: 'バックアップと復元',
+ backupExport: '設定をエクスポート',
+ backupExportDesc: 'すべての設定、サーバープロファイル、Last.fm 設定、テーマ、EQ、キーバインドを .psybkp ファイルへ保存します。パスワードは平文で保存されます。ファイルを安全に保管してください。',
+ backupImport: '設定をインポート',
+ backupImportDesc: '.psybkp ファイルから設定を復元します。インポート後にアプリはリロードされます。',
+ backupImportConfirm: '現在のすべての設定を上書きします。続行しますか?',
+ backupImportAny: 'バックアップをインポート',
+ backupImportAnyConfirm: '選択したバックアップファイルをインポートし、その内容 (設定、ライブラリデータベース、または完全) を適用します。続行しますか?',
+ backupSuccess: 'バックアップを保存しました',
+ backupImportSuccess: '設定を復元しました。リロード中…',
+ backupImportError: 'バックアップファイルが無効または破損しています。',
+ backupModeFull: '完全',
+ backupModeLibrary: 'ライブラリデータベース',
+ backupModeConfig: '設定',
+ backupFullDesc: '設定とライブラリデータベースを 1 つのバックアップファイルにまとめます。',
+ backupFullExport: '完全バックアップをエクスポート',
+ backupFullImport: '完全バックアップをインポート',
+ backupFullImportConfirm: '設定を上書きし、現在のライブラリデータベースを置き換えて .bak へ移動します。続行しますか?',
+ backupFullExportSuccess: '完全バックアップをエクスポートしました。',
+ backupFullImportSuccess: '完全バックアップをインポートしました。リロード中…',
+ backupFullImportError: '完全バックアップをインポートできませんでした。',
+ backupLibraryExport: 'データベースをエクスポート',
+ backupLibraryExportDesc: 'ライブラリデータベースのクリーンな SQLite スナップショットを含む圧縮アーカイブを作成します。',
+ backupLibraryImport: 'データベースをインポート',
+ backupLibraryImportDesc: 'アーカイブファイルからライブラリデータベースを復元します。切り替え前に現在のデータベースは .bak へ移動されます。',
+ backupLibraryImportConfirm: '現在のライブラリデータベースを置き換え、.bak へ移動します。続行しますか?',
+ backupLibraryExportSuccess: 'データベースバックアップをエクスポートしました。',
+ backupLibraryImportSuccess: 'データベースバックアップをインポートしました。',
+ backupLibraryImportError: 'データベースバックアップをインポートできませんでした。',
+ backupOverlayExportTitle: 'バックアップを作成中…',
+ backupOverlayImportTitle: 'バックアップを復元中…',
+ backupOverlayHint: '処理中もウィンドウを開いたままにできます。入力は一時的にロックされます。',
+ shortcutsReset: '既定に戻す',
+ shortcutListening: 'キーを押してください…',
+ shortcutUnbound: '—',
+ globalShortcutsTitle: 'グローバルショートカット',
+ globalShortcutsNote: 'Psysonic がバックグラウンドや最小化中でもシステム全体で動作します。修飾キーとして Ctrl、Alt、Super のいずれかが必要です。',
+ shortcutClear: 'クリア',
+ shortcutPlayPause: '再生 / 一時停止',
+ shortcutNext: '次のトラック',
+ shortcutPrev: '前のトラック',
+ shortcutVolumeUp: '音量を上げる',
+ shortcutVolumeDown: '音量を下げる',
+ shortcutSeekForward: '10 秒進む',
+ shortcutSeekBackward: '10 秒戻る',
+ shortcutToggleQueue: 'キューを切り替え',
+ shortcutOpenFolderBrowser: '{{folderBrowser}} を開く',
+ shortcutFullscreenPlayer: 'フルスクリーンプレイヤー',
+ shortcutNativeFullscreen: 'ネイティブフルスクリーン',
+ shortcutOpenMiniPlayer: 'ミニプレイヤーを開く',
+ shortcutStartSearch: '検索を開始',
+ shortcutStartAdvancedSearch: '詳細検索を開始',
+ shortcutToggleSidebar: 'サイドバーを切り替え',
+ shortcutMuteSound: '音をミュート',
+ shortcutToggleEqualizer: 'イコライザーを開く / 切り替え',
+ shortcutToggleRepeat: 'リピートを切り替え',
+ shortcutOpenNowPlaying: '"Now Playing" を開く',
+ shortcutShowLyrics: '歌詞を表示',
+ shortcutFavoriteCurrentTrack: '現在のトラックをお気に入りに追加',
+ shortcutOpenHelp: 'ヘルプ',
+ playbackTitle: '再生',
+ replayGain: 'Replay Gain',
+ replayGainDesc: 'ReplayGain メタデータを使ってトラック音量を正規化',
+ replayGainMode: 'モード',
+ replayGainAuto: '自動',
+ replayGainAutoDesc: '隣接するキュートラックが同じアルバム由来ならアルバムゲイン、それ以外はトラックゲインを選びます。',
+ replayGainTrack: 'トラック',
+ replayGainAlbum: 'アルバム',
+ replayGainPreGain: 'プリアンプ (タグ付きファイル)',
+ replayGainPreGainDesc: 'すべての ReplayGain 計算に追加する共通ブーストです。ライブラリ全体が小さく感じる場合の補正に使います。',
+ replayGainFallback: 'フォールバック (未タグ / ラジオ)',
+ replayGainFallbackDesc: 'ReplayGain タグがまったくないトラック (およびラジオストリーム) に適用し、未タグ音源が他より大きく飛び出さないようにします。',
+ normalization: '正規化',
+ normalizationDesc: 'トラック、アルバム、ラジオ間の知覚ラウドネスをそろえます。',
+ normalizationOff: 'オフ',
+ normalizationReplayGain: 'ReplayGain',
+ normalizationLufs: 'LUFS',
+ loudnessTargetLufs: 'ターゲット LUFS',
+ loudnessTargetLufsDesc: 'すべてのトラックを合わせる基準ラウドネスです。数値が低いほど出力は大きくなります。ストリーミングサービスは通常 -14 LUFS 前後です。',
+ loudnessPreAnalysisAttenuation: '解析前の減衰',
+ loudnessPreAnalysisAttenuationDesc:
+ 'このトラックのラウドネスが保存されるまで追加で静かにします。ストリーミングでは完全測定ではなく粗い推定を使います。0 dB = オフ、低いほど静かです。右の数値は現在のターゲットに対する有効 dB です。',
+ loudnessPreAnalysisAttenuationRef: 'ターゲット {{tgt}} LUFS で有効 {{eff}} dB。',
+ loudnessPreAnalysisAttenuationReset: '既定に戻す',
+ loudnessFirstPlayNote:
+ '新しいトラックの初回再生では、測定中に音量が短時間ずれる場合があります。次回再生ではキャッシュ済み測定を使うため安定します。次のキュートラックは通常、前の曲の再生中に事前解析されるため、実際にはまれです。',
+ crossfade: 'クロスフェード',
+ crossfadeSecs: '{{n}} 秒',
+ autoDj: 'AutoDJ',
+ autoDjDesc: '固定時間ではありません。AutoDJ は実際の音声に追従し、秒数固定ではなく本物のフェードアウトとイントロをブレンドします。安定した結果にはホット再生キャッシュを有効にしてください。',
+ autodjSmoothSkip: 'スムーズスキップ',
+ autodjSmoothSkipDesc: '再生中に次または前のトラックへスキップすると、突然切り替えず、現在位置から同じ AutoDJ ルール (重なり長、イントロトリム) でブレンドします。次のトラックがすでにバッファ済みだと最も安定します。',
+ gapless: 'ギャップレス再生',
+ transitionsTitle: 'トラック遷移',
+ transitionsDesc: '連続するトラックのつなぎ方です。一度に有効にできるモードは 1 つだけです。',
+ transitionOff: 'オフ',
+ queueBehaviourTitle: 'キューの動作',
+ preservePlayNextOrder: '"次に再生" の順序を保持',
+ preservePlayNextOrderDesc: '新しく追加された "次に再生" 項目を、先に追加されたものの前へ割り込ませず後ろに並べます。',
+ trackPreviewsTitle: 'トラックプレビュー',
+ trackPreviewsToggle: 'トラックプレビューを有効化',
+ trackPreviewsDesc: 'トラックリスト内に再生 / プレビューボタンを表示し、曲の途中をすばやく試聴します。',
+ trackPreviewStart: '開始位置',
+ trackPreviewStartDesc: 'プレビューをトラックのどの位置から開始するか (% of track length)。',
+ trackPreviewDuration: '長さ',
+ trackPreviewDurationDesc: '各プレビューを停止するまでの再生時間です。',
+ trackPreviewDurationSecs: '{{n}} 秒',
+ trackPreviewLocationsTitle: 'プレビューを表示する場所',
+ trackPreviewLocationsDesc: 'インラインプレビューボタンを表示するリストを選びます。',
+ trackPreviewLocation_suggestions: 'プレイリスト候補',
+ trackPreviewLocation_albums: 'アルバムのトラックリスト',
+ trackPreviewLocation_playlists: 'プレイリスト',
+ trackPreviewLocation_favorites: 'お気に入り',
+ trackPreviewLocation_artist: 'アーティストの人気トラック',
+ trackPreviewLocation_randomMix: 'ランダムミックス',
+ nextTrackBufferingTitle: 'バッファリング',
+ infiniteQueue: '無限キュー',
+ infiniteQueueDesc: 'キューが尽きたときランダムトラックを自動追加します',
+ experimental: '実験的',
+ sidebarLyricsStyle: '歌詞スクロール形式',
+ sidebarLyricsStyleClassic: 'クラシック',
+ sidebarLyricsStyleClassicDesc: 'アクティブ行を中央へスクロールします。',
+ sidebarLyricsStyleApple: 'Apple Music 風',
+ sidebarLyricsStyleAppleDesc: 'アクティブ行を上部付近に固定し、滑らかなスプリング遷移を使います。',
+ seekbarStyle: 'シークバー形式',
+ seekbarStyleDesc: 'プレイヤーシークバーの見た目を選びます',
+ seekbarTruewave: 'Truewave',
+ seekbarPseudowave: 'Pseudowave',
+ seekbarLinedot: 'Line & Dot',
+ seekbarBar: 'Bar',
+ seekbarThick: 'Thick Bar',
+ seekbarSegmented: 'Segmented',
+ seekbarNeon: 'Neon Glow',
+ seekbarPulsewave: 'Pulse Wave',
+ seekbarParticletrail: 'Particle Trail',
+ seekbarLiquidfill: 'Liquid Fill',
+ seekbarRetrotape: 'Retro Tape',
+ themeSchedulerTitle: 'テーマ自動切り替え',
+ themeSchedulerEnable: 'テーマスケジューラーを有効化',
+ themeSchedulerEnableSub: '時刻に基づいて 2 つのテーマを自動で切り替えます',
+ themeSchedulerDayTheme: '昼テーマ',
+ themeSchedulerDayStart: '昼の開始時刻',
+ themeSchedulerNightTheme: '夜テーマ',
+ themeSchedulerNightStart: '夜の開始時刻',
+ themeSchedulerActiveHint: 'テーマスケジューラーが有効です。テーマ変更は自動で管理されます。',
+ visualOptionsTitle: '表示オプション',
+ coverArtBackground: 'カバーアート背景',
+ coverArtBackgroundSub: 'アルバム/プレイリストヘッダーの背景にぼかしたカバーアートを表示',
+ playlistCoverPhoto: 'プレイリストカバー写真',
+ playlistCoverPhotoSub: 'プレイリスト詳細ビューにカバー写真グリッドを表示',
+ showBitrate: 'ビットレートを表示',
+ showBitrateSub: 'トラック一覧に音声ビットレートを表示',
+ floatingPlayerBar: 'フローティングプレイヤーバー',
+ floatingPlayerBarSub: 'コンテンツの上にプレイヤーバーを浮かせて表示',
+ uiScaleTitle: 'インターフェース倍率',
+ uiScaleLabel: 'ズーム',
+};
diff --git a/src/locales/ja/sharePaste.ts b/src/locales/ja/sharePaste.ts
new file mode 100644
index 00000000..d21842de
--- /dev/null
+++ b/src/locales/ja/sharePaste.ts
@@ -0,0 +1,20 @@
+export const sharePaste = {
+ notLoggedIn: '共有リンクを貼り付ける前にサインインしてサーバーを追加してください。',
+ noMatchingServer: 'このリンクに一致する保存済みサーバーがありません。このアドレスのサーバーを追加してください: {{url}}',
+ trackUnavailable: 'このトラックはサーバー上で見つかりませんでした。',
+ albumUnavailable: 'このアルバムはサーバー上で見つかりませんでした。',
+ artistUnavailable: 'このアーティストはサーバー上で見つかりませんでした。',
+ composerUnavailable: 'この作曲者はサーバー上で見つかりませんでした。',
+ openedTrack: '共有トラックを再生しています。',
+ openedAlbum: '共有アルバムを開いています。',
+ openedArtist: '共有アーティストを開いています。',
+ openedComposer: '共有作曲者を開いています。',
+ openedQueue_one: '共有リンクから {{count}} 曲を再生しています。',
+ openedQueue_other: '共有リンクから {{count}} 曲を再生しています。',
+ openedQueuePartial:
+ 'リンク内の {{total}} 曲中 {{played}} 曲を再生しています ({{skipped}} 曲はこのサーバーで見つかりませんでした)。',
+ queueAllUnavailable: 'このリンク内のトラックはどれもサーバー上で見つかりませんでした。',
+ playQueue: '再生キュー',
+ playQueueing: '再生を開始中…',
+ genericError: '共有リンクを開けませんでした。',
+};
diff --git a/src/locales/ja/sidebar.ts b/src/locales/ja/sidebar.ts
new file mode 100644
index 00000000..1e6cb0ca
--- /dev/null
+++ b/src/locales/ja/sidebar.ts
@@ -0,0 +1,45 @@
+export const sidebar = {
+ library: 'ライブラリ',
+ mainstage: 'Mainstage',
+ newReleases: '新着リリース',
+ allAlbums: 'すべてのアルバム',
+ randomAlbums: 'ランダムアルバム',
+ randomPicker: 'ミックスを作成',
+ artists: 'アーティスト',
+ composers: '作曲者',
+ randomMix: 'ランダムミックス',
+ favorites: 'お気に入り',
+ nowPlaying: 'Now Playing',
+ system: 'システム',
+ statistics: '統計',
+ settings: '設定',
+ help: 'ヘルプ',
+ expand: 'サイドバーを展開',
+ collapse: 'サイドバーを折りたたむ',
+
+ downloadingTracks: '{{n}} 曲をキャッシュ中…',
+ offlinePinActive: '«{{name}}» をキャッシュ中…',
+ offlinePinActiveQueued: '«{{name}}» をキャッシュ中 · +{{queued}} 件キュー',
+ syncingTracks: '{{done}}/{{total}} を同期中…',
+ cancelDownload: 'ダウンロードをキャンセル',
+ offlineLibrary: 'オフラインライブラリ',
+ genres: 'ジャンル',
+ tracks: 'トラック',
+ playlists: 'プレイリスト',
+ smartPlaylists: 'スマートプレイリスト',
+ mostPlayed: 'よく再生',
+ losslessAlbums: 'ロスレス',
+ radio: 'インターネットラジオ',
+ folderBrowser: 'フォルダーブラウザー',
+ deviceSync: 'デバイス同期',
+ libraryScope: 'ライブラリ範囲',
+ allLibraries: 'すべてのライブラリ',
+ expandPlaylists: 'プレイリストを展開',
+ collapsePlaylists: 'プレイリストを折りたたむ',
+ more: 'その他',
+ feelingLucky: 'Lucky Mix',
+
+ themeUpdatesTitle: 'テーマアップデート',
+ themeUpdatesTooltip: 'テーマアップデートがあります',
+ themeUpdatesDismiss: '閉じる',
+};
diff --git a/src/locales/ja/smartPlaylists.ts b/src/locales/ja/smartPlaylists.ts
new file mode 100644
index 00000000..ca56c2a7
--- /dev/null
+++ b/src/locales/ja/smartPlaylists.ts
@@ -0,0 +1,41 @@
+export const smartPlaylists = {
+ sectionBasic: '1. 基本',
+ sectionGenres: '2. ジャンル',
+ sectionYearsAndFilters: '3. 年とフィルター',
+ genreMode: 'ジャンルモード',
+ genreModeInclude: 'ジャンルを含める',
+ genreModeExclude: 'ジャンルを除外',
+ genreSearchPlaceholder: 'ジャンルを絞り込み…',
+ availableGenres: '利用可能',
+ selectedGenres: '選択済み',
+ yearMode: '年モード',
+ yearModeInclude: '範囲を含める',
+ yearModeExclude: '範囲を除外',
+ name: '名前 (接頭辞なし)',
+ limit: '上限',
+ limitHint: 'プレイリストに含めるトラック数 (1-{{max}}、通常は 50)。',
+ artistContains: 'アーティストに含む…',
+ albumContains: 'アルバムに含む…',
+ titleContains: 'タイトルに含む…',
+ minRating: '最小評価',
+ minRatingAria: 'スマートプレイリストの最小評価',
+ minRatingHint: '0 で最小しきい値を無効化。1-5 は選択値以上の評価のトラックを残します。',
+ fromYear: '開始年',
+ toYear: '終了年',
+ excludeUnrated: '未評価トラックを除外',
+ compilationOnly: 'コンピレーションのみ',
+ create: '新規スマートプレイリスト',
+ save: 'スマートプレイリストを保存',
+ created: '{{name}} を作成しました',
+ updated: '{{name}} を更新しました',
+ createFailed: 'スマートプレイリストを作成できませんでした。',
+ updateFailed: 'スマートプレイリストを更新できませんでした。',
+ navidromeOnly: 'スマートプレイリストは Navidrome サーバーでのみ作成できます。',
+ loadFailed: 'Navidrome からスマートプレイリストを読み込めませんでした。',
+ sortRandom: '並び順: ランダム',
+ sortTitleAsc: '並び順: タイトル A-Z',
+ sortTitleDesc: '並び順: タイトル Z-A',
+ sortYearDesc: '並び順: 年 降順',
+ sortYearAsc: '並び順: 年 昇順',
+ sortPlayCountDesc: '並び順: 再生数 降順',
+};
diff --git a/src/locales/ja/songInfo.ts b/src/locales/ja/songInfo.ts
new file mode 100644
index 00000000..3ba54967
--- /dev/null
+++ b/src/locales/ja/songInfo.ts
@@ -0,0 +1,27 @@
+export const songInfo = {
+ title: '曲情報',
+ songTitle: 'タイトル',
+ artist: 'アーティスト',
+ album: 'アルバム',
+ albumArtist: 'アルバムアーティスト',
+ year: '年',
+ genre: 'ジャンル',
+ duration: '長さ',
+ track: 'トラック',
+ bpm: 'BPM',
+ mood: 'ムード',
+ playCount: '再生数',
+ lastPlayed: '最終再生',
+ format: '形式',
+ bitrate: 'ビットレート',
+ sampleRate: 'サンプルレート',
+ bitDepth: 'ビット深度',
+ channels: 'チャンネル',
+ fileSize: 'ファイルサイズ',
+ path: 'パス',
+ replayGainTrack: 'RG トラックゲイン',
+ replayGainAlbum: 'RG アルバムゲイン',
+ replayGainPeak: 'RG トラックピーク',
+ mono: 'モノラル',
+ stereo: 'ステレオ',
+};
diff --git a/src/locales/ja/statistics.ts b/src/locales/ja/statistics.ts
new file mode 100644
index 00000000..66efbe0b
--- /dev/null
+++ b/src/locales/ja/statistics.ts
@@ -0,0 +1,93 @@
+export const statistics = {
+ title: '統計',
+ recentlyPlayed: '最近再生',
+ mostPlayed: 'よく再生したアルバム',
+ highestRated: '高評価アルバム',
+ genreDistribution: 'ジャンル分布 (上位 20)',
+ loadMore: 'さらに読み込む',
+ statArtists: 'アーティスト',
+ statArtistsTooltip: 'アルバムアーティストのみ。自分のアルバムがなく、トラック単位のアーティスト (フィーチャリング、ゲストなど) としてのみ登場するアーティストは含まれません。',
+ statAlbums: 'アルバム',
+ statSongs: '曲',
+ statGenres: 'ジャンル',
+ statPlaytime: '総再生時間',
+ genreInsights: 'ジャンル分析',
+ formatDistribution: '形式分布',
+ formatSample: '{{n}} 曲のサンプル',
+ computing: '計算中…',
+ genreSongs: '{{count}} 曲',
+ genreAlbums: '{{count}} 枚のアルバム',
+ recentlyAdded: '最近追加',
+ decadeDistribution: '年代別アルバム',
+ decadeAlbums_one: '{{count}} 枚のアルバム',
+ decadeAlbums_other: '{{count}} 枚のアルバム',
+ decadeUnknown: '不明',
+ lfmTitle: '{{provider}} 統計',
+ lfmTopArtists: 'トップアーティスト',
+ lfmTopAlbums: 'トップアルバム',
+ lfmTopTracks: 'トップトラック',
+ lfmPlays: '{{count}} 回再生',
+ lfmPeriodOverall: '全期間',
+ lfmPeriod7day: '7 日',
+ lfmPeriod1month: '1 か月',
+ lfmPeriod3month: '3 か月',
+ lfmPeriod6month: '6 か月',
+ lfmPeriod12month: '12 か月',
+ lfmRecentTracks: '最近の scrobble',
+ lfmNowPlaying: '再生中',
+ lfmJustNow: 'たった今',
+ lfmMinutesAgo: '{{n}} 分前',
+ lfmHoursAgo: '{{n}} 時間前',
+ lfmDaysAgo: '{{n}} 日前',
+ topRatedSongs: '高評価の曲',
+ topRatedArtists: '高評価のアーティスト',
+ noRatedSongs: '評価済みの曲はまだありません。アルバムまたはプレイリスト表示で曲を評価してください。',
+ noRatedArtists: '評価済みのアーティストはまだありません。',
+ exportShare: '共有',
+ exportTitle: 'トップアルバムを共有',
+ exportSubtitle: 'よく再生したアルバムの共有用画像を生成します。',
+ exportFormat: '形式',
+ exportFormatStory: 'ストーリー',
+ exportFormatSquare: '正方形',
+ exportFormatTwitter: 'Twitter カード',
+ exportGrid: 'グリッド',
+ exportGridLabel: '{{n}}×{{n}}',
+ exportPreview: 'プレビュー',
+ exportGenerate: '生成',
+ exportSave: '画像を保存…',
+ exportCancel: 'キャンセル',
+ exportFooterLabel: 'トップアルバム',
+ exportNotEnough: '{{n}}×{{n}} グリッドにはライブラリ内に少なくとも {{count}} 枚のアルバムが必要です。',
+ exportSaving: '保存中…',
+ exportSaved: '保存しました。',
+ exportSaveFailed: '画像を保存できませんでした。',
+ tabServer: 'サーバー統計',
+ tabPlayer: 'プレイヤー統計',
+ playerEmpty: '聴き始めると、ローカルの再生履歴がここに表示されます。',
+ playerSummaryTime: 'リスニング時間',
+ playerListeningDayShort: '{{count}}日',
+ playerListeningHourShort: '{{count}}時間',
+ playerListeningMinuteShort: '{{count}}分',
+ playerSummarySessions: 'セッション',
+ playerSummaryTracks: 'トラック再生',
+ playerSummaryUniqueTracks: 'ユニークトラック',
+ playerSummaryDays: '日数',
+ playerIndexRequired: 'プレイヤー統計には少なくとも 1 つの設定済みサーバーが必要です。',
+ playerPartialIndexSettings: 'サーバー設定',
+ playerSummaryCompletion: '完了 / 部分',
+ playerYearPrev: '前年',
+ playerYearNext: '翌年',
+ playerHeatmapLegend: '色が濃いセルほど、その日に再生したトラックが多いことを示します。',
+ playerHeatmapLess: '少ない',
+ playerHeatmapMore: '多い',
+ playerDaySessions: '{{count}} セッション',
+ playerDayTrackPlays: '{{count}} 曲',
+ playerDayFullPartial: '{{full}} 完了 · {{partial}} 部分',
+ playerRecentDaysTitle: '最近の日',
+ playerDayToday: '今日',
+ playerDayYesterday: '昨日',
+ playerListenedSecShort: '{{seconds}}秒',
+ playerListenedMinDecimal: '{{minutes}} 分',
+ completionFull: '最後まで再生',
+ completionPartial: '部分再生',
+};
diff --git a/src/locales/ja/tracks.ts b/src/locales/ja/tracks.ts
new file mode 100644
index 00000000..3b11ca58
--- /dev/null
+++ b/src/locales/ja/tracks.ts
@@ -0,0 +1,16 @@
+export const tracks = {
+ title: 'トラック',
+ subtitle: 'ブラウズ。検索。発見。',
+ heroEyebrow: '今のトラック',
+ heroReroll: '別の曲を選ぶ',
+ playSong: '再生',
+ enqueueSong: 'キューに追加',
+ toAlbum: 'アルバムへ',
+ railRandom: 'ランダムピック',
+ railHighlyRated: '高評価',
+ browseTitle: 'すべてのトラックをブラウズ',
+ browseUnsupported: 'このサーバーはライブラリ全体を一度に一覧できません。上の検索で特定のトラックを探してください。',
+ searchPlaceholder: 'タイトル、アーティスト、アルバムでトラックを検索…',
+ count_one: '{{count}} 曲',
+ count_other: '{{count}} 曲',
+};
diff --git a/src/locales/ja/tray.ts b/src/locales/ja/tray.ts
new file mode 100644
index 00000000..1ac95978
--- /dev/null
+++ b/src/locales/ja/tray.ts
@@ -0,0 +1,8 @@
+export const tray = {
+ playPause: '再生 / 一時停止',
+ nextTrack: '次のトラック',
+ previousTrack: '前のトラック',
+ showHide: '表示 / 非表示',
+ exitPsysonic: 'Psysonic を終了',
+ nothingPlaying: '何も再生されていません',
+};
diff --git a/src/locales/ja/whatsNew.ts b/src/locales/ja/whatsNew.ts
new file mode 100644
index 00000000..22e453a5
--- /dev/null
+++ b/src/locales/ja/whatsNew.ts
@@ -0,0 +1,12 @@
+export const whatsNew = {
+ title: '新機能',
+ changelogTitle: '変更履歴',
+ viewTabsLabel: 'リリースノート表示',
+ viewHighlights: 'ハイライト',
+ viewChangelog: '変更履歴',
+ empty: 'このバージョンの変更履歴はまだありません。',
+ bannerTitle: '変更履歴',
+ bannerCollapsed: 'v{{version}} の新機能',
+ dismiss: '閉じる',
+ close: '閉じる',
+};
diff --git a/src/locales/nb/settings.ts b/src/locales/nb/settings.ts
index ee9393fe..beebd22f 100644
--- a/src/locales/nb/settings.ts
+++ b/src/locales/nb/settings.ts
@@ -10,6 +10,7 @@ export const settings = {
languageRu: 'Русский',
languageZh: '中文',
languageRo: 'Română',
+ languageJa: '日本語',
font: 'Skrifttype',
fontHintOpenDyslexic: 'Dyslexivennlig · ingen kinesisk støtte',
theme: 'Tema',
diff --git a/src/locales/nl/settings.ts b/src/locales/nl/settings.ts
index 3adc8eed..ceead3fa 100644
--- a/src/locales/nl/settings.ts
+++ b/src/locales/nl/settings.ts
@@ -10,6 +10,7 @@ export const settings = {
languageRu: 'Русский',
languageZh: '中文',
languageRo: 'Română',
+ languageJa: '日本語',
font: 'Lettertype',
fontHintOpenDyslexic: 'Dyslexie-vriendelijk · geen Chinese ondersteuning',
theme: 'Thema',
diff --git a/src/locales/ro/settings.ts b/src/locales/ro/settings.ts
index 12e01a0c..2ad8ad21 100644
--- a/src/locales/ro/settings.ts
+++ b/src/locales/ro/settings.ts
@@ -10,6 +10,7 @@ export const settings = {
languageRu: 'Rusă',
languageEs: 'Spaniolă',
languageRo: 'Română',
+ languageJa: '日本語',
font: 'Font',
fontHintOpenDyslexic: 'Prietenos cu dislexia · Chineza nu este suportată',
theme: 'Temă',
diff --git a/src/locales/ru/settings.ts b/src/locales/ru/settings.ts
index 9bf821db..e7905161 100644
--- a/src/locales/ru/settings.ts
+++ b/src/locales/ru/settings.ts
@@ -10,6 +10,7 @@ export const settings = {
languageRu: 'Русский',
languageZh: '中文',
languageRo: 'Română',
+ languageJa: '日本語',
font: 'Шрифт',
fontHintOpenDyslexic: 'Подходит для дислексии · без поддержки китайского',
theme: 'Тема',
diff --git a/src/locales/zh/settings.ts b/src/locales/zh/settings.ts
index 1c90d816..2f8b5450 100644
--- a/src/locales/zh/settings.ts
+++ b/src/locales/zh/settings.ts
@@ -10,6 +10,7 @@ export const settings = {
languageRu: 'Русский',
languageZh: '中文',
languageRo: 'Română',
+ languageJa: '日本語',
font: '字体',
fontHintOpenDyslexic: '阅读障碍友好 · 不支持中文',
theme: '主题',
diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx
index dcdce10c..fa687d92 100644
--- a/src/pages/Login.tsx
+++ b/src/pages/Login.tsx
@@ -245,6 +245,7 @@ export default function Login() {
{ value: 'nb', label: t('settings.languageNb') },
{ value: 'ru', label: t('settings.languageRu') },
{ value: 'zh', label: t('settings.languageZh') },
+ { value: 'ja', label: t('settings.languageJa') },
]}
/>