From 4b224f7fe579a5a33060547a68b292dd55d75083 Mon Sep 17 00:00:00 2001 From: ebbit1q Date: Sat, 7 Nov 2026 16:26:31 +0100 Subject: [PATCH] Translate the filter string error at display time (#5283) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep the parser message untranslated so FilterStringLog stays in the source language, and format the user-facing text in error() instead. That gives both consumers what they need without localizing the log. Q_DECLARE_TR_FUNCTIONS provides the tr() context without deriving from QObject, which would have deleted copy/move assignment and broken the by-value uses in PlayerActions and ViewZone. Drop the unreachable line-number branch; peglib reports 1-based lines, so every message keeps master's "position" wording. Co-authored-by: Lukas BrĂ¼bach <44814898+BruebachL@users.noreply.github.com> --- .../libcockatrice/filters/filter_string.cpp | 11 ++++++++++- .../libcockatrice/filters/filter_string.h | 13 ++++++++----- tests/carddatabase/filter_string_test.cpp | 16 ++++++++++++++++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/libcockatrice_filters/libcockatrice/filters/filter_string.cpp b/libcockatrice_filters/libcockatrice/filters/filter_string.cpp index 1bcb1646b..f7ca82344 100644 --- a/libcockatrice_filters/libcockatrice/filters/filter_string.cpp +++ b/libcockatrice_filters/libcockatrice/filters/filter_string.cpp @@ -506,6 +506,14 @@ FilterString::FilterString() _error = "Not initialized"; } +QString FilterString::error() const +{ + if (_errorColumn == 0) { + return _error; + } + return tr("Error at position %1: %2").arg(_errorColumn).arg(_error); +} + FilterString::FilterString(const QString &expr, const CardSearchLanguage &searchLanguage) { QByteArray ba = expr.simplified().toUtf8(); @@ -522,7 +530,8 @@ FilterString::FilterString(const QString &expr, const CardSearchLanguage &search searchLanguageContext = searchLanguage; search.set_logger([&](size_t /*ln*/, size_t col, const std::string &msg) { - _error = QString("Error at position %1: %2").arg(col).arg(QString::fromStdString(msg)); + _error = QString::fromStdString(msg); + _errorColumn = col; }); if (!search.parse(ba.data(), result)) { diff --git a/libcockatrice_filters/libcockatrice/filters/filter_string.h b/libcockatrice_filters/libcockatrice/filters/filter_string.h index 2abe95201..34e2bfb35 100644 --- a/libcockatrice_filters/libcockatrice/filters/filter_string.h +++ b/libcockatrice_filters/libcockatrice/filters/filter_string.h @@ -7,6 +7,7 @@ #ifndef FILTER_STRING_H #define FILTER_STRING_H +#include #include #include #include @@ -33,6 +34,8 @@ typedef AstBase Ast; class FilterString { + Q_DECLARE_TR_FUNCTIONS(FilterString) + public: FilterString(); explicit FilterString(const QString &exp, const CardSearchLanguage &searchLanguage = {}); @@ -45,18 +48,18 @@ public: return result(card); } - bool valid() + [[nodiscard]] bool valid() const { return _error.isEmpty(); } - QString error() - { - return _error; - } + [[nodiscard]] QString error() const; private: + // Untranslated parser message; error() adds the translated prefix, logging uses it as-is. QString _error; + // Column reported by the parser, or 0 when the message carries no position. + size_t _errorColumn = 0; Filter result; }; diff --git a/tests/carddatabase/filter_string_test.cpp b/tests/carddatabase/filter_string_test.cpp index 931cb7e0c..88058278f 100644 --- a/tests/carddatabase/filter_string_test.cpp +++ b/tests/carddatabase/filter_string_test.cpp @@ -279,6 +279,22 @@ TEST_F(SetQuery, ComparisonMatchesByReleaseDate) EXPECT_FALSE(FilterString("set