0

Django is real fucking awesome, this morning i want to share a basic tutorial how to implement the django internationalization with GeoIP. Of course this tutorial if you need to make a site with multiple languages.

Default django already integrated with common / modern translation system. as the docs warning says:

Translation and formatting are controlled by USE_I18N and USE_L10N settings respectively. However, both features involve internationalization and localization. The names of the settings are an unfortunate result of Django’s history.

Yeah, controlled by internationalization and localization.

To make a message file is a plain-text file, representing a single language, that contains all available translation strings and how they should be represented in the given language. Message files have a .po file extension. This is the method applied by the translator sites such as transifex or similiar.


Okay, let’s do it now how to make it;

1. in your settings.py, in this example below i implement the Indonesian as default language.

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',

    # adding local middleware
    'django.middleware.locale.LocaleMiddleware',
]

from django.utils.translation import ugettext_lazy as _

LANGUAGE_CODE = 'id'
LANGUAGES = (
    ('id', _('Indonesia')),
    ('en', _('English'))
)
DEFAULT_LANGUAGE = 1
LOCALE_PATHS = (
    os.path.join(BASE_DIR, 'youproject/locale'),
)
TIME_ZONE = 'Asia/Jakarta'
USE_I18N = True
USE_L10N = True
USE_TZ = True

2. Implement the standard translation for the python file. “Judul” mean is “Title”.

from django.db import models
from django.utils.translation import ugettext_lazy as _

class Post(models.Model):
    judul = models.CharField(
        _("Judul"), max_length=200
    )
    ....

2. a. Or, if you need to implement in the templates. read this for more.

{% trans "Judul" %} {# -> mean is 'Title' #}

3. Generate all messages by selecting the language with ./manage.py or django-admin commands. read this for more.
This command should be generate the .po file

./manage.py makemessages -l en

And compile it with command:

./manage.py compilemessages # optional => -l en

4. Prepare the database GeoIP.dat before implement the GeoIP to switch the current languange with language country code by detecting IP address from client.

  1. Download it: http://dev.maxmind.com/geoip/legacy/geolite/
  2. Extract and save the GeoIP.dat to the directory such as below for sample.
yourapp/
??? __init__.py
??? models.py
??? views.py
yourproject/
??? geoipdb
?   ??? GeoIP.dat
?   ??? __init__.py
??? locale
?   ??? en
?       ??? LC_MESSAGES
?           ??? django.po
??? settings.py
??? middleware.py
??? urls.py  
??? __init__.py

5. Installing a Pure Python API for Maxmind’s binary GeoIP databases with pygeoip

$ pip install pygeoip

Makesure the geoip is work fine. To check it, you can go to your shell such as bellow.

$ ./manage.py shell
>>> import pygeoip
>>> from django.conf import settings
>>>
>>> geoipdb = os.path.join(
        settings.BASE_DIR, 
        'yourproject/geoipdb/GeoIP.dat'
    )
>>> gi = pygeoip.GeoIP(geoipdb)  
>>> gi.country_code_by_name('google.com')
'US'
>>> gi.country_code_by_addr('64.233.161.99')
'US'
>>> gi.country_name_by_addr('64.233.161.99')
'United States'

6. Then, setup the urls.py javascript catalog and javascript internalionalization.

from django.conf import settings
from django.contrib import admin
from django.conf.urls import include, url
from django.conf.urls.static import static
from django.views.i18n import JavaScriptCatalog

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^jsi18n/$', JavaScriptCatalog.as_view(), name='javascript-catalog'),
    url(r'^i18n/', include('django.conf.urls.i18n')),
    .....
    .....
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

7. Create the Language Middleware to check the client IP address to set as default language.

impor os
import pygeoip
from django.conf import settings
from django.utils import translation
from django.utils.deprecation import MiddlewareMixin

class LanguageMiddleware(MiddlewareMixin):
    """
    Setup Internationalization with middleware
    """

    def get_client_ip(self, request):
        """
        Get Client IP.
        Refference: http://stackoverflow.com/a/4581997/6396981
        """
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip

    def process_request(self, request):
        geoipdb = os.path.join(
            settings.BASE_DIR, 
            'yourproject/geoipdb/GeoIP.dat'
        )
        gi = pygeoip.GeoIP(geoipdb)
        client_ip = self.get_client_ip(request)
        client_country_code = gi.country_code_by_name(client_ip).lower()

        # this condition if user switch it with `set_language`
        if 'lang' in request.GET:
            translation.activate(request.GET.get('lang'))
        elif client_country_code != 'id' and client_country_code != '':
            translation.activate('en')

8. Update your settings middleware inside file of settings.py

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    ....
    ....
    'django.middleware.locale.LocaleMiddleware',
    'yourproject.middleware.LanguageMiddleware',
]

The middleware above to set automatically by detecting the client IP address. And this is optionally form if the client need to be switch it to another languange.

{% load i18n %}
<form action="{% url 'set_language' %}" method="post">
  {% csrf_token %}
  <div class="form-group">
    <select name="language" onchange="javascript:form.submit()">
      <option value="en" {% if request.LANGUAGE_CODE == 'en' %}selected="selected"{% endif %}>English</option>
      <option value="id" {% if request.LANGUAGE_CODE == 'id' %}selected="selected"{% endif %}>Indonesia</option>
    </select>
  </div>
</form>

Finally, you already can build the site with multiple languages. ^_^ and order your :coffe: again

python django multi languages internationalization

Your Answer

blog comments powered by Disqus