Repository: digitalfabrik/integreat-cms

Issue:
Add natural language names
In the language creation form, we also need a form for the native name of the language. Also, we need both the names in German and English to show them in the backend languages.
It should be flexible to be extended with new backend languages.
Probably just add hardcoded language name translation fields to the language model.


Discussion:
I have a feature request which maybe fits to this: It would be cool if the API would deliver a property which tells whether the language is RTL/LTR like here:

https://gist.githubusercontent.com/AdamRamberg/ecf2451505416114048c5f89ad6f028f/raw/5e582dbe586396d6e80a02de4586b9e032945f11/locales.js

Resolving patch:
diff --git a/backend/cms/models/language.py b/backend/cms/models/language.py
--- a/backend/cms/models/language.py
+++ b/backend/cms/models/language.py
@@ -28,17 +28,23 @@ class Language(models.Model):
     # The recommended minimum buffer is 35 (see https://tools.ietf.org/html/bcp47#section-4.4.1).
     # It's unlikely that we have language codes longer than 8 characters though.
     code = models.CharField(max_length=8, unique=True, validators=[MinLengthValidator(2)])
-    name = models.CharField(max_length=250, blank=False)
+    native_name = models.CharField(max_length=250, blank=False)
+    english_name = models.CharField(max_length=250, blank=False)
     text_direction = models.CharField(default=DIRECTION[0][0], choices=DIRECTION, max_length=3)
     created_date = models.DateTimeField(default=timezone.now)
     last_updated = models.DateTimeField(auto_now=True)
 
+    # name of the language in the current backend language
+    @property
+    def translated_name(self):
+        return _(self.english_name)
+
     def __str__(self):
         """Function that provides a string representation of this object
 
         Returns: String
         """
-        return self.name
+        return self.english_name
 
     class Meta:
         default_permissions = ()
@@ -70,6 +76,27 @@ class LanguageTreeNode(MPTTModel):
     created_date = models.DateTimeField(default=timezone.now)
     last_updated = models.DateTimeField(auto_now=True)
 
+    @property
+    def code(self):
+        return self.language.code
+
+    @property
+    def native_name(self):
+        return self.language.native_name
+
+    @property
+    def english_name(self):
+        return self.language.english_name
+
+    # name of the language in the current backend language
+    @property
+    def translated_name(self):
+        return self.language.translated_name
+
+    @property
+    def text_direction(self):
+        return self.language.text_direction
+
     @property
     def depth(self):
         """Provide level of inheritance
@@ -92,4 +119,4 @@ def __str__(self):
 
         Returns: String
         """
-        return self.language.name
+        return self.language.english_name
diff --git a/backend/cms/views/languages/language_form.py b/backend/cms/views/languages/language_form.py
--- a/backend/cms/views/languages/language_form.py
+++ b/backend/cms/views/languages/language_form.py
@@ -16,28 +16,9 @@ class LanguageForm(forms.ModelForm):
 
     class Meta:
         model = Language
-        fields = ['code', 'name', 'text_direction', ]
-
-    def __init__(self, *args, **kwargs):
-        super(LanguageForm, self).__init__(*args, **kwargs)
-
-    def save_language(self, language_code=None):
-        """Function to create or update a language
-            language_code ([String], optional): Defaults to None. If it's not set creates
-            a language or update the language with the given code.
-        """
-
-        if language_code:
-            # save language
-            language = Language.objects.get(code=language_code)
-            language.code = self.cleaned_data['code']
-            language.name = self.cleaned_data['name']
-            language.text_direction = self.cleaned_data['text_direction']
-            language.save()
-        else:
-            # create language
-            language = Language.objects.create(
-                code=self.cleaned_data['code'],
-                name=self.cleaned_data['name'],
-                text_direction=self.cleaned_data['text_direction'],
-            )
+        fields = [
+            'code',
+            'english_name',
+            'native_name',
+            'text_direction',
+        ]
diff --git a/backend/cms/views/languages/languages.py b/backend/cms/views/languages/languages.py
--- a/backend/cms/views/languages/languages.py
+++ b/backend/cms/views/languages/languages.py
@@ -41,35 +41,33 @@ class LanguageView(PermissionRequiredMixin, TemplateView):
 
     template_name = 'languages/language.html'
     base_context = {'current_menu_item': 'languages'}
