Skip to content

Commit c012bf4

Browse files
feat: support multi-language kirby sites
1 parent 21a77b2 commit c012bf4

File tree

10 files changed

+135
-13
lines changed

10 files changed

+135
-13
lines changed

docs/.vitepress/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ function sidebarGuide(): DefaultTheme.SidebarGroup[] {
8686
collapsible: true,
8787
items: [
8888
{ text: 'Token-Based Authentication', link: '/guide/token-authentication' },
89+
{ text: 'Multi-Language Sites', link: '/guide/multi-language-sites' },
8990
],
9091
},
9192
{

docs/api/kql.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Query responses are cached by default.
99
```ts
1010
function $kql<T extends KirbyQueryResponse = KirbyQueryResponse>(
1111
query: KirbyQueryRequest,
12-
options: KqlOptions = {},
12+
opts: KqlOptions = {},
1313
): Promise<T>
1414

1515
interface KqlOptions {
@@ -19,6 +19,14 @@ interface KqlOptions {
1919
* @default true
2020
*/
2121
cache?: boolean
22+
/**
23+
* Language code to fetch data for in multilang Kirby setups
24+
*/
25+
language?: string
26+
/**
27+
* Custom headers to send with the request
28+
*/
29+
headers?: HeadersInit
2230
}
2331
```
2432

docs/api/public-kql.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@ function $publicKql<T extends KirbyQueryResponse = KirbyQueryResponse>(
1515
): Promise<T>
1616

1717
// `FetchOptions` imported from `ohmyfetch`
18-
type PublicKqlOptions = Omit<FetchOptions, 'baseURL' | 'body' | 'params' | 'parseResponse' | 'responseType' | 'response'>
18+
type PublicKqlOptions = Omit<
19+
FetchOptions,
20+
'baseURL' | 'body' | 'params' | 'parseResponse' | 'responseType' | 'response'
21+
> & {
22+
/**
23+
* Language code to fetch data for in multilang Kirby setups
24+
*/
25+
language?: string
26+
}
1927
```
2028
2129
## Example

docs/api/use-kql.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function useKql<
1212
ReqT extends KirbyQueryRequest = KirbyQueryRequest,
1313
>(query: Ref<ReqT> | ReqT, opts?: UseKqlOptions<ResT>): AsyncData<ResT, true | Error>
1414

15-
export type UseKqlOptions<T> = Omit<
15+
type UseKqlOptions<T> = Omit<
1616
UseFetchOptions<T>,
1717
| 'baseURL'
1818
| 'params'
@@ -22,7 +22,12 @@ export type UseKqlOptions<T> = Omit<
2222
| 'response'
2323
| 'transform'
2424
| keyof Omit<globalThis.RequestInit, 'headers'>
25-
>
25+
> & {
26+
/**
27+
* Language code to fetch data for in multilang Kirby setups
28+
*/
29+
language?: string
30+
}
2631
```
2732
2833
`useKql` infers all of Nuxt's [`useAsyncData` options](https://v3.nuxtjs.org/api/composables/use-async-data#params).

docs/api/use-public-kql.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ function usePublicKql<
1616
ReqT extends KirbyQueryRequest = KirbyQueryRequest,
1717
>(query: Ref<ReqT> | ReqT, opts?: UseKqlOptions<ResT>): AsyncData<ResT, true | Error>
1818

19-
export type UseKqlOptions<T> = Omit<
19+
type UseKqlOptions<T> = Omit<
2020
UseFetchOptions<T>,
2121
| 'baseURL'
2222
| 'params'
@@ -26,7 +26,12 @@ export type UseKqlOptions<T> = Omit<
2626
| 'response'
2727
| 'transform'
2828
| keyof Omit<globalThis.RequestInit, 'headers'>
29-
>
29+
> & {
30+
/**
31+
* Language code to fetch data for in multilang Kirby setups
32+
*/
33+
language?: string
34+
}
3035
```
3136
3237
`usePublicKql` infers all of Nuxt's [`useAsyncData` options](https://v3.nuxtjs.org/api/composables/use-async-data#params).

docs/guide/multi-language-sites.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Multi-Language Sites
2+
3+
`nuxt-kql` comes with built-in support for multi-language Kirby sites. For this to work, you will have to use the [kirby-headless-starter](https://github.com/johannschopplich/kirby-headless-starter), which provides a custom KQL endpoint to retrieve translated content.
4+
5+
To fetch language-specific content from your Kirby instance, pass a `language` option with your query request for every language but the primary one.
6+
7+
Take the following example to fetch data from the about page, where `en` is the default language, `de` the secondary one. The `en` slug is called `about`, the `de` slug `ueber-uns`.
8+
9+
```ts
10+
// Since `en` is the default language, the `language` option isn't needed
11+
const { data } = await useKql({
12+
query: 'kirby.page("home")'
13+
})
14+
15+
// For the `de` slug to be found, add the `language` option
16+
const { data } = await useKql(
17+
{
18+
query: 'kirby.page("ueber-uns")'
19+
},
20+
{
21+
language: 'de'
22+
}
23+
)
24+
```
25+
26+
## Dynamic Routes
27+
28+
You will probably use some kind of dynamic routes in your Nuxt application. To make your life easier fetching translated content, you can create a `useLocaleSlug` composable to extract both a page's `slug` and its language code:
29+
30+
```ts
31+
// `/composables/language.ts`
32+
33+
// Extract language code and slug from path
34+
export function useLocaleSlug(path: string) {
35+
const segments = path.split('/').filter(i => i !== '')
36+
37+
return {
38+
language: segments[0],
39+
slug: segments.slice(1).join('/'),
40+
}
41+
}
42+
```
43+
44+
Now you can simplify your templates. For example in `/pages/[...id].vue`:
45+
46+
```vue
47+
<script setup lang="ts">
48+
const route = useRoute()
49+
const { language, slug } = useLocaleSlug(route.path)
50+
51+
const { data } = await useKql({
52+
query: `kirby.page("${slug}")`
53+
}, { language })
54+
</script>
55+
```

src/runtime/composables/$kql.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { hash } from 'ohash'
2+
import { headersToObject } from '../utils'
23
import type { KirbyQueryRequest, KirbyQueryResponse } from '#nuxt-kql'
34
import { useNuxtApp } from '#imports'
45
import { apiRoute } from '#build/nuxt-kql/options'
@@ -10,15 +11,29 @@ export interface KqlOptions {
1011
* @default true
1112
*/
1213
cache?: boolean
14+
/**
15+
* Language code to fetch data for in multilang Kirby setups
16+
*/
17+
language?: string
18+
/**
19+
* Custom headers to send with the request
20+
*/
21+
headers?: HeadersInit
1322
}
1423

1524
export function $kql<T extends KirbyQueryResponse = KirbyQueryResponse>(
1625
query: KirbyQueryRequest,
17-
options: KqlOptions = {},
26+
opts: KqlOptions = {},
1827
): Promise<T> {
19-
const body = { query }
28+
const body = {
29+
query,
30+
headers: {
31+
...headersToObject(opts.headers),
32+
...(opts.language ? { 'X-Language': opts.language } : {}),
33+
},
34+
}
2035

21-
if (options.cache === false) {
36+
if (opts.cache === false) {
2237
return $fetch<T>(apiRoute, {
2338
method: 'POST',
2439
body,

src/runtime/composables/$publicKql.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,15 @@ import { getAuthHeaders, headersToObject } from '../utils'
44
import type { KirbyQueryRequest, KirbyQueryResponse } from '#nuxt-kql'
55
import { useRuntimeConfig } from '#imports'
66

7-
export type PublicKqlOptions = Omit<FetchOptions, 'baseURL' | 'body' | 'params' | 'parseResponse' | 'responseType' | 'response'>
7+
export type PublicKqlOptions = Omit<
8+
FetchOptions,
9+
'baseURL' | 'body' | 'params' | 'parseResponse' | 'responseType' | 'response'
10+
> & {
11+
/**
12+
* Language code to fetch data for in multilang Kirby setups
13+
*/
14+
language?: string
15+
}
816

917
export function $publicKql<T extends KirbyQueryResponse = KirbyQueryResponse>(
1018
query: KirbyQueryRequest,
@@ -23,6 +31,7 @@ export function $publicKql<T extends KirbyQueryResponse = KirbyQueryResponse>(
2331
headers: {
2432
...headersToObject(opts.headers),
2533
...getAuthHeaders(kql as ModuleOptions),
34+
...(opts.language ? { 'X-Language': opts.language } : {}),
2635
},
2736
})
2837
}

src/runtime/composables/useKql.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { hash } from 'ohash'
33
import type { Ref } from 'vue'
44
import type { NitroFetchRequest } from 'nitropack'
55
import type { AsyncData, UseFetchOptions } from 'nuxt/app'
6+
import { headersToObject } from '../utils'
67
import type { KirbyQueryRequest, KirbyQueryResponse } from '#nuxt-kql'
78
import { useFetch } from '#imports'
89
import { apiRoute } from '#build/nuxt-kql/options'
@@ -17,7 +18,12 @@ export type UseKqlOptions<T> = Omit<
1718
| 'response'
1819
| 'transform'
1920
| keyof Omit<globalThis.RequestInit, 'headers'>
20-
>
21+
> & {
22+
/**
23+
* Language code to fetch data for in multilang Kirby setups
24+
*/
25+
language?: string
26+
}
2127

2228
export function useKql<
2329
ResT extends KirbyQueryResponse = KirbyQueryResponse,
@@ -34,7 +40,10 @@ export function useKql<
3440
method: 'POST',
3541
body: {
3642
query: _query.value,
37-
headers: opts.headers,
43+
headers: {
44+
...headersToObject(opts.headers),
45+
...(opts.language ? { 'X-Language': opts.language } : {}),
46+
},
3847
},
3948
}) as AsyncData<ResT, true | Error>
4049
}

src/runtime/composables/usePublicKql.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@ export type UseKqlOptions<T> = Omit<
1818
| 'response'
1919
| 'transform'
2020
| keyof Omit<globalThis.RequestInit, 'headers'>
21-
>
21+
> & {
22+
/**
23+
* Language code to fetch data for in multilang Kirby setups
24+
*/
25+
language?: string
26+
}
2227

2328
export function usePublicKql<
2429
ResT extends KirbyQueryResponse = KirbyQueryResponse,
@@ -43,6 +48,8 @@ export function usePublicKql<
4348
headers: {
4449
...headersToObject(opts.headers),
4550
...getAuthHeaders(kql as ModuleOptions),
51+
...(opts.language ? { 'X-Language': opts.language } : {}),
52+
4653
},
4754
}) as AsyncData<ResT, true | Error>
4855
}

0 commit comments

Comments
 (0)