Skip to content

Instantly share code, notes, and snippets.

@BowlingX
Created January 20, 2012 11:49
Show Gist options
  • Save BowlingX/1647010 to your computer and use it in GitHub Desktop.
Save BowlingX/1647010 to your computer and use it in GitHub Desktop.
Accept Language locale extraction
package org.scalatra.i18n
import org.scalatra.{CookieSupport, ScalatraKernel}
import java.util.Locale
import org.scalatra.i18n.Messages
object I18nSupport {
def localeKey = "locale"
def messagesKey = "messages"
}
trait I18nSupport {
this: ScalatraKernel with CookieSupport =>
import I18nSupport._
var locale: Locale = _
var messages: Messages = _
var userLocales: Array[Locale] = _
before() {
locale = resolveLocale
messages = new Messages(locale)
}
/*
* Resolve Locale based on HTTP request parameter or Cookie
*/
private def resolveLocale: Locale = {
resolveHttpLocale.map(localeFromObject(_)) getOrElse defaultLocale
}
/*
* Get locale string either from HTTP param or Cookie.
*
* If locale string is found in HTTP param, it will be set
* in cookie.
*
* If it's not found, then look at Accept-Language header.
*
*/
private def resolveHttpLocale: Option[Any] = {
params.get(localeKey) match {
case Some(localeValue) =>
cookies.set(localeKey, localeValue)
Some(localeValue)
case _ => cookies.get(localeKey) orElse resolveHttpLocaleFromUserAgent
}
}
/**
* Accept-Language header looks like "de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4"
* Specification see [[http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html]]
* @return first preferred found locale or None
*/
private def resolveHttpLocaleFromUserAgent: Option[Locale] = {
request.getHeader("Accept-Language") match {
case s: String => {
val locales = s.split(",").map(s => {
def splitLanguageCountry(s: String): Locale = {
val langCountry = s.split("-")
if (langCountry.length > 1) {
new Locale(langCountry.head, langCountry.last)
} else {
new Locale(langCountry.head)
}
}
// If this language has a quality index:
if (s.indexOf(";") > 0) {
val qualityLocale = s.split(";")
splitLanguageCountry(qualityLocale.head)
} else {
splitLanguageCountry(s)
}
})
// save all found locales for later user
userLocales = locales
// We assume that all accept-languages are stored in order of quality
// (so first language is preferred)
Some(locales.head)
}
// Its possible that "Accept-Language" header is not set
case _ => None
}
}
/**
* Reads a locale from any object
* @param in could be a string or Locale
*/
private def localeFromObject(in: Any): Locale = {
if (in.isInstanceOf[String]) {
val token = in.asInstanceOf[String].split("_")
new Locale(token.head, token.last)
} else {
in.asInstanceOf[Locale]
}
}
private def defaultLocale: Locale = {
Locale.getDefault
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment