propose language fallbacks
This commit is contained in:
parent
d6856e2dfe
commit
f32fee941f
|
@ -1,15 +1,15 @@
|
||||||
package lila.app
|
package lila.app
|
||||||
package templating
|
package templating
|
||||||
|
|
||||||
|
import scala.util.Random.shuffle
|
||||||
|
|
||||||
import controllers._
|
import controllers._
|
||||||
import lila.user.Context
|
|
||||||
import lila.i18n.Env.{ current ⇒ i18nEnv }
|
import lila.i18n.Env.{ current ⇒ i18nEnv }
|
||||||
import lila.i18n.{ LangList, I18nDomain }
|
import lila.i18n.{ LangList, I18nDomain }
|
||||||
|
import lila.user.Context
|
||||||
import play.api.i18n.Lang
|
import play.api.i18n.Lang
|
||||||
import play.api.templates.Html
|
|
||||||
import play.api.mvc.{ RequestHeader, Call }
|
import play.api.mvc.{ RequestHeader, Call }
|
||||||
import scala.util.Random.shuffle
|
import play.api.templates.Html
|
||||||
|
|
||||||
trait I18nHelper {
|
trait I18nHelper {
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ trait I18nHelper {
|
||||||
|
|
||||||
def langLinks(lang: Lang)(implicit ctx: Context) = Html {
|
def langLinks(lang: Lang)(implicit ctx: Context) = Html {
|
||||||
langLinksCache.getOrElseUpdate(lang.language, {
|
langLinksCache.getOrElseUpdate(lang.language, {
|
||||||
pool.names.toList sortBy (_._1) collect {
|
pool.names.toList sortBy (_._1) map {
|
||||||
case (code, name) ⇒ """<li><a lang="%s" href="%s"%s>%s</a></li>""".format(
|
case (code, name) ⇒ """<li><a lang="%s" href="%s"%s>%s</a></li>""".format(
|
||||||
code,
|
code,
|
||||||
langUrl(Lang(code))(I18nDomain(ctx.req.domain)),
|
langUrl(Lang(code))(I18nDomain(ctx.req.domain)),
|
||||||
|
@ -48,11 +48,23 @@ trait I18nHelper {
|
||||||
}).replace(uriPlaceholder, ctx.req.uri)
|
}).replace(uriPlaceholder, ctx.req.uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def langFallbackLinks(implicit ctx: Context) = Html {
|
||||||
|
{
|
||||||
|
pool.preferredNames(ctx.req, 3) map {
|
||||||
|
case (code, name) ⇒ """<a class="lang_fallback" lang="%s" href="%s">%s</a>""".format(
|
||||||
|
code, langUrl(Lang(code))(I18nDomain(ctx.req.domain)), name)
|
||||||
|
} mkString ""
|
||||||
|
}.replace(uriPlaceholder, ctx.req.uri)
|
||||||
|
}
|
||||||
|
|
||||||
def commonDomain(implicit ctx: Context): String =
|
def commonDomain(implicit ctx: Context): String =
|
||||||
I18nDomain(ctx.req.domain).commonDomain
|
I18nDomain(ctx.req.domain).commonDomain
|
||||||
|
|
||||||
def acceptLanguages(implicit ctx: Context): String =
|
def acceptLanguages(implicit ctx: Context): List[String] =
|
||||||
ctx.req.acceptLanguages.map(_.language).distinct mkString ","
|
ctx.req.acceptLanguages.map(_.language.toString).toList.distinct
|
||||||
|
|
||||||
|
def acceptsLanguage(lang: Lang)(implicit ctx: Context): Boolean =
|
||||||
|
ctx.req.acceptLanguages exists (_.language == lang.language)
|
||||||
|
|
||||||
private val uriPlaceholder = "[URI]"
|
private val uriPlaceholder = "[URI]"
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ themepicker: Boolean = false)(body: Html)(implicit ctx: Context)
|
||||||
data-sound-file="@routes.Assets.at("sound/alert.ogg")"
|
data-sound-file="@routes.Assets.at("sound/alert.ogg")"
|
||||||
data-troll="@ctx.troll.toString"
|
data-troll="@ctx.troll.toString"
|
||||||
data-port="@netPort"
|
data-port="@netPort"
|
||||||
data-accept-languages="@acceptLanguages">
|
data-accept-languages="@acceptLanguages.mkString(",")">
|
||||||
<div id="site_description">@trans.freeOnlineChessGamePlayChessNowInACleanInterfaceNoRegistrationNoAdsNoPluginRequiredPlayChessWithComputerFriendsOrRandomOpponents()</div>
|
<div id="site_description">@trans.freeOnlineChessGamePlayChessNowInACleanInterfaceNoRegistrationNoAdsNoPluginRequiredPlayChessWithComputerFriendsOrRandomOpponents()</div>
|
||||||
<div id="top" class="clearfix">
|
<div id="top" class="clearfix">
|
||||||
<a title="@trans.toggleSound()" id="sound_state" class="available">
|
<a title="@trans.toggleSound()" id="sound_state" class="available">
|
||||||
|
@ -102,7 +102,11 @@ data-accept-languages="@acceptLanguages">
|
||||||
<a id="site_title" href="@routes.Lobby.home">
|
<a id="site_title" href="@routes.Lobby.home">
|
||||||
lichess<span class="extension">.org</span>
|
lichess<span class="extension">.org</span>
|
||||||
</a>
|
</a>
|
||||||
|
@if(acceptsLanguage(lang)) {
|
||||||
@baseline
|
@baseline
|
||||||
|
} else {
|
||||||
|
@langFallbackLinks
|
||||||
|
}
|
||||||
</h1>
|
</h1>
|
||||||
@menu.map { side =>
|
@menu.map { side =>
|
||||||
<div class="side_menu">@side</div>
|
<div class="side_menu">@side</div>
|
||||||
|
|
|
@ -9,15 +9,19 @@ private[i18n] case class I18nPool(val langs: Set[Lang], val default: Lang) {
|
||||||
|
|
||||||
def nonDefaultLangs = langs - default
|
def nonDefaultLangs = langs - default
|
||||||
|
|
||||||
val names: Map[String, String] = langs map { l ⇒
|
val names: Map[String, String] = (langs map langNames).toMap
|
||||||
l.language -> LangList.nameOrCode(l.language)
|
|
||||||
} toMap
|
private def langNames(lang: Lang): (String, String) =
|
||||||
|
lang.language -> LangList.nameOrCode(lang.language)
|
||||||
|
|
||||||
def lang(req: RequestHeader) = domainLang(req) | default
|
def lang(req: RequestHeader) = domainLang(req) | default
|
||||||
|
|
||||||
def preferred(req: RequestHeader) =
|
def preferred(req: RequestHeader) =
|
||||||
(req.acceptLanguages find langs.contains) | default
|
(req.acceptLanguages find langs.contains) | default
|
||||||
|
|
||||||
|
def preferredNames(req: RequestHeader, nb: Int): Seq[(String, String)] =
|
||||||
|
req.acceptLanguages filter langs.contains take nb map langNames
|
||||||
|
|
||||||
def domainLang(req: RequestHeader) =
|
def domainLang(req: RequestHeader) =
|
||||||
cache.getOrElseUpdate(req.domain, {
|
cache.getOrElseUpdate(req.domain, {
|
||||||
I18nDomain(req.domain).lang filter langs.contains
|
I18nDomain(req.domain).lang filter langs.contains
|
||||||
|
|
|
@ -602,9 +602,10 @@ var storage = {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var acceptLanguages = $('body').data('accept-languages').split(',');
|
||||||
$('#top .lichess_language').one('mouseover', function() {
|
$('#top .lichess_language').one('mouseover', function() {
|
||||||
var $t = $(this);
|
var $t = $(this);
|
||||||
_.each($('body').data('accept-languages').split(','), function(lang) {
|
_.each(acceptLanguages, function(lang) {
|
||||||
$t.find('a[lang="' + lang + '"]').addClass('accepted');
|
$t.find('a[lang="' + lang + '"]').addClass('accepted');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -362,6 +362,11 @@ body.tight #site_header {
|
||||||
#site_header strong {
|
#site_header strong {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
#site_header a.lang_fallback {
|
||||||
|
font-weight: bold;
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
body > div.content {
|
body > div.content {
|
||||||
width: 1005px;
|
width: 1005px;
|
||||||
min-height: 590px;
|
min-height: 590px;
|
||||||
|
|
Loading…
Reference in a new issue