← cd ..
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 키 발급

  1. deepl.com/pro#developer 접속
  2. DeepL API Free 플랜 선택
  3. 카드 정보 입력 (무료 한도 내에선 청구 없음)
  4. 가입 완료 후 계정 → 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, 다시 개발자로 돌아갑니다. 실패하고 배우며 성장하는 기록.

DeepL API 사용법 — Next.js에서 번역 기능 붙이기 | backtodev