分类: Discord 机器人开发

Discord 机器人开发#10支持多语言(i18n)!(Python 示例)

本文译自韩语原文。

目录10 项

大家好!我是 Mojangcam 😎

上一篇 #9 我们给机器人接入了 AI(Claude·ChatGPT API),做出了能聊天的机器人。这一篇要把我们的机器人升级成全球化机器人,也就是支持多语言(i18n)!

运营有海外玩家的游戏服务器时,只会用一种语言回复的机器人难免让人觉得有点可惜。Discord 的每个用户都有自己的客户端语言设置,只要读取这个设置,就能做出给韩国用户回复韩语、给海外用户回复英语的自动回复机器人。甚至连斜杠命令的名称和描述都可以按语言显示成不同的内容!

🧠 i18n 是什么?为什么需要它?

i18n 是 internationalization(国际化)的缩写。因为 i 和 n 之间有 18 个字母,所以叫 i18n 💡

在 Discord 机器人里需要 i18n 的场景比想象中多。

  • 有海外玩家的游戏服务器(Minecraft、ARK 等)里的公告机器人
  • 部署到多个国家服务器的公开机器人
  • 想用用户的语言显示命令说明,降低上手门槛的时候

discord.py 已经内置了实现这些的功能。只要掌握 interaction.locale(用户语言)和 Translator(命令翻译器)这两样就够了!

📌 准备工作

  • Python 3.8 及以上
  • discord.py 2.x(本文以最新版 2.7.1 为准)
  • 机器人 Token + 已邀请机器人的测试服务器(参考 #1)
终端
pip install -U discord.py

📌 第 1 步 - 获取用户语言(interaction.locale)

执行斜杠命令时,Discord 会把该用户的语言信息一起发过来。我们先看看会收到什么值。

Python
@bot.tree.command(name="lang", description="查看我的语言设置")
async def lang(interaction: discord.Interaction):
    await interaction.response.send_message(
        f"客户端语言:{interaction.locale}"
    )

我们逐个拆开来看 💡

  • interaction.locale:执行命令的用户的 Discord 应用语言设置。韩语客户端会收到 ko,英语(美国)是 en-US,日语是 ja。
  • interaction.guild_locale:这个不是用户的语言,而是服务器(公会)的默认语言。适合用在公告这类以服务器为单位的消息上。
  • 返回类型是一个叫 discord.Locale 的枚举(enum),用 str() 包一下就会变成 'ko' 这样的字符串。

📌 第 2 步 - 用翻译字典切换回复消息

接下来创建一个保存各语言回复的翻译字典(dict),再根据 interaction.locale 选出对应的消息发送。

Python
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。

Python
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)到服务器时,Discord 会针对它支持的所有语言调用 translate()。没有翻译时返回 None,就会直接使用原文。
  • string.message:用 _T() 包起来的原文字符串。以它为键去翻译字典里查找。
  • ⚠️ 命令名称的规则同样适用于译文。不能有空格,英文只能用小写!(韩文、日文可以直接用)

最后,在机器人启动时先于 sync 注册翻译器。

Python
@bot.event
async def on_ready():
    await bot.tree.set_translator(MyTranslator())  # 一定要在 sync 之前!
    await bot.tree.sync()
    print(f"{bot.user} 登录成功!")

📌 完整代码(可直接复制)

Python
# 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("在这里输入机器人 Token")

📌 运行结果

启动机器人后输入命令试试……

  • 韩语客户端:命令列表里显示为 /인사 - 봇이 반갑게 인사를 건네요(意为"/问候 - 机器人热情地向你打招呼"),执行后回复"안녕하세요, ○○님! 만나서 반가워요 🙌"("你好,○○!很高兴见到你 🙌")
  • 英语客户端:显示为 /hello - Send a friendly greeting,回复"Hello, ○○! Nice to meet you 🙌"
  • 日语客户端:显示为 /あいさつ!明明是同一个命令,在不同语言下看起来却完全不一样。

也别忘了确认一下:用翻译字典里没有的语言(比如法语)执行时,会用默认的英语回复!

📌 常见报错

  1. 命令名称没有被翻译,只显示英文 原因:在 sync() 之后才调用 set_translator(),或者注册翻译器后没有重新同步。因为翻译是在 sync 的时候生效的。 解决:遵守 await bot.tree.set_translator(...) → await bot.tree.sync() 的顺序,然后在 Discord 客户端按 Ctrl+R 刷新。生效可能需要几分钟。
  2. sync 时出现 400 Bad Request(CommandSyncFailure)错误 原因:翻译后的命令名称违反了 Discord 的规则。命令名称里不能有空格,也不能用英文大写字母。 解决:检查翻译字典里命令名称的部分。"인사 하기"(有空格 ❌)→ "인사하기"(⭕),"Hello"(大写 ❌)→ "hello"(⭕)
  3. interaction.locale 总是 en-US 原因:locale 依据的不是服务器语言,而是每个用户自己的 Discord 应用语言设置。如果你的应用设置成英语,显示 en-US 是正常的。 解决:在 Discord 设置 → 语言里改成韩语(或其他语言)后再测试一次。如果需要以服务器为准的语言,用 interaction.guild_locale 就行。

📌 结语

