mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 03:08:55 -05:00
[Utils] Add humanize_number() function to chat formatting (#2836)
This adds babel as a dependency, and also includes `redbot.core.i18n.get_babel_locale()`
This commit is contained in:
parent
6c3a3fea66
commit
3c1b6ae4cf
1
changelog.d/2836.feature.rst
Normal file
1
changelog.d/2836.feature.rst
Normal file
@ -0,0 +1 @@
|
|||||||
|
New :func:`humanize_number` in :module:`redbot.core.utils.chat_formatting` function to convert numbers into text which respect locale.
|
||||||
1
changelog.d/2836.misc.rst
Normal file
1
changelog.d/2836.misc.rst
Normal file
@ -0,0 +1 @@
|
|||||||
|
New :func:`humanize_number` is used throughout the bot.
|
||||||
@ -19,7 +19,7 @@ import redbot.core
|
|||||||
from redbot.core import Config, commands, checks, bank
|
from redbot.core import Config, commands, checks, bank
|
||||||
from redbot.core.data_manager import cog_data_path
|
from redbot.core.data_manager import cog_data_path
|
||||||
from redbot.core.i18n import Translator, cog_i18n
|
from redbot.core.i18n import Translator, cog_i18n
|
||||||
from redbot.core.utils.chat_formatting import bold, box, pagify
|
from redbot.core.utils.chat_formatting import bold, box, pagify, humanize_number
|
||||||
from redbot.core.utils.menus import (
|
from redbot.core.utils.menus import (
|
||||||
menu,
|
menu,
|
||||||
DEFAULT_CONTROLS,
|
DEFAULT_CONTROLS,
|
||||||
@ -442,7 +442,7 @@ class Audio(commands.Cog):
|
|||||||
await self._embed_msg(
|
await self._embed_msg(
|
||||||
ctx,
|
ctx,
|
||||||
_("Track queueing command price set to {price} {currency}.").format(
|
_("Track queueing command price set to {price} {currency}.").format(
|
||||||
price=price, currency=await bank.get_currency_name(ctx.guild)
|
price=humanize_number(price), currency=await bank.get_currency_name(ctx.guild)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -613,7 +613,9 @@ class Audio(commands.Cog):
|
|||||||
msg += _("DJ Role: [{role.name}]\n").format(role=dj_role_obj)
|
msg += _("DJ Role: [{role.name}]\n").format(role=dj_role_obj)
|
||||||
if jukebox:
|
if jukebox:
|
||||||
msg += _("Jukebox: [{jukebox_name}]\n").format(jukebox_name=jukebox)
|
msg += _("Jukebox: [{jukebox_name}]\n").format(jukebox_name=jukebox)
|
||||||
msg += _("Command price: [{jukebox_price}]\n").format(jukebox_price=jukebox_price)
|
msg += _("Command price: [{jukebox_price}]\n").format(
|
||||||
|
jukebox_price=humanize_number(jukebox_price)
|
||||||
|
)
|
||||||
if maxlength > 0:
|
if maxlength > 0:
|
||||||
msg += _("Max track length: [{tracklength}]\n").format(
|
msg += _("Max track length: [{tracklength}]\n").format(
|
||||||
tracklength=self._dynamic_time(maxlength)
|
tracklength=self._dynamic_time(maxlength)
|
||||||
@ -762,11 +764,15 @@ class Audio(commands.Cog):
|
|||||||
em = discord.Embed(
|
em = discord.Embed(
|
||||||
colour=await ctx.embed_colour(),
|
colour=await ctx.embed_colour(),
|
||||||
title=_("Playing in {num}/{total} servers:").format(
|
title=_("Playing in {num}/{total} servers:").format(
|
||||||
num=server_num, total=total_num
|
num=humanize_number(server_num), total=humanize_number(total_num)
|
||||||
),
|
),
|
||||||
description=page,
|
description=page,
|
||||||
)
|
)
|
||||||
em.set_footer(text="Page {}/{}".format(pages, (math.ceil(len(msg) / 1500))))
|
em.set_footer(
|
||||||
|
text="Page {}/{}".format(
|
||||||
|
humanize_number(pages), humanize_number((math.ceil(len(msg) / 1500)))
|
||||||
|
)
|
||||||
|
)
|
||||||
pages += 1
|
pages += 1
|
||||||
servers_embed.append(em)
|
servers_embed.append(em)
|
||||||
|
|
||||||
@ -933,7 +939,9 @@ class Audio(commands.Cog):
|
|||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
colour=await ctx.embed_colour(), description=(f"{header}\n{formatted_page}")
|
colour=await ctx.embed_colour(), description=(f"{header}\n{formatted_page}")
|
||||||
)
|
)
|
||||||
embed.set_footer(text=_("{num} preset(s)").format(num=len(list(eq_presets.keys()))))
|
embed.set_footer(
|
||||||
|
text=_("{num} preset(s)").format(num=humanize_number(len(list(eq_presets.keys()))))
|
||||||
|
)
|
||||||
page_list.append(embed)
|
page_list.append(embed)
|
||||||
if len(page_list) == 1:
|
if len(page_list) == 1:
|
||||||
return await ctx.send(embed=page_list[0])
|
return await ctx.send(embed=page_list[0])
|
||||||
@ -1869,6 +1877,7 @@ class Audio(commands.Cog):
|
|||||||
song_info = "{} {}".format(i["name"], i["artists"][0]["name"])
|
song_info = "{} {}".format(i["name"], i["artists"][0]["name"])
|
||||||
else:
|
else:
|
||||||
song_info = "{} {}".format(i["track"]["name"], i["track"]["artists"][0]["name"])
|
song_info = "{} {}".format(i["track"]["name"], i["track"]["artists"][0]["name"])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
track_url = await self._youtube_api_search(yt_key, song_info)
|
track_url = await self._youtube_api_search(yt_key, song_info)
|
||||||
except (RuntimeError, aiohttp.client_exceptions.ServerDisconnectedError):
|
except (RuntimeError, aiohttp.client_exceptions.ServerDisconnectedError):
|
||||||
@ -1878,7 +1887,6 @@ class Audio(commands.Cog):
|
|||||||
)
|
)
|
||||||
await playlist_msg.edit(embed=error_embed)
|
await playlist_msg.edit(embed=error_embed)
|
||||||
return None
|
return None
|
||||||
pass
|
|
||||||
try:
|
try:
|
||||||
yt_track = await player.get_tracks(track_url)
|
yt_track = await player.get_tracks(track_url)
|
||||||
except (RuntimeError, aiohttp.client_exceptions.ServerDisconnectedError):
|
except (RuntimeError, aiohttp.client_exceptions.ServerDisconnectedError):
|
||||||
@ -3416,8 +3424,8 @@ class Audio(commands.Cog):
|
|||||||
" Votes: {num_votes}/{num_members}"
|
" Votes: {num_votes}/{num_members}"
|
||||||
" ({cur_percent}% out of {required_percent}% needed)"
|
" ({cur_percent}% out of {required_percent}% needed)"
|
||||||
).format(
|
).format(
|
||||||
num_votes=num_votes,
|
num_votes=humanize_number(num_votes),
|
||||||
num_members=num_members,
|
num_members=humanize_number(num_members),
|
||||||
cur_percent=vote,
|
cur_percent=vote,
|
||||||
required_percent=percent,
|
required_percent=percent,
|
||||||
)
|
)
|
||||||
@ -3869,7 +3877,7 @@ class Audio(commands.Cog):
|
|||||||
await self._embed_msg(
|
await self._embed_msg(
|
||||||
ctx,
|
ctx,
|
||||||
_("Not enough {currency} ({required_credits} required).").format(
|
_("Not enough {currency} ({required_credits} required).").format(
|
||||||
currency=credits_name, required_credits=jukebox_price
|
currency=credits_name, required_credits=humanize_number(jukebox_price)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import discord
|
import discord
|
||||||
from redbot.core.utils.chat_formatting import box
|
from redbot.core.utils.chat_formatting import box, humanize_number
|
||||||
|
|
||||||
from redbot.core import checks, bank, commands
|
from redbot.core import checks, bank, commands
|
||||||
from redbot.core.i18n import Translator, cog_i18n
|
from redbot.core.i18n import Translator, cog_i18n
|
||||||
@ -88,7 +88,9 @@ class Bank(commands.Cog):
|
|||||||
"Bank settings:\n\nBank name: {bank_name}\nCurrency: {currency_name}\n"
|
"Bank settings:\n\nBank name: {bank_name}\nCurrency: {currency_name}\n"
|
||||||
"Default balance: {default_balance}"
|
"Default balance: {default_balance}"
|
||||||
).format(
|
).format(
|
||||||
bank_name=bank_name, currency_name=currency_name, default_balance=default_balance
|
bank_name=bank_name,
|
||||||
|
currency_name=currency_name,
|
||||||
|
default_balance=humanize_number(default_balance),
|
||||||
)
|
)
|
||||||
await ctx.send(box(settings))
|
await ctx.send(box(settings))
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import discord
|
|||||||
from redbot.core import checks, commands
|
from redbot.core import checks, commands
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
from redbot.core.i18n import Translator, cog_i18n
|
from redbot.core.i18n import Translator, cog_i18n
|
||||||
|
from redbot.core.utils.chat_formatting import humanize_number
|
||||||
from redbot.core.utils.mod import slow_deletion, mass_purge
|
from redbot.core.utils.mod import slow_deletion, mass_purge
|
||||||
from redbot.core.utils.predicates import MessagePredicate
|
from redbot.core.utils.predicates import MessagePredicate
|
||||||
from .converters import RawMessageIds
|
from .converters import RawMessageIds
|
||||||
@ -39,7 +40,9 @@ class Cleanup(commands.Cog):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
prompt = await ctx.send(
|
prompt = await ctx.send(
|
||||||
_("Are you sure you want to delete {number} messages? (y/n)").format(number=number)
|
_("Are you sure you want to delete {number} messages? (y/n)").format(
|
||||||
|
number=humanize_number(number)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
response = await ctx.bot.wait_for("message", check=MessagePredicate.same_context(ctx))
|
response = await ctx.bot.wait_for("message", check=MessagePredicate.same_context(ctx))
|
||||||
|
|
||||||
@ -152,7 +155,11 @@ class Cleanup(commands.Cog):
|
|||||||
to_delete.append(ctx.message)
|
to_delete.append(ctx.message)
|
||||||
|
|
||||||
reason = "{}({}) deleted {} messages containing '{}' in channel {}.".format(
|
reason = "{}({}) deleted {} messages containing '{}' in channel {}.".format(
|
||||||
author.name, author.id, len(to_delete), text, channel.id
|
author.name,
|
||||||
|
author.id,
|
||||||
|
humanize_number(len(to_delete), override_locale="en_us"),
|
||||||
|
text,
|
||||||
|
channel.id,
|
||||||
)
|
)
|
||||||
log.info(reason)
|
log.info(reason)
|
||||||
|
|
||||||
@ -208,7 +215,14 @@ class Cleanup(commands.Cog):
|
|||||||
reason = (
|
reason = (
|
||||||
"{}({}) deleted {} messages "
|
"{}({}) deleted {} messages "
|
||||||
" made by {}({}) in channel {}."
|
" made by {}({}) in channel {}."
|
||||||
"".format(author.name, author.id, len(to_delete), member or "???", _id, channel.name)
|
"".format(
|
||||||
|
author.name,
|
||||||
|
author.id,
|
||||||
|
humanize_number(len(to_delete), override_locale="en_US"),
|
||||||
|
member or "???",
|
||||||
|
_id,
|
||||||
|
channel.name,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
log.info(reason)
|
log.info(reason)
|
||||||
|
|
||||||
@ -240,7 +254,10 @@ class Cleanup(commands.Cog):
|
|||||||
)
|
)
|
||||||
|
|
||||||
reason = "{}({}) deleted {} messages in channel {}.".format(
|
reason = "{}({}) deleted {} messages in channel {}.".format(
|
||||||
author.name, author.id, len(to_delete), channel.name
|
author.name,
|
||||||
|
author.id,
|
||||||
|
humanize_number(len(to_delete), override_locale="en_US"),
|
||||||
|
channel.name,
|
||||||
)
|
)
|
||||||
log.info(reason)
|
log.info(reason)
|
||||||
|
|
||||||
@ -277,7 +294,10 @@ class Cleanup(commands.Cog):
|
|||||||
to_delete.append(ctx.message)
|
to_delete.append(ctx.message)
|
||||||
|
|
||||||
reason = "{}({}) deleted {} messages in channel {}.".format(
|
reason = "{}({}) deleted {} messages in channel {}.".format(
|
||||||
author.name, author.id, len(to_delete), channel.name
|
author.name,
|
||||||
|
author.id,
|
||||||
|
humanize_number(len(to_delete), override_locale="en_US"),
|
||||||
|
channel.name,
|
||||||
)
|
)
|
||||||
log.info(reason)
|
log.info(reason)
|
||||||
|
|
||||||
@ -319,7 +339,10 @@ class Cleanup(commands.Cog):
|
|||||||
)
|
)
|
||||||
to_delete.append(ctx.message)
|
to_delete.append(ctx.message)
|
||||||
reason = "{}({}) deleted {} messages in channel {}.".format(
|
reason = "{}({}) deleted {} messages in channel {}.".format(
|
||||||
author.name, author.id, len(to_delete), channel.name
|
author.name,
|
||||||
|
author.id,
|
||||||
|
humanize_number(len(to_delete), override_locale="en_US"),
|
||||||
|
channel.name,
|
||||||
)
|
)
|
||||||
log.info(reason)
|
log.info(reason)
|
||||||
|
|
||||||
@ -420,7 +443,12 @@ class Cleanup(commands.Cog):
|
|||||||
reason = (
|
reason = (
|
||||||
"{}({}) deleted {} "
|
"{}({}) deleted {} "
|
||||||
" command messages in channel {}."
|
" command messages in channel {}."
|
||||||
"".format(author.name, author.id, len(to_delete), channel.name)
|
"".format(
|
||||||
|
author.name,
|
||||||
|
author.id,
|
||||||
|
humanize_number(len(to_delete), override_locale="en_US"),
|
||||||
|
channel.name,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
log.info(reason)
|
log.info(reason)
|
||||||
|
|
||||||
@ -500,7 +528,12 @@ class Cleanup(commands.Cog):
|
|||||||
reason = (
|
reason = (
|
||||||
"{}({}) deleted {} messages "
|
"{}({}) deleted {} messages "
|
||||||
"sent by the bot in {}."
|
"sent by the bot in {}."
|
||||||
"".format(author.name, author.id, len(to_delete), channel_name)
|
"".format(
|
||||||
|
author.name,
|
||||||
|
author.id,
|
||||||
|
humanize_number(len(to_delete), override_locale="en_US"),
|
||||||
|
channel_name,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
log.info(reason)
|
log.info(reason)
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import discord
|
|||||||
from redbot.cogs.bank import check_global_setting_guildowner, check_global_setting_admin
|
from redbot.cogs.bank import check_global_setting_guildowner, check_global_setting_admin
|
||||||
from redbot.core import Config, bank, commands, errors
|
from redbot.core import Config, bank, commands, errors
|
||||||
from redbot.core.i18n import Translator, cog_i18n
|
from redbot.core.i18n import Translator, cog_i18n
|
||||||
from redbot.core.utils.chat_formatting import box
|
from redbot.core.utils.chat_formatting import box, humanize_number
|
||||||
from redbot.core.utils.menus import menu, DEFAULT_CONTROLS
|
from redbot.core.utils.menus import menu, DEFAULT_CONTROLS
|
||||||
|
|
||||||
from redbot.core.bot import Red
|
from redbot.core.bot import Red
|
||||||
@ -162,7 +162,7 @@ class Economy(commands.Cog):
|
|||||||
|
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
_("{user}'s balance is {num} {currency}").format(
|
_("{user}'s balance is {num} {currency}").format(
|
||||||
user=user.display_name, num=bal, currency=currency
|
user=user.display_name, num=humanize_number(bal), currency=currency
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -179,7 +179,10 @@ class Economy(commands.Cog):
|
|||||||
|
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
_("{user} transferred {num} {currency} to {other_user}").format(
|
_("{user} transferred {num} {currency} to {other_user}").format(
|
||||||
user=from_.display_name, num=amount, currency=currency, other_user=to.display_name
|
user=from_.display_name,
|
||||||
|
num=humanize_number(amount),
|
||||||
|
currency=currency,
|
||||||
|
other_user=to.display_name,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -203,7 +206,7 @@ class Economy(commands.Cog):
|
|||||||
await bank.deposit_credits(to, creds.sum)
|
await bank.deposit_credits(to, creds.sum)
|
||||||
msg = _("{author} added {num} {currency} to {user}'s account.").format(
|
msg = _("{author} added {num} {currency} to {user}'s account.").format(
|
||||||
author=author.display_name,
|
author=author.display_name,
|
||||||
num=creds.sum,
|
num=humanize_number(creds.sum),
|
||||||
currency=currency,
|
currency=currency,
|
||||||
user=to.display_name,
|
user=to.display_name,
|
||||||
)
|
)
|
||||||
@ -211,7 +214,7 @@ class Economy(commands.Cog):
|
|||||||
await bank.withdraw_credits(to, creds.sum)
|
await bank.withdraw_credits(to, creds.sum)
|
||||||
msg = _("{author} removed {num} {currency} from {user}'s account.").format(
|
msg = _("{author} removed {num} {currency} from {user}'s account.").format(
|
||||||
author=author.display_name,
|
author=author.display_name,
|
||||||
num=creds.sum,
|
num=humanize_number(creds.sum),
|
||||||
currency=currency,
|
currency=currency,
|
||||||
user=to.display_name,
|
user=to.display_name,
|
||||||
)
|
)
|
||||||
@ -219,7 +222,7 @@ class Economy(commands.Cog):
|
|||||||
await bank.set_balance(to, creds.sum)
|
await bank.set_balance(to, creds.sum)
|
||||||
msg = _("{author} set {user}'s account balance to {num} {currency}.").format(
|
msg = _("{author} set {user}'s account balance to {num} {currency}.").format(
|
||||||
author=author.display_name,
|
author=author.display_name,
|
||||||
num=creds.sum,
|
num=humanize_number(creds.sum),
|
||||||
currency=currency,
|
currency=currency,
|
||||||
user=to.display_name,
|
user=to.display_name,
|
||||||
)
|
)
|
||||||
@ -271,7 +274,9 @@ class Economy(commands.Cog):
|
|||||||
"You've reached the maximum amount of {currency}!"
|
"You've reached the maximum amount of {currency}!"
|
||||||
"Please spend some more \N{GRIMACING FACE}\n\n"
|
"Please spend some more \N{GRIMACING FACE}\n\n"
|
||||||
"You currently have {new_balance} {currency}."
|
"You currently have {new_balance} {currency}."
|
||||||
).format(currency=credits_name, new_balance=exc.max_balance)
|
).format(
|
||||||
|
currency=credits_name, new_balance=humanize_number(exc.max_balance)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
next_payday = cur_time + await self.config.PAYDAY_TIME()
|
next_payday = cur_time + await self.config.PAYDAY_TIME()
|
||||||
@ -287,9 +292,9 @@ class Economy(commands.Cog):
|
|||||||
).format(
|
).format(
|
||||||
author=author,
|
author=author,
|
||||||
currency=credits_name,
|
currency=credits_name,
|
||||||
amount=await self.config.PAYDAY_CREDITS(),
|
amount=humanize_number(await self.config.PAYDAY_CREDITS()),
|
||||||
new_balance=await bank.get_balance(author),
|
new_balance=humanize_number(await bank.get_balance(author)),
|
||||||
pos=pos,
|
pos=humanize_number(pos) if pos else pos,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -319,7 +324,9 @@ class Economy(commands.Cog):
|
|||||||
"You've reached the maximum amount of {currency}! "
|
"You've reached the maximum amount of {currency}! "
|
||||||
"Please spend some more \N{GRIMACING FACE}\n\n"
|
"Please spend some more \N{GRIMACING FACE}\n\n"
|
||||||
"You currently have {new_balance} {currency}."
|
"You currently have {new_balance} {currency}."
|
||||||
).format(currency=credits_name, new_balance=exc.max_balance)
|
).format(
|
||||||
|
currency=credits_name, new_balance=humanize_number(exc.max_balance)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
next_payday = cur_time + await self.config.guild(guild).PAYDAY_TIME()
|
next_payday = cur_time + await self.config.guild(guild).PAYDAY_TIME()
|
||||||
@ -334,9 +341,9 @@ class Economy(commands.Cog):
|
|||||||
).format(
|
).format(
|
||||||
author=author,
|
author=author,
|
||||||
currency=credits_name,
|
currency=credits_name,
|
||||||
amount=credit_amount,
|
amount=humanize_number(credit_amount),
|
||||||
new_balance=await bank.get_balance(author),
|
new_balance=humanize_number(await bank.get_balance(author)),
|
||||||
pos=pos,
|
pos=humanize_number(pos) if pos else pos,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -364,7 +371,7 @@ class Economy(commands.Cog):
|
|||||||
else:
|
else:
|
||||||
bank_sorted = await bank.get_leaderboard(positions=top, guild=guild)
|
bank_sorted = await bank.get_leaderboard(positions=top, guild=guild)
|
||||||
try:
|
try:
|
||||||
bal_len = len(str(bank_sorted[0][1]["balance"]))
|
bal_len = len(humanize_number(bank_sorted[0][1]["balance"]))
|
||||||
# first user is the largest we'll see
|
# first user is the largest we'll see
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return await ctx.send(_("There are no accounts in the bank."))
|
return await ctx.send(_("There are no accounts in the bank."))
|
||||||
@ -387,14 +394,17 @@ class Economy(commands.Cog):
|
|||||||
if await ctx.bot.is_owner(ctx.author):
|
if await ctx.bot.is_owner(ctx.author):
|
||||||
user_id = f"({str(acc[0])})"
|
user_id = f"({str(acc[0])})"
|
||||||
name = f"{acc[1]['name']} {user_id}"
|
name = f"{acc[1]['name']} {user_id}"
|
||||||
balance = acc[1]["balance"]
|
balance = humanize_number(acc[1]["balance"])
|
||||||
|
|
||||||
if acc[0] != author.id:
|
if acc[0] != author.id:
|
||||||
temp_msg += f"{f'{pos}.': <{pound_len+2}} {balance: <{bal_len + 5}} {name}\n"
|
temp_msg += (
|
||||||
|
f"{f'{humanize_number(pos)}.': <{pound_len+2}} "
|
||||||
|
f"{balance: <{bal_len + 5}} {name}\n"
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
temp_msg += (
|
temp_msg += (
|
||||||
f"{f'{pos}.': <{pound_len+2}} "
|
f"{f'{humanize_number(pos)}.': <{pound_len+2}} "
|
||||||
f"{balance: <{bal_len + 5}} "
|
f"{balance: <{bal_len + 5}} "
|
||||||
f"<<{author.display_name}>>\n"
|
f"<<{author.display_name}>>\n"
|
||||||
)
|
)
|
||||||
@ -503,8 +513,8 @@ class Economy(commands.Cog):
|
|||||||
"Please spend some more \N{GRIMACING FACE}\n{old_balance} -> {new_balance}!"
|
"Please spend some more \N{GRIMACING FACE}\n{old_balance} -> {new_balance}!"
|
||||||
).format(
|
).format(
|
||||||
currency=await bank.get_currency_name(getattr(channel, "guild", None)),
|
currency=await bank.get_currency_name(getattr(channel, "guild", None)),
|
||||||
old_balance=then,
|
old_balance=humanize_number(then),
|
||||||
new_balance=exc.max_balance,
|
new_balance=humanize_number(exc.max_balance),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
@ -523,10 +533,10 @@ class Economy(commands.Cog):
|
|||||||
slot=slot,
|
slot=slot,
|
||||||
author=author,
|
author=author,
|
||||||
phrase=phrase,
|
phrase=phrase,
|
||||||
bid=bid,
|
bid=humanize_number(bid),
|
||||||
old_balance=then,
|
old_balance=humanize_number(then),
|
||||||
new_balance=now,
|
new_balance=humanize_number(now),
|
||||||
pay=pay,
|
pay=humanize_number(pay),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -552,12 +562,12 @@ class Economy(commands.Cog):
|
|||||||
"Payday cooldown: {payday_time}\n"
|
"Payday cooldown: {payday_time}\n"
|
||||||
"Amount given at account registration: {register_amount}"
|
"Amount given at account registration: {register_amount}"
|
||||||
).format(
|
).format(
|
||||||
slot_min=await conf.SLOT_MIN(),
|
slot_min=humanize_number(await conf.SLOT_MIN()),
|
||||||
slot_max=await conf.SLOT_MAX(),
|
slot_max=humanize_number(await conf.SLOT_MAX()),
|
||||||
slot_time=await conf.SLOT_TIME(),
|
slot_time=humanize_number(await conf.SLOT_TIME()),
|
||||||
payday_time=await conf.PAYDAY_TIME(),
|
payday_time=humanize_number(await conf.PAYDAY_TIME()),
|
||||||
payday_amount=await conf.PAYDAY_CREDITS(),
|
payday_amount=humanize_number(await conf.PAYDAY_CREDITS()),
|
||||||
register_amount=await bank.get_default_balance(guild),
|
register_amount=humanize_number(await bank.get_default_balance(guild)),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -575,7 +585,9 @@ class Economy(commands.Cog):
|
|||||||
await self.config.guild(guild).SLOT_MIN.set(bid)
|
await self.config.guild(guild).SLOT_MIN.set(bid)
|
||||||
credits_name = await bank.get_currency_name(guild)
|
credits_name = await bank.get_currency_name(guild)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
_("Minimum bid is now {bid} {currency}.").format(bid=bid, currency=credits_name)
|
_("Minimum bid is now {bid} {currency}.").format(
|
||||||
|
bid=humanize_number(bid), currency=credits_name
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@economyset.command()
|
@economyset.command()
|
||||||
@ -594,7 +606,9 @@ class Economy(commands.Cog):
|
|||||||
else:
|
else:
|
||||||
await self.config.guild(guild).SLOT_MAX.set(bid)
|
await self.config.guild(guild).SLOT_MAX.set(bid)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
_("Maximum bid is now {bid} {currency}.").format(bid=bid, currency=credits_name)
|
_("Maximum bid is now {bid} {currency}.").format(
|
||||||
|
bid=humanize_number(bid), currency=credits_name
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@economyset.command()
|
@economyset.command()
|
||||||
@ -635,7 +649,7 @@ class Economy(commands.Cog):
|
|||||||
await self.config.guild(guild).PAYDAY_CREDITS.set(creds)
|
await self.config.guild(guild).PAYDAY_CREDITS.set(creds)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
_("Every payday will now give {num} {currency}.").format(
|
_("Every payday will now give {num} {currency}.").format(
|
||||||
num=creds, currency=credits_name
|
num=humanize_number(creds), currency=credits_name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -655,7 +669,7 @@ class Economy(commands.Cog):
|
|||||||
_(
|
_(
|
||||||
"Every payday will now give {num} {currency} "
|
"Every payday will now give {num} {currency} "
|
||||||
"to people with the role {role_name}."
|
"to people with the role {role_name}."
|
||||||
).format(num=creds, currency=credits_name, role_name=role.name)
|
).format(num=humanize_number(creds), currency=credits_name, role_name=role.name)
|
||||||
)
|
)
|
||||||
|
|
||||||
@economyset.command()
|
@economyset.command()
|
||||||
@ -668,7 +682,7 @@ class Economy(commands.Cog):
|
|||||||
await bank.set_default_balance(creds, guild)
|
await bank.set_default_balance(creds, guild)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
_("Registering an account will now give {num} {currency}.").format(
|
_("Registering an account will now give {num} {currency}.").format(
|
||||||
num=creds, currency=credits_name
|
num=humanize_number(creds), currency=credits_name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import discord
|
|||||||
from redbot.core import commands
|
from redbot.core import commands
|
||||||
from redbot.core.i18n import Translator, cog_i18n
|
from redbot.core.i18n import Translator, cog_i18n
|
||||||
from redbot.core.utils.menus import menu, DEFAULT_CONTROLS
|
from redbot.core.utils.menus import menu, DEFAULT_CONTROLS
|
||||||
from redbot.core.utils.chat_formatting import escape, italics
|
from redbot.core.utils.chat_formatting import escape, italics, humanize_number
|
||||||
|
|
||||||
_ = T_ = Translator("General", __file__)
|
_ = T_ = Translator("General", __file__)
|
||||||
|
|
||||||
@ -89,7 +89,11 @@ class General(commands.Cog):
|
|||||||
author = ctx.author
|
author = ctx.author
|
||||||
if number > 1:
|
if number > 1:
|
||||||
n = randint(1, number)
|
n = randint(1, number)
|
||||||
await ctx.send("{author.mention} :game_die: {n} :game_die:".format(author=author, n=n))
|
await ctx.send(
|
||||||
|
"{author.mention} :game_die: {n} :game_die:".format(
|
||||||
|
author=author, n=humanize_number(n)
|
||||||
|
)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
await ctx.send(_("{author.mention} Maybe higher than 1? ;P").format(author=author))
|
await ctx.send(_("{author.mention} Maybe higher than 1? ;P").format(author=author))
|
||||||
|
|
||||||
@ -223,10 +227,12 @@ class General(commands.Cog):
|
|||||||
async def serverinfo(self, ctx):
|
async def serverinfo(self, ctx):
|
||||||
"""Show server information."""
|
"""Show server information."""
|
||||||
guild = ctx.guild
|
guild = ctx.guild
|
||||||
online = len([m.status for m in guild.members if m.status != discord.Status.offline])
|
online = humanize_number(
|
||||||
total_users = len(guild.members)
|
len([m.status for m in guild.members if m.status != discord.Status.offline])
|
||||||
text_channels = len(guild.text_channels)
|
)
|
||||||
voice_channels = len(guild.voice_channels)
|
total_users = humanize_number(len(guild.members))
|
||||||
|
text_channels = humanize_number(len(guild.text_channels))
|
||||||
|
voice_channels = humanize_number(len(guild.voice_channels))
|
||||||
passed = (ctx.message.created_at - guild.created_at).days
|
passed = (ctx.message.created_at - guild.created_at).days
|
||||||
created_at = _("Since {date}. That's over {num} days ago!").format(
|
created_at = _("Since {date}. That's over {num} days ago!").format(
|
||||||
date=guild.created_at.strftime("%d %b %Y %H:%M"), num=passed
|
date=guild.created_at.strftime("%d %b %Y %H:%M"), num=passed
|
||||||
@ -234,9 +240,9 @@ class General(commands.Cog):
|
|||||||
data = discord.Embed(description=created_at, colour=(await ctx.embed_colour()))
|
data = discord.Embed(description=created_at, colour=(await ctx.embed_colour()))
|
||||||
data.add_field(name=_("Region"), value=str(guild.region))
|
data.add_field(name=_("Region"), value=str(guild.region))
|
||||||
data.add_field(name=_("Users"), value=f"{online}/{total_users}")
|
data.add_field(name=_("Users"), value=f"{online}/{total_users}")
|
||||||
data.add_field(name=_("Text Channels"), value=str(text_channels))
|
data.add_field(name=_("Text Channels"), value=text_channels)
|
||||||
data.add_field(name=_("Voice Channels"), value=str(voice_channels))
|
data.add_field(name=_("Voice Channels"), value=voice_channels)
|
||||||
data.add_field(name=_("Roles"), value=str(len(guild.roles)))
|
data.add_field(name=_("Roles"), value=humanize_number(len(guild.roles)))
|
||||||
data.add_field(name=_("Owner"), value=str(guild.owner))
|
data.add_field(name=_("Owner"), value=str(guild.owner))
|
||||||
data.set_footer(text=_("Server ID: ") + str(guild.id))
|
data.set_footer(text=_("Server ID: ") + str(guild.id))
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ from typing import cast, Optional, Union
|
|||||||
|
|
||||||
import discord
|
import discord
|
||||||
from redbot.core import commands, i18n, checks, modlog
|
from redbot.core import commands, i18n, checks, modlog
|
||||||
from redbot.core.utils.chat_formatting import pagify
|
from redbot.core.utils.chat_formatting import pagify, humanize_number
|
||||||
from redbot.core.utils.mod import is_allowed_by_hierarchy, get_audit_reason
|
from redbot.core.utils.mod import is_allowed_by_hierarchy, get_audit_reason
|
||||||
from .abc import MixinMeta
|
from .abc import MixinMeta
|
||||||
from .converters import RawUserIds
|
from .converters import RawUserIds
|
||||||
@ -244,7 +244,9 @@ class KickBanMixin(MixinMeta):
|
|||||||
errors = {}
|
errors = {}
|
||||||
|
|
||||||
async def show_results():
|
async def show_results():
|
||||||
text = _("Banned {num} users from the server.").format(num=len(banned))
|
text = _("Banned {num} users from the server.").format(
|
||||||
|
num=humanize_number(len(banned))
|
||||||
|
)
|
||||||
if errors:
|
if errors:
|
||||||
text += _("\nErrors:\n")
|
text += _("\nErrors:\n")
|
||||||
text += "\n".join(errors.values())
|
text += "\n".join(errors.values())
|
||||||
|
|||||||
@ -6,7 +6,7 @@ from collections import Counter
|
|||||||
import discord
|
import discord
|
||||||
from redbot.core import bank
|
from redbot.core import bank
|
||||||
from redbot.core.i18n import Translator
|
from redbot.core.i18n import Translator
|
||||||
from redbot.core.utils.chat_formatting import box, bold, humanize_list
|
from redbot.core.utils.chat_formatting import box, bold, humanize_list, humanize_number
|
||||||
from redbot.core.utils.common_filters import normalize_smartquotes
|
from redbot.core.utils.common_filters import normalize_smartquotes
|
||||||
from .log import LOG
|
from .log import LOG
|
||||||
|
|
||||||
@ -292,7 +292,7 @@ class TriviaSession:
|
|||||||
" for coming first."
|
" for coming first."
|
||||||
).format(
|
).format(
|
||||||
user=winner.display_name,
|
user=winner.display_name,
|
||||||
num=amount,
|
num=humanize_number(amount),
|
||||||
currency=await bank.get_currency_name(self.ctx.guild),
|
currency=await bank.get_currency_name(self.ctx.guild),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@ -5,6 +5,7 @@ from functools import wraps
|
|||||||
|
|
||||||
import discord
|
import discord
|
||||||
|
|
||||||
|
from redbot.core.utils.chat_formatting import humanize_number
|
||||||
from . import Config, errors, commands
|
from . import Config, errors, commands
|
||||||
from .i18n import Translator
|
from .i18n import Translator
|
||||||
|
|
||||||
@ -237,11 +238,20 @@ async def withdraw_credits(member: discord.Member, amount: int) -> int:
|
|||||||
if not isinstance(amount, int):
|
if not isinstance(amount, int):
|
||||||
raise TypeError("Withdrawal amount must be of type int, not {}.".format(type(amount)))
|
raise TypeError("Withdrawal amount must be of type int, not {}.".format(type(amount)))
|
||||||
if _invalid_amount(amount):
|
if _invalid_amount(amount):
|
||||||
raise ValueError("Invalid withdrawal amount {} < 0".format(amount))
|
raise ValueError(
|
||||||
|
"Invalid withdrawal amount {} < 0".format(
|
||||||
|
humanize_number(amount, override_locale="en_US")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
bal = await get_balance(member)
|
bal = await get_balance(member)
|
||||||
if amount > bal:
|
if amount > bal:
|
||||||
raise ValueError("Insufficient funds {} > {}".format(amount, bal))
|
raise ValueError(
|
||||||
|
"Insufficient funds {} > {}".format(
|
||||||
|
humanize_number(amount, override_locale="en_US"),
|
||||||
|
humanize_number(bal, override_locale="en_US"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return await set_balance(member, bal - amount)
|
return await set_balance(member, bal - amount)
|
||||||
|
|
||||||
@ -272,7 +282,11 @@ async def deposit_credits(member: discord.Member, amount: int) -> int:
|
|||||||
if not isinstance(amount, int):
|
if not isinstance(amount, int):
|
||||||
raise TypeError("Deposit amount must be of type int, not {}.".format(type(amount)))
|
raise TypeError("Deposit amount must be of type int, not {}.".format(type(amount)))
|
||||||
if _invalid_amount(amount):
|
if _invalid_amount(amount):
|
||||||
raise ValueError("Invalid deposit amount {} <= 0".format(amount))
|
raise ValueError(
|
||||||
|
"Invalid deposit amount {} <= 0".format(
|
||||||
|
humanize_number(amount, override_locale="en_US")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
bal = await get_balance(member)
|
bal = await get_balance(member)
|
||||||
return await set_balance(member, amount + bal)
|
return await set_balance(member, amount + bal)
|
||||||
@ -309,7 +323,11 @@ async def transfer_credits(from_: discord.Member, to: discord.Member, amount: in
|
|||||||
if not isinstance(amount, int):
|
if not isinstance(amount, int):
|
||||||
raise TypeError("Transfer amount must be of type int, not {}.".format(type(amount)))
|
raise TypeError("Transfer amount must be of type int, not {}.".format(type(amount)))
|
||||||
if _invalid_amount(amount):
|
if _invalid_amount(amount):
|
||||||
raise ValueError("Invalid transfer amount {} <= 0".format(amount))
|
raise ValueError(
|
||||||
|
"Invalid transfer amount {} <= 0".format(
|
||||||
|
humanize_number(amount, override_locale="en_US")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if await get_balance(to) + amount > MAX_BALANCE:
|
if await get_balance(to) + amount > MAX_BALANCE:
|
||||||
currency = await get_currency_name(to.guild)
|
currency = await get_currency_name(to.guild)
|
||||||
@ -727,7 +745,7 @@ def cost(amount: int):
|
|||||||
credits_name = await get_currency_name(context.guild)
|
credits_name = await get_currency_name(context.guild)
|
||||||
raise commands.UserFeedbackCheckFailure(
|
raise commands.UserFeedbackCheckFailure(
|
||||||
_("You need at least {cost} {currency} to use this command.").format(
|
_("You need at least {cost} {currency} to use this command.").format(
|
||||||
cost=amount, currency=credits_name
|
cost=humanize_number(amount), currency=credits_name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import importlib.machinery
|
|||||||
|
|
||||||
import discord
|
import discord
|
||||||
|
|
||||||
|
from redbot.core.utils.chat_formatting import humanize_number
|
||||||
from .i18n import Translator
|
from .i18n import Translator
|
||||||
|
|
||||||
_ = Translator(__name__, __file__)
|
_ = Translator(__name__, __file__)
|
||||||
@ -45,8 +46,8 @@ class BalanceTooHigh(BankError, OverflowError):
|
|||||||
self.currency_name = currency_name
|
self.currency_name = currency_name
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return _("{user}'s balance cannot rise above {max:,} {currency}.").format(
|
return _("{user}'s balance cannot rise above max {currency}.").format(
|
||||||
user=self.user, max=self.max_balance, currency=self.currency_name
|
user=self.user, max=humanize_number(self.max_balance), currency=self.currency_name
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,21 @@
|
|||||||
import contextlib
|
import contextlib
|
||||||
|
import functools
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Callable, Union, Dict
|
from typing import Callable, Union, Dict, Optional
|
||||||
|
|
||||||
__all__ = ["get_locale", "set_locale", "reload_locales", "cog_i18n", "Translator"]
|
import babel.localedata
|
||||||
|
from babel.core import Locale
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"get_locale",
|
||||||
|
"set_locale",
|
||||||
|
"reload_locales",
|
||||||
|
"cog_i18n",
|
||||||
|
"Translator",
|
||||||
|
"get_babel_locale",
|
||||||
|
]
|
||||||
|
|
||||||
_current_locale = "en-US"
|
_current_locale = "en-US"
|
||||||
|
|
||||||
@ -160,6 +171,44 @@ class Translator(Callable[[str], str]):
|
|||||||
self.translations[untranslated] = translated
|
self.translations[untranslated] = translated
|
||||||
|
|
||||||
|
|
||||||
|
@functools.lru_cache()
|
||||||
|
def _get_babel_locale(red_locale: str) -> babel.core.Locale:
|
||||||
|
supported_locales = babel.localedata.locale_identifiers()
|
||||||
|
try: # Handles cases where red_locale is already Babel supported
|
||||||
|
babel_locale = Locale(*babel.parse_locale(red_locale))
|
||||||
|
except (ValueError, babel.core.UnknownLocaleError):
|
||||||
|
try:
|
||||||
|
babel_locale = Locale(*babel.parse_locale(red_locale, sep="-"))
|
||||||
|
except (ValueError, babel.core.UnknownLocaleError):
|
||||||
|
# ValueError is Raised by `parse_locale` when an invalid Locale is given to it
|
||||||
|
# Lets handle it silently and default to "en_US"
|
||||||
|
try:
|
||||||
|
# Try to find a babel locale that's close to the one used by red
|
||||||
|
babel_locale = Locale(Locale.negotiate([red_locale], supported_locales, sep="-"))
|
||||||
|
except (ValueError, TypeError, babel.core.UnknownLocaleError):
|
||||||
|
# If we fail to get a close match we will then default to "en_US"
|
||||||
|
babel_locale = Locale("en", "US")
|
||||||
|
return babel_locale
|
||||||
|
|
||||||
|
|
||||||
|
def get_babel_locale(locale: Optional[str] = None) -> babel.core.Locale:
|
||||||
|
"""Function to convert a locale to a ``babel.core.Locale``.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
locale : Optional[str]
|
||||||
|
The locale to convert, if not specified it defaults to the bot's locale.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
babel.core.Locale
|
||||||
|
The babel locale object.
|
||||||
|
"""
|
||||||
|
if locale is None:
|
||||||
|
locale = get_locale()
|
||||||
|
return _get_babel_locale(locale)
|
||||||
|
|
||||||
|
|
||||||
# This import to be down here to avoid circular import issues.
|
# This import to be down here to avoid circular import issues.
|
||||||
# This will be cleaned up at a later date
|
# This will be cleaned up at a later date
|
||||||
# noinspection PyPep8
|
# noinspection PyPep8
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
import itertools
|
import itertools
|
||||||
import datetime
|
import datetime
|
||||||
from typing import Sequence, Iterator, List, Optional
|
from typing import Sequence, Iterator, List, Optional, Union
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
import discord
|
|
||||||
|
|
||||||
from redbot.core.i18n import Translator
|
import discord
|
||||||
|
from babel.numbers import format_decimal
|
||||||
|
|
||||||
|
from redbot.core.i18n import Translator, get_babel_locale
|
||||||
|
|
||||||
_ = Translator("UtilsChatFormatting", __file__)
|
_ = Translator("UtilsChatFormatting", __file__)
|
||||||
|
|
||||||
@ -432,6 +434,25 @@ def humanize_timedelta(
|
|||||||
return ", ".join(strings)
|
return ", ".join(strings)
|
||||||
|
|
||||||
|
|
||||||
|
def humanize_number(val: Union[int, float], override_locale=None) -> str:
|
||||||
|
"""
|
||||||
|
Convert an int or float to a str with digit separators based on bot locale
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
val : Union[int, float]
|
||||||
|
The int/float to be formatted.
|
||||||
|
override_locale: Optional[str]
|
||||||
|
A value to override the bots locale.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
locale aware formatted number.
|
||||||
|
"""
|
||||||
|
return format_decimal(val, locale=get_babel_locale(override_locale))
|
||||||
|
|
||||||
|
|
||||||
def text_to_file(
|
def text_to_file(
|
||||||
text: str, filename: str = "file.txt", *, spoiler: bool = False, encoding: str = "utf-8"
|
text: str, filename: str = "file.txt", *, spoiler: bool = False, encoding: str = "utf-8"
|
||||||
):
|
):
|
||||||
|
|||||||
@ -31,6 +31,7 @@ install_requires =
|
|||||||
appdirs==1.4.3
|
appdirs==1.4.3
|
||||||
async-timeout==3.0.1
|
async-timeout==3.0.1
|
||||||
attrs==19.1.0
|
attrs==19.1.0
|
||||||
|
babel==2.7.0
|
||||||
chardet==3.0.4
|
chardet==3.0.4
|
||||||
Click==7.0
|
Click==7.0
|
||||||
colorama==0.4.1
|
colorama==0.4.1
|
||||||
|
|||||||
@ -9,6 +9,7 @@ install_requires =
|
|||||||
aiohttp
|
aiohttp
|
||||||
aiohttp-json-rpc
|
aiohttp-json-rpc
|
||||||
appdirs
|
appdirs
|
||||||
|
babel
|
||||||
click
|
click
|
||||||
colorama
|
colorama
|
||||||
discord.py
|
discord.py
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user