Question regarding multilingual block snippets rendered via toBlocks()->toHtml()

Our Kirby API is returning each language in one response, and is doing something like so (apologies if I am going about this the wrong way):

$langs = ['en', 'de', 'cn'];

foreach($langs as $lang):
  $p = $this->content($lang);
  return $p->blocks()->toBlocks()->toHtml();
endforeach;

I noticed this problem when trying to output the image caption:

/snippets/blocks/gallery.php

...
<figcaption><?= $image->caption()->kirbytextinline() ?></figcaption>
...

My snippet is always rendering in the default en language, and not in the language triggered by the toHtml() render.

Should I be setting the language somehow in the Kirby object? Or how should I be doing this?

I am using Kirby 3.5.3

AFAIK visit “sets” the language of the Kirby object to the correct language: $site->visit($this, $lang). So maybe this would do it (untested):

$langs = ['en', 'de', 'cn'];

foreach($langs as $lang):
  $site->visit($this, $lang);
  return $this->blocks()->toBlocks()->toHtml();
endforeach;

More: $site->visit() | Kirby

Ah that really seems like exactly what I want but it isn’t working for some reason.

For example, I am in a template: project.json.php

<?php

$langs = [
  'en',
  'de',
  'cn'
];

$response = [];

foreach($langs as $lang):
  $site->visit($page, $lang);
  $response[$lang] = $page->blocks()->toBlocks()->toHtml();
endforeach;

return $response;

Somehow this is always in en still. Even basic things like $page->title() are also still always in en.

I’m confused… If you want to do this inside a content representation template, the Kirby router takes care of this for you via the URL parameter. I don’t even know if $site->visit() still works here.

It might be better to fetch content in all languages via a custom route?
Not really sure if that would make the blocks render out the translated content though!

Yes, perhaps it’s a poor solution but I was just returning all languages in the json template to avoid having to fetch multiple requests to load each language into the frontend vue app (each language needs to display simultaneously).

What is odd is that the snippets are actually rendered in the correct language, but trying to fetch the caption for the corresponding image in the gallery block is not:

<?php
/** @var \Kirby\Cms\Block $block */ ?>
<figure>
  <ul>
    <?php foreach ($block->images()->toFiles() as $image) : ?>
      <li>
        <?= $image ?> // The image itself is correct
        <figcaption><?= $image->caption()->kirbytextinline() ?></figcaption> // The caption is not
      </li>
    <?php endforeach ?>
  </ul>
</figure>

OK I think I have found the root if the issue, we have projects with multiple fields. However, one field is a set of gallery blocks that uses the same images across each language. As a result, we made that field non-translatable to avoid confusion.

So I think the question is more explicitly: Is it possible to set the language or pass a variable to a snippet through toBlocks() or toHtml() so something like the image caption can be rendered in the desired language?

Doesn’t it work if you use the language code in the block snippet for those field that are non-translatable:

<figcaption><?= $image->content('de')>caption()->kirbytextinline() ?></figcaption> 

(or whatever your default language is)

Yes that’s correct, it does work there, but I’m wondering how to get the language inside the snippet when it is rendered via toBlocks()->toHtml().

In the template, $kirby->language() always returns en.

Why would you have to do that if it just affects non-translatable fields?

If you want to pass something to blocks snippets explicitly, you can render the blocks in a loop rather then through ->toBlocks()

In this case, the projects utilized the same selection of images through the gallery block, but the caption but their captions need to display in their corresponding languages.

I’m just surprised there’s no way to access the current language inside the snippet.

This is an awful solution, but in the meantime I just set $GLOBALS['snippet_lang'] = $lang in the API call and fetch it in the snippet :nauseated_face:

Would love to know if there’s a better way.