Logo

dev-resources.site

for different kinds of informations.

Leveraging Headers for Dynamic Localization in Django

Published at
9/25/2024
Categories
django
aws
drf
pycon
Author
yokwejuste
Categories
4 categories in total
django
open
aws
open
drf
open
pycon
open
Author
10 person written this
yokwejuste
open
Leveraging Headers for Dynamic Localization in Django

Ahhhh it's been long I passed here! I was cooking some else as usual. Please calm down, by the end of this talk I will have three good news for you!

Let's speak about cultural diversity, localization, internalization and translations. In a few steps let's discuss about how (it is done) and how (best way to do it). On your marks... get set... ready.... GOOOOOOOOOOOO!!!!!!

Yes to API translations

I will be good to give a brief run down of the steps we are to go through.

Workshop RoadMap

Project Setup

mkdir TransTab

cd TransTab

python -m venv venv

source venv/bin/activate

pip install django boto3 djangorestframework polib python-dotenv pip-chill

pip-chill > requirements.txt --no-chill

django-admin startproject transtab .

python manage.py startapp translator

mkdir utils/

touch translator/serializer.py translator/urls.py utils.py middleware.py renderer.py .env
Enter fullscreen mode Exit fullscreen mode

At this point in time, we should have a folder structure and output as this when running python manage.py runserver:

    .
    ├── manage.py
+   ├── middleware.py
+   ├── requirements.txt
    ├── translator
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── migrations
    │   │   └── __init__.py
    │   ├── models.py
+   │   ├── serializer.py
    │   ├── tests.py
+   │   ├── urls.py
    │   └── views.py
    ├── transtab
    │   ├── __init__.py
    │   ├── asgi.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    └── utils
+       ├── renderer.py
+       └── translate.py

    4 directories, 20 files
Enter fullscreen mode Exit fullscreen mode

Django Application Running

Creating Translation Middleware

Inside the middleware.py file, add the following content:

from django.utils import translation
from django.conf import settings

class TRSLocaleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        language = request.headers.get('Accept-Language', settings.LANGUAGE_CODE)
        translation.activate(language)
        request.LANGUAGE_CODE = translation.get_language()
        response = self.get_response(request)
        translation.deactivate()
        return response
Enter fullscreen mode Exit fullscreen mode

JSON Response Render

Inspired by a Postman Blog post, Let's customize the renderer.py file with the content below.

# utils/renderer.py
from rest_framework.renderers import JSONRenderer
from rest_framework.views import exception_handler
from django.utils import timezone
import uuid

class NewJSONRenderer(JSONRenderer):
    def render(self, data, accepted_media_type=None, renderer_context=None):
        status_code = renderer_context['response'].status_code

        if 200 <= status_code < 300:
            response = {
                "status": "success",
                "statusCode": status_code,
                "data": data
            }
        else:
            response = {
                "status": "error",
                "statusCode": status_code,
                "error": {
                    "code": data.get('code', 'UNKNOWN_ERROR'),
                    "message": data.get('detail', str(data)),
                    "details": data.get('details', None),
                    "timestamp": timezone.now().isoformat(),
                    "path": renderer_context['request'].path,
                    "suggestion": data.get('suggestion', None)
                }
            }

        response["requestId"] = str(uuid.uuid4())
        response["documentation_url"] = "https://api.example.com/docs/errors"

        return super().render(response, accepted_media_type, renderer_context)

def trans_exception_handler(exc, context):
    response = exception_handler(exc, context)

    if response is not None:
        response.data['status'] = 'error'
        response.data['statusCode'] = response.status_code

    return response
Enter fullscreen mode Exit fullscreen mode

AWS Translate Function

Enter the utils/translate.py file and change the content to:

import os
import boto3
import polib
from django.conf import settings

def translate_text(text, source_language, target_language):
    translate = boto3.client(
        "translate",
        region_name=settings.AWS_REGION,
        aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
        aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY
    )

    result = translate.translate_text(
        Text=text,
        SourceLanguageCode=source_language,
        TargetLanguageCode=target_language
    )
    return result.get("TranslatedText")


def translate_po_files():
    dirs = [
        d for d in os.listdir("locale") if os.path.isdir(os.path.join("locale", d))
    ]
    for dir in dirs:
        po = polib.pofile(f"locale/{dir}/LC_MESSAGES/django.po")
        target_language = po.metadata['Language']
        for entry in po:
            if not entry.translated():
                translated_text = translate_text(entry.msgid, 'auto', target_language)
                entry.msgstr = translated_text
        po.save()

Enter fullscreen mode Exit fullscreen mode

Settings configuration

Let's do a few changes here and there in the settings.py and .env

# settings.py
import os
from dotenv import load_dotenv

load_dotenv()

SECRET_KEY = os.getenv('SECRET_KEY')
DEBUG = True if os.getenv('DEBUG') == 'True' else False

