Filter child pages by available translations

I’m wondering what’s the best and cleanest way to filter (grand-)child pages by available languages? In my template I only want to display those children that have a translation in the currently selected language.

I was thinking of something like this

foreach ($page->children()->filterBy('languages', '*=', $site->language()->code() as $child) {
    ....
}

Should I create a custom filter, use the filter method with a callback or is there actually a build-in method that I didn’t find yet?

I think this article by @texnixe might help you: https://www.texniq.de/en/texniq-u/kirby-multilingual-site

I think that article is a bit outdated cause it was written for Kirby 1, so there might now be an easier way of doing it using a custom filter. An alternative would be to use a separate language field in the files.

Ah sorry, wasn’t aware of this. My bad.

That’s exactly what I ended up doing:

foreach ($page->children()->filterBy('languages', $site->language()->code(), ',') as $child) {
    ...
}

I feel like there should be an easier, native way to achieve this.

I totally agree with @FabianSperrle; Kirby core should definitely expose available translations/language versions of pages as standard data fields —for both filterBy and//or sortBy method chaining. Any plans @bastianallgeier?

So, @FabianSperrle, here is the custom filter I added to /site/plugins/filters.php:

collection::$filters['languageIs'] = function($collection, $field, $value) {

  foreach($collection->data as $key => $item) {
    // if(str::startsWith(collection::extractValue($item, $field), $value)) continue;
    if (collection::extractValue(collection::extractValue(collection::extractValue($item, 'content'), 'language'), $field) != $value){
      unset($collection->$key);
    }
  }

  return $collection;

};

You then can filter by language with, for example, this:

$page->children()->filterBy('code', 'languageIs', 'ja')

Have fun,
Moritz

P.S. @distantnative and @texnixe: the solution above does not looks very performant to my eyes. If you have and input on optimizations, I’m eager to listen up. Even though I’m still convinced, Kirby core should expose language fields to filterBy by default.

There used to be a feature request but it was withdrawn because filtering can be done via a custom filter:

$articles = $page->children()->visible()->filter(function($child) {
     return site()->language()->code() == $child->language()->code();
});

Here’s the filter incorporating @texnixe’s helpful input:

// Anything that matches a given language attribute
collection::$filters['languageIs'] = function($collection, $field, $value) {

  foreach($collection->data as $key => $item) {
    if (collection::extractValue($item->content()->language(), $field) != $value) {
      unset($collection->$key);
    }
  }

  return $collection;

};

Add this to your site/plugin/filters.php and use the following in your templates:

$articles = $page->children()->visible()->filterBy('code', 'languageIs', 'ja');

Thanks,
Moritz