feat(glossary): add episode groups, search, and import/export

Apply glossary edits directly to translated subtitles and reload the active track. Keep terms with their originating episode, preserve existing translations, and clear stale episode groups with glossary entries.
This commit is contained in:
tri committed 2026-11-11 19:44:38 +07:00
1 parent 0bfaf3c9db
commit 97b4a2fe32
9 files changed
+955 -50

No files matched your search

+13 -1
View File
@@ -34,6 +34,8 @@ class TranslationService : public QObject
Q_PROPERTY(bool fetchingModels READ isFetchingModels NOTIFY fetchingModelsChanged)
Q_PROPERTY(QVariantList glossaryEntries READ glossaryEntries NOTIFY glossaryChanged)
Q_PROPERTY(QString glossaryDirectory READ glossaryDirectory NOTIFY glossaryChanged)
Q_PROPERTY(QString glossaryEpisode READ glossaryEpisode NOTIFY glossaryChanged)
Q_PROPERTY(QStringList glossaryEpisodes READ glossaryEpisodes NOTIFY glossaryChanged)
Q_PROPERTY(QString glossaryError READ glossaryError NOTIFY glossaryErrorChanged)
public:
@@ -49,6 +51,8 @@ public:
bool isFetchingModels() const;
QVariantList glossaryEntries() const;
QString glossaryDirectory() const;
QString glossaryEpisode() const;
QStringList glossaryEpisodes() const;
QString glossaryError() const;
// \a track is an entry of MpvItem::subtitleTracks.
@@ -57,9 +61,14 @@ public:
// Asks the API configured in the settings for its models.
Q_INVOKABLE void fetchModels();
Q_INVOKABLE void clearError();
Q_INVOKABLE void forgetTranslation();
Q_INVOKABLE void loadGlossary(const QUrl &videoUrl);
Q_INVOKABLE bool saveGlossary(const QVariantList &entries);
Q_INVOKABLE bool saveGlossary(const QVariantList &entries, const QStringList &episodes = {});
Q_INVOKABLE void clearGlossary();
// File operations use the dialog draft; import only commits when Save is clicked.
Q_INVOKABLE QVariantMap importGlossaryFile(const QUrl &url, const QVariantList &entries, const QStringList &episodes);
Q_INVOKABLE QVariantMap exportGlossaryFile(const QUrl &url, const QVariantList &entries, const QStringList &episodes);
Q_INVOKABLE QStringList sortedGlossaryEpisodes(const QStringList &episodes) const;
Q_SIGNALS:
void busyChanged();
@@ -94,6 +103,7 @@ private:
void setStatusText(const QString &text);
void setErrorText(const QString &text);
void setFetchingModels(bool fetching);
void applyGlossaryEdits(const GlossaryStore::Glossary &previous, const GlossaryStore::Glossary &updated);
QNetworkAccessManager *m_network;
std::shared_ptr<Job> m_job;
@@ -105,4 +115,6 @@ private:
QStringList m_availableModels;
bool m_fetchingModels = false;
GlossaryStore::Glossary m_glossary;
QString m_glossaryEpisode;
QString m_lastTranslationPath;
};