elkex - I followed these steps:https://twillcm...
# ❓questions
e
I followed these steps: https://twillcms.com/guides/building_a_multilingual_site_with_twill_and_laravel_localization.html#content-create-the-articles-module But the slugs of my model do not seem to translate.. For instance when I am on the registration page in English, it still shows registration as slug in the other languages instead of (NL: registratie, FR: Enregistration) etc..
p
Hi @elkex, just to make sure I understand correctly, is this in an
<a>
tag? The value of the
href
is not translated correctly?
e
Indeed
The route is {slug} (so it is on root level)
But the slugs are not translating in my language switch..
I even added it to lang/nl,fr,ar,en/routes.php however I do not think that is possible because there is nog slug after the root..
p
Ok, just to poke around and understand a bit more: if you enter your translated url manually in the browser's bar, can you reach the translated page?
e
Yes
I created a Singleton to create a navigation and all these URL's translate & work correctly
I added the pages to this singleton in a browser and this all works as a charm & translates correctly etc..
On the homepage the language switch works (because there are no slugs) and the navigation also translates correctly
The URL's come from the CMS btw
p
Not sure I understand this... how do you generate the URLs?
e
web.php
Copy code
Route::group([
    'prefix' => LaravelLocalization::setLocale(),
    'middleware' => ['localize', 'localeSessionRedirect', 'localizationRedirect', 'localeViewPath'],
], function () {
    Route::name('welcome')->get('/', [PageController::class, 'welcomeView']);
    Route::name('page')->get('{page}', [PageController::class, 'index'])->where('page', '.*');
});
p
Sorry, I mean on the front-end. How do you generate the
<a>
tag?
e
Language switch:
Copy code
@foreach (LaravelLocalization::getSupportedLocales() as $localeCode => $properties)
                    <li>
                        <a rel="alternate" hreflang="{{ $localeCode }}"
                            href="{{ LaravelLocalization::getLocalizedURL($localeCode, null, [], true) }}"
                            class="ml-2 text-sm {{ app()->getLocale() === $localeCode ? 'font-bold' : '' }}">
                            {{ strtoupper($localeCode) }}
                        </a>
                    </li>
                @endforeach
And for the general navigation:
Copy code
@foreach ($navigation as $item)
                    <x-nav-link :href="route('page', ['page' => $item->slug])" :active="in_array($item->nestedslug, request::segments())">
                        {{ $item->title }}
                    </x-nav-link>
                @endforeach
So I don't think I'm doing anything special haha
My model has the traits, also the resolveRouteBinding function and the getLocalizedRouteKey functions..
p
Yeah, so far so good 🙂 So again, if I understand correctly,
$item->slug
never returns the correct translated value?
e
It does return the correct slug in the other language
Just not in the language switch
I'm not calling item->slug in the language switch as you can see
p
Ok I see, so the problem is only in the language switcher?
e
It's the language switch that is the problem, not my general navigation
Yes
Once I change the language on the homepage (where it works because there is no slug obviously) the pages show correctly in the language I selected
It's just when I try to change the language from a page (with slug) to another language, the language slug is still in the same language as the current language...
Not of the language it should be according to the language switch
Hope I'm making any sense haha
Visual example might help haha

https://cdn.discordapp.com/attachments/1106563618176245782/1106583749421969560/Screenshot_2023-05-12_at_16.08.37.png

In English it should be /registration, in NL it should be /registratie etc
p
Ok, thanks for the visual, it helps!
Can I have a look at your
resolveRouteBinding()
and
getLocalizedRouteKey()
?
e
Copy code
public function resolveRouteBinding($slug, $field = null)
    {
        $page = app(PageRepository::class)->forSlug($slug);
 
        abort_if(! $page, 404);
 
        return $page;
    }
 
    // #region routekey
    public function getLocalizedRouteKey($locale)
    {
        return $this->getSlug($locale);
    }
