feat: Added multilingual text output display
This commit is contained in:
1 parent
68eca80e5f
commit
3a0f1b025e
4 files changed
+141
-25
No files matched your search
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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; // 默认中文
|
||||
}
|
||||
Reference in new issue
Block a user