def __init__(self, *args, **kwargs): super(TranslationAdmin, self).__init__(*args, **kwargs) trans_opts = translator.get_options_for_model(self.model) # Replace original field with translation field for each language if self.fields: fields_new = list(self.fields) for field in self.fields: if field in trans_opts.fields: index = fields_new.index(field) translation_fields = get_translation_fields(field) fields_new[index : index + 1] = translation_fields self.fields = fields_new if self.fieldsets: fieldsets_new = list(self.fieldsets) for (name, dct) in self.fieldsets: if "fields" in dct: tfields_new = [] for field in list(dct["fields"]): if isinstance(field, tuple): tfields = [] for f in field: if f in trans_opts.fields: tfields.extend(get_translation_fields(f)) else: tfields.extend((f,)) # FIXME: Flatten nested tuples as they will break in the # current tabs implementation. Normally we want: # tfields_new.append(tuple(tfields)) tfields_new.append(tuple(tfields)) else: if field in trans_opts.fields: tfields_new.extend(get_translation_fields(field)) else: tfields_new.extend((field,)) dct["fields"] = tuple(tfields_new) self.fieldsets = fieldsets_new if self.list_editable: editable_new = list(self.list_editable) display_new = list(self.list_display) for field in self.list_editable: if field in trans_opts.fields: index = editable_new.index(field) display_index = display_new.index(field) translation_fields = get_translation_fields(field) editable_new[index : index + 1] = translation_fields display_new[display_index : display_index + 1] = translation_fields self.list_editable = editable_new self.list_display = display_new if self.prepopulated_fields: prepopulated_fields_new = dict(self.prepopulated_fields) for (k, v) in self.prepopulated_fields.items(): if v[0] in trans_opts.fields: translation_fields = get_translation_fields(v[0]) prepopulated_fields_new[k] = tuple([translation_fields[0]]) self.prepopulated_fields = prepopulated_fields_new
def __init__(self, *args, **kwargs): super(TranslationAdmin, self).__init__(*args, **kwargs) trans_opts = translator.get_options_for_model(self.model) # Replace original field with translation field for each language if self.fields: fields_new = list(self.fields) for field in self.fields: if field in trans_opts.fields: index = fields_new.index(field) translation_fields = get_translation_fields(field) fields_new[index:index + 1] = translation_fields self.fields = fields_new if self.fieldsets: fieldsets_new = list(self.fieldsets) for (name, dct) in self.fieldsets: if 'fields' in dct: # TODO: Add support for grouped fieldsets # (see issue 52 for details) fields_new = list(dct['fields']) for field in dct['fields']: if field in trans_opts.fields: index = fields_new.index(field) translation_fields = get_translation_fields(field) fields_new[index:index + 1] = translation_fields dct['fields'] = fields_new self.fieldsets = fieldsets_new if self.list_editable: editable_new = list(self.list_editable) display_new = list(self.list_display) for field in self.list_editable: if field in trans_opts.fields: index = editable_new.index(field) display_index = display_new.index(field) translation_fields = get_translation_fields(field) editable_new[index:index + 1] = translation_fields display_new[display_index:display_index + 1] =\ translation_fields self.list_editable = editable_new self.list_display = display_new if self.prepopulated_fields: prepopulated_fields_new = dict(self.prepopulated_fields) for (k, v) in self.prepopulated_fields.items(): if v[0] in trans_opts.fields: translation_fields = get_translation_fields(v[0]) prepopulated_fields_new[k] = tuple([translation_fields[0]]) self.prepopulated_fields = prepopulated_fields_new
def __init__(self, *args, **kwargs): super(TranslationAdmin, self).__init__(*args, **kwargs) trans_opts = translator.get_options_for_model(self.model) # Replace original field with translation field for each language if self.fields: fields_new = list(self.fields) for field in self.fields: if field in trans_opts.fields: index = fields_new.index(field) translation_fields = get_translation_fields(field) fields_new[index:index + 1] = translation_fields self.fields = fields_new if self.fieldsets: fieldsets_new = list(self.fieldsets) for (name, dct) in self.fieldsets: if 'fields' in dct: fields_new = list(dct['fields']) for field in dct['fields']: if field in trans_opts.fields: index = fields_new.index(field) translation_fields = get_translation_fields(field) fields_new[index:index + 1] = translation_fields dct['fields'] = fields_new self.fieldsets = fieldsets_new if self.list_editable: editable_new = list(self.list_editable) display_new = list(self.list_display) for field in self.list_editable: if field in trans_opts.fields: index = editable_new.index(field) display_index = display_new.index(field) translation_fields = get_translation_fields(field) editable_new[index:index + 1] = translation_fields display_new[display_index:display_index + 1] = \ translation_fields self.list_editable = editable_new self.list_display = display_new if self.prepopulated_fields: prepopulated_fields_new = dict(self.prepopulated_fields) for (k, v) in self.prepopulated_fields.items(): if v[0] in trans_opts.fields: translation_fields = get_translation_fields(v[0]) prepopulated_fields_new[k] = tuple([translation_fields[0]]) self.prepopulated_fields = prepopulated_fields_new
def replace_orig_field(self, option): """ Replaces each original field in `option` that is registered for translation by its translation fields. Returns a new list with replaced fields. If `option` contains no registered fields, it is returned unmodified. >>> print self.trans_opts.fields ('title',) >>> get_translation_fields(self.trans_opts.fields[0]) ['title_de', 'title_en'] >>> self.replace_orig_field(['title', 'url']) ['title_de', 'title_en', 'url'] """ # TODO: Handle nested lists to display multiple fields on same line. if option: option_new = list(option) for opt in option: if opt in self.trans_opts.fields: index = option_new.index(opt) translation_fields = get_translation_fields(opt) option_new[index:index + 1] = translation_fields option = option_new return option
def replace_orig_field(self, option): """ Replaces each original field in `option` that is registered for translation by its translation fields. Returns a new list with replaced fields. If `option` contains no registered fields, it is returned unmodified. >>> print(self.trans_opts.fields.keys()) ['title',] >>> get_translation_fields(self.trans_opts.fields.keys()[0]) ['title_de', 'title_en'] >>> self.replace_orig_field(['title', 'url']) ['title_de', 'title_en', 'url'] Note that grouped fields are flattened. We do this because: 1. They are hard to handle in the jquery-ui tabs implementation 2. They don't scale well with more than a few languages 3. It's better than not handling them at all (okay that's weak) >>> self.replace_orig_field((('title', 'url'), 'email', 'text')) ['title_de', 'title_en', 'url_de', 'url_en', 'email_de', 'email_en', 'text'] """ if option: option_new = list(option) for opt in option: if opt in self.trans_opts.fields: index = option_new.index(opt) option_new[index : index + 1] = get_translation_fields(opt) elif isinstance(opt, (tuple, list)) and ([o for o in opt if o in self.trans_opts.fields]): index = option_new.index(opt) option_new[index : index + 1] = self.replace_orig_field(opt) option = option_new return option
def note_down_translatable_fields(sender, instance, **kwargs): """ Note down the translatable fields that have been modified on the updated_trans_fields field of the instance being saved. :param sender: the instance's model class. :param instance: object being saved. :param kwargs: keyword arguments, including trans_opts_class key that contains the modeltranslation.TranslationOptions which contains the translatable fields of the model. """ instance.updated_trans_fields = [] trans_opts_class = kwargs.get('trans_opts_class') lokalise_fields = get_lokalise_fields(trans_opts_class) try: db_instance = sender.objects.get(pk=instance.pk) except sender.DoesNotExist: instance.updated_trans_fields = lokalise_fields return for parent_field in lokalise_fields: trans_fields = get_translation_fields(parent_field) for field in trans_fields: if getattr(db_instance, field) != getattr(instance, field): instance.updated_trans_fields.append(parent_field) break
def _patch_prepopulated_fields(self): if self.prepopulated_fields: prepopulated_fields_new = dict(self.prepopulated_fields) for (k, v) in self.prepopulated_fields.items(): if v[0] in self.trans_opts.fields: translation_fields = get_translation_fields(v[0]) prepopulated_fields_new[k] = tuple([translation_fields[0]]) self.prepopulated_fields = prepopulated_fields_new
def get_readonly_fields(self, request, obj=None): if request.user.is_superuser: return self.readonly_fields fields = list(self.readonly_fields) fields.extend(['user', 'nickname', 'birth_place', 'birth_date', 'email']) fields.extend(get_translation_fields('subtitle')) return tuple(fields)
def _get_translation_fields_map(self): try: from modeltranslation.utils import get_translation_fields except ImportError: return {} return { f: tuple(get_translation_fields(f)) for f in self.trans_opts.fields }
def replace_orig_field(self, option): """ Replaces each original field in `option` that is registered for translation by its translation fields. Returns a new list with replaced fields. If `option` contains no registered fields, it is returned unmodified. >>> self = TranslationAdmin() # PyFlakes >>> print(self.trans_opts.fields.keys()) ['title',] >>> get_translation_fields(self.trans_opts.fields.keys()[0]) ['title_de', 'title_en'] >>> self.replace_orig_field(['title', 'url']) ['title_de', 'title_en', 'url'] Note that grouped fields are flattened. We do this because: 1. They are hard to handle in the jquery-ui tabs implementation 2. They don't scale well with more than a few languages 3. It's better than not handling them at all (okay that's weak) >>> self.replace_orig_field((('title', 'url'), 'email', 'text')) ['title_de', 'title_en', 'url_de', 'url_en', 'email_de', 'email_en', 'text'] """ if option: option_new = list(option) for opt in option: if opt in self.trans_opts.fields: index = option_new.index(opt) option_new[index:index + 1] = get_translation_fields(opt) elif isinstance(opt, (tuple, list)): trans = [o for o in opt if o in self.trans_opts.fields] if trans: index = option_new.index(opt) if len(trans) == len(opt): option_new[index:index + 1] = zip(*(get_translation_fields(f) for f in opt)) else: option_new[index:index + 1] = self.replace_orig_field(opt) option = option_new return option
def url_path_fix(apps, schema_editor): # cannot use apps.get_model here # because Page instances wouldn't have set_url_path method from wagtail.wagtailcore.models import Page url_path_fields = get_translation_fields('url_path') for page in Page.objects.order_by('path').iterator(): page.set_url_path(page.get_parent()) # make sure descendant page url paths are not updated at this point # because it would fail page.save(update_fields=url_path_fields)
def create_or_update_translations(fields_l, obj_instance): """ This function takes a list of translatable fields and an object instance and checks if there are uploaded translations for that fields and then it creates or updates them. :param fields_l: list of field names to upload translations for. :param obj_instance: instance of the objects the translations belong to. """ fields_key_map = {} platforms = ['web'] if len(fields_l) == 0: return operations = {'create': [], 'update': []} for field in fields_l: key_name = f'{obj_instance.__class__.__name__}_' \ f'{obj_instance.pk}_{field}' fields_key_map[key_name] = field t_fields = get_translation_fields(field) translations = [{ 'language_iso': f[-2:], 'translation': getattr(obj_instance, f) or '' } for f in t_fields] trans = { 'key_name': key_name, 'platforms': platforms, 'translations': translations } try: content_type = ContentType.objects.get_for_model( obj_instance.__class__) trans['key_id'] = LokaliseTranslation.objects.get( content_type=content_type, object_id=obj_instance.pk, field_name=field).key_id operations['update'].append(trans) except LokaliseTranslation.DoesNotExist: operations['create'].append(trans) update_translations(operations['update'], 'update') new_trans = update_translations(operations['create'], 'create') # We must create a LokaliseTranslation row for every created translation for k in new_trans['keys']: LokaliseTranslation.objects.create( key_id=k['key_id'], field_name=fields_key_map[k['key_name'][platforms[0]]], content_object=obj_instance, )
def _patch_list_editable(self): if self.list_editable: editable_new = list(self.list_editable) display_new = list(self.list_display) for field in self.list_editable: if field in self.trans_opts.fields: index = editable_new.index(field) display_index = display_new.index(field) translation_fields = get_translation_fields(field) editable_new[index:index + 1] = translation_fields display_new[display_index:display_index + 1] = translation_fields self.list_editable = editable_new self.list_display = display_new
def validate_unique(self): """ Calls the instance's validate_unique() method and updates the form's validation errors if any were raised. """ if translator: for fname in get_translation_fields('name'): if getattr(self.instance, fname, None) == "": setattr(self.instance, fname, None) try: self.instance.validate_unique() except ValidationError as e: self._update_errors(e)
def update_translation(self, data): lang_code = data['language']['iso'] translation_key = data['key']['id'] translation = data['translation']['value'] try: t_obj = LokaliseTranslation.objects.get(key_id=translation_key, ) except LokaliseTranslation.DoesNotExist(): return False translated_obj = t_obj.content_object translated_field = t_obj.field_name obj_translatable_fields = get_translation_fields(translated_field) field_lang = next( (f for f in obj_translatable_fields if f.endswith(lang_code)), None) if field_lang is None: return False setattr(translated_obj, field_lang, translation) translated_obj.save() return True
def __init__(self, *args, **kwargs): super(TranslationAdmin, self).__init__(*args, **kwargs) trans_opts = translator.get_options_for_model(self.model) # Replace original field with translation field for each language if self.fields: fields_new = list(self.fields) for field in self.fields: if field in trans_opts.fields: index = fields_new.index(field) translation_fields = get_translation_fields(field) fields_new[index:index + 1] = translation_fields self.fields = fields_new # Simple policy: if the admin class already defines a fieldset, we # leave it alone and assume the author has done whatever grouping for # translated fields they desire: if self.fieldsets: fieldsets_new = list(self.fieldsets) for (name, dct) in self.fieldsets: if 'fields' in dct: fields_new = list(dct['fields']) for field in dct['fields']: if field in trans_opts.fields: index = fields_new.index(field) translation_fields = get_translation_fields(field) fields_new[index:index + 1] = translation_fields dct['fields'] = fields_new self.fieldsets = fieldsets_new else: # If there aren't any existing fieldsets, we'll automatically # create one to group each translated field's localized fields: non_translated_fields = [ f.name for f in self.opts.fields if ( # The original translation field: f.name not in trans_opts.fields # The auto-generated fields for translations: and f.name not in trans_opts.localized_fieldnames_rev # Avoid including the primary key field: and f is not self.opts.auto_field # Avoid non-editable fields and f.editable) ] self.fieldsets = [ ('', { 'fields': non_translated_fields }), ] for orig_field, trans_fields in trans_opts.localized_fieldnames.items( ): # Extract the original field's verbose_name for use as this # fieldset's label - using ugettext_lazy in your model # declaration can make that translatable: label = self.model._meta.get_field(orig_field).verbose_name self.fieldsets.append((label, { "fields": trans_fields, "classes": ("modeltranslations", ) })) if self.list_editable: editable_new = list(self.list_editable) display_new = list(self.list_display) for field in self.list_editable: if field in trans_opts.fields: index = editable_new.index(field) display_index = display_new.index(field) translation_fields = get_translation_fields(field) editable_new[index:index + 1] = translation_fields display_new[display_index:display_index + 1] =\ translation_fields self.list_editable = editable_new self.list_display = display_new if self.prepopulated_fields: prepopulated_fields_new = dict(self.prepopulated_fields) for (k, v) in self.prepopulated_fields.items(): if v[0] in trans_opts.fields: translation_fields = get_translation_fields(v[0]) prepopulated_fields_new[k] = tuple([translation_fields[0]]) self.prepopulated_fields = prepopulated_fields_new
def __init__(self, *args, **kwargs): super(TranslationAdmin, self).__init__(*args, **kwargs) trans_opts = translator.get_options_for_model(self.model) # Replace original field with translation field for each language if self.fields: fields_new = list(self.fields) for field in self.fields: if field in trans_opts.fields: index = fields_new.index(field) translation_fields = get_translation_fields(field) fields_new[index:index + 1] = translation_fields self.fields = fields_new # Simple policy: if the admin class already defines a fieldset, we # leave it alone and assume the author has done whatever grouping for # translated fields they desire: if self.fieldsets: fieldsets_new = list(self.fieldsets) for (name, dct) in self.fieldsets: if 'fields' in dct: fields_new = list(dct['fields']) for field in dct['fields']: if field in trans_opts.fields: index = fields_new.index(field) translation_fields = get_translation_fields(field) fields_new[index:index + 1] = translation_fields dct['fields'] = fields_new self.fieldsets = fieldsets_new else: # If there aren't any existing fieldsets, we'll automatically # create one to group each translated field's localized fields: non_translated_fields = [ f.name for f in self.opts.fields if ( # The original translation field: f.name not in trans_opts.fields # The auto-generated fields for translations: and f.name not in trans_opts.localized_fieldnames_rev # Avoid including the primary key field: and f is not self.opts.auto_field # Avoid non-editable fields and f.editable ) ] self.fieldsets = [ ('', {'fields': non_translated_fields}), ] for orig_field, trans_fields in trans_opts.localized_fieldnames.items(): # Extract the original field's verbose_name for use as this # fieldset's label - using ugettext_lazy in your model # declaration can make that translatable: label = self.model._meta.get_field(orig_field).verbose_name self.fieldsets.append((label, { "fields": trans_fields, "classes": ("modeltranslations",) })) if self.list_editable: editable_new = list(self.list_editable) display_new = list(self.list_display) for field in self.list_editable: if field in trans_opts.fields: index = editable_new.index(field) display_index = display_new.index(field) translation_fields = get_translation_fields(field) editable_new[index:index + 1] = translation_fields display_new[display_index:display_index + 1] =\ translation_fields self.list_editable = editable_new self.list_display = display_new if self.prepopulated_fields: prepopulated_fields_new = dict(self.prepopulated_fields) for (k, v) in self.prepopulated_fields.items(): if v[0] in trans_opts.fields: translation_fields = get_translation_fields(v[0]) prepopulated_fields_new[k] = tuple([translation_fields[0]]) self.prepopulated_fields = prepopulated_fields_new
def find(self, query): return model_search(query, self, get_translation_fields('text'))
def save(self, *args, **kwargs): self.full_clean() update_descendant_url_paths = False is_new = self.id is None if is_new: self.set_url_path(self.get_parent()) else: # update url paths if: # a) update_fields is specified and it includes any slug field # or # b) update_fields is not specified (check all slug fields in that case) slug_fields = get_translation_fields('slug') update_fields = kwargs.get('update_fields', slug_fields) updated_slug_fields = [f for f in slug_fields if f in update_fields] if updated_slug_fields: old_record = Page.objects.get(id=self.id) if any( getattr(old_record, f) != getattr(self, f) for f in updated_slug_fields): self.set_url_path(self.get_parent()) update_descendant_url_paths = True # current language fields may have been set to our uuid, # let's get rid of that lang_code = get_language() or mt_settings.DEFAULT_LANGUAGE xp = re.compile(r"{}[0-9a-f]+".format(PREFIX)) title_field = build_localized_fieldname('title', lang_code) slug_field = build_localized_fieldname('slug', lang_code) url_path_field = build_localized_fieldname('url_path', lang_code) field_list = [ title_field, slug_field, url_path_field, ] for field in field_list: setattr(self, field, xp.sub("", getattr(self, field))) if xp.match(self.draft_title): # try to override uuid-draft_title with a nice one for lang_code in mt_settings.AVAILABLE_LANGUAGES: title_field = build_localized_fieldname('title', lang_code) if getattr(self, title_field): self.draft_title = getattr(self, title_field) break result = super(Page, self).save(*args, **kwargs) if update_descendant_url_paths: self._update_descendant_lang_url_paths(old_record) if Site.objects.filter(root_page=self).exists(): delete_root_path_cache() if is_new: cls = type(self) logger.info("Page created: \"%s\" id=%d content_type=%s.%s path=%s", self.title, self.id, cls._meta.app_label, cls.__name__, self.url_path) return result