Closed antoine3000 closed 5 months ago
Sure, you can create a API route in the backend:
use JohannSchopplich\Headless\Api\Api;
use JohannSchopplich\Headless\Api\Middlewares;
use Kirby\Cms\App;
use Kirby\Cms\Language;
return [
'routes' => function (App $kirby) {
return [
[
'pattern' => '__translations__',
'method' => 'GET',
'auth' => false,
'action' => Api::createHandler(
[Middlewares::class, 'hasBearerToken'],
function () use ($kirby) {
$languages = $kirby
->languages()
->map(
fn (Language $language) => [
'code' => $language->code(),
'translations' => $language->translations()
]
)
->values();
return Api::createResponse(200, $languages);
}
)
]
];
}
];
And then create a module in the frontend under modules/translation-prefetch.ts
that prefetches your language at build-time (will be run by Nuxt automatically, ne need to add it to your Nuxt config):
import { writeFile } from 'node:fs/promises'
import { joinURL } from 'ufo'
import { ofetch } from 'ofetch'
import type { KirbyApiResponse } from 'kirby-types'
import { defineNuxtModule, useLogger } from 'nuxt/kit'
type KirbyTranslationsResponse = KirbyApiResponse<
{
code: string
translations: Record<string, string>
}[]
>
export default defineNuxtModule({
meta: {
name: 'translations-prefetch',
},
async setup(options, nuxt) {
const logger = useLogger('translations-prefetch')
const start = Date.now()
const $kirby = ofetch.create({
baseURL: process.env.KIRBY_BASE_URL,
headers: {
Authorization: `Bearer ${process.env.KIRBY_API_TOKEN}`,
},
})
try {
const response = await $kirby<KirbyTranslationsResponse>(
'api/__translations__',
)
for (const language of response.result!) {
const nestedTranslations = flatToNestedTranslations(
language.translations,
)
await writeFile(
joinURL(nuxt.options.rootDir, 'locales', `${language.code}.json`),
JSON.stringify(nestedTranslations, null, 2),
'utf-8',
)
}
logger.info(
`Prefetched Kirby language translations ${Date.now() - start}ms`,
)
} catch (error) {
logger.error(error)
logger.error('Failed to prefetch Kirby language translations')
}
},
})
function flatToNestedTranslations(
translations: Record<string, string>,
): Record<string, any> {
const nestedObject: Record<string, any> = {}
for (const [key, value] of Object.entries(translations)) {
let currentLevel = nestedObject // Start at the root of the nested object
const parts = key.split('.')
for (const [index, part] of parts.entries()) {
if (index === parts.length - 1) {
// If we're at the last part, assign the value
currentLevel[part] = value
} else {
// If we're not at the last part, either use the existing object or create a new one
currentLevel[part] = currentLevel[part] || {}
// Move down one level in the nested structure
currentLevel = currentLevel[part]
}
}
}
return nestedObject
}
Now, all your locales are available in the frontend. Make sure to exclude the prefetched files from your Git repo.
It works perfectly, huge thanks @johannschopplich!
Hello,
Is there a way to use Kirby's language variables, rather than having to duplicate them in Nuxt?
Thanks!