I'm working on my personal website and wanted to handle both frontend and database translations (ie having everything in 2-3 languages). While there are already quite a few third-party apps for handling translation in the database, I thought it'd be both fun and interesting to build my own.
I'm at the last step. So far, everything's been working fine. Here's a quick recap on how it works (skipping over a few things):
Ok so let's say we have a "Job" model that has 2 fields that must be translated: title and description . Now whenever I create a new entry in Job, here is what happens automatically:
My issue is as follows:
What I want to do is:
My idea would be to "override the general change_form.html by adding a new zone dedicated to translation, which gets all the Translation entry related to an instance" (only if this instance is subject to translation). But not sure how to do that.
(Note that I already automatically detect all the models that require translations, and can easily get their specific fields)
Any help would be appreciated :)
For anyone that stumbles upon this topic, I've managed to solve this issue and publish my own application for database translation. The code is fully open-source and available here: https://pypi.org/project/django-database-translation/
As for the problem mentioned in my original post, I managed to apply the following logic:
Here are the snippets, also available on https://github.com/Jordan-Kowal/django_database_translation
class DynamicTranslationForm(forms.ModelForm):
"""
Form to use in a ModelAdmin for any model that has fields to translate.
It will allow you to display and edit the Translation instances linked to the object.
Since fields are dynamically generated, you must override the get_fieldsets method in the admin (or else they won't show)
The "TranslatedAdmin" ModelAdmin natively use this form.
"""
# ----------------------------------------
# Core Methods
# ----------------------------------------
def __init__(self, *args, **kwargs):
"""Overridden method to dynamically add a new field for each Translation linked with our object"""
super(DynamicTranslationForm, self).__init__(*args, **kwargs)
if self.instance.pk:
self.set_translation_info()
for translation in self.translations:
self.fields[translation["fieldname"]] = translation["field"]
self.initial[translation["fieldname"]] = translation["instance"].text
def save(self, commit=True):
"""Overridden method to save the updated Translation texts"""
if self.instance.pk:
for translation in self.translations:
obj = translation["instance"]
fieldname = translation["fieldname"]
value = self.cleaned_data[fieldname]
obj.text = value
obj.save()
return super(DynamicTranslationForm, self).save(commit=commit)
# ----------------------------------------
# Custom Methods
# ----------------------------------------
def set_translation_info(self):
"""
Finds all the Translation instances linked to our object, and stores their info in an attribute
The attribute is a list of dict, each dict containing the information of one translation
"""
obj = self.instance
information = []
translations = obj.get_translations()
for translation in translations:
fieldname = create_translation_fieldname(translation)
information.append({
"instance": translation,
"fieldname": fieldname,
"field": forms.CharField(required=False, widget=forms.Textarea)
})
self.translations = information
# ADMIN.PY
class TranslatedAdmin(admin.ModelAdmin):
"""
ModelAdmin to use as parent for any model that has fields to translate
It comes with the "DynamicTranslationForm" and custom methods to display its fields
"""
# ----------------------------------------
# Config
# ----------------------------------------
form = DynamicTranslationForm
# ----------------------------------------
# Detail View
# ----------------------------------------
fieldsets = []
# ----------------------------------------
# Custom Methods
# ----------------------------------------
def get_form(self, request, obj=None, **kwargs):
"""Required for get_fieldsets"""
kwargs['fields'] = flatten_fieldsets(self.fieldsets)
return super().get_form(request, obj, **kwargs)
def get_fieldsets(self, request, obj=None):
"""
Allows us to display the field dynamically created by "DynamicTranslationForm"
The fieldnames in "DynamicTranslationForm" and this function must be identical
In other words:
- "DynamicTranslationForm" creates the fields
- This function adds fields with the same name to the fieldsets
- As a result, the fields now appear on the form
"""
fieldsets = self.fieldsets.copy()
# Get current Item
url = request.build_absolute_uri("?")
if url.endswith("/change/"):
url = url[:-8]
object_id = url.split("/")[-1]
obj = self.model.objects.get(pk=object_id)
# Create a field for each translation associated with our object
fields = []
translations = obj.get_translations()
for translation in translations:
fieldname = create_translation_fieldname(translation)
fields.append(fieldname)
# Add a fieldset with our fields
fieldsets.append(['TRANSLATIONS', {'fields': fields}])
return fieldsets
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.