def __new__(cls, name, bases, attrs): ### START - Build translation model # At first we build translation model so we can add it to attrs # Purpose is to not call 'add_to_class' after model is registered # We have to copy attributes because they change during creation of a model trans_attrs = attrs.copy() # Make a copy of Meta, so changes in it when creating a translation model does not affect # creation of multilingual model if attrs.has_key('Meta'): trans_attrs['Meta'] = classobj.__new__(classobj, 'Meta', (attrs['Meta'],), attrs['Meta'].__dict__.copy()) translation_name = name + "Translation" trans_attrs['multilingual_model_name'] = name c_trans_model = TranslationModelBase(translation_name, (TranslationModel, ), trans_attrs) ### END - Build translation model ### And some changes before we build multilingual model meta = attrs.get('Meta', None) abstract = getattr(meta, 'abstract', False) # Add translation model to attrs attrs['translation_model'] = c_trans_model if not abstract: # Add translation relations for language_code in [None] + get_all(): field = TranslationRelation(c_trans_model, base_name=TRANSLATION_FIELD_NAME, language_code=language_code) attrs[field.name] = field # Add proxies for translated fields into attrs for field in (c_trans_model._meta.fields + c_trans_model._meta.many_to_many): if field.name in ('id', 'language_code', 'master'): continue for language_code in get_all(): proxy = TranslationProxyField(field.name, language_code) attrs[proxy.name] = proxy proxy = TranslationProxyField(field.name, None) attrs[proxy.name] = proxy proxy = TranslationProxyField(field.name, None, fallback=True) attrs[proxy.name] = proxy # Handle manager if not 'objects' in attrs: # If there is no manager, set MultilingualManager as manager attrs['objects'] = MultilingualManager() elif not isinstance(attrs['objects'], MultilingualManager): # Make sure that if the class specifies objects then it is a subclass of our Manager. # Don't check other managers since someone might want to have a non-multilingual manager, but assigning # a non-multilingual manager to objects would be a common mistake. raise ValueError("Model %s specifies translations, so its 'objects' manager must be a subclass of "\ "multilingual.Manager." % name) # And now just create multilingual model return super(MultilingualModelBase, cls).__new__(cls, name, bases, attrs)
def add_select_related(self, fields): """ Sets up the select_related data structure so that we only select certain related models (as opposed to all models, when self.select_related=True). """ new_fields = [] opts = self.model._meta # There is not actually any useful code, all this is to handle deprecated arguments. for field_name in fields: if field_name.startswith('translations'): new_name = None if field_name == 'translations': new_name = '%s_%s' % (TRANSLATION_FIELD_NAME, sanitize_language_code(get_active())) elif '_' in field_name: dummy, language_code = field_name.rsplit('_', 1) if language_code in get_all(): new_name = '%s_%s' % (TRANSLATION_FIELD_NAME, sanitize_language_code(language_code)) if new_name: msg = "Using '%s' in select_related is deprecated, use '%s' or '%s' instead." warnings.warn(msg % (field_name, TRANSLATION_FIELD_NAME, new_name), DeprecationWarning) new_fields.append(TRANSLATION_FIELD_NAME) new_fields.append(new_name) continue # In all other cases use the old name new_fields.append(field_name) new_fields = set(new_fields) return super(MultilingualQuery, self).add_select_related(new_fields)
def add_select_related(self, fields): """ If in fields is related_field for translations, will be replaced by fields in proper languages. """ new_fields = [] extra_select = {} opts = self.model._meta trans_opts = opts.translation_model._meta # TODO: fix this #related_name = trans_opts.related_name related_name = 'translations' translation_fields = [f.name for f in trans_opts.fields if f.name not in ('master', 'language_code')] for field in fields: # usual select_related if not field.startswith(related_name): new_fields.append(field) continue # get language if field == related_name: language_code = get_active() else: field_and_lang = field.rsplit('_', 1) # Coincidental field name might occur if language_code is not correct, do not do anything as # select_related does not raise errors if used with incorrect fields if len(field_and_lang) != 2 or field_and_lang[1] not in get_all(): new_fields.append(field) continue field, language_code = field_and_lang # This is main code of this method, build extra_select that might be used by fill_translation_cache for trans_field in translation_fields: extra_select[get_field_alias(trans_field, language_code)] = '%s.%s' % ( get_table_alias(trans_opts.db_table, language_code), connection.ops.quote_name(trans_field) ) # XXX: this is not safe if translation model has no fields, can it happen?? # join translatable model (original) table if not joined yet alias = self.get_initial_alias() # join translation table if not joined yet translation_fields.remove(trans_opts.pk.name) self.setup_joins( ['%s_%s' % (translation_fields[0], language_code)], # any translated_field opts, alias, True, can_reuse = set([alias]) ) if extra_select: self.add_extra(extra_select, None, None, None, None, None) super(MultilingualQuery, self).add_select_related(new_fields)
def multilingual(request): """ Returns context variables containing information about available languages. """ codes = sorted(get_all()) return {'ML_LANGUAGE': get_active(), # DEPRECATED context #TODO: LANGUAGE_CODES, LANGUAGE_CODES_AND_NAMES available in i18n context processor 'LANGUAGE_CODES': codes, 'LANGUAGE_CODES_AND_NAMES': get_dict(), 'DEFAULT_LANGUAGE_CODE': get_settings_default()}
def __new__(cls, name, bases, attrs): ### START - Build translation model # At first we build translation model so we can add it to attrs # Purpose is to not call 'add_to_class' after model is registered # We have to copy attributes because they change during creation of a model trans_attrs = attrs.copy() # Make a copy of Meta, so changes in it when creating a translation model does not affect # creation of multilingual model if attrs.has_key("Meta"): trans_attrs["Meta"] = classobj.__new__(classobj, "Meta", (attrs["Meta"],), attrs["Meta"].__dict__.copy()) translation_name = name + "Translation" trans_attrs["multilingual_model_name"] = name c_trans_model = TranslationModelBase(translation_name, (TranslationModel,), trans_attrs) ### END - Build translation model ### And some changes before we build multilingual model # Add translation model to attrs attrs["translation_model"] = c_trans_model # Add proxies for translated fields into attrs for field in c_trans_model._meta.fields: if field.name in ("id", "language_code", "master"): continue for language_code in get_all(): proxy = TranslationProxyField(field.name, language_code) attrs[proxy.name] = proxy proxy = TranslationProxyField(field.name, None) attrs[proxy.name] = proxy proxy = TranslationProxyField(field.name, None, fallback=True) attrs[proxy.name] = proxy # Handle manager if not "objects" in attrs: # If there is no manager, set MultilingualManager as manager attrs["objects"] = MultilingualManager() elif not isinstance(attrs["objects"], MultilingualManager): # Make sure that if the class specifies objects then it is a subclass of our Manager. # Don't check other managers since someone might want to have a non-multilingual manager, but assigning # a non-multilingual manager to objects would be a common mistake. raise ValueError( "Model %s specifies translations, so its 'objects' manager must be a subclass of " "multilingual.Manager." % name ) # And now just create multilingual model return super(MultilingualModelBase, cls).__new__(cls, name, bases, attrs)
def multilingual(request): """ Returns context variables containing information about available languages. """ codes = sorted(get_all()) return { "ML_LANGUAGE": get_active(), # DEPRECATED context # TODO: LANGUAGE_CODES, LANGUAGE_CODES_AND_NAMES available in i18n context processor "LANGUAGE_CODES": codes, "LANGUAGE_CODES_AND_NAMES": get_dict(), "DEFAULT_LANGUAGE_CODE": get_settings_default(), "ADMIN_MEDIA_URL": settings.ADMIN_MEDIA_PREFIX, }
def test01_basics(self): self.assertEqual(languages.get_dict(), SortedDict(self.LANGUAGES)) self.assertEqual(languages.get_all(), ['cs', 'en', 'en-us']) self.assertEqual(languages.get_settings_default(), 'cs') self.assertEqual(languages.get_active(), 'cs')
def test_get_all(self): self.assertEqual(languages.get_all(), ['cs', 'en', 'en-us', 'fr'])
def test_basics(self): self.assertEqual(languages.get_dict(), SortedDict((('cs', u'Čeština'), ('en', u'English'), ('en-us', u'American english')))) self.assertEqual(languages.get_all(), ['cs', 'en', 'en-us']) self.assertEqual(languages.get_settings_default(), 'cs') self.assertEqual(languages.get_active(), 'cs')