Scala Play: как динамически настроить представление ответов для каждого языка? - PullRequest
0 голосов
/ 05 октября 2019

У меня есть Scala Play 2.7.x, и для представлений, содержащих много текста, вместо использования MessagesApi, я просто разделяю их по языку, например так:

/views 
   /en
     something.scala.html      
   /es
     something.scala.html      

, затем в моей реализации контроллера ябудет делать следующее:

def doSomething() = Action { request =>
    val lang = request.lang
    lang.code match {
        case "en" => Future.successful(Ok(views.html.en.something()))
        case "es" => Future.successful(Ok(views.html.es.something()))
        case _ => Future.successful(Ok(views.html.en.something()))
    }
  }
}

Но это подвержено ошибкам и явно не является устойчивым, поскольку мне нужно будет перекомпилировать каждый раз, когда я поддерживаю новый язык. Я бы предпочел что-то вроде этого (не работает):

def doSomething() = Action { request =>
    implicit val lang = request.lang
    val dynamicViewTarget = s"view.html.$lang.something()"
    Future.successful(Ok(dynamicViewTarget)) 
}

Как этого достичь? Возможно, еще более понятный подход - включить lang как часть ресурса маршрутизации, и он напрямую перейдет в это представление. Или сочетание этих двух идей.

1 Ответ

0 голосов
/ 06 октября 2019

После некоторых исследований я пришел к следующему полному решению. Это плагин модуля, который будет динамически разрешать представление цели Result (проверено, работает на Scala 2.12.8 и Play 2.7.3):

package modules

import javax.inject.{ Inject, Provider, Singleton }
import play.api.Application
import play.api.i18n.Lang
import play.api.mvc.{ Result, Results }
import play.twirl.api.Html

/**
 * The dynamic template loader module implementation.
 * @param app the Play Application instance.
 */
@Singleton
class DynamicTemplateLoader @Inject() (app: Provider[Application]) {
  import Results._
  import reflect.runtime.universe._
  /**
   * Returns the dynamically resolved play Result corresponding to a view function name using Reflection.
   *
   * @param target the target view name, note it's the name only e.g. "index"
   * @param args the formal arguments the view requires e.g. Seq(form, credentials)
   * @param implicitArgs the implicit arguments that the view requires e.g. Seq(request, messages, webJarsUtil,
   *                     assets, configuration)
   * @param langOpt the language to default to, if the language is defined then it will branch to the specific language
   *                otherwise will omit the language.
   * @return the dynamically resolved play Result corresponding to a view function name using Reflection.
   */
  def resolve(target: String, args: Seq[Any], implicitArgs: Seq[Any])(implicit langOpt: Option[Lang]): Result = {
    val loader = app.get().classloader
    val currentMirror = runtimeMirror(loader)
    val templateName = langOpt.map { lang => s"views.html.${lang.code}.$target" }.getOrElse(s"views.html.$target")
    val moduleMirror = currentMirror.reflectModule(currentMirror.staticModule(templateName))
    val methodSymbol = moduleMirror.symbol.typeSignature.decl(TermName("apply")).asMethod
    val instanceMirror = currentMirror.reflect(moduleMirror.instance)
    val methodMirror = instanceMirror.reflectMethod(methodSymbol)
    val allArgs = args ++ implicitArgs
    Ok(methodMirror.apply(allArgs: _*).asInstanceOf[Html])
  }
}

Пример использования:

def doSomething() = Action { request =>
  implicit val langOpt = Option(request.lang)
  val target = "something"
  val args = Seq(credentials) // e.g. user credentials
  val implicitArgs = Seq(request, messages, webJarsUtil, assets, configuration)
  Future.successful(dynamicTemplateLoader.resolve(target, args, implicitArgs)) 
}

и, наконец,образец views/en/something.scala.html

@import play.api.i18n.Messages
@import play.api.mvc.RequestHeader
@import org.webjars.play.WebJarsUtil
@import controllers.AssetsFinder
@import play.api.data._
@import play.api.Configuration

@(credentials: Credentials)(implicit request: RequestHeader, messages: Messages, webJarsUtil: WebJarsUtil, assets: AssetsFinder, configuration: Configuration) {
  <div class="TODO">
  <div>
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...