Практическое руководство: создайте интернационализированный справочник аэропортов в Profound CMS — один параметрический маршрут, который отображает страницу для каждого аэропорта на 35 языках.
Создайте настоящий, интернационализированный справочник аэропортов на Profound CMS: один шаблон URL, который отображает страницу для каждого аэропорта на 35 языках. Вы пишете код Next.js и вручную строите структуру CMS; Claude Code (через Profound MCP) берёт на себя три задачи — генерирует данные об аэропортах, подключает дизайн-систему и создаёт четыре React-компонента. Три части: Подготовка, Сборка, Продакшен.
Посмотрите полный видеоразбор.
/{language}/{airport_code}.cms-renderer.curl -fsSL https://bun.sh/install | bashgh) с выполненным входом и аккаунт Vercel, связанный с GitHub.language) встроены по умолчанию.cms-renderer с API-ключом уровня чтения.Конечный результат: ~50 аэропортов в CMS, приложение подключено к их чтению, и дизайн-система настроена.
Зарегистрируйтесь в Profound (аутентификация через WorkOS) и создайте сайт с именем airports. Скопируйте две вещи: ID сайта (UUID в URL админки) и API-ключ уровня чтения из Deployments → Create API key. Приложению нужен только доступ на чтение, так что достаточно ключа чтения.
bunx create-profound-next airports
cd airports
Добавьте свои учётные данные в .env.local:
PROFOUND_API_KEY=<your read key>
NEXT_PUBLIC_PROFOUND_WEBSITE_ID=<your website id>
NEXT_PUBLIC_CMS_API_URL=https://cms.dev.tryprofound.com
NEXT_PUBLIC_BUNNY_CDN_URL=https://cms-profound.b-cdn.net
Запустите bun dev и откройте localhost:3000, чтобы убедиться, что соединение работает.
airportВ админке зайдите в Components → Create new component и назовите его airport. Добавьте шесть полей: code, name, city, country (Text) и latitude, longitude (Number). Отметьте code как поле Route Slug и установите статус Active. Оставьте все поля необязательными; тег UI Element не добавляйте.
Компонент airport — шесть полей, code назначено Route Slug.
bun run generate-schemas
Это создаст airportSchema (Zod) и Airport (тип) в generated/cms-schemas.ts и подтвердит, что ваши учётные данные работают.
Подключите MCP и аутентифицируйтесь:
claude mcp add --transport http Profound http://107.21.107.99:8081/mcp
Сервер аутентифицируется через OAuth (WorkOS). В Claude Code запустите /mcp, выберите Profound и завершите вход в браузере — Claude Code также автоматически предложит это при первом вызове инструмента Profound. Когда /mcp показывает Profound как connected, попросите Claude:
Сгенерируй пятьдесят реальных аэропортов — корректные коды IATA, названия, города, страны и координаты. Сохрани их как JSON в папке
data, проверь на соответствие нашему компоненту airport, затем создай каждый как опубликованный документ через Profound MCP, параллельно.
Откройте airport → Variants, чтобы убедиться, что опубликовано ~50 аэропортов. Приложение читает их по API-ключу; MCP пишет, используя собственную сессию WorkOS.
Около 50 аэропортов, загруженных как опубликованные варианты.
Заготовка поставляется без стилей. Поместите DESIGN.md (блок @theme Tailwind v4 плюс токены) в корень проекта — свой собственный или скачайте с refero.design. Затем попросите Claude:
Прочитай DESIGN.md. Настрой Tailwind v4 и подключи тему и шрифты. Используй
next/fontдля шрифтов, не подключай Google во время выполнения. Только стили — никаких страниц или компонентов.
Убедитесь, что src/app/globals.css содержит @import "tailwindcss"; плюс блок @theme, и что на localhost:3000 видны токены.
Постройте слой рендеринга: UI-элементы, React-компоненты, маршрут, привязки CEL и перевод.
В админке Create new component четыре раза (без Route Slug). Для каждого добавьте поля как Text, если не указано иначе, установите статус Active и добавьте тег UI Element в Settings → Tags:
nav → brandheadline → title, subtitlebody → code, city, country, latitude (Number), longitude (Number)footer → textbody.latitude и body.longitude должны быть типа Number, чтобы соответствовать компоненту аэропорта.
Каждый UI-элемент — отдельный компонент; здесь body, активирован и помечен тегом UI Element.
Все четыре UI-элемента рядом с компонентом airport.
bun run generate-schemas
Попросите Claude:
Создай четыре React-компонента — nav, headline, body, footer — в
components/. Каждый принимает один пропcontent, типизированный какBlockComponentProps<T>изcms-renderer/lib/types, гдеT— сгенерированный тип элемента, и читает свои поля изcontent. Зарегистрируй все четыре в реестре маршрутного catch-all по имени компонента. Стилизуй их нашей дизайн-системой, но как наши собственные компоненты — не копируй макет исходного сайта. Nav: бренд слева. Headline: название аэропорта с подзаголовкомcode · city, country. Body: панель с деталями — код, город, страна и координаты. Footer: одна статичная строка. Только компоновка и стили.
Claude создаёт четыре компонента и заполняет реестр в src/app/[...slug]/page.tsx:
const registry = { nav: Nav, headline: Headline, body: Body, footer: Footer };
Два правила: каждый компонент считывает поля из content (не через отдельные пропы), а ключи реестра должны точно совпадать с именами компонентов в CMS — несоответствие приведёт к пустому рендеру.
В админке перейдите в Pages → Create page и установите шаблон /{airport_code}. В разделе Dynamic Segment Mappings сопоставьте airport_code → компонент airport, поле slug code. Сохраните — вы попадёте в Page Builder. Убедитесь, что /JFK открывается.
Добавление UI-элемента на страницу из вкладки Custom.
Четыре UI-элемента, добавленные в привязку JFK в Page Builder.
Выберите привязку JFK → Add UI Element → вкладка Custom → добавьте nav, headline, body, footer по порядку. Profound распространяет набор на каждую привязку аэропорта.
Заполните каждое поле. Для статических значений (бренд в nav, текст в footer) введите их напрямую. Для динамических значений переключитесь на dynamic и напишите CEL. Общий источник — documents.get("airport", meta.params.airport_code).
| Поле | Значение CEL |
|---|---|
headline.title | documents.get("airport", meta.params.airport_code).name |
headline.subtitle | documents.get("airport", meta.params.airport_code).code + " · " + documents.get("airport", meta.params.airport_code).city + ", " + documents.get("airport", meta.params.airport_code).country |
body.code / body.city / body.country | documents.get("airport", meta.params.airport_code).<field> |
body.latitude / body.longitude | documents.get("airport", meta.params.airport_code).latitude (и .longitude) |
nav.brand, footer.text | статические строки |
Publish страницу (правый верхний угол).
Откройте localhost:3000/JFK, затем /SFO, /LAX — один шаблон, разные аэропорты.
Готовая страница с данными JFK на английском.
Сначала переведите компоненты. В админке откройте каждый компонент (любой — не обязательно UI-элемент) и нажмите Translate → Submit. Profound переведёт его контент на все 35 языков сразу, включая статические значения полей. Сделайте это до того, как измените маршрут или тронете любой CEL.
Translate → Submit отправляет компонент на все 35 языков сразу.
Добавьте измерение языка. В Pages измените шаблон на /{language}/{airport_code}. Добавьте Dynamic Segment Mapping для language → встроенный системный компонент language, поле slug code. Сохраните и убедитесь, что /en/JFK открывается.
Добавляем сегмент {language} в маршрут.
Переключите каждое переводимое поле на переведённую выборку. Интернационализация страницы означает, что нужно переключить каждое языко-зависимое поле — не только заголовок — с documents.get(...) на documents.translated("airport", meta.params.airport_code, meta.params.language):
| Поле | Переведённое CEL |
|---|---|
headline.title | documents.translated("airport", meta.params.airport_code, meta.params.language).name |
headline.subtitle | documents.get("airport", meta.params.airport_code).code + " · " + documents.translated("airport", meta.params.airport_code, meta.params.language).city + ", " + documents.translated("airport", meta.params.airport_code, meta.params.language).country |
body.city / body.country | documents.translated("airport", meta.params.airport_code, meta.params.language).city (и .country) |
Оставьте код IATA code и координаты на documents.get — они одинаковы на всех языках. nav.brand и footer.text уже покрыты переводом компонента из шага 1.
Когда все три шага завершены, /fr/SFO, /de/SFO и т. д. отображаются полностью переведёнными.
Отправьте в GitHub:
git init
git add -A
git commit -m "Airport directory"
gh repo create airports --public --source=. --push
Импортируйте в Vercel: Add New → Project → импортируйте репозиторий airports. Добавьте переменные окружения — PROFOUND_API_KEY, NEXT_PUBLIC_PROFOUND_WEBSITE_ID, NEXT_PUBLIC_CMS_API_URL и, при необходимости, NEXT_PUBLIC_BUNNY_CDN_URL — затем нажмите Deploy. Откройте /en/JFK и /fr/SFO. Каждый последующий git push переразвёртывает проект.
Оба поставляются с заготовкой.
<Refresher> в layout.tsx обновляет страницу, которую вы просматриваете, когда вы редактируете и сохраняете в админке — без повторного деплоя.?edit_mode=true к любому URL (например, …/en/JFK?edit_mode=true), чтобы увидеть оверлеи редактирования. Публичные посетители по-прежнему видят чистую страницу.?edit_mode=true накладывает интерфейс редактирования поверх живой страницы.
Пятьдесят аэропортов, 35 языков, всё вживую — описано один раз и наполнено данными: один маршрут, четыре React-компонента и несколько привязок CEL. CMS хранит контент, ваш код его рендерит, а CEL связывает их.