feat: Added multilingual text output display

This commit is contained in:
gdjdkid committed 2026-03-26 01:13:04 +08:00
1 parent 68eca80e5f
commit 3a0f1b025e
4 files changed
+141 -25

No files matched your search

+11 -4
View File
@@ -8,6 +8,7 @@ import { display } from './lib/display.js';
import { clearCache, setConfig } from './lib/cache.js';
import ora from 'ora';
import chalk from 'chalk';
import { getLang } from './lib/i18n.js';
const require = createRequire(import.meta.url);
const pkg = require('./package.json');
@@ -20,6 +21,7 @@ program
.option('-r, --raw', '显示原始详细数据')
.option('--clear-cache', '清空本地缓存')
.option('--setup', '配置JAVDB Cookie(可选,提高查询覆盖率)')
.option('-l, --lang <lang>', '显示语言 zh/en/jp/kr/de', 'zh')
.action(async (id, options) => {
if (options.setup) {
@@ -63,21 +65,26 @@ program
process.exit(0);
}
const spinner = ora(`正在查询 ${id.toUpperCase()} ...`).start();
const t = getLang(options.lang || 'zh');
const spinner = ora(`${t.searching} ${id.toUpperCase()} ...`).start();
try {
const result = await search(id.toUpperCase());
spinner.stop();
if (!result) {
console.log(chalk.red(`\n未找到番号: ${id.toUpperCase()}`));
console.log(chalk.red(`\n${t.notFound}: ${id.toUpperCase()}`));
// Windows 用户提示
if (process.platform === 'win32') {
process.stderr.write(chalk.gray(` ${t.windowsHint}\n`));
}
process.exit(1);
}
display(result, options.raw);
display(result, options.raw, options.lang || 'zh');
} catch (err) {
spinner.stop();
console.error('\n查询失败:', err.message);
console.error(`\n${t.queryFailed}:`, err.message);
process.exit(1);
}
});
+19 -16
View File
@@ -1,19 +1,22 @@
import chalk from 'chalk';
import { getLang } from './i18n.js';
const DIVIDER = chalk.gray('─'.repeat(60));
function row(label, value, color = chalk.white) {
if (!value || (Array.isArray(value) && value.length === 0)) return;
const paddedLabel = chalk.cyan(label.padEnd(8, ' ')); // 用全角空格对齐中文
const paddedLabel = chalk.cyan(label.padEnd(8, ' '));
console.log(` ${paddedLabel} ${color(value)}`);
}
export function display(info, raw = false) {
export function display(info, raw = false, lang = 'zh') {
if (raw) {
console.log(JSON.stringify(info, null, 2));
return;
}
const t = getLang(lang);
console.log('');
console.log(DIVIDER);
console.log(
@@ -29,29 +32,29 @@ export function display(info, raw = false) {
console.log(DIVIDER);
row('女优', info.actresses.join(' / '), chalk.magenta);
row('男优', info.actors.join(' / '), chalk.blue);
row('发售日期', info.releaseDate, chalk.green);
row('时长', info.duration);
row('制作商', info.studio, chalk.yellow);
row('发行商', info.label);
row('导演', info.director);
row('系列', info.series);
row('评分', info.score ? `${info.score}${info.scoreCount ? `(${info.scoreCount}人评价)` : ''}` : '', chalk.yellow);
row('想看', info.wantCount ? `${info.wantCount} 人想看` : '', chalk.cyan);
row(t.actress, info.actresses.join(' / '), chalk.magenta);
row(t.actor, info.actors.join(' / '), chalk.blue);
row(t.releaseDate, info.releaseDate, chalk.green);
row(t.duration, info.duration);
row(t.studio, info.studio, chalk.yellow);
row(t.label, info.label);
row(t.director, info.director);
row(t.series, info.series);
row(t.rating, info.score ? `${info.score}${info.scoreCount ? `(${info.scoreCount})` : ''}` : '', chalk.yellow);
row(t.wishlist, info.wantCount ? `${info.wantCount}` : '', chalk.cyan);
if (info.tags.length > 0) {
const tagStr = info.tags.map(t => chalk.bgGray(` ${t} `)).join(' ');
console.log(' ' + chalk.cyan('类别  ') + ' ' + tagStr);
const tagStr = info.tags.map(tag => chalk.bgGray(` ${tag} `)).join(' ');
console.log(' ' + chalk.cyan(t.tags.padEnd(8, ' ')) + ' ' + tagStr);
}
if (info.coverUrl) {
console.log('');
console.log(' ' + chalk.cyan('封面  ') + ' ' + chalk.underline.gray(info.coverUrl));
console.log(' ' + chalk.cyan(t.cover.padEnd(8, ' ')) + ' ' + chalk.underline.gray(info.coverUrl));
}
if (info.source) {
console.log(' ' + chalk.gray(`数据来源: ${info.source}`));
console.log(' ' + chalk.gray(`${t.source}: ${info.source}`));
}
console.log(DIVIDER);
-5
View File
@@ -360,10 +360,5 @@ export async function search(id) {
}
}
// Windows 用户提示
if (process.platform === 'win32') {
process.stderr.write(chalk.gray(' 温馨提示: 此车牌号需要JAVDB数据源,Windows暂不支持~\n'));
}
return null;
}
+111
View File
@@ -0,0 +1,111 @@
export const messages = {
zh: {
actress: '女优',
actor: '男优',
releaseDate: '发售日期',
duration: '时长',
studio: '制作商',
label: '发行商',
director: '导演',
series: '系列',
rating: '评分',
wishlist: '想看',
tags: '类别',
cover: '封面',
source: '数据来源',
searching: '正在查询',
notFound: '未找到番号',
queryFailed: '查询失败',
cacheCleared: '缓存已清空',
fc2Detected: 'FC2番号已转换为',
windowsHint: '温馨提示: 此番号需要JAVDB数据源,Windows暂不支持~',
},
en: {
actress: 'Actress',
actor: 'Actor',
releaseDate: 'Released',
duration: 'Duration',
studio: 'Studio',
label: 'Label',
director: 'Director',
series: 'Series',
rating: 'Rating',
wishlist: 'Wishlist',
tags: 'Tags',
cover: 'Cover',
source: 'Source',
searching: 'Searching',
notFound: 'Title not found',
queryFailed: 'Query failed',
cacheCleared: 'Cache cleared',
fc2Detected: 'FC2 format detected',
windowsHint: 'Note: This title requires JAVDB, which is unavailable on Windows.',
},
jp: {
actress: '女優',
actor: '男優',
releaseDate: '発売日',
duration: '時間',
studio: 'メーカー',
label: 'レーベル',
director: '監督',
series: 'シリーズ',
rating: '評価',
wishlist: '観たい',
tags: 'カテゴリ',
cover: 'カバー',
source: 'データソース',
searching: '検索中',
notFound: '番号が見つかりません',
queryFailed: '検索失敗',
cacheCleared: 'キャッシュを削除しました',
fc2Detected: 'FC2番号を変換しました',
windowsHint: '注意: この番号はJAVDBが必要ですが、WindowsではJAVDBが利用できません。',
},
kr: {
actress: '여배우',
actor: '남배우',
releaseDate: '발매일',
duration: '시간',
studio: '제작사',
label: '레이블',
director: '감독',
series: '시리즈',
rating: '평점',
wishlist: '보고싶어요',
tags: '카테고리',
cover: '커버',
source: '데이터 출처',
searching: '검색 중',
notFound: '번호를 찾을 수 없습니다',
queryFailed: '검색 실패',
cacheCleared: '캐시가 삭제되었습니다',
fc2Detected: 'FC2 번호 변환됨',
windowsHint: '알림: 이 번호는 JAVDB가 필요하지만 Windows에서는 사용할 수 없습니다.',
},
de: {
actress: 'Darstellerin',
actor: 'Darsteller',
releaseDate: 'Erscheinungsdatum',
duration: 'Laufzeit',
studio: 'Studio',
label: 'Label',
director: 'Regisseur',
series: 'Serie',
rating: 'Bewertung',
wishlist: 'Merkliste',
tags: 'Kategorien',
cover: 'Cover',
source: 'Datenquelle',
searching: 'Suche läuft',
notFound: 'Titel nicht gefunden',
queryFailed: 'Suche fehlgeschlagen',
cacheCleared: 'Cache geleert',
fc2Detected: 'FC2-Format erkannt',
windowsHint: 'Hinweis: Dieser Titel benötigt JAVDB, das unter Windows nicht verfügbar ist.',
},
};
export function getLang(lang) {
return messages[lang] || messages.zh; // 默认中文
}