Найменший ендпоінт в API — і саме той, на який давно чекає ваш перемикач мов. Він відповідає на одне питання — «якими мовами цей сайт говорить просто зараз?» — і відповідає рівно в тому порядку, у якому редактори розставили мови в CRM.
Беріть його, коли треба:
- вивести перемикач мов у шапці, не зашиваючи
enіdeу п’ять різних місць; - перевірити, що мова з URL (
/de/pricing) справді існує, перш ніж передавати її в?lang; - згенерувати локалізовані маршрути, теги
hreflangабо мапу сайту для кожної мови.
Список активних мов
/v1/langshttps://back.sitecog.com/content/v1/langs
?lang.Параметри
Налаштовувати тут нічого: ні параметрів шляху, ні параметрів запиту. Лише ключ.
x-crm-keyheaderstringобовʼязково?key=. Див. «Ключі сайту».Приклад запиту
curl https://back.sitecog.com/content/v1/langs \
-H "x-crm-key: pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40"const res = await fetch('https://back.sitecog.com/content/v1/langs', {
headers: { 'x-crm-key': 'pk_3f9c2a7e1b4d4c0e8a6f5b2d9c1e7a40' },
});
if (!res.ok) throw new Error(`Content API: ${res.status}`);
const langs = await res.json();
console.log(langs.map((l) => l.key)); // ["en", "de"]// lib/langs.ts — серверний помічник із кешем на хвилину
export type Lang = { key: string; title: string; index: number };
export async function getLangs(): Promise<Lang[]> {
const res = await fetch('https://back.sitecog.com/content/v1/langs', {
headers: { 'x-crm-key': process.env.CRM_KEY! },
next: { revalidate: 60 },
});
if (!res.ok) throw new Error(`Content API: ${res.status}`);
return res.json();
}Приклад відповіді
[
{ "key": "en", "title": "English", "index": 0 },
{ "key": "de", "title": "German", "index": 1 }
]Поля відповіді
Масив об’єктів, по одному на кожну активну мову. У кожного три поля — ми ж обіцяли, що він маленький.
keystringen, de) або регіональний варіант на кшталт pt-BR. Саме це значення ви передаєте в ?lang. Чутливий до регістру: pt-BR і pt-br — різні коди.titlestringindexnumberПеремикач мов на React
Звичайна схема: мова живе в URL (/en/…, /de/…), перемикач будується з /v1/langs, а кожен запит контенту несе той самий код у ?lang. Ось перемикач, який нічого не знає про конкретні мови: додайте завтра в CRM італійську — і вона просто з’явиться.
type Lang = { key: string; title: string; index: number };
export function LangSwitcher({ langs, current, path }: {
langs: Lang[]; // просто з GET /v1/langs
current: string; // мова сторінки, яку зараз показано
path: string; // решта URL, наприклад "/pricing"
}) {
return (
<nav aria-label="Language">
{langs.map((lang) => (
<a
key={lang.key}
href={`/${lang.key}${path}`}
hrefLang={lang.key}
aria-current={lang.key === current ? 'true' : undefined}
>
{lang.title}
</a>
))}
</nav>
);
}У парі з ?lang
Ключ, який ви отримуєте тут, — це той самий ключ, який ви надсилаєте всюди. Спершу звірте код з URL зі списком: невідомий код у ?lang — це 400 unknown_lang, а сторінка з помилкою через те, що хтось вручну надрукував /fr/, нікому не потрібна.
import { notFound } from 'next/navigation';
import { getLangs } from '@/lib/langs';
import { LangSwitcher } from '@/components/LangSwitcher';
export default async function Home({ params }: { params: Promise<{ lang: string }> }) {
const { lang } = await params;
const langs = await getLangs();
// Невідома мова в URL → звичайний 404 замість 400 від API
if (!langs.some((l) => l.key === lang)) notFound();
const res = await fetch(`https://back.sitecog.com/content/v1/pages/home?lang=${lang}`, {
headers: { 'x-crm-key': process.env.CRM_KEY! },
next: { revalidate: 60 },
});
const page = await res.json();
return (
<>
<LangSwitcher langs={langs} current={lang} path="" />
<h1>{page.content.hero.content.hero_title.content[lang]}</h1>
</>
);
}Потрібна мова за замовчуванням для відвідувачів, які потрапляють на /? Тут вирішуєте ви — багато сайтів просто беруть першу мову зі списку. Сам API ніколи не обирає мову за вас і ніколи не підставляє відсутній переклад; як елегантно обробляти прогалини, розказано в розділі «Мови та запасна мова».
Помилки
| Статус | Тіло | Що сталося |
|---|---|---|
| 401 | {"message":"invalid_key"} | Ключа немає, він зіпсований або відкликаний. |
| 405 | {"message":"method_not_allowed"} | Приймаються лише GET (і HEAD). API працює тільки на читання. |
| 429 | {"message":"rate_limit_exceeded"} | Забагато запитів за цю хвилину. Див. «Ліміти запитів». |
Повний список із рецептами виправлення — на сторінці «Помилки».