Skip to content

Instantly share code, notes, and snippets.

@wsargent
Forked from loicknuchel/README.md
Created September 8, 2016 00:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wsargent/a2ce40edd8e9ebd333193be90266d6ba to your computer and use it in GitHub Desktop.
Save wsargent/a2ce40edd8e9ebd333193be90266d6ba to your computer and use it in GitHub Desktop.
Missing features in Play i18n

I use Play 2.5.6 with Scala and found several interesting modules but I think some basic and really useful features are still missing...

Here is my sample app where I do my tests :

I list here needed features (according to me) from the most needed to the least needed.

1 - Langage selection

MessagesApi use the browser Accept-Language to choose language which is really nice :) But sometimes I want to give to the user the possibility to change the language of the application and I couldn't figure out how... Maybe I just lack of knowledge but none of my google search did help.

2 - Pluralization

I often have text like : "no results", "1 result", "5 results" and it doesn't seem to exist a convenient way to do it in Play templates. The naive approach is quite verbose and needs 3 keys :

results.0=no results
results.1=1 result
results.n={0} results
@results.length match {
  case 0 => { @message("results.0") }
  case 1 => { @message("results.1") }
  case _ => { @message("results.n", results.length) }
}

So I've done two helpers (depending on the needed flexibility) based on this convention to minimize template code :

object I18nHelper {
  def plural(count: Int): String = count match {
    case 0 => ".0"
    case 1 => ".1"
    case _ => ".n"
  }
  def messagePlural(key: String, count: Int)(implicit lang: Lang, message: MessagesApi): String = count match {
    case 0 => message(key + ".0")
    case 1 => message(key + ".1")
    case _ => message(key + ".n", count)
  }
}
@import global.helpers.I18nHelper._
@message("results"+plural(results.length), results.length)
@messagePlural("results", results.length)

I find it better as there is a "clear" convention and the code template holds in one line but it's just a workaround. To me, the solution of angular translate is quite nice :

results={$0, plural, =0{no results} one{1 result} other{# results}}
@message("results", results.length)

3 - Type safety

I love Scala and Play partly because of the type safety they provide. But when it comes to i18n, it's just like any JavaScript unsafe code :( How to be sure that all my keys are declared on all languages ? And used with correct parameters (number & type) ?

If I forgot to declare a key, there is no error, the key is simply printed on screen (who want that ?) It's the same when I forget a parameter, no error, the {0} is simply printed out (again, who want that ?) In the same way, if I define a key twice, it is simply overridden silently, which could be hard to troubleshoot...

Moreover, I don't want to write test for all of these errors... So I can ship some of them in my code :(

I saw e2e and play-messagescompiler but I didn't test them yet and I think it should be the default behavior of Play build. It's quite cumbersome to find, learn & install many plugins (more or less mature/maintained)

4 - Rich & named parameters

Having named parameters (just like html input helpers) and having the possibility to pass objects and access some property could be a great improvement for clarity :

page_result=results {1} to {2} on {3}
@message("page_result", page.start, page.end, page.total)

vs

page_result=results {page.start} to {page.end} on {page.total}
@message("page_result", 'page -> page)

5 - Value re-use

Dealing with date formatting is always tough. Personally I define many standards formatting for each language :

date=dd/MM/yyyy
date.l=d/M/yyyy
date.L=dd/MM/yyyy
date.ll=d MMM yyyy
date.LL=d MMMM yyyy
date.lll=EE d MMM yyyy
date.LLL=EEEE d MMMM yyyy
time=HH:mm
time.t=H:mm
time.T=HH:mm
time.tt=H:mm:ss
time.TT=HH:mm:ss
datetime=dd/MM/yyyy HH:mm
datetime.lt=d/M/yyyy H:mm
datetime.LT=dd/MM/yyyy HH:mm
datetime.ltt=d/M/yyyy H:mm:ss
datetime.LTT=dd/MM/yyyy HH:mm:ss

text_with_date=Today we are on {0}
object I18nHelper {
  def date(date: DateTime, suffix: String = "L")(implicit lang: Lang, message: MessagesApi): String = {
    date.toString(message("date." + suffix), lang.toLocale)
  }
}
@message("text_with_date", I18nHelper.date(new DateTime()))

It would be nice if I could re-use some values, ex :

date=dd/MM/yyyy
time=HH:mm
datetime={date} {time}

I don't have a great solution for dates (yet) but I think it could be worth thinking about it.

6 - HTML values

Now, the result of the @message is a string which is escaped but splitting text not to include html tags could be cumbersome (ex: <a>, <b>, <i>, <span>) So, I use the workaround :

pages.index.sample.twitt=Follow <a href="https://twitter.com/{0}" target="_blank">{0}</a> on Twitter
@Html(message("pages.index.sample.twitt", "conferencelist_"))

But I don't know if it's the intended usage...

7 - Multi-file and nested properties

These are more nice-to-have but it would be nice to be able to use nested keys (like in hocon) and split keys in multiple files (like with foldermessages)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment