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 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 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 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.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, **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 get_translatable_models(): """ Get the translatable models according to django-modeltranslation !! only use to migrate from django-modeltranslation !! """ _raise_if_not_django_modeltranslation() return translator.get_registered_models()
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 autodiscover(): """ Auto-discover INSTALLED_APPS translation.py modules and fail silently when not present. This forces an import on them to register. Also import explicit modules. """ import os import sys import copy from django.conf import settings from django.utils.module_loading import module_has_submodule from modeltranslation.translator import translator from modeltranslation.settings import TRANSLATION_FILES, DEBUG if django.VERSION < (1, 7): from django.utils.importlib import import_module mods = [(app, import_module(app)) for app in settings.INSTALLED_APPS] else: from importlib import import_module from django.apps import apps mods = [(app_config.name, app_config.module) for app_config in apps.get_app_configs()] for (app, mod) in mods: # Attempt to import the app's translation module. module = '%s.translation' % app before_import_registry = copy.copy(translator._registry) try: import_module(module) except: # Reset the model registry to the state before the last import as # this import will have to reoccur on the next request and this # could raise NotRegistered and AlreadyRegistered exceptions translator._registry = before_import_registry # Decide whether to bubble up this error. If the app just # doesn't have an translation module, we can ignore the error # attempting to import it, otherwise we want it to bubble up. if module_has_submodule(mod, 'translation'): raise for module in TRANSLATION_FILES: import_module(module) # In debug mode, print a list of registered models and pid to stdout. # Note: Differing model order is fine, we don't rely on a particular # order, as far as base classes are registered before subclasses. if DEBUG: try: if sys.argv[1] in ('runserver', 'runserver_plus'): models = translator.get_registered_models() names = ', '.join(m.__name__ for m in models) print('modeltranslation: Registered %d models for translation' ' (%s) [pid: %d].' % (len(models), names, os.getpid())) except IndexError: pass
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 patch_wagtail_models(): # After all models being registered the Page or BaseSetting subclasses and snippets are patched registered_models = translator.get_registered_models() # We need to sort the models to ensure that subclasses of a model are registered first, # or else if the panels are inherited all the changes on the subclass would be # reflected in the superclass registered_models.sort(key=compare_class_tree_depth) for model_class in registered_models: WagtailTranslator(model_class)
def patch_wagtail_models(): # After all models being registered the Page or BaseSetting subclasses and snippets are patched registered_models = translator.get_registered_models() # We need to sort the models to ensure that subclasses of a model are registered first, # or else if the panels are inherited all the changes on the subclass would be # reflected in the superclass registered_models.sort(key=compare_class_tree_depth) for model_class in registered_models: if issubclass(model_class, Page) or model_class in get_snippet_models() or issubclass(model_class, BaseSetting): WagtailTranslator(model_class)
def autodiscover(): """ Auto-discover INSTALLED_APPS translation.py modules and fail silently when not present. This forces an import on them to register. Also import explicit modules. """ import os import sys import copy from django.utils.module_loading import module_has_submodule from modeltranslation.translator import translator from modeltranslation.settings import TRANSLATION_FILES, DEBUG from importlib import import_module from django.apps import apps mods = [(app_config.name, app_config.module) for app_config in apps.get_app_configs()] for (app, mod) in mods: # Attempt to import the app's translation module. module = '%s.translation' % app before_import_registry = copy.copy(translator._registry) try: import_module(module) except: # Reset the model registry to the state before the last import as # this import will have to reoccur on the next request and this # could raise NotRegistered and AlreadyRegistered exceptions translator._registry = before_import_registry # Decide whether to bubble up this error. If the app just # doesn't have an translation module, we can ignore the error # attempting to import it, otherwise we want it to bubble up. if module_has_submodule(mod, 'translation'): raise for module in TRANSLATION_FILES: import_module(module) # In debug mode, print a list of registered models and pid to stdout. # Note: Differing model order is fine, we don't rely on a particular # order, as far as base classes are registered before subclasses. if DEBUG: try: if sys.argv[1] in ('runserver', 'runserver_plus'): models = translator.get_registered_models() names = ', '.join(m.__name__ for m in models) print('modeltranslation: Registered %d models for translation' ' (%s) [pid: %d].' % (len(models), names, os.getpid())) except IndexError: pass
def inner(klass): class_name = klass.__name__ options_class_name = class_name + "TranslationOptions" options_class = type(options_class_name, (TranslationOptions, ), {"fields": fields}) if klass not in translator.get_registered_models( ): # Workaround for AlreadyRegistered bug translator.register(klass, options_class) return klass
def handle(self, *args, **options): if not hasattr(settings, 'MODELTRANSLATION_LOCALE_PATH'): raise CommandError( "Settings has no attribute 'MODELTRANSLATION_LOCALE_PATH'") if not hasattr(settings, 'MODELTRANSLATION_PO_FILE'): filename_po = "modeltranslation.po" else: filename_po = settings.MODELTRANSLATION_PO_FILE if not filename_po.endswith(".po"): filename_po += '.po' locale_path = settings.MODELTRANSLATION_LOCALE_PATH if not isdir(locale_path): mkdir(locale_path) for lang in [l[0] for l in list(settings.LANGUAGES)]: catalog = Catalog(locale=lang) for model in translator.get_registered_models(): opts = translator.get_options_for_model(model) for field in opts.get_field_names(): if field != "url_path": tr_field = "%s_%s" % (field, lang) en_field = "%s_%s" % (field, "en") for item in model.objects.all(): msgid = "%s.%s.%s" % (item._meta, item.pk, field) msgstr = "%s" % getattr(item, tr_field) enval = getattr(item, en_field) if enval is not None: enstr = "%s" % enval catalog.add(id=enstr, string=msgstr, auto_comments=[ msgid, ]) # write catalog to file lang_path = join(locale_path, lang) if not isdir(lang_path): mkdir(lang_path) mkdir(join(lang_path, "LC_MESSAGES")) f = open(join(lang_path, "LC_MESSAGES", filename_po), "wb") write_po(f, catalog) f.close()
def _update_obj_index_iter(self, obj): klass = obj.__class__ curr_lang = translation.get_language() try: if klass in translator.get_registered_models(): # make sure doc in default language has highest priority langs = list(zip(*settings.LANGUAGES)[0]) langs.remove(settings.LANGUAGE_CODE) langs.append(settings.LANGUAGE_CODE) else: langs = [curr_lang] for lang in langs: translation.activate(lang) for ret in super(MultiligualSearchEngine, self)._update_obj_index_iter(obj, lang): yield ret finally: translation.activate(curr_lang)
def handle_noargs(self, **options): """ Command execution. """ self.cursor = connection.cursor() self.introspection = connection.introspection self.interactive = options['interactive'] found_missing_fields = False models = translator.get_registered_models(abstract=False) for model in models: db_table = model._meta.db_table if django.VERSION < (1, 8): model_name = model._meta.module_name else: model_name = model._meta.model_name model_full_name = '%s.%s' % (model._meta.app_label, model_name) opts = translator.get_options_for_model(model) for field_name, fields in opts.local_fields.items(): # Take `db_column` attribute into account field = list(fields)[0] column_name = field.db_column if field.db_column else field_name missing_langs = list( self.get_missing_languages(column_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, 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 django.VERSION < (1, 6): transaction.commit_unless_managed() if not found_missing_fields: print('No new translatable fields detected')
def handle(self, *args, **options): """ Command execution. """ self.cursor = connection.cursor() self.introspection = connection.introspection self.interactive = options['interactive'] found_missing_fields = False models = translator.get_registered_models(abstract=False) for model in models: db_table = model._meta.db_table model_name = model._meta.model_name model_full_name = '%s.%s' % (model._meta.app_label, model_name) opts = translator.get_options_for_model(model) for field_name, fields in opts.local_fields.items(): # Take `db_column` attribute into account try: field = list(fields)[0] except IndexError: # Ignore IndexError for ProxyModel # maybe there is better way to handle this continue column_name = field.db_column if field.db_column else field_name missing_langs = list( self.get_missing_languages(column_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, 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_missing_fields: print('No new translatable fields detected')
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] 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, 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: ""}) model._default_manager.filter(q).rewrite(False).update( **{def_lang_fieldname: F(field_name)} )
def handle_noargs(self, **options): """ Command execution. """ self.cursor = connection.cursor() self.introspection = connection.introspection self.interactive = options['interactive'] found_missing_fields = False models = translator.get_registered_models(abstract=False) for model in models: db_table = model._meta.db_table if django.VERSION < (1, 8): model_name = model._meta.module_name else: model_name = model._meta.model_name model_full_name = '%s.%s' % (model._meta.app_label, model_name) opts = translator.get_options_for_model(model) for field_name, fields in opts.local_fields.items(): # Take `db_column` attribute into account field = list(fields)[0] column_name = field.db_column if field.db_column else field_name missing_langs = list(self.get_missing_languages(column_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, 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 django.VERSION < (1, 6): transaction.commit_unless_managed() if not found_missing_fields: print('No new translatable fields detected')
def handle_noargs(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: ""}) model._default_manager.filter(q).rewrite(False).update( **{def_lang_fieldname: F(field_name)})
def handle(self, *args, **options): """Handle the save_trans command.""" filename_po = load_translation_settings(settings) locale_path = settings.MODELTRANSLATION_LOCALE_PATH if not isdir(locale_path): mkdir(locale_path) for lang in [l[0] for l in list(settings.LANGUAGES)]: catalog = Catalog(locale=lang) for model in translator.get_registered_models(): opts = translator.get_options_for_model(model) for field in opts.get_field_names(): tr_field = "%s_%s" % (field, lang) en_field = "%s_%s" % (field, "en") for item in model.objects.all(): msgid = "%s.%s.%s" % (item._meta, item.pk, field) msgstr = "%s" % getattr(item, tr_field) enval = getattr(item, en_field) if enval is not None and field not in [ "slug", "url_path" ]: enstr = json.dumps(enval.stream_data) if hasattr( enval, "stream_data") else "%s" % enval catalog.add(id=enstr, string=msgstr, auto_comments=[ msgid, ]) # write catalog to file lang_path = join(locale_path, lang) if not isdir(lang_path): mkdir(lang_path) mkdir(join(lang_path, "LC_MESSAGES")) po_file = open(join(lang_path, "LC_MESSAGES", filename_po), "wb") write_po(po_file, catalog) po_file.close()
def translated_field_list(*args): """ Generates a dictionary of translatable model fields associated with the model. Models and fields can be specified in `args`, thus allowing for export even before fields are set up as translatable. If none are provided, then modeltranslation's `translator` instance is queried for the list of *all* models and fields that are registered for translation. Args: *args: optional list of fields by dotted string path Returns: a defaultdict mapping translation models to translated field names """ class_and_field = OrderedDict() if not args: from modeltranslation.translator import translator for model_class in translator.get_registered_models(abstract=False): class_and_field[model_class] = translator.get_options_for_model( model_class).get_field_names() return class_and_field for dotted_path in args: module_name, class_name, field_name = dotted_path.rsplit(".", 2) module = importlib.import_module(module_name) try: model_class = getattr(module, class_name) except AttributeError: model_class = apps.get_model(module_name, class_name) try: class_and_field[model_class].append(field_name) except KeyError: class_and_field[model_class] = [field_name] return class_and_field
def handle(self, *args, **options): """ Command execution. """ self.cursor = connection.cursor() self.introspection = connection.introspection self.interactive = options['interactive'] found_missing_fields = False models = translator.get_registered_models(abstract=False) for model in models: db_table = model._meta.db_table model_name = model._meta.model_name model_full_name = '%s.%s' % (model._meta.app_label, model_name) opts = translator.get_options_for_model(model) for field_name, fields in opts.local_fields.items(): # Take `db_column` attribute into account try: field = list(fields)[0] except IndexError: # Ignore IndexError for ProxyModel # maybe there is better way to handle this continue column_name = field.db_column if field.db_column else field_name missing_langs = list(self.get_missing_languages(column_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, 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_missing_fields: print('No new translatable fields detected')
def handle(self, *args, **options): """Handle the save_trans command.""" filename_po = load_translation_settings(settings) locale_path = settings.MODELTRANSLATION_LOCALE_PATH if not isdir(locale_path): mkdir(locale_path) for lang in [lang_tup[0] for lang_tup in list(settings.LANGUAGES)]: word_count = 0 lang_path = join(locale_path, lang) if not isdir(lang_path): mkdir(lang_path) mkdir(join(lang_path, "LC_MESSAGES")) po_filepath = join(lang_path, "LC_MESSAGES", filename_po) existing_ids = [] existing_trans = {} if exists(po_filepath): print(po_filepath) po_file = open(po_filepath, "r", encoding="utf-8") catalog = read_po(po_file) po_file.close() for message in catalog: existing_ids.append(message.id) for auto_comment in message.auto_comments: existing_trans[auto_comment] = message.id else: catalog = Catalog(locale=lang) for model in translator.get_registered_models(): if model not in EXCLUDE_MODELS: opts = translator.get_options_for_model(model) for field in opts.get_field_names(): tr_field = "%s_%s" % (field, lang) en_field = "%s_%s" % (field, "en") for item in model.objects.all(): if hasattr(item, "specific") and isinstance(item.specific, EXCLUDE_MODELS): continue msgid = "%s.%s.%s" % (item._meta, item.pk, field) msgval = getattr(item, tr_field) enval = getattr(item, en_field) if isinstance(msgval, StreamValue): msgstr = json.dumps(list(msgval.raw_data)) else: msgstr = "%s" % msgval if enval is not None and field not in ["slug", "url_path"]: if isinstance(enval, StreamValue): enstr = json.dumps(list(enval.raw_data)) else: enstr = "%s" % enval # We already have a translation, just add the new comment to pick it up if enstr in existing_ids: catalog.add(id=enstr, string=msgstr, auto_comments=[msgid, ]) # We don't have an exact translation, but we've translated the page before elif msgid in existing_trans.keys(): # If it's JSON, the dumped strings might not match, but the objs can if isinstance(enval, StreamValue): new_json = json.loads(enstr) old_json = json.loads(existing_trans[msgid]) # If it doesn't match, delete the old and re-add with a blank translation so the vendor knows it needs re-translation. If it does match, do nothing if new_json != old_json: catalog.delete(id=existing_trans[msgid]) catalog.add(id=enstr, string="", auto_comments=[msgid, ]) word_count += len(enstr.split()) # If it's not JSON, just add it. We can't delete because can't guarantee it's not reused later else: catalog.add(id=enstr, string=msgstr, auto_comments=[msgid, ]) word_count += len(enstr.split()) # If we don't have a translation, and it's not in a previously translated page, it's brand new else: catalog.add(id=enstr, string=msgstr, auto_comments=[msgid, ]) word_count += len(enstr.split()) # write catalog to file po_file = open(po_filepath, "wb") write_po(po_file, catalog, width=None) po_file.close() # write copy to default_storage stream_str = io.BytesIO() write_po(stream_str, catalog, width=None) output_path = join("po_files", lang, filename_po) output_dir = dirname(output_path) if not isdir(output_dir): makedirs(output_dir) if default_storage.exists(output_path): default_storage.delete(output_path) default_storage.save(output_path, ContentFile(stream_str.getvalue())) print("New {} word count: {}".format(lang, word_count))
def handle_noargs(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)})
class TranslationAdmin(TranslationAdminMixin, O_TranslationAdmin): TRANSLATION_REGISTERED_MODELS = set( translator.get_registered_models(abstract=False)) def get_url_namespace(self, name, absolute=True): meta = self.model._meta namespace = f'{meta.app_label}_{meta.model_name}_{name}' return f'admin:{namespace}' if absolute else namespace def get_additional_addlinks(self, request): url = reverse(self.get_url_namespace( 'toggle_edit_all_language')) + f'?next={request.get_full_path()}' label = ugettext( 'hide all language') if self._go__show_all_language_in_form( ) else ugettext('show all language') return [{'url': url, 'label': label}] def change_view(self, request, object_id, form_url='', extra_context=None): extra_context = extra_context or {} extra_context['additional_addlinks'] = extra_context.get( 'additional_addlinks') or [] # extra_context['additional_addlinks'].extend(self.get_additional_addlinks(request)) return super().change_view(request, object_id, form_url, extra_context=extra_context) def add_view(self, request, form_url='', extra_context=None): extra_context = extra_context or {} extra_context['additional_addlinks'] = extra_context.get( 'additional_addlinks') or [] # extra_context['additional_addlinks'].extend(self.get_additional_addlinks(request)) return super().add_view(request, form_url, extra_context=extra_context) def get_urls(self): return [ path('toggle-edit-all-language/', self.admin_site.admin_view(self.toggle_edit_all_language), name=self.get_url_namespace('toggle_edit_all_language', False)), ] + super().get_urls() def toggle_edit_all_language(self, request): request.session[ self. SHOW_ALL_LANGUAGE_TOGGLE_SESSION_NAME] = not request.session.get( self.SHOW_ALL_LANGUAGE_TOGGLE_SESSION_NAME, False) return redirect(request.GET.get('next')) def save_model(self, request, obj, form, change): # To trigger translate super().save_model(request, obj, form, change) TranslatedModelSerializerMixin.trigger_field_translation(obj) def save_formset(self, request, form, formset, change): # To trigger translate for inline models instances = formset.save() if instances and formset.model in self.TRANSLATION_REGISTERED_MODELS: TranslatedModelSerializerMixin.trigger_field_translation_in_bulk( formset.model, instances) def get_search_fields(self, request): # Ex. 'name' is translatable - add 'name_fr', 'name_es', etc concated_search = ( list(self.search_fields) + TranslatedModelSerializerMixin._get_translated_searchfields_list( self.model, self.search_fields)) return concated_search
def handle(self, *args, **options): """Handle the save_trans command.""" filename_po = load_translation_settings(settings) locale_path = settings.MODELTRANSLATION_LOCALE_PATH if not isdir(locale_path): mkdir(locale_path) for lang in [l[0] for l in list(settings.LANGUAGES)]: word_count = 0 lang_path = join(locale_path, lang) if not isdir(lang_path): mkdir(lang_path) mkdir(join(lang_path, "LC_MESSAGES")) po_filepath = join(lang_path, "LC_MESSAGES", filename_po) existing_ids = [] existing_trans = {} if exists(po_filepath): po_file = open(po_filepath, "r") catalog = read_po(po_file) po_file.close() for message in catalog: existing_ids.append(message.id) for auto_comment in message.auto_comments: existing_trans[auto_comment] = message.id else: catalog = Catalog(locale=lang) for model in translator.get_registered_models(): opts = translator.get_options_for_model(model) for field in opts.get_field_names(): tr_field = "%s_%s" % (field, lang) en_field = "%s_%s" % (field, "en") for item in model.objects.all(): msgid = "%s.%s.%s" % (item._meta, item.pk, field) msgstr = "%s" % getattr(item, tr_field) enval = getattr(item, en_field) if enval is not None and field not in [ "slug", "url_path" ]: enstr = json.dumps(enval.stream_data) if hasattr( enval, "stream_data") else "%s" % enval # We already have a translation, just add the new comment to pick it up if enstr in existing_ids: catalog.add(id=enstr, string=msgstr, auto_comments=[ msgid, ]) # We don't have an exact translation, but we've translated the page before elif msgid in existing_trans.keys(): # If it's JSON, the dumped strings might not match, but the objs can if hasattr(enval, "stream_data"): new_json = json.loads(enstr) old_json = json.loads( existing_trans[msgid]) # If it doesn't match, delete the old and readd. If it does match, do nothing if new_json != old_json: catalog.delete( id=existing_trans[msgid]) catalog.add(id=enstr, string=msgstr, auto_comments=[ msgid, ]) word_count += len(enstr.split()) # If it's not JSON, just add it. We can't delete because can't guarantee it's not reused later else: catalog.add(id=enstr, string=msgstr, auto_comments=[ msgid, ]) word_count += len(enstr.split()) # If we don't have a translation, and it's not in a previously translated page, it's brand new else: catalog.add(id=enstr, string=msgstr, auto_comments=[ msgid, ]) word_count += len(enstr.split()) # write catalog to file po_file = open(po_filepath, "wb") write_po(po_file, catalog, width=None) po_file.close() print("New {} word count: {}".format(lang, word_count))
def get_translatable_models(cls): # return all models excluding proxy- and not managed models return [ m for m in translator.get_registered_models(abstract=False) if not m._meta.proxy and m._meta.managed ]
def apply_po_file(self, po: polib.POFile, fix_empty_db_strings=False): string_entries = {} model_entries = {} for entry in po: for kind, identity in entry.occurrences: if kind == 'strings': string_entries[entry.msgid] = (entry.msgid, entry.msgstr) else: model_entries['{}:{}'.format(kind, identity)] = (entry.msgid, entry.msgstr) lang = po.metadata['Language'] strings_updated = 0 for key, val in string_entries.items(): for obj in StringTranslation.objects.filter(key=key): localized_fieldname = build_localized_fieldname( 'translation', lang) msgid, msgstr = string_entries[key] if not msgstr: if fix_empty_db_strings: msgstr = msgid else: continue if getattr(obj, localized_fieldname) != msgstr: setattr(obj, localized_fieldname, msgstr) strings_updated += 1 obj.save() models = translator.get_registered_models(abstract=False) model_entries_updated = 0 for model in models: 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(): model_updated = False for field_name, field_name_local in fields_to_copy: key = '{}:{}:{}'.format(get_model_ct(model), field_name, obj.id) if key in model_entries: localized_fieldname = build_localized_fieldname( field_name, lang) msgid, msgstr = model_entries[key] if not msgstr: if fix_empty_db_strings: msgstr = msgid else: continue if getattr(obj, localized_fieldname) != msgstr: setattr(obj, localized_fieldname, msgstr) model_updated = True model_entries_updated += 1 if model_updated: obj.save() return { 'lang': lang, 'strings_updated': strings_updated, 'model_entries_updated': model_entries_updated, }