-    language_code = None
 
     def get(self, request, *args, **kwargs):
-        self.language_code = self.kwargs.get('language_code', None)
-        if self.language_code:
-            language = Language.objects.get(code=self.language_code)
-            form = LanguageForm(initial={
-                'name': language.name,
-                'code': language.code,
-                'text_direction': language.text_direction,
-            })
-        else:
-            form = LanguageForm()
+        language_code = self.kwargs.get('language_code', None)
+        language = Language.objects.filter(code=language_code).first()
+        form = LanguageForm(instance=language)
         return render(request, self.template_name, {
-            'form': form, **self.base_context})
+            'form': form, **self.base_context
+        })
 
-    def post(self, request, language_code=None):
-        # TODO: error handling
-        form = LanguageForm(request.POST)
+    def post(self, request, *args, **kwargs):
+        language_code = self.kwargs.get('language_code', None)
+        language = Language.objects.filter(code=language_code).first()
+        form = LanguageForm(
+            request.POST,
+            instance=language
+        )
         if form.is_valid():
+            form.save()
             if language_code:
-                form.save_language(language_code=language_code)
                 messages.success(request, _('Language saved successfully.'))
             else:
-                form.save_language()
                 messages.success(request, _('Language created successfully'))
-            # TODO: improve messages
         else:
+            # TODO: error handling
+            # TODO: improve messages
             messages.error(request, _('An error has occurred.'))
 
         return render(request, self.template_name, {
-            'form': form, **self.base_context})
+            'form': form, **self.base_context
+        })


Test patch:
diff --git a/backend/cms/fixtures/test_data.json b/backend/cms/fixtures/test_data.json
--- a/backend/cms/fixtures/test_data.json
+++ b/backend/cms/fixtures/test_data.json
@@ -48,7 +48,8 @@
     "pk": 1,
     "fields": {
       "code": "de-de",
-      "name": "Deutsch",
+      "english_name": "German",
+      "native_name": "Deutsch",
       "text_direction": "ltr",
       "created_date": "2019-08-12T07:50:18.139Z",
       "last_updated": "2019-08-12T07:50:18.140Z"
@@ -59,7 +60,8 @@
     "pk": 2,
     "fields": {
       "code": "en-gb",
-      "name": "Englisch",
+      "english_name": "English",
+      "native_name": "Deutsch",
       "text_direction": "ltr",
       "created_date": "2019-08-12T07:50:24.635Z",
       "last_updated": "2019-08-12T07:50:24.636Z"
@@ -70,7 +72,8 @@
     "pk": 3,
     "fields": {
       "code": "ar-ma",
-      "name": "Arabisch",
+      "english_name": "Arabic",
+      "native_name": "العربية",
       "text_direction": "rtl",
       "created_date": "2019-08-12T07:51:29.233Z",
       "last_updated": "2019-08-12T07:51:29.233Z"
@@ -81,7 +84,8 @@
     "pk": 4,
     "fields": {
       "code": "fa-ir",
-      "name": "Farsi",
+      "english_name": "Farsi",
+      "native_name": "فارسی",
       "text_direction": "rtl",
       "created_date": "2019-08-12T07:52:21.399Z",
       "last_updated": "2019-08-12T07:52:21.400Z"
diff --git a/backend/cms/tests.py b/backend/cms/tests.py
--- a/backend/cms/tests.py
+++ b/backend/cms/tests.py
@@ -31,7 +31,7 @@ def create_region(region_data):
     def create_language(language_data):
         language_form = LanguageForm(language_data)
         language_form.is_valid()
-        language_form.save_language()
+        language_form.save()
         return Language.objects.get(name=language_data['name'])
 
     @staticmethod