Skip to content

Commit 11d9814

Browse files
committed
Add Integration with Locales
1 parent 35f77c9 commit 11d9814

File tree

5 files changed

+72
-104
lines changed

5 files changed

+72
-104
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"openapi":"3.0.3","info":{"title":"Localess Open API Specification","version":"2.4.1","description":"Fetch data from Localess via REST API","contact":{"name":"Lessify Team","email":"info@lessify.io","url":"https://github.com/Lessify"},"license":{"name":"MIT License","url":"https://github.com/Lessify/localess/blob/main/LICENSE"}},"externalDocs":{"url":"https://localess.org/docs/api/overview","description":"Localess Documentation"},"paths":{"/api/v1/spaces/{spaceId}/translations/{locale}":{"get":{"tags":["Translations"],"summary":"Retrieve all Translations by Locale","description":"The endpoint allows you to retrieve all translations by locale. In case Locale is not present in the Localess, it will return the default locale translations. In case cache version is not present, it will redirect to the latest version.","operationId":"getTranslationsByLocale","parameters":[{"name":"spaceId","in":"path","description":"Unique identifier for the Space object.","required":true,"schema":{"type":"string","example":"UdV5ygPZuOD1JMO9Qat9"}},{"name":"locale","in":"path","description":"Locale unique identifier (ISO 639-1).","required":true,"schema":{"type":"string","example":"en"}},{"name":"cv","in":"query","description":"Cache version.","required":false,"schema":{"type":"string","example":"1706217382028"}},{"name":"token","in":"query","description":"Authentication Token.","required":true,"schema":{"type":"string","example":"fb6oTcVjbnyLCMhO2iLY"}}],"responses":{"200":{"description":"Return the Translations Object if the request succeeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Translations"}}}}},"security":[{"apikey":[]}]}},"/api/v1/spaces/{spaceId}/links":{"get":{"tags":["Contents"],"summary":"Retrieve Links to all Contents","description":"The endpoint allows you to retrieve all Content summery metadata mainly used to recreate content tree. In case cache version is not present, it will redirect to the latest version.","operationId":"getContentLinks","parameters":[{"name":"spaceId","in":"path","description":"Unique identifier for the Space object.","required":true,"schema":{"type":"string","example":"UdV5ygPZuOD1JMO9Qat9"}},{"name":"kind","in":"query","description":"Content Kind. FOLDER or DOCUMENT. If not provided, it will return all.","required":false,"schema":{"type":"string","enum":["FOLDER","DOCUMENT"],"example":"DOCUMENT"}},{"name":"parentSlug","in":"query","description":"Content parent slug.","required":false,"schema":{"type":"string","example":"legal/policy"}},{"name":"excludeChildren","in":"query","description":"If **true**, exclude all sub slugs, otherwise include all content under current selected **parent slug**.","required":false,"schema":{"type":"boolean","example":true,"default":false}},{"name":"cv","in":"query","description":"Cache version.","required":false,"schema":{"type":"string","example":"1706217382028"}},{"name":"token","in":"query","description":"Authentication Token.","required":true,"schema":{"type":"string","example":"fb6oTcVjbnyLCMhO2iLY"}}],"responses":{"200":{"description":"Return the Links Object if the request succeeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Links"}}}}},"security":[{"apikey":[]}]}},"/api/v1/spaces/{spaceId}/contents/slugs/{contentSlug}":{"get":{"tags":["Contents"],"summary":"Retrieve Content by Slug","description":"The endpoint allows you to retrieve a specific Content by the content full slug. In case cache version is not present, it will redirect to the latest version.","operationId":"getContentBySlug","parameters":[{"name":"spaceId","in":"path","description":"Unique identifier for the Space object.","required":true,"schema":{"type":"string","example":"UdV5ygPZuOD1JMO9Qat9"}},{"name":"contentSlug","in":"path","description":"Content full slug.","required":true,"schema":{"type":"string","example":"legal/policy"}},{"name":"cv","in":"query","description":"Cache version.","required":false,"schema":{"type":"string","example":"1706217382028"}},{"name":"locale","in":"query","description":"Locale unique identifier (ISO 639-1).","required":false,"schema":{"type":"string","example":"en"}},{"name":"version","in":"query","description":"Content version.","required":false,"schema":{"type":"string","enum":["draft"],"example":"draft"}},{"name":"token","in":"query","description":"Authentication Token.","required":true,"schema":{"type":"string","example":"fb6oTcVjbnyLCMhO2iLY"}}],"responses":{"200":{"description":"Return the Content Object if the request succeeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Content"}}}}},"security":[{"apikey":[]}]}},"/api/v1/spaces/{spaceId}/contents/{contentId}":{"get":{"tags":["Contents"],"summary":"Retrieve Content By ID","description":"The endpoint allows you to retrieve a specific Content by Unique identifier for the Content object. In case cache version is not present, it will redirect to the latest version.","operationId":"getContentById","parameters":[{"name":"spaceId","in":"path","description":"Unique identifier for the Space object.","required":true,"schema":{"type":"string","example":"UdV5ygPZuOD1JMO9Qat9"}},{"name":"contentId","in":"path","description":"Unique identifier for the Content object.","required":true,"schema":{"type":"string","example":"4ykrlCKwI7OCawK2T68g"}},{"name":"cv","in":"query","description":"Cache version.","required":false,"schema":{"type":"string","example":"1706217382028"}},{"name":"locale","in":"query","description":"Locale unique identifier (ISO 639-1).","required":false,"schema":{"type":"string","example":"en"}},{"name":"version","in":"query","description":"Content version.","required":false,"schema":{"type":"string","enum":["draft"],"example":"draft"}},{"name":"token","in":"query","description":"Authentication Token.","required":true,"schema":{"type":"string","example":"fb6oTcVjbnyLCMhO2iLY"}}],"responses":{"200":{"description":"Return the Content Object if the request succeeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Content"}}}}},"security":[{"apikey":[]}]}},"/api/v1/spaces/{spaceId}/assets/{assetId}":{"get":{"tags":["Assets"],"summary":"Retrieve Asset By ID","description":"The endpoint allows you to retrieve a specific Asset by Unique identifier for the Asset object.","operationId":"getAssetById","parameters":[{"name":"spaceId","in":"path","description":"Unique identifier for the Space object.","required":true,"schema":{"type":"string","example":"UdV5ygPZuOD1JMO9Qat9"}},{"name":"assetId","in":"path","description":"Unique identifier for the Asset object.","required":true,"schema":{"type":"string","example":"UdV5ygPZuOD1JMO9Qat9"}},{"name":"w","in":"query","description":"Asset width, in case it is a image (In Pixel). Otherwise it will be ignored.","required":false,"schema":{"type":"integer","example":250}},{"name":"download","in":"query","description":"In case you wish to download the asset.","required":false,"schema":{"type":"boolean","example":false}},{"name":"thumbnail","in":"query","description":"In case you have a video or animated image like WebP/Gif, and you wish to generate thumbnail.","required":false,"schema":{"type":"boolean","example":false}}],"responses":{"200":{"description":"Returns Asset file.","content":{"image/*":{"schema":{"type":"string","format":"binary"}},"application/*":{"schema":{"type":"string","format":"binary"}}}}}}}},"components":{"schemas":{"Translations":{"description":"Key-Value Object. Where Key is Translation ID and Value is Translated Content","type":"object","additionalProperties":{"type":"string","description":"Translation Content","example":"Email"},"example":{"login.form.email":"Email","login.form.password":"Password","login.form.login":"Login","login.form.cancel":"Cancel"}},"ContentAsset":{"type":"object","description":"Content Asset define reference to a Asset.","required":["kind","uri"],"properties":{"kind":{"type":"string","description":"Define the type of Asset","enum":["ASSET"]},"uri":{"type":"string","format":"uri","description":"Unique identifier for the asset.","example":"WLWc4vOACzG1QjK9AEo9"}},"example":{"kind":"ASSET","uri":"WLWc4vOACzG1QjK9AEo9"}},"ContentLink":{"type":"object","description":"Content Link define reference to a Link.","required":["kind","type","target","uri"],"properties":{"kind":{"type":"string","description":"Define the type of Link","enum":["LINK"]},"type":{"type":"string","description":"Define the type of Link. URL for external links and Content for internal links.","enum":["url","content"]},"target":{"type":"string","description":"Define the target of the link. _blank for new tab and _self for same tab.","enum":["_blank","_self"]},"uri":{"type":"string","format":"uri","example":"WLWc4vOACzG1QjK9AEo9","description":"If type is content, then it will be Content ID. Otherwise it will be URL."}},"example":{"kind":"LINK","type":"content","target":"_self","uri":"WLWc4vOACzG1QjK9AEo9"}},"ContentReference":{"type":"object","description":"Content Reference define reference to a Content.","required":["kind","uri"],"properties":{"kind":{"type":"string","description":"Define the type of REFERENCE","enum":["REFERENCE"]},"uri":{"type":"string","format":"uri","description":"Unique identifier for the Content Document.","example":"WLWc4vOACzG1QjK9AEo9"}},"example":{"kind":"REFERENCE","uri":"WLWc4vOACzG1QjK9AEo9"}},"ContentRichText":{"type":"object","description":"Content RichText define content as JSON Object.","properties":{"type":{"type":"string","description":"Define the type of Content Node"},"content":{"type":"array","description":"List of Content Nodes","items":{"$ref":"#/components/schemas/ContentRichText"}}},"example":{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Wow, this editor instance exports its content as JSON."}]}]}},"Content":{"allOf":[{"$ref":"#/components/schemas/ContentMetadata"},{"type":"object","description":"Content define shared object for all possible Content Types.","properties":{"data":{"$ref":"#/components/schemas/ContentData"}}},{"type":"object","description":"References of all links used in the content.","properties":{"links":{"$ref":"#/components/schemas/Links"}}}],"example":{"id":"WLWc4vOACzG1QjK9AEo9","kind":"DOCUMENT","name":"Privacy Policy","locale":"en","slug":"privacy-policy","parentSlug":"legal","fullSlug":"legal/privacy-policy","createdAt":"2023-08-23T21:08:17.551Z","updatedAt":"2024-01-23T14:10:37.852Z","publishedAt":"2023-08-23T21:09:15.191Z","data":{"_id":"a8ca3ed3-6613-4fb6-ae4e-5b846eb5775c","schema":"docArticle"}}},"ContentMetadata":{"type":"object","description":"Content Metadata define short information about a Content for navigation reason.","required":["id","kind","name","slug","parentSlug","fullSlug","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uri","description":"Unique identifier for the object.","example":"WLWc4vOACzG1QjK9AEo9"},"kind":{"type":"string","description":"Define the type of Content, whether it is a FOLDER or DOCUMENT.","enum":["FOLDER","DOCUMENT"],"example":"DOCUMENT"},"name":{"type":"string","description":"Name of the Content","example":"Privacy Policy"},"slug":{"type":"string","description":"SLUG of the Content","example":"privacy-policy"},"parentSlug":{"type":"string","description":"Parent SLUG of the Content","example":"legal"},"fullSlug":{"type":"string","description":"Combination of SLUG and Parent SLUG of the Content","example":"legal/privacy-policy"},"createdAt":{"type":"string","format":"date-time","description":"Date and Time at which the Content was created.","example":"2023-08-23T21:08:17.551Z"},"updatedAt":{"type":"string","format":"date-time","description":"Date and Time at which the Content was updated.","example":"2024-01-23T14:10:37.852Z"},"publishedAt":{"type":"string","format":"date-time","description":"Date and Time at which the Content was published.","example":"2023-08-23T21:09:15.191Z"}},"example":{"id":"WLWc4vOACzG1QjK9AEo9","kind":"DOCUMENT","name":"Privacy Policy","slug":"privacy-policy","parentSlug":"legal","fullSlug":"legal/privacy-policy","createdAt":"2023-08-23T21:08:17.551Z","updatedAt":"2024-01-23T14:10:37.852Z","publishedAt":"2023-08-23T21:09:15.191Z"}},"Links":{"description":"Key-Value Object. Where Key is Unique identifier for the Content object and Value is Content Metadata.","type":"object","additionalProperties":{"$ref":"#/components/schemas/ContentMetadata"},"example":{"4pLYWyN47c076mSfpWIy":{"id":"4pLYWyN47c076mSfpWIy","kind":"DOCUMENT","name":"Options","slug":"options","fullSlug":"docs/schemas/options","parentSlug":"docs/schemas","createdAt":"2024-05-01T09:56:00.923Z","updatedAt":"2024-05-01T09:57:06.445Z","publishedAt":"2024-05-01T13:03:31.672Z"},"5L2ELYsmaM6C0fOBzKp0":{"id":"5L2ELYsmaM6C0fOBzKp0","kind":"DOCUMENT","name":"Translations","slug":"translations","fullSlug":"docs/api/translations","parentSlug":"docs/api","createdAt":"2024-05-04T14:03:54.100Z","updatedAt":"2024-05-07T14:03:57.457Z","publishedAt":"2024-05-07T11:05:46.094Z"},"7fUavXjDpFuHGdWgTFXy":{"id":"7fUavXjDpFuHGdWgTFXy","kind":"DOCUMENT","name":"Overview","slug":"overview","fullSlug":"docs/content/overview","parentSlug":"docs/content","createdAt":"2024-04-30T20:57:41.827Z","updatedAt":"2024-04-30T21:31:47.344Z","publishedAt":"2024-05-01T13:02:41.814Z"}}},"ContentData":{"description":"ContentData defined Object to connect all possible root Schemas.","oneOf":[{"$ref":"#/components/schemas/Page"}],"discriminator":{"propertyName":"schema"}},"Page":{"type":"object","required":["_id","schema"],"properties":{"_id":{"type":"string","format":"uuid","description":"Unique identifier of a component in a content.","example":"a8ca3ed3-6613-4fb6-ae4e-5b846eb5775c"},"_schema":{"type":"string","enum":["Page"],"description":"Unique identifier for the Schema object."},"schema":{"type":"string","enum":["Page"],"description":"Unique identifier for the Schema object. Will be deprecated in future in favor of `_schema`."},"description":{"type":"string"},"title":{"type":"string"}}}},"securitySchemes":{"apikey":{"type":"apiKey","in":"query","name":"token"}}}}
-10.3 KB
Binary file not shown.

playgrounds/next15/src/app/layout.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@ export default function RootLayout({
3333
}>) {
3434
return (
3535
<html lang="en">
36-
<body
37-
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
38-
>
36+
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
3937
{children}
4038
</body>
4139
</html>
Lines changed: 29 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,39 @@
1-
import Image from "next/image";
21
import {getLocalessClient} from "@localess/react";
2+
import {LOCALES} from "@/utils/locales";
33

4-
export default async function Home() {
5-
const data = await fetchData();
6-
console.log('Home', data)
4+
export default async function Home({searchParams}: {
5+
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
6+
}) {
7+
const {locale} = await searchParams
8+
const {data} = await fetchData(locale?.toString());
79
return (
8-
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
9-
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
10-
<Image
11-
className="dark:invert"
12-
src="/next.svg"
13-
alt="Next.js logo"
14-
width={180}
15-
height={38}
16-
priority
17-
/>
18-
<ol className="list-inside list-decimal text-sm/6 text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
19-
<li className="mb-2 tracking-[-.01em]">
20-
Get started by editing{" "}
21-
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-[family-name:var(--font-geist-mono)] font-semibold">
22-
src/app/page.tsx
23-
</code>
24-
.
25-
</li>
26-
<li className="tracking-[-.01em]">
27-
Save and see your changes instantly.
28-
</li>
29-
</ol>
30-
31-
<div className="flex gap-4 items-center flex-col sm:flex-row">
32-
<a
33-
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:w-auto"
34-
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
35-
target="_blank"
36-
rel="noopener noreferrer"
37-
>
38-
<Image
39-
className="dark:invert"
40-
src="/vercel.svg"
41-
alt="Vercel logomark"
42-
width={20}
43-
height={20}
44-
/>
45-
Deploy now
46-
</a>
47-
<a
48-
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-full sm:w-auto md:w-[158px]"
49-
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
50-
target="_blank"
51-
rel="noopener noreferrer"
52-
>
53-
Read our docs
54-
</a>
55-
</div>
10+
<div className="flex flex-col w-full gap-8 mx-auto max-w-5xl">
11+
<header className="py-8">
12+
<nav className="flex justify-center">
13+
<ul
14+
className="flex rounded-full bg-white/90 px-3 text-sm font-medium text-zinc-800 shadow-lg ring-1 shadow-zinc-800/5 ring-zinc-900/5 backdrop-blur-sm dark:bg-zinc-800/90 dark:text-zinc-200 dark:ring-white/10">
15+
{
16+
LOCALES.map(locale => (
17+
<li key={locale.id}>
18+
<a className="relative block px-3 py-2 transition hover:text-teal-500 dark:hover:text-teal-400"
19+
href={"/?locale=" + locale.id} hrefLang={locale.id}>
20+
{locale.name}
21+
</a>
22+
</li>
23+
))
24+
}
25+
</ul>
26+
</nav>
27+
</header>
28+
<main className="flex flex-col gap-4">
29+
<h1 className="text-center">{data?.title}</h1>
30+
<p className="text-center whitespace-pre-line">{data?.description}</p>
5631
</main>
57-
<footer className="row-start-3 flex gap-[24px] flex-wrap items-center justify-center">
58-
<a
59-
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
60-
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
61-
target="_blank"
62-
rel="noopener noreferrer"
63-
>
64-
<Image
65-
aria-hidden
66-
src="/file.svg"
67-
alt="File icon"
68-
width={16}
69-
height={16}
70-
/>
71-
Learn
72-
</a>
73-
<a
74-
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
75-
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
76-
target="_blank"
77-
rel="noopener noreferrer"
78-
>
79-
<Image
80-
aria-hidden
81-
src="/window.svg"
82-
alt="Window icon"
83-
width={16}
84-
height={16}
85-
/>
86-
Examples
87-
</a>
88-
<a
89-
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
90-
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
91-
target="_blank"
92-
rel="noopener noreferrer"
93-
>
94-
<Image
95-
aria-hidden
96-
src="/globe.svg"
97-
alt="Globe icon"
98-
width={16}
99-
height={16}
100-
/>
101-
Go to nextjs.org →
102-
</a>
103-
</footer>
10432
</div>
10533
);
10634
}
10735

108-
export async function fetchData() {
36+
export async function fetchData(locale?: string) {
10937
const client = getLocalessClient();
110-
return client.getContentBySlug('home');
38+
return client.getContentBySlug('home', {locale: locale ? locale : undefined});
11139
}

0 commit comments

Comments
 (0)