Multilingual menu and tagclouds

I’m working on trilingual website

what I need is :

the mainmenu showing only these menuitems which are translated into the active language
(ex.: “blog” will display in the mainmenu for /en/ users only if there is a file /en/blog/blog.en.txt"… and so on)

the sitewidetagcloud in the footer should be filtered by language as well
(each .txt file contains “Tags:” field with tags labeled in appropriate language)

the “listbytags” page where, without changing the active language, users could choose to see all “language1tags”, “language2tags”, language3tags" by clicking the appropriate button

still the same “listbytags” page where, without changing the active language, users could list all the pages tagged with “Year” (nevermind the language)

a private webmaster page that lists all the pages/subpages/subsubpages… where I could see, at a glance, side-by-side, available translations
I mean a table like :

| UID | LANG 1 | LANG 2 | LANG 3 |
| uid | not yet | ok | not yet |

anyone could help ?

The content class provides the functionality you need,, especially content($lang)->exists().

ad 4) You could achieve that via a page on the front end that is hidden behind a login (using a route to create the URL).

1 Like

seems logical and would be nice. The problem is that
sends true (or is ignored ?) even if there is no translation available.
What it may come from ?

The function should return false if the content file does not exist; it will, however, return true, if the file exists and there is no translated content in it. The content file for the default language is always created via the panel, even if you only create content in a non-default language. The other languages are not created by default, only if you actually save the (empty) content.

So does the function really return true even if the file does not exist?

Kirby 2.3 will have the $field->isTranslated() method which will let you check if a field is actually translated (as compared to the default language).

Edit: I just tested this and indeed, it does not seem to work. I could have sworn it worked when I tested this a little while ago.

I created an issue on GitHub.

Edit: But maybe it is not even supposed to work like this.

Anyway, there is an alternative:

<?php if($page->content()->language() == $site->language()->code()): ?>
  //do stuff
<?php endif ?>

Are you testing $page->content($lang)->exists() or $page->content($lang)->$field()->exists()? The latter should work, while the first example would just return an empty “exists” field.

In fact I tested the first; looks like I have to change the docs.

I just checked in the source code. There is a Content::exists() method and it checks if the content file exists. So the docs are correct. Strange that it is not working for you.

Yeah, I checked the source code as well, but maybe it is language agnostic? I wonder if any of these work with the language code; I just added the codes after @distantnative’s remark … Need to check that again, or it should be implemented in the upcoming version.

Only texnixe alternative solution seems to work as expected.

…but I don’t find how it could suit my need :confused:

What exactly do you mean?

E.g. to filter the menu items, you could do this:

    <?php foreach ($site->pages()->visible() as $p): ?>
      <?php if ($p->content()->language() == $site->language()): ?>
        <li><a href="<?= $p->url() ?>"><?= $p->title() ?></a></li>
      <?php endif ?>
    <?php endforeach ?>

that’s true for the mainmenu, thanks texnixe

I meant that your workaround seems hard to be converted as replacement of “if($page->content($lang)->exists())… do the stuff” because it applies to 1 language at a time, while - to solve my point 4 (see my first post) - I need all languages side-by-side

as for lang sensitive tagclouds (pt 2, 3a, 3b) I don’t see how to convert your workaround into a variable. I’ve tried some other ways :

  • I added an appropriate language code to each “Tags:” field in aim to “filterby(’tags’, $activelang)” the results coming from tagcloud plugin. The final results are incorrect, depending on language.
  • I’ve tried to add “case ‘lang’” to tagcloud plugin $options. Unsuccessfully (the new “case” was ignored).
  • I’ve tried multiple tagclouds but once I loose pagination, once home pages.

That’s where I am at the moment.

Yeah, but you should be able to get all the relevant information by looping through all languages and then check for each language if the page exists, something like that:

$languages = $site->languages();
foreach ($site->index() as $p) {
  foreach($languages as $l) {
    if($p->content()->language() == $l) {
      //do stuff

Or maybe the other way round, if you want to get your table style. Not tested …

you’re pretty reactive, texnixe
thanks for track
I will feedback

Here is what I found to satisfy pt 4 (see initial post above) thanks to your suggestions, Texnixe.

The table lists pages/urls in given language only if corresponding “.lang.txt” file phisically exists. It bypasses Kirby internal logic with strpos() which allows to have correct aswers even when there are pages that doesn’t exist in default language.


$languages = $site->languages();
foreach ($site->index() as $p) {
$pen = $p->content('en')->root();
$pfr = $p->content('fr')->root();
$pes = $p->content('es')->root();
  foreach($languages as $l) {
    if($p->content()->language() == $l) {

echo '<tr>';

// EN
if(strpos($pen, 'en.txt')) { 
echo '<td><a href="' . $p->url('en') . '">' . $p->content('en')->title() . '</a></td>';
} else { 
echo '<td>---</td>';

// FR
if(strpos($pfr, 'fr.txt')) { 
echo '<td><a href="' . $p->url('fr') . '">' . $p->content('fr')->title() . '</a></td>';
} else { 
echo '<td>---</td>';

// ES
if(strpos($pes, 'es.txt')) { 
echo '<td><a href="' . $p->url('es') . '">' . $p->content('es')->title() . '</a></td>';
} else { 
echo '<td>---</td>';

echo '</tr>';


It could be compacted with another foreach loop but I’m fed up with it.

Hope it can be useful for someone before $page->content($lang)->exists() acts as expected.

By the way I ask myself whether I shouldn’t use similar approach to filter tagcloud by languages.
Any better idea ?