
PolyLingo로 30분 이내에 Next.js 앱 번역하는 방법
By Robert
PolyLingo로 30분 이내에 Next.js 앱 번역하기
이 튜토리얼이 끝나면 작동하는 다국어 Next.js App Router 프로젝트를 갖게 됩니다: 문자열은 messages/en.json에 추출되고, 필요한 모든 언어에 대한 번역된 로케일 파일이 생성되며, next-intl이 경로별로 올바른 파일을 제공하고, 콘텐츠가 변경될 때마다 다시 실행할 수 있는 단일 Node 스크립트가 준비됩니다.
가입할 번역 플랫폼이 없습니다. 언어별 고정 요금도 없습니다. 하나의 API 호출로 모든 대상 언어를 한 번에 처리합니다.
필요한 것:
- App Router를 사용하는 Next.js 프로젝트 (Next.js 14 또는 15)
- Node.js 18 이상
- 무료 PolyLingo 계정과 API 키
1단계: PolyLingo API 키 받기 (5분)
usepolylingo.com에서 무료 계정을 만드세요. 무료 플랜은 매월 100,000 토큰을 포함하며, 이는 중간 크기의 로케일 파일을 10개 이상의 언어로 여러 번 번역할 수 있는 양입니다.
가입 후 대시보드의 API 키로 이동하여 키를 생성하세요. 전체 값은 한 번만 볼 수 있으니 즉시 복사하세요.
프로젝트에 환경 변수로 추가하세요. 절대 버전 관리에 커밋하거나 클라이언트 측 코드에 노출하지 마세요:
# .env.local
POLYLINGO_API_KEY="pl_your_key_here"
계속 진행하기 전에 API가 접근 가능한지 확인하세요:
curl -sS "https://api.usepolylingo.com/v1/health"
"status": "ok"가 포함된 작은 JSON 페이로드가 반환되어야 합니다.
2단계: next-intl 설치 및 라우팅 설정 (10분)
라이브러리를 설치하세요:
npm install next-intl
프로젝트 루트에 i18n.ts 파일을 만드세요. 이 파일은 next-intl에 지원하는 로케일과 각 요청에 맞는 메시지 파일을 불러오는 방법을 알려줍니다:
// i18n.ts
import { getRequestConfig } from 'next-intl/server'
export const locales = ['en', 'de', 'fr'] as const
export type Locale = (typeof locales)[number]
export const defaultLocale: Locale = 'en'
export default getRequestConfig(async ({ requestLocale }) => {
let locale = await requestLocale
if (!locale || !locales.includes(locale as Locale)) {
locale = defaultLocale
}
return {
locale,
messages: (await import(`./messages/${locale}.json`)).default,
}
})
로케일로 경로를 접두사하는 미들웨어를 추가하세요:
// middleware.ts
import createMiddleware from 'next-intl/middleware'
import { locales, defaultLocale } from './i18n'
export default createMiddleware({
locales: [...locales],
defaultLocale,
localePrefix: 'as-needed',
})
export const config = {
matcher: ['/((?!api|_next|.*\\..*).*)'],
}
페이지 파일을 app/[locale]/ 아래로 이동하세요. 루트 레이아웃을 업데이트하여 locale 파라미터를 받고 NextIntlClientProvider로 자식을 감싸세요:
// app/[locale]/layout.tsx
import { NextIntlClientProvider } from 'next-intl'
import { getMessages } from 'next-intl/server'
export default async function LocaleLayout({
children,
params,
}: {
children: React.ReactNode
params: Promise<{ locale: string }>
}) {
const { locale } = await params
const messages = await getMessages()
return (
<html lang={locale}>
<body>
<NextIntlClientProvider messages={messages}>
{children}
</NextIntlClientProvider>
</body>
</html>
)
}
3단계: 문자열을 JSON 메시지 파일로 추출하기 (10분)
프로젝트 루트에 messages/ 폴더를 만드세요. 소스 문자열이 담긴 en.json 파일을 추가하세요. next-intl은 중첩된 키 구조를 사용합니다:
{
"Home": {
"title": "Welcome",
"cta": "Get started"
}
}
페이지를 하드코딩된 문자열 대신 useTranslations를 사용하도록 업데이트하세요:
// app/[locale]/page.tsx
import { useTranslations } from 'next-intl'
export default function HomePage() {
const t = useTranslations('Home')
return (
<main>
<h1>{t('title')}</h1>
<button type="button">{t('cta')}</button>
</main>
)
}
이제 번역 스크립트를 작성하세요. 이 스크립트는 messages/en.json을 읽고, format: "json"과 함께 PolyLingo API에 보내며, 대상 로케일별로 출력 파일을 작성합니다. format: "json" 플래그는 API에 키 구조를 유지하고 문자열 값만 번역하도록 지시합니다 — 중첩 키, 배열, 비문자열 타입은 모두 변경되지 않고 그대로 반환됩니다.
// scripts/translate-messages.mjs
// Run with: node scripts/translate-messages.mjs
import fs from 'node:fs'
import path from 'node:path'
const API_KEY = process.env.POLYLINGO_API_KEY
const API_URL = (process.env.POLYLINGO_API_URL || 'https://api.usepolylingo.com/v1').replace(/\/$/, '')
const TARGETS = ['de', 'fr'] // 더 많은 로케일을 추가하려면 이 배열을 확장하세요
const enPath = path.join('messages', 'en.json')
const en = JSON.parse(fs.readFileSync(enPath, 'utf8'))
const res = await fetch(`${API_URL}/translate`, {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
content: JSON.stringify(en),
format: 'json',
targets: TARGETS,
model: 'standard',
}),
})
if (!res.ok) {
const err = await res.text()
throw new Error(`PolyLingo ${res.status}: ${err}`)
}
const { translations } = await res.json()
for (const locale of TARGETS) {
const out = path.join('messages', `${locale}.json`)
fs.writeFileSync(out, JSON.stringify(JSON.parse(translations[locale]), null, 2) + '\n')
console.log('Wrote', out)
}
실행하세요:
node scripts/translate-messages.mjs
다음과 같은 출력이 표시됩니다:
Wrote messages/de.json
Wrote messages/fr.json
파일을 열어 확인하세요. 키는 en.json과 동일하며, 문자열 값만 변경되어 있습니다.
4단계: 경로 스모크 테스트 (5분)
개발 서버를 시작하세요:
npm run dev
http://localhost:3000과 http://localhost:3000/de를 방문하세요. 제목과 버튼이 각각 영어와 독일어로 렌더링되어야 합니다. 스크립트의 TARGETS 배열과 i18n.ts의 locales 배열을 확장하여 더 많은 로케일을 추가한 후 스크립트를 다시 실행하세요.
PolyLingo 대시보드의 Usage에서 토큰 사용량을 확인하세요. 두 개 언어로 번역된 작은 로케일 파일의 경우 월별 할당량에서 몇 백 토큰만 사용됩니다.
다음 단계
더 많은 로케일 추가하기. 스크립트는 TARGETS에 몇 개 항목이 있든 한 번의 요청만 보냅니다. 일본어, 스페인어, 아랍어를 추가해도 API 호출은 한 번입니다.
CI에 연동하기. GitHub Actions에 POLYLINGO_API_KEY를 저장소 시크릿으로 추가하고 빌드 파이프라인의 일부로 스크립트를 실행하세요. en.json이 변경될 때마다 로케일 파일이 자동으로 동기화됩니다.
다른 포맷 번역하기. 같은 스크립트 패턴이 Markdown 문서 페이지(format: "markdown")와 HTML 이메일 템플릿(format: "html")에도 작동합니다. API는 모든 경우에 구조를 유지합니다.
대규모 프로젝트에는 배치 엔드포인트 사용하기. 여러 개의 별도 JSON 파일(예: 기능 영역별) 이 있다면, POST /translate/batch는 최대 100개 항목을 한 번에 요청할 수 있으며, 각 항목은 고유한 id와 format을 가집니다.
무료로 사용해보기
PolyLingo의 무료 플랜은 매월 100,000 토큰을 포함합니다. 신용카드가 필요 없습니다.
curl -sS -X POST "https://api.usepolylingo.com/v1/translate" \
-H "Authorization: Bearer $POLYLINGO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "{\"Home\":{\"title\":\"Welcome\",\"cta\":\"Get started\"}}",
"format": "json",
"targets": ["de", "fr", "es", "ja"]
}'