Browse Source

Add auto_locale_strings parameter to application commands

pull/8314/head
Rapptz 3 years ago
parent
commit
1c9792e0ed
  1. 174
      discord/app_commands/commands.py
  2. 13
      discord/app_commands/transformers.py
  3. 23
      discord/app_commands/tree.py

174
discord/app_commands/commands.py

@ -457,12 +457,6 @@ def _get_context_menu_parameter(func: ContextMenuCallback) -> Tuple[str, Any, Ap
return (parameter.name, resolved, type)
async def _get_translation_payload(
command: Union[Command[Any, ..., Any], Group, ContextMenu], translator: Translator
) -> Dict[str, Any]:
...
class Command(Generic[GroupT, P, T]):
"""A class that implements an application command.
@ -475,15 +469,39 @@ class Command(Generic[GroupT, P, T]):
.. versionadded:: 2.0
Parameters
-----------
name: Union[:class:`str`, :class:`locale_str`]
The name of the application command.
description: Union[:class:`str`, :class:`locale_str`]
The description of the application command. This shows up in the UI to describe
the application command.
callback: :ref:`coroutine <coroutine>`
The coroutine that is executed when the command is called.
auto_locale_strings: :class:`bool`
If this is set to ``True``, then all translatable strings will implicitly
be wrapped into :class:`locale_str` rather than :class:`str`. This could
avoid some repetition and be more ergonomic for certain defaults such
as default command names, command descriptions, and parameter names.
Defaults to ``False``.
nsfw: :class:`bool`
Whether the command is NSFW and should only work in NSFW channels.
Defaults to ``False``.
Due to a Discord limitation, this does not work on subcommands.
parent: Optional[:class:`Group`]
The parent application command. ``None`` if there isn't one.
extras: :class:`dict`
A dictionary that can be used to store extraneous data.
The library will not touch any values or keys within this dictionary.
Attributes
------------
name: :class:`str`
The name of the application command. When passed as an argument
to ``__init__`` this can also be :class:`locale_str`.
The name of the application command.
description: :class:`str`
The description of the application command. This shows up in the UI to describe
the application command. When passed as an argument to ``__init__`` this
can also be :class:`locale_str`.
the application command.
checks
A list of predicates that take a :class:`~discord.Interaction` parameter
to indicate whether the command callback should be executed. If an exception
@ -499,12 +517,10 @@ class Command(Generic[GroupT, P, T]):
Due to a Discord limitation, this does not work on subcommands.
guild_only: :class:`bool`
Whether the command should only be usable in guild contexts.
Defaults to ``False``.
Due to a Discord limitation, this does not work on subcommands.
nsfw: :class:`bool`
Whether the command is NSFW and should only work in NSFW channels.
Defaults to ``False``.
Due to a Discord limitation, this does not work on subcommands.
parent: Optional[:class:`Group`]
@ -523,6 +539,7 @@ class Command(Generic[GroupT, P, T]):
nsfw: bool = False,
parent: Optional[Group] = None,
guild_ids: Optional[List[int]] = None,
auto_locale_strings: bool = False,
extras: Dict[Any, Any] = MISSING,
):
name, locale = (name.message, name) if isinstance(name, locale_str) else (name, None)
@ -562,6 +579,18 @@ class Command(Generic[GroupT, P, T]):
if self._guild_ids is not None and self.parent is not None:
raise ValueError('child commands cannot have default guilds set, consider setting them in the parent instead')
if auto_locale_strings:
self._convert_to_locale_strings()
def _convert_to_locale_strings(self) -> None:
if self._locale_name is None:
self._locale_name = locale_str(self.name)
if self._locale_description is None:
self._locale_description = locale_str(self.description)
for param in self._params.values():
param._convert_to_locale_strings()
def __set_name__(self, owner: Type[Any], name: str) -> None:
self._attr = name
@ -972,11 +1001,32 @@ class ContextMenu:
.. versionadded:: 2.0
Parameters
-----------
name: Union[:class:`str`, :class:`locale_str`]
The name of the context menu.
callback: :ref:`coroutine <coroutine>`
The coroutine that is executed when the command is called.
type: :class:`.AppCommandType`
The type of context menu application command. By default, this is inferred
by the parameter of the callback.
auto_locale_strings: :class:`bool`
If this is set to ``True``, then all translatable strings will implicitly
be wrapped into :class:`locale_str` rather than :class:`str`. This could
avoid some repetition and be more ergonomic for certain defaults such
as default command names, command descriptions, and parameter names.
Defaults to ``False``.
nsfw: :class:`bool`
Whether the command is NSFW and should only work in NSFW channels.
Defaults to ``False``.
extras: :class:`dict`
A dictionary that can be used to store extraneous data.
The library will not touch any values or keys within this dictionary.
Attributes
------------
name: :class:`str`
The name of the context menu. When passed as an argument to ``__init__``
this can be :class:`locale_str`.
The name of the context menu.
type: :class:`.AppCommandType`
The type of context menu application command. By default, this is inferred
by the parameter of the callback.
@ -1010,6 +1060,7 @@ class ContextMenu:
type: AppCommandType = MISSING,
nsfw: bool = False,
guild_ids: Optional[List[int]] = None,
auto_locale_strings: bool = False,
extras: Dict[Any, Any] = MISSING,
):
name, locale = (name.message, name) if isinstance(name, locale_str) else (name, None)
@ -1037,6 +1088,10 @@ class ContextMenu:
self.checks: List[Check] = getattr(callback, '__discord_app_commands_checks__', [])
self.extras: Dict[Any, Any] = extras or {}
if auto_locale_strings:
if self._locale_name is None:
self._locale_name = locale_str(self.name)
@property
def callback(self) -> ContextMenuCallback:
""":ref:`coroutine <coroutine>`: The coroutine that is executed when the context menu is called."""
@ -1164,17 +1219,21 @@ class Group:
.. versionadded:: 2.0
Attributes
------------
name: :class:`str`
Parameters
-----------
name: Union[:class:`str`, :class:`locale_str`]
The name of the group. If not given, it defaults to a lower-case
kebab-case version of the class name. When passed as an argument to
``__init__`` or the class this can be :class:`locale_str`.
description: :class:`str`
kebab-case version of the class name.
description: Union[:class:`str`, :class:`locale_str`]
The description of the group. This shows up in the UI to describe
the group. If not given, it defaults to the docstring of the
class shortened to 100 characters. When passed as an argument to
``__init__`` or the class this can be :class:`locale_str`.
class shortened to 100 characters.
auto_locale_strings: :class:`bool`
If this is set to ``True``, then all translatable strings will implicitly
be wrapped into :class:`locale_str` rather than :class:`str`. This could
avoid some repetition and be more ergonomic for certain defaults such
as default command names, command descriptions, and parameter names.
Defaults to ``False``.
default_permissions: Optional[:class:`~discord.Permissions`]
The default permissions that can execute this group on Discord. Note
that server administrators can override this value in the client.
@ -1191,6 +1250,34 @@ class Group:
Whether the command is NSFW and should only work in NSFW channels.
Defaults to ``False``.
Due to a Discord limitation, this does not work on subcommands.
parent: Optional[:class:`Group`]
The parent application command. ``None`` if there isn't one.
extras: :class:`dict`
A dictionary that can be used to store extraneous data.
The library will not touch any values or keys within this dictionary.
Attributes
------------
name: :class:`str`
The name of the group.
description: :class:`str`
The description of the group. This shows up in the UI to describe
the group.
default_permissions: Optional[:class:`~discord.Permissions`]
The default permissions that can execute this group on Discord. Note
that server administrators can override this value in the client.
Setting an empty permissions field will disallow anyone except server
administrators from using the command in a guild.
Due to a Discord limitation, this does not work on subcommands.
guild_only: :class:`bool`
Whether the group should only be usable in guild contexts.
Due to a Discord limitation, this does not work on subcommands.
nsfw: :class:`bool`
Whether the command is NSFW and should only work in NSFW channels.
Due to a Discord limitation, this does not work on subcommands.
parent: Optional[:class:`Group`]
The parent group. ``None`` if there isn't one.
@ -1276,6 +1363,7 @@ class Group:
guild_ids: Optional[List[int]] = None,
guild_only: bool = MISSING,
nsfw: bool = MISSING,
auto_locale_strings: bool = False,
default_permissions: Optional[Permissions] = MISSING,
extras: Dict[Any, Any] = MISSING,
):
@ -1364,6 +1452,17 @@ class Group:
raise ValueError('groups can only be nested at most one level')
parent.add_command(self)
if auto_locale_strings:
self._convert_to_locale_strings()
def _convert_to_locale_strings(self) -> None:
if self._locale_name is None:
self._locale_name = locale_str(self.name)
if self._locale_description is None:
self._locale_description = locale_str(self.description)
# I don't know if propagating to the children is the right behaviour here.
def __set_name__(self, owner: Type[Any], name: str) -> None:
self._attr = name
self.module = owner.__module__
@ -1653,6 +1752,7 @@ class Group:
name: Union[str, locale_str] = MISSING,
description: Union[str, locale_str] = MISSING,
nsfw: bool = False,
auto_locale_strings: bool = False,
extras: Dict[Any, Any] = MISSING,
) -> Callable[[CommandCallback[GroupT, P, T]], Command[GroupT, P, T]]:
"""Creates an application command under this group.
@ -1668,6 +1768,12 @@ class Group:
of the callback shortened to 100 characters.
nsfw: :class:`bool`
Whether the command is NSFW and should only work in NSFW channels. Defaults to ``False``.
auto_locale_strings: :class:`bool`
If this is set to ``True``, then all translatable strings will implicitly
be wrapped into :class:`locale_str` rather than :class:`str`. This could
avoid some repetition and be more ergonomic for certain defaults such
as default command names, command descriptions, and parameter names.
Defaults to ``False``.
extras: :class:`dict`
A dictionary that can be used to store extraneous data.
The library will not touch any values or keys within this dictionary.
@ -1691,6 +1797,7 @@ class Group:
callback=func,
nsfw=nsfw,
parent=self,
auto_locale_strings=auto_locale_strings,
extras=extras,
)
self.add_command(command)
@ -1704,6 +1811,7 @@ def command(
name: Union[str, locale_str] = MISSING,
description: Union[str, locale_str] = MISSING,
nsfw: bool = False,
auto_locale_strings: bool = False,
extras: Dict[Any, Any] = MISSING,
) -> Callable[[CommandCallback[GroupT, P, T]], Command[GroupT, P, T]]:
"""Creates an application command from a regular function.
@ -1721,6 +1829,12 @@ def command(
Whether the command is NSFW and should only work in NSFW channels. Defaults to ``False``.
Due to a Discord limitation, this does not work on subcommands.
auto_locale_strings: :class:`bool`
If this is set to ``True``, then all translatable strings will implicitly
be wrapped into :class:`locale_str` rather than :class:`str`. This could
avoid some repetition and be more ergonomic for certain defaults such
as default command names, command descriptions, and parameter names.
Defaults to ``False``.
extras: :class:`dict`
A dictionary that can be used to store extraneous data.
The library will not touch any values or keys within this dictionary.
@ -1744,6 +1858,7 @@ def command(
callback=func,
parent=None,
nsfw=nsfw,
auto_locale_strings=auto_locale_strings,
extras=extras,
)
@ -1754,6 +1869,7 @@ def context_menu(
*,
name: Union[str, locale_str] = MISSING,
nsfw: bool = False,
auto_locale_strings: bool = False,
extras: Dict[Any, Any] = MISSING,
) -> Callable[[ContextMenuCallback], ContextMenu]:
"""Creates an application command context menu from a regular function.
@ -1785,6 +1901,12 @@ def context_menu(
Whether the command is NSFW and should only work in NSFW channels. Defaults to ``False``.
Due to a Discord limitation, this does not work on subcommands.
auto_locale_strings: :class:`bool`
If this is set to ``True``, then all translatable strings will implicitly
be wrapped into :class:`locale_str` rather than :class:`str`. This could
avoid some repetition and be more ergonomic for certain defaults such
as default command names, command descriptions, and parameter names.
Defaults to ``False``.
extras: :class:`dict`
A dictionary that can be used to store extraneous data.
The library will not touch any values or keys within this dictionary.
@ -1795,7 +1917,13 @@ def context_menu(
raise TypeError('context menu function must be a coroutine function')
actual_name = func.__name__.title() if name is MISSING else name
return ContextMenu(name=actual_name, nsfw=nsfw, callback=func, extras=extras)
return ContextMenu(
name=actual_name,
nsfw=nsfw,
callback=func,
auto_locale_strings=auto_locale_strings,
extras=extras,
)
return decorator

13
discord/app_commands/transformers.py

@ -176,6 +176,19 @@ class CommandParameter:
return base
def _convert_to_locale_strings(self) -> None:
if self._rename is MISSING:
self._rename = locale_str(self.name)
elif isinstance(self._rename, str):
self._rename = locale_str(self._rename)
if isinstance(self.description, str):
self.description = locale_str(self.description)
for choice in self.choices:
if choice._locale_name is None:
choice._locale_name = locale_str(choice.name)
def is_choice_annotation(self) -> bool:
return getattr(self._annotation, '__discord_app_commands_is_choice__', False)

23
discord/app_commands/tree.py

@ -838,6 +838,7 @@ class CommandTree(Generic[ClientT]):
nsfw: bool = False,
guild: Optional[Snowflake] = MISSING,
guilds: Sequence[Snowflake] = MISSING,
auto_locale_strings: bool = False,
extras: Dict[Any, Any] = MISSING,
) -> Callable[[CommandCallback[Group, P, T]], Command[Group, P, T]]:
"""Creates an application command directly under this tree.
@ -862,6 +863,12 @@ class CommandTree(Generic[ClientT]):
The list of guilds to add the command to. This cannot be mixed
with the ``guild`` parameter. If no guilds are given at all
then it becomes a global command instead.
auto_locale_strings: :class:`bool`
If this is set to ``True``, then all translatable strings will implicitly
be wrapped into :class:`locale_str` rather than :class:`str`. This could
avoid some repetition and be more ergonomic for certain defaults such
as default command names, command descriptions, and parameter names.
Defaults to ``False``.
extras: :class:`dict`
A dictionary that can be used to store extraneous data.
The library will not touch any values or keys within this dictionary.
@ -885,6 +892,7 @@ class CommandTree(Generic[ClientT]):
callback=func,
nsfw=nsfw,
parent=None,
auto_locale_strings=auto_locale_strings,
extras=extras,
)
self.add_command(command, guild=guild, guilds=guilds)
@ -899,6 +907,7 @@ class CommandTree(Generic[ClientT]):
nsfw: bool = False,
guild: Optional[Snowflake] = MISSING,
guilds: Sequence[Snowflake] = MISSING,
auto_locale_strings: bool = False,
extras: Dict[Any, Any] = MISSING,
) -> Callable[[ContextMenuCallback], ContextMenu]:
"""Creates an application command context menu from a regular function directly under this tree.
@ -937,6 +946,12 @@ class CommandTree(Generic[ClientT]):
The list of guilds to add the command to. This cannot be mixed
with the ``guild`` parameter. If no guilds are given at all
then it becomes a global command instead.
auto_locale_strings: :class:`bool`
If this is set to ``True``, then all translatable strings will implicitly
be wrapped into :class:`locale_str` rather than :class:`str`. This could
avoid some repetition and be more ergonomic for certain defaults such
as default command names, command descriptions, and parameter names.
Defaults to ``False``.
extras: :class:`dict`
A dictionary that can be used to store extraneous data.
The library will not touch any values or keys within this dictionary.
@ -947,7 +962,13 @@ class CommandTree(Generic[ClientT]):
raise TypeError('context menu function must be a coroutine function')
actual_name = func.__name__.title() if name is MISSING else name
context_menu = ContextMenu(name=actual_name, nsfw=nsfw, callback=func, extras=extras)
context_menu = ContextMenu(
name=actual_name,
nsfw=nsfw,
callback=func,
auto_locale_strings=auto_locale_strings,
extras=extras,
)
self.add_command(context_menu, guild=guild, guilds=guilds)
return context_menu

Loading…
Cancel
Save