Packt Publishing is actually discounting the full range of their eBooks and videos by 50 percent until October 17th using this discount code : COL50.

It can be a good opportunity to check “Instant Apache Wicket 6” which I reviewed a few weeks ago for the newcomers to Apache Wicket. Another good deal could be checking out the best-seller title “Mastering Web Application Development with AngularJS”!

Head over to Packt Publishing site and pick the books of your choice using the promo code COL50.

When you're developping Web applications, you often ask yourself what does your beautiful design will look like if your users enter a very long text. Or you may want to prototype a new screen based on an existing one, I came around a quick hack using HTML5 goodness: content editable !

On the page you want to edit, open your JavaScript console (Cmd+Alt+I on Chrome Mac), and enter the following

document.body.contentEditable = true;

Now you can freely edit the text on your page, once you're done, you can switch off the content editable mode setting the property to false !

Maven

At SRMvision, we develop with localization in mind. We don't have any user visible text that is not in fact tied to a java property file. Quickly, the problem that we faced was the difficulty to keep every language file in sync (and to tidy things up). We developed a small Maven plugin allowing us to ensure that our two main problems are now gone : merge-properties-maven-plugin.

Quick example

I think the easiest way to understand how it works is to explain it with a real use case. Let's say we have a module named Zones in our application, it will lead to create four files (if we are localized in two different languages) :

  • l10n/Zones_en.properties
  • l10n/Zones_fr.properties
  • help/Zones_en.properties
  • help/Zones_fr.properties

As you might have guessed, we have got two different categories of target files, one for the application's localization, and the other one for the application's help. There is only one rule when it comes to filling these files, the property keys must begin with the name of the file, otherwise the build would fail. In this example, every key must begin with the prefix "Zones.".

At the end, we want to get two resource bundles, so we set up the build to do so :

By reading this configuration section you can view almost every single option available in the plugin. You can exclude files from automatic key checking : in the example the files Global_*.properties will not be checked. It allows us to group commonly used keys without needing them to begin with the correct prefix (it also eases migration for legacy code, breaking the build would be too intrusive).

You can also notice that we use a Maven property to enable the fail on count mismatch functionality of the plugin, with the help of Maven profiles, we can set it to false for development and to true for continuous integration and translation team. When this configuration is used you will get an output like the following in your Maven build :

If the build should check consistency in merged files and if it does not match, it will output blank keys as well as lonely keys in order for your translator to fix it easily.

Bonus feature

We use Java's MessageFormat to format our translated string, one of the thing we tend to forget is to escape the single quotes in our translations. The plugin does this magic for us, it automatically adds the missing single quotes in every messages.

playlogo

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)(implicit lang: Lang)

With this little trick, your calls to localization will use the locale extracted from the http request as expected.

Sorry english readers, the following post is only available in french !

tl;dr : application Play (java ou scala) sur un serveur Centos (ou Red Hat) derrière un serveur nginx.

Script de démarrage/arrêt du daemon.

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 :

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.

Source :

Configuration de nginx

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.

Compilation des fichiers statiques

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.

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.