A django IETF's BCP 47 DB-based translation system
Project description
Tradukoj
Tradujok is a django db-based translation system with IETF's BCP 47 standard support and django-rest-framework serializers.
Tradukoj can be integrated with common js i18n libs thanks to his JSON tree generation feature.
This app is maintained and internally used by Develatio Technologies.
Requierements
-
Python: >= 3.6
-
Django: >= 2.1, 2.2
Features
- Namespaces to separate projects or big sections of your app
- JSON tree generation with your translations
- django-rest-framework urls/views/serializers
- django-rest-framework fields to be used in serializers
- Fallback translation for drf fields
- Translate model fields
- Languaje detection endpoint
- RTL - LTR support
- PO files Import/Export
- Public/Private translations isolation
Quick start
-
Install
pip install django-tradukoj
-
Add "tradukoj" to INSTALLED_APPS:
INSTALLED_APPS = {
...
'tradukoj'
}
-
Include the tradukoj URLconf in urls.py:
url(r'^tradukoj/', include('tradukoj.urls'))
-
Run
python manage.py migrate
to create db records.
Translate model fields
Usage of OneToOneTradukojField
:
from tradukoj.fields import OneToOneTradukojField
class MyModel(models.Model):
name = OneToOneTradukojField(null=True, blank=True, verbose_name='Name')
Handle translations
Automatic key generation:
>>> from tradukoj.models import TranslationKey
>>> from myapp.models import MyModel
>>> instance = MyModel()
>>> # This creates a translatable key with automatically generated name
>>> instance.name = TranslationKey(init_namespace='mynamespace', public=True)
>>> instance.name
<TranslationKey: mynamespace.myapp_mymodel_name_0def4d78080144cdbc96302842935192>
>>> # This will add a translation for es-ES to instance.name
>>> # A record with 'es-ES' into tradukoj.models.BCP47 will be created if it
>>> # does not exist.
>>> instance.name.translate('es-ES', 'mi nombre')
>>> # Access translations:
>>> instance.name.translations.all()
<QuerySet [<Translation: (es-ES - español (Spanish)) mynamespace.myapp_mymodel_name_0def4d78080144cdbc96302842935192 => mi nombre>]>
>>> instance.name.translations.get(bcp47__langtag='es-ES')
<Translation: (es-ES - español (Spanish)) test.medicalscience_specialties_name_0def4d78080144cdbc96302842935192 => mi nombre>
>>> instance.name.translations.get(bcp47__langtag='es-ES').str_translation()
'mi nombre'
Custom key name:
If you dont specify a key for translation, a random one will be generated. To
specify a key, you should pass it as argument to TranslationKey
:
>>> instance.name = TranslationKey(init_namespace='test', text='A translatable string', public=True)
>>> instance.name
<TranslationKey: test.A translatable string>
>>> instance.name.save()
>>> instance.name.translate('es-ES', 'Una cadena traducible')
>>> instance.name.translations.all()
<QuerySet [<Translation: (es-ES - español (Spanish)) test.A translatable string => Una cadena traducible>]>
JSON tree of translations
If you are planning to use json tree feature of tradukoj, remember that a dot in key are handled as subobject.
TranslationKey(init_namespace='project', text='home.title', public=True)
TranslationKey(init_namespace='project', text='home.subtitle', public=True)
results into this json object:
{
es-ES: {
project: {
home: {
title: 'Bienvenido',
subtitle: 'Secciones'
}
}
},
en-US: {
project: {
home: {
title: 'Welcome',
subtitle: 'Sections'
}
}
}
}
API REST Endpoints
- Languaje detection:
YOUR_API_URL/tradukoj/bestlangtag/
Asking fromes-ES;en
(spanish-Spain,english) a web with onlyes-MX
(spanish-Mexico) lang:
[
{
"langtag": "es-MX",
"score":92,
"accept_lang": "es-es"
},
{
"langtag": "es-MX",
"score": 92,
"accept_lang":"es"
},
{
"langtag":"en",
"score":100,
"accept_lang":"en"
}
]
- Available langs:
YOUR_API_URL/tradukoj/available/
{
"count": 28,
"next": null,
"previous": null,
"results": [
{"langtag":"en-EN","name":"English (English)","best_match_score":92,"default":false,"direction":0},
{"langtag":"es-MX","name":"español (Spanish)","best_match_score":92,"default":false,"direction":0},
{"langtag":"en-US","name":"English (English)","best_match_score":98,"default":false,"direction":0},
{"langtag":"ar-LB","name":"العربية (Arabic)","best_match_score":0,"default":false,"direction":1},
{"langtag":"fr-FR","name":"français (French)","best_match_score":0,"default":false,"direction":0},
{"langtag":"pt-PT","name":"português (Portuguese)","best_match_score":0,"default":false,"direction":0},
{"langtag":"ru-RU","name":"русский (Russian)","best_match_score":0,"default":false,"direction":0},
{"langtag":"de-DE","name":"Deutsch (German)","best_match_score":0,"default":false,"direction":0},
{"langtag":"it-IT","name":"italiano (Italian)","best_match_score":0,"default":false,"direction":0},
{"langtag":"hu-HU","name":"magyar (Hungarian)","best_match_score":0,"default":false,"direction":0},
{"langtag":"cs-CZ","name":"čeština (Czech)","best_match_score":0,"default":false,"direction":0},
{"langtag":"zh-CN","name":"中文 (Chinese)","best_match_score":0,"default":false,"direction":0},
{"langtag":"vi-VN","name":"Tiếng Việt (Vietnamese)","best_match_score":0,"default":false,"direction":0},
{"langtag":"hi-IN","name":"हिन्दी (Hindi)","best_match_score":0,"default":false,"direction":0},
{"langtag":"uk_UA","name":"українська (Ukrainian)","best_match_score":0,"default":false,"direction":0},
{"langtag":"hy_AM","name":"հայերեն (Armenian)","best_match_score":0,"default":false,"direction":0},
{"langtag":"be_BY","name":"беларуская (Belarusian)","best_match_score":0,"default":false,"direction":0},
{"langtag":"bg_BG","name":"български (Bulgarian)","best_match_score":0,"default":false,"direction":0},
{"langtag":"km_KH","name":"ខ្មែរ (Khmer)","best_match_score":84,"default":false,"direction":0},
{"langtag":"et_EE","name":"eesti (Estonian)","best_match_score":0,"default":false,"direction":0},
{"langtag":"lv_LV","name":"latviešu (Latvian)","best_match_score":0,"default":false,"direction":0},
{"langtag":"pl_PL","name":"polski (Polish)","best_match_score":0,"default":false,"direction":0},
{"langtag":"ro_RO","name":"română (Romanian)","best_match_score":0,"default":false,"direction":0},
{"langtag":"uz_Latn","name":"o‘zbek (Uzbek)","best_match_score":0,"default":false,"direction":0},
{"langtag":"tr_TR","name":"Türkçe (Turkish)","best_match_score":0,"default":false,"direction":0},
{"langtag":"th_TH","name":"ไทย (Thai)","best_match_score":0,"default":false,"direction":0},
{"langtag":"zh_TW","name":"中文 (Chinese)","best_match_score":0,"default":false,"direction":0},
{"langtag":"az_AZ","name":"azərbaycan (Azerbaijani)","best_match_score":0,"default":false,"direction":0},
]
}
- Get all public translations list:
YOUR_API_URL/tradukoj/public/
- Get all private translations list:
YOUR_API_URL/tradukoj/private/
- Get plain JSON of all public translations:
YOUR_API_URL/tradukoj/public/plain/
- Get plain JSON of all private translations:
YOUR_API_URL/tradukoj/private/plain/
- Get filtered public translations:
YOUR_API_URL/tradukoj/public/plain/?bcp47__langtag=es&key__namespace__text=mynamespace
- Get filtered private translations:
YOUR_API_URL/tradukoj/public/plain/?bcp47__langtag=es&key__namespace__text=mynamespace
Django Rest Framework, Tradukoj Field.
To handle a model translatable field into your drf serializers, TradukojSerializedField
from tradukoj.drf_fields import TradukojSerializedField
class MySerializer(serializers.ModelSerializer):
name = TradukojSerializedField(read_only=True, fallback_langtag='en-US')
class Meta:
model = MyModel
exclude = ('id', )
This will give you a JSON like:
{
name: {
'fallback': 'Welcome',
'text': 'mykey',
'translations': {
'es-ES': 'Bienvenido',
'en-US': 'Welcome'
}
}
}
Command line tools
Generate .po file
usage: manage.py generate_pofile [-h] --langtag LANGTAG --output OUTPUT
--namespace NAMESPACE --reference_langtag
REFERENCE_LANGTAG [--version] [-v {0,1,2,3}]
[--settings SETTINGS]
[--pythonpath PYTHONPATH] [--traceback]
[--no-color] [--force-color]
Generate a .po file of langtag
optional arguments:
-h, --help show this help message and exit
--langtag LANGTAG tag used in BCP47
--output OUTPUT output file
--namespace NAMESPACE
namespace of translations
--reference_langtag REFERENCE_LANGTAG
translated text used in comments to help translator
team
--version show program's version number and exit
-v {0,1,2,3}, --verbosity {0,1,2,3}
Verbosity level; 0=minimal output, 1=normal output,
2=verbose output, 3=very verbose output
--settings SETTINGS The Python path to a settings module, e.g.
"myproject.settings.main". If this isn't provided, the
DJANGO_SETTINGS_MODULE environment variable will be
used.
--pythonpath PYTHONPATH
A directory to add to the Python path, e.g.
"/home/djangoprojects/myproject".
--traceback Raise on CommandError exceptions
--no-color Don't colorize the command output.
--force-color Force colorization of the command output.
Generate a .po file of es-ES
and put en-US
translations as a commentary of
every msgid
:
python manage.py generate_pofile --langtag es-ES --output ./pofile.po --namespace mynamespace --reference_langtag en-US
Destroy keys not in a .po file:
This will destroy those keys not in a .po file and related translations.
usage: manage.py destroy_dbkeys_not_in_pofile [-h] --pofile POFILE --namespace
NAMESPACE [--safe] [--version]
[-v {0,1,2,3}]
[--settings SETTINGS]
[--pythonpath PYTHONPATH]
[--traceback] [--no-color]
[--force-color]
Remove those translations key in DB that does not exists in a given pofile
optional arguments:
-h, --help show this help message and exit
--pofile POFILE The pofile
--namespace NAMESPACE
The namespace
--safe Show those keys that should be deleted but do not
commit delete command on db
--version show program's version number and exit
-v {0,1,2,3}, --verbosity {0,1,2,3}
Verbosity level; 0=minimal output, 1=normal output,
2=verbose output, 3=very verbose output
--settings SETTINGS The Python path to a settings module, e.g.
"myproject.settings.main". If this isn't provided, the
DJANGO_SETTINGS_MODULE environment variable will be
used.
--pythonpath PYTHONPATH
A directory to add to the Python path, e.g.
"/home/djangoprojects/myproject".
--traceback Raise on CommandError exceptions
--no-color Don't colorize the command output.
--force-color Force colorization of the command output.
Show incompatible keys when use JSON tree generation feature
If you are planning to use JSON tree generation, some keys will be incompatible with this scheme:
- namespace.section.title = 'test'
- namespace.section = 'test'
to detect those incompatibility, use show_incompatible_tree_key
command:
usage: manage.py show_incompatible_tree_key [-h] [--pofile POFILE] [--version]
[-v {0,1,2,3}]
[--settings SETTINGS]
[--pythonpath PYTHONPATH]
[--traceback] [--no-color]
[--force-color]
Show incompatible Translation Key for plain tree generation
optional arguments:
-h, --help show this help message and exit
--pofile POFILE Test pofile instead database
--version show program's version number and exit
-v {0,1,2,3}, --verbosity {0,1,2,3}
Verbosity level; 0=minimal output, 1=normal output,
2=verbose output, 3=very verbose output
--settings SETTINGS The Python path to a settings module, e.g.
"myproject.settings.main". If this isn't provided, the
DJANGO_SETTINGS_MODULE environment variable will be
used.
--pythonpath PYTHONPATH
A directory to add to the Python path, e.g.
"/home/djangoprojects/myproject".
--traceback Raise on CommandError exceptions
--no-color Don't colorize the command output.
--force-color Force colorization of the command output.
Load .po files
Importing tradukoj.admin
models into your admin, will give you some features
like importing .po files.
from tradukoj import models
class TranslationKeyAdmin(admin.ModelAdmin):
search_fields = ('text',)
class TranslationAdmin(admin.ModelAdmin):
search_fields = ('key__text',)
admin.site.register(models.TranslationKey, TranslationKeyAdmin)
admin.site.register(models.GetTextFile)
admin.site.register(models.Namespace)
admin.site.register(models.Translation, TranslationAdmin)
admin.site.register(models.BCP47)
Vue.js: Translate fields POC
Assuming that you are storing your current languaje tag in store.state.i18n.active_langtag
,
use this POC vuejs code:
create a plugins/tradukoj-translate.js
with this content:
import store from "../store";
const TradukojTranslatable = {
install(Vue) {
Vue.mixin({
methods: {
$tradukojTranslate(translatable) {
if (!translatable) {
return "";
}
if (
translatable.translations &&
translatable.translations[store.state.i18n.active_langtag]
) {
return translatable.translations[
store.state.i18n.active_langtag
];
}
if (translatable.fallback) {
return translatable.fallback;
}
return "";
}
}
});
}
};
export default TradukojTranslatable;
Register globally:
import TradukojTranslatable from "@/plugins/tradukoj-translatable";
Vue.use(TradukojTranslatable);
Use in component:
<template>
<div>
<p>{{ $tradukojTranslate(mymodel.name) }}</p>
</div>
</template>
[...]
Once you change the value of store.state.i18n.active_langtag
, the translations will be
automatically updated to current selected lang.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file django-tradukoj-1.2.4.tar.gz
.
File metadata
- Download URL: django-tradukoj-1.2.4.tar.gz
- Upload date:
- Size: 17.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.12.1 pkginfo/1.4.2 requests/2.23.0 setuptools/46.0.0 requests-toolbelt/0.9.1 tqdm/4.28.1 CPython/3.7.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 7338a3b1a7b01e6e67590beaaa0b294e2f3714da698bad68d3f7f27187f5fd32 |
|
MD5 | 2efb8dae040e99ad6b184ae42f5a19dc |
|
BLAKE2b-256 | 3636c40dd08ecfe249bd437fad379347a6060a0a78b6e78924d9760a96da0067 |
File details
Details for the file django_tradukoj-1.2.4-py2-none-any.whl
.
File metadata
- Download URL: django_tradukoj-1.2.4-py2-none-any.whl
- Upload date:
- Size: 27.7 kB
- Tags: Python 2
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.12.1 pkginfo/1.4.2 requests/2.23.0 setuptools/46.0.0 requests-toolbelt/0.9.1 tqdm/4.28.1 CPython/3.7.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 34886ea75e209822e6ab96186ceb0634c72e10a8063c07395e304c8818fb8aff |
|
MD5 | 526a1d57cb77a82bde458423bb69a98b |
|
BLAKE2b-256 | 3e8da2100ca7f8f85fb4ff51430def9195ca799d8790611af515992876f66eff |