def handle(self, *args, **options): file_class_map = { 'auteur': Artist, # no parent 'collect': CollectMethod, 'stade-creation': CreationState, 'denomination': Denomination, 'domain': Domain, 'inscriptions': InscriptionType, 'lieu': GeographicalLocation, 'juridique': LegalState, 'techniques': MaterialTechnique, 'datation': Period, 'sources-representation': RepresentationSource, 'sujet': RepresentationSubject, 'ecole': School, 'epoque': StyleEra, 'utilisations': UsageDestination, } model_class = None for k, v in file_class_map.items(): if k in args[0]: model_class = v break if not model_class: print "What to do with" + args[0] return r = csv.reader(open(args[0], 'U'), delimiter=',') current = [] for row in r: i = 0 for node in row: name = node.strip('", ').decode('utf-8') if name: if '=' in name: names = [x.strip() for x in name.split('=')] name = '%s (%s)' % (names[0].strip(), ', '.join(names[1:])) o = {} try: translator.get_options_for_model(model_class) o['name_fr'] = name except: o['name'] = name if i > 0: o['parent'] = current[i-1] model, created = model_class.objects.get_or_create(**o) if len(current) < i + 1: current.append(model) else: current[i] = model i += 1
def formfield_exclude_irrelevant(db_field, **kwargs): """Filter form and keep only localized fields""" trans_opts = translator.get_options_for_model(db_field.model) if db_field.name in trans_opts.fields: return None if 'field' in kwargs: field = kwargs['field'] else: field = db_field.formfield(**kwargs) if hasattr(db_field, 'translated_field'): if db_field.name.endswith('_{0}'.format(get_language())): field.required = True field.widget.attrs['class'] = '{0} {1}'.format( getattr(field.widget.attrs, 'class', ''), 'language-depended' ) field.help_text = string_concat( field.help_text, _(' '), _('This field dependent on current language.') ) else: return None return field
def handle_noargs(self, **options): """ Command execution. """ self.cursor = connection.cursor() self.introspection = connection.introspection found_missing_fields = False models = translator.get_registered_models(abstract=False) for model in models: db_table = model._meta.db_table model_full_name = '%s.%s' % (model._meta.app_label, model._meta.module_name) opts = translator.get_options_for_model(model) for field_name in opts.local_fields.iterkeys(): missing_langs = list(self.get_missing_languages(field_name, db_table)) if missing_langs: found_missing_fields = True print_missing_langs(missing_langs, field_name, model_full_name) sql_sentences = self.get_sync_sql(field_name, missing_langs, model) execute_sql = ask_for_confirmation(sql_sentences, model_full_name) if execute_sql: print 'Executing SQL...', for sentence in sql_sentences: self.cursor.execute(sentence) print 'Done' else: print 'SQL not executed' transaction.commit_unless_managed() if not found_missing_fields: print 'No new translatable fields detected'
def handle(self, *args, **options): verbosity = int(options['verbosity']) if verbosity > 0: self.stdout.write("Using default language: %s\n" % DEFAULT_LANGUAGE) models = translator.get_registered_models(abstract=False) for model in models: if verbosity > 0: self.stdout.write("Updating data of model '%s'\n" % model) opts = translator.get_options_for_model(model) for field_name in opts.fields.keys(): def_lang_fieldname = build_localized_fieldname( field_name, DEFAULT_LANGUAGE) # We'll only update fields which do not have an existing value q = Q(**{def_lang_fieldname: None}) field = model._meta.get_field(field_name) if field.get_internal_type( ) == 'JsonBField': # support for jsonbfields q |= Q(**{def_lang_fieldname: {}}) if field.empty_strings_allowed: q |= Q(**{def_lang_fieldname: ""}) model._default_manager.filter(q).rewrite(False).update( **{def_lang_fieldname: F(field_name)})
def replace_orig_fields(self): self.orig_fields = self.fields.keys() # Expand i18n fields try: # Obtain model translation options mto = translator.get_options_for_model(self._meta.model) except NotRegistered: # No translation field on this model, nothing to do return # For each translated model field for modelfield in mto.fields: if modelfield not in self.fields: continue # Remove form native field (e.g. `name`) native = self.fields.pop(modelfield) # Add translated fields (e.g. `name_fr`, `name_en`...) for l in app_settings['TRANSLATED_LANGUAGES']: lang = l[0] name = '%s_%s' % (modelfield, lang) # Add to form.fields{} translated = copy.deepcopy(native) translated.required = native.required and ( lang == app_settings['LANGUAGE_CODE']) translated.label = u"%s [%s]" % (translated.label, lang) self.fields[name] = translated # Keep track of replacements self._translated.setdefault(modelfield, []).append(name)
def __init__(self, *args, **kwargs): super(CurLocaleModelForm, self).__init__(*args, **kwargs) # trans_fields will contain dict from original field name to localized bound # formfield for current locale. # This is useful in templates to render localized field by original name without # locale suffix. For example to render localized name field in template you can write: # {{form.trans_fields.name}} # if current locale is 'en' it is equivalent to: # {{form.name_en}} self.trans_fields = {} model_trans_fields = translator.get_options_for_model(self._meta.model).fields lang = get_language() for f in self._meta.model._meta.fields: if f.name not in self.fields: continue if f.name in model_trans_fields: del self.fields[f.name] # Delete original unlocalized fields elif isinstance(f, TranslationField): if not f.name.endswith('_' + lang): # Delete localized field for other language del self.fields[f.name] else: # Set trans_fields mapping from original field name to this field self.trans_fields[f.translated_field.name] = self[f.name] if not f.translated_field.blank: # Original modelfield has blank=False attribute, we should set "required" flag on # localized formfield for current language. self.fields[f.name].required = True
def patch_translation_field(self, db_field, field, **kwargs): trans_opts = translator.get_options_for_model(self.model) # Hide the original field by making it non-editable. if db_field.name in trans_opts.fields: db_field.editable = False # For every localized field copy the widget from the original field # and add a css class to identify a modeltranslation widget. if db_field.name in trans_opts.localized_fieldnames_rev: orig_fieldname = trans_opts.localized_fieldnames_rev[db_field.name] orig_formfield = self.formfield_for_dbfield(\ self.model._meta.get_field(orig_fieldname), **kwargs) field.widget = copy(orig_formfield.widget) css_classes = field.widget.attrs.get('class', '').split(' ') css_classes.append('modeltranslation') if db_field.language == DEFAULT_LANGUAGE: # Add another css class to identify a default modeltranslation # widget. css_classes.append('modeltranslation-default') if orig_formfield.required: # In case the original form field was required, make the default # translation field required instead. orig_formfield.required = False orig_formfield.blank = True field.required = True field.blank = False field.widget.attrs['class'] = ' '.join(css_classes)
def __init__(self, progress_cb=None): self.warnings = {} self.line = 0 self.nb_success = 0 self.nb_created = 0 self.nb_updated = 0 self.nb_unmodified = 0 self.progress_cb = progress_cb try: mto = translator.get_options_for_model(self.model) except NotRegistered: self.translated_fields = [] else: self.translated_fields = mto.fields.keys() if self.fields is None: self.fields = { f.name: force_text(f.verbose_name) for f in self.model._meta.fields if not isinstance(f, TranslationField) } self.m2m_fields = { f.name: force_text(f.verbose_name) for f in self.model._meta.many_to_many }
def get_translatable_fields_for_model(model): from modeltranslation.translator import NotRegistered, translator try: return translator.get_options_for_model(model).get_field_names() except NotRegistered: return None
def collect_po_file(self, lang): po = polib.POFile() po.metadata = { 'Language': lang, 'Content-Type': 'text/plain; charset=utf-8', 'Content-Transfer-Encoding': '8bit', } def append_item(msgid, msgstr, occurrences): entry = po.find(msgid) if not entry: po.append( polib.POEntry(msgid=msgid, msgstr=msgstr, occurrences=occurrences)) else: entry.occurrences += occurrences for string in StringTranslation.objects.all(): if string.key and len(string.key) > 0: append_item( msgid=string.key, msgstr=getattr(string, 'translation_{}'.format(lang)) or '', occurrences=[('strings', str(string.id))]) models = translator.get_registered_models(abstract=False) for model in models: if 'products' in str(model): continue if model is StringTranslation: continue opts = translator.get_options_for_model(model) fields_to_copy = [] for field_name in opts.fields.keys(): fields_to_copy.append( (field_name, build_localized_fieldname(field_name, lang))) for obj in model.objects.all(): for field_name, field_name_local in fields_to_copy: try: msgid = obj.__dict__[field_name] except KeyError: msgid = None if msgid and msgid != '': if len(msgid) < 300: append_item(msgid=msgid, msgstr=getattr(obj, field_name_local) or '', occurrences=[('{}:{}'.format( get_model_ct(model), field_name), str(obj.id))]) else: print( "WARN: text too long for msgid. Model: {} Field: {}" .format(model, field_name)) return po
def handle_noargs(self, **options): """ Command execution. """ self.interactive = options['interactive'] models = translator.get_registered_models(abstract=False) found_bad_fields = False for model in models: db_table = model._meta.db_table model_full_name = '%s.%s' % (model._meta.app_label, model._meta.module_name) opts = translator.get_options_for_model(model) for field_name in opts.local_fields.keys(): bad_lang_field_names = self.get_bad_lang_field_names(field_name, db_table) if bad_lang_field_names: found_bad_fields = True print_bad_langs(bad_lang_field_names, field_name, model_full_name) sql_sentences = self.get_alter_sql(bad_lang_field_names, model) execute_sql = ask_for_confirmation( sql_sentences, model_full_name, self.interactive) if execute_sql: print('Executing SQL...') for sentence in sql_sentences: self.cursor.execute(sentence) print('Done') else: print('SQL not executed') if not found_bad_fields: print('No new translatable fields detected')
def replace_orig_fields(self): self.orig_fields = self.fields.keys() # Expand i18n fields try: # Obtain model translation options mto = translator.get_options_for_model(self._meta.model) except NotRegistered: # No translation field on this model, nothing to do return # For each translated model field for modelfield in mto.fields: if modelfield not in self.fields: continue # Remove form native field (e.g. `name`) native = self.fields.pop(modelfield) # Add translated fields (e.g. `name_fr`, `name_en`...) for l in app_settings['TRANSLATED_LANGUAGES']: lang = l[0] name = '%s_%s' % (modelfield, lang) # Add to form.fields{} translated = copy.deepcopy(native) translated.required = native.required and (lang == app_settings['LANGUAGE_CODE']) translated.label = u"%s [%s]" % (translated.label, lang) self.fields[name] = translated # Keep track of replacements self._translated.setdefault(modelfield, []).append(name)
def populate_exclude(exclude, model): """handles exclude""" trans_opts = translator.get_options_for_model(model) for fn in exclude[:]: for tf in trans_opts.fields.get(fn, set()): exclude.append(tf.name) return exclude
def _patch_simple_panel(self, model, original_panel): panel_class = original_panel.__class__ translated_panels = [] translation_registered_fields = translator.get_options_for_model( model).fields # If the panel field is not registered for translation # the original one is returned if original_panel.field_name not in translation_registered_fields: return [original_panel] for language in mt_settings.AVAILABLE_LANGUAGES: original_field = model._meta.get_field(original_panel.field_name) localized_field_name = build_localized_fieldname( original_panel.field_name, language) # if the original field is required and the current language is the default one # this field's blank property is set to False if not original_field.blank and language == mt_settings.DEFAULT_LANGUAGE: localized_field = model._meta.get_field(localized_field_name) localized_field.blank = False localized_panel = panel_class(localized_field_name) # Pass the original panel extra attributes to the localized if hasattr(original_panel, 'classname'): localized_panel.classname = original_panel.classname if hasattr(original_panel, 'widget'): localized_panel.widget = original_panel.widget translated_panels.append(localized_panel) return translated_panels
def __init__(self, *args, **kwargs): super(CurLocaleModelForm, self).__init__(*args, **kwargs) # trans_fields will contain dict from original field name to localized bound # formfield for current locale. # This is useful in templates to render localized field by original name without # locale suffix. For example to render localized name field in template you can write: # {{form.trans_fields.name}} # if current locale is 'en' it is equivalent to: # {{form.name_en}} self.trans_fields = {} model_trans_fields = translator.get_options_for_model( self._meta.model).fields lang = get_language() for f in self._meta.model._meta.fields: if f.name not in self.fields: continue if f.name in model_trans_fields: del self.fields[f.name] # Delete original unlocalized fields elif isinstance(f, TranslationField): if not f.name.endswith('_' + lang): # Delete localized field for other language del self.fields[f.name] else: # Set trans_fields mapping from original field name to this field self.trans_fields[f.translated_field.name] = self[f.name] if not f.translated_field.blank: # Original modelfield has blank=False attribute, we should set "required" flag on # localized formfield for current language. self.fields[f.name].required = True
def formfield_exclude_irrelevant(db_field, **kwargs): """ only localized fields """ from modeltranslation.translator import translator from modeltranslation.utils import get_language trans_opts = translator.get_options_for_model(db_field.model) if db_field.name in trans_opts.fields: return None if 'field' in kwargs: field = kwargs['field'] else: field = db_field.formfield(**kwargs) if hasattr(db_field, 'translated_field'): if db_field.name.endswith('_{0}'.format(get_language())): field.required = True field.widget.attrs['class'] = '{0} {1}'.format( getattr(field.widget.attrs, 'class', ''), 'language-depended' ) field.help_text = string_concat( field.help_text, _(' '), _('This field dependent on current language.') ) else: return None return field
def get_translation_stats(lang, model=None): """ Returns statistics on the total number of translatable items for the passed in class along with how many actually have translations """ total = 0 translated = 0 # no model passed in, figure out our totals from the translated models if model == None: for model in get_translatable_models(): stats = get_translation_stats(lang, model) total += stats.total translated += stats.translated # otherwise, figure out the stats just for the passed in model else: options = translator.get_options_for_model(model) # total # of items is the total count of active objects total = model.objects.count() # translated is number that have a value for the translated field kwargs = dict() for field in options.fields: kwargs["%s_%s__isnull" % (field, lang)] = False translated = model.objects.filter(**kwargs).count() return TranslationStats(lang, total, translated)
def handle_noargs(self, **options): """ Command execution. """ self.interactive = options['interactive'] models = translator.get_registered_models(abstract=False) found_bad_fields = False for model in models: db_table = model._meta.db_table model_full_name = '%s.%s' % (model._meta.app_label, model._meta.module_name) opts = translator.get_options_for_model(model) for field_name in opts.local_fields.keys(): bad_lang_field_names = self.get_bad_lang_field_names( field_name, db_table) if bad_lang_field_names: found_bad_fields = True print_bad_langs(bad_lang_field_names, field_name, model_full_name) sql_sentences = self.get_alter_sql(bad_lang_field_names, model) execute_sql = ask_for_confirmation(sql_sentences, model_full_name, self.interactive) if execute_sql: print('Executing SQL...') for sentence in sql_sentences: self.cursor.execute(sentence) print('Done') else: print('SQL not executed') if not found_bad_fields: print('No new translatable fields detected')
def __init__(self, progress_cb=None, user=None, encoding='utf8'): self.warnings = {} self.line = 0 self.nb_success = 0 self.nb_created = 0 self.nb_updated = 0 self.nb_unmodified = 0 self.progress_cb = progress_cb self.user = user self.structure = user and user.profile.structure or default_structure() self.encoding = encoding try: mto = translator.get_options_for_model(self.model) except NotRegistered: self.translated_fields = [] else: self.translated_fields = mto.fields.keys() if self.fields is None: self.fields = { f.name: force_text(f.verbose_name) for f in self.model._meta.fields if not isinstance(f, TranslationField) } self.m2m_fields = { f.name: force_text(f.verbose_name) for f in self.model._meta.many_to_many }
def _patch_simple_panel(self, model, original_panel): panel_class = original_panel.__class__ translated_panels = [] translation_registered_fields = translator.get_options_for_model(model).fields # If the panel field is not registered for translation # the original one is returned if original_panel.field_name not in translation_registered_fields: return [original_panel] for language in mt_settings.AVAILABLE_LANGUAGES: original_field = model._meta.get_field(original_panel.field_name) localized_field_name = build_localized_fieldname(original_panel.field_name, language) # if the original field is required and the current language is the default one # this field's blank property is set to False if not original_field.blank and language == mt_settings.DEFAULT_LANGUAGE: localized_field = model._meta.get_field(localized_field_name) localized_field.blank = False localized_panel = panel_class(localized_field_name) # Pass the original panel extra attributes to the localized if hasattr(original_panel, 'classname'): localized_panel.classname = original_panel.classname if hasattr(original_panel, 'widget'): localized_panel.widget = original_panel.widget translated_panels.append(localized_panel) return translated_panels
def _patch_other_models(self, model): translation_registered_fields = translator.get_options_for_model( model).fields if hasattr(model, 'edit_handler'): edit_handler = model.edit_handler for tab in edit_handler.children: tab.children = self._patch_panels(tab.children) elif hasattr(model, 'panels'): model.panels = self._patch_panels(model.panels) else: panels = extract_panel_definitions_from_model_class(model) panels = filter( lambda field: field.field_name not in translation_registered_fields, panels) edit_handler = ObjectList(panels) if VERSION < (2, 5): SNIPPET_EDIT_HANDLERS[model] = edit_handler.bind_to_model( model) else: SNIPPET_EDIT_HANDLERS[model] = edit_handler.bind_to( model=model) # OVERRIDE FIELDS model_fields = model._meta.get_fields() for field in model_fields: if isinstance(field, StreamField ) and field.name in translation_registered_fields: descriptor = getattr(model, field.name) _patch_stream_field_meaningful_value(descriptor)
def __init__(self, progress_cb=None, user=None, encoding='utf8'): self.warnings = {} self.line = 0 self.nb_success = 0 self.nb_created = 0 self.nb_updated = 0 self.nb_unmodified = 0 self.progress_cb = progress_cb self.user = user self.structure = user and user.profile.structure or default_structure() self.encoding = encoding try: mto = translator.get_options_for_model(self.model) except NotRegistered: self.translated_fields = [] else: self.translated_fields = mto.fields.keys() if self.fields is None: self.fields = { f.name: force_str(f.verbose_name) for f in self.model._meta.fields if not isinstance(f, TranslationField) } self.m2m_fields = { f.name: force_str(f.verbose_name) for f in self.model._meta.many_to_many }
def localize_fieldname(self, name, model=None, lang=None): """Localizes translatable field name""" model = model or self.model trans_opts = translator.get_options_for_model(model) if name in trans_opts.fields: return localize_fieldname(name, lang) return name
def formfield_exclude_translations(db_field, **kwargs): """Filter form and keep only non-localized fields""" if hasattr(db_field, 'translated_field'): return None if 'field' in kwargs: field = kwargs['field'] else: field = db_field.formfield(**kwargs) if not field: return field trans_opts = translator.get_options_for_model(db_field.model) if db_field.name in trans_opts.fields: field.widget.attrs['class'] = '{0} {1}'.format( getattr(field.widget.attrs, 'class', ''), 'language-depended' ) field.help_text = string_concat( field.help_text, _(' '), _('This field dependent on current language.') ) return field
def update_translation_time_stamp(instance, class_model): """Update last update time stamp. This method is used inside a signal. Class model should have field tracker. :param instance: The instance of the class. :type instance: TranslationMixin :param class_model: The sender of the signal / the class of instance. :type class_model: class """ # New instance, always set the last_update if instance.pk is None: instance.last_update = datetime.datetime.now() return need_update_timestamp = False translated_fields = translator.get_options_for_model( class_model).get_field_names() for translated_field in translated_fields: if instance.tracker.has_changed(translated_field): need_update_timestamp = True break if need_update_timestamp: instance.last_update = datetime.datetime.now()
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 handle(self, **options): verbosity = int(options['verbosity']) if verbosity > 0: self.stdout.write("Using default language: %s\n" % DEFAULT_LANGUAGE) models = translator.get_registered_models(abstract=False) for model in models: if verbosity > 0: self.stdout.write("Updating data of model '%s'\n" % model) opts = translator.get_options_for_model(model) for field_name in opts.fields.keys(): def_lang_fieldname = build_localized_fieldname( field_name, DEFAULT_LANGUAGE) # We'll only update fields which do not have an existing value q = Q(**{def_lang_fieldname: None}) field = model._meta.get_field(field_name) if field.empty_strings_allowed: q |= Q(**{def_lang_fieldname: ''}) if issubclass(model, Page): for obj in model._default_manager.filter(q): # Get table description in order to know if field is # in child or parent table # TODO: Tested only on PostgreSQL engine db_table = model._meta.db_table db_table_desc = connection.introspection. \ get_table_description( connection.cursor(), db_table) # original field in child class if field_name in [x.name for x in db_table_desc]: raw = model._default_manager.raw( 'SELECT *, %s AS original_field FROM %s \ WHERE page_ptr_id=%d LIMIT 1' % (field_name, db_table, obj.page_ptr_id))[0] setattr(obj, def_lang_fieldname, raw.original_field) # field is a foreign key elif (field_name + '_id') in \ [x.name for x in db_table_desc]: raw = model._default_manager.raw( 'SELECT *, %s AS original_field FROM %s \ WHERE page_ptr_id=%d LIMIT 1' % (field_name + '_id', db_table, obj.page_ptr_id))[0] setattr(obj, def_lang_fieldname + '_id', raw.original_field) # original field parent class else: raw = Page._default_manager.raw( 'SELECT *, %s AS original_field FROM \ wagtailcore_page WHERE id=%d LIMIT 1' % (field_name, obj.page_ptr_id))[0] setattr(obj, def_lang_fieldname, raw.original_field) obj.save(update_fields=[def_lang_fieldname]) else: model._default_manager.filter(q).rewrite(False).update( **{def_lang_fieldname: F(field_name)})
def _patch_page_models(self, model): # PANEL PATCHING # Check if the model has a custom edit handler if hasattr(model, 'edit_handler'): tabs = model.edit_handler.children for tab in tabs: tab.children = self._patch_panels(tab.children) else: # If the page doesn't have an edit_handler we patch the panels that # wagtail uses by default if hasattr(model, 'content_panels'): model.content_panels = self._patch_panels(model.content_panels) if hasattr(model, 'promote_panels'): model.promote_panels = self._patch_panels(model.promote_panels) if hasattr(model, 'settings_panels'): model.settings_panels = self._patch_panels( model.settings_panels) # Clear the edit handler cached value, if it exists, so wagtail reconstructs # the edit_handler based on the patched panels model.get_edit_handler.cache_clear() # SEARCH FIELDS PATCHING translation_registered_fields = translator.get_options_for_model( model).fields for field in model.search_fields: # Check if the field is a SearchField and if it is one of the fields registered for translation if field.__class__ is SearchField and field.field_name in translation_registered_fields: # If it is we create a clone of the original SearchField to keep all the defined options # and replace its name by the translated one for language in mt_settings.AVAILABLE_LANGUAGES: translated_field = copy.deepcopy(field) translated_field.field_name = build_localized_fieldname( field.field_name, language) model.search_fields = list( model.search_fields) + [translated_field] # OVERRIDE FIELDS model_fields = model._meta.get_fields() for field in model_fields: if isinstance(field, StreamField ) and field.name in translation_registered_fields: descriptor = getattr(model, field.name) _patch_stream_field_meaningful_value(descriptor) # OVERRIDE PAGE METHODS model.set_url_path = _new_set_url_path model.route = _new_route model._update_descendant_url_paths = _new_update_descendant_url_paths _patch_clean(model) if not model.save.__name__.startswith('localized'): setattr(model, 'save', LocalizedSaveDescriptor(model.save))
def test_required_fields_banner_component(en_locale): options = translator.get_options_for_model(models.BannerComponent) assert options.required_languages == { 'en-gb': [ 'title', 'banner_content', ] }
def test_required_fields_invest_sector_landing_page(): options = translator.get_options_for_model(models.SectorLandingPage) assert options.required_languages == { 'en-gb': [ 'title', 'heading', ] }
def test_required_fields_invest_info_page(): options = translator.get_options_for_model(models.InfoPage) assert options.required_languages == { 'en-gb': [ 'title', 'content', ] }
def _patch_page_models(self, model): # PANEL PATCHING # Check if the model has a custom edit handler if hasattr(model, 'edit_handler'): tabs = model.edit_handler.children for tab in tabs: tab.children = self._patch_panels(tab.children) else: # If the page doesn't have an edit_handler we patch the panels that # wagtail uses by default if hasattr(model, 'content_panels'): model.content_panels = self._patch_panels(model.content_panels) if hasattr(model, 'promote_panels'): model.promote_panels = self._patch_panels(model.promote_panels) if hasattr(model, 'settings_panels'): model.settings_panels = self._patch_panels(model.settings_panels) # Clear the edit handler cached value, if it exists, so wagtail reconstructs # the edit_handler based on the patched panels model.get_edit_handler.cache_clear() # SEARCH FIELDS PATCHING translation_registered_fields = translator.get_options_for_model(model).fields for field in model.search_fields: # Check if the field is a SearchField and if it is one of the fields registered for translation if field.__class__ is SearchField and field.field_name in translation_registered_fields: # If it is we create a clone of the original SearchField to keep all the defined options # and replace its name by the translated one for language in mt_settings.AVAILABLE_LANGUAGES: translated_field = copy.deepcopy(field) translated_field.field_name = build_localized_fieldname(field.field_name, language) model.search_fields = list(model.search_fields) + [translated_field] # OVERRIDE FIELDS model_fields = model._meta.get_fields() for field in model_fields: if isinstance(field, StreamField) and field.name in translation_registered_fields: descriptor = getattr(model, field.name) _patch_stream_field_meaningful_value(descriptor) # OVERRIDE PAGE METHODS if TRANSLATE_SLUGS: model.set_url_path = _new_set_url_path model.route = _new_route model._update_descendant_url_paths = _new_update_descendant_url_paths if not hasattr(model, '_get_site_root_paths'): model.get_url_parts = _new_get_url_parts # Wagtail<1.11 model._get_site_root_paths = _new_get_site_root_paths _patch_clean(model) if not model.save.__name__.startswith('localized'): setattr(model, 'save', LocalizedSaveDescriptor(model.save))
def _append_translated(self, fields): "If translated field is encountered, add also all its translation fields." fields = set(fields) from modeltranslation.translator import translator opts = translator.get_options_for_model(self.model) for key, translated in opts.fields.items(): if key in fields: fields = fields.union(f.name for f in translated) return fields
def append_translated(model, fields): "If translated field is encountered, add also all its translation fields." fields = set(fields) from modeltranslation.translator import translator opts = translator.get_options_for_model(model) for key, translated in opts.fields.items(): if key in fields: fields = fields.union(f.name for f in translated) return fields
def get_fields_to_translatable_models(model): from modeltranslation.translator import translator results = [] for field_name in translator.get_options_for_model(model).fields.keys(): field_object, modelclass, direct, m2m = model._meta.get_field_by_name(field_name) if direct and isinstance(field_object, RelatedField): if get_translatable_fields_for_model(field_object.related.parent_model) is not None: results.append((field_name, field_object.related.parent_model)) return results
def _patch_page_models(self, model): # PANEL PATCHING # Check if the model has a custom edit handler if hasattr(model, 'edit_handler'): tabs = model.edit_handler.children for tab in tabs: tab.children = self._patch_panels(tab.children) else: # If the page doesn't have an edit_handler we patch the panels that # wagtail uses by default if hasattr(model, 'content_panels'): model.content_panels = self._patch_panels(model.content_panels) if hasattr(model, 'promote_panels'): model.promote_panels = self._patch_panels(model.promote_panels) if hasattr(model, 'settings_panels'): model.settings_panels = self._patch_panels( model.settings_panels) # Clear the edit handler cached value, if it exists, so wagtail reconstructs # the edit_handler based on the patched panels model.get_edit_handler.cache_clear() # SEARCH FIELDS PATCHING translation_registered_fields = translator.get_options_for_model( model).fields for field in model.search_fields: # Check if the field is a SearchField and if it is one of the fields registered for translation if field.__class__ is SearchField and field.field_name in translation_registered_fields: # If it is we create a clone of the original SearchField to keep all the defined options # and replace its name by the translated one for language in mt_settings.AVAILABLE_LANGUAGES: translated_field = copy.deepcopy(field) translated_field.field_name = build_localized_fieldname( field.field_name, language) model.search_fields = list( model.search_fields) + [translated_field] # OVERRIDE PAGE METHODS model.move = _new_move model.set_url_path = _new_set_url_path model.route = _new_route model.get_site_root_paths = _new_get_site_root_paths # FIXME: check since which version we can use the default major, minor, patch = wagtail_version[:3] if major == 1 and minor < 11: model.relative_url = _new_relative_url model.url = _new_url _patch_clean(model)
def test_required_fields_invest_setup_guide_page(): options = translator.get_options_for_model(models.SetupGuidePage) assert options.required_languages == { 'en-gb': [ 'title', 'description', 'heading', 'sub_heading', 'subsection_title_one', 'subsection_content_one', 'subsection_title_two', 'subsection_content_two' ] }
def test_required_field_invest_setup_guide_landing_page(): options = translator.get_options_for_model(models.SetupGuideLandingPage) assert options.required_languages == { 'en-gb': [ 'title', 'heading', 'sub_heading', ] }
def get_base_translation_field_name(self): """ Get field names defined as translatable on 'modeltranslation' :return: list of name fields """ try: trans_options = translator.get_options_for_model(self.get_model()) return trans_options.get_field_names() except NotRegistered: return []
def test_required_fields_invest_home_page(): options = translator.get_options_for_model(models.InvestHomePage) assert options.required_languages == { 'en-gb': [ 'title', 'breadcrumbs_label', 'heading', 'sub_heading', ] }
def get_translated_fields(self): if self._translated_fields is None: models = translator.get_registered_models() if self.model in models: options = translator.get_options_for_model(self.model) rv = [field for field in options.fields] self._translated_fields = rv else: self._translated_fields = [] return self._translated_fields
def handle(self, *args, **options): verbosity = options['verbosity'] if verbosity > 0: self.stdout.write("Using default language: %s" % DEFAULT_LANGUAGE) # get all models excluding proxy- and not managed models models = translator.get_registered_models(abstract=False) models = [m for m in models if not m._meta.proxy and m._meta.managed] # optionally filter by given app_label app_label = options['app_label'] if app_label: models = [m for m in models if m._meta.app_label == app_label] # optionally filter by given model_name model_name = options['model_name'] if model_name: model_name = model_name.lower() models = [m for m in models if m._meta.model_name == model_name] # optionally defining the translation field language lang = options.get('language') or DEFAULT_LANGUAGE if lang not in AVAILABLE_LANGUAGES: raise CommandError( "Cannot find language '%s'. Options are %s." % (lang, COMMASPACE.join(AVAILABLE_LANGUAGES)) ) else: lang = lang.replace('-', '_') if verbosity > 0: self.stdout.write( "Working on models: %s" % ', '.join( ["{app_label}.{object_name}".format(**m._meta.__dict__) for m in models] ) ) for model in models: if verbosity > 0: self.stdout.write("Updating data of model '%s'" % model) opts = translator.get_options_for_model(model) for field_name in opts.fields.keys(): def_lang_fieldname = build_localized_fieldname(field_name, lang) # We'll only update fields which do not have an existing value q = Q(**{def_lang_fieldname: None}) field = model._meta.get_field(field_name) if field.empty_strings_allowed: q |= Q(**{def_lang_fieldname: ""}) model._default_manager.filter(q).rewrite(False).order_by().update( **{def_lang_fieldname: F(field_name)} )
def get_models(self, app): r = [] for mdname in dir(app.models): if mdname[0] == '_': continue md = getattr(app.models, mdname) try: opts = translator.get_options_for_model(md) r.append((md, opts)) except NotRegistered: continue return r
def save_model(self, request, obj, form, change): # Rule is: 3. Assigning a value to a translation field of the default language also # updates the original field. # Ensure that an empty default language field value clears the default field. # See issue 47 for details. trans_opts = translator.get_options_for_model(self.model) for k, v in trans_opts.localized_fieldnames.items(): if getattr(obj, k): default_lang_fieldname = build_localized_fieldname(k, DEFAULT_LANGUAGE) if not getattr(obj, default_lang_fieldname): # TODO: Handle null values setattr(obj, k, "") super(TranslationAdmin, self).save_model(request, obj, form, change)
def handle(self, *args, **options): """ Command execution. """ self.cursor = connection.cursor() self.introspection = connection.introspection self.verbosity = int(options.get('verbosity', 1)) self.interactive = options.get('interactive', True) all_models = get_models() found_missing_fields = False for model in all_models: try: options = translator.get_options_for_model(model) # options returns full-wide spectrum of localized fields but # we only to synchronize the local fields attached to the model. local_field_names = [field.name for field in model._meta.local_fields] translatable_fields = [field for field in options.localized_fieldnames if field in local_field_names] model_full_name = '%s.%s' % (model._meta.app_label, model._meta.module_name) db_table = model._meta.db_table for field_name in translatable_fields: missing_langs = list( self.get_missing_languages(field_name, db_table)) if missing_langs: found_missing_fields = True if self.verbosity: print_missing_langs( missing_langs, field_name, model_full_name) sql_sentences = self.get_sync_sql( field_name, missing_langs, model) if (not self.interactive or ask_for_confirmation(sql_sentences, model_full_name)): if self.verbosity: print 'Executing SQL...', for sentence in sql_sentences: self.cursor.execute(sentence) if self.verbosity: print 'Done' else: print 'SQL not executed' except NotRegistered: pass transaction.commit_unless_managed() if not found_missing_fields and self.verbosity: print 'No new translatable fields detected'
def _patch_inline_panel(self, panel): # get the model relation through the panel relation_name which is the # inline model related_name relation = getattr(self.patched_model, panel.relation_name) try: related_model = relation.rel.related_model except AttributeError: # Django 1.8 related_model = relation.related.related_model # If the related model is not registered for translation there is nothing # for us to do try: translator.get_options_for_model(related_model) except NotRegistered: pass else: related_model.panels = self._patch_panels(getattr(related_model, 'panels', []), related_model) # The original panel is returned as only the related_model panels need to be # patched, leaving the original untouched return panel
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 _patch_other_models(self, model): if hasattr(model, 'edit_handler'): edit_handler = model.edit_handler for tab in edit_handler: tab.children = self._patch_panels(tab.children) elif hasattr(model, 'panels'): model.panels = self._patch_panels(model.panels) else: panels = extract_panel_definitions_from_model_class(model) translation_registered_fields = translator.get_options_for_model(model).fields panels = filter(lambda field: field.field_name not in translation_registered_fields, panels) edit_handler = ObjectList(panels) SNIPPET_EDIT_HANDLERS[model] = edit_handler.bind_to_model(model)
def __init__(self, *args, **kwargs): super(TranslationMixin, self).__init__(*args, **kwargs) TranslationMixin._translation_options = translator.get_options_for_model(self.__class__) if self.__class__._translated: return # CONSTRUCT TEMPORARY EDIT HANDLER if issubclass(self.__class__, Page): edit_handler_class = get_page_edit_handler(self.__class__) else: edit_handler_class = get_snippet_edit_handler(self.__class__) TranslationMixin._wgform_class = edit_handler_class.get_form_class(self.__class__) defined_tabs = TranslationMixin._fetch_defined_tabs(self.__class__) for tab_name, tab in defined_tabs: patched_tab = [] for panel in tab: trtab = TranslationMixin._patch_panel(self, panel) if trtab: for x in trtab: patched_tab.append(x) setattr(self.__class__, tab_name, patched_tab) # DELETE TEMPORARY EDIT HANDLER IN ORDER TO LET WAGTAIL RECONSTRUCT # NEW EDIT HANDLER BASED ON NEW TRANSLATION PANELS if issubclass(self.__class__, Page): if self.__class__ in PAGE_EDIT_HANDLERS: del PAGE_EDIT_HANDLERS[self.__class__] edit_handler_class = get_page_edit_handler(self.__class__) else: if self.__class__ in SNIPPET_EDIT_HANDLERS: del SNIPPET_EDIT_HANDLERS[self.__class__] edit_handler_class = get_snippet_edit_handler(self.__class__) form = edit_handler_class.get_form_class(self.__class__) for fname, f in form.base_fields.items(): # set field required on formset level if original field is required as well if fname in self._required_fields: f.required = True if fname in TranslationMixin._translation_options.fields and TranslationMixin._is_orig_required(fname): f.required = False self.__class__._translated = True
def _patch_inlinepanel(cls, instance, panel): inline_panels = getattr(instance.__class__, panel.relation_name).related.model.panels try: inline_model_tr_fields = translator.get_options_for_model( getattr(instance.__class__, panel.relation_name).related.model ).fields except NotRegistered: return None translated_inline = [] for inlinepanel in inline_panels: for item in cls._patch_fieldpanel(inlinepanel, inline_model_tr_fields): translated_inline.append(item) getattr(instance.__class__, panel.relation_name).related.model.panels = translated_inline
def get_models(self, app): for mdname in dir(app.models): if mdname[0] == '_': continue md = getattr(app.models, mdname) try: assert issubclass(md, models.Model) except (AssertionError, TypeError): continue try: opts = translator.get_options_for_model(md) except NotRegistered: continue else: yield (md, opts)
def translated_fields(model): """Given a model, returns a list of translated field names for it. The returned list excludes the extra field created for the default language. """ options = translator.get_options_for_model(model) fields = [f.name for l in options.fields.values() for f in l] for i, f in enumerate(fields): if f.endswith(settings.MODELTRANSLATION_DEFAULT_LANGUAGE): del fields[i] return fields
def _patch_page_models(self, model): # PANEL PATCHING # Check if the model has a custom edit handler if hasattr(model, 'edit_handler'): tabs = model.edit_handler.children for tab in tabs.children: tab.children = self._patch_panels(tab.children) else: # If the page doesn't have an edit_handler we patch the panels that # wagtail uses by default if hasattr(model, 'content_panels'): model.content_panels = self._patch_panels(model.content_panels) if hasattr(model, 'promote_panels'): model.promote_panels = self._patch_panels(model.promote_panels) if hasattr(model, 'settings_panels'): model.settings_panels = self._patch_panels(model.settings_panels) # Clear the edit handler cached value, if it exists, so wagtail reconstructs # the edit_handler based on the patched panels model.get_edit_handler.cache_clear() # SEARCH FIELDS PATCHING translation_registered_fields = translator.get_options_for_model(model).fields for field in model.search_fields: # Check if the field is a SearchField and if it is one of the fields registered for translation if field.__class__ is SearchField and field.field_name in translation_registered_fields: # If it is we create a clone of the original SearchField to keep all the defined options # and replace its name by the translated one for language in mt_settings.AVAILABLE_LANGUAGES: translated_field = copy.deepcopy(field) translated_field.field_name = build_localized_fieldname(field.field_name, language) model.search_fields = list(model.search_fields) + [translated_field] # OVERRIDE PAGE METHODS model.move = _new_move model.set_url_path = _new_set_url_path model.route = _new_route model.get_site_root_paths = _new_get_site_root_paths model.relative_url = _new_relative_url model.url = _new_url _patch_clean(model)
def append_fallback(model, fields): """ If translated field is encountered, add also all its fallback fields. Returns tuple: (set_of_new_fields_to_use, set_of_translated_field_names) """ fields = set(fields) trans = set() from modeltranslation.translator import translator opts = translator.get_options_for_model(model) for key, _ in opts.fields.items(): if key in fields: langs = resolution_order(get_language(), getattr(model, key).fallback_languages) fields = fields.union(build_localized_fieldname(key, lang) for lang in langs) fields.remove(key) trans.add(key) return fields, trans