Play Router: Как добавить правило перенаправления URL-адреса с учетом языка? - PullRequest
1 голос
/ 09 октября 2019

У меня есть интернационализированное веб-приложение Scala Play 2.7.x, и у меня есть обычные маршруты, например,

GET /               controllers.ApplicationController.index
GET /page/somePage/ controllers.SomeController.somePage
GET /contact        controllers.ContactController.view

Теперь я хотел бы добавить новый маршрут, который будет в основном менять язык-перенаправлять на любой целевой маршрут. ,Я реализую этот вариант использования, добавив дополнительный маршрут поверх routes, например:

GET /$lang<(en|es)> controllers.ApplicationController.langRedirect(lang: String, target: String = "")

Идея состоит в том, что каждый раз, когда вы делаете, например,

http://localhost:9000/en => will go to home page in english
http://localhost:9000/en/contact => will go to contact page in english
http://localhost:9000/es => will go to home page in spanish
http://localhost:9000/es/contact => will go to contact page in spanish

и т. Д. ,К сожалению, он не всегда работает, например, тот, который включен до /en/page/somePage/, он не будет правильно соответствовать первому правилу:

 GET /$lang<(en|es)> controllers.ApplicationController.langRedirect(lang: String, target: String = "")

предположительно из-за промежуточного / ... как я могу это исправитьчто?

Для полноты вот моя реализация ApplicationController.langRedirect(...):

def langRedirect(lang: String, target: String = "") = silhouette.UserAwareAction.async { implicit request =>
    Future.successful(Redirect("/" + target).withLang(Lang(lang)))
}

Ответы [ 2 ]

1 голос
/ 13 октября 2019

Используя Router.withPrefix, вы можете добавить префикс кода языка ко всем вашим маршрутам.

Вот пример.

package handlers

import javax.inject.Inject
import play.api.http._
import play.api.i18n.{ Langs, Lang }
import play.api.mvc.{ Handler, RequestHeader }

class I18nRequestHandler @Inject()(
    webCommands: play.core.WebCommands,
    optDevContext: play.api.OptionalDevContext,
    router: play.api.routing.Router,
    errorHandler: HttpErrorHandler,
    configuration: HttpConfiguration,
    filters: HttpFilters,
    langs: Langs)
  extends DefaultHttpRequestHandler(
    webCommands, optDevContext, router, errorHandler, configuration, filters) {

  def getLang(request: RequestHeader): Lang = {
    // Get the first path
    request.path.tail.split('/').headOption
      .flatMap(path => Lang.get(path))
      // language from the fist path, if it is in "play.i18n.langs (application.conf)"
      .filter(lang => langs.availables.exists(_ == lang))
      // Or preferred language, refereeing "Accept-Languages"
      .getOrElse(langs.preferred(request.acceptLanguages))
  }

  override def handlerForRequest(request: RequestHeader): (RequestHeader, Handler) = {
    // To use the language code from the path with MessagesApi,
    // Replace "Accept-Languages" to the language from the path.
    val requestWithLang = request.withHeaders(
      request.headers.replace(HeaderNames.ACCEPT_LANGUAGE -> getLang(request).code))
    super.handlerForRequest(requestWithLang)
  }

  override def routeRequest(request: RequestHeader): Option[Handler] = {
    val lang = getLang(request)
    request.path.tail.split('/').headOption
      // If the first path is right language code (if not, Not Found)
      .filter(_ == lang.code)
      // Route this request with language code prefix
      .flatMap(_ => router.withPrefix("/" + lang.code).handlerFor(request))
  }
}

Чтобы включить I18nRequestHandler, вы должны добавить егов "application.conf".

play.http.requestHandler = "handlers.I18nRequestHandler"

Также добавьте поддерживаемые языки в "application.conf".

play.i18n.langs = [ "en", "es" ]

Этот код заставляет все маршруты иметь префикс кода языка. Если вам нужны исключительные маршруты, такие как "/", чтобы позволить пользователям выбирать его язык, создайте пользовательские маршруты и добавьте его по методу routeRequest.

Надеюсь, это именно то, что вам нужно;)

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

ОК нашел возможное решение, которое заключается в добавлении второго верхнего маршрута, который будет принимать любую возможную цель, включая /, вершина моего routes файла теперь выглядит следующим образом:

GET /$lang<(en|es)> controllers.ApplicationController.langRedirect(lang: String, target: String = "")
GET /$lang<(en|es)>/*target controllers.ApplicationController.langRedirect(lang: String, target: String = "")    

GET /               controllers.ApplicationController.index
GET /page/somePage/ controllers.SomeController.somePage
GET /contact        controllers.ContactController.view

Почему янужно два? потому что домашняя страница может быть только http://localhost:9000/en и не может быть http://localhost:9000/en/

Однако я буду рад узнать (и принять) лучшее / более простое решение.

...