p
Did you add the
implements LocalizedUrlRoutable
?
e
Copy code
class Page extends Model implements Sortable, LocalizedUrlRoutable
{
    use HasBlocks, HasTranslation, HasSlug, HasMedias, HasFiles, HasPosition, HasNesting, HasMetadata;
p
Mmmkay. Can I have a look at
lang/fr/routes.php
and
lang/en/routes.php
?
I think I'm starting to get it... your page routes don't have a "prefix", right?
e
Copy code
<?php
 
return [
    'page' => '{page}',
];
p
Right... I think I've never tried this 😄
e
Yes, I don't know what I did
But it seems to work ...
I re-added the translatedROute again in the web.php file
Oké I know what the problem was
Wow
My controller was first like this because I followed the nestedSlug tutotial
Copy code
public function index($slug){
        $page = $this->repository->forNestedSlug($slug);
        abort_unless($page, 404, 'page');
        $this->setMetadata($page);
        return view('pages.index', compact('page'));
    }
But after viewing some other documentation, don't even know what it was anymore.. I changed it to:
Copy code
public function index(Page $page){
        $this->setMetadata($page);
        return view('pages.index', compact('page'));
    }
Maybe I can come work for you guys as difficult bug reporter haha
p
Ah nice! So
index(Page $page)
works for top-level pages (like /nl/registratie) ?
e
Yes!
p
And for nested pages?
e
I'll try that later for you is that ok?
But I think it should..
Oké I'll test it haha
p
For sure, just curious. Let me know when you work on it 🙌
e
I will ! (Prolly on Monday haha)
p
Nice, enjoy the weekend then 😄
e
It does not work for nested slugs it seems..
I don't think it recognises the page from the where clause:
Copy code
Route::name('page')->get(LaravelLocalization::transRoute('routes.page'), [PageController::class, 'index'])->where('page', '.*');
It does not work with nestedSlugs it seems.. The localisation needs to use the model to get the right content etc in the controller function it seems.. The nestedSlug needs to get the instance of nestedSlug in the function so there is a dilemma
The nestedSlug url's do not seem to exist....
Nested modules do not work with the translated slug...
i
they do, I'm not sure what you mean
e
The nested pages only seems to work with the forNestedSlug property in the controller, if not, the page does not even seem to exist.. So like this:
Copy code
public function index($slug)
    {
        $page = $this->repository->forNestedSlug($slug);
        $this->setMetadata($page);
        return view('pages.index', compact('page'));
    }
But the translation of the slugs only seems to work if the function in the controller contains the model like this:
Copy code
public function index(Page $page)
    {
        $this->setMetadata($page);
        return view('pages.index', compact('page'));
    }
I have not found a workaround to combine the two though...
p
@elkex Have you tried extending
resolveRouteBinding
? Something like this :
Copy code
php
    public function resolveRouteBinding($slug, $field = null)
    {
        if ($page = app(PageRepository::class)->forNestedSlug($slug)) {
            return $page;
        }

        if ($page = app(PageRepository::class)->forSlug($slug)) {
            return $page;
        }

        abort(404);
    }
(not tested...)
Oh, the second
if
might not even be necessary.
e
It conflicts with the returning of the data..
If I use this the translation of the slugs works (not child pages)
Copy code
public function index(Page $page)
    {
        $this->setMetadata($page);
        return view('pages.index', compact('page'));
    }
If I use this: child pages slugs work but not the translations..
Copy code
public function index($slug)
    {
        $page = $this->repository->forNestedSlug($slug);
        $this->setMetadata($page);
        return view('pages.index', compact('page'));
    }
p
Hi @elkex, here's what works for me on
3.x
routes/web.php
Copy code
php
    Route::get(LaravelLocalization::transRoute('routes.page'), function (SitePage $page) {
        return view('site.pages.show', ['page' => $page]);
    })
        ->where(['page' => '.*'])
        ->name('page');
(This is basically equivalent to your first controller example above.) Model
Copy code
php
    public function resolveRouteBinding($slug, $field = null)
    {
        $page = app(SitePageRepository::class)->forNestedSlug($slug);

        abort_if(! $page, 404);

        return $page;
    }

    public function getLocalizedRouteKey($locale)
    {
        return $this->getSlug($locale);
    }

    public function getAncestorsSlug($locale = null)
    {
        return collect($this->ancestors->sortByDesc('position') ?? [])
            ->map(function ($i) use ($locale) { return $i->getSlug($locale); })
            ->implode('/');
    }
I had to override
getAncestorsSlug()
in the model to a previous version of the method. I'm not exactly sure why the new one doesn't work in my case.
e
How can this be fixed for Twill 2.0? The environment only supports 7.3 unfortunately..
PHP 7.3.. Is that compatible with Twill 3?
i
nope, Twill 3 is PHP 8+
the code @pboivin provided should work fine on Twill 2 though
e
You also place the getAncestorsSlug in the model right?
i
the implementation above is exactly what is already in twill 2
e
So weird.. The frontend should still be like this like the docs right?:
Copy code
php
 @foreach (LaravelLocalization::getSupportedLocales() as $localeCode => $properties)
                    <li>
                        
                        <a rel="alternate" hreflang="{{ $localeCode }}"
                            href="{{ LaravelLocalization::getLocalizedURL($localeCode, null, [], true) }}"
                            class="ml-2 text-sm {{ app()->getLocale() === $localeCode ? 'font-bold' : '' }}">
                            {{ strtoupper($localeCode) }}
                        </a>
                        
                       
                    </li>
                @endforeach
i
yes
e
It works perfectly for first level items but not for second level items.. That's the weirdest part
The nested pages do not seem to exist either, only with the slug as parameter.. So like this:
Copy code
php
public function index($slug)
    {
        $page = $this->repository->forNestedSlug($slug);
        $this->setMetadata($page);
        return view('pages.index', compact('page'));
    }
And not with the model as param.. It returns 404
Copy code
php
public function index(Page $page)
    {
        $this->setMetadata($page);
        return view('pages.index', compact('page'));
    }
Okay so.. Something new I might have discovered is that the slugs of the first level parent do not seem to translate in the backend.. And I think that is the slug it is using for the translation.. However in the frontend it seems so exist.. Very weird..
So English: /teachers/apply Dutch should be: /leerkrachten/apply-nl but the backend shows /teachers/apply-nl However /leerkrachten/apply-nl exists in the frontend and shows the correct page..
This is what it still shows like in the backend

https://cdn.discordapp.com/attachments/1106563618176245782/1110217189472096326/Screenshot_2023-05-22_at_16.46.31.png

Is it normal that the slugs of nested pages not translate in the backend?
p
e
According to this, where does the TwillModelContract come from?
Okay so this issue is fixed... I just had to change getSlug to getNestedSlug in the getLocalizedRouteKey function