DeepL번역 APINext.jsAPI 연동
DeepL API 사용법 — Next.js에서 번역 기능 붙이기
April 18, 20261 min read
번역 기능, 생각보다 API 선택이 중요하다
블로그 어드민에 "한국어 → 영어 번역 초안" 버튼을 만들려고 처음엔 무료 API를 붙였다. 잘 되는 듯했는데 마크다운 특수문자(**, ##)가 번역 과정에서 계속 깨졌다. 몇 번 삽질하다가 결국 DeepL로 갈아탔고, 문제가 깔끔하게 해결됐다.
DeepL은:
- 월 500,000자 무료 (블로그 포스트 기준 수백 개 번역 가능)
- 마크다운 특수문자를 변형하지 않음
- 한국어↔영어 번역 품질이 다른 무료 API와 비교가 안 됨
직접 써보면서 설정한 과정을 정리해본다.
사전 준비
- Next.js 프로젝트 (App Router 기준)
- DeepL 계정 (카드 등록 필요, 무료 플랜 이용 가능)
Step 1. DeepL 계정 만들고 API 키 발급
- deepl.com/pro#developer 접속
- DeepL API Free 플랜 선택
- 카드 정보 입력 (무료 한도 내에선 청구 없음)
- 가입 완료 후 계정 → API Keys 메뉴에서 키 확인
발급된 키는 이런 형태다:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:fx
끝에 :fx가 붙으면 Free 플랜 API 키다. Pro 플랜은 :fx가 없다.
주의: API 키는 코드에 직접 넣으면 안 된다. 반드시 환경변수로 관리해야 한다.
Step 2. 환경변수 설정
로컬 개발용 .env.local:
DEEPL_API_KEY=여기에_API_키_입력
Vercel 배포 시:
Settings → Environment Variables → DEEPL_API_KEY 추가
Step 3. 서버 라우트 만들기
DeepL API 키는 클라이언트에 노출되면 안 되기 때문에 서버사이드 API 라우트를 통해 호출해야 한다.
app/api/translate/route.ts 생성:
import { NextRequest, NextResponse } from "next/server";
// Free 플랜: api-free.deepl.com / Pro 플랜: api.deepl.com
const DEEPL_API_URL = "https://api-free.deepl.com/v2/translate";
export async function POST(req: NextRequest) {
const apiKey = process.env.DEEPL_API_KEY;
if (!apiKey) {
return NextResponse.json(
{ error: "DEEPL_API_KEY가 설정되지 않았습니다." },
{ status: 500 }
);
}
const { text, sourceLang, targetLang } = await req.json();
const res = await fetch(DEEPL_API_URL, {
method: "POST",
headers: {
Authorization: `DeepL-Auth-Key ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
text: [text], // 배열로 전달 (여러 텍스트 동시 번역 가능)
source_lang: sourceLang, // "KO", "EN" 등
target_lang: targetLang, // "EN", "KO" 등
}),
});
if (!res.ok) {
const err = await res.text();
return NextResponse.json(
{ error: `DeepL API 오류: ${err}` },
{ status: res.status }
);
}
const data = await res.json();
const translated = data.translations?.[0]?.text ?? "";
return NextResponse.json({ translated });
}
Step 4. 클라이언트에서 호출하기
컴포넌트에서는 DeepL을 직접 부르지 않고, 방금 만든 서버 라우트를 호출한다.
async function translateText(text: string, direction: "ko-en" | "en-ko") {
const res = await fetch("/api/translate", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text,
sourceLang: direction === "ko-en" ? "KO" : "EN",
targetLang: direction === "ko-en" ? "EN" : "KO",
}),
});
if (!res.ok) {
const err = await res.json();
throw new Error(err.error ?? "번역 실패");
}
const data = await res.json();
return data.translated; // 번역된 텍스트
}
버튼에 붙이면 끝이다:
<button onClick={async () => {
const result = await translateText(koreanText, "ko-en");
setEnglishText(result);
}}>
영어로 번역
</button>
자주 쓰는 언어 코드
| 언어 | source_lang / target_lang |
|---|---|
| 한국어 | KO |
| 영어 (미국) | EN-US |
| 영어 (영국) | EN-GB |
| 일본어 | JA |
| 중국어 (간체) | ZH-HANS |
source_lang은 자동 감지가 가능해서 생략할 수도 있다.target_lang은 필수.
트러블슈팅
403 Forbidden 오류
- API 키가 잘못됐거나 환경변수가 제대로 설정되지 않은 경우
- Free 플랜 키인데
api.deepl.com(Pro URL)을 쓴 경우 →api-free.deepl.com으로 변경
456 Quota Exceeded
- 월 무료 한도(500,000자) 초과
- DeepL 계정에서 사용량 확인 가능
번역 결과가 비어있다
data.translations?.[0]?.text로 접근하는지 확인- 요청한
text가 빈 문자열이면 빈 결과가 반환됨
Vercel 배포 후 번역이 안 된다
- Vercel에
DEEPL_API_KEY환경변수 추가 후 Redeploy 했는지 확인 - 환경변수 추가만으로는 반영 안 됨, 재배포 필요
정리 — 핵심 흐름 한눈에
1. DeepL API Free 가입 → API 키 발급
(deepl.com/pro#developer)
2. 환경변수 설정
.env.local → DEEPL_API_KEY=...
Vercel → Environment Variables에도 동일하게 추가
3. 서버 라우트 생성
app/api/translate/route.ts
→ process.env.DEEPL_API_KEY 사용
→ https://api-free.deepl.com/v2/translate 호출
4. 클라이언트에서 서버 라우트 호출
fetch("/api/translate", { method: "POST", body: ... })
⚠️ API 키를 클라이언트 코드에 직접 넣으면 절대 안 됨
설정 자체는 30분이면 끝난다. 무료 한도가 넉넉해서 개인 블로그나 사이드 프로젝트에 번역 기능을 붙이기에 딱 맞는 선택이다.
PM
backtodev
40대 PM, 다시 개발자로 돌아갑니다. 실패하고 배우며 성장하는 기록.