Felipe
Felipe

Reputation: 7563

Using play.i18n.Lang or play.api.i18n.Messages at Play framework with Scala

I am trying to put internationalization on my Play for Scala example. I am following the book Play for Scala. I am getting errors about which parameter long use (play.i18n.Lang or play.api.i18n.Messages). The problem is that when I use play.api.i18n.Messages the method @Messages("products.form") and I have to use @Messages.get("products.form") from play.i18n.Lang. The errors are:

[info] Compiling 21 Scala sources and 1 Java source to /home/felipe/workspace-play/products/target/scala-2.11/classes...
[error] /home/felipe/workspace-play/products/app/controllers/Products.scala:34: could not find implicit value for parameter lang: play.i18n.Lang
[error]       Ok(views.html.products.details(product))
[error]                                     ^
[error] /home/felipe/workspace-play/products/app/views/products/editProduct.scala.html:13: could not find implicit value for parameter messages: play.api.i18n.Messages
[error]      @helper.inputText(productForm("ean"))
[error]                       ^
[error] /home/felipe/workspace-play/products/app/views/products/editProduct.scala.html:14: could not find implicit value for parameter messages: play.api.i18n.Messages
[error]      @helper.inputText(productForm("name"))
[error]                       ^
[error] /home/felipe/workspace-play/products/app/views/products/editProduct.scala.html:15: could not find implicit value for parameter messages: play.api.i18n.Messages
[error]      @helper.textarea(productForm("description"))
[error]                      ^
[error] /home/felipe/workspace-play/products/app/views/products/list.scala.html:4: could not find implicit value for parameter lang: play.i18n.Lang
[error] @main(Messages.get("application.name")) {
[error]                                         ^
[error] 5 errors found

My controller :

package controllers

import models.Product
import play.api.mvc.{Action, Controller}
import play.api.data.Form
import play.api.data.Forms.{mapping, longNumber, nonEmptyText}
import play.api.mvc.Flash
import play.i18n._
// import play.api.i18n.Messages
// import play.api.Play.current
// import play.api.i18n.Messages.Implicits._

/**
  * Created by felipe on 6/4/16.
  */
class Products extends Controller {

  private val productForm: Form[Product] = Form(
    mapping(
      "ean" -> longNumber.verifying(
        "validation.ean.duplicate", Product.findByEan(_).isEmpty),
      "name" -> nonEmptyText,
      "description" -> nonEmptyText
    )(Product.apply)(Product.unapply)
  )

  def list = Action { implicit request =>
    val products = Product.findAll
    Ok(views.html.products.list(products))
  }

  def show(ean: Long) = Action { implicit request =>
    Product.findByEan(ean).map { product =>
      Ok(views.html.products.details(product))
    }.getOrElse(NotFound)
  }

  def save = Action { implicit request =>

    val newProductForm = productForm.bindFromRequest()

    newProductForm.fold(
      hasErrors = { form =>
        Redirect(routes.Products.newProduct()).
          flashing(Flash(form.data) +
            ("error" -> Messages.get("validation.errors")))
      },
      success = { newProduct =>
        Product.add(newProduct)
        val message = Messages.get("products.new.success", newProduct.name)
        Redirect(routes.Products.show(newProduct.ean)).flashing("success" -> message)
      }
    )
  }

  def newProduct = Action { implicit request =>
    val form = if (request.flash.get("error").isDefined)
      productForm.bind(request.flash.data)
    else
      productForm
    Ok(views.html.products.editProduct(form))
  }
}

My view:

@(productForm: Form[Product])(implicit flash: Flash, lang: Lang)
@import play.i18n._
@import helper._

@main(Messages.get("products.form")) {
  <h2>@Messages.get("products.form")</h2>

  @helper.form(action = routes.Products.save()) {
    <fieldset>
     <legend>
      @Messages.get("products.details", Messages.get("products.new"))
     </legend>
     @helper.inputText(productForm("ean"))
     @helper.inputText(productForm("name"))
     @helper.textarea(productForm("description"))
    </fieldset>
    <p>
      <input type="submit" class="btn primary" value='@Messages.get("products.new.submit")'>
    </p>
   }
}

Upvotes: 1

Views: 2574

Answers (1)

Felipe
Felipe

Reputation: 7563

I got it to work! Thanks anyway. Here is my solution based on this question.

I am using view form helpers (such as @inputText) requires you to pass an implicit play.api.i18n.Messages parameter to your view. You can do this adding (implicit messages: Messages) to the signature. Then I am using application controller with this parameter implicitly available in my scope. The simplest way to do this is to implement play's I18nSupport trait.

package controllers

import javax.inject.Inject

import models.Product
import play.api.mvc.{Action, Controller}
import play.api.data.Form
import play.api.data.Forms.{longNumber, mapping, nonEmptyText}
import play.api.i18n.{I18nSupport, Messages, MessagesApi}
import play.api.mvc.Flash

/**
  * Created by felipe on 6/4/16.
  */
class Products @Inject()(val messagesApi: MessagesApi) extends Controller with I18nSupport {

  private val productForm: Form[Product] = Form(
    mapping(
      "ean" -> longNumber.verifying(
        "validation.ean.duplicate", Product.findByEan(_).isEmpty),
      "name" -> nonEmptyText,
      "description" -> nonEmptyText
    )(Product.apply)(Product.unapply)
  )

  def list = Action { implicit request =>
    val products = Product.findAll
    Ok(views.html.products.list(products))
  }

  def show(ean: Long) = Action { implicit request =>
    Product.findByEan(ean).map { product =>
      Ok(views.html.products.details(product))
    }.getOrElse(NotFound)
  }

  def save = Action { implicit request =>

    val newProductForm = productForm.bindFromRequest()

    newProductForm.fold(
      hasErrors = { form =>
        Redirect(routes.Products.newProduct()).
          flashing(Flash(form.data) +
            ("error" -> Messages("validation.errors")))
      },
      success = { newProduct =>
        Product.add(newProduct)
        val message = Messages("products.new.success", newProduct.name)
        Redirect(routes.Products.show(newProduct.ean)).flashing("success" -> message)
      }
    )
  }

  def newProduct = Action { implicit request =>
    val form = if (request.flash.get("error").isDefined)
      productForm.bind(request.flash.data)
    else
      productForm
    Ok(views.html.products.editProduct(form))
  }
}

The view:

@(productForm: Form[Product])(implicit flash: Flash, messages: Messages)
@import helper._

@main(Messages("products.form")) {
  <h2>@Messages("products.form")</h2>

  @helper.form(action = routes.Products.save()) {
    <fieldset>
     <legend>
      @Messages("products.details", Messages("products.new"))
     </legend>
     @helper.inputText(productForm("ean"))
     @helper.inputText(productForm("name"))
     @helper.textarea(productForm("description"))
    </fieldset>
    <p>
      <input type="submit" class="btn primary" value='@Messages("products.new.submit")'>
    </p>
   }
}

Upvotes: 1

Related Questions