今天我们用 interaction.locale 读取用户语言,用翻译字典切换回复,再用 Translator 把命令名称和描述也翻译过来,做出了一个三步搞定的多语言机器人。只要在翻译字典里加一行,就能支持任何语言,大家可以根据自己的服务器去扩展!

下一篇准备讲防止刷命令的冷却时间(Cooldown)与权限管理。敬请期待 🙌

📚 Discord 机器人开发系列

  1. Discord 机器人开发 - 彻底掌握 Slash Command!
  2. Discord 机器人开发 #2 - 给 Slash Command 添加选项(Arguments)!
  3. Discord 机器人开发 #3 - 给 Slash Command 加入子命令(Subcommand)!
  4. Discord 机器人开发 #4 - 用 Slash Command 发送嵌入消息!
  5. Discord 机器人开发 #5 - 实现按钮(Button)交互
  6. Discord 机器人开发 #6 - 实现下拉菜单(Select Menu)
  7. Discord 机器人开发 #7 - 用模态框(Modal)接收输入
  8. Discord 机器人开发 #8 - 用嵌入消息(Embed)的图片和字段美化消息
  9. Discord 机器人开发 #9 - 接入 AI(Claude·ChatGPT API)
  10. Discord 机器人开发 #10 - 支持多语言(i18n)← 就是这一篇!

连载 · 共 32 篇中的第 10 篇

Discord 机器人开发

  1. #1Discord 机器人开发 - Slash Command 完全攻略!
  2. #2为 Slash Command 添加选项(Arguments)!
  3. #3在 Slash Command 中添加子命令(Subcommand)!
  4. #4用 Slash Command 发送 Embed 嵌入消息!
  5. #5实现按钮(Button)交互!
  6. #6实现下拉菜单(Select Menu)!
  7. #7用模态框(Modal)接收用户输入(Python 示例)
  8. #8用嵌入消息(Embed)的图片和字段美化消息(Python 示例)
  9. #9接入 AI(Claude·ChatGPT API)!(Python 示例)
  10. #10支持多语言(i18n)!(Python 示例)当前文章
  11. #11用 Flask 制作网页仪表盘!(Python 示例)
  12. #12管理命令冷却时间(Cooldown)与权限(Permission)!(Python 示例)
  13. #13用身份组·频道自动化管理服务器!(Python 示例)
  14. #14保存数据!JSON vs SQLite(Python 示例)
  15. #15슬래시 명령어 그룹(Group)으로 명령어 정리하기! (파이썬 예제) (韩语)
  16. #16리마인더·알림 기능 만들기! 봇이 먼저 말 걸게 하기 (파이썬 예제) (韩语)
  17. #17RAG로 문서 기반 답변봇 만들기! 우리 서버 전용 FAQ 봇 (파이썬 예제) (韩语)
  18. #18투표(Poll) 기능 만들기! 다수결로 정하는 서버 규칙 (파이썬 예제) (韩语)
  19. #19Cog로 코드 쪼개기! 1000줄 봇도 안 더러워지는 구조 (파이썬 예제) (韩语)
  20. #20자동 환영 메시지·온보딩 만들기! 규칙 동의 버튼으로 자동 역할 부여 (파이썬 예제) (韩语)
  21. #21키워드 자동응답·금지어 필터 만들기! 경고 누적으로 자동 제재까지 (파이썬 예제) (韩语)
  22. #22슬래시 명령어 자동완성(Autocomplete) 만들기! 금지어를 골라서 추가·삭제 (파이썬 예제) (韩语)
  23. #23aiosqlite로 비동기 DB 제대로 설계하기! JSON 탈출 (파이썬 예제) (韩语)
  24. #24채널 난독화(Channel Obfuscation) 대응하기! 11/16부터 안 보이는 채널이 생겨요 (파이썬 예제) (韩语)
  25. #25봇이 죽지 않게! 에러 핸들링·로깅 체계 잡기 (파이썬 예제) (韩语)
  26. #26티켓(Ticket) 문의 시스템 만들기! 버튼 하나로 1:1 상담 채널 자동 생성 (파이썬 예제) (韩语)
  27. #27티켓 담당자 배정·우선순위 만들기! 스태프가 여러 명이어도 안 꼬이게 (파이썬 예제) (韩语)
  28. #28레벨·경험치(XP) 시스템 만들기! 채팅할수록 레벨업, 랭킹판까지 (파이썬 예제) (韩语)
  29. #29화폐·상점(Economy) 시스템 만들기! 코인 벌어서 아이템 사기 (파이썬 예제) (韩语)
  30. #30打造投票·问卷(Poll)机器人!原生投票 + 按钮实时统计(Python 示例)🗳️
  31. #32打造服务器日志·审核日志(Audit Log)频道!自动记录消息删除、编辑、成员进出和踢出(Python 示例)🕵️
  32. #33임시 음성방 확장, 파티방 만들기! 방장 위임·강퇴·초대 전용(비공개) 방 + 전용 채팅방 자동 생성 (파이썬 예제) 🎉 (韩语)
显示全部 32 篇收起

作者

Mojangcam

亲手写代码、跑服务器、解决卡住的报错,把一路学到的东西记录下来的开发与 IT 实战博客