Một hướng dẫn thực hành: xây dựng danh bạ sân bay đa ngôn ngữ trên Profound CMS — một route tham số hiển thị trang cho mọi sân bay bằng 35 ngôn ngữ.
Xây dựng một danh bạ sân bay thật sự, hỗ trợ đa ngôn ngữ trên Profound CMS: một mẫu URL hiển thị trang cho mọi sân bay, bằng 35 ngôn ngữ. Bạn viết mã Next.js và tự tay xây dựng cấu trúc CMS; Claude Code (thông qua Profound MCP) đảm nhiệm ba việc — tạo dữ liệu sân bay, kết nối hệ thống thiết kế và tạo bốn component React. Ba phần: Chuẩn bị, Xây dựng, Sản xuất.
/{language}/{airport_code}.cms-renderer.curl -fsSL https://bun.sh/install | bashgh) đã đăng nhập và tài khoản Vercel liên kết với GitHub.language) có sẵn.cms-renderer với API key ở cấp độ đọc.Trạng thái cuối: khoảng 50 sân bay trong CMS, ứng dụng đọc được chúng và hệ thống thiết kế đã sẵn sàng.
Đăng ký tại Profound (xác thực WorkOS) và tạo website tên airports. Sao chép hai thứ: ID website (UUID trong URL quản trị) và một API key cấp đọc từ Deployments → Create API key. Ứng dụng chỉ đọc, nên chỉ cần key đọc.
bunx create-profound-next airports
cd airports
Thêm thông tin xác thực vào .env.local:
PROFOUND_API_KEY=<read key của bạn>
NEXT_PUBLIC_PROFOUND_WEBSITE_ID=<website id của bạn>
NEXT_PUBLIC_CMS_API_URL=https://cms.dev.tryprofound.com
NEXT_PUBLIC_BUNNY_CDN_URL=https://cms-profound.b-cdn.net
Chạy bun dev và mở localhost:3000 để xác nhận đã kết nối.
airportTrong trang quản trị, vào Components → Create new component và đặt tên airport. Thêm sáu trường: code, name, city, country (Text) và latitude, longitude (Number). Đánh dấu code là trường Route Slug và đặt trạng thái Active. Để tất cả trường tùy chọn; không thêm thẻ UI Element.
Component airport — sáu trường, với code đặt làm Route Slug.
bun run generate-schemas
Lệnh này ghi airportSchema (Zod) và Airport (type) vào generated/cms-schemas.ts, đồng thời xác nhận thông tin xác thực của bạn hoạt động.
Kết nối MCP và xác thực:
claude mcp add --transport http Profound http://107.21.107.99:8081/mcp
Máy chủ xác thực bằng OAuth (WorkOS). Trong Claude Code, chạy /mcp, chọn Profound, và hoàn tất đăng nhập trong trình duyệt — Claude Code cũng sẽ nhắc bạn tự động khi gọi một công cụ Profound lần đầu. Khi /mcp hiển thị Profound là connected, hãy nhắc Claude:
Tạo năm mươi sân bay thật — đúng mã IATA, tên, thành phố, quốc gia và tọa độ. Lưu thành JSON trong thư mục
data, xác thực theo component airport của chúng ta, sau đó tạo từng document được publish qua Profound MCP, thực hiện song song.
Mở airport → Variants để xác nhận khoảng 50 sân bay đã publish. Ứng dụng đọc bằng API key; MCP ghi bằng phiên WorkOS của nó.
Khoảng 50 sân bay, được gieo dữ liệu và publish thành Variant.
Bộ khởi tạo không có style. Đặt một file DESIGN.md (khối @theme của Tailwind v4 cùng các token) tại thư mục gốc dự án — tự tạo hoặc tải từ refero.design. Sau đó nhắc Claude:
Đọc DESIGN.md. Thiết lập Tailwind v4 và tích hợp theme cũng như font. Dùng
next/fontcho font, không import Google tại runtime. Chỉ styling — chưa tạo trang hay component.
Xác nhận src/app/globals.css có @import "tailwindcss"; cùng khối @theme, và localhost:3000 hiển thị các token.
Xây dựng lớp render: UI element, component React, route, binding CEL và dịch thuật.
Trong trang quản trị, Create new component bốn lần (không Route Slug). Với mỗi component, thêm các trường dạng Text trừ khi ghi chú khác, đặt trạng thái Active, và thêm thẻ UI Element tại Settings → Tags:
nav → brandheadline → title, subtitlebody → code, city, country, latitude (Number), longitude (Number)footer → textbody.latitude và body.longitude phải là Number để khớp với component airport.
Mỗi UI element là một component riêng — đây là body, đặt Active với thẻ UI Element.
Tất cả bốn UI element bên cạnh component airport.
bun run generate-schemas
Nhắc Claude:
Xây dựng bốn component React — nav, headline, body, footer — trong
components/. Mỗi component nhận duy nhất propcontentđược gõ kiểuBlockComponentProps<T>từcms-renderer/lib/types, nơiTlà type đã sinh của element, và đọc các trường từcontent. Đăng ký cả bốn trong registry của route bắt tất cả trongsrc/app/[...slug]/page.tsxtheo tên component. Style theo hệ thống thiết kế của chúng ta, nhưng là component riêng — đừng sao chép layout của site gốc. Nav: brand bên trái. Headline: tên sân bay với subtitlecode · city, country. Body: bảng chi tiết gồm code, city, country và tọa độ. Footer: một dòng tĩnh. Chỉ layout và styling.
Claude tạo bốn component và điền registry trong src/app/[...slug]/page.tsx:
const registry = { nav: Nav, headline: Headline, body: Body, footer: Footer };
Hai quy tắc: mỗi component đọc trường từ content (không truyền prop riêng), và key trong registry phải khớp chính xác với tên component trong CMS — sai lệch sẽ không render.
Trong trang quản trị, vào Pages → Create page và đặt mẫu /{airport_code}. Trong Dynamic Segment Mappings, ánh xạ airport_code → component airport, trường slug code. Lưu — bạn sẽ đến Page Builder. Kiểm tra /JFK hoạt động.
Thêm UI element vào trang từ tab Custom.
Bốn UI element đã thêm vào binding JFK trong Page Builder.
Chọn binding JFK → Add UI Element → tab Custom → thêm lần lượt nav, headline, body, footer. Profound tự nhân bản bộ phần tử này cho mọi binding sân bay.
Điền từng trường. Giá trị tĩnh (nav brand, footer text): gõ trực tiếp. Giá trị động: chuyển sang dynamic và viết CEL. Lệnh gọi chia sẻ: documents.get("airport", meta.params.airport_code).
| Trường | Giá trị 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 (và .longitude) |
nav.brand, footer.text | chuỗi tĩnh |
Publish trang (góc trên bên phải).
Mở localhost:3000/JFK, sau đó /SFO, /LAX — cùng template, dữ liệu sân bay khác nhau.
Trang hoàn chỉnh hiển thị dữ liệu JFK bằng tiếng Anh.
Dịch các component trước. Trong trang quản trị, mở từng component (bất kỳ — không nhất thiết là UI element) và click Translate → Submit. Profound dịch nội dung đó sang toàn bộ 35 ngôn ngữ cùng lúc, bao gồm giá trị tĩnh. Làm việc này trước khi chỉnh route hay đụng tới CEL.
Translate → Submit gửi component đến tất cả 35 ngôn ngữ một lần.
Thêm chiều ngôn ngữ. Trong Pages, đổi mẫu thành /{language}/{airport_code}. Thêm Dynamic Segment Mapping cho language → component hệ thống language, trường slug code. Lưu và kiểm tra /en/JFK hoạt động.
Thêm đoạn {language} vào route.
Chuyển mọi trường có thể dịch sang lệnh fetch đã dịch. Đa ngôn ngữ nghĩa là chuyển mọi trường phụ thuộc ngôn ngữ — không chỉ headline — từ documents.get(...) sang documents.translated("airport", meta.params.airport_code, meta.params.language):
| Trường | CEL đã dịch |
|---|---|
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 (và .country) |
Giữ code IATA và tọa độ dùng documents.get — chúng giống nhau ở mọi ngôn ngữ. nav.brand và footer.text đã được dịch ở bước 1.
Khi hoàn tất cả ba bước, /fr/SFO, /de/SFO, v.v. sẽ hiển thị đầy đủ bản dịch.
Push lên GitHub:
git init
git add -A
git commit -m "Airport directory"
gh repo create airports --public --source=. --push
Nhập vào Vercel: Add New → Project → nhập repo airports. Thêm biến môi trường — PROFOUND_API_KEY, NEXT_PUBLIC_PROFOUND_WEBSITE_ID, NEXT_PUBLIC_CMS_API_URL, và tùy chọn NEXT_PUBLIC_BUNNY_CDN_URL — rồi Deploy. Truy cập /en/JFK và /fr/SFO. Mỗi lần git push sau này sẽ redeploy.
Cả hai đi kèm sẵn với bộ khởi tạo.
<Refresher> trong layout.tsx cập nhật trang bạn đang preview khi bạn chỉnh sửa và lưu trong trang quản trị — không cần redeploy.?edit_mode=true vào bất kỳ URL nào (ví dụ …/en/JFK?edit_mode=true) để hiển thị lớp chỉnh sửa. Khách truy cập công khai vẫn thấy trang sạch.?edit_mode=true phủ lớp chỉnh sửa lên trang live.
Năm mươi sân bay, 35 ngôn ngữ, live — mô tả một lần và dữ liệu điền vào: một route, bốn component React và vài binding CEL. CMS giữ nội dung, mã của bạn render, và CEL kết nối chúng.