2025-06-22 11:33:58 +08:00
|
|
|
|
|
|
|
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
2025-06-22 21:09:32 +08:00
|
|
|
|
using CommunityToolkit.Mvvm.Input;
|
2025-06-24 22:56:20 +08:00
|
|
|
|
using MCI18n.AI;
|
2025-06-22 21:09:32 +08:00
|
|
|
|
using MCI18n.Models;
|
2025-06-24 22:56:20 +08:00
|
|
|
|
using MCI18n.Services;
|
2025-06-22 11:33:58 +08:00
|
|
|
|
using MCI18n.Utilities;
|
|
|
|
|
using Microsoft.Win32;
|
|
|
|
|
using SharpNBT;
|
|
|
|
|
using SharpNBT.SNBT;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Windows;
|
|
|
|
|
|
|
|
|
|
namespace MCI18n
|
|
|
|
|
{
|
|
|
|
|
public partial class MainWindowViewModel : ObservableObject
|
2025-06-22 21:09:32 +08:00
|
|
|
|
{
|
|
|
|
|
private List<CompoundTag> _oriQuestsData;
|
|
|
|
|
private List<string> _updatedChapters;
|
|
|
|
|
private List<QuestLangModel> _langs;
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private ObservableCollection<ChapterModel> _chapters;
|
|
|
|
|
|
2025-06-24 22:56:20 +08:00
|
|
|
|
private FTBQuestsService _service;
|
2025-06-22 11:33:58 +08:00
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
2025-06-22 21:09:32 +08:00
|
|
|
|
private ObservableCollection<QuestModel> _selectedQuests;
|
2025-06-22 11:33:58 +08:00
|
|
|
|
|
2025-06-22 21:09:32 +08:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private bool _loading = false;
|
2025-06-24 22:56:20 +08:00
|
|
|
|
|
2025-06-25 09:32:03 +08:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
private bool _multipleLangSupport;
|
2025-06-22 11:33:58 +08:00
|
|
|
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
private void LoadQuests()
|
|
|
|
|
{
|
2025-06-22 21:09:32 +08:00
|
|
|
|
var openFolderDialog = new OpenFolderDialog
|
|
|
|
|
{
|
|
|
|
|
Title = "选择ftbquests文件夹",
|
|
|
|
|
Multiselect = false
|
2025-06-22 11:33:58 +08:00
|
|
|
|
};
|
|
|
|
|
|
2025-06-22 21:09:32 +08:00
|
|
|
|
if (openFolderDialog.ShowDialog() == true)
|
2025-06-22 11:33:58 +08:00
|
|
|
|
{
|
|
|
|
|
try
|
2025-06-22 21:09:32 +08:00
|
|
|
|
{
|
|
|
|
|
var folderPath = openFolderDialog.FolderName;
|
2025-06-24 22:56:20 +08:00
|
|
|
|
_service = new FTBQuestsService(folderPath);
|
|
|
|
|
var ftbQuests = _service.Parse();
|
|
|
|
|
Chapters = [];
|
|
|
|
|
foreach (var group in ftbQuests.Groups)
|
2025-06-22 21:09:32 +08:00
|
|
|
|
{
|
2025-06-24 22:56:20 +08:00
|
|
|
|
foreach (var chapter in group.Chapters)
|
2025-06-22 21:09:32 +08:00
|
|
|
|
{
|
2025-06-24 22:56:20 +08:00
|
|
|
|
Chapters.Add(chapter);
|
2025-06-22 21:09:32 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-25 09:32:03 +08:00
|
|
|
|
MultipleLangSupport = GlobalContext.MultipleLangSupport;
|
2025-06-22 11:33:58 +08:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show($"加载文件失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
private void SaveQuest()
|
|
|
|
|
{
|
2025-06-24 22:56:20 +08:00
|
|
|
|
//TODO Sava ALL (非多语言)
|
2025-06-22 11:33:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
private void SaveQuestAs()
|
|
|
|
|
{
|
2025-06-22 21:09:32 +08:00
|
|
|
|
if (GlobalContext.MultipleLangSupport)
|
|
|
|
|
{
|
|
|
|
|
/// 另存为多语言文件
|
|
|
|
|
|
|
|
|
|
var saveFileDialog = new SaveFileDialog
|
|
|
|
|
{
|
|
|
|
|
Title = "保存多语言文件",
|
|
|
|
|
Filter = "SNBT 文件 (*.snbt)|*.snbt",
|
|
|
|
|
FileName = "zh_cn.snbt",
|
|
|
|
|
};
|
|
|
|
|
if (saveFileDialog.ShowDialog() == true)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var filePath = saveFileDialog.FileName;
|
|
|
|
|
var langData = new CompoundTag("");
|
2025-06-24 22:56:20 +08:00
|
|
|
|
langData.Add(new StringTag("file.0000000000000001.title", Application.Current.MainWindow.Title));
|
2025-06-22 21:09:32 +08:00
|
|
|
|
foreach (var chapter in Chapters)
|
|
|
|
|
{
|
|
|
|
|
langData.Add(new StringTag($"chapter.{chapter.Id}.title", chapter.Title));
|
|
|
|
|
if (chapter.Quests != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var quest in chapter.Quests)
|
|
|
|
|
{
|
|
|
|
|
langData.Add(new StringTag($"quest.{quest.Id}.title", quest.Title));
|
2025-06-24 22:56:20 +08:00
|
|
|
|
if (!string.IsNullOrWhiteSpace(quest.SubTitle))
|
|
|
|
|
{
|
|
|
|
|
langData.Add(new StringTag($"quest.{quest.Id}.quest_subtitle", quest.SubTitle));
|
|
|
|
|
}
|
2025-06-22 21:09:32 +08:00
|
|
|
|
var descLines = quest.Description.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
|
|
|
|
|
var descList = new ListTag($"quest.{quest.Id}.quest_desc",TagType.String);
|
|
|
|
|
foreach (var line in descLines)
|
|
|
|
|
{
|
2025-06-24 22:56:20 +08:00
|
|
|
|
if(!string.IsNullOrWhiteSpace(line))
|
|
|
|
|
descList.Add(new StringTag(null, line));
|
2025-06-22 21:09:32 +08:00
|
|
|
|
}
|
|
|
|
|
langData.Add(descList);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SnbtWriter.SaveToFile(langData, filePath, prettyPrint: true);
|
|
|
|
|
MessageBox.Show("多语言文件保存成功!", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show($"保存文件失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-22 11:33:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
private void CreateNewQuest()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
2025-06-22 21:09:32 +08:00
|
|
|
|
|
2025-06-24 22:56:20 +08:00
|
|
|
|
[RelayCommand]
|
|
|
|
|
private async Task TranslateTheChapter()
|
|
|
|
|
{
|
|
|
|
|
Loading = true;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var aiClient = new I18nChatClient("doubao-1-5-pro-32k-250115");
|
|
|
|
|
|
|
|
|
|
var translationTasks = new List<Task>();
|
|
|
|
|
|
|
|
|
|
foreach (var item in SelectedQuests)
|
|
|
|
|
{
|
|
|
|
|
translationTasks.Add(TranslateQuestAsync(item, aiClient));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await Task.WhenAll(translationTasks);
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
Loading = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task TranslateQuestAsync(QuestModel quest, I18nChatClient aiClient)
|
|
|
|
|
{
|
|
|
|
|
var titleTask = !string.IsNullOrWhiteSpace(quest.Title)
|
|
|
|
|
? aiClient.TranslateAsync(quest.Title, "zh_cn")
|
|
|
|
|
: Task.FromResult<string>(quest.Title);
|
|
|
|
|
|
|
|
|
|
var subtitleTask = !string.IsNullOrWhiteSpace(quest.SubTitle)
|
|
|
|
|
? aiClient.TranslateAsync(quest.SubTitle, "zh_cn")
|
|
|
|
|
: Task.FromResult<string>(quest.SubTitle);
|
|
|
|
|
|
|
|
|
|
var descriptionTask = !string.IsNullOrWhiteSpace(quest.Description)
|
|
|
|
|
? aiClient.TranslateAsync(quest.Description, "zh_cn")
|
|
|
|
|
: Task.FromResult<string>(quest.Description);
|
|
|
|
|
|
|
|
|
|
// 等待所有翻译任务完成
|
|
|
|
|
await Task.WhenAll(titleTask, subtitleTask, descriptionTask);
|
|
|
|
|
|
|
|
|
|
// 更新属性
|
|
|
|
|
quest.Title = await titleTask;
|
|
|
|
|
quest.SubTitle = await subtitleTask;
|
|
|
|
|
quest.Description = await descriptionTask;
|
|
|
|
|
}
|
2025-06-22 21:09:32 +08:00
|
|
|
|
internal void ChapterSelectionChanged(ChapterModel selectedChapter)
|
|
|
|
|
{
|
|
|
|
|
if (selectedChapter != null && selectedChapter.Quests != null)
|
|
|
|
|
{
|
|
|
|
|
SelectedQuests = selectedChapter.Quests;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SelectedQuests = [];
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-24 22:56:20 +08:00
|
|
|
|
}
|
2025-06-22 11:33:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|