I was having a strange issue with localization in a Play Framework
application. I followed the
simple steps
detailed on the official documentation but with no luck.
When experimenting, I figured out that the locale used is the
default locale of the JVM. In my case, my default locale is French
so I only had French in my application. But on Heroku, the default
locale is English and thus the application was only working in
English.
The trick consists in adding an implicit lang to your template
views. In fact, Scala import an implicit lang with the lowest
priority being the one coming from the JVM, if you want to get the
language parsed from the Accept-Languages http header, you need to
add an implicit as below :
@(title:String)(content:Html)(implicitlang:Lang)
With this little trick, your calls to localization will use the
locale extracted from the http request as expected.
Lancer une application Play en dev est assez aisé :
$ play run.
Maintenant, si vous avez besoin de déployer votre application en
production, il est plus confortable de considérer votre application
comme un service à part entière du système. Il se peut aussi que
vous ayez besoin de spécifier un port et une interface particulière
pour pouvoir utiliser nginx comme front-end (en
reverse proxy). Et évidement, à l'instar d'un environnement de développement,
vous pourriez avoir besoin de compresser le JS et le CSS, et
également de régler finement les en-têtes HTTP pour gérer
correctement le cache.
Tout d'abord le script de lancement du daemon :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Je me suis inspiré des deux gists ci-dessous. Le premier, pour
RedHat, utilise le binaire de play pour lancer le processus
principal. Cette méthode facile à utiliser en développement semble
assez limité en paramètre (tout du moins, très peu documentée). La
seconde méthode, pour Debian,
donne un bonne exemple d'une configuration un peu plus élaborée de
l'exécution du daemon. Les paramètres en début de fichier parlent
d'eux-mêmes, je vous laisse les découvrir et reste à votre
disposition pour toute question.
Sur un serveur web, il est souvent pratique de pouvoir faire tourner
plusieurs applications utilisant des langages, des librairies, des
frameworks, etc... hétérogènes (sur mon serveur, il y a
l'application Play en scala, une application
Nodejs en
Coffescript et une
application PHP/MySQL
utilisant Apache). C'est là
que nginx intervient. Configuré en reverse-proxy, c'est lui qui
écoutera sur le port 80 de votre serveur et en fonction du nom de
domaine relayera les requêtes HTTP à l'application que vous avez
choisis. Il vous suffit de configurer votre application en écoute
sur un port libre en localhost et d'indiquer à nginx qu'en fonction
du nom de domaine (à la manière des VirtualHost d'Apache), il doit
transmettre ses requêtes sur ce port.
Vous noterez une section fournissant un traitement particulier pour
les fichiers statiques (js, css, png, jpg, etc...). En effet, je ne
trouvais pas la configuration par défaut de play très satisfaisante
pour diffuser ces fichiers. Il conviendra donc de copier tous les
fichiers dans un dossier particulier au lancement de l'application
(il faut également pensé à y placer les fichiers "compilé" des
scripts utilisant un pre-processeurs : coffeescript,
SASS/SCSS,
LESS, etc...). Tous les fichiers
dans ce dossier auront une durée de cache maximale afin de minimiser
le nombre de requêtes au serveur (la requête la plus rapide est
celle qui n'est pas faite). Cette technique a aussi l'avantage de
décharger la JVM du traitement de ses fichiers, ils sont directement
retourné par nginx.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Les pré-processeurs (Coffeescript, SASS, LESS, etc...) sont d'un
grand confort pour le développement de la partie front-end d'une
application web. Toutefois, il y a quelques détails qui ne faut pas
négliger afin d'optimiser au maximum la distribution en HTTP de ces
fichiers.
Prenons comme exemple un fichier .coffee (Coffeescript). Lorsqu'en
développement vous lancer votre serveur, play se charge de
re-compiler automatiquement le fichier afin de desservir un fichier
javascript au navigateur qui a demandé le fichier. Dans notre
environnement, les fichiers statiques se trouvent tous dans un
dossier static/. Il faut donc "traduire" ce fichier en
javascript et le placer dans ce dossier (en respectant
l'arborescence utilisée en développement) :
coffee -o static/javascripts/ -c
app/assets/javascripts/*.coffee.
Ensuite, comme optimisation souvent préconnisée, il convient de
"minifier" ces fichiers afin qu'ils soient le plus léger possible
pendant le transport sur le réseau (qui peut-être une faible
connexion 3g). Dans mon cas, j'ai utilisé
yuicompressor
qui fonctionne bien. Il en existe certainement des mieux, je n'ai
pas testé, mais celui-là fonctionne comme je veux.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Note : comme amélioration possible, il faudrait dans cette partie là
renommer les fichiers par un nom de fichier contenant un hash
représentant le contenu de ce fichier afin de palier à tout problème
d'invalidation du cache.
Dans le futur
Pour parfaire le déploiement de l'application, sur un VCS
git par exemple, il serait
pratique d'automatiser le redémarrage du serveur sur un hook
post-commit. Pour éviter également une coupure de service, il
faudrait également, lancer la nouvelle application sur un autre port
et switcher sur la nouvelle instance uniquement avec un reload de
nginx. Mais bon tout ça peut faire l'objet d'un autre article. :)
Mise à jour du 29 juillet 2013 : correction du
script de lancement du daemon.
One issue that came when we first deployed the application with
Compass to Heroku was that the default scala buildpack does not
include sass and compass binaries.
Following
this post
on the Play!Framework mailing list, I forked and patched the
buildpack
to install sass and compass on the environment.
You can find it here and use it with the following command :
At Code-Troopers, we like to
work with the frameworks we love. One of them is
Apache Wicket, and it happens
to some of us doing some
Play! Framework or
Ruby on Rails (either for a
client project, a side project or giving back OSS love).
One thing really great is this two frameworks is the central route
system, one file allows to group all the routes handled by your
application. Wicket does not provide such way of grouping routes,
you can manually mount routes into your application or annotate your
page classes.
Wicket routes mount library
This small library project available on Github
allows to group mounts into a central file. To use it, simply add
its dependency to your pom.xml (artifact is available
on Maven central):
This dependency will transitively gets
wicket-auth-roles (if there is a special need for a
version without this dependency, it could be done easily).
Usage
To use it, simply create a routes.conf file at the root
of the sources in your project (typically
src/main/resources/) respecting the following format :
# mountPoint class roles
/home codetroopers.HomePage
/secured codetroopers.SecuredPage USER
/user/${mode}/#{id} codetroopers.UserPage ADMIN,USER
The files content is the following :
Mount path : using standard Wicket syntax (${requiredParam}
and #{optionalParam} are available)
Page class : fully qualified name of the page class to mount
Roles (optional) : comma separated list of roles required to
access the page
IntelliJ IDEA can do completion for class names in this file (you
just need to hit the ctrl+space shortcut twice)