Search code examples
pythonjsonpython-3.xdjangogettext

How could I translate static data coming from JSon files in Django?


I have a json file with a long list of geographic locations

[
    {
        "id": 1,
        "name": "Afghanistan",
        "iso3": "AFG",
        "iso2": "AF",
        "phone_code": "93",
        "capital": "Kabul",
        "currency": "AFN",
        "currency_symbol": "؋",
        "tld": ".af",
        "native": "افغانستان",
        "region": "Asia",
        "subregion": "Southern Asia",
        "timezones": [
            {
                "zoneName": "Asia\/Kabul",
                "gmtOffset": 16200,
                "gmtOffsetName": "UTC+04:30",
                "abbreviation": "AFT",
                "tzName": "Afghanistan Time"
            }
        ],

        "latitude": "33.00000000",
        "longitude": "65.00000000",
        "emoji": "🇦🇫",
        "emojiU": "U+1F1E6 U+1F1EB",
        "states": [
            {
                "id": 3901,
                "name": "Badakhshan",
                "state_code": "BDS",
                "cities": [
                    {
                        "id": 52,
                        "name": "Ashkāsham",
                        "latitude": "36.68333000",
                        "longitude": "71.53333000"
                    },
        .......
        /* very long list */

This file is loaded in Django forms when country/state/city dropdown lists are needed.

The problem is that I want to translate at least the country names to other languages.

Even if I was allowed to use {% trans "Country_name" %} in my JSon file it wouldn't be very practical. Is there a faster way to do so? For example making this in forms.py doesn't work:

from django.utils.translation import gettext_lazy as _
# ...

def get_country():
    filepath = 'myproj/static/data/countries_states_cities.json'
    all_data = readJson(filepath)

    all_countries = [('----', _("--- Select a Country ---"))]

    for x in all_data:
        y = (x['name'], _(x['name']))
        all_countries.append(y)

    return all_countries

"--- Select a Country ---" will be translated but x['name'] will not, because it seems that

django-admin makemessages -l fr

doesn't execute loops and doesn't not lookup into arrays.

In short I have the same problem that I would have if I had to translate data coming from a database.

For the database django_modeltranslation would be a solution. But how could I translate data coming from json files without have to manually edit the json file, wihch is extremely tedious and error prone?


Solution

  • You can customize the makemessages command to preprocess .json files.

    # mysite/myapp/management/commands/makemessages.py
    
    import os
    import subprocess
    
    from django.core.management.commands import makemessages
    
    
    def templatize(path):
        return subprocess.check_output(["sed", "-E", f's/"name": "(.*)"/"name": _("\\1")/g', path]).decode()
    
    
    class BuildFile(makemessages.BuildFile):
    
        def preprocess(self):
            if not self.is_templatized:
                return
    
            file_ext = os.path.splitext(self.translatable.file)[1]
            if file_ext == '.json':
                content = templatize(self.path)
                with open(self.work_path, 'w', encoding='utf-8') as fp:
                    fp.write(content)
                return
    
            super().preprocess()
    
    
    class Command(makemessages.Command):
        build_file_class = BuildFile
    

    Usage:

    python manage.py makemessages -l fr -e html,txt,py,json