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!!!!!!
I will be good to give a brief run down of the steps we are to go through.
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
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
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
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
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()
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'
}
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=
Hey!!! Is there someone here? Hope we are together, don't sleep (yet)!!!
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
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
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.'))
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
That's all folks!!!
Wait a minute.... Who remember about my first line talking about the 3 good news? Ohh you forgot about...
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!!!
Top comments (0)