mirror of https://github.com/kiwix/libkiwix.git
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.
This commit is contained in:
parent
33a3277400
commit
958067d94d
|
@ -72,6 +72,13 @@ class SearchRenderer
|
||||||
this->pageLength = pageLength;
|
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.
|
* Generate the html page with the resutls of the search.
|
||||||
*
|
*
|
||||||
|
@ -105,6 +112,7 @@ class SearchRenderer
|
||||||
unsigned int pageLength;
|
unsigned int pageLength;
|
||||||
unsigned int estimatedResultCount;
|
unsigned int estimatedResultCount;
|
||||||
unsigned int resultStart;
|
unsigned int resultStart;
|
||||||
|
std::string userlang = "en";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -192,7 +192,6 @@ kainjow::mustache::data buildPagination(
|
||||||
|
|
||||||
std::string SearchRenderer::renderTemplate(const std::string& tmpl_str, const NameMapper& nameMapper, const Library* library)
|
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;
|
const std::string absPathPrefix = protocolPrefix;
|
||||||
// Build the results list
|
// Build the results list
|
||||||
kainjow::mustache::data items{kainjow::mustache::data::type::list};
|
kainjow::mustache::data items{kainjow::mustache::data::type::list};
|
||||||
|
|
|
@ -967,6 +967,7 @@ std::unique_ptr<Response> InternalServer::handle_search_request(const RequestCon
|
||||||
renderer.setProtocolPrefix(m_root + "/content/");
|
renderer.setProtocolPrefix(m_root + "/content/");
|
||||||
renderer.setSearchProtocolPrefix(m_root + "/search");
|
renderer.setSearchProtocolPrefix(m_root + "/search");
|
||||||
renderer.setPageLength(pageLength);
|
renderer.setPageLength(pageLength);
|
||||||
|
renderer.setUserLang(request.get_user_language());
|
||||||
if (request.get_requested_format() == "xml") {
|
if (request.get_requested_format() == "xml") {
|
||||||
return ContentResponse::build(
|
return ContentResponse::build(
|
||||||
renderer.getXml(*mp_nameMapper, mp_library.get()),
|
renderer.getXml(*mp_nameMapper, mp_library.get()),
|
||||||
|
|
|
@ -42,4 +42,9 @@
|
||||||
, "preview-book": "[I18N] Preview [TESTING]"
|
, "preview-book": "[I18N] Preview [TESTING]"
|
||||||
, "no-query" : "[I18N TESTING] Kiwix can read your thoughts but it is against GDPR. Please provide your query explicitly."
|
, "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}}}\""
|
, "invalid-request" : "[I18N TESTING] Invalid URL: \"{{{url}}}\""
|
||||||
|
, "search-results-page-title": "[I18N TESTING] Search: {{SEARCH_PATTERN}}"
|
||||||
|
, "search-results-page-header": "[I18N TESTING] Results <b>{{START}}-{{END}}</b> of <b>{{COUNT}}</b> for <b>\"{{{SEARCH_PATTERN}}}\"</b>"
|
||||||
|
, "empty-search-results-page-header": "[I18N TESTING] No results were found for <b>\"{{{SEARCH_PATTERN}}}\"</b>"
|
||||||
|
, "search-result-book-info": "from [I18N TESTING] {{BOOK_TITLE}}"
|
||||||
|
, "word-count": "{{COUNT}} [I18N TESTING] words"
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ std::string makeSearchResultsHtml(const std::string& pattern,
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<title>Search: %PATTERN%</title>
|
<title>%USERLANGMARKER%Search: %PATTERN%</title>
|
||||||
</head>
|
</head>
|
||||||
<body bgcolor="white">
|
<body bgcolor="white">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
|
@ -173,8 +173,8 @@ struct SearchResult
|
||||||
+ " " + title + "\n"
|
+ " " + title + "\n"
|
||||||
+ " </a>\n"
|
+ " </a>\n"
|
||||||
+ " <cite>" + snippet + "</cite>\n"
|
+ " <cite>" + snippet + "</cite>\n"
|
||||||
+ " <div class=\"book-title\">from " + bookTitle + "</div>\n"
|
+ " <div class=\"book-title\">from %USERLANGMARKER%" + bookTitle + "</div>\n"
|
||||||
+ " <div class=\"informations\">" + wordCount + " words</div>\n";
|
+ " <div class=\"informations\">" + wordCount + " %USERLANGMARKER%words</div>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getXml() const
|
std::string getXml() const
|
||||||
|
@ -737,18 +737,16 @@ struct TestData
|
||||||
|
|
||||||
std::string expectedHtmlHeader() const
|
std::string expectedHtmlHeader() const
|
||||||
{
|
{
|
||||||
if ( totalResultCount == 0 ) {
|
std::string header = totalResultCount == 0
|
||||||
return "No results were found for <b>\"" + getPattern() + "\"</b>";
|
? R"(No results were found for <b>"PATTERN"</b>)"
|
||||||
}
|
: R"(Results <b>FIRSTRESULT-LASTRESULT</b> of <b>RESULTCOUNT</b> for <b>"PATTERN"</b>)";
|
||||||
|
|
||||||
std::string header = R"(Results <b>FIRSTRESULT-LASTRESULT</b> of <b>RESULTCOUNT</b> for <b>"PATTERN"</b>)";
|
|
||||||
|
|
||||||
const size_t lastResultIndex = std::min(totalResultCount, firstResultIndex + results.size() - 1);
|
const size_t lastResultIndex = std::min(totalResultCount, firstResultIndex + results.size() - 1);
|
||||||
header = replace(header, "FIRSTRESULT", std::to_string(firstResultIndex));
|
header = replace(header, "FIRSTRESULT", std::to_string(firstResultIndex));
|
||||||
header = replace(header, "LASTRESULT", std::to_string(lastResultIndex));
|
header = replace(header, "LASTRESULT", std::to_string(lastResultIndex));
|
||||||
header = replace(header, "RESULTCOUNT", std::to_string(totalResultCount));
|
header = replace(header, "RESULTCOUNT", std::to_string(totalResultCount));
|
||||||
header = replace(header, "PATTERN", getPattern());
|
header = replace(header, "PATTERN", getPattern());
|
||||||
return header;
|
return "%USERLANGMARKER%" + header;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string expectedHtmlResultsString() const
|
std::string expectedHtmlResultsString() const
|
||||||
|
@ -792,12 +790,18 @@ struct TestData
|
||||||
|
|
||||||
std::string expectedHtml() const
|
std::string expectedHtml() const
|
||||||
{
|
{
|
||||||
return makeSearchResultsHtml(
|
const std::string html = makeSearchResultsHtml(
|
||||||
getPattern(),
|
getPattern(),
|
||||||
expectedHtmlHeader(),
|
expectedHtmlHeader(),
|
||||||
expectedHtmlResultsString(),
|
expectedHtmlResultsString(),
|
||||||
expectedHtmlFooter()
|
expectedHtmlFooter()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const std::string userlangMarker = extractQueryValue("userlang") == "test"
|
||||||
|
? "[I18N TESTING] "
|
||||||
|
: "";
|
||||||
|
|
||||||
|
return replace(html, "%USERLANGMARKER%", userlangMarker);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string expectedXmlHeader() const
|
std::string expectedXmlHeader() const
|
||||||
|
@ -816,7 +820,8 @@ struct TestData
|
||||||
/>)";
|
/>)";
|
||||||
|
|
||||||
const auto realResultsPerPage = resultsPerPage?resultsPerPage:25;
|
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, "URL", replace(url, "&", "&"));
|
||||||
header = replace(header, "FIRSTRESULT", std::to_string(firstResultIndex));
|
header = replace(header, "FIRSTRESULT", std::to_string(firstResultIndex));
|
||||||
header = replace(header, "ITEMCOUNT", std::to_string(realResultsPerPage));
|
header = replace(header, "ITEMCOUNT", std::to_string(realResultsPerPage));
|
||||||
|
@ -923,6 +928,17 @@ TEST(ServerSearchTest, searchResults)
|
||||||
/* pagination */ {}
|
/* 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,
|
/* query */ "pattern=razaf&books.id=" RAYCHARLESZIMID,
|
||||||
/* start */ -1,
|
/* start */ -1,
|
||||||
|
@ -1029,6 +1045,17 @@ TEST(ServerSearchTest, searchResults)
|
||||||
/* pagination */ {}
|
/* 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,
|
/* query */ "pattern=jazz&books.id=" RAYCHARLESZIMID,
|
||||||
/* start */ -1,
|
/* start */ -1,
|
||||||
|
|
Loading…
Reference in New Issue