Reputation: 324
the short question is: is there a way to change the ACCEPT_LANGUAGE Request Header before Play extracts it to determine the i18n language?
I thought that this could be accompished by overriding onRouteRequest (see http://www.playframework.com/documentation/2.2.0/ScalaInterceptors).
But it does not seem to work. This is my "test" code, see the same at https://gist.github.com/mcallisto/3f428fad87f7a7759519
import play.api._
import play.api.mvc._
import play.api.http.HeaderNames
object Global extends GlobalSettings {
override def onRouteRequest(rh: RequestHeader): Option[Handler] = {
Logger.info("Request: " + rh.toString)
Logger.info("Accepted languages : " + rh.acceptLanguages.mkString(", "))
val newLang = "it"
val newHeaders = new Headers { val data = (rh.headers.toMap
+ (HeaderNames.ACCEPT_LANGUAGE -> Seq(newLang))).toList }
val newRequestHeader = rh.copy(headers = newHeaders)
Logger.info("New accepted languages : " + newRequestHeader.acceptLanguages.mkString(", "))
super.onRouteRequest(newRequestHeader)
}
}
Without this code, i18n works according to the browser settings affecting the AcceptLanguage header.
With it, even if the header is apparently changed to the Italian ("it") language (see logger), still the i18n is given by the browser language.
At which point Play extracts the header?
Is there any other way to achieve the same goal? I would just like to reach a basic step where the request subdomain (like it.example.com) prevails against the browser settings to determine the i18n
Thank you in advance for your hints
Upvotes: 2
Views: 1419
Reputation: 609
You could try this:
import play.api._
import play.api.mvc._
import play.api.http.HeaderNames
import scala.concurrent.Future
object LangFromSubdomain extends Filter {
def apply(next: (RequestHeader) => Future[SimpleResult])(requestHeader: RequestHeader): Future[SimpleResult] = {
val subdomainLanguage = requestHeader.domain.toString.substring(0, 3) match {
case "it." => "it"
case "es." => "es"
case _ => "en"
}
next(requestHeader.copy(headers = requestHeader.headers.add(HeaderNames.ACCEPT_LANGUAGE -> subdomainLanguage)))
}
}
object Global extends WithFilters(LangFromSubdomain)
Upvotes: 0
Reputation: 324
Thanks to @vptheron, this is working
import play.api._
import play.api.mvc._
import play.api.http.HeaderNames
import scala.concurrent.Future
object LangFromSubdomain extends Filter {
def apply(next: (RequestHeader) => Future[SimpleResult])(request: RequestHeader): Future[SimpleResult] = {
val subdomainLanguage = request.domain.toString.substring(0, 3) match {
case "it." => "it"
case "es." => "es"
case _ => "en"
}
val newHeaders = new Headers { val data = (request.headers.toMap
+ (HeaderNames.ACCEPT_LANGUAGE -> Seq(subdomainLanguage))).toList }
val newRequestHeader = request.copy(headers = newHeaders)
next(newRequestHeader)
}
}
object Global extends WithFilters(LangFromSubdomain)
Upvotes: 2
Reputation: 7466
Note that in onRouteRequest
you are overriding the behavior to find the handler that will handle your request, not the call to the handler itself.
onRouteRequest
is called from onRequestReceived
:
def onRequestReceived(request: RequestHeader): (RequestHeader, Handler) = {
val (routedRequest, handler) = onRouteRequest(request) map {
case handler: RequestTaggingHandler => (handler.tagRequest(request), handler)
case otherHandler => (request, otherHandler)
} getOrElse {
(request, Action.async(BodyParsers.parse.empty)(_ => this.onHandlerNotFound(request)))
}
(routedRequest, doFilter(rh => handler)(routedRequest))
}
Note how the returned tuple of type (RequestHeader, Handler)
is using the original request
. Basically, all the changes to the request that you perfom in onRouteRequest
are completely ignored since the original request is used and applied to the found handler.
For your use case, a Filter may be a better option:
object ItalianLanguage extends Filter {
def apply(next: (RequestHeader) => Future[SimpleResult])(request: RequestHeader): Future[SimpleResult] = {
// your code to set the italian language in request
next(request)
}
}
Upvotes: 1