Language switcher example creating invalid URLs for missing translations

Hi,

Regarding language control and Switch B which is giving me hard times:
http://getkirby.com/docs/languages/switching-languages

The given example only creates valid results in case of existing content (text files) at the target destination.

foreach($site->languages() as $language): 
$site->page()->url($language->code());

If there are no text files in other languages available, kirby will create “invalid” URLs by just adding a language slug (e.g. “en”) to the original URL. This leads to further problems when using functions like filemtime() on non-existing files.

For this reason, I would need to know how to check the returned absolute string with kirby’s API to send the user to another page in his/her language.

Wouldn’t it be more convenient, if kirby returned a page-like object or null instead of a string?

Any help is appreciated. Thank you!

What do you mean by invalid? Does it produce an error message?

Kirby’s default behavior is to show the content of the default text file if the text file of the non-default language is missing or the fields are empty.

You can prevent this behavior if you filter your pages by language (using a custom filter); you could also check if the content file exists for a language and not show the language switcher in this case or redirect to another page.

Hi texnixe,

Thanks for your response.

Let’s say, I have German as default language and I have an English blog entry:
http://mydomain.local/en/blog/english-news-entry-1

There is a folder representing this page which is available in English only.
1-blog/02-english-news-entry-1

Inside this folder, there is a file named
blogarticle.en.txt

Being on this page as a user, my language switcher offers me a link for German like:
http://mydomain.local/blog/english-news-entry-1

But as there is no blogarticle.de.txt, visiting the “invalid” location results in kirby offering the same English content but changing return attributes like

$page->textfile()

to a non existing location.

My goal is to check, if there is a translation available in other languages. If so, provide the link (this already works). If not, link to front page, or even better, link to a search page of the language with a suitable message.

Right now, I have the following code:

<?php foreach($site->languages() as $language): 
                 
            // get page URL string in other language
            $pageTranslation = $site->page()->url($language->code());
            // how to check for valid url?
            // Created a boolean function isValidTranslationURL below, but I do not know how to check the string with kirby's API
        ?>
        <li <?php e($language->code() == site()->language()->code(),'class="link-active"') ?> >
            <a href="<?php echo (isValidTranslationURL($pageTranslation) ? $pageTranslation : $language->url()) ?>" title="<?php echo $language->name()?>">
                <img src="/assets/images/<?php echo $language->code ?>.png" width="16" height="11" alt="<?php echo Helpers::getCountryByLanguageCode($language->code()) ?>"></img>
                <?php echo html($language->name()) ?>
            </a>
        </li>
 <?php endforeach ?>

@texnixe

How can I do this with the returned url string? This would solve my problem, I guess.

Okay, I found a solution on my own. Did not know, there is an inventory array… It is not documented anywhere as far as I could see… :sweat:

         <?php           
            // get the current page's inventory
            $inventory = $site->page()->inventory();
            $translatedContents = $inventory['content'];
                
            foreach($site->languages() as $language):
                              
                // false in the beginning
                $isTranslationAvailable = false; 
            
                // get page URL
                $pageTranslationURL = $site->page()->url($language->code());               
                
                if(array_key_exists($language->code, $translatedContents)) {
                    // explode array from file name
                    $filename = explode(".", $translatedContents[$language->code]);
                     
                    // retrieve language chunk from file's name
                    if(count($filename) > 2) {                               
                        if($filename[count($filename)-2] == $language->code()) {
                            $isTranslationAvailable = true;
                        }                                                    
                    }                    
                }
            ?>
            <li <?php e($language->code() == site()->language()->code(),'class="link-active"') ?> >
                <a href="<?php echo  ($isTranslationAvailable ? $pageTranslationURL : $site->url()) ?>" title="<?php echo $language->name()?>">
                    <img src="/assets/images/<?php echo $language->code ?>.png" width="16" height="11" alt="<?php echo Helpers::getCountryByLanguageCode($language->code()) ?>"></img>
                    <?php echo html($language->name()) ?>
                </a>
            </li>
           <?php endforeach ?>
1 Like

You could try this:

<nav class="languages" role="navigation'"> 
  <?php foreach($site->languages() as $language): ?>
       <?php //if($page->content($language->code())->language() == $site->language($language->code())): ?>
      <?php if(($site->language() != $language)): ?>
        <span>
          <a href="<?php e($page->content($language->code())->language() != $site->language($language->code()), page('error')->url($language->code()), $page->url($language->code()))?>"><?php echo $language->code(); ?></a> 
        </span> 
      <?php endif ?>
    <?php //endif ?>
  <?php endforeach ?>
</nav>

You can use the uncommented lines to only display the switch if the content in that language exists. Then you would not need the if-statement within the link tag.

1 Like

Hi texnixe,

Thank you very much for your advice. Your code uses kirby’s API only which I find much better than messing around with URLs stored in arrays.

I have to confess that code like

$page->content($language->code())->language()->code()

is hard to comprehend when learning a new API. I did not find any information in the documentation on what can be done with a returned content element.

Now I have learned something new. Thank you! :smile:

My language switcher is part of a global navigation menu. There should be a switch to change languages at all times, even if there is no translation of the page available. For this reason, I will stick with your error page version.

Come to think of it, you don’t even need the double code … I changed it in the code snippet above.

1 Like

Maybe your example should be added to the documentation as “Switch C” to help newbies?

I agree, and will take care of that.

Edit: Done.

A post was merged into an existing topic: Check if language file loaded or default is loaded