[Core] Guild scoped I18n (#3896)

* Guild I18n

Never again!

* Finish off guild scoped i18n

* Black formatting

* Added guild only flags.

* Fix missing import.

* Added listing of guild i18n settings

* Added API support

* Added API support... properly!

* Added API support... for realsies!

* Auto-translate create_cases instances

You're welcome cog creators! Jack talked me into this!

* Fix get_regional_format to actually return properly

* Cleanup `set showsettings`

* Style pass

* Update redbot/core/core_commands.py

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>

* Update redbot/core/events.py

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>

* Update redbot/core/core_commands.py

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>

* Fix missing import

* Improve caching

* Removal of unneeded function

* Fix some naming

* IDFK anymore...

* Reformat

* Update redbot/core/settings_caches.py

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>

* Update redbot/core/settings_caches.py

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>

* Update redbot/core/settings_caches.py

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>

* Remove line number

* Fix global sets

* Set contextual locale manually where needed

* Reports cog is wonderful...

* Update redbot/core/core_commands.py

Co-authored-by: Draper <27962761+Drapersniper@users.noreply.github.com>

* Set contextual locale manually where needed in Mutes cog

* s

Co-authored-by: jack1142 <6032823+jack1142@users.noreply.github.com>
Co-authored-by: Draper <27962761+Drapersniper@users.noreply.github.com>
This commit is contained in:
Kowlin 2020-10-26 17:59:11 +01:00 committed by GitHub
parent 7bb6e60c52
commit 2413c6abd3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 341 additions and 36 deletions

View File

@ -170,7 +170,7 @@ class Alias(commands.Cog):
for p in prefixes:
if content.startswith(p):
return p
raise ValueError(_("No prefix found."))
raise ValueError("No prefix found.")
async def call_alias(self, message: discord.Message, prefix: str, alias: AliasEntry):
new_message = copy(message)

View File

@ -6,7 +6,7 @@ from pathlib import Path
import discord
import lavalink
from redbot.core.i18n import Translator
from redbot.core.i18n import Translator, set_contextual_locales_from_guild
from ...errors import DatabaseError, TrackEnqueueError
from ..abc import MixinMeta
from ..cog_utils import CompositeMetaClass
@ -31,6 +31,7 @@ class LavalinkEvents(MixinMeta, metaclass=CompositeMetaClass):
guild_id = self.rgetattr(guild, "id", None)
if not guild:
return
await set_contextual_locales_from_guild(self.bot, guild)
current_requester = self.rgetattr(current_track, "requester", None)
current_stream = self.rgetattr(current_track, "is_stream", None)
current_length = self.rgetattr(current_track, "length", None)

View File

@ -5,7 +5,7 @@ from typing import Union, Set, Literal
from redbot.core import checks, Config, modlog, commands
from redbot.core.bot import Red
from redbot.core.i18n import Translator, cog_i18n
from redbot.core.i18n import Translator, cog_i18n, set_contextual_locales_from_guild
from redbot.core.utils import AsyncIter
from redbot.core.utils.chat_formatting import pagify, humanize_list
@ -396,6 +396,8 @@ class Filter(commands.Cog):
if await self.bot.is_automod_immune(message):
return
await set_contextual_locales_from_guild(self.bot, message.guild)
await self.check_filter(message)
@commands.Cog.listener()
@ -429,6 +431,8 @@ class Filter(commands.Cog):
if not guild_data["filter_names"]:
return
await set_contextual_locales_from_guild(self.bot, guild)
if await self.filter_hits(member.display_name, member.guild):
name_to_use = guild_data["filter_default_name"]

View File

@ -151,6 +151,9 @@ class Events(MixinMeta):
# As are anyone configured to be
if await self.bot.is_automod_immune(message):
return
await i18n.set_contextual_locales_from_guild(self.bot, message.guild)
deleted = await self.check_duplicates(message)
if not deleted:
await self.check_mention_spam(message)

View File

@ -194,6 +194,7 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
guild = self.bot.get_guild(g_id)
if guild is None or await self.bot.cog_disabled_in_guild(self, guild):
continue
await i18n.set_contextual_locales_from_guild(self.bot, guild)
for u_id in self._server_mutes[guild.id]:
if self._server_mutes[guild.id][u_id]["until"] is None:
continue
@ -295,6 +296,7 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
for guild_id, users in multiple_mutes.items():
guild = self.bot.get_guild(guild_id)
await i18n.set_contextual_locales_from_guild(self.bot, guild)
for user, channels in users.items():
if len(channels) > 1:
task_name = f"server-unmute-channels-{guild_id}-{user}"
@ -461,6 +463,7 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
a = set(after.roles)
roles_removed = list(b - a)
roles_added = list(a - b)
await i18n.set_contextual_locales_from_guild(self.bot, guild)
if mute_role in roles_removed:
# send modlog case for unmute and remove from cache
if guild.id not in self._server_mutes:
@ -511,6 +514,7 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
"""
if await self.bot.cog_disabled_in_guild(self, after.guild):
return
await i18n.set_contextual_locales_from_guild(self.bot, after.guild)
if after.id in self._channel_mutes:
before_perms: Dict[int, Dict[str, Optional[bool]]] = {
o.id: {name: attr for name, attr in p} for o, p in before.overwrites.items()
@ -569,6 +573,7 @@ class Mutes(VoiceMutes, commands.Cog, metaclass=CompositeMetaClass):
# user to globally rate limit the bot therefore we are not
# going to support re-muting users via channel overwrites
return
await i18n.set_contextual_locales_from_guild(self.bot, guild)
if guild.id in self._server_mutes:
if member.id in self._server_mutes[guild.id]:
role = guild.get_role(mute_role)

View File

@ -11,7 +11,7 @@ from redbot.core.utils import AsyncIter
from redbot.core.utils.chat_formatting import pagify, box
from redbot.core.utils.antispam import AntiSpam
from redbot.core.bot import Red
from redbot.core.i18n import Translator, cog_i18n
from redbot.core.i18n import Translator, cog_i18n, set_contextual_locales_from_guild
from redbot.core.utils.predicates import MessagePredicate
from redbot.core.utils.tunnel import Tunnel
@ -346,8 +346,10 @@ class Reports(commands.Cog):
if t is None:
return
guild = t[0][0]
tun = t[1]["tun"]
if payload.user_id in [x.id for x in tun.members]:
await set_contextual_locales_from_guild(self.bot, guild)
await tun.react_close(
uid=payload.user_id, message=_("{closer} has closed the correspondence")
)
@ -365,6 +367,7 @@ class Reports(commands.Cog):
to_remove.append(k)
continue
await set_contextual_locales_from_guild(self.bot, guild)
topic = _("Re: ticket# {ticket_number} in {guild.name}").format(
ticket_number=ticket_number, guild=guild
)
@ -376,6 +379,7 @@ class Reports(commands.Cog):
for key in to_remove:
if tun := self.tunnel_store.pop(key, None):
guild, ticket = key
await set_contextual_locales_from_guild(self.bot, guild)
await tun["tun"].close_because_disabled(
_(
"Correspondence about ticket# {ticket_number} in "

View File

@ -1,7 +1,7 @@
import discord
from redbot.core.bot import Red
from redbot.core import checks, commands, Config
from redbot.core.i18n import cog_i18n, Translator
from redbot.core.i18n import cog_i18n, Translator, set_contextual_locales_from_guild
from redbot.core.utils._internal_utils import send_to_owners_with_prefix_replaced
from redbot.core.utils.chat_formatting import escape, pagify
@ -714,6 +714,9 @@ class Streams(commands.Cog):
ignore_reruns = await self.config.guild(channel.guild).ignore_reruns()
if ignore_reruns and is_rerun:
continue
await set_contextual_locales_from_guild(self.bot, channel.guild)
mention_str, edited_roles = await self._get_mention_str(
channel.guild, channel
)

View File

@ -41,14 +41,13 @@ from .data_manager import cog_data_path
from .dev_commands import Dev
from .events import init_events
from .global_checks import init_global_checks
from .settings_caches import (
PrefixManager,
IgnoreManager,
WhitelistBlacklistManager,
DisabledCogCache,
I18nManager,
)
from .rpc import RPCMixin
from .utils import common_filters, AsyncIter
from .utils._internal_utils import send_to_owners_with_prefix_replaced
@ -142,6 +141,8 @@ class RedBase(
disabled_commands=[],
autoimmune_ids=[],
delete_delay=-1,
locale=None,
regional_format=None,
)
self._config.register_channel(embeds=None, ignored=False)
@ -159,6 +160,7 @@ class RedBase(
self._disabled_cog_cache = DisabledCogCache(self._config)
self._ignored_cache = IgnoreManager(self._config)
self._whiteblacklist_cache = WhitelistBlacklistManager(self._config)
self._i18n_cache = I18nManager(self._config)
async def prefix_manager(bot, message) -> List[str]:
prefixes = await self._prefix_cache.get_prefixes(message.guild)

View File

@ -1569,8 +1569,22 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
mod_role_ids = guild_data["mod_role"]
mod_role_names = [r.name for r in guild.roles if r.id in mod_role_ids]
mod_roles_str = humanize_list(mod_role_names) if mod_role_names else "Not Set."
guild_settings = _("Admin roles: {admin}\nMod roles: {mod}\n").format(
admin=admin_roles_str, mod=mod_roles_str
guild_locale = await i18n.get_locale_from_guild(self.bot, ctx.guild)
guild_regional_format = (
await i18n.get_regional_format_from_guild(self.bot, ctx.guild) or guild_locale
)
guild_settings = _(
"Admin roles: {admin}\n"
"Mod roles: {mod}\n"
"Locale: {guild_locale}\n"
"Regional format: {guild_regional_format}\n"
).format(
admin=admin_roles_str,
mod=mod_roles_str,
guild_locale=guild_locale,
guild_regional_format=guild_regional_format,
)
else:
guild_settings = ""
@ -1578,7 +1592,7 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
prefixes = await ctx.bot._prefix_cache.get_prefixes(ctx.guild)
global_data = await ctx.bot._config.all()
locale = global_data["locale"]
regional_format = global_data["regional_format"] or _("Same as bot's locale")
regional_format = global_data["regional_format"] or locale
colour = discord.Colour(global_data["color"])
prefix_string = " ".join(prefixes)
@ -1586,8 +1600,8 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
"{bot_name} Settings:\n\n"
"Prefixes: {prefixes}\n"
"{guild_settings}"
"Locale: {locale}\n"
"Regional format: {regional_format}\n"
"Global locale: {locale}\n"
"Global regional format: {regional_format}\n"
"Default embed colour: {colour}"
).format(
bot_name=ctx.bot.user.name,
@ -2018,9 +2032,10 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
@_set.command()
@checks.is_owner()
async def locale(self, ctx: commands.Context, language_code: str):
async def globallocale(self, ctx: commands.Context, language_code: str):
"""
Changes bot's locale.
Changes the bot's default locale.
This will be used when a server has not set a locale, or in DMs.
`<language_code>` can be any language code with country code included,
e.g. `en-US`, `de-DE`, `fr-FR`, `pl-PL`, etc.
@ -2042,12 +2057,51 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
return
standardized_locale_name = f"{locale.language}-{locale.territory}"
i18n.set_locale(standardized_locale_name)
await ctx.bot._config.locale.set(standardized_locale_name)
await self.bot._i18n_cache.set_locale(None, standardized_locale_name)
await i18n.set_contextual_locales_from_guild(self.bot, ctx.guild)
await ctx.send(_("Global locale has been set."))
@_set.command()
@commands.guild_only()
@checks.guildowner_or_permissions(manage_guild=True)
async def locale(self, ctx: commands.Context, language_code: str):
"""
Changes the bot's locale in this server.
`<language_code>` can be any language code with country code included,
e.g. `en-US`, `de-DE`, `fr-FR`, `pl-PL`, etc.
Go to Red's Crowdin page to see locales that are available with translations:
https://translate.discord.red
Use "default" to return to the bot's default set language.
To reset to English, use "en-US".
"""
if language_code.lower() == "default":
global_locale = await self.bot._config.locale()
i18n.set_contextual_locale(global_locale)
await self.bot._i18n_cache.set_locale(ctx.guild, None)
await ctx.send(_("Locale has been set to the default."))
return
try:
locale = BabelLocale.parse(language_code, sep="-")
except (ValueError, UnknownLocaleError):
await ctx.send(_("Invalid language code. Use format: `en-US`"))
return
if locale.territory is None:
await ctx.send(
_("Invalid format - language code has to include country code, e.g. `en-US`")
)
return
standardized_locale_name = f"{locale.language}-{locale.territory}"
i18n.set_contextual_locale(standardized_locale_name)
await self.bot._i18n_cache.set_locale(ctx.guild, standardized_locale_name)
await ctx.send(_("Locale has been set."))
@_set.command(aliases=["region"])
@_set.command(aliases=["globalregion"])
@commands.guild_only()
@checks.is_owner()
async def regionalformat(self, ctx: commands.Context, language_code: str = None):
async def globalregionalformat(self, ctx: commands.Context, language_code: str = None):
"""
Changes bot's regional format. This is used for formatting date, time and numbers.
@ -2058,8 +2112,8 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
"""
if language_code is None:
i18n.set_regional_format(None)
await ctx.bot._config.regional_format.set(None)
await ctx.send(_("Regional formatting will now be based on bot's locale."))
await self.bot._i18n_cache.set_regional_format(None, None)
await ctx.send(_("Global regional formatting will now be based on bot's locale."))
return
try:
@ -2074,7 +2128,45 @@ class Core(commands.commands._RuleDropper, commands.Cog, CoreLogic):
return
standardized_locale_name = f"{locale.language}-{locale.territory}"
i18n.set_regional_format(standardized_locale_name)
await ctx.bot._config.regional_format.set(standardized_locale_name)
await self.bot._i18n_cache.set_regional_format(None, standardized_locale_name)
await ctx.send(
_("Global regional formatting will now be based on `{language_code}` locale.").format(
language_code=standardized_locale_name
)
)
@_set.command(aliases=["region"])
@checks.guildowner_or_permissions(manage_guild=True)
async def regionalformat(self, ctx: commands.Context, language_code: str = None):
"""
Changes bot's regional format in this server. This is used for formatting date, time and numbers.
`<language_code>` can be any language code with country code included,
e.g. `en-US`, `de-DE`, `fr-FR`, `pl-PL`, etc.
Leave `<language_code>` empty to base regional formatting on bot's locale in this server.
"""
if language_code is None:
i18n.set_contextual_regional_format(None)
await self.bot._i18n_cache.set_regional_format(ctx.guild, None)
await ctx.send(
_("Regional formatting will now be based on bot's locale in this server.")
)
return
try:
locale = BabelLocale.parse(language_code, sep="-")
except (ValueError, UnknownLocaleError):
await ctx.send(_("Invalid language code. Use format: `en-US`"))
return
if locale.territory is None:
await ctx.send(
_("Invalid format - language code has to include country code, e.g. `en-US`")
)
return
standardized_locale_name = f"{locale.language}-{locale.territory}"
i18n.set_contextual_regional_format(standardized_locale_name)
await self.bot._i18n_cache.set_regional_format(ctx.guild, standardized_locale_name)
await ctx.send(
_("Regional formatting will now be based on `{language_code}` locale.").format(
language_code=standardized_locale_name

View File

@ -15,7 +15,12 @@ from pkg_resources import DistributionNotFound
from redbot.core import data_manager
from redbot.core.commands import RedHelpFormatter, HelpSettings
from redbot.core.i18n import Translator
from redbot.core.i18n import (
Translator,
set_contextual_locale,
set_contextual_regional_format,
set_contextual_locales_from_guild,
)
from .utils import AsyncIter
from .. import __version__ as red_version, version_info as red_version_info, VersionInfo
from . import commands
@ -313,6 +318,8 @@ def init_events(bot, cli_flags):
@bot.event
async def on_message(message):
await set_contextual_locales_from_guild(bot, message.guild)
await bot.process_commands(message)
discord_now = message.created_at
if (

View File

@ -1,13 +1,23 @@
from __future__ import annotations
import contextlib
import functools
import io
import os
import logging
import discord
from pathlib import Path
from typing import Callable, Union, Dict, Optional
from typing import Callable, TYPE_CHECKING, Union, Dict, Optional
from contextvars import ContextVar
import babel.localedata
from babel.core import Locale
if TYPE_CHECKING:
from redbot.core.bot import Red
__all__ = [
"get_locale",
"set_locale",
@ -16,10 +26,15 @@ __all__ = [
"Translator",
"get_babel_locale",
"get_babel_regional_format",
"get_locale_from_guild",
"get_regional_format_from_guild",
"set_contextual_locales_from_guild",
]
_current_locale = "en-US"
_current_regional_format = None
log = logging.getLogger("red.i18n")
_current_locale = ContextVar("_current_locale", default="en-US")
_current_regional_format = ContextVar("_current_regional_format", default=None)
WAITING_FOR_MSGID = 1
IN_MSGID = 2
@ -33,24 +48,33 @@ _translators = []
def get_locale() -> str:
return _current_locale
return str(_current_locale.get())
def set_locale(locale: str) -> None:
global _current_locale
_current_locale = locale
_current_locale = ContextVar("_current_locale", default=locale)
reload_locales()
def set_contextual_locale(locale: str) -> None:
_current_locale.set(locale)
reload_locales()
def get_regional_format() -> str:
if _current_regional_format is None:
return _current_locale
return _current_regional_format
if _current_regional_format.get() is None:
return str(_current_locale.get())
return str(_current_regional_format.get())
def set_regional_format(regional_format: Optional[str]) -> None:
global _current_regional_format
_current_regional_format = regional_format
_current_regional_format = ContextVar("_current_regional_format", default=regional_format)
def set_contextual_regional_format(regional_format: Optional[str]) -> None:
_current_regional_format.set(regional_format)
def reload_locales() -> None:
@ -58,6 +82,64 @@ def reload_locales() -> None:
translator.load_translations()
async def get_locale_from_guild(bot: Red, guild: Optional[discord.Guild]) -> str:
"""
Get locale set for the given guild.
Parameters
----------
bot: Red
The bot's instance.
guild: Optional[discord.Guild]
The guild contextual locale is set for.
Use `None` if the context doesn't involve guild.
Returns
-------
str
Guild's locale string.
"""
return await bot._i18n_cache.get_locale(guild)
async def get_regional_format_from_guild(bot: Red, guild: Optional[discord.Guild]) -> str:
"""
Get regional format for the given guild.
Parameters
----------
bot: Red
The bot's instance.
guild: Optional[discord.Guild]
The guild contextual locale is set for.
Use `None` if the context doesn't involve guild.
Returns
-------
str
Guild's locale string.
"""
return await bot._i18n_cache.get_regional_format(guild)
async def set_contextual_locales_from_guild(bot: Red, guild: Optional[discord.Guild]) -> None:
"""
Set contextual locales (locale and regional format) for given guild context.
Parameters
----------
bot: Red
The bot's instance.
guild: Optional[discord.Guild]
The guild contextual locale is set for.
Use `None` if the context doesn't involve guild.
"""
locale = await get_locale_from_guild(bot, guild)
regional_format = await get_regional_format_from_guild(bot, guild)
set_contextual_locale(locale)
set_contextual_regional_format(regional_format)
def _parse(translation_file: io.TextIOWrapper) -> Dict[str, str]:
"""
Custom gettext parsing of translation files.
@ -78,6 +160,10 @@ def _parse(translation_file: io.TextIOWrapper) -> Dict[str, str]:
untranslated = ""
translated = ""
translations = {}
locale = get_locale()
translations[locale] = {}
for line in translation_file:
line = line.strip()
@ -85,7 +171,7 @@ def _parse(translation_file: io.TextIOWrapper) -> Dict[str, str]:
# New msgid
if step is IN_MSGSTR and translated:
# Store the last translation
translations[_unescape(untranslated)] = _unescape(translated)
translations[locale][_unescape(untranslated)] = _unescape(translated)
step = IN_MSGID
untranslated = line[len(MSGID) : -1]
elif line.startswith('"') and line.endswith('"'):
@ -102,7 +188,7 @@ def _parse(translation_file: io.TextIOWrapper) -> Dict[str, str]:
if step is IN_MSGSTR and translated:
# Store the final translation
translations[_unescape(untranslated)] = _unescape(translated)
translations[locale][_unescape(untranslated)] = _unescape(translated)
return translations
@ -159,8 +245,9 @@ class Translator(Callable[[str], str]):
This will look for the string in the translator's :code:`.pot` file,
with respect to the current locale.
"""
locale = get_locale()
try:
return self.translations[untranslated]
return self.translations[locale][untranslated]
except KeyError:
return untranslated
@ -168,7 +255,16 @@ class Translator(Callable[[str], str]):
"""
Loads the current translations.
"""
self.translations = {}
locale = get_locale()
if locale.lower() == "en-us":
# Red is written in en-US, no point in loading it
return
if locale in self.translations:
# Locales cannot be loaded twice as they have an entry in
# self.translations
return
locale_path = get_locale_path(self.cog_folder, "po")
with contextlib.suppress(IOError, FileNotFoundError):
with locale_path.open(encoding="utf-8") as file:

View File

@ -15,7 +15,7 @@ from .utils.common_filters import (
filter_urls,
escape_spoilers,
)
from .i18n import Translator
from .i18n import Translator, set_contextual_locales_from_guild
from .generic_casetypes import all_generics
@ -885,6 +885,7 @@ async def create_case(
await _config.custom(_CASES, str(guild.id), str(next_case_number)).set(case.to_json())
await _config.guild(guild).latest_case_number.set(next_case_number)
await set_contextual_locales_from_guild(bot, guild)
bot.dispatch("modlog_case_create", case)
try:
mod_channel = await get_modlog_channel(case.guild)

View File

@ -1,6 +1,6 @@
from __future__ import annotations
from typing import Dict, List, Optional, Union, Set, Iterable, Tuple
from typing import Dict, List, Optional, Union, Set, Iterable, Tuple, overload
import asyncio
from argparse import Namespace
from collections import defaultdict
@ -56,6 +56,93 @@ class PrefixManager:
await self._config.guild_from_id(gid).prefix.set(prefixes)
class I18nManager:
def __init__(self, config: Config):
self._config: Config = config
self._guild_locale: Dict[Union[int, None], Union[str, None]] = {}
self._guild_regional_format: Dict[Union[int, None], Union[str, None]] = {}
async def get_locale(self, guild: Union[discord.Guild, None]) -> str:
"""Get the guild locale from the cache"""
# Ensure global locale is in the cache
if None not in self._guild_locale:
global_locale = await self._config.locale()
self._guild_locale[None] = global_locale
if guild is None: # Not a guild so cannot support guild locale
# Return the bot's globally set locale if its None on a guild scope.
return self._guild_locale[None]
elif guild.id in self._guild_locale: # Cached guild
if self._guild_locale[guild.id] is None:
return self._guild_locale[None]
else:
return self._guild_locale[guild.id]
else: # Uncached guild
out = await self._config.guild(guild).locale() # No locale set
if out is None:
self._guild_locale[guild.id] = None
return self._guild_locale[None]
else:
self._guild_locale[guild.id] = out
return out
@overload
async def set_locale(self, guild: None, locale: str):
...
@overload
async def set_locale(self, guild: discord.Guild, locale: Union[str, None]):
...
async def set_locale(
self, guild: Union[discord.Guild, None], locale: Union[str, None]
) -> None:
"""Set the locale in the config and cache"""
if guild is None:
if locale is None:
# this method should never be called like this
raise ValueError("Global locale can't be None!")
self._guild_locale[None] = locale
await self._config.locale.set(locale)
return
self._guild_locale[guild.id] = locale
await self._config.guild(guild).locale.set(locale)
async def get_regional_format(self, guild: Union[discord.Guild, None]) -> Optional[str]:
"""Get the regional format from the cache"""
# Ensure global locale is in the cache
if None not in self._guild_regional_format:
global_regional_format = await self._config.regional_format()
self._guild_regional_format[None] = global_regional_format
if guild is None: # Not a guild so cannot support guild locale
return self._guild_regional_format[None]
elif guild.id in self._guild_regional_format: # Cached guild
if self._guild_regional_format[guild.id] is None:
return self._guild_regional_format[None]
else:
return self._guild_regional_format[guild.id]
else: # Uncached guild
out = await self._config.guild(guild).regional_format() # No locale set
if out is None:
self._guild_regional_format[guild.id] = None
return self._guild_regional_format[None]
else: # Not cached, got a custom regional format.
self._guild_regional_format[guild.id] = out
return out
async def set_regional_format(
self, guild: Union[discord.Guild, None], regional_format: Union[str, None]
) -> None:
"""Set the regional format in the config and cache"""
if guild is None:
self._guild_regional_format[None] = regional_format
await self._config.regional_format.set(regional_format)
return
self._guild_regional_format[guild.id] = regional_format
await self._config.guild(guild).regional_format.set(regional_format)
class IgnoreManager:
def __init__(self, config: Config):
self._config: Config = config