Dans cette série d’articles, nous tentons de trouver une solution élégante au problème de l’internationalisation des images dans les feuilles de style.
Dans la partie précédente, je montrais qu’en utilisant SASS, il était possible d’internationaliser proprement les feuilles de style. Néanmoins, il est parfois possible de faire encore mieux.
Dans notre cas, toutes les valeurs que nous mettons dans les fichiers localisées (chemin vers l’image et largeur de l’image) seraient en théorie calculables automatiquement en fonction de la langue. Pour éviter de les écrire à la main, il est possible de générer automatiquement ces fichiers (avec n’importe quel langage de script) ou bien de profiter de la possibilité offerte par SASS de définir ses propres fonctions en Ruby.
Par exemple, pour définir une fonction qui calcule l’URL relative d’une image :
module Sass::Script::Functions
# Return the url of the given image (given as a filename) for the given language
def image_url(sass_lang, sass_filename)
assert_type sass_filename, :String
assert_type sass_lang, :String
filename = sass_filename.value
lang = sass_lang.value
url = '/images/locales/' + lang + '/' + filename
return Sass::Script::String.new(url)
end
end
La fonction commence par vérifier le type des arguments qui lui sont passés puis les « transforme » en type système Ruby. Ensuite l’URL est calculée puis renvoyée sous forme de chaîne de caractère SASS.
De la même manière, vous pouvez écrire une fonction qui va automatiquement calculer la taille de l’image, par exemple grâce au gem image_size (simple à manipuler mais qui ne fonctionne pas sous Windows) ou à ImageMagick.
Avec ImageMagick, voici la fonction de calcul de la taille de l’image (modifiable facilement pour pouvoir également retrouver la hauteur) :
module Sass::Script::Functions
# Return the width in pixels of the given image (given as a filename) for the given language
def image_width_px(sass_lang, sass_filename)
assert_type sass_filename, :String
assert_type sass_lang, :String
filename = sass_filename.value
lang = sass_lang.value
path = 'public/images/locales/' + lang + '/' + filename
size_array = (`identify -format %wx%h #{path}`).chomp.split("x")
size = {:width => size_array[0].to_i, :height => size_array[1].to_i}
width = size[:width]
return Sass::Script::Number.new(width, 'px')
end
end
Le calcul dynamique des tailles des images ne pose pas de réel problème de performance car les fichiers CSS ne sont générés que lorsqu’il y en a besoin (configuration SASS réglable). Néanmoins, si vous avez peur que ça prenne trop de temps, notamment en mode développement dans lequel on force souvent le SASS à générer le CSS plus souvent, ou si vous souhaitez éviter le risque de calculer deux fois la même chose (si une même image est utilisée plusieurs fois), il est toujours possible, à chaque calcul, de stocker le résultat dans une variable de classe pour servir de cache.
Lorsque vous avez écrit un module de ce type, n’oubliez pas de faire en sorte de charger ce fichier au démarrage de Ruby ou de votre application pour qu’il soit pris en compte par SASS. Pour une application Ruby on Rails, cela revient à ajouter la ligne suivante dans « config/environnement.rb » :
config/environnement.rb
(...)
require "#{RAILS_ROOT}/lib/sass_extension.rb"
(Dans l’hypothèse où vous avez appelé le fichier « sass_extension.rb » et que vous l’avez placé dans le repertoire « lib » de votre application.)
Voyons à présent ce que deviennent nos fichiers de styles. En premier lieu le fichier « fr.sass » est réduit à sa plus simple expression :
fr.sass
$lang: fr
@import _styles.sass
Quant au fichier « _styles.sass », il reste relativement lisible :
_style.sass
form#setup button.validate
background: transparent url(image_url($lang, “validate_button.png”)) no-repeat
height: 25px
width: image_width_px($lang, " validate_button.png ")
Sans compter qu’avec les possibilités du SASS, vous pourrez factoriser la plus grande partie des lignes ci-dessus. La formation du bouton peut se réduire aux lignes suivantes :
_style.sass
form#setup button .validate
+button(“validate_button.png”)
(...)
À partir du moment où vous avez défini le mixin qui suit :
_style.sass
(...)
@mixin button($filename)
background: transparent url(image_url($lang, $filename)) no-repeat
height: 25px
width: image_width_px($lang, $filename)
Cela permet de ne s’occuper d’internationalisation que dans quelques endroits bien identifiés de votre feuille de style.
Avec le système décrit, l’ajout d’une langue est simple, l’ajout d’une image est simple, la modification d’un sélecteur aussi. Que demander de plus ?
Français
English 