From 958067d94d8ffe549ce2881bc9c78eaf110b094f Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Tue, 30 Jan 2024 17:21:05 +0400 Subject: [PATCH] Backend translates the search results page Now the search results page is presented by the backend in the language controlled by the value of the `userlang` URL query parameter (or, if the latter is missing, the value of the `Accept-Language:` HTTP header). Note that the front-end doesn't yet take advantage of this functionality. --- include/search_renderer.h | 8 +++++ src/search_renderer.cpp | 1 - src/server/internalServer.cpp | 1 + static/skin/i18n/test.json | 5 +++ test/server_search.cpp | 57 ++++++++++++++++++++++++++--------- 5 files changed, 56 insertions(+), 16 deletions(-) diff --git a/include/search_renderer.h b/include/search_renderer.h index 2669b84cf..e328f85b5 100644 --- a/include/search_renderer.h +++ b/include/search_renderer.h @@ -72,6 +72,13 @@ class SearchRenderer this->pageLength = pageLength; } + /** + * set user language + */ + void setUserLang(const std::string& lang){ + this->userlang = lang; + } + /** * Generate the html page with the resutls of the search. * @@ -105,6 +112,7 @@ class SearchRenderer unsigned int pageLength; unsigned int estimatedResultCount; unsigned int resultStart; + std::string userlang = "en"; }; diff --git a/src/search_renderer.cpp b/src/search_renderer.cpp index 96392e961..e64eb5611 100644 --- a/src/search_renderer.cpp +++ b/src/search_renderer.cpp @@ -192,7 +192,6 @@ kainjow::mustache::data buildPagination( std::string SearchRenderer::renderTemplate(const std::string& tmpl_str, const NameMapper& nameMapper, const Library* library) { - const std::string userlang("en"); const std::string absPathPrefix = protocolPrefix; // Build the results list kainjow::mustache::data items{kainjow::mustache::data::type::list}; diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index 5c9d733d9..910ade8a4 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -967,6 +967,7 @@ std::unique_ptr InternalServer::handle_search_request(const RequestCon renderer.setProtocolPrefix(m_root + "/content/"); renderer.setSearchProtocolPrefix(m_root + "/search"); renderer.setPageLength(pageLength); + renderer.setUserLang(request.get_user_language()); if (request.get_requested_format() == "xml") { return ContentResponse::build( renderer.getXml(*mp_nameMapper, mp_library.get()), diff --git a/static/skin/i18n/test.json b/static/skin/i18n/test.json index 29def8eac..29c2e9613 100644 --- a/static/skin/i18n/test.json +++ b/static/skin/i18n/test.json @@ -42,4 +42,9 @@ , "preview-book": "[I18N] Preview [TESTING]" , "no-query" : "[I18N TESTING] Kiwix can read your thoughts but it is against GDPR. Please provide your query explicitly." , "invalid-request" : "[I18N TESTING] Invalid URL: \"{{{url}}}\"" + , "search-results-page-title": "[I18N TESTING] Search: {{SEARCH_PATTERN}}" + , "search-results-page-header": "[I18N TESTING] Results {{START}}-{{END}} of {{COUNT}} for \"{{{SEARCH_PATTERN}}}\"" + , "empty-search-results-page-header": "[I18N TESTING] No results were found for \"{{{SEARCH_PATTERN}}}\"" + , "search-result-book-info": "from [I18N TESTING] {{BOOK_TITLE}}" + , "word-count": "{{COUNT}} [I18N TESTING] words" } diff --git a/test/server_search.cpp b/test/server_search.cpp index 30149a373..de8cd9046 100644 --- a/test/server_search.cpp +++ b/test/server_search.cpp @@ -113,7 +113,7 @@ std::string makeSearchResultsHtml(const std::string& pattern, } - Search: %PATTERN% + %USERLANGMARKER%Search: %PATTERN%
@@ -173,8 +173,8 @@ struct SearchResult + " " + title + "\n" + " \n" + " " + snippet + "\n" - + "
from " + bookTitle + "
\n" - + "
" + wordCount + " words
\n"; + + "
from %USERLANGMARKER%" + bookTitle + "
\n" + + "
" + wordCount + " %USERLANGMARKER%words
\n"; } std::string getXml() const @@ -737,18 +737,16 @@ struct TestData std::string expectedHtmlHeader() const { - if ( totalResultCount == 0 ) { - return "No results were found for \"" + getPattern() + "\""; - } - - std::string header = R"(Results FIRSTRESULT-LASTRESULT of RESULTCOUNT for "PATTERN")"; + std::string header = totalResultCount == 0 + ? R"(No results were found for "PATTERN")" + : R"(Results FIRSTRESULT-LASTRESULT of RESULTCOUNT for "PATTERN")"; const size_t lastResultIndex = std::min(totalResultCount, firstResultIndex + results.size() - 1); header = replace(header, "FIRSTRESULT", std::to_string(firstResultIndex)); header = replace(header, "LASTRESULT", std::to_string(lastResultIndex)); header = replace(header, "RESULTCOUNT", std::to_string(totalResultCount)); header = replace(header, "PATTERN", getPattern()); - return header; + return "%USERLANGMARKER%" + header; } std::string expectedHtmlResultsString() const @@ -792,12 +790,18 @@ struct TestData std::string expectedHtml() const { - return makeSearchResultsHtml( - getPattern(), - expectedHtmlHeader(), - expectedHtmlResultsString(), - expectedHtmlFooter() + const std::string html = makeSearchResultsHtml( + getPattern(), + expectedHtmlHeader(), + expectedHtmlResultsString(), + expectedHtmlFooter() ); + + const std::string userlangMarker = extractQueryValue("userlang") == "test" + ? "[I18N TESTING] " + : ""; + + return replace(html, "%USERLANGMARKER%", userlangMarker); } std::string expectedXmlHeader() const @@ -816,7 +820,8 @@ struct TestData />)"; const auto realResultsPerPage = resultsPerPage?resultsPerPage:25; - const auto url = makeUrl(query + "&format=xml", firstResultIndex, realResultsPerPage); + const auto cleanedUpQuery = replace(query, "&userlang=test", ""); + const auto url = makeUrl(cleanedUpQuery + "&format=xml", firstResultIndex, realResultsPerPage); header = replace(header, "URL", replace(url, "&", "&")); header = replace(header, "FIRSTRESULT", std::to_string(firstResultIndex)); header = replace(header, "ITEMCOUNT", std::to_string(realResultsPerPage)); @@ -923,6 +928,17 @@ TEST(ServerSearchTest, searchResults) /* pagination */ {} }, + { + /* query */ "pattern=velomanyunkan&books.id=" RAYCHARLESZIMID + "&userlang=test", + /* start */ -1, + /* resultsPerPage */ 0, + /* totalResultCount */ 0, + /* firstResultIndex */ 1, + /* results */ {}, + /* pagination */ {} + }, + { /* query */ "pattern=razaf&books.id=" RAYCHARLESZIMID, /* start */ -1, @@ -1029,6 +1045,17 @@ TEST(ServerSearchTest, searchResults) /* pagination */ {} }, + { + /* query */ "pattern=jazz&books.id=" RAYCHARLESZIMID + "&userlang=test", + /* start */ -1, + /* resultsPerPage */ 100, + /* totalResultCount */ 44, + /* firstResultIndex */ 1, + /* results */ LARGE_SEARCH_RESULTS, + /* pagination */ {} + }, + { /* query */ "pattern=jazz&books.id=" RAYCHARLESZIMID, /* start */ -1,