Ticket #11688: 11688-verbose_name_plural_evolution-1.diff
File 11688-verbose_name_plural_evolution-1.diff, 77.9 KB (added by , 13 years ago) |
---|
-
django/contrib/admin/actions.py
diff --git a/django/contrib/admin/actions.py b/django/contrib/admin/actions.py
a b 20 20 21 21 Next, it delets all selected objects and redirects back to the change list. 22 22 """ 23 opts = modeladmin.model._meta 23 model = modeladmin.model 24 opts = model._meta 24 25 app_label = opts.app_label 25 26 26 27 # Check that the user has delete permission for the actual model 27 28 if not modeladmin.has_delete_permission(request): 28 29 raise PermissionDenied 29 30 30 using = router.db_for_write(model admin.model)31 using = router.db_for_write(model) 31 32 32 33 # Populate deletable_objects, a data structure of all related objects that 33 34 # will also be deleted. … … 46 47 modeladmin.log_deletion(request, obj, obj_display) 47 48 queryset.delete() 48 49 modeladmin.message_user(request, _("Successfully deleted %(count)d %(items)s.") % { 49 "count": n, "items": model_ngettext(model admin.opts, n)50 "count": n, "items": model_ngettext(model, n) 50 51 }) 51 52 # Return None to display the change list page again. 52 53 return None 53 54 54 if len(queryset) == 1: 55 objects_name = force_unicode(opts.verbose_name) 56 else: 57 objects_name = force_unicode(opts.verbose_name_plural) 55 objects_name = force_unicode(model.get_verbose_name(len(queryset))) 58 56 59 57 if perms_needed or protected: 60 58 title = _("Cannot delete %(name)s") % {"name": objects_name} -
django/contrib/admin/filters.py
diff --git a/django/contrib/admin/filters.py b/django/contrib/admin/filters.py
a b 150 150 if hasattr(field, 'verbose_name'): 151 151 self.lookup_title = field.verbose_name 152 152 else: 153 self.lookup_title = other_model. _meta.verbose_name153 self.lookup_title = other_model.get_verbose_name() 154 154 rel_name = other_model._meta.pk.name 155 155 self.lookup_kwarg = '%s__%s__exact' % (self.field_path, rel_name) 156 156 self.lookup_kwarg_isnull = '%s__isnull' % (self.field_path) -
django/contrib/admin/models.py
diff --git a/django/contrib/admin/models.py b/django/contrib/admin/models.py
a b 2 2 from django.contrib.contenttypes.models import ContentType 3 3 from django.contrib.auth.models import User 4 4 from django.contrib.admin.util import quote 5 from django.utils.translation import ugettext_lazy as _ 5 from django.utils.translation import ugettext_lazy as _, ungettext_lazy 6 6 from django.utils.encoding import smart_unicode 7 7 from django.utils.safestring import mark_safe 8 8 … … 27 27 objects = LogEntryManager() 28 28 29 29 class Meta: 30 verbose_name = _('log entry')31 verbose_name_plural = _('log entries')32 30 db_table = 'django_admin_log' 33 31 ordering = ('-action_time',) 34 32 … … 66 64 if self.content_type and self.object_id: 67 65 return mark_safe(u"%s/%s/%s/" % (self.content_type.app_label, self.content_type.model, quote(self.object_id))) 68 66 return None 67 68 @classmethod 69 def verbose_names(cls, count=1): 70 return ungettext_lazy('log entry', 'log entries', count) -
django/contrib/admin/options.py
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
a b 609 609 """ 610 610 choices = [] + default_choices 611 611 for func, name, description in self.get_actions(request).itervalues(): 612 choice = (name, description % model_format_dict(self. opts))612 choice = (name, description % model_format_dict(self.model)) 613 613 choices.append(choice) 614 614 return choices 615 615 … … 674 674 for formset in formsets: 675 675 for added_object in formset.new_objects: 676 676 change_message.append(_('Added %(name)s "%(object)s".') 677 % {'name': force_unicode(added_object. _meta.verbose_name),677 % {'name': force_unicode(added_object.get_verbose_name()), 678 678 'object': force_unicode(added_object)}) 679 679 for changed_object, changed_fields in formset.changed_objects: 680 680 change_message.append(_('Changed %(list)s for %(name)s "%(object)s".') 681 681 % {'list': get_text_list(changed_fields, _('and')), 682 'name': force_unicode(changed_object. _meta.verbose_name),682 'name': force_unicode(changed_object.get_verbose_name()), 683 683 'object': force_unicode(changed_object)}) 684 684 for deleted_object in formset.deleted_objects: 685 685 change_message.append(_('Deleted %(name)s "%(object)s".') 686 % {'name': force_unicode(deleted_object. _meta.verbose_name),686 % {'name': force_unicode(deleted_object.get_verbose_name()), 687 687 'object': force_unicode(deleted_object)}) 688 688 change_message = ' '.join(change_message) 689 689 return change_message or _('No fields changed.') … … 769 769 opts = obj._meta 770 770 pk_value = obj._get_pk_val() 771 771 772 msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(o pts.verbose_name), 'obj': force_unicode(obj)}772 msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': force_unicode(obj.get_verbose_name()), 'obj': force_unicode(obj)} 773 773 # Here, we distinguish between different save types by checking for 774 774 # the presence of keys in request.POST. 775 775 if "_continue" in request.POST: … … 785 785 # escape() calls force_unicode. 786 786 (escape(pk_value), escapejs(obj))) 787 787 elif "_addanother" in request.POST: 788 self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(o pts.verbose_name)))788 self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(obj.get_verbose_name()))) 789 789 return HttpResponseRedirect(request.path) 790 790 else: 791 791 self.message_user(request, msg) … … 810 810 811 811 # Handle proxy models automatically created by .only() or .defer(). 812 812 # Refs #14529 813 verbose_name = o pts.verbose_name813 verbose_name = obj.get_verbose_name() 814 814 module_name = opts.module_name 815 815 if obj._deferred: 816 816 opts_ = opts.proxy_for_model._meta 817 verbose_name = opts _.verbose_name817 verbose_name = opts.proxy_for_model.get_verbose_name() 818 818 module_name = opts_.module_name 819 819 820 820 pk_value = obj._get_pk_val() … … 995 995 media = media + inline_admin_formset.media 996 996 997 997 context = { 998 'title': _('Add %s') % force_unicode( opts.verbose_name),998 'title': _('Add %s') % force_unicode(model.get_verbose_name()), 999 999 'adminform': adminForm, 1000 1000 'is_popup': "_popup" in request.REQUEST, 1001 1001 'show_delete': False, … … 1020 1020 raise PermissionDenied 1021 1021 1022 1022 if obj is None: 1023 raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_unicode( opts.verbose_name), 'key': escape(object_id)})1023 raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_unicode(model.get_verbose_name()), 'key': escape(object_id)}) 1024 1024 1025 1025 if request.method == 'POST' and "_saveasnew" in request.POST: 1026 1026 return self.add_view(request, form_url=reverse('admin:%s_%s_add' % … … 1086 1086 media = media + inline_admin_formset.media 1087 1087 1088 1088 context = { 1089 'title': _('Change %s') % force_unicode( opts.verbose_name),1089 'title': _('Change %s') % force_unicode(model.get_verbose_name()), 1090 1090 'adminform': adminForm, 1091 1091 'object_id': object_id, 1092 1092 'original': obj, … … 1105 1105 The 'change list' admin view for this model. 1106 1106 """ 1107 1107 from django.contrib.admin.views.main import ERROR_FLAG 1108 opts = self.model._meta 1108 model = self.model 1109 opts = model._meta 1109 1110 app_label = opts.app_label 1110 1111 if not self.has_change_permission(request, None): 1111 1112 raise PermissionDenied … … 1194 1195 changecount += 1 1195 1196 1196 1197 if changecount: 1197 if changecount == 1: 1198 name = force_unicode(opts.verbose_name) 1199 else: 1200 name = force_unicode(opts.verbose_name_plural) 1198 name = force_unicode(model.get_verbose_name(changecount)) 1201 1199 msg = ungettext("%(count)s %(name)s was changed successfully.", 1202 1200 "%(count)s %(name)s were changed successfully.", 1203 1201 changecount) % {'count': changecount, 1204 'name': name, 1205 'obj': force_unicode(obj)} 1202 'name': name} 1206 1203 self.message_user(request, msg) 1207 1204 1208 1205 return HttpResponseRedirect(request.get_full_path()) … … 1229 1226 'All %(total_count)s selected', cl.result_count) 1230 1227 1231 1228 context = { 1232 'module_name': force_unicode( opts.verbose_name_plural),1229 'module_name': force_unicode(model.get_verbose_name(0)), 1233 1230 'selection_note': _('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)}, 1234 1231 'selection_note_all': selection_note_all % {'total_count': cl.result_count}, 1235 1232 'title': cl.title, … … 1255 1252 @transaction.commit_on_success 1256 1253 def delete_view(self, request, object_id, extra_context=None): 1257 1254 "The 'delete' admin view for this model." 1258 opts = self.model._meta 1255 model = self.model 1256 opts = model._meta 1259 1257 app_label = opts.app_label 1260 1258 1261 1259 obj = self.get_object(request, unquote(object_id)) … … 1264 1262 raise PermissionDenied 1265 1263 1266 1264 if obj is None: 1267 raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_unicode( opts.verbose_name), 'key': escape(object_id)})1265 raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_unicode(model.get_verbose_name()), 'key': escape(object_id)}) 1268 1266 1269 using = router.db_for_write( self.model)1267 using = router.db_for_write(model) 1270 1268 1271 1269 # Populate deleted_objects, a data structure of all related objects that 1272 1270 # will also be deleted. … … 1280 1278 self.log_deletion(request, obj, obj_display) 1281 1279 self.delete_model(request, obj) 1282 1280 1283 self.message_user(request, _('The %(name)s "%(obj)s" was deleted successfully.') % {'name': force_unicode( opts.verbose_name), 'obj': force_unicode(obj_display)})1281 self.message_user(request, _('The %(name)s "%(obj)s" was deleted successfully.') % {'name': force_unicode(model.get_verbose_name()), 'obj': force_unicode(obj_display)}) 1284 1282 1285 1283 if not self.has_change_permission(request, None): 1286 1284 return HttpResponseRedirect(reverse('admin:index', … … 1289 1287 (opts.app_label, opts.module_name), 1290 1288 current_app=self.admin_site.name)) 1291 1289 1292 object_name = force_unicode( opts.verbose_name)1290 object_name = force_unicode(model.get_verbose_name()) 1293 1291 1294 1292 if perms_needed or protected: 1295 1293 title = _("Cannot delete %(name)s") % {"name": object_name} … … 1329 1327 context = { 1330 1328 'title': _('Change history: %s') % force_unicode(obj), 1331 1329 'action_list': action_list, 1332 'module_name': capfirst(force_unicode( opts.verbose_name_plural)),1330 'module_name': capfirst(force_unicode(model.get_verbose_name(0))), 1333 1331 'object': obj, 1334 1332 'app_label': app_label, 1335 1333 'opts': opts, … … 1365 1363 self.opts = self.model._meta 1366 1364 super(InlineModelAdmin, self).__init__() 1367 1365 if self.verbose_name is None: 1368 self.verbose_name = self.model. _meta.verbose_name1366 self.verbose_name = self.model.get_verbose_name() 1369 1367 if self.verbose_name_plural is None: 1370 self.verbose_name_plural = self.model. _meta.verbose_name_plural1368 self.verbose_name_plural = self.model.get_verbose_name(0) 1371 1369 1372 1370 @property 1373 1371 def media(self): -
django/contrib/admin/sites.py
diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
a b 341 341 if True in perms.values(): 342 342 info = (app_label, model._meta.module_name) 343 343 model_dict = { 344 'name': capfirst(model. _meta.verbose_name_plural),344 'name': capfirst(model.get_verbose_name(0)), 345 345 'admin_url': reverse('admin:%s_%s_changelist' % info, current_app=self.name), 346 346 'add_url': reverse('admin:%s_%s_add' % info, current_app=self.name), 347 347 'perms': perms, … … 387 387 if True in perms.values(): 388 388 info = (app_label, model._meta.module_name) 389 389 model_dict = { 390 'name': capfirst(model. _meta.verbose_name_plural),390 'name': capfirst(model.get_verbose_name(0)), 391 391 'admin_url': reverse('admin:%s_%s_changelist' % info, current_app=self.name), 392 392 'add_url': reverse('admin:%s_%s_add' % info, current_app=self.name), 393 393 'perms': perms, -
django/contrib/admin/util.py
diff --git a/django/contrib/admin/util.py b/django/contrib/admin/util.py
a b 90 90 p = '%s.%s' % (opts.app_label, 91 91 opts.get_delete_permission()) 92 92 if not user.has_perm(p): 93 perms_needed.add(o pts.verbose_name)93 perms_needed.add(obj.get_verbose_name()) 94 94 # Display a link to the admin page. 95 95 return mark_safe(u'%s: <a href="%s">%s</a>' % 96 (escape(capfirst(o pts.verbose_name)),96 (escape(capfirst(obj.get_verbose_name())), 97 97 admin_url, 98 98 escape(obj))) 99 99 else: 100 100 # Don't display link to edit, because it either has no 101 101 # admin or is edited inline. 102 return u'%s: %s' % (capfirst(o pts.verbose_name),102 return u'%s: %s' % (capfirst(obj.get_verbose_name()), 103 103 force_unicode(obj)) 104 104 105 105 to_delete = collector.nested(format_callback) … … 165 165 Return a `dict` with keys 'verbose_name' and 'verbose_name_plural', 166 166 typically for use with string formatting. 167 167 168 `obj` may be a `Model` instance, `Model` subclass, or `QuerySet` instance.168 `obj` may be a `Model` instance, `Model` subclass, or a `QuerySet` instance. 169 169 170 170 """ 171 171 if isinstance(obj, (models.Model, models.base.ModelBase)): 172 opts = obj._meta172 model = obj 173 173 elif isinstance(obj, models.query.QuerySet): 174 opts = obj.model._meta 175 else: 176 opts = obj 174 model = obj.model 177 175 return { 178 'verbose_name': force_unicode( opts.verbose_name),179 'verbose_name_plural': force_unicode( opts.verbose_name_plural)176 'verbose_name': force_unicode(model.get_verbose_name()), 177 'verbose_name_plural': force_unicode(model.get_verbose_name(0)) 180 178 } 181 179 182 180 … … 229 227 def label_for_field(name, model, model_admin=None, return_attr=False): 230 228 """ 231 229 Returns a sensible label for a field name. The name can be a callable or the 232 name of an object attribute s, as well as a genuine fields. If return_attr is230 name of an object attribute, as well as a genuine field. If return_attr is 233 231 True, the resolved attribute (which could be a callable) is also returned. 234 232 This will be None if (and only if) the name refers to a field. 235 233 """ … … 237 235 try: 238 236 field = model._meta.get_field_by_name(name)[0] 239 237 if isinstance(field, RelatedObject): 240 label = field. opts.verbose_name238 label = field.get_verbose_name() 241 239 else: 242 240 label = field.verbose_name 243 241 except models.FieldDoesNotExist: 244 242 if name == "__unicode__": 245 label = force_unicode(model. _meta.verbose_name)243 label = force_unicode(model.get_verbose_name()) 246 244 attr = unicode 247 245 elif name == "__str__": 248 label = smart_str(model. _meta.verbose_name)246 label = smart_str(model.get_verbose_name()) 249 247 attr = str 250 248 else: 251 249 if callable(name): … … 311 309 312 310 313 311 def get_model_from_relation(field): 314 if isinstance(field, models.related.RelatedObject):312 if isinstance(field, RelatedObject): 315 313 return field.model 316 314 elif getattr(field, 'rel'): # or isinstance? 317 315 return field.rel.to -
django/contrib/admin/views/main.py
diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py
a b 81 81 title = ugettext('Select %s') 82 82 else: 83 83 title = ugettext('Select %s to change') 84 self.title = title % force_unicode(self. opts.verbose_name)84 self.title = title % force_unicode(self.model.get_verbose_name()) 85 85 self.pk_attname = self.lookup_opts.pk.attname 86 86 87 87 def get_filters(self, request, use_distinct=False): -
django/contrib/auth/models.py
diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py
a b 5 5 from django.db import models 6 6 from django.db.models.manager import EmptyManager 7 7 from django.utils.encoding import smart_str 8 from django.utils.translation import ugettext_lazy as _9 8 from django.utils import timezone 9 from django.utils.translation import ugettext_lazy as _, ungettext_lazy 10 10 11 11 from django.contrib import auth 12 12 from django.contrib.auth.signals import user_logged_in … … 54 54 objects = PermissionManager() 55 55 56 56 class Meta: 57 verbose_name = _('permission')58 verbose_name_plural = _('permissions')59 57 unique_together = (('content_type', 'codename'),) 60 58 ordering = ('content_type__app_label', 'content_type__model', 'codename') 61 59 … … 69 67 return (self.codename,) + self.content_type.natural_key() 70 68 natural_key.dependencies = ['contenttypes.contenttype'] 71 69 70 @classmethod 71 def verbose_names(cls, count=1): 72 return ungettext_lazy('permission', 'permissions', count) 73 72 74 class Group(models.Model): 73 75 """Groups are a generic way of categorizing users to apply permissions, or some other label, to those users. A user can belong to any number of groups. 74 76 … … 79 81 name = models.CharField(_('name'), max_length=80, unique=True) 80 82 permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True) 81 83 82 class Meta:83 verbose_name = _('group')84 verbose_name_plural = _('groups')85 86 84 def __unicode__(self): 87 85 return self.name 88 86 87 @classmethod 88 def verbose_names(cls, count=1): 89 return ungettext_lazy('group', 'groups', count) 90 89 91 class UserManager(models.Manager): 90 92 def create_user(self, username, email=None, password=None): 91 93 """ … … 188 190 user_permissions = models.ManyToManyField(Permission, verbose_name=_('user permissions'), blank=True) 189 191 objects = UserManager() 190 192 191 class Meta:192 verbose_name = _('user')193 verbose_name_plural = _('users')194 195 193 def __unicode__(self): 196 194 return self.username 197 195 … … 337 335 raise SiteProfileNotAvailable 338 336 return self._profile_cache 339 337 338 @classmethod 339 def verbose_names(cls, count=1): 340 return ungettext_lazy('user', 'users', count) 341 340 342 341 343 class AnonymousUser(object): 342 344 id = None -
django/contrib/comments/models.py
diff --git a/django/contrib/comments/models.py b/django/contrib/comments/models.py
a b 5 5 from django.contrib.sites.models import Site 6 6 from django.db import models 7 7 from django.core import urlresolvers 8 from django.utils.translation import ugettext_lazy as _9 8 from django.utils import timezone 9 from django.utils.translation import ugettext_lazy as _, ungettext_lazy 10 10 from django.conf import settings 11 11 12 12 COMMENT_MAX_LENGTH = getattr(settings,'COMMENT_MAX_LENGTH',3000) … … 73 73 db_table = "django_comments" 74 74 ordering = ('submit_date',) 75 75 permissions = [("can_moderate", "Can moderate comments")] 76 verbose_name = _('comment')77 verbose_name_plural = _('comments')78 76 79 77 def __unicode__(self): 80 78 return "%s: %s..." % (self.name, self.comment[:50]) … … 152 150 } 153 151 return _('Posted by %(user)s at %(date)s\n\n%(comment)s\n\nhttp://%(domain)s%(url)s') % d 154 152 153 @classmethod 154 def verbose_names(cls, count=1): 155 return ungettext_lazy('comment', 'comments', count) 156 155 157 class CommentFlag(models.Model): 156 158 """ 157 159 Records a flag on a comment. This is intentionally flexible; right now, a … … 178 180 class Meta: 179 181 db_table = 'django_comment_flags' 180 182 unique_together = [('user', 'comment', 'flag')] 181 verbose_name = _('comment flag')182 verbose_name_plural = _('comment flags')183 183 184 184 def __unicode__(self): 185 185 return "%s flag of comment ID %s by %s" % \ … … 189 189 if self.flag_date is None: 190 190 self.flag_date = timezone.now() 191 191 super(CommentFlag, self).save(*args, **kwargs) 192 193 @classmethod 194 def verbose_names(cls, count=1): 195 return ungettext_lazy('comment flag', 'comment flags', count) -
django/contrib/contenttypes/models.py
diff --git a/django/contrib/contenttypes/models.py b/django/contrib/contenttypes/models.py
a b 1 1 from django.db import models 2 from django.utils.translation import ugettext_lazy as _ 2 from django.utils.translation import ugettext_lazy as _, ungettext_lazy 3 3 from django.utils.encoding import smart_unicode, force_unicode 4 4 5 5 class ContentTypeManager(models.Manager): … … 127 127 objects = ContentTypeManager() 128 128 129 129 class Meta: 130 verbose_name = _('content type')131 verbose_name_plural = _('content types')132 130 db_table = 'django_content_type' 133 131 ordering = ('name',) 134 132 unique_together = (('app_label', 'model'),) … … 145 143 if not model or self.name != model._meta.verbose_name_raw: 146 144 return self.name 147 145 else: 148 return force_unicode(model. _meta.verbose_name)146 return force_unicode(model.get_verbose_name()) 149 147 150 148 def model_class(self): 151 149 "Returns the Python model class for this type of content." … … 170 168 171 169 def natural_key(self): 172 170 return (self.app_label, self.model) 171 172 @classmethod 173 def verbose_names(cls, count=1): 174 return ungettext_lazy('content type', 'content types', count) -
django/contrib/databrowse/datastructures.py
diff --git a/django/contrib/databrowse/datastructures.py b/django/contrib/databrowse/datastructures.py
a b 18 18 self.site = site 19 19 self.model = model 20 20 self.model_list = site.registry.keys() 21 self.verbose_name = model. _meta.verbose_name22 self.verbose_name_plural = model. _meta.verbose_name_plural21 self.verbose_name = model.get_verbose_name() 22 self.verbose_name_plural = model.get_verbose_name(0) 23 23 24 24 def __repr__(self): 25 25 return '<EasyModel for %s>' % smart_str(self.model._meta.object_name) -
django/contrib/flatpages/models.py
diff --git a/django/contrib/flatpages/models.py b/django/contrib/flatpages/models.py
a b 1 1 from django.db import models 2 2 from django.contrib.sites.models import Site 3 from django.utils.translation import ugettext_lazy as _ 3 from django.utils.translation import ugettext_lazy as _, ungettext_lazy 4 4 5 5 6 6 class FlatPage(models.Model): … … 15 15 16 16 class Meta: 17 17 db_table = 'django_flatpage' 18 verbose_name = _('flat page')19 verbose_name_plural = _('flat pages')20 18 ordering = ('url',) 21 19 22 20 def __unicode__(self): … … 24 22 25 23 def get_absolute_url(self): 26 24 return self.url 25 26 @classmethod 27 def verbose_names(cls, count=1): 28 return ungettext_lazy('flat page', 'flat pages', count) -
django/contrib/redirects/models.py
diff --git a/django/contrib/redirects/models.py b/django/contrib/redirects/models.py
a b 1 1 from django.db import models 2 2 from django.contrib.sites.models import Site 3 from django.utils.translation import ugettext_lazy as _ 3 from django.utils.translation import ugettext_lazy as _, ungettext_lazy 4 4 5 5 class Redirect(models.Model): 6 6 site = models.ForeignKey(Site) … … 10 10 help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'.")) 11 11 12 12 class Meta: 13 verbose_name = _('redirect')14 verbose_name_plural = _('redirects')15 13 db_table = 'django_redirect' 16 14 unique_together=(('site', 'old_path'),) 17 15 ordering = ('old_path',) 18 16 19 17 def __unicode__(self): 20 18 return "%s ---> %s" % (self.old_path, self.new_path) 19 20 @classmethod 21 def verbose_names(cls, count=1): 22 return ungettext_lazy('redirect', 'redirects', count) -
django/contrib/sessions/models.py
diff --git a/django/contrib/sessions/models.py b/django/contrib/sessions/models.py
a b 1 1 from django.db import models 2 from django.utils.translation import ugettext_lazy as _ 2 from django.utils.translation import ugettext_lazy as _, ungettext_lazy 3 3 4 4 5 5 class SessionManager(models.Manager): … … 43 43 44 44 class Meta: 45 45 db_table = 'django_session' 46 verbose_name = _('session')47 verbose_name_plural = _('sessions')48 46 49 47 def get_decoded(self): 50 48 return SessionStore().decode(self.session_data) 51 49 50 @classmethod 51 def verbose_names(cls, count=1): 52 return ungettext_lazy('session', 'sessions', count) 53 52 54 53 55 # At bottom to avoid circular import 54 56 from django.contrib.sessions.backends.db import SessionStore -
django/contrib/sites/models.py
diff --git a/django/contrib/sites/models.py b/django/contrib/sites/models.py
a b 1 1 from django.db import models 2 from django.utils.translation import ugettext_lazy as _ 2 from django.utils.translation import ugettext_lazy as _, ungettext_lazy 3 3 4 4 5 5 SITE_CACHE = {} … … 40 40 41 41 class Meta: 42 42 db_table = 'django_site' 43 verbose_name = _('site')44 verbose_name_plural = _('sites')45 43 ordering = ('domain',) 46 44 47 45 def __unicode__(self): … … 61 59 except KeyError: 62 60 pass 63 61 62 @classmethod 63 def verbose_names(cls, count=1): 64 return ungettext_lazy('site', 'sites', count) 65 64 66 65 67 class RequestSite(object): 66 68 """ -
django/db/models/base.py
diff --git a/django/db/models/base.py b/django/db/models/base.py
a b 2 2 import sys 3 3 from functools import update_wrapper 4 4 from itertools import izip 5 import re 5 6 6 7 import django.db.models.manager # Imported to register signal handler. 7 8 from django.conf import settings … … 16 17 from django.db.models.query import Q 17 18 from django.db.models.query_utils import DeferredAttribute 18 19 from django.db.models.deletion import Collector 19 from django.db.models.options import Options 20 from django.db.models.options import Options, CAMEL_CASE_RE 20 21 from django.db.models import signals 21 22 from django.db.models.loading import register_models, get_model 22 from django.utils.translation import ugettext_lazy as _ 23 from django.utils.translation import ugettext_lazy as _, string_concat 23 24 from django.utils.functional import curry 24 25 from django.utils.encoding import smart_str, force_unicode 25 26 from django.utils.text import get_text_list, capfirst … … 98 99 for obj_name, obj in attrs.items(): 99 100 new_class.add_to_class(obj_name, obj) 100 101 102 if hasattr(new_class, 'verbose_names'): 103 new_class._meta._verbose_name = new_class.get_verbose_name() 104 new_class._meta._verbose_name_plural = new_class.get_verbose_name(0) 105 101 106 # All the fields of any type declared on this model 102 107 new_fields = new_class._meta.local_fields + \ 103 108 new_class._meta.local_many_to_many + \ … … 770 775 771 776 def unique_error_message(self, model_class, unique_check): 772 777 opts = model_class._meta 773 model_name = capfirst( opts.verbose_name)778 model_name = capfirst(self.get_verbose_name()) 774 779 775 780 # A unique field 776 781 if len(unique_check) == 1: … … 849 854 if errors: 850 855 raise ValidationError(errors) 851 856 857 @classmethod 858 def get_verbose_name(cls, count=1): 859 if hasattr(cls, 'verbose_names'): 860 retv = cls.verbose_names(count) 861 if retv is not None: 862 return retv 863 if count == 1: 864 return CAMEL_CASE_RE.sub(' \\1', cls.__name__).lower().strip() 865 return string_concat(cls.get_verbose_name(1), 's') 866 852 867 853 868 ############################################ 854 869 # HELPER FUNCTIONS (CURRIED MODEL METHODS) # -
django/db/models/fields/related.py
diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
a b 115 115 def set_attributes_from_rel(self): 116 116 self.name = self.name or (self.rel.to._meta.object_name.lower() + '_' + self.rel.to._meta.pk.name) 117 117 if self.verbose_name is None: 118 self.verbose_name = self.rel.to. _meta.verbose_name118 self.verbose_name = self.rel.to.get_verbose_name() 119 119 self.rel.field_name = self.rel.field_name or self.rel.to._meta.pk.name 120 120 121 121 def do_related_class(self, other, cls): … … 940 940 qs = qs.complex_filter(self.rel.limit_choices_to) 941 941 if not qs.exists(): 942 942 raise exceptions.ValidationError(self.error_messages['invalid'] % { 943 'model': self.rel.to. _meta.verbose_name, 'pk': value})943 'model': self.rel.to.get_verbose_name(), 'pk': value}) 944 944 945 945 def get_attname(self): 946 946 return '%s_id' % self.name … … 1052 1052 def create_many_to_many_intermediary_model(field, klass): 1053 1053 from django.db import models 1054 1054 managed = True 1055 1056 def verbose_name_method(f, t): 1057 def verbose_names(cls, count=1): 1058 return '%(from)s-%(to)s relationship%(extra)s' % {'from': f, 'to': t, 'extra': 's' if count != 1 else ''} 1059 return verbose_names 1060 1055 1061 if isinstance(field.rel.to, basestring) and field.rel.to != RECURSIVE_RELATIONSHIP_CONSTANT: 1056 1062 to_model = field.rel.to 1057 1063 to = to_model.split('.')[-1] … … 1080 1086 'app_label': klass._meta.app_label, 1081 1087 'db_tablespace': klass._meta.db_tablespace, 1082 1088 'unique_together': (from_, to), 1083 'verbose_name': '%(from)s-%(to)s relationship' % {'from': from_, 'to': to},1084 'verbose_name_plural': '%(from)s-%(to)s relationships' % {'from': from_, 'to': to},1085 1089 }) 1086 1090 # Construct and return the new class. 1087 1091 return type(name, (models.Model,), { 1088 1092 'Meta': meta, 1089 1093 '__module__': klass.__module__, 1090 1094 from_: models.ForeignKey(klass, related_name='%s+' % name, db_tablespace=field.db_tablespace), 1091 to: models.ForeignKey(to_model, related_name='%s+' % name, db_tablespace=field.db_tablespace) 1095 to: models.ForeignKey(to_model, related_name='%s+' % name, db_tablespace=field.db_tablespace), 1096 'verbose_names': classmethod(verbose_name_method(from_, to)), 1092 1097 }) 1093 1098 1094 1099 class ManyToManyField(RelatedField, Field): -
django/db/models/options.py
diff --git a/django/db/models/options.py b/django/db/models/options.py
a b 1 from bisect import bisect 1 2 import re 2 from bisect import bisect 3 import warnings 3 4 4 5 from django.conf import settings 5 6 from django.db.models.related import RelatedObject … … 11 12 from django.utils.encoding import force_unicode, smart_str 12 13 from django.utils.datastructures import SortedDict 13 14 14 # Calculate the verbose_name by converting from InitialCaps to "lowercase with spaces". 15 get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', ' \\1', class_name).lower().strip() 16 17 DEFAULT_NAMES = ('verbose_name', 'verbose_name_plural', 'db_table', 'ordering', 15 DEFAULT_NAMES = ('db_table', 'ordering', 18 16 'unique_together', 'permissions', 'get_latest_by', 19 17 'order_with_respect_to', 'app_label', 'db_tablespace', 20 18 'abstract', 'managed', 'proxy', 'auto_created') 21 19 20 DEPRECATED_NAMES = ('verbose_name', 'verbose_name_plural') 21 22 CAMEL_CASE_RE = re.compile('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))') 23 22 24 class Options(object): 23 25 def __init__(self, meta, app_label=None): 24 26 self.local_fields, self.local_many_to_many = [], [] 25 27 self.virtual_fields = [] 26 self.module_name, self. verbose_name = None, None27 self. verbose_name_plural = None28 self.module_name, self._verbose_name = None, None 29 self._verbose_name_plural = None 28 30 self.db_table = '' 29 31 self.ordering = [] 30 32 self.unique_together = [] … … 54 56 # from *other* models. Needed for some admin checks. Internal use only. 55 57 self.related_fkey_lookups = [] 56 58 59 def _get_verbose_name(self): 60 warnings.warn("Meta.verbose_name is deprecated. Use a verbose_names()" 61 " classmethod in the model instead.", PendingDeprecationWarning) 62 return self._verbose_name 63 def _set_verbose_name(self, value): 64 self._verbose_name = value 65 verbose_name = property(_get_verbose_name, _set_verbose_name) 66 67 def _get_verbose_name_plural(self): 68 warnings.warn("Meta.verbose_name_plural is deprecated. Use a " 69 "verbose_names() classmethod in the model instead.", 70 PendingDeprecationWarning) 71 return self._verbose_name_plural 72 def _set_verbose_name_plural(self, value): 73 self._verbose_name_plural = value 74 verbose_name_plural = property(_get_verbose_name_plural, _set_verbose_name_plural) 75 57 76 def contribute_to_class(self, cls, name): 58 77 from django.db import connection 59 78 from django.db.backends.util import truncate_name … … 63 82 # First, construct the default values for these options. 64 83 self.object_name = cls.__name__ 65 84 self.module_name = self.object_name.lower() 66 self. verbose_name = get_verbose_name(self.object_name)85 self._verbose_name = CAMEL_CASE_RE.sub(' \\1', self.object_name).lower().strip() 67 86 68 87 # Next, apply any overridden values from 'class Meta'. 69 88 if self.meta: … … 80 99 elif hasattr(self.meta, attr_name): 81 100 setattr(self, attr_name, getattr(self.meta, attr_name)) 82 101 102 for attr_name in DEPRECATED_NAMES: 103 if attr_name in meta_attrs: 104 warnings.warn("%(cls)s: Meta.%(attr_name)s is deprecated. Use a " 105 "verbose_names() classmethod in the model " 106 "instead." % {'cls': cls, 'attr_name': attr_name}, 107 PendingDeprecationWarning) 108 setattr(self, '_%s' % attr_name, meta_attrs.pop(attr_name)) 109 83 110 # unique_together can be either a tuple of tuples, or a single 84 111 # tuple of two strings. Normalize it to a tuple of tuples, so that 85 112 # calling code can uniformly expect that. … … 90 117 91 118 # verbose_name_plural is a special case because it uses a 's' 92 119 # by default. 93 if self. verbose_name_plural is None:94 self. verbose_name_plural = string_concat(self.verbose_name, 's')120 if self._verbose_name_plural is None: 121 self._verbose_name_plural = string_concat(self._verbose_name, 's') 95 122 96 123 # Any leftover attributes must be invalid. 97 124 if meta_attrs != {}: 98 125 raise TypeError("'class Meta' got invalid attribute(s): %s" % ','.join(meta_attrs.keys())) 99 126 else: 100 self. verbose_name_plural = string_concat(self.verbose_name, 's')127 self._verbose_name_plural = string_concat(self._verbose_name, 's') 101 128 del self.meta 102 129 103 130 # If the db_table wasn't provided, use the app_label + module_name. … … 199 226 """ 200 227 lang = get_language() 201 228 deactivate_all() 202 raw = force_unicode(self. verbose_name)229 raw = force_unicode(self._verbose_name) 203 230 activate(lang) 204 231 return raw 205 232 verbose_name_raw = property(verbose_name_raw) -
django/db/models/related.py
diff --git a/django/db/models/related.py b/django/db/models/related.py
a b 36 36 {'%s__isnull' % self.parent_model._meta.module_name: False}) 37 37 lst = [(x._get_pk_val(), smart_unicode(x)) for x in queryset] 38 38 return first_choice + lst 39 39 40 40 def get_db_prep_lookup(self, lookup_type, value, connection, prepared=False): 41 41 # Defer to the actual field definition for db prep 42 42 return self.field.get_db_prep_lookup(lookup_type, value, … … 67 67 68 68 def get_cache_name(self): 69 69 return "_%s_cache" % self.get_accessor_name() 70 71 def get_verbose_name(self, count=1): 72 return self.model.get_verbose_name(count) -
django/views/generic/create_update.py
diff --git a/django/views/generic/create_update.py b/django/views/generic/create_update.py
a b 95 95 return model.objects.get(**lookup_kwargs) 96 96 except ObjectDoesNotExist: 97 97 raise Http404("No %s found for %s" 98 % (model. _meta.verbose_name, lookup_kwargs))98 % (model.get_verbose_name(), lookup_kwargs)) 99 99 100 100 def create_object(request, model=None, template_name=None, 101 101 template_loader=loader, extra_context=None, post_save_redirect=None, … … 119 119 new_object = form.save() 120 120 121 121 msg = ugettext("The %(verbose_name)s was created successfully.") %\ 122 {"verbose_name": model. _meta.verbose_name}122 {"verbose_name": model.get_verbose_name()} 123 123 messages.success(request, msg, fail_silently=True) 124 124 return redirect(post_save_redirect, new_object) 125 125 else: … … 162 162 if form.is_valid(): 163 163 obj = form.save() 164 164 msg = ugettext("The %(verbose_name)s was updated successfully.") %\ 165 {"verbose_name": model. _meta.verbose_name}165 {"verbose_name": model.get_verbose_name()} 166 166 messages.success(request, msg, fail_silently=True) 167 167 return redirect(post_save_redirect, obj) 168 168 else: … … 205 205 if request.method == 'POST': 206 206 obj.delete() 207 207 msg = ugettext("The %(verbose_name)s was deleted.") %\ 208 {"verbose_name": model. _meta.verbose_name}208 {"verbose_name": model.get_verbose_name()} 209 209 messages.success(request, msg, fail_silently=True) 210 210 return HttpResponseRedirect(post_delete_redirect) 211 211 else: -
django/views/generic/date_based.py
diff --git a/django/views/generic/date_based.py b/django/views/generic/date_based.py
a b 34 34 queryset = queryset.filter(**{'%s__lte' % date_field: datetime.datetime.now()}) 35 35 date_list = queryset.dates(date_field, 'year')[::-1] 36 36 if not date_list and not allow_empty: 37 raise Http404("No %s available" % model. _meta.verbose_name)37 raise Http404("No %s available" % model.get_verbose_name()) 38 38 39 39 if date_list and num_latest: 40 40 latest = queryset.order_by('-'+date_field)[:num_latest] … … 354 354 try: 355 355 obj = queryset.get(**lookup_kwargs) 356 356 except ObjectDoesNotExist: 357 raise Http404("No %s found for" % model. _meta.verbose_name)357 raise Http404("No %s found for" % model.get_verbose_name()) 358 358 if not template_name: 359 359 template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower()) 360 360 if template_name_field: -
django/views/generic/dates.py
diff --git a/django/views/generic/dates.py b/django/views/generic/dates.py
a b 195 195 196 196 if not allow_empty and not qs: 197 197 raise Http404(_(u"No %(verbose_name_plural)s available") % { 198 'verbose_name_plural': force_unicode(qs.model. _meta.verbose_name_plural)198 'verbose_name_plural': force_unicode(qs.model.get_verbose_name(0)) 199 199 }) 200 200 201 201 return qs … … 464 464 465 465 if not self.get_allow_future() and date > datetime.date.today(): 466 466 raise Http404(_(u"Future %(verbose_name_plural)s not available because %(class_name)s.allow_future is False.") % { 467 'verbose_name_plural': qs.model. _meta.verbose_name_plural,467 'verbose_name_plural': qs.model.get_verbose_name(0), 468 468 'class_name': self.__class__.__name__, 469 469 }) 470 470 -
django/views/generic/detail.py
diff --git a/django/views/generic/detail.py b/django/views/generic/detail.py
a b 49 49 obj = queryset.get() 50 50 except ObjectDoesNotExist: 51 51 raise Http404(_(u"No %(verbose_name)s found matching the query") % 52 {'verbose_name': queryset.model. _meta.verbose_name})52 {'verbose_name': queryset.model.get_verbose_name()}) 53 53 return obj 54 54 55 55 def get_queryset(self): -
django/views/generic/list_detail.py
diff --git a/django/views/generic/list_detail.py b/django/views/generic/list_detail.py
a b 131 131 try: 132 132 obj = queryset.get() 133 133 except ObjectDoesNotExist: 134 raise Http404("No %s found matching the query" % (model. _meta.verbose_name))134 raise Http404("No %s found matching the query" % (model.get_verbose_name())) 135 135 if not template_name: 136 136 template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower()) 137 137 if template_name_field: -
docs/ref/models/instances.txt
diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt
a b 540 540 More details on named URL patterns are in the :doc:`URL dispatch documentation 541 541 </topics/http/urls>`. 542 542 543 ``verbose_names`` 544 ----------------- 545 546 .. classmethod:: Model.verbose_names(count=1) 547 548 .. versionadded:: 1.4 549 550 A Python classmethod. 551 552 This method has no default implementation and you might provide one depending 553 on the the human readable name you need for your model. 554 555 The *count* argument is the quantity of model instances the verbose name is 556 being requested for. 557 558 It provides a straight migration path from the :attr:`~Options.verbose_name` and 559 :attr:`~Options.verbose_name_plural` options that entered a deprecation cycle 560 starting with Django 1.4. For example this model declaration:: 561 562 class SSN(models.Model): 563 value = models.CharField(max_length=11) 564 565 class Meta: 566 verbose_name = 'social security number' 567 568 needs to be changed to:: 569 570 class SSN(models.Model): 571 value = models.CharField(max_length=11) 572 573 @classmethod 574 def verbose_names(cls, count=1): 575 return 'social security number' 576 577 and this one:: 578 579 class SecurityPolicy(models.Model): 580 title = models.CharField(max_length=30) 581 582 class Meta: 583 verbose_name_plural = 'security policies' 584 585 should be changed to:: 586 587 class SecurityPolicy(models.Model): 588 title = models.CharField(max_length=30) 589 590 @classmethod 591 def verbose_names(cls, count=1): 592 if count != 1: 593 return 'security policies' 594 595 This new syntax can take in account the number of model instances at play to 596 decide the exact verbose name to show in user interaction contexts. It provides 597 for better internationalization of your application because the name of your 598 model is now translatable in a more correct way to many more locales:: 599 600 from django.utils.translation import ugettext_lazy 601 602 class Man(models.Model): 603 first_name = models.CharField(max_length=30) 604 605 @classmethod 606 def verbose_names(cls, count=1): 607 if count == 1: 608 return ugettext_lazy('man') 609 else: 610 return ugettext_lazy('men') 611 612 Although you usually will use the 613 :func:`~django.utils.translation.ungettext_lazy` function:: 614 615 from django.utils.translation import ungettext_lazy 616 617 class Library(models.Model): 618 city_name = models.CharField(max_length=30) 619 620 @classmethod 621 def verbose_names(cls, count=1): 622 return ungetttext_lazy('llbrary', 'libraries', count) 623 624 .. note:: 625 Remember to declare this method as a classmethod:: 626 627 class MyModel(models.Model): 628 ... 629 630 @classmethod 631 def verbose_names(cls, count=1): 632 ... 633 634 .. seealso:: 635 636 The :meth:`~Model.get_verbose_name` method that works together with this 637 method. 638 543 639 Extra instance methods 544 640 ====================== 545 641 546 642 In addition to :meth:`~Model.save()`, :meth:`~Model.delete()`, a model object 547 643 might have some of the following methods: 548 644 645 ``get_*_display`` 646 ----------------- 647 549 648 .. method:: Model.get_FOO_display() 550 649 551 650 For every field that has :attr:`~django.db.models.Field.choices` set, the … … 570 669 >>> p.get_gender_display() 571 670 'Male' 572 671 672 ``get_next_by_*`` and ``get_prev_by_*`` 673 --------------------------------------- 674 573 675 .. method:: Model.get_next_by_FOO(\**kwargs) 574 676 .. method:: Model.get_previous_by_FOO(\**kwargs) 575 677 … … 587 689 primary key as a tie-breaker. This guarantees that no records are skipped or 588 690 duplicated. That also means you cannot use those methods on unsaved objects. 589 691 692 ``get_verbose_name`` 693 -------------------- 694 695 .. classmethod:: Model.get_verbose_name(count=1) 696 697 .. versionadded:: 1.4 698 699 A Python classmethod. 700 701 Django automatically gives all models an implementation of this method so you 702 usually don't need to override it. 703 704 It provides an official API to access translated and correctly pluralized 705 verbose names of models (something that previously involved using non public 706 APIs like accessing the ``Model._meta.verbose_name`` and 707 ``Model._meta.verbose_name_plural`` attributes.) 708 709 .. seealso:: 710 711 The :meth:`~Model.verbose_names` user-provided classmethod that works 712 together with this method. 713 714 This method will always return a value independently of whether the model 715 implements the :meth:`~Model.verbose_names` classmethod or not. Django provides 716 fallback return values compatible with the default values of the deprecated 717 :attr:`~Options.verbose_name` and :attr:`~Options.verbose_name_plural` options. 718 719 For example, given this model:: 720 721 class Door(models.Model): 722 height = models.PositiveIntegerField() 723 724 then these are the return values of this method:: 725 726 >>> Door.get_verbose_name(1) # One door 727 >>> 'door' # Automatically provided singular verbose name 728 >>> Door.get_verbose_name(3) # More than one door 729 >>> 'doors' 730 # Note how it returns an automatically provided simple naive pluralization 731 # appending a 's' to the singular value 732 733 Or, for the examples in the :meth:`~Model.verbose_names` section above:: 734 735 >>> SSN.get_verbose_name() # One SSN, count default value 736 >>> 'social security number' 737 # Note how it returns the value returned by SSN.verbose_names(count) for a 738 # value of count=1 739 >>> SSN.get_verbose_name(0) # Zero SSN 740 >>> 'social security numbers' 741 # Note how it returns an automatically provided simple naive pluralization 742 # appending a 's' to the singular value 743 744 >>> SecurityPolicy.get_verbose_name() # One policy 745 >>> 'security policy' 746 # Note how it returns a value automatically provided by Django by processing 747 # the model class name 748 >>> SecurityPolicy.get_verbose_name(10) # Ten policies 749 >>> 'security policies' 750 # Note how it returns the value returned by 751 # SecurityPolicy.verbose_names(count) for a count value different from 1 -
docs/ref/models/options.txt
diff --git a/docs/ref/models/options.txt b/docs/ref/models/options.txt
a b 253 253 254 254 .. attribute:: Options.verbose_name 255 255 256 .. deprecated:: 1.4 257 This option has been replaced by the :meth:`~Model.verbose_names` model 258 classmethod. Implement such method in your model to make Django aware 259 of its human readable name(s). 260 256 261 A human-readable name for the object, singular:: 257 262 258 263 verbose_name = "pizza" … … 265 270 266 271 .. attribute:: Options.verbose_name_plural 267 272 273 .. deprecated:: 1.4 274 This option has been replaced by the :meth:`~Model.verbose_names` model 275 classmethod. Implement such method in your model to make Django aware 276 of its human readable name(s). 277 268 278 The plural name for the object:: 269 279 270 280 verbose_name_plural = "stories" -
docs/topics/db/models.txt
diff --git a/docs/topics/db/models.txt b/docs/topics/db/models.txt
a b 641 641 642 642 class Meta: 643 643 ordering = ["horn_length"] 644 verbose_name_plural = "oxen"645 644 646 645 Model metadata is "anything that's not a field", such as ordering options 647 (:attr:`~Options.ordering`), database table name (:attr:`~Options.db_table`), or 648 human-readable singular and plural names (:attr:`~Options.verbose_name` and 649 :attr:`~Options.verbose_name_plural`). None are required, and adding ``class 650 Meta`` to a model is completely optional. 646 (:attr:`~Options.ordering`), database table name (:attr:`~Options.db_table`). 647 None are required, and adding ``class Meta`` to a model is completely optional. 651 648 652 649 A complete list of all possible ``Meta`` options can be found in the :doc:`model 653 650 option reference </ref/models/options>`. -
docs/topics/i18n/translation.txt
diff --git a/docs/topics/i18n/translation.txt b/docs/topics/i18n/translation.txt
a b 168 168 translation string and the number of objects. 169 169 170 170 This function is useful when you need your Django application to be localizable 171 to languages where the number and complexity of `plural forms 172 <http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms>`_ is 173 greater than the two forms used in English ('object' for the singular and 174 'objects' for all the cases where ``count`` is different from one, irrespective 175 of its value.) 171 to languages where the number and complexity of `plural forms`_ is greater than 172 the two forms as used in the English language (e.g. 'object' for the singular 173 and 'objects' for all the cases where ``count`` is different from one, 174 irrespective of its value.) 176 175 177 176 For example:: 178 177 … … 187 186 } 188 187 return HttpResponse(page) 189 188 190 In this example the number of objects is passed to the translation 191 languages asthe ``count`` variable.189 In this example the number of objects is passed to the translation functions as 190 the ``count`` variable. 192 191 193 Lets see a slightly more complex usageexample::192 Lets see a slightly more complex example:: 194 193 195 194 from django.utils.translation import ungettext 196 195 197 196 count = Report.objects.count() 198 if count == 1: 199 name = Report._meta.verbose_name 200 else: 201 name = Report._meta.verbose_name_plural 197 name = Report.get_verbose_name(count) 202 198 203 199 text = ungettext( 204 200 'There is %(count)d %(name)s available.', … … 209 205 'name': name 210 206 } 211 207 212 Here we reuse localizable, hopefully already translated literals (contained in 213 the ``verbose_name`` and ``verbose_name_plural`` model ``Meta`` options) for 214 other parts of the sentence so all of it is consistently based on the 215 cardinality of the elements at play. 208 Here we reuse localizable, potentially translated literals (as returned by the 209 :meth:`~django.db.models.Model.get_verbose_name` model classmethod) for other 210 parts of the sentence so all of it is consistently based on the cardinality of 211 the elements at play. 212 213 .. _plural forms: http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms 216 214 217 215 .. _pluralization-var-notes: 218 216 -
tests/modeltests/custom_pk/models.py
diff --git a/tests/modeltests/custom_pk/models.py b/tests/modeltests/custom_pk/models.py
a b 26 26 class Business(models.Model): 27 27 name = models.CharField(max_length=20, primary_key=True) 28 28 employees = models.ManyToManyField(Employee) 29 class Meta:30 verbose_name_plural = 'businesses'31 29 32 30 def __unicode__(self): 33 31 return self.name 34 32 33 @classmethod 34 def verbose_names(cls, count=1): 35 return 'businesses' 36 35 37 class Bar(models.Model): 36 38 id = MyAutoField(primary_key=True, db_index=True) 37 39 -
tests/regressiontests/admin_util/models.py
diff --git a/tests/regressiontests/admin_util/models.py b/tests/regressiontests/admin_util/models.py
a b 34 34 event = models.OneToOneField(Event) 35 35 name = models.CharField(max_length=255) 36 36 37 class Meta: 38 verbose_name = "awesome guest" 37 @classmethod 38 def verbose_names(cls, count=1): 39 return "awesome guest" -
tests/regressiontests/admin_views/models.py
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py
a b 63 63 def __unicode__(self): 64 64 return self.title 65 65 66 class Meta: 66 @classmethod 67 def verbose_names(cls, count=1): 67 68 # Use a utf-8 bytestring to ensure it works (see #11710) 68 verbose_name ='¿Chapter?'69 return '¿Chapter?' 69 70 70 71 71 72 class ChapterXtra1(models.Model): … … 538 539 age = models.PositiveIntegerField() 539 540 is_employee = models.NullBooleanField() 540 541 541 class PrePopulatedPostLargeSlug(models.Model): 542 """ 543 Regression test for #15938: a large max_length for the slugfield must not 544 be localized in prepopulated_fields_js.html or it might end up breaking 545 the javascript (ie, using THOUSAND_SEPARATOR ends up with maxLength=1,000) 546 """ 547 title = models.CharField(max_length=100) 548 published = models.BooleanField() 542 class PrePopulatedPostLargeSlug(models.Model): 543 """ 544 Regression test for #15938: a large max_length for the slugfield must not 545 be localized in prepopulated_fields_js.html or it might end up breaking 546 the javascript (ie, using THOUSAND_SEPARATOR ends up with maxLength=1,000) 547 """ 548 title = models.CharField(max_length=100) 549 published = models.BooleanField() 549 550 slug = models.SlugField(max_length=1000) 550 551 -
tests/regressiontests/backends/models.py
diff --git a/tests/regressiontests/backends/models.py b/tests/regressiontests/backends/models.py
a b 28 28 # Until #13711 is fixed, this test can't be run under MySQL. 29 29 if connection.features.supports_long_model_names: 30 30 class VeryLongModelNameZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ(models.Model): 31 class Meta:32 # We need to use a short actual table name or33 # we hit issue #8548 which we're not testing!34 verbose_name = 'model_with_long_table_name'35 31 primary_key_is_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz = models.AutoField(primary_key=True) 36 32 charfield_is_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz = models.CharField(max_length=100) 37 33 m2m_also_quite_long_zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz = models.ManyToManyField(Person,blank=True) 38 34 35 # We need to use a short actual verbose name or 36 # we hit issue #8548 which we're not testing! 37 @classmethod 38 def verbose_names(cls, count=1): 39 return 'model_with_long_table_name' 40 39 41 40 42 class Tag(models.Model): 41 43 name = models.CharField(max_length=30) -
tests/regressiontests/generic_views/models.py
diff --git a/tests/regressiontests/generic_views/models.py b/tests/regressiontests/generic_views/models.py
a b 1 1 from django.db import models 2 2 from django.utils.translation import ungettext_lazy 3 3 4 4 class Artist(models.Model): 5 5 name = models.CharField(max_length=100) 6 6 7 7 class Meta: 8 8 ordering = ['name'] 9 verbose_name = 'professional artist'10 verbose_name_plural = 'professional artists'11 9 12 10 def __unicode__(self): 13 11 return self.name … … 16 14 def get_absolute_url(self): 17 15 return ('artist_detail', (), {'pk': self.id}) 18 16 17 @classmethod 18 def verbose_names(cls, count=1): 19 return ungettext_lazy('professional artist', 'professional artists', count) 20 19 21 class Author(models.Model): 20 22 name = models.CharField(max_length=100) 21 23 slug = models.SlugField() -
tests/regressiontests/i18n/models.py
diff --git a/tests/regressiontests/i18n/models.py b/tests/regressiontests/i18n/models.py
a b 13 13 cents_payed = models.DecimalField(max_digits=4, decimal_places=2) 14 14 products_delivered = models.IntegerField() 15 15 16 class Meta:17 verbose_name = _('Company')18 No newline at end of file16 @classmethod 17 def verbose_names(cls, count=1): 18 return _('Company') -
tests/regressiontests/model_inheritance_regress/models.py
diff --git a/tests/regressiontests/model_inheritance_regress/models.py b/tests/regressiontests/model_inheritance_regress/models.py
a b 108 108 109 109 class Meta: 110 110 abstract = True 111 verbose_name_plural = u'Audits' 111 112 @classmethod 113 def verbose_names(cls, count=1): 114 return u'Audits' 112 115 113 116 class CertificationAudit(AuditBase): 114 117 class Meta(AuditBase.Meta): -
tests/regressiontests/model_regress/models.py
diff --git a/tests/regressiontests/model_regress/models.py b/tests/regressiontests/model_regress/models.py
a b 16 16 17 17 class Meta: 18 18 ordering = ('pub_date','headline') 19 # A utf-8 verbose name (Ångström's Articles) to test they are valid.20 verbose_name = "\xc3\x85ngstr\xc3\xb6m's Articles"21 19 22 20 def __unicode__(self): 23 21 return self.headline 24 22 23 @classmethod 24 def verbose_names(cls, count=1): 25 # An utf-8 verbose name (Ångström's Articles) to test they are valid. 26 return "\xc3\x85ngstr\xc3\xb6m's Articles" 27 25 28 class Movie(models.Model): 26 29 #5218: Test models with non-default primary keys / AutoFields 27 30 movie_id = models.AutoField(primary_key=True) -
new file tests/regressiontests/verbose_names/__init__.py
diff --git a/tests/regressiontests/verbose_names/__init__.py b/tests/regressiontests/verbose_names/__init__.py new file mode 100644 diff --git a/tests/regressiontests/verbose_names/locale/es_AR/LC_MESSAGES/django.mo b/tests/regressiontests/verbose_names/locale/es_AR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..5a0d607200b2b05b66bf95085b76d736061c03bf GIT binary patch literal 1052 zc$|%q-EPw`7=|-CeiY6)<<E!{KzQUwz~r^4p-rb~NmsS$jyUlWlVwWn%65TX0Nep* zoFQ=^a0EB8b1njjFH5R2Xg939d2Ky!{C%-cZft%uU|a*;0=)uV2YoWC@f~y*^aIoe z{RAP<qm3%RSNjq8ZSeQCe+EAWeXaT9hG8_pgGROA2k@KVUuypbeh2)d_Fv!|bzkMU z1ZvdttDsHLm3n=-e8rM-RZvY23x@jaEmnFCvx!Jqf$rNEaOYgE{v+U?4HPV+$$U-u zv(Q-&|1JC%b&Y`($1Kq}Nbv!aDi@rff!Epdc71f<4@bd%-yE{3kQzrS%TxSvmMI(y zg3Q5wj60H14Ikky)r=s=vTY2H^Bma@fr<6ZvLJ|u>`ks#=bjSF!j=oUkSdKA?Fvay zZybiG??pap`jHoeZLixM`lHbci1KVkGlpYECj^CFe|KEA+zi8Zk#7l^Ei=$+6h!{= z|LiTx><F$IhjQ~N1T=f6pG*sy^Bt5NQK^`2jpH8PUgpZSUNeb(o`^K(8A02Jxi$yI zOwt1Pgq$dX`1EwCTFwrtrmY7Y-D@HHp=m_rp^MYAms}t%X*x^t@>bx2&w)-2)q<)& bu)3JLi_Oc+PuCP)!It}0aBbO@*fo9wrIRVG
-
new file tests/regressiontests/verbose_names/locale/es_AR/LC_MESSAGES/django.po
diff --git a/tests/regressiontests/verbose_names/locale/es_AR/LC_MESSAGES/django.po b/tests/regressiontests/verbose_names/locale/es_AR/LC_MESSAGES/django.po new file mode 100644
- + 1 # SOME DESCRIPTIVE TITLE. 2 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 # This file is distributed under the same license as the PACKAGE package. 4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. 5 # 6 msgid "" 7 msgstr "" 8 "Project-Id-Version: PACKAGE VERSION\n" 9 "Report-Msgid-Bugs-To: \n" 10 "POT-Creation-Date: 2011-11-27 12:11-0600\n" 11 "PO-Revision-Date: 2011-11-27 15:00-0300\n" 12 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 13 "Language-Team: LANGUAGE <LL@li.org>\n" 14 "Language: \n" 15 "MIME-Version: 1.0\n" 16 "Content-Type: text/plain; charset=UTF-8\n" 17 "Content-Transfer-Encoding: 8bit\n" 18 "Plural-Forms: nplurals=2; plural=(n != 1)\n" 19 20 msgid "Translatable legacy model #1" 21 msgstr "Modelo legado traducible #1" 22 23 msgid "Translatable legacy model #2" 24 msgstr "Modelo legado traducible #2" 25 26 msgid "Translatable legacy models #2" 27 msgstr "Modelos legados traducibles #2" 28 29 msgid "Translatable legacy models #3" 30 msgstr "Modelos legados traducibles #3" 31 32 msgid "Translatable New-style model #1" 33 msgstr "Modelo moderno traducible #1" 34 35 msgid "Translatable New-style model #2" 36 msgid_plural "Translatable New-style models #2" 37 msgstr[0] "Modelo moderno traducible #2" 38 msgstr[1] "Modelos modernos traducibles #2" 39 40 msgid "Translatable New-style models #3" 41 msgstr "Modelos modernos traducibles #3" -
new file tests/regressiontests/verbose_names/models.py
diff --git a/tests/regressiontests/verbose_names/models.py b/tests/regressiontests/verbose_names/models.py new file mode 100644
- + 1 from django.db import models 2 from django.utils.translation import ugettext_lazy as _, ungettext_lazy 3 4 5 class NoMeta(models.Model): 6 name = models.CharField(max_length=20) 7 8 class LegacyOnlyVerboseName(models.Model): 9 name = models.CharField(max_length=20) 10 11 class Meta: 12 verbose_name = 'Legacy model #1' 13 14 class LegacyBothVNames(models.Model): 15 name = models.CharField(max_length=20) 16 17 class Meta: 18 verbose_name = 'Legacy model #2' 19 verbose_name_plural = 'Legacy models #2' 20 21 class LegacyOnlyVerboseNamePlural(models.Model): 22 name = models.CharField(max_length=20) 23 24 class Meta: 25 verbose_name_plural = 'Legacy models #3' 26 27 class LegacyOnlyVerbosenameIntl(models.Model): 28 name = models.CharField(max_length=20) 29 30 class Meta: 31 verbose_name = _('Translatable legacy model #1') 32 33 class LegacyBothIntl(models.Model): 34 name = models.CharField(max_length=20) 35 36 class Meta: 37 verbose_name = _('Translatable legacy model #2') 38 verbose_name_plural = _('Translatable legacy models #2') 39 40 class LegacyPluralIntl(models.Model): 41 name = models.CharField(max_length=20) 42 43 class Meta: 44 verbose_name_plural = _('Translatable legacy models #3') 45 46 # === Models using new classmethod syntax for verbose names ========== 47 48 class NewstyleSingular(models.Model): 49 name = models.CharField(max_length=20) 50 51 @classmethod 52 def verbose_names(cls, count=1): 53 if count == 1: 54 return 'New-style model #1' 55 56 class NewstyleBoth(models.Model): 57 name = models.CharField(max_length=20) 58 59 @classmethod 60 def verbose_names(cls, count=1): 61 if count == 1: 62 return 'New-style model #2' 63 else: 64 return 'New-style models #2' 65 66 class NewstylePlural(models.Model): 67 name = models.CharField(max_length=20) 68 69 @classmethod 70 def verbose_names(cls, count=1): 71 if count != 1: 72 return 'New-style models #3' 73 74 class NewstyleSingularIntl(models.Model): 75 name = models.CharField(max_length=20) 76 77 @classmethod 78 def verbose_names(cls, count=1): 79 if count == 1: 80 return _('Translatable New-style model #1') 81 82 class NewstyleBothIntl(models.Model): 83 name = models.CharField(max_length=20) 84 85 @classmethod 86 def verbose_names(cls, count=1): 87 return ungettext_lazy('Translatable New-style model #2', 'Translatable New-style models #2', count) 88 89 class NewstylePluralIntl(models.Model): 90 name = models.CharField(max_length=20) 91 92 @classmethod 93 def verbose_names(cls, count=1): 94 if count != 1: 95 return _('Translatable New-style models #3') -
new file tests/regressiontests/verbose_names/tests.py
diff --git a/tests/regressiontests/verbose_names/tests.py b/tests/regressiontests/verbose_names/tests.py new file mode 100644
- + 1 from __future__ import absolute_import 2 3 from django.utils.encoding import force_unicode 4 from django.utils import translation 5 from django.utils.unittest import TestCase 6 7 from .models import (NoMeta, LegacyOnlyVerboseName, LegacyBothVNames, 8 LegacyOnlyVerboseNamePlural, LegacyOnlyVerbosenameIntl, LegacyBothIntl, 9 LegacyPluralIntl, NewstyleSingular, NewstyleBoth, NewstylePlural, 10 NewstyleSingularIntl, NewstyleBothIntl, NewstylePluralIntl) 11 12 13 class LegacyVerboseNameNoI18NTests(TestCase): 14 """ 15 Test we don't disrupt behavior associated with legacy 16 Meta.verbose_name{,_plural} attributes when translation isn't used. 17 """ 18 19 def test_noi18n_no_meta_inner_class(self): 20 # A model without an inner Meta class 21 a = NoMeta.objects.create(name=u'Name') 22 self.assertEqual('no meta', NoMeta._meta.verbose_name) 23 self.assertEqual('no meta', a._meta.verbose_name) 24 # Automatically generated plural form, can be bogus (note the arbitrary 25 # 's' tucked at the end) 26 self.assertEqual('no metas', force_unicode(NoMeta._meta.verbose_name_plural)) 27 self.assertEqual('no metas', force_unicode(a._meta.verbose_name_plural)) 28 29 def test_noi18n_only_verbose_name_option(self): 30 a = LegacyOnlyVerboseName.objects.create(name=u'Name') 31 # The verbose_name we specified 32 self.assertEqual('Legacy model #1', LegacyOnlyVerboseName._meta.verbose_name) 33 self.assertEqual('Legacy model #1', a._meta.verbose_name) 34 # Automatically generated plural form, can be bogus (note the arbitrary 35 # 's' tucked at the end) 36 self.assertEqual('Legacy model #1s', force_unicode(LegacyOnlyVerboseName._meta.verbose_name_plural)) 37 self.assertEqual('Legacy model #1s', force_unicode(a._meta.verbose_name_plural)) 38 39 def test_noi18n_both_verbose_name_options(self): 40 b = LegacyBothVNames.objects.create(name=u'Name') 41 # The verbose_name we specified 42 self.assertEqual('Legacy model #2', LegacyBothVNames._meta.verbose_name) 43 self.assertEqual('Legacy model #2', b._meta.verbose_name) 44 # The verbose_name_plural we specified 45 self.assertEqual('Legacy models #2', LegacyBothVNames._meta.verbose_name_plural) 46 self.assertEqual('Legacy models #2', b._meta.verbose_name_plural) 47 48 def test_noi18n_only_verbose_name_plural_option(self): 49 c = LegacyOnlyVerboseNamePlural.objects.create(name=u'Name') 50 # Verbose name automatically generated from the class name 51 self.assertEqual('legacy only verbose name plural', LegacyOnlyVerboseNamePlural._meta.verbose_name) 52 self.assertEqual('legacy only verbose name plural', c._meta.verbose_name) 53 # The verbose_name_plural we specified 54 self.assertEqual('Legacy models #3', LegacyOnlyVerboseNamePlural._meta.verbose_name_plural) 55 self.assertEqual('Legacy models #3', c._meta.verbose_name_plural) 56 57 58 class LegacyVerboseNameI18NTests(TestCase): 59 """ 60 Test we don't disrupt behavior associated with legacy 61 Meta.verbose_name{,_plural} attributes when translation is used. 62 """ 63 64 def setUp(self): 65 translation.activate('es-ar') 66 67 def tearDown(self): 68 translation.deactivate() 69 70 def test_i18n_no_meta_inner_class(self): 71 # A model without an inner Meta class 72 a = NoMeta.objects.create(name=u'Name') 73 self.assertEqual('no meta', NoMeta._meta.verbose_name) 74 self.assertEqual('no meta', a._meta.verbose_name) 75 # Automatically generated plural form, can be bogus (note the arbitrary 76 # 's' tucked at the end) 77 self.assertEqual('no metas', force_unicode(NoMeta._meta.verbose_name_plural)) 78 self.assertEqual('no metas', force_unicode(a._meta.verbose_name_plural)) 79 80 def test_i18n_only_verbose_name_option(self): 81 a = LegacyOnlyVerbosenameIntl.objects.create(name=u'Name') 82 # The verbose_name we specified 83 self.assertEqual('Modelo legado traducible #1', force_unicode(LegacyOnlyVerbosenameIntl._meta.verbose_name)) 84 self.assertEqual('Modelo legado traducible #1', a._meta.verbose_name) 85 # Automatically generated plural form, can be bogus (note the arbitrary 86 # 's' tucked at the end) 87 self.assertEqual('Modelo legado traducible #1s', force_unicode(LegacyOnlyVerbosenameIntl._meta.verbose_name_plural)) 88 self.assertEqual('Modelo legado traducible #1s', force_unicode(a._meta.verbose_name_plural)) 89 90 def test_i18n_both_verbose_name_options(self): 91 a = LegacyBothIntl.objects.create(name=u'Name') 92 # The verbose_name we specified 93 self.assertEqual('Modelo legado traducible #2', LegacyBothIntl._meta.verbose_name) 94 self.assertEqual('Modelo legado traducible #2', a._meta.verbose_name) 95 # The verbose_name_plural we specified 96 self.assertEqual('Modelos legados traducibles #2', LegacyBothIntl._meta.verbose_name_plural) 97 self.assertEqual('Modelos legados traducibles #2', a._meta.verbose_name_plural) 98 99 def test_i18n_only_verbose_name_plural_option(self): 100 a = LegacyPluralIntl.objects.create(name=u'Name') 101 # Verbose name automatically generated from the class name 102 self.assertEqual('legacy plural intl', LegacyPluralIntl._meta.verbose_name) 103 self.assertEqual('legacy plural intl', a._meta.verbose_name) 104 # The verbose_name_plural we specified 105 self.assertEqual('Modelos legados traducibles #3', LegacyPluralIntl._meta.verbose_name_plural) 106 self.assertEqual('Modelos legados traducibles #3', a._meta.verbose_name_plural) 107 108 109 class VerboseNameNoI18NTests(TestCase): 110 """ 111 Test new verbose_names() model classmethod behavior when translation isn't 112 used. 113 """ 114 115 def test_backward_compatibility(self): 116 """ 117 Test backward compatibility with legacy Meta.verbose_name{,_plural} 118 attributes. 119 """ 120 a = NewstyleSingular.objects.create(name=u'Name') 121 # The verbose_name derived from the verbose_names() method we specified 122 self.assertEqual('New-style model #1', NewstyleSingular._meta.verbose_name) 123 self.assertEqual('New-style model #1', a._meta.verbose_name) 124 # Automatically generated plural form, can be bogus (note the arbitrary 125 # 's' tucked at the end) 126 self.assertEqual('New-style model #1s', force_unicode(NewstyleSingular._meta.verbose_name_plural)) 127 self.assertEqual('New-style model #1s', force_unicode(a._meta.verbose_name_plural)) 128 129 b = NewstyleBoth.objects.create(name=u'Name') 130 # The verbose_name derived from the verbose_names() we specified 131 self.assertEqual('New-style model #2', NewstyleBoth._meta.verbose_name) 132 self.assertEqual('New-style model #2', b._meta.verbose_name) 133 # The verbose_name_plural derived from the verbose_names() method we 134 # specified 135 self.assertEqual('New-style models #2', NewstyleBoth._meta.verbose_name_plural) 136 self.assertEqual('New-style models #2', b._meta.verbose_name_plural) 137 138 c = NewstylePlural.objects.create(name=u'Name') 139 # Verbose name automatically generated from the class name 140 self.assertEqual('newstyle plural', NewstylePlural._meta.verbose_name) 141 self.assertEqual('newstyle plural', c._meta.verbose_name) 142 # The verbose_name_plural derived from the verbose_names() method we 143 # specified 144 self.assertEqual('New-style models #3', NewstylePlural._meta.verbose_name_plural) 145 self.assertEqual('New-style models #3', c._meta.verbose_name_plural) 146 147 def test_new_behavior(self): 148 """ 149 Test sanity of new verbose_names() model classmethod. 150 """ 151 a = NewstyleSingular.objects.create(name=u'Name') 152 self.assertEqual('New-style model #1', NewstyleSingular.get_verbose_name()) 153 self.assertEqual('New-style model #1', a.get_verbose_name()) 154 # Fallback get_verbose_name() implementation, its return value 155 # can be bogus (note the arbitrary 's' tucked at the end) 156 self.assertEqual('New-style model #1s', force_unicode(NewstyleSingular.get_verbose_name(0))) 157 self.assertEqual('New-style model #1s', force_unicode(a.get_verbose_name(0))) 158 159 b = NewstyleBoth.objects.create(name=u'Name') 160 self.assertEqual('New-style model #2', NewstyleBoth.get_verbose_name()) 161 self.assertEqual('New-style model #2', b.get_verbose_name()) 162 163 self.assertEqual('New-style models #2', NewstyleBoth.get_verbose_name(0)) 164 self.assertEqual('New-style models #2', b.get_verbose_name(0)) 165 166 c = NewstylePlural.objects.create(name=u'Name') 167 # Fallback get_verbose_name() implementation: Returns a value 168 # automatically generated from the class name 169 self.assertEqual('newstyle plural', NewstylePlural.get_verbose_name()) 170 self.assertEqual('newstyle plural', c.get_verbose_name()) 171 172 self.assertEqual('New-style models #3', NewstylePlural.get_verbose_name(0)) 173 self.assertEqual('New-style models #3', c.get_verbose_name(0)) 174 175 176 class VerboseNameI18NTests(TestCase): 177 """ 178 Test new verbose_names() model classmethod behavior when translation is 179 used. 180 """ 181 182 def setUp(self): 183 translation.activate('es-ar') 184 185 def tearDown(self): 186 translation.deactivate() 187 188 def test_backward_compatibility(self): 189 """ 190 Test backward compatibility with legacy Meta.verbose_name{,_plural} 191 attributes. 192 """ 193 a = NewstyleSingularIntl.objects.create(name=u'Name') 194 # The verbose_name derived from the verbose_names() method we specified 195 self.assertEqual('Modelo moderno traducible #1', NewstyleSingularIntl._meta.verbose_name) 196 self.assertEqual('Modelo moderno traducible #1', a._meta.verbose_name) 197 # Automatically generated plural form, can be bogus (note the arbitrary 198 # 's' tucked at the end) 199 self.assertEqual('Modelo moderno traducible #1s', force_unicode(NewstyleSingularIntl._meta.verbose_name_plural)) 200 self.assertEqual('Modelo moderno traducible #1s', force_unicode(a._meta.verbose_name_plural)) 201 202 b = NewstyleBothIntl.objects.create(name=u'Name') 203 # The verbose_name derived from the verbose_names() we specified 204 self.assertEqual('Modelo moderno traducible #2', force_unicode(NewstyleBothIntl._meta.verbose_name)) 205 self.assertEqual('Modelo moderno traducible #2', b._meta.verbose_name) 206 # The verbose_name_plural derived from the verbose_names() method we 207 # specified 208 self.assertEqual('Modelos modernos traducibles #2', NewstyleBothIntl._meta.verbose_name_plural) 209 self.assertEqual('Modelos modernos traducibles #2', b._meta.verbose_name_plural) 210 211 c = NewstylePluralIntl.objects.create(name=u'Name') 212 # Verbose name automatically generated from the class name -- untranslatable 213 self.assertEqual('newstyle plural intl', NewstylePluralIntl._meta.verbose_name) 214 self.assertEqual('newstyle plural intl', c._meta.verbose_name) 215 # The verbose_name_plural derived from the verbose_names() method we 216 # specified 217 self.assertEqual('Modelos modernos traducibles #3', NewstylePluralIntl._meta.verbose_name_plural) 218 self.assertEqual('Modelos modernos traducibles #3', c._meta.verbose_name_plural) 219 220 def test_new_behavior(self): 221 """ 222 Test sanity of new verbose_names() model classmethod. 223 """ 224 a = NewstyleSingularIntl.objects.create(name=u'Name') 225 self.assertEqual('Modelo moderno traducible #1', NewstyleSingularIntl.get_verbose_name()) 226 self.assertEqual('Modelo moderno traducible #1', a.get_verbose_name()) 227 # Fallback get_verbose_name() implementation, its return value 228 # can be bogus (note the arbitrary 's' tucked at the end) 229 self.assertEqual('Modelo moderno traducible #1s', force_unicode(NewstyleSingularIntl.get_verbose_name(0))) 230 self.assertEqual('Modelo moderno traducible #1s', force_unicode(a.get_verbose_name(0))) 231 232 b = NewstyleBothIntl.objects.create(name=u'Name') 233 self.assertEqual('Modelo moderno traducible #2', NewstyleBothIntl.get_verbose_name()) 234 self.assertEqual('Modelo moderno traducible #2', b.get_verbose_name()) 235 236 self.assertEqual('Modelos modernos traducibles #2', NewstyleBothIntl.get_verbose_name(0)) 237 self.assertEqual('Modelos modernos traducibles #2', b.get_verbose_name(0)) 238 239 c = NewstylePluralIntl.objects.create(name=u'Name') 240 # Fallback get_verbose_name() implementation: Returns a value 241 # automatically generated from the class name -- untranslatable 242 self.assertEqual('newstyle plural intl', NewstylePluralIntl.get_verbose_name()) 243 self.assertEqual('newstyle plural intl', c.get_verbose_name()) 244 245 self.assertEqual('Modelos modernos traducibles #3', NewstylePluralIntl.get_verbose_name(0)) 246 self.assertEqual('Modelos modernos traducibles #3', c.get_verbose_name(0))