In a previous post about django translations in this blog, I shared how to achieve a quick system that allowed me to manage translations stored in models and served using a template tag. In this post I will explain how to serve images that contain translated text and, hence, a localized image exists for each language.

In my case, images are referenced from <img> HTML tags in templates and from CSS files.

First of all we must create a basic structure in our img/ and css/ media folders, creating inside a directory for each language code we will use. For example, if we have two languages -- english and spanish -- we would create img/en/, img/es/, css/en/ and css/es/.

In the CSS folders, the same files must be initially copied. If we have, for instance, just one style.css file, it must be both in css/en/style.css and css/es/style.css:

css/
    en/
        style.css
    es/
        style.css

For the images, we should create the images that will be translated into each language code folder. All CSS files will reference the non-translated images in the same way, but their own file path to the translated image. I'll give an example. Let's say we have one background image without text to be translated (bg_color_red.png), and one logo with a claim text to be translated (logo.png). The final structure would end like this:

img/
    bg_color_red.png
    en/
        logo.png
    es/
        logo.png

We need to edit each CSS file and fix the image path references to match the localized ones. For the spanish CSS, for instance, if we have a declaration like this in the spanish CSS:

background: url(/media/img/logo.png) top left repeat-x;

we have to insert the correct path to the translated image:

background: url(/media/img/es/logo.png) top left repeat-x;

We still have to provide a way to properly request those CSS files, as well as the images that are linked dircetly from the templates. To do so, we will use a template tag that will receive a path and a language code and will return the path to the proper file. In your app, create the .py file inside the templatetags folder (don't forget to include an __init__.py to make it a python module) and paste this contents. For example, I am going to call it img_lazy_tags.py:

import os
from django import template

register = template.Library()


class LocalizedFilePath(template.Node):
    def __init__(self, filepath, language_code):
        self.filepath = filepath
        self.lang = language_code

    def render(self, context):
        filepath = template.resolve_variable(self.filepath, context)
        lang = template.resolve_variable(self.lang, context)
        static_url = template.resolve_variable('STATIC_URL', context)
        return os.path.join(static_url, os.path.dirname(filepath),
                lang, os.path.basename(filepath))


@register.tag(name='get_localized_filepath')
def get_localized_filepath(parser, token):
    bits = list(token.split_contents())
    if len(bits) != 3:
        raise template.TemplateSyntaxError(
                "'get_localized_filepath' tag takes exactly 2 arguments")
    return LocalizedFilePath(filepath=bits[1], language_code=bits[2])

In order to use the template tag, you first have to load it:

{% load img_lazy_tags %}

Then call the tag passing it the filepath and the language code you want to get the object fields translated to. To request, for example, the CSS for spanish:

{% get_localized_filepath 'css/style.css' 'es' %}

Observe that we are initially providing a filepath to a non existant CSS. The template tag will insert the STATIC_URL prefix and /es/ part and will return something like:

/media/css/es/style.css

It is convenient to use this tag altogether with the django.core.context_processors.request context processor in your settings, so we can automatically call the tag with the current language code for the session:

{% get_localized_filepath 'css/style.css' LANGUAGE_CODE %}

Remember, you must use this template tag for all your CSS and image references in all your templates.

Happy coding!