디스코드 봇 만들기#10다국어(i18n) 지원하기! (파이썬 예제)
목차10개 항목
안녕하세요! Mojangcam입니다 😎
지난 #9편에서는 봇에 AI(Claude·ChatGPT API)를 연동해서 대화하는 봇을 만들어봤죠? 이번 편에서는 우리 봇을 글로벌 봇으로 업그레이드해볼 거예요. 바로 다국어(i18n) 지원입니다!
해외 유저가 섞여 있는 게임 서버를 운영하다 보면, 한국어로만 답하는 봇이 아쉬울 때가 있어요. 디스코드는 사용자마다 클라이언트 언어 설정을 가지고 있어서, 이걸 읽으면 한국 유저에게는 한국어로, 외국 유저에게는 영어로 자동 응답하는 봇을 만들 수 있답니다. 심지어 슬래시 명령어 이름과 설명까지 언어별로 다르게 보여줄 수 있어요!

🧠 i18n이 뭐예요? 왜 필요할까요?
i18n은 internationalization(국제화)의 줄임말이에요. i와 n 사이에 글자가 18개라서 i18n이라고 부른답니다 💡
디스코드 봇에서 i18n이 필요한 순간은 생각보다 많아요.
- 해외 유저가 섞인 게임 서버(마인크래프트·아크 등)의 안내 봇
- 여러 나라 서버에 배포하는 공개 봇
- 명령어 설명을 사용자 언어로 보여줘서 진입 장벽을 낮추고 싶을 때
discord.py에는 이걸 위한 기능이 이미 내장되어 있어요. interaction.locale(사용자 언어)과 Translator(명령어 번역기) 두 가지만 알면 됩니다!
📌 준비물
- Python 3.8 이상
- discord.py 2.x (이 글은 최신 버전 2.7.1 기준이에요)
- 봇 토큰 + 봇이 초대된 테스트 서버 (#1편 참고)
pip install -U discord.py📌 1단계 - 사용자 언어 알아내기 (interaction.locale)
슬래시 명령어가 실행되면, 디스코드가 그 사용자의 언어 정보를 함께 보내줘요. 먼저 어떤 값이 오는지 확인해볼게요.
@bot.tree.command(name="lang", description="내 언어 설정 확인")
async def lang(interaction: discord.Interaction):
await interaction.response.send_message(
f"클라이언트 언어: {interaction.locale}"
)하나씩 뜯어볼게요 💡
- interaction.locale : 명령어를 실행한 사용자의 디스코드 앱 언어 설정이에요. 한국어 클라이언트면
ko, 영어(미국)면en-US, 일본어면ja가 와요. - interaction.guild_locale : 이건 사용자가 아니라 서버(길드)의 기본 언어예요. 공지 같은 서버 단위 메시지에 쓰면 좋아요.
- 반환 타입은
discord.Locale이라는 열거형(enum)인데,str()로 감싸면'ko'같은 문자열이 됩니다.
📌 2단계 - 번역 사전으로 응답 메시지 바꾸기
이제 언어별 응답을 담은 번역 사전(dict)을 만들고, interaction.locale에 맞는 메시지를 골라서 보내볼게요.
RESPONSES = {
"ko": "안녕하세요, {user}님! 만나서 반가워요 🙌",
"ja": "こんにちは、{user}さん!",
"en-US": "Hello, {user}! Nice to meet you 🙌",
}
DEFAULT_LOCALE = "en-US"
@bot.tree.command(name="hello", description="Send a friendly greeting")
async def hello(interaction: discord.Interaction):
lang = str(interaction.locale)
template = RESPONSES.get(lang, RESPONSES[DEFAULT_LOCALE])
await interaction.response.send_message(
template.format(user=interaction.user.display_name)
)하나씩 뜯어볼게요 💡
- RESPONSES : 언어 코드를 키로 쓰는 번역 사전이에요. 언어를 추가하고 싶으면 여기에 한 줄만 더하면 돼요.
- RESPONSES.get(lang, 기본값) : 사전에 없는 언어(예: 프랑스어
fr)로 들어오면 기본 언어(영어)로 대신 응답해요. 다국어 처리의 핵심 안전장치입니다! - {user} + format() : 메시지 안에 닉네임 같은 변수를 끼워 넣는 자리표시자예요.
📌 3단계 - 명령어 이름·설명까지 번역하기 (Translator)
응답만 바꾸면 반쪽짜리예요. 한국 유저 화면에는 명령어 자체가 /인사로 보이면 더 좋겠죠? 이럴 때 쓰는 게 app_commands.Translator입니다.
from discord import app_commands
from discord.app_commands import locale_str as _T
COMMAND_I18N = {
"ko": {
"hello": "인사",
"Send a friendly greeting": "봇이 반갑게 인사를 건네요",
},
"ja": {
"hello": "あいさつ",
"Send a friendly greeting": "ボットがあいさつします",
},
}
class MyTranslator(app_commands.Translator):
async def translate(self, string, locale, context):
# 번역이 있으면 번역문을, 없으면 None(원문 유지)을 돌려줘요
return COMMAND_I18N.get(str(locale), {}).get(string.message)하나씩 뜯어볼게요 💡
- locale_str (_T) : "이 문자열은 번역 대상이에요"라고 표시하는 마커예요. 명령어를 만들 때
name=_T("hello")처럼 감싸줍니다. - Translator : 명령어를 서버에 등록(sync)할 때 디스코드가 지원하는 모든 언어에 대해
translate()를 호출해요. 번역이 없으면None을 돌려주면 원문이 그대로 쓰여요. - string.message :
_T()로 감쌌던 원문 문자열이에요. 이걸 키로 번역 사전에서 찾아요. - ⚠️ 명령어 이름 규칙은 번역문에도 똑같이 적용돼요. 공백 금지, 영문은 소문자만! (한글·일본어는 그대로 OK)
마지막으로 봇이 켜질 때 번역기를 sync보다 먼저 등록해요.
@bot.event
async def on_ready():
await bot.tree.set_translator(MyTranslator()) # 반드시 sync보다 먼저!
await bot.tree.sync()
print(f"{bot.user} 로그인 완료!")📌 전체 코드 (복붙 OK)
# discord.py 2.7.x / Python 3.8+
from typing import Optional
import discord
from discord import app_commands
from discord.app_commands import locale_str as _T
from discord.ext import commands
intents = discord.Intents.default()
bot = commands.Bot(command_prefix="!", intents=intents)
# 명령어 이름·설명 번역표 (Translator가 사용)
COMMAND_I18N = {
"ko": {
"hello": "인사",
"Send a friendly greeting": "봇이 반갑게 인사를 건네요",
},
"ja": {
"hello": "あいさつ",
"Send a friendly greeting": "ボットがあいさつします",
},
}
# 응답 메시지 번역표 (interaction.locale로 선택)
RESPONSES = {
"ko": "안녕하세요, {user}님! 만나서 반가워요 🙌",
"ja": "こんにちは、{user}さん!",
"en-US": "Hello, {user}! Nice to meet you 🙌",
}
DEFAULT_LOCALE = "en-US"
class MyTranslator(app_commands.Translator):
async def translate(
self,
string: app_commands.locale_str,
locale: discord.Locale,
context: app_commands.TranslationContext,
) -> Optional[str]:
return COMMAND_I18N.get(str(locale), {}).get(string.message)
@bot.tree.command(name=_T("hello"), description=_T("Send a friendly greeting"))
async def hello(interaction: discord.Interaction):
lang = str(interaction.locale) # 예: 'ko', 'ja', 'en-US'
template = RESPONSES.get(lang, RESPONSES[DEFAULT_LOCALE])
await interaction.response.send_message(
template.format(user=interaction.user.display_name)
)
@bot.event
async def on_ready():
await bot.tree.set_translator(MyTranslator()) # 반드시 sync보다 먼저!
await bot.tree.sync()
print(f"{bot.user} 로그인 완료!")
bot.run("여기에 봇 토큰 입력")📌 실행 결과
봇을 실행하고 명령어를 입력해보면...
- 한국어 클라이언트: 명령어 목록에 /인사 - 봇이 반갑게 인사를 건네요로 표시되고, 실행하면 "안녕하세요, ○○님! 만나서 반가워요 🙌"
- 영어 클라이언트: /hello - Send a friendly greeting으로 표시되고, "Hello, ○○! Nice to meet you 🙌"
- 일본어 클라이언트: /あいさつ로 표시! 같은 명령어인데 언어별로 완전히 다르게 보여요.


번역 사전에 없는 언어(프랑스어 등)로 실행하면 기본값인 영어로 응답하는 것도 확인해보세요!
📌 자주 나는 에러
- 명령어 이름이 번역 안 되고 영어로만 나와요
원인:
set_translator()를sync()뒤에 호출했거나, 번역기 등록 후 재동기화를 안 한 경우예요. 번역은 sync 시점에 적용되거든요. 해결:await bot.tree.set_translator(...)→await bot.tree.sync()순서를 지키고, 디스코드 클라이언트에서 Ctrl+R로 새로고침해보세요. 반영까지 몇 분 걸릴 수도 있어요. - sync 중 400 Bad Request (CommandSyncFailure) 에러가 나요 원인: 번역된 명령어 이름이 디스코드 규칙을 어긴 경우예요. 명령어 이름엔 공백이 들어갈 수 없고, 영문 대문자도 안 돼요. 해결: 번역 사전에서 명령어 이름 부분을 확인하세요. "인사 하기"(공백 ❌) → "인사하기"(⭕), "Hello"(대문자 ❌) → "hello"(⭕)
- interaction.locale이 항상 en-US로 나와요
원인:
locale은 서버 언어가 아니라 각 사용자의 디스코드 앱 언어 설정 기준이에요. 내 앱이 영어로 설정돼 있으면 en-US가 정상이에요. 해결: 디스코드 설정 → 언어에서 한국어로 바꾸고 다시 테스트해보세요. 서버 기준 언어가 필요하면interaction.guild_locale을 쓰면 됩니다.
📌 마무리
오늘은 interaction.locale로 사용자 언어를 읽고, 번역 사전으로 응답을 바꾸고, Translator로 명령어 이름·설명까지 번역하는 3단계 다국어 봇을 만들어봤어요. 번역 사전에 언어 한 줄만 추가하면 어떤 언어든 지원할 수 있으니, 여러분 서버에 맞게 확장해보세요!
다음 편에서는 명령어 도배를 막는 쿨다운(Cooldown)과 권한 관리를 다뤄볼 예정이에요. 기대해주세요 🙌
📚 디스코드 봇 만들기 시리즈
- 디스코드 봇 만들기 - Slash Command 완전 정복!
- 디스코드 봇 만들기 #2 - Slash Command에 옵션(Arguments) 추가하기!
- 디스코드 봇 만들기 #3 - Slash Command에 서브 커맨드(Subcommand) 넣기!
- 디스코드 봇 만들기 #4 - Slash Command로 임베드 전송하기!
- 디스코드 봇 만들기 #5 - 버튼(Button) 상호작용 구현하기
- 디스코드 봇 만들기 #6 - 드롭다운(Select Menu) 메뉴 구현하기
- 디스코드 봇 만들기 #7 - 모달(Modal)로 입력 받기
- 디스코드 봇 만들기 #8 - 임베드(Embed) 이미지·필드로 꾸미기
- 디스코드 봇 만들기 #9 - AI(Claude·ChatGPT API) 연동하기
- 디스코드 봇 만들기 #10 - 다국어(i18n) 지원하기 ← 지금 이 글!
연재 · 32편 중 10번째
디스코드 봇 만들기
- #1디스코드 봇 만들기 - Slash Command 완전 정복!
- #2Slash Command에 옵션(Arguments) 추가하기!
- #3Slash Command에 서브 커맨드(Subcommand) 넣기!
- #4Slash Command로 임베드 전송하기!
- #5버튼(Button) 상호작용 구현하기!
- #6드롭다운(Select Menu) 메뉴 구현하기!
- #7모달(Modal)로 입력 받기 구현하기 (파이썬 예제)
- #8임베드(Embed) 이미지·필드로 꾸미기 (파이썬 예제)
- #9AI(Claude·ChatGPT API) 연동하기! (파이썬 예제)
- #10다국어(i18n) 지원하기! (파이썬 예제)지금 읽는 글
- #11플라스크(Flask)로 웹 대시보드 만들기! (파이썬 예제)
- #12명령어 쿨다운(Cooldown)·권한(Permission) 관리하기! (파이썬 예제)
- #13역할·채널 자동화로 서버 관리하기! (파이썬 예제)
- #14데이터 저장하기! JSON vs SQLite (파이썬 예제)
- #15슬래시 명령어 그룹(Group)으로 명령어 정리하기! (파이썬 예제)
- #16리마인더·알림 기능 만들기! 봇이 먼저 말 걸게 하기 (파이썬 예제)
- #17RAG로 문서 기반 답변봇 만들기! 우리 서버 전용 FAQ 봇 (파이썬 예제)
- #18투표(Poll) 기능 만들기! 다수결로 정하는 서버 규칙 (파이썬 예제)
- #19Cog로 코드 쪼개기! 1000줄 봇도 안 더러워지는 구조 (파이썬 예제)
- #20자동 환영 메시지·온보딩 만들기! 규칙 동의 버튼으로 자동 역할 부여 (파이썬 예제)
- #21키워드 자동응답·금지어 필터 만들기! 경고 누적으로 자동 제재까지 (파이썬 예제)
- #22슬래시 명령어 자동완성(Autocomplete) 만들기! 금지어를 골라서 추가·삭제 (파이썬 예제)
- #23aiosqlite로 비동기 DB 제대로 설계하기! JSON 탈출 (파이썬 예제)
- #24채널 난독화(Channel Obfuscation) 대응하기! 11/16부터 안 보이는 채널이 생겨요 (파이썬 예제)
- #25봇이 죽지 않게! 에러 핸들링·로깅 체계 잡기 (파이썬 예제)
- #26티켓(Ticket) 문의 시스템 만들기! 버튼 하나로 1:1 상담 채널 자동 생성 (파이썬 예제)
- #27티켓 담당자 배정·우선순위 만들기! 스태프가 여러 명이어도 안 꼬이게 (파이썬 예제)
- #28레벨·경험치(XP) 시스템 만들기! 채팅할수록 레벨업, 랭킹판까지 (파이썬 예제)
- #29화폐·상점(Economy) 시스템 만들기! 코인 벌어서 아이템 사기 (파이썬 예제)
- #30투표·설문(Poll) 봇 만들기! 네이티브 투표 + 버튼으로 실시간 집계까지 (파이썬 예제) 🗳️
- #32서버 로그·감사(Audit Log) 채널 만들기! 메시지 삭제·수정·입퇴장·추방까지 자동 기록 (파이썬 예제) 🕵️
- #33임시 음성방 확장, 파티방 만들기! 방장 위임·강퇴·초대 전용(비공개) 방 + 전용 채팅방 자동 생성 (파이썬 예제) 🎉