#...

AWS_REGION = os.getenv('AWS_REGION')
AWS_ACCESS_KEY_ID = os.getenv('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.getenv('AWS_SECRET_ACCESS_KEY ')

MIDDLEWARE = [
    # ...
    'middleware.TRSLocaleMiddleware',
    # ...
]

INSTALLED_APPS = [
     # ...
     'translator',
]

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'utils.renderer.NewJSONRenderer',
    ),
    'EXCEPTION_HANDLER': 'utils.renderer.trans_exception_handler'
}
Enter fullscreen mode Exit fullscreen mode

Then we add our environment variables:

DEBUG=True
SECRET_KEY='This should look like a secret key'
AWS_REGION=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
Enter fullscreen mode Exit fullscreen mode

Hey!!! Is there someone here? Hope we are together, don't sleep (yet)!!!

Thinking about automation

Automating the translation with a command

Now let's automate the translation by creating a custom manage.py command in django.

Creating the command file

mkdir -p translator/management/command

touch translator/management/commands/translate_po.py
Enter fullscreen mode Exit fullscreen mode

After this command running, we have this structure:

    .
    ├── db.sqlite3
    ├── manage.py
    ├── middleware.py
    ├── requirements.txt
    ├── translator
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── apps.py
+   │   ├── management
+   │   │   └── commands
+   │   │       └── translate_po.py
    │   ├── migrations
    │   │   └── __init__.py
    │   ├── models.py
    │   ├── serializer.py
    │   ├── tests.py
    │   ├── urls.py
    │   └── views.py
    ├── transtab
    │   ├── __init__.py
    │   ├── asgi.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    └── utils
        ├── renderer.py
        └── translate.py

    6 directories, 21 files
Enter fullscreen mode Exit fullscreen mode

Let's drop the command logic now in the code base

from django.core.management.base import BaseCommand
from utils.translate import translate_po_files

class Command(BaseCommand):
    help = 'Translates all .po files using AWS Translate'

    def handle(self, *args, **options):
        translate_po_files()languages.
        self.stdout.write(self.style.SUCCESS('Successfully translated .po files.'))
Enter fullscreen mode Exit fullscreen mode

Hello 👋, are you here? If you are missing anything refer to this repo

Some commands to run:

# make messages for a language
django-admin makemessages -l <lang_code> --ignore=venv/*

# compiling messages, converting from `.po` to `.mo`
django-admin compilemessages --ignore=venv/*

# our new command we made
python manage.py translate_po
Enter fullscreen mode Exit fullscreen mode

That's all folks!!!

Wait a minute.... Who remember about my first line talking about the 3 good news? Ohh you forgot about...
thinking meme pawpaw
So, a few days ago, I decided to be more social media focused and each content I make it directed towards learning with fun. I have a todo for you:

Ciao ciao!!!

drf Article's
30 articles in total
Favicon
Djoser+SimpleJWT
Favicon
AssertionError: 403
Favicon
extra_kwargs arguments
Favicon
To Django or to DjangoREST?
Favicon
Django API | queryset & object, filter() & get()
Favicon
I just tried to compare values between model and serializer
Favicon
Customize Schema with @extend_schema_view
Favicon
Seperate serializers
Favicon
Leveraging Headers for Dynamic Localization in Django
Favicon
Django REST Framework warning: `UnorderedObjectListWarning`
Favicon
DRF create @property decorator in view and use property in serializer
Favicon
why Serializers used for? easy to understand
Favicon
Async API Calls Unleashed: Exploring Django 4 and Django Rest Framework
Favicon
# Comprehensive Security for Class-Based Views in Django Rest Framework
Favicon
HATEOAS Principle - Generating Full Paths for Objects in Django Rest Framework.
Favicon
Instance version control in DRF with Django Reversion
Favicon
Django News #171 - DjangoCon US 2023 Preview
Favicon
How to create thumbnails programmatically in Django
Favicon
Automatically Add Logged In User Under 'created_by' and 'updated_by' to Model in Django Rest Framework
Favicon
how to fix raise ImproperlyConfigured("settings.DATABASES is improperly configured. "
Favicon
CSRF verification failed. Request aborted. in django rest framework
Favicon
CSRF verification failed. Request aborted. in django rest framework
Favicon
How to fix "Must supply api_key"
Favicon
Updating A Many-To-Many Relationship In Django
Favicon
Excluding Fields in Django Rest Framework Serializers
Favicon
JWT Authentication with Django REST Framework - What? Why? How?
Favicon
How to implement Auto Expiring Token in Django Rest Framework
Favicon
Building web applications with Django, Django REST Framework and Nuxt
Favicon
How to use Postman to authenticate to Django Rest Framework
Favicon
Setting Up Django Rest Framework

Featured ones: