mirror of https://github.com/kiwix/libkiwix.git
Preliminary support for Accept-Language: header
In the absence of the "userlang" query parameter in the URL, the value of the "Accept-Language" header is used. However, it is assumed that "Accept-Language" specifies a single language (rather than a comma separated list of languages possibly weighted with quality values). Example: Accept-Language: fr // should work Accept-Language: fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5 // The requested language will be considered to be // "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5". // The i18n code will fail to find resources for such a language // and will use the default "en" instead.
This commit is contained in:
parent
9987fbd488
commit
927c12574a
|
@ -195,7 +195,15 @@ std::string RequestContext::get_query() const {
|
||||||
|
|
||||||
std::string RequestContext::get_user_language() const
|
std::string RequestContext::get_user_language() const
|
||||||
{
|
{
|
||||||
return get_optional_param<std::string>("userlang", "en");
|
try {
|
||||||
|
return get_argument("userlang");
|
||||||
|
} catch(const std::out_of_range&) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return get_header("Accept-Language");
|
||||||
|
} catch(const std::out_of_range&) {}
|
||||||
|
|
||||||
|
return "en";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,6 @@ std::string removeEOLWhitespaceMarkers(const std::string& s)
|
||||||
return std::regex_replace(s, pattern, "");
|
return std::regex_replace(s, pattern, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ZimFileServer
|
class ZimFileServer
|
||||||
{
|
{
|
||||||
public: // types
|
public: // types
|
||||||
|
@ -879,6 +878,79 @@ TEST_F(ServerTest, 500)
|
||||||
EXPECT_EQ(r->body, expectedBody);
|
EXPECT_EQ(r->body, expectedBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, UserLanguageControl)
|
||||||
|
{
|
||||||
|
struct TestData
|
||||||
|
{
|
||||||
|
const std::string url;
|
||||||
|
const std::string acceptLanguageHeader;
|
||||||
|
const std::string expectedH1;
|
||||||
|
|
||||||
|
operator TestContext() const
|
||||||
|
{
|
||||||
|
return TestContext{
|
||||||
|
{"url", url},
|
||||||
|
{"acceptLanguageHeader", acceptLanguageHeader},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const TestData testData[] = {
|
||||||
|
{
|
||||||
|
/*url*/ "/ROOT/zimfile/invalid-article",
|
||||||
|
/*Accept-Language:*/ "",
|
||||||
|
/* expected <h1> */ "Not Found"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/*url*/ "/ROOT/zimfile/invalid-article?userlang=en",
|
||||||
|
/*Accept-Language:*/ "",
|
||||||
|
/* expected <h1> */ "Not Found"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/*url*/ "/ROOT/zimfile/invalid-article?userlang=hy",
|
||||||
|
/*Accept-Language:*/ "",
|
||||||
|
/* expected <h1> */ "Սխալ հասցե"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/*url*/ "/ROOT/zimfile/invalid-article",
|
||||||
|
/*Accept-Language:*/ "*",
|
||||||
|
/* expected <h1> */ "Not Found"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/*url*/ "/ROOT/zimfile/invalid-article",
|
||||||
|
/*Accept-Language:*/ "hy",
|
||||||
|
/* expected <h1> */ "Սխալ հասցե"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// userlang query parameter takes precedence over Accept-Language
|
||||||
|
/*url*/ "/ROOT/zimfile/invalid-article?userlang=en",
|
||||||
|
/*Accept-Language:*/ "hy",
|
||||||
|
/* expected <h1> */ "Not Found"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// The value of the Accept-Language header is not currently parsed.
|
||||||
|
// In case of a comma separated list of languages (optionally weighted
|
||||||
|
// with quality values) the default (en) language is used instead.
|
||||||
|
/*url*/ "/ROOT/zimfile/invalid-article",
|
||||||
|
/*Accept-Language:*/ "hy;q=0.9, en;q=0.2",
|
||||||
|
/* expected <h1> */ "Not Found"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::regex h1Regex("<h1>(.+)</h1>");
|
||||||
|
for ( const auto& t : testData ) {
|
||||||
|
std::smatch h1Match;
|
||||||
|
Headers headers;
|
||||||
|
if ( !t.acceptLanguageHeader.empty() ) {
|
||||||
|
headers.insert({"Accept-Language", t.acceptLanguageHeader});
|
||||||
|
}
|
||||||
|
const auto r = zfs1_->GET(t.url.c_str(), headers);
|
||||||
|
std::regex_search(r->body, h1Match, h1Regex);
|
||||||
|
const std::string h1(h1Match[1]);
|
||||||
|
EXPECT_EQ(h1, t.expectedH1) << t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ServerTest, RandomPageRedirectsToAnExistingArticle)
|
TEST_F(ServerTest, RandomPageRedirectsToAnExistingArticle)
|
||||||
{
|
{
|
||||||
auto g = zfs1_->GET("/ROOT/random?content=zimfile");
|
auto g = zfs1_->GET("/ROOT/random?content=zimfile");
|
||||||
|
|
Loading…
Reference in New Issue