From 5f83008ec0ab6c7316b094cc195da0f6a87d16c2 Mon Sep 17 00:00:00 2001 From: Azalea <22280294+hykilpikonna@users.noreply.github.com> Date: Sun, 23 Nov 2025 00:50:53 +0800 Subject: [PATCH] [+] Japanese --- src/app.d.ts | 2 +- src/hooks.server.ts | 4 +- src/lib/i18n/index.ts | 6 +- src/lib/i18n/ja.ts | 130 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 src/lib/i18n/ja.ts diff --git a/src/app.d.ts b/src/app.d.ts index 6ef9db7..518120a 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -4,7 +4,7 @@ declare global { namespace App { // interface Error {} interface Locals { - lang: 'en' | 'zh' + lang: 'en' | 'zh' | 'ja' } // interface PageData {} // interface PageState {} diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 3cadebf..4eb73fe 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -5,7 +5,7 @@ checkAudioSeparator().catch(e => console.error('Audio separator check failed:', export const handle: Handle = async ({ event, resolve }) => { const langCookie = event.cookies.get('lang'); - if (langCookie === 'zh' || langCookie === 'en') { + if (langCookie === 'zh' || langCookie === 'en' || langCookie === 'ja') { event.locals.lang = langCookie; } else { const acceptLanguage = event.request.headers.get('accept-language'); @@ -14,6 +14,8 @@ export const handle: Handle = async ({ event, resolve }) => { // For now, let's assume if 'zh' is in the header, the user likely understands Chinese. if (acceptLanguage && acceptLanguage.includes('zh')) { event.locals.lang = 'zh'; + } else if (acceptLanguage && acceptLanguage.includes('ja')) { + event.locals.lang = 'ja'; } else { event.locals.lang = 'en'; } diff --git a/src/lib/i18n/index.ts b/src/lib/i18n/index.ts index 1d92106..50024eb 100644 --- a/src/lib/i18n/index.ts +++ b/src/lib/i18n/index.ts @@ -1,17 +1,19 @@ import { getContext, setContext } from 'svelte' import EN from "./en" import ZH from "./zh" +import JA from "./ja" // i18n related files: // src\hooks.server.ts // src\routes\+layout.server.ts -type Lang = 'en' | 'zh' +type Lang = 'en' | 'zh' | 'ja' const msgs: Record = { en: EN, - zh: ZH + zh: ZH, + ja: JA } const I18N_KEY = Symbol('i18n') diff --git a/src/lib/i18n/ja.ts b/src/lib/i18n/ja.ts new file mode 100644 index 0000000..f14d9c9 --- /dev/null +++ b/src/lib/i18n/ja.ts @@ -0,0 +1,130 @@ +export default { + home: { + titles: { + continue: '前回のセッションから続ける', + history: '履歴', + myPlaylists: 'マイプレイリスト', + recPlaylists: 'おすすめプレイリスト' + }, + btn: { + importFromNetease: 'NetEaseからインポート' + }, + text: { + playlistCreatedBy: '{u} 作成' + } + }, + admin: { + neteaseLogin: { + title: 'NetEaseログイン', + scanTitle: 'スキャンしてログイン', + scanTip: 'NetEase Musicアプリでスキャンしてください', + generating: 'QRコードを生成中...', + scanned: 'スキャン完了', + confirm: '携帯電話でログインを確認してください', + success: 'ログイン成功', + errorPrefix: 'エラー: ' + } + }, + import: { + netease: { + title: 'NetEaseからインポート', + status: { + importing: 'インポート中', + success: 'インポート完了', + error: 'インポート失敗' + }, + songs: '曲', + tip: 'NetEase Musicアプリでお気に入りの日本語プレイリストを見つけ、共有をクリックし、リンクをコピーしてここに貼り付けると、インポートを開始できます!', + inputLabel: 'NetEaseプレイリストリンク / ID', + btnStart: 'インポート開始', + btnView: 'プレイリストを表示' + } + }, + playlist: { + detail: { + title: 'プレイリスト詳細', + creator: '作成者: ', + count: '曲数: ', + startPractice: '練習開始', + songList: '曲リスト', + songs: '曲' + }, + list: { + mine: 'マイプレイリスト', + rec: 'おすすめプレイリスト', + import: 'NetEaseからインポート', + created: '{u} 作成', + count: '{n} 曲' + } + }, + results: { + title: '練習結果', + fields: { + speed: '速度', + accuracy: '正確率', + realtime: 'リアルタイム率', + count: '文字数', + time: '時間', + duration: '曲の長さ' + }, + units: { + cpm: 'CPM', + percent: '%', + x: 'x', + char: '文字' + }, + chart: { + speed: '速度 (CPM)', + accuracy: '正確率 (%)' + }, + btn: { + next: '次の曲', + back: 'プレイリストに戻る', + retry: 'もう一度' + } + }, + song: { + mode: { + typing: 'タイピングモード', + music: '音楽モード' + }, + karaoke: { + noVocals: 'ボーカル分離トラックが検出されないため、ボーカル音量を調整できません。まず曲の詳細ページで処理してください。' + }, + play: { + speed: '速度: ', + accuracy: '正確率: ', + stats: { + right: '正解:', + fuzzy: '曖昧:', + wrong: '不正解:', + remaining: '残り:' + } + } + }, + user: { + title: 'アカウント管理', + loginSuccess: { + title: 'ログイン成功', + content: 'ログインに成功しました!', + jump: '移動' + }, + generateCode: { + title: '引き継ぎコード生成', + copy: 'コピー', + success: '引き継ぎコードが生成されました!コードは:{code}', + expiry: 'このコードは使用後、または未使用の場合は7日後に無効になります。' + }, + desc: { + intro: 'このアプリは日本のモバイルゲームのように引き継ぎコードシステムを使用しており、メールアドレスやパスワードの登録は不要です。', + instruction: '別のデバイスでログインするには、「引き継ぎコード生成」をクリックし、ログインしたいデバイスで「ログイン」をクリックしてください。', + loginMode: '現在は「引き継ぎログイン」ページです。別のデバイスで引き継ぎコードを取得し、下の入力欄に入力して「ログイン」をクリックしてください。' + }, + input: '引き継ぎコードを入力', + btn: { + generate: '引き継ぎコード生成', + loginWithCode: '引き継ぎコードでログイン', + login: 'ログイン' + } + } +}