Skip to content

Commit ded7bac

Browse files
Y-RyuZUclaude
andcommitted
fix: resolve overall progress calculation issues and improve UI responsiveness
- Fix overall progress calculation in all translation tabs (mods, quests, guidebooks, custom files) - Change denominator from selected items to actual jobs to ensure 100% completion - Improve translation history dialog table responsiveness with flexible column widths - Remove unused variables and fix TypeScript/ESLint issues - Apply Rust code formatting for consistency - Add proper progress tracking for skipped translations 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent efbe16a commit ded7bac

File tree

13 files changed

+222
-77
lines changed

13 files changed

+222
-77
lines changed

src-tauri/src/backup.rs

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -371,9 +371,7 @@ pub async fn get_translation_summary(
371371
});
372372
} else {
373373
// Session directory doesn't exist
374-
return Err(format!(
375-
"Session not found: {session_id}"
376-
));
374+
return Err(format!("Session not found: {session_id}"));
377375
}
378376
}
379377

@@ -402,13 +400,16 @@ pub async fn update_translation_summary(
402400
) -> Result<(), String> {
403401
println!("[update_translation_summary] Called with: minecraft_dir={}, session_id={}, translation_type={}, name={}, status={}, translated_keys={}, total_keys={}, target_language={}",
404402
minecraft_dir, session_id, translation_type, name, status, translated_keys, total_keys, target_language);
405-
403+
406404
let session_dir = PathBuf::from(&minecraft_dir)
407405
.join("logs")
408406
.join("localizer")
409407
.join(&session_id);
410-
411-
println!("[update_translation_summary] Session directory: {}", session_dir.display());
408+
409+
println!(
410+
"[update_translation_summary] Session directory: {}",
411+
session_dir.display()
412+
);
412413

413414
// Ensure session directory exists
414415
fs::create_dir_all(&session_dir)
@@ -446,7 +447,10 @@ pub async fn update_translation_summary(
446447

447448
fs::write(&summary_path, json).map_err(|e| format!("Failed to write summary file: {e}"))?;
448449

449-
println!("[update_translation_summary] Successfully wrote summary to: {}", summary_path.display());
450+
println!(
451+
"[update_translation_summary] Successfully wrote summary to: {}",
452+
summary_path.display()
453+
);
450454
Ok(())
451455
}
452456

@@ -460,13 +464,16 @@ pub async fn batch_update_translation_summary(
460464
) -> Result<(), String> {
461465
println!("[batch_update_translation_summary] Called with: minecraft_dir={}, session_id={}, target_language={}, entries_count={}",
462466
minecraft_dir, session_id, target_language, entries.len());
463-
467+
464468
let session_dir = PathBuf::from(&minecraft_dir)
465469
.join("logs")
466470
.join("localizer")
467471
.join(&session_id);
468-
469-
println!("[batch_update_translation_summary] Session directory: {}", session_dir.display());
472+
473+
println!(
474+
"[batch_update_translation_summary] Session directory: {}",
475+
session_dir.display()
476+
);
470477

471478
// Ensure session directory exists
472479
fs::create_dir_all(&session_dir)
@@ -490,27 +497,34 @@ pub async fn batch_update_translation_summary(
490497

491498
// Add all new translation entries
492499
for entry_value in entries {
493-
if let Ok(entry_data) = serde_json::from_value::<serde_json::Map<String, serde_json::Value>>(entry_value) {
494-
let translation_type = entry_data.get("translationType")
500+
if let Ok(entry_data) =
501+
serde_json::from_value::<serde_json::Map<String, serde_json::Value>>(entry_value)
502+
{
503+
let translation_type = entry_data
504+
.get("translationType")
495505
.and_then(|v| v.as_str())
496506
.unwrap_or("unknown")
497507
.to_string();
498-
499-
let name = entry_data.get("name")
508+
509+
let name = entry_data
510+
.get("name")
500511
.and_then(|v| v.as_str())
501512
.unwrap_or("unknown")
502513
.to_string();
503-
504-
let status = entry_data.get("status")
514+
515+
let status = entry_data
516+
.get("status")
505517
.and_then(|v| v.as_str())
506518
.unwrap_or("failed")
507519
.to_string();
508-
509-
let translated_keys = entry_data.get("translatedKeys")
520+
521+
let translated_keys = entry_data
522+
.get("translatedKeys")
510523
.and_then(|v| v.as_i64())
511524
.unwrap_or(0) as i32;
512-
513-
let total_keys = entry_data.get("totalKeys")
525+
526+
let total_keys = entry_data
527+
.get("totalKeys")
514528
.and_then(|v| v.as_i64())
515529
.unwrap_or(0) as i32;
516530

@@ -531,6 +545,10 @@ pub async fn batch_update_translation_summary(
531545

532546
fs::write(&summary_path, json).map_err(|e| format!("Failed to write summary file: {e}"))?;
533547

534-
println!("[batch_update_translation_summary] Successfully wrote summary with {} entries to: {}", summary.translations.len(), summary_path.display());
548+
println!(
549+
"[batch_update_translation_summary] Successfully wrote summary with {} entries to: {}",
550+
summary.translations.len(),
551+
summary_path.display()
552+
);
535553
Ok(())
536554
}

src-tauri/src/filesystem.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,12 @@ pub async fn get_ftb_quest_files_with_language(
233233
debug!("Skipping already translated file: {file_name}");
234234
continue;
235235
}
236-
236+
237237
// If target language is specified, check if translation already exists
238238
if let Some(target_lang) = target_language {
239239
if file_name == "en_us.json" {
240-
let target_file = kubejs_assets_dir.join(format!("{}.json", target_lang));
240+
let target_file =
241+
kubejs_assets_dir.join(format!("{}.json", target_lang));
241242
if target_file.exists() && target_file.is_file() {
242243
debug!("Skipping {} - target language file already exists: {}", file_name, target_file.display());
243244
continue;
@@ -340,7 +341,6 @@ pub async fn get_ftb_quest_files_with_language(
340341
if entry_path.is_file()
341342
&& entry_path.extension().is_some_and(|ext| ext == "snbt")
342343
{
343-
344344
match entry_path.to_str() {
345345
Some(path_str) => quest_files.push(path_str.to_string()),
346346
None => {

src-tauri/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub mod minecraft;
99
mod tests;
1010

1111
use backup::{
12-
backup_resource_pack, backup_snbt_files, batch_update_translation_summary, create_backup,
12+
backup_resource_pack, backup_snbt_files, batch_update_translation_summary, create_backup,
1313
get_translation_summary, list_translation_sessions, update_translation_summary,
1414
};
1515
use config::{load_config, save_config};
@@ -27,7 +27,7 @@ use logging::{
2727
};
2828
use minecraft::{
2929
analyze_mod_jar, check_guidebook_translation_exists, check_mod_translation_exists,
30-
check_quest_translation_exists, detect_snbt_content_type, extract_lang_files,
30+
check_quest_translation_exists, detect_snbt_content_type, extract_lang_files,
3131
extract_patchouli_books, write_patchouli_book,
3232
};
3333

src-tauri/src/minecraft/mod.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -946,28 +946,28 @@ pub async fn check_guidebook_translation_exists(
946946
#[tauri::command]
947947
pub async fn detect_snbt_content_type(file_path: &str) -> Result<String, String> {
948948
use std::fs;
949-
950-
let content = fs::read_to_string(file_path)
951-
.map_err(|e| format!("Failed to read SNBT file: {e}"))?;
952-
949+
950+
let content =
951+
fs::read_to_string(file_path).map_err(|e| format!("Failed to read SNBT file: {e}"))?;
952+
953953
// Simple heuristic: check if the content contains typical JSON key patterns
954954
// JSON keys usually contain dots (e.g., "item.minecraft.stick") or colons (e.g., "minecraft:stick")
955-
let has_json_key_patterns = content.contains("minecraft:") ||
956-
content.contains("ftbquests:") ||
957-
content.contains(".minecraft.") ||
958-
content.contains("item.") ||
959-
content.contains("block.") ||
960-
content.contains("entity.") ||
961-
content.contains("gui.") ||
962-
content.contains("quest.");
963-
955+
let has_json_key_patterns = content.contains("minecraft:")
956+
|| content.contains("ftbquests:")
957+
|| content.contains(".minecraft.")
958+
|| content.contains("item.")
959+
|| content.contains("block.")
960+
|| content.contains("entity.")
961+
|| content.contains("gui.")
962+
|| content.contains("quest.");
963+
964964
// Check if the content has direct readable text (not just IDs and keys)
965965
// Look for typical quest text patterns
966-
let has_direct_text = content.contains("description:") ||
967-
content.contains("title:") ||
968-
content.contains("subtitle:") ||
969-
content.contains("text:");
970-
966+
let has_direct_text = content.contains("description:")
967+
|| content.contains("title:")
968+
|| content.contains("subtitle:")
969+
|| content.contains("text:");
970+
971971
if has_json_key_patterns && !has_direct_text {
972972
Ok("json_keys".to_string())
973973
} else if has_direct_text {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"item.complexmod.energy_crystal": "エネルギー クリスタル",
3+
"item.complexmod.energy_crystal.tooltip": "[翻訳] Stores %s RF",
4+
"item.complexmod.advanced_tool": "高度な Multi-ツール",
5+
"item.complexmod.advanced_tool.tooltip": "採掘 Level: %d, Efficiency: %d",
6+
"item.complexmod.quantum_ingot": "量子 Ingot",
7+
"block.complexmod.machine_frame": "機械 Frame",
8+
"block.complexmod.energy_conduit": "エネルギー Conduit",
9+
"block.complexmod.energy_conduit.tooltip": "[翻訳] Transfers up to %d RF/t",
10+
"block.complexmod.quantum_storage": "量子 貯蔵",
11+
"tile.complexmod.reactor": "Fusion リアクター",
12+
"tile.complexmod.reactor.status": "[翻訳] Status: %s",
13+
"tile.complexmod.reactor.temperature": "温度: %d K",
14+
"complexmod.gui.energy": "エネルギー: %d / %d RF",
15+
"complexmod.gui.progress": "進捗: %d%%",
16+
"complexmod.tooltip.shift_info": "[翻訳] Hold §eSHIFT§r for more info",
17+
"complexmod.tooltip.energy_usage": "[翻訳] Uses %d RF per operation",
18+
"complexmod.jei.category.fusion": "[翻訳] Fusion Crafting",
19+
"complexmod.manual.title": "Complex Mod マニュアル",
20+
"complexmod.manual.chapter.basics": "はじめに",
21+
"complexmod.manual.chapter.machines": "[翻訳] Machines and Automation",
22+
"complexmod.manual.chapter.energy": "エネルギー Systems",
23+
"death.attack.complexmod.radiation": "[翻訳] %s died from radiation poisoning",
24+
"death.attack.complexmod.radiation.player": "[翻訳] %s was irradiated by %s",
25+
"commands.complexmod.reload": "[翻訳] Reloaded configuration",
26+
"commands.complexmod.reload.error": "[翻訳] Failed to reload: %s"
27+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
{
2+
title: "[JP] Getting Started"
3+
icon: "minecraft:grass_block"
4+
default_quest_shape: ""
5+
quests: [
6+
{
7+
title: "Welcome!"
8+
x: 0.0d
9+
y: 0.0d
10+
description: [
11+
"Welcome to this modpack!"
12+
"This quest will guide you through the basics."
13+
""
14+
"Let's start by gathering some basic resources."
15+
]
16+
id: "0000000000000001"
17+
tasks: [{
18+
id: "0000000000000002"
19+
type: "item"
20+
item: "minecraft:oak_log"
21+
count: 16L
22+
}]
23+
rewards: [{
24+
id: "0000000000000003"
25+
type: "item"
26+
item: "minecraft:apple"
27+
count: 5
28+
}]
29+
}
30+
{
31+
title: "First Tools"
32+
x: 2.0d
33+
y: 0.0d
34+
description: ["Time to craft your first set of tools!"]
35+
dependencies: ["0000000000000001"]
36+
id: "0000000000000004"
37+
tasks: [
38+
{
39+
id: "0000000000000005"
40+
type: "item"
41+
item: "minecraft:wooden_pickaxe"
42+
}
43+
{
44+
id: "0000000000000006"
45+
type: "item"
46+
item: "minecraft:wooden_axe"
47+
}
48+
]
49+
rewards: [{
50+
id: "0000000000000007"
51+
type: "xp_levels"
52+
xp_levels: 5
53+
}]
54+
}
55+
{
56+
title: "Mining Time"
57+
x: 4.0d
58+
y: 0.0d
59+
subtitle: "Dig deeper!"
60+
description: [
61+
"Now that you have tools, it's time to start mining."
62+
"Find some stone and coal to progress."
63+
]
64+
dependencies: ["0000000000000004"]
65+
id: "0000000000000008"
66+
tasks: [
67+
{
68+
id: "0000000000000009"
69+
type: "item"
70+
item: "minecraft:cobblestone"
71+
count: 64L
72+
}
73+
{
74+
id: "000000000000000A"
75+
type: "item"
76+
item: "minecraft:coal"
77+
count: 8L
78+
}
79+
]
80+
}
81+
]
82+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"item.samplemod.example_item": "[JP] Example Item",
3+
"item.samplemod.example_item.tooltip": "[JP] This is an example item",
4+
"block.samplemod.example_block": "[JP] Example Block",
5+
"block.samplemod.example_block.desc": "[JP] A block that does example things",
6+
"itemGroup.samplemod": "[JP] Sample Mod",
7+
"samplemod.config.title": "[JP] Sample Mod Configuration",
8+
"samplemod.config.enabled": "[JP] Enable Sample Features",
9+
"samplemod.config.enabled.tooltip": "[JP] Enable or disable the sample features",
10+
"samplemod.message.welcome": "[JP] Welcome to Sample Mod!",
11+
"samplemod.message.error": "[JP] An error occurred: %s",
12+
"samplemod.gui.button.confirm": "[JP] Confirm",
13+
"samplemod.gui.button.cancel": "[JP] Cancel",
14+
"advancement.samplemod.root": "[JP] Sample Mod",
15+
"advancement.samplemod.root.desc": "[JP] The beginning of your journey",
16+
"advancement.samplemod.first_item": "[JP] First Item",
17+
"advancement.samplemod.first_item.desc": "[JP] Craft your first example item"
18+
}

src/components/tabs/custom-files-tab.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,6 @@ export function CustomFilesTab() {
189189
setProgress(0);
190190
setCompletedCustomFiles(0);
191191

192-
// Set total files for progress tracking
193-
const totalFiles = sortedTargets.length;
194-
setTotalChunks(totalFiles); // Track at file level
195-
setTotalCustomFiles(totalFiles);
196-
197192
// Create jobs for all files
198193
const jobs: Array<{
199194
target: TranslationTarget;
@@ -276,6 +271,11 @@ export function CustomFilesTab() {
276271
}
277272
}
278273

274+
// Set total files for progress tracking: denominator = actual jobs, numerator = completed files
275+
// This ensures progress reaches 100% when all translatable files are processed
276+
setTotalCustomFiles(jobs.length);
277+
setTotalChunks(jobs.length); // Track at file level
278+
279279
// Use the session ID provided by the common translation tab
280280
const minecraftDir = selectedDirectory;
281281
const sessionPath = await invoke<string>('create_logs_directory_with_session', {

src/components/tabs/guidebooks-tab.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,12 @@ export function GuidebooksTab() {
194194
setWholeProgress(0);
195195
setCompletedGuidebooks(0);
196196

197-
// Set total guidebooks for progress tracking
198-
setTotalGuidebooks(sortedTargets.length);
199-
200197
// Prepare jobs and count total chunks
201198
let totalChunksCount = 0;
202199
const jobs = [];
203200
let skippedCount = 0;
204201

205-
for (const target of selectedTargets) {
202+
for (const target of sortedTargets) {
206203
try {
207204
// Extract Patchouli books first to get mod ID
208205
const books = await FileService.invoke<PatchouliBook[]>("extract_patchouli_books", {
@@ -276,6 +273,10 @@ export function GuidebooksTab() {
276273
}
277274
}
278275

276+
// Set total guidebooks for progress tracking: denominator = actual jobs, numerator = completed guidebooks
277+
// This ensures progress reaches 100% when all translatable guidebooks are processed
278+
setTotalGuidebooks(jobs.length);
279+
279280
// Ensure totalChunks is set correctly, fallback to jobs.length if calculation failed
280281
const finalTotalChunks = totalChunksCount > 0 ? totalChunksCount : jobs.length;
281282
setTotalChunks(finalTotalChunks);

0 commit comments

Comments
 (0)