3

modeltranslation...

i change title, content and slug sections on my translation.py. Everything work is fine but i have a problem.

let me try to explain;

i have one post in my website and this post "slug" like this;

slug_en = some_en_slug

slug_fr = some_fr_slug

And i have one language changer on my navbar.

     {% get_current_language as LANGUAGE_CODE %}
     {% get_available_languages as LANGUAGES %}
     {% get_language_info_list for LANGUAGES as languages %}

<form action="{% url "set_language" %}" method="post" class="navbar-form navbar-right">
{% csrf_token %}
<div class="form-group">
    <select name="language" class="form-control" onchange="this.form.submit()">
    {% for language in languages %}
    <option value="{{ language.code }}"
        {% if language.code == LANGUAGE_CODE %}selected="selected"{% endif %}>
        {{ language.name_local }}
    </option>
    {% endfor %}
    </select>
</div>
</form>

Actually this lang. changer working fine. This is change all slug href url's on outside post... But this didnt change slug url in post page.

when i go this url;

https://example.com/en/en_slug

and after try change language, my browser is going this url;

https://example.com/fr/en_slug and i see 404 page..

i need to go to https://example.com/fr/fr_slug this url after change language ...

I dont have any idea for this. I would like your help.

urls.py
from django.urls import path
from . import views
from django.utils.translation import gettext_lazy as _

app_name = "article"


urlpatterns = [
    path(_('dashboard/'),views.dashboard,name="dashboard"),
    path(_('addarticle/'),views.addarticle,name="addarticle"),
    path('<slug>',views.detail,name="detail"),
    path('edit/<int:id>',views.editArticle,name="edit"),
    path('delete/<int:id>',views.deleteArticle,name="delete"),
    path(_('article/'),views.articles,name="article"),
    path('comment/<int:id>',views.addcomment,name="comment"),
    path('category/<slug>', views.category_detail,name="category_detail" )
]

models.py

from django.db import models
from ckeditor.fields import RichTextField
from django.utils.text import slugify

class Article(models.Model):

    author = models.ForeignKey("auth.User",on_delete = models.CASCADE, verbose_name="Author")
    title = models.CharField(max_length = 120, verbose_name="Title")
    category = models.ForeignKey('Category', on_delete = models.CASCADE, null=True, blank=True)
    content = RichTextField(verbose_name="Content")
    created_date = models.DateTimeField(auto_now_add=True, verbose_name="Created Date")
    image = models.ImageField(blank=True, null=True, verbose_name="Add Image (.jpg .png)")
    slug = models.SlugField(unique=True, max_length = 130)

    def __str__(self):
        return self.title

    def get_unique_slug(self):
        slug = slugify(self.title.replace("ı","i"))
        unique_slug = slug
        counter = 1
        while Article.objects.filter(slug=unique_slug).exists():
            unique_slug = '{}-{}'.format(slug, counter)
            counter += 1
        return unique_slug

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = self.get_unique_slug()
        return super(Article, self).save(*args, **kwargs)

translation.py

from modeltranslation.translator import translator, TranslationOptions
from .models import Article

class ArticleTranslationOptions(TranslationOptions):
    fields = ('title', 'content','slug')

translator.register(Article, ArticleTranslationOptions)

view.py

from django.shortcuts import render,  get_object_or_404
from .models import Article, Category
from django.core.paginator import Paginator
from django.utils.translation import gettext as _

def index(request): 
    from django.utils import translation  
    articles = Article.objects.all()
    category = Category.objects.all()

    context = {
        "articles": articles,
        "category": category,

         }

    return render(request, 'index.html', context)

def detail(request,slug):
    article = get_object_or_404(Article, slug = slug)
    category = Category.objects.all()

    return render(request, "detail.html", {"article":article, "category":category,})



def category_detail(request,slug):
    template = "category_detail.html"

    category=get_object_or_404(Category,slug=slug)
    article=Article.objects.filter(category=category)

    context = {
        'category' : category,
        'article' : article,
    }
    return render(request,template,context)

def category_page(request):
    object_list = Category.objects.all()
    context = {'object_list': object_list,}
    return render(request, 'detail.html', context)

I think i need some changes in urls.py but i dont know :/

Thanks for help...

Aytek
  • 224
  • 4
  • 16
  • 1
    Are you sure you want the slug to be translated? I would think very carefully about this, because if someone with the `fr` setting finds a link somewhere (via Google) with the english slug, it will give a 404. If you really want slugs translated, I would change the detail view to handle all the possible languages by overriding `get_object()` (and either redirect to the url with the translated slug or just leave it in whatever language it was first). – dirkgroten Nov 12 '18 at 16:33
  • hey @dirkgroten thanks for answer. i think actually good for google for seo url. Why would you get a 404 page? And you have a solution for this ? can you show me sample codes please... Thanks – Aytek Nov 13 '18 at 00:16
  • Because the way you describe it, for language `fr` you want the translated slug to be used in the URL, so if someone tries to open the page with the english slug, your view will not find the corresponding object (and `DetailView` will return a 404). – dirkgroten Nov 14 '18 at 10:28
  • Show us your detail view (`views.detail`) that's the one that will handle the translated slugs. – dirkgroten Nov 14 '18 at 10:31
  • @dirkgroten thanks for answer. I added views.py – Aytek Nov 14 '18 at 11:50
  • 1
    Did you ever find a solution for this? I have the same scenario. – Philipp May 11 '19 at 16:17

1 Answers1

1

In your detail view you should try matching the slug for all the languages:

from django.conf import settings
from django.db.models import Q

languages = dict(settings.LANGUAGES).keys()
q = Q()
for lang in languages:
    kwargs = {'slug_%s' % lang: slug}
    q |= Q(**kwargs)
articles = Article.objects.filter(q)
if articles.exists():
    article = articles.first()
else:
    return Http404

If you want to switch the URL to the correct slug for the current language, you could add the following line after article = articles.first():

if not article.slug == slug:  
    # slug is a different language than the current one
    return redirect(reverse("detail", kwargs={'slug': article.slug}))

Note that this will add a round-trip and refetch the same article a second time, but I don't see how you would otherwise change the URL.

dirkgroten
  • 20,112
  • 2
  • 29
  • 42
  • Most likely I couldn't do that. didn't work. I've written these codes into "def detail", but it didn't happen. thank you anyway. my incompetence :/ – Aytek Nov 14 '18 at 15:46
  • I wrote this on mobile so I didn’t test it, was more to give you a direction. What isn’t working? You get an error? – dirkgroten Nov 14 '18 at 16:09
  • Just dosnt work. Url's still doesn't change when I change the language in post. Going to 404 page... when i change language in post, example.com/en/post_en_slug go to example.com/fr/post_en_slug... i need to redirect url example.com/fr/post_fr_slug.. the problem may be caused by me. Probably I couldn't put you codes in my view.py file... – Aytek Nov 14 '18 at 21:56