I have been to a django conference this morning (DjangoCong / @djangocong) , and a talk was about django-modeltranslation. At the end of the presentation, someone ask the question: “How can I translate my slugs with this app ?”. I remembered I used this app and I do that but I could’nt remember HOW ! So, here is how I did that, I think it might be tricky but it worked in my case:
I’ll pass about how to use the app, there is a good documentation on the author site but just remember that the app add “_lang” (i.e: _en, _fr…) at the end of each translated attribute.
So, let’s begin:
First make your model with a slug (or add to you existing model), I choose to describe a product :
#File models.py from django.db import models from django.utils.translation import ugettext_lazy as _ from django.conf import settings from django.template.defaultfilters import slugify class Product(Model): name = models.CharField(max_length=200, help_text=_(u"Name of the product")) slug = AutoSlugField(_('slug'), populate_from='name', overwrite=True) class Meta: app_label = "my_app" verbose_name = _(u"Product") verbose_name_plural = _(u"Products")
Then in your translation.py, say that “slug” has to be translated:
#File translation.py from modeltranslation.translator import translator, TranslationOptions from my_app.models import Product class ProductTranslationOptions(TranslationOptions): fields = ('name', 'slug') translator.register(Product, ProductTranslationOptions)
So by now, your slug can be translated but it is never filled and I don’t want my clients to fill this information. The populate_from could’nt work with translations and I don’t want to translate myself each time someone added a Product. So I overrode the save of Product using the translated “name” (which is done by the person who add the Product).
I defined also “get_absolute_url” which we’ll talk later.
#File models.py from django.db import models from django.utils.translation import ugettext_lazy as _ from django.conf import settings from django.template.defaultfilters import slugify class Product(models.Model): name = models.CharField(max_length=200, help_text=_(u"Name of the product")) slug = AutoSlugField(_('slug'), populate_from='name', overwrite=True) class Meta: app_label = "my_app" verbose_name = _(u"Product") verbose_name_plural = _(u"Products") #So for each defined language I set the slug with the name of the Product # I think the test of hasattr could be removed if you entirely "control" your application def save(self, *args, **kwargs): for lang_code, lang_verbose in settings.LANGUAGES: if hasattr(self, 'slug_%s' % lang_code) and hasattr(self, 'name_%s' % lang_code): setattr(self, 'slug_%s' % lang_code, slugify(getattr(self, 'name_%s' % lang_code, u""))) super(Product, self).save(*args, **kwargs) def get_absolute_url(self): return "/product/%s-%s" % (self.id, self.slug)
Now all my Products have their slug automaticaly translated ! I defined the “get_absolute_url” to use the translated slug (as you know django-modeltranslation uses the defined attribute [here “slug”] as a wrapper for “slug_fr”, “slug_en”,…and returns you the translated attribute in the current choosen language).
But, which pattern will match with my translated url ?? Answer : No one ! Here is the tricky part:
I defined the detailview url of a product as its product_id and “a slug”:
#File urls.py from django.conf.urls.defaults import * urlpatterns = patterns('my_app.views', (r'^product/(?P\d+)-(?P([\w,-]+)*)$', "products.detail_product"), )
And in my view, I set the default value slug to an empty string (maybe None works?), so it doesn’t matter which slug the url pattern will receive it matches only the product_id will be catched (and verified) !
#File products.py (== views.py) def detail_product(request, product_id, slug=""): product = get_object_or_404(Product, pk=product_id) #Return your HttpResponse..
So my product could be found either by:
That’s it ! I hope I was enough clear otherwise tell me in comments 😉