Question

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

Was it helpful?

Solution 2

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)
  }
}

OTHER TIPS

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)

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)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top