diff --git a/hoyo_buddy/bot/bot.py b/hoyo_buddy/bot/bot.py index 99aafd3f..d333785d 100644 --- a/hoyo_buddy/bot/bot.py +++ b/hoyo_buddy/bot/bot.py @@ -22,12 +22,14 @@ from ..exceptions import NoAccountFoundError from ..hoyo.clients.novel_ai import NAIClient from ..utils import get_now +from .cache import LFUCache from .command_tree import CommandTree -from .translator import AppCommandTranslator, LocaleStr, Translator +from .translator import AppCommandTranslator, EnumStr, LocaleStr, Translator if TYPE_CHECKING: import asyncio from collections.abc import Sequence + from enum import StrEnum import asyncpg import git @@ -98,6 +100,7 @@ def __init__( self.pool = pool self.executor = concurrent.futures.ProcessPoolExecutor() self.config = config + self.cache = LFUCache() self.autocomplete_choices: AutocompleteChoices = {} """[game][category][locale][item_name] -> item_id""" @@ -154,12 +157,26 @@ async def dm_user(self, user_id: int, **kwargs: Any) -> discord.Message | None: return message - @staticmethod - def get_error_app_command_choice(error_message: LocaleStr) -> app_commands.Choice[str]: - return app_commands.Choice( - name=error_message.to_app_command_locale_str(), - value="none", - ) + def get_error_autocomplete( + self, error_message: LocaleStr, locale: discord.Locale + ) -> list[app_commands.Choice[str]]: + return [ + app_commands.Choice( + name=error_message.translate(self.translator, locale), + value="none", + ) + ] + + def get_enum_autocomplete( + self, enums: Sequence[StrEnum], locale: discord.Locale, current: str + ) -> list[discord.app_commands.Choice[str]]: + return [ + discord.app_commands.Choice( + name=EnumStr(enum).translate(self.translator, locale), value=enum.value + ) + for enum in enums + if current.lower() in EnumStr(enum).translate(self.translator, locale).lower() + ] async def get_account_autocomplete( self, @@ -195,26 +212,16 @@ async def get_account_autocomplete( if not accounts: if is_author: - return [ - self.get_error_app_command_choice( - LocaleStr( - "You don't have any accounts yet. Add one with /accounts", - key="no_accounts_autocomplete_choice", - ) - ) - ] - return [ - self.get_error_app_command_choice( - LocaleStr( - "This user doesn't have any accounts yet", - key="user_no_accounts_autocomplete_choice", - ) + return self.get_error_autocomplete( + LocaleStr(key="no_accounts_autocomplete_choice"), locale ) - ] + return self.get_error_autocomplete( + LocaleStr(key="user_no_accounts_autocomplete_choice"), locale + ) return [ discord.app_commands.Choice( - name=f"{account if is_author else account.blurred_display} | {translator.translate(LocaleStr(account.game, warn_no_key=False), locale)}{' (✦)' if account.current else ''}", + name=f"{account if is_author else account.blurred_display} | {translator.translate(EnumStr(account.game), locale)}{' (✦)' if account.current else ''}", value=f"{account.id}", ) for account in accounts @@ -272,10 +279,7 @@ def get_all_commands(self, locale: discord.Locale) -> dict[str, str]: for cog in self.cogs.values(): for command in cog.walk_app_commands(): desc = ( - LocaleStr( - command._locale_description.message, - **command._locale_description.extras, - ) + LocaleStr(key=command._locale_description.message) if command._locale_description is not None else command.description ) diff --git a/hoyo_buddy/bot/cache.py b/hoyo_buddy/bot/cache.py new file mode 100644 index 00000000..af587fbb --- /dev/null +++ b/hoyo_buddy/bot/cache.py @@ -0,0 +1,48 @@ +from collections import OrderedDict, defaultdict +from typing import Any + +import aiocache + + +class LFUCache(aiocache.SimpleMemoryCache): + def __init__(self, maxsize: int = 1024, **kwargs: Any) -> None: + super().__init__(**kwargs) + self._maxsize = maxsize + self._frequency: defaultdict[Any, int] = defaultdict(int) + self._freq_list: OrderedDict[int, list[Any]] = OrderedDict() + + def _update_freq(self, key: Any) -> None: + freq = self._frequency[key] + self._frequency[key] += 1 + + if freq in self._freq_list: + self._freq_list[freq].remove(key) + if not self._freq_list[freq]: + del self._freq_list[freq] + + if self._frequency[key] not in self._freq_list: + self._freq_list[self._frequency[key]] = [] + self._freq_list[self._frequency[key]].append(key) + + async def _evict(self) -> None: + if len(self._cache) >= self._maxsize: + min_freq = next(iter(self._freq_list)) + key_to_evict = self._freq_list[min_freq].pop(0) + if not self._freq_list[min_freq]: + del self._freq_list[min_freq] + await super().delete(key_to_evict) + del self._frequency[key_to_evict] + + async def get(self, key: Any, default: Any = None) -> Any: + if await super().exists(key): + self._update_freq(key) + return await super().get(key, default) + + async def set(self, key: Any, value: Any, ttl: int = 0) -> None: + await self._evict() + await super().set(key, value, ttl) + self._update_freq(key) + + async def delete(self, key: Any) -> None: + await super().delete(key) + del self._frequency[key] diff --git a/hoyo_buddy/bot/error_handler.py b/hoyo_buddy/bot/error_handler.py index e0e9716c..694f1ac4 100644 --- a/hoyo_buddy/bot/error_handler.py +++ b/hoyo_buddy/bot/error_handler.py @@ -15,7 +15,7 @@ from ..enums import GeetestType from ..exceptions import HoyoBuddyError, InvalidQueryError from ..utils import get_now -from .translator import LocaleStr, Translator +from .translator import EnumStr, LocaleStr, Translator if TYPE_CHECKING: import discord @@ -24,111 +24,66 @@ GENSHIN_ERROR_CONVERTER: dict[tuple[int, ...], dict[Literal["title", "description"], LocaleStr]] = { (-5003,): { - "title": LocaleStr("Daily Check-In Reward Already Claimed", key="already_claimed_title"), - "description": LocaleStr("Come back tomorrow!", key="already_claimed_description"), + "title": LocaleStr(key="already_claimed_title"), + "description": LocaleStr(key="already_claimed_description"), }, (-100, 10001, 10103, -1071): { - "title": LocaleStr("Invalid Cookies", key="invalid_cookies_title"), - "description": LocaleStr( - "Refresh your cookies by adding your accounts again using ", - key="invalid_cookies_description", - ), + "title": LocaleStr(key="invalid_cookies_title"), + "description": LocaleStr(key="invalid_cookies_description"), }, (-3205, -3102): { - "title": LocaleStr("Invalid Verification Code", key="invalid_verification_code_title"), - "description": LocaleStr( - "Please check the verification code and try again.", - key="invalid_verification_code_description", - ), + "title": LocaleStr(key="invalid_verification_code_title"), + "description": LocaleStr(key="invalid_verification_code_description"), }, (-3208, -3203, -3004): { - "title": LocaleStr("Invalid Email or Password", key="invalid_email_password_title"), - "description": LocaleStr( - "The email or password you provided is incorrect, please check and try again.", - key="invalid_email_password_description", - ), + "title": LocaleStr(key="invalid_email_password_title"), + "description": LocaleStr(key="invalid_email_password_description"), }, (-3206,): { - "title": LocaleStr( - "Verification Code Service Unavailable", key="verification_code_unavailable_title" - ), - "description": LocaleStr( - "Please try again later", key="verification_code_unavailable_description" - ), + "title": LocaleStr(key="verification_code_unavailable_title"), + "description": LocaleStr(key="verification_code_unavailable_description"), }, (-3101, -1004): { - "title": LocaleStr("Action in Cooldown", key="action_in_cooldown_error_title"), + "title": LocaleStr(key="action_in_cooldown_error_title"), "description": LocaleStr( - "Please try again at {available_time}.", key="action_in_cooldown_error_message", available_time=format_dt(get_now() + timedelta(minutes=1), "T"), ), }, - (-2017, -2018): { - "title": LocaleStr("Redemption code already claimed", key="redeem_code.already_claimed") - }, - (-2001,): { - "title": LocaleStr("Redemption code expired", key="redeem_code.expired"), - }, - (-1065, -2003, -2004, -2014): { - "title": LocaleStr("Invalid redemption code", key="redeem_code.invalid"), - }, - (-2016,): { - "title": LocaleStr("Code redemption in cooldown", key="redeem_code.cooldown"), - }, + (-2017, -2018): {"title": LocaleStr(key="redeem_code.already_claimed")}, + (-2001,): {"title": LocaleStr(key="redeem_code.expired")}, + (-1065, -2003, -2004, -2014): {"title": LocaleStr(key="redeem_code.invalid")}, + (-2016,): {"title": LocaleStr(key="redeem_code.cooldown")}, (10102,): { - "title": LocaleStr("Data is not Public", key="data_not_public.title"), - "description": LocaleStr( - "Enable the data sharing option in your battle chronicle settings\nhttps://raw.githubusercontent.com/seriaati/hoyo-buddy/assets/DataNotPublicTutorial.gif", - key="data_not_public.description", - ), - }, - (-2021, -2011): { - "title": LocaleStr("Adventure rank too low", key="redeem_code.ar_too_low"), + "title": LocaleStr(key="data_not_public.title"), + "description": LocaleStr(key="data_not_public.description"), }, + (-2021, -2011): {"title": LocaleStr(key="redeem_code.ar_too_low")}, (30001,): { - "title": LocaleStr("No need for geetest", key="geetest.no_need"), - "description": LocaleStr( - "You never needed to do a geetest! What are you here for?!", - key="geetest.no_need.description", - ), + "title": LocaleStr(key="geetest.no_need"), + "description": LocaleStr(key="geetest.no_need.description"), }, tuple(genshin.constants.GEETEST_RETCODES): { - "title": LocaleStr("Geetest Verification Required", key="geetest.required"), + "title": LocaleStr(key="geetest.required"), "description": LocaleStr( - "Use the command, choose the account that triggered the geetest, and choose `{geetest_type}` to complete the verification", - geetest_type=LocaleStr(GeetestType.REALTIME_NOTES.value, warn_no_key=False), + geetest_type=EnumStr(GeetestType.REALTIME_NOTES), key="geetest.required.description", ), }, - (-1,): { - "title": LocaleStr("Game is Under Maintenance", key="game_maintenance_title"), - }, + (-1,): {"title": LocaleStr(key="game_maintenance_title")}, # Below are custom retcodes for Hoyo Buddy, they don't exist in Hoyo's API (999,): { - "title": LocaleStr("Cookie Token Expired", key="redeeem_code.cookie_token_expired_title"), - "description": LocaleStr( - "Refresh your cookie token by adding your accounts again using .\n" - "If you use the email and password method to add your accounts, cookie token can be refreshed automatically.", - key="redeeem_code.cookie_token_expired_description", - ), + "title": LocaleStr(key="redeeem_code.cookie_token_expired_title"), + "description": LocaleStr(key="redeeem_code.cookie_token_expired_description"), }, (1000,): { - "title": LocaleStr( - "Failed to Refresh Cookie Token", key="redeeem_code.cookie_token_refresh_failed_title" - ), - "description": LocaleStr( - "It is likely that you have changed your account's password since the last time you add your accounts.\n" - "Please add your accounts again using with the email and password method.", - key="redeeem_code.cookie_token_refresh_failed_description", - ), + "title": LocaleStr(key="redeeem_code.cookie_token_refresh_failed_title"), + "description": LocaleStr(key="redeeem_code.cookie_token_refresh_failed_description"), }, (-9999,): { - "title": LocaleStr("Geetest Verification Required", key="geetest.required"), + "title": LocaleStr(key="geetest.required"), "description": LocaleStr( - "Use the command, choose the account that triggered the geetest, and choose `{geetest_type}` to complete the verification", - geetest_type=LocaleStr(GeetestType.DAILY_CHECKIN.value, warn_no_key=False), - key="geetest.required.description", + geetest_type=EnumStr(GeetestType.DAILY_CHECKIN), key="geetest.required.description" ), }, } @@ -139,20 +94,16 @@ dict[Literal["title", "description"], LocaleStr], ] = { enka_errors.PlayerDoesNotExistError: { - "title": LocaleStr("Player Does Not Exist", key="player_not_found_title"), - "description": LocaleStr( - "Please check the provided UID", key="player_not_found_description" - ), + "title": LocaleStr(key="player_not_found_title"), + "description": LocaleStr(key="player_not_found_description"), }, enka_errors.GameMaintenanceError: { - "title": LocaleStr("Game is Under Maintenance", key="game_maintenance_title"), - "description": LocaleStr("Please try again later", key="game_maintenance_description"), + "title": LocaleStr(key="game_maintenance_title"), + "description": LocaleStr(key="game_maintenance_description"), }, enka_errors.WrongUIDFormatError: { - "title": LocaleStr("Invalid UID Format", key="invalid_uid_format_title"), - "description": LocaleStr( - "UID must be a string of 9 digits", key="invalid_uid_format_description" - ), + "title": LocaleStr(key="invalid_uid_format_title"), + "description": LocaleStr(key="invalid_uid_format_description"), }, } @@ -198,13 +149,9 @@ def get_error_embed( embed = ErrorEmbed( locale, translator, - title=LocaleStr("An Error Occurred", key="error_title"), + title=LocaleStr(key="error_title"), description=description, ) - embed.set_footer( - text=LocaleStr( - "Please report this error to the developer via /feedback", key="error_footer" - ) - ) + embed.set_footer(text=LocaleStr(key="error_footer")) return embed, recognized diff --git a/hoyo_buddy/bot/translator.py b/hoyo_buddy/bot/translator.py index 4360c8fa..3eb754ee 100644 --- a/hoyo_buddy/bot/translator.py +++ b/hoyo_buddy/bot/translator.py @@ -5,21 +5,27 @@ import re from typing import TYPE_CHECKING, Any +from ambr.models import Character as GenshinCharacter from discord import app_commands +from hakushin.models.gi import Character as HakushinCharacter from loguru import logger from seria.utils import read_json, read_yaml -from ..enums import GenshinElement, HSRElement +from ..constants import ( + AMBR_ELEMENT_TO_ELEMENT, + HAKUSHIN_GI_ELEMENT_TO_ELEMENT, + WEEKDAYS, + YATTA_COMBAT_TYPE_TO_ELEMENT, +) from ..utils import capitalize_first_word as capitalize_first_word_ from ..utils import convert_to_title_case if TYPE_CHECKING: + from enum import StrEnum from types import TracebackType - from ambr.models import Character as GenshinCharacter from discord.app_commands.translator import TranslationContextTypes from discord.enums import Locale - from hakushin.models.gi import Character as HakushinCharacter from yatta.models import Character as HSRCharacter from ..models import Config @@ -51,30 +57,33 @@ ) +def gen_string_key(string: str) -> str: + return string.replace(" ", "_").replace(",", "").replace(".", "").replace("-", "_").lower() + + class LocaleStr: def __init__( self, - message: str, *, + custom_str: str | None = None, key: str | None = None, - warn_no_key: bool = True, translate: bool = True, **kwargs: Any, ) -> None: - self.message = message + self.custom_str = custom_str self.key = key - self.warn_no_key = warn_no_key self.translate_ = translate self.extras: dict[str, Any] = kwargs - def __repr__(self) -> str: - return f"locale_str({self.message!r}, key={self.key!r}, extras={self.extras!r})" + @property + def identifier(self) -> str: + return self.custom_str or self.key or "" def to_app_command_locale_str(self) -> app_commands.locale_str: return app_commands.locale_str( - self.message, + self.identifier, + custom_str=self.custom_str, key=self.key, - warn_no_key=self.warn_no_key, translate=self.translate_, **self.extras, ) @@ -83,12 +92,27 @@ def translate(self, translator: Translator, locale: Locale) -> str: return translator.translate(self, locale) +class EnumStr(LocaleStr): + def __init__(self, enum: StrEnum) -> None: + super().__init__(key=gen_string_key(enum.value)) + + +class LevelStr(LocaleStr): + def __init__(self, level: int) -> None: + super().__init__(key="level_str", level=level) + + +class WeekdayStr(LocaleStr): + def __init__(self, weekday: int) -> None: + super().__init__(key=WEEKDAYS[weekday].lower()) + + class Translator: def __init__(self, config: Config | None = None) -> None: super().__init__() self._config = config - self._not_translated: dict[str, str] = {} + self._not_translated: set[str] = set() self._synced_commands: dict[str, int] = {} self._localizations: dict[str, dict[str, str]] = {} @@ -147,37 +171,20 @@ def translate( capitalize_first_word: bool = False, ) -> str: if isinstance(string, str): - # it's intentional that we don't apply any modifiers when string is not LocaleStr + # It's intentional that we don't apply any modifiers when string is not LocaleStr return string extras = self._translate_extras(string.extras, locale) - message = string.message string_key = self._get_string_key(string) - if string.translate_: - # Check if the string is missing or has different values - source_string = self._localizations[SOURCE_LANG].get(string_key) - - if source_string is None and string_key not in self._not_translated: - self._not_translated[string_key] = message - logger.error(f"String {string_key!r} is missing in source lang file") - elif ( - source_string is not None - and source_string.lower() != message.lower() - and string_key not in self._not_translated - ): - self._not_translated[string_key] = message - logger.error( - f"String {string_key!r} has different values in code vs. source lang file" - ) + source_string = self._localizations[SOURCE_LANG].get(string_key) + if string.translate_ and source_string is None and string_key not in self._not_translated: + self._not_translated.add(string_key) + logger.error(f"String {string_key!r} is missing in source lang file") lang = locale.value.replace("-", "_") - - if "en" in lang or not string.translate_ or string_key in self._not_translated: - translation = message - else: - translation = self._localizations.get(lang, {}).get(string_key) - translation = translation or message + translation = self._localizations.get(lang, {}).get(string_key) + translation = translation or source_string or string.custom_str or string_key with contextlib.suppress(KeyError): translation = translation.format(**extras) @@ -204,18 +211,11 @@ def _translate_extras(self, extras: dict[str, Any], locale: Locale) -> dict[str, @staticmethod def _get_string_key(string: LocaleStr) -> str: if string.key is None: - if string.warn_no_key: - logger.warning(f"Missing key for string {string.message!r}, using generated key") - string_key = ( - string.message.replace(" ", "_") - .replace(",", "") - .replace(".", "") - .replace("-", "_") - .lower() - ) - else: - string_key = string.key - return string_key + if string.custom_str is None: + msg = "Either key or custom_str must be provided" + raise ValueError(msg) + return gen_string_key(string.custom_str) + return string.key def get_traveler_name( self, @@ -224,16 +224,14 @@ def get_traveler_name( *, gender_symbol: bool = True, ) -> str: - element_str = ( - self.translate( - LocaleStr( - GenshinElement(character.element.name.lower()).value.title(), warn_no_key=False - ), - locale, - ) - if character.element is not None - else "" - ) + if isinstance(character, GenshinCharacter): + element = AMBR_ELEMENT_TO_ELEMENT[character.element] + elif isinstance(character, HakushinCharacter) and character.element is not None: + element = HAKUSHIN_GI_ELEMENT_TO_ELEMENT[character.element] + else: + element = None + + element_str = "" if element is None else self.translate(EnumStr(element), locale) gender_str = ("♂" if "5" in character.id else "♀") if gender_symbol else "" return ( f"{character.name} ({element_str}) ({gender_str})" @@ -245,10 +243,7 @@ def get_trailblazer_name( self, character: HSRCharacter, locale: Locale, *, gender_symbol: bool = True ) -> str: element_str = self.translate( - LocaleStr( - HSRElement(character.types.combat_type.lower()).value.title(), warn_no_key=False - ), - locale, + EnumStr(YATTA_COMBAT_TYPE_TO_ELEMENT[character.types.combat_type]), locale ) gender_str = ("♂" if character.id % 2 != 0 else "♀") if gender_symbol else "" return ( @@ -264,12 +259,8 @@ def __init__(self, translator: Translator) -> None: self.translator = translator async def translate( - self, - string: app_commands.locale_str, - locale: Locale, - _: TranslationContextTypes, + self, string: app_commands.locale_str, locale: Locale, _: TranslationContextTypes ) -> str: - locale_str_ = LocaleStr(string.message, **string.extras) - if not locale_str_.translate_: - return locale_str_.message - return self.translator.translate(locale_str_, locale) + if (key := string.extras.get("key")) is None: + return string.message + return self.translator.translate(LocaleStr(key=key), locale) diff --git a/hoyo_buddy/cogs/farm.py b/hoyo_buddy/cogs/farm.py index cf8adcea..9dfd3939 100644 --- a/hoyo_buddy/cogs/farm.py +++ b/hoyo_buddy/cogs/farm.py @@ -20,14 +20,14 @@ class Farm( commands.GroupCog, - name=app_commands.locale_str("farm", translate=False), - description=app_commands.locale_str("Farm commands", translate=False), + name=app_commands.locale_str("farm"), + description=app_commands.locale_str("Farm commands"), ): def __init__(self, bot: HoyoBuddy) -> None: self.bot = bot @app_commands.command( - name=app_commands.locale_str("view", translate=False), + name=app_commands.locale_str("view"), description=app_commands.locale_str( "View farmable domains in Genshin Impact", key="farm_view_command_description" ), @@ -64,7 +64,7 @@ async def farm_view_command( await view.start(i) @app_commands.command( - name=app_commands.locale_str("add", translate=False), + name=app_commands.locale_str("add"), description=app_commands.locale_str( "Add character/weapon to be notified when its materials are farmable", key="farm_add_command_description", @@ -76,7 +76,7 @@ async def farm_view_command( ) @app_commands.describe( query=app_commands.locale_str( - "Query to search for", key="search_command_query_param_description" + "Query to search for", query="search_command_query_param_description" ), account=app_commands.locale_str( "Account to run this command with, defaults to the selected one in /accounts", @@ -95,7 +95,7 @@ async def farm_add_command( await command.run() @app_commands.command( - name=app_commands.locale_str("remove", translate=False), + name=app_commands.locale_str("remove"), description=app_commands.locale_str( "Remove character/weapon from farm reminder list", key="farm_remove_command_description" ), @@ -125,7 +125,7 @@ async def farm_remove_command( await command.run() @app_commands.command( - name=app_commands.locale_str("reminder", translate=False), + name=app_commands.locale_str("reminder"), description=app_commands.locale_str( "Notify you when materials of characters/weapons are farmable", key="farm_reminder_command_description", @@ -165,21 +165,17 @@ async def account_autocomplete( @farm_add_command.autocomplete("query") async def query_autocomplete(self, i: Interaction, current: str) -> list[app_commands.Choice]: + locale = await get_locale(i) + try: characters = self.bot.autocomplete_choices[Game.GENSHIN][ItemCategory.CHARACTERS] weapons = self.bot.autocomplete_choices[Game.GENSHIN][ItemCategory.WEAPONS] except KeyError: - return [ - self.bot.get_error_app_command_choice( - LocaleStr( - "Search autocomplete choices not set up yet, please try again later.", - key="search_autocomplete_not_setup", - ) - ) - ] + return self.bot.get_error_autocomplete( + LocaleStr(key="search_autocomplete_not_setup"), locale + ) if not current: - locale = await get_locale(i) choice_dict = dict( characters.get(locale.value, characters[Locale.american_english.value]).items() ) diff --git a/hoyo_buddy/cogs/hoyo.py b/hoyo_buddy/cogs/hoyo.py index 0a82fde6..4e48df2b 100644 --- a/hoyo_buddy/cogs/hoyo.py +++ b/hoyo_buddy/cogs/hoyo.py @@ -14,7 +14,7 @@ from ..draw.main_funcs import draw_exploration_card from ..embeds import DefaultEmbed from ..enums import Game, GeetestType, Platform -from ..exceptions import IncompleteParamError +from ..exceptions import IncompleteParamError, InvalidQueryError from ..hoyo.clients.ambr import AmbrAPIClient from ..hoyo.clients.yatta import YattaAPIClient from ..hoyo.transformers import HoyoAccountTransformer # noqa: TCH001 @@ -40,10 +40,7 @@ async def _get_uid_and_game( if uid is not None: if game_value is None: raise IncompleteParamError( - LocaleStr( - "You must specify the game of the UID", - key="game_value_incomplete_param_error_message", - ) + LocaleStr(key="game_value_incomplete_param_error_message") ) uid_ = int(uid) game = Game(game_value) @@ -56,7 +53,7 @@ async def _get_uid_and_game( return uid_, game, account_ @app_commands.command( - name=app_commands.locale_str("check-in", translate=False), + name=app_commands.locale_str("check-in"), description=app_commands.locale_str( "Game daily check-in", key="checkin_command_description" ), @@ -96,7 +93,7 @@ async def checkin_command( await view.start(i) @app_commands.command( - name=app_commands.locale_str("profile", translate=False), + name=app_commands.locale_str("profile"), description=app_commands.locale_str( "View your in-game profile and generate character build cards", key="profile_command_description", @@ -105,7 +102,7 @@ async def checkin_command( @app_commands.rename( user=app_commands.locale_str("user", key="user_autocomplete_param_name"), account=app_commands.locale_str("account", key="account_autocomplete_param_name"), - uid=app_commands.locale_str("uid", translate=False), + uid=app_commands.locale_str("uid"), game_value=app_commands.locale_str("game", key="search_command_game_param_name"), ) @app_commands.describe( @@ -125,18 +122,6 @@ async def checkin_command( "Game of the UID", key="profile_command_game_value_description" ), ) - @app_commands.choices( - game_value=[ - app_commands.Choice( - name=app_commands.locale_str(Game.GENSHIN.value, warn_no_key=False), - value=Game.GENSHIN.value, - ), - app_commands.Choice( - name=app_commands.locale_str(Game.STARRAIL.value, warn_no_key=False), - value=Game.STARRAIL.value, - ), - ] - ) async def profile_command( self, i: Interaction, @@ -170,7 +155,7 @@ async def profile_command( await view.start(i) @app_commands.command( - name=app_commands.locale_str("notes", translate=False), + name=app_commands.locale_str("notes"), description=app_commands.locale_str( "View real-time notes", key="notes_command_description" ), @@ -209,7 +194,7 @@ async def notes_command( await view.start(i) @app_commands.command( - name=app_commands.locale_str("characters", translate=False), + name=app_commands.locale_str("characters"), description=app_commands.locale_str( "View all of your characters", key="characters_command_description" ), @@ -263,7 +248,7 @@ async def characters_command( await view.start(i, show_first_time_msg=account_.game is Game.GENSHIN) @app_commands.command( - name=app_commands.locale_str("challenge", translate=False), + name=app_commands.locale_str("challenge"), description=app_commands.locale_str( "View game end-game content statistics, like spiral abyss, memory of chaos, etc.", key="challenge_command_description", @@ -293,7 +278,7 @@ async def challenge_command( await command.run() @app_commands.command( - name=app_commands.locale_str("exploration", translate=False), + name=app_commands.locale_str("exploration"), description=app_commands.locale_str( "View your exploration statistics in Genshin Impact", key="exploration_command_description", @@ -346,10 +331,9 @@ async def exploration_command( await i.followup.send(embed=embed, files=[file_]) @app_commands.command( - name=app_commands.locale_str("redeem", translate=False), + name=app_commands.locale_str("redeem"), description=app_commands.locale_str( - "Redeem codes for in-game rewards", - key="redeem_command_description", + "Redeem codes for in-game rewards", key="redeem_command_description" ), ) @app_commands.rename( @@ -383,10 +367,9 @@ async def redeem_command( view.message = await i.original_response() @app_commands.command( - name=app_commands.locale_str("geetest", translate=False), + name=app_commands.locale_str("geetest"), description=app_commands.locale_str( - "Complete geetest verification", - key="geetest_command_description", + "Complete geetest verification", key="geetest_command_description" ), ) @app_commands.rename( @@ -395,36 +378,43 @@ async def redeem_command( ) @app_commands.describe( account=app_commands.locale_str( - "Account to run this command with", - key="account_autocomplete_no_default_param_description", + "Account to run this command with", key="acc_no_default_param_desc" ), type_=app_commands.locale_str( - "Type of geetest verification", - key="geetest_command_type_param_description", + "Type of geetest verification", key="geetest_cmd_type_param_desc" ), ) - @app_commands.choices( - type_=[ - app_commands.Choice( - name=app_commands.locale_str(GeetestType.REALTIME_NOTES.value, warn_no_key=False), - value=GeetestType.REALTIME_NOTES.value, - ), - app_commands.Choice( - name=app_commands.locale_str(GeetestType.DAILY_CHECKIN.value, warn_no_key=False), - value=GeetestType.DAILY_CHECKIN.value, - ), - ] - ) async def geetest_command( self, i: Interaction, account: app_commands.Transform[HoyoAccount, HoyoAccountTransformer], - type_: GeetestType, + type_: str, ) -> None: + try: + type_ = GeetestType(type_) + except ValueError as e: + raise InvalidQueryError from e + command = GeetestCommand(self.bot, i, account, type_) await command.run() command.start_listener() + @geetest_command.autocomplete("type_") + async def geetest_type_autocomplete( + self, i: Interaction, current: str + ) -> list[app_commands.Choice[str]]: + locale = await get_locale(i) + return self.bot.get_enum_autocomplete( + [GeetestType.DAILY_CHECKIN, GeetestType.REALTIME_NOTES], locale, current + ) + + @profile_command.autocomplete("game_value") + async def profile_game_autocomplete( + self, i: Interaction, current: str + ) -> list[app_commands.Choice[str]]: + locale = await get_locale(i) + return self.bot.get_enum_autocomplete([Game.GENSHIN, Game.STARRAIL], locale, current) + @exploration_command.autocomplete("account") async def exploration_command_autocomplete( self, i: Interaction, current: str @@ -432,12 +422,7 @@ async def exploration_command_autocomplete( locale = await get_locale(i) user: User = i.namespace.user return await self.bot.get_account_autocomplete( - user, - i.user.id, - current, - locale, - self.bot.translator, - (Game.GENSHIN,), + user, i.user.id, current, locale, self.bot.translator, (Game.GENSHIN,) ) @challenge_command.autocomplete("account") @@ -449,12 +434,7 @@ async def account_autocomplete(self, i: Interaction, current: str) -> list[app_c locale = await get_locale(i) user: User = i.namespace.user return await self.bot.get_account_autocomplete( - user, - i.user.id, - current, - locale, - self.bot.translator, - (Game.GENSHIN, Game.STARRAIL), + user, i.user.id, current, locale, self.bot.translator, (Game.GENSHIN, Game.STARRAIL) ) @checkin_command.autocomplete("account") diff --git a/hoyo_buddy/cogs/login.py b/hoyo_buddy/cogs/login.py index 93ad4f14..e01ace7f 100644 --- a/hoyo_buddy/cogs/login.py +++ b/hoyo_buddy/cogs/login.py @@ -18,7 +18,7 @@ def __init__(self, bot: HoyoBuddy) -> None: self.bot = bot @app_commands.command( - name=locale_str("accounts", translate=False), + name=locale_str("accounts"), description=locale_str("Manage your accounts", key="accounts_command_description"), ) async def accounts(self, i: Interaction) -> Any: diff --git a/hoyo_buddy/cogs/others.py b/hoyo_buddy/cogs/others.py index c6bca36c..8dfd87c3 100644 --- a/hoyo_buddy/cogs/others.py +++ b/hoyo_buddy/cogs/others.py @@ -39,7 +39,7 @@ def get_last_commits(self, count: int = 5) -> str: return "\n".join(self.format_commit(commit) for commit in commits) @app_commands.command( - name=locale_str("feedback", translate=False), + name=locale_str("feedback"), description=locale_str( "Give feedback to the bot's developer", key="feedback_command_description" ), @@ -52,28 +52,17 @@ async def feedback_command(self, i: Interaction) -> Any: locale, self.bot.translator, description=LocaleStr( - ( - "🤗 Hi! Thanks for taking the time to give me feedback.\n" - "Click on the button below to start.\n\n" - "Note: I might contact you for more details. So please keep your DMs opened (or join the [Hoyo Buddy Discord server](https://dsc.gg/hoyo-buddy))." - ), key="feedback_command.description", ), ) owner = await i.client.fetch_user(i.client.owner_id) assert owner is not None embed.set_author(name=owner.name, icon_url=owner.display_avatar.url) - embed.set_footer( - text=LocaleStr( - "", - key="feedback_command.footer", - ) - ) await i.followup.send(embed=embed, view=view) view.message = await i.original_response() @app_commands.command( - name=locale_str("about", translate=False), + name=locale_str("about"), description=locale_str("About the bot", key="about_command_description"), ) async def about_command(self, i: Interaction) -> None: @@ -86,15 +75,12 @@ async def about_command(self, i: Interaction) -> None: locale=locale, translator=self.bot.translator, title=f"{self.bot.user.name} {self.bot.version}", - description=LocaleStr( - "A feature rich, easy to use, and beautifully designed Discord bot specifically made for Hoyoverse gamers.", - key="about_embed.description", - ), + description=LocaleStr(key="about_embed.description"), ) # latest changes embed.add_field( - name=LocaleStr("Latest changes", key="about_command.latest_changes"), + name=LocaleStr(key="about_command.latest_changes"), value=self.get_last_commits(), inline=False, ) @@ -103,7 +89,7 @@ async def about_command(self, i: Interaction) -> None: owner = await i.client.fetch_user(i.client.owner_id) assert owner is not None embed.add_field( - name=LocaleStr("Developer", key="about_command.developer"), + name=LocaleStr(key="about_command.developer"), value=get_discord_user_md_link(owner), inline=False, ) @@ -120,28 +106,28 @@ async def about_command(self, i: Interaction) -> None: get_discord_user_md_link(translator) for translator in translator_role.members ] embed.add_field( - name=LocaleStr("Translators", key="about_command.translators"), + name=LocaleStr(key="about_command.translators"), value=" ".join(translators), inline=False, ) # guild count embed.add_field( - name=LocaleStr("Guild count", key="about_command.guild_count"), + name=LocaleStr(key="about_command.guild_count"), value=str(len(i.client.guilds)), ) # ram usage memory_usage = self.process.memory_info().rss / 1024**2 embed.add_field( - name=LocaleStr("RAM Usage", key="about_command.ram_usage"), + name=LocaleStr(key="about_command.ram_usage"), value=f"{memory_usage:.2f} MB", ) # uptime uptime = discord.utils.format_dt(i.client.uptime, "R") embed.add_field( - name=LocaleStr("Uptime", key="about_command.uptime"), + name=LocaleStr(key="about_command.uptime"), value=uptime, ) @@ -150,7 +136,7 @@ async def about_command(self, i: Interaction) -> None: view.add_item(Button(label="GitHub", url=self.repo_url, emoji=GITHUB_WHITE_ICON, row=0)) view.add_item( Button( - label=LocaleStr("Discord server", key="about_command.discord_server"), + label=LocaleStr(key="about_command.discord_server"), url="https://dsc.gg/hoyo-buddy", emoji=DISCORD_WHITE_ICON, row=0, @@ -158,14 +144,14 @@ async def about_command(self, i: Interaction) -> None: ) view.add_item( Button( - label=LocaleStr("Official website", key="about_command.website"), + label=LocaleStr(key="about_command.website"), url="https://seria.is-a.dev/hoyo-buddy", row=1, ) ) view.add_item( Button( - label=LocaleStr("Invite bot", key="about_command.invite"), + label=LocaleStr(key="about_command.invite"), url="https://dub.sh/hb-invite" if self.bot.env == "prod" else "https://dub.sh/hb-beta-invite", @@ -174,14 +160,14 @@ async def about_command(self, i: Interaction) -> None: ) view.add_item( Button( - label=LocaleStr("Support developer", key="about_command.support"), + label=LocaleStr(key="about_command.support"), url="https://buymeacoffee.com/seria", row=1, ) ) view.add_item( Button( - label=LocaleStr("Contribute", key="about_command.contribute"), + label=LocaleStr(key="about_command.contribute"), url="https://github.com/seriaati/hoyo-buddy/blob/main/CONTRIBUTING.md", row=1, ) diff --git a/hoyo_buddy/cogs/search.py b/hoyo_buddy/cogs/search.py index a84e1c4f..cfbced9f 100644 --- a/hoyo_buddy/cogs/search.py +++ b/hoyo_buddy/cogs/search.py @@ -29,9 +29,9 @@ class Search(commands.Cog): def __init__(self, bot: HoyoBuddy) -> None: self.bot = bot - self._search_categories: dict[Game, list[str]] = { - Game.GENSHIN: [c.value for c in ambr.ItemCategory], - Game.STARRAIL: [c.value for c in yatta.ItemCategory], + self._search_categories: dict[Game, list[ambr.ItemCategory | yatta.ItemCategory]] = { + Game.GENSHIN: list(ambr.ItemCategory), + Game.STARRAIL: list(yatta.ItemCategory), } self._beta_id_to_category: dict[str, str] = {} self._tasks: set[asyncio.Task] = set() @@ -65,16 +65,14 @@ async def _setup_search_autocomplete_choices(self) -> None: ) @app_commands.command( - name=app_commands.locale_str("search", translate=False), + name=app_commands.locale_str("search"), description=app_commands.locale_str( "Search anything game related", key="search_command_description" ), ) @app_commands.rename( game_value=app_commands.locale_str("game", key="search_command_game_param_name"), - category_value=app_commands.locale_str( - "category", key="search_command_category_param_name" - ), + category_value=app_commands.locale_str("category", key="search_cmd_category_param_name"), query=app_commands.locale_str("query", key="search_command_query_param_name"), ) @app_commands.describe( @@ -88,18 +86,6 @@ async def _setup_search_autocomplete_choices(self) -> None: "Query to search for", key="search_command_query_param_description" ), ) - @app_commands.choices( - game_value=[ - app_commands.Choice( - name=app_commands.locale_str(Game.GENSHIN.value, warn_no_key=False), - value=Game.GENSHIN.value, - ), - app_commands.Choice( - name=app_commands.locale_str(Game.STARRAIL.value, warn_no_key=False), - value=Game.STARRAIL.value, - ), - ] - ) async def search_command( # noqa: C901, PLR0911, PLR0912, PLR0914, PLR0915 self, i: Interaction, @@ -404,41 +390,34 @@ async def search_command( # noqa: C901, PLR0911, PLR0912, PLR0914, PLR0915 ) await character_ui.start(i) + @search_command.autocomplete("game_value") + async def search_command_game_autocomplete( + self, i: Interaction, current: str + ) -> list[app_commands.Choice]: + locale = await get_locale(i) + return self.bot.get_enum_autocomplete([Game.GENSHIN, Game.STARRAIL], locale, current) + @search_command.autocomplete("category_value") async def search_command_category_autocomplete( self, i: Interaction, current: str ) -> list[app_commands.Choice]: + locale = await get_locale(i) try: game = Game(i.namespace.game) except ValueError: - return [ - self.bot.get_error_app_command_choice( - LocaleStr("Invalid game selected", key="invalid_category_selected") - ) - ] + return self.bot.get_error_autocomplete(LocaleStr(key="invalid_game_selected"), locale) - locale = await get_locale(i) - return [ - app_commands.Choice( - name=LocaleStr(c, warn_no_key=False).translate(i.client.translator, locale), - value=c, - ) - for c in self._search_categories[game] - if current.lower() in c.lower() - ] + return self.bot.get_enum_autocomplete(self._search_categories[game], locale, current) @search_command.autocomplete("query") async def search_command_query_autocomplete( # noqa: PLR0912, PLR0911 self, i: Interaction, current: str ) -> list[app_commands.Choice]: + locale = await get_locale(i) try: game = Game(i.namespace.game) except ValueError: - return [ - self.bot.get_error_app_command_choice( - LocaleStr("Invalid game selected", key="invalid_game_selected") - ) - ] + return self.bot.get_error_autocomplete(LocaleStr(key="invalid_game_selected"), locale) try: if game is Game.GENSHIN: @@ -446,34 +425,24 @@ async def search_command_query_autocomplete( # noqa: PLR0912, PLR0911 elif game is Game.STARRAIL: category = yatta.ItemCategory(i.namespace.category) else: - return [ - self.bot.get_error_app_command_choice( - LocaleStr("Invalid game selected", key="invalid_game_selected") - ) - ] - except ValueError: - return [ - self.bot.get_error_app_command_choice( - LocaleStr("Invalid category selected", key="invalid_category_selected") + return self.bot.get_error_autocomplete( + LocaleStr(key="invalid_game_selected"), locale ) - ] + except ValueError: + return self.bot.get_error_autocomplete( + LocaleStr(key="invalid_category_selected"), locale + ) # Special handling for spiral abyss if category is ambr.ItemCategory.SPIRAL_ABYSS: return await AbyssEnemyView.get_autocomplete_choices() if not self.bot.autocomplete_choices or game not in self.bot.autocomplete_choices: - return [ - self.bot.get_error_app_command_choice( - LocaleStr( - "Search autocomplete choices not set up yet, please try again later.", - key="search_autocomplete_not_setup", - ) - ) - ] + return self.bot.get_error_autocomplete( + LocaleStr(key="search_autocomplete_not_setup"), locale + ) if not current: - locale = await get_locale(i) try: choice_dict = self.bot.autocomplete_choices[game][category][locale.value] except KeyError: @@ -482,11 +451,9 @@ async def search_command_query_autocomplete( # noqa: PLR0912, PLR0911 Locale.american_english.value ] except KeyError: - return [ - self.bot.get_error_app_command_choice( - LocaleStr("No results found", key="search_autocomplete_no_results") - ) - ] + return self.bot.get_error_autocomplete( + LocaleStr(key="search_autocomplete_no_results"), locale + ) else: choice_dict = { k: v @@ -501,11 +468,9 @@ async def search_command_query_autocomplete( # noqa: PLR0912, PLR0911 ] if not choices: - return [ - self.bot.get_error_app_command_choice( - LocaleStr("No results found", key="search_autocomplete_no_results") - ) - ] + return self.bot.get_error_autocomplete( + LocaleStr(key="search_autocomplete_no_results"), locale + ) random.shuffle(choices) return choices[:25] diff --git a/hoyo_buddy/cogs/settings.py b/hoyo_buddy/cogs/settings.py index 081d3fff..b031531e 100644 --- a/hoyo_buddy/cogs/settings.py +++ b/hoyo_buddy/cogs/settings.py @@ -18,7 +18,7 @@ def __init__(self, bot: HoyoBuddy) -> None: self.bot = bot @app_commands.command( - name=locale_str("settings", translate=False), + name=locale_str("settings"), description=locale_str("Configure your user settings", key="settings_command_description"), ) async def settings_command(self, i: Interaction) -> Any: diff --git a/hoyo_buddy/commands/farm.py b/hoyo_buddy/commands/farm.py index b7b6ba77..131a9d21 100644 --- a/hoyo_buddy/commands/farm.py +++ b/hoyo_buddy/commands/farm.py @@ -64,13 +64,8 @@ async def _check_item_in_list(self, farm_notify: FarmNotify) -> bool: embed = DefaultEmbed( self.locale, self._translator, - title=LocaleStr( - "Item Already in List", key="farm_add_command.item_already_in_list" - ), - description=LocaleStr( - "This item is already in your farm reminder list.", - key="farm_add_command.item_already_in_list_description", - ), + title=LocaleStr(key="farm_add_command.item_already_in_list"), + description=LocaleStr(key="farm_add_command.item_already_in_list_description"), ) await self._interaction.response.send_message(embed=embed) return True diff --git a/hoyo_buddy/commands/geetest.py b/hoyo_buddy/commands/geetest.py index 60a6db6a..88e4404a 100644 --- a/hoyo_buddy/commands/geetest.py +++ b/hoyo_buddy/commands/geetest.py @@ -67,11 +67,8 @@ async def _handle_notif(self, notif: asyncpg_listen.NotificationOrTimeout) -> No embed = DefaultEmbed( self._locale, translator, - title=LocaleStr("Verification timeout", key="geeetest_verification_timeout"), - description=LocaleStr( - "The verification has timed out. Please use the comand to try again.", - key="geeetest_verification_timeout_description", - ), + title=LocaleStr(key="geeetest_verification_timeout"), + description=LocaleStr(key="geeetest_verification_timeout_description"), ) await self._message.edit(embed=embed, view=None) self._bot.login_notif_tasks.pop(self._user_id).cancel() @@ -96,7 +93,7 @@ async def _handle_notif(self, notif: asyncpg_listen.NotificationOrTimeout) -> No embed = DefaultEmbed( self._locale, translator, - title=LocaleStr("Verification complete", key="geeetest_verification_complete"), + title=LocaleStr(key="geeetest_verification_complete"), ) await self._message.edit(embed=embed, view=None) @@ -143,17 +140,14 @@ async def run(self) -> None: i.client.translator, self._locale, url=url, - label=LocaleStr("Complete geetest", key="complete_geetest_button_label"), + label=LocaleStr(key="complete_geetest_button_label"), ) embed = DefaultEmbed( self._locale, i.client.translator, - title=LocaleStr("Complete geetest", key="complete_geetest_button_label"), - description=LocaleStr( - "Click the button below to complete the geetest verification", - key="complete_geetest_button_description", - ), + title=LocaleStr(key="complete_geetest_button_label"), + description=LocaleStr(key="complete_geetest_button_description"), ).add_acc_info(self._account) await i.followup.send(embed=embed, view=view, ephemeral=True) diff --git a/hoyo_buddy/constants.py b/hoyo_buddy/constants.py index 622d6daf..be392d1e 100644 --- a/hoyo_buddy/constants.py +++ b/hoyo_buddy/constants.py @@ -3,16 +3,14 @@ import datetime from typing import Final +import ambr import discord import enka import genshin import hakushin -from ambr import Language as AmbrLanguage -from genshin import Game as GPYGame -from yatta import Language as YattaLanguage -from yatta import PathType +import yatta -from .enums import ChallengeType, Game, HSRPath +from .enums import ChallengeType, Game, GenshinCity, GenshinElement, HSRElement, HSRPath DB_INTEGER_MAX = 2147483647 DB_SMALLINT_MAX = 32767 @@ -150,40 +148,40 @@ def contains_traveler_id(character_id: str) -> bool: discord.Locale.russian: {"name": "Русский", "emoji": "🇷🇺"}, } -LOCALE_TO_AMBR_LANG: dict[discord.Locale, AmbrLanguage] = { - discord.Locale.taiwan_chinese: AmbrLanguage.CHT, - discord.Locale.chinese: AmbrLanguage.CHS, - discord.Locale.german: AmbrLanguage.DE, - discord.Locale.american_english: AmbrLanguage.EN, - discord.Locale.spain_spanish: AmbrLanguage.ES, - discord.Locale.french: AmbrLanguage.FR, - discord.Locale.indonesian: AmbrLanguage.ID, - discord.Locale.japanese: AmbrLanguage.JP, - discord.Locale.korean: AmbrLanguage.KR, - discord.Locale.brazil_portuguese: AmbrLanguage.PT, - discord.Locale.russian: AmbrLanguage.RU, - discord.Locale.ukrainian: AmbrLanguage.RU, - discord.Locale.thai: AmbrLanguage.TH, - discord.Locale.vietnamese: AmbrLanguage.VI, - discord.Locale.italian: AmbrLanguage.IT, - discord.Locale.turkish: AmbrLanguage.TR, +LOCALE_TO_AMBR_LANG: dict[discord.Locale, ambr.Language] = { + discord.Locale.taiwan_chinese: ambr.Language.CHT, + discord.Locale.chinese: ambr.Language.CHS, + discord.Locale.german: ambr.Language.DE, + discord.Locale.american_english: ambr.Language.EN, + discord.Locale.spain_spanish: ambr.Language.ES, + discord.Locale.french: ambr.Language.FR, + discord.Locale.indonesian: ambr.Language.ID, + discord.Locale.japanese: ambr.Language.JP, + discord.Locale.korean: ambr.Language.KR, + discord.Locale.brazil_portuguese: ambr.Language.PT, + discord.Locale.russian: ambr.Language.RU, + discord.Locale.ukrainian: ambr.Language.RU, + discord.Locale.thai: ambr.Language.TH, + discord.Locale.vietnamese: ambr.Language.VI, + discord.Locale.italian: ambr.Language.IT, + discord.Locale.turkish: ambr.Language.TR, } -LOCALE_TO_YATTA_LANG: dict[discord.Locale, YattaLanguage] = { - discord.Locale.taiwan_chinese: YattaLanguage.CHT, - discord.Locale.chinese: YattaLanguage.CN, - discord.Locale.german: YattaLanguage.DE, - discord.Locale.american_english: YattaLanguage.EN, - discord.Locale.spain_spanish: YattaLanguage.ES, - discord.Locale.french: YattaLanguage.FR, - discord.Locale.indonesian: YattaLanguage.ID, - discord.Locale.japanese: YattaLanguage.JP, - discord.Locale.korean: YattaLanguage.KR, - discord.Locale.brazil_portuguese: YattaLanguage.PT, - discord.Locale.russian: YattaLanguage.RU, - discord.Locale.ukrainian: YattaLanguage.RU, - discord.Locale.thai: YattaLanguage.TH, - discord.Locale.vietnamese: YattaLanguage.VI, +LOCALE_TO_YATTA_LANG: dict[discord.Locale, yatta.Language] = { + discord.Locale.taiwan_chinese: yatta.Language.CHT, + discord.Locale.chinese: yatta.Language.CN, + discord.Locale.german: yatta.Language.DE, + discord.Locale.american_english: yatta.Language.EN, + discord.Locale.spain_spanish: yatta.Language.ES, + discord.Locale.french: yatta.Language.FR, + discord.Locale.indonesian: yatta.Language.ID, + discord.Locale.japanese: yatta.Language.JP, + discord.Locale.korean: yatta.Language.KR, + discord.Locale.brazil_portuguese: yatta.Language.PT, + discord.Locale.russian: yatta.Language.RU, + discord.Locale.ukrainian: yatta.Language.RU, + discord.Locale.thai: yatta.Language.TH, + discord.Locale.vietnamese: yatta.Language.VI, } LOCALE_TO_HAKUSHIN_LANG: dict[discord.Locale, hakushin.Language] = { @@ -242,31 +240,69 @@ def contains_traveler_id(character_id: str) -> bool: } YATTA_PATH_TO_HSR_PATH = { - PathType.KNIGHT: HSRPath.PRESERVATION, - PathType.MAGE: HSRPath.ERUDITION, - PathType.PRIEST: HSRPath.ABUNDANCE, - PathType.ROGUE: HSRPath.THE_HUNT, - PathType.SHAMAN: HSRPath.HARMONY, - PathType.WARLOCK: HSRPath.NIHILITY, - PathType.WARRIOR: HSRPath.DESTRUCTION, + yatta.PathType.KNIGHT: HSRPath.PRESERVATION, + yatta.PathType.MAGE: HSRPath.ERUDITION, + yatta.PathType.PRIEST: HSRPath.ABUNDANCE, + yatta.PathType.ROGUE: HSRPath.THE_HUNT, + yatta.PathType.SHAMAN: HSRPath.HARMONY, + yatta.PathType.WARLOCK: HSRPath.NIHILITY, + yatta.PathType.WARRIOR: HSRPath.DESTRUCTION, } YATTA_PATH_TO_GPY_PATH = { - PathType.KNIGHT: genshin.models.StarRailPath.PRESERVATION, - PathType.MAGE: genshin.models.StarRailPath.ERUDITION, - PathType.PRIEST: genshin.models.StarRailPath.ABUNDANCE, - PathType.ROGUE: genshin.models.StarRailPath.THE_HUNT, - PathType.SHAMAN: genshin.models.StarRailPath.HARMONY, - PathType.WARLOCK: genshin.models.StarRailPath.NIHILITY, - PathType.WARRIOR: genshin.models.StarRailPath.DESTRUCTION, + yatta.PathType.KNIGHT: genshin.models.StarRailPath.PRESERVATION, + yatta.PathType.MAGE: genshin.models.StarRailPath.ERUDITION, + yatta.PathType.PRIEST: genshin.models.StarRailPath.ABUNDANCE, + yatta.PathType.ROGUE: genshin.models.StarRailPath.THE_HUNT, + yatta.PathType.SHAMAN: genshin.models.StarRailPath.HARMONY, + yatta.PathType.WARLOCK: genshin.models.StarRailPath.NIHILITY, + yatta.PathType.WARRIOR: genshin.models.StarRailPath.DESTRUCTION, +} + +YATTA_COMBAT_TYPE_TO_ELEMENT = { + yatta.CombatType.ICE: HSRElement.ICE, + yatta.CombatType.FIRE: HSRElement.FIRE, + yatta.CombatType.IMAGINARY: HSRElement.IMAGINARY, + yatta.CombatType.PHYSICAL: HSRElement.PHYSICAL, + yatta.CombatType.QUANTUM: HSRElement.QUANTUM, + yatta.CombatType.WIND: HSRElement.WIND, + yatta.CombatType.THUNDER: HSRElement.THUNDER, +} + +HAKUSHIN_GI_ELEMENT_TO_ELEMENT = { + hakushin.enums.GIElement.ANEMO: GenshinElement.ANEMO, + hakushin.enums.GIElement.GEO: GenshinElement.GEO, + hakushin.enums.GIElement.ELECTRO: GenshinElement.ELECTRO, + hakushin.enums.GIElement.DENDRO: GenshinElement.DENDRO, + hakushin.enums.GIElement.PYRO: GenshinElement.PYRO, + hakushin.enums.GIElement.CRYO: GenshinElement.CRYO, + hakushin.enums.GIElement.HYDRO: GenshinElement.HYDRO, +} + +AMBR_ELEMENT_TO_ELEMENT = { + ambr.Element.ANEMO: GenshinElement.ANEMO, + ambr.Element.GEO: GenshinElement.GEO, + ambr.Element.ELECTRO: GenshinElement.ELECTRO, + ambr.Element.DENDRO: GenshinElement.DENDRO, + ambr.Element.PYRO: GenshinElement.PYRO, + ambr.Element.CRYO: GenshinElement.CRYO, + ambr.Element.HYDRO: GenshinElement.HYDRO, +} + +AMBR_CITY_TO_CITY = { + ambr.City.MONDSTADT: GenshinCity.MONDSTADT, + ambr.City.LIYUE: GenshinCity.LIYUE, + ambr.City.INAZUMA: GenshinCity.INAZUMA, + ambr.City.SUMERU: GenshinCity.SUMERU, + ambr.City.FONTAINE: GenshinCity.FONTAINE, } STARRAIL_RES = "https://raw.githubusercontent.com/Mar-7th/StarRailRes/master" -HB_GAME_TO_GPY_GAME: dict[Game, GPYGame] = { - Game.GENSHIN: GPYGame.GENSHIN, - Game.STARRAIL: GPYGame.STARRAIL, - Game.HONKAI: GPYGame.HONKAI, +HB_GAME_TO_GPY_GAME: dict[Game, genshin.Game] = { + Game.GENSHIN: genshin.Game.GENSHIN, + Game.STARRAIL: genshin.Game.STARRAIL, + Game.HONKAI: genshin.Game.HONKAI, } """Hoyo Buddy game enum to genshin.py game enum.""" diff --git a/hoyo_buddy/db/models.py b/hoyo_buddy/db/models.py index 5c3a9bdc..485c7590 100644 --- a/hoyo_buddy/db/models.py +++ b/hoyo_buddy/db/models.py @@ -218,5 +218,10 @@ async def write(filename: str, data: dict[str, Any]) -> None: async def get_locale(i: Interaction) -> Locale: + cache = i.client.cache + if await cache.exists(i.user.id): + return Locale(await cache.get(i.user.id)) settings = await Settings.get(user_id=i.user.id) - return settings.locale or i.locale + locale = settings.locale or i.locale + await cache.set(i.user.id, locale.value) + return locale diff --git a/hoyo_buddy/draw/funcs/hoyo/farm.py b/hoyo_buddy/draw/funcs/hoyo/farm.py index 17e32c63..80af9843 100644 --- a/hoyo_buddy/draw/funcs/hoyo/farm.py +++ b/hoyo_buddy/draw/funcs/hoyo/farm.py @@ -31,13 +31,11 @@ def draw_farm_card( ) -> io.BytesIO: def get_domain_title(domain: ambr.Domain, locale: Locale, translator: Translator) -> str: """Get the title of a GI domain based on its name and city, assuming the language is English.""" - city_name = translator.translate( - LocaleStr(domain.city.name.title(), warn_no_key=False), locale - ) + city_name = translator.translate(LocaleStr(custom_str=domain.city.name.title()), locale) domain_type = ( - LocaleStr("Characters", key="domain-type.characters") + LocaleStr(key="domain-type.characters") if "Mastery" in domain.name - else LocaleStr("Weapons", key="domain-type.weapons") + else LocaleStr(key="domain-type.weapons") ) domain_type_name = translator.translate(domain_type, locale) return f"{domain_type_name} ({city_name})" diff --git a/hoyo_buddy/draw/funcs/hoyo/genshin/abyss.py b/hoyo_buddy/draw/funcs/hoyo/genshin/abyss.py index a67add3d..c1e1a4b5 100644 --- a/hoyo_buddy/draw/funcs/hoyo/genshin/abyss.py +++ b/hoyo_buddy/draw/funcs/hoyo/genshin/abyss.py @@ -6,7 +6,7 @@ from discord import Locale from PIL import Image, ImageDraw, ImageFilter -from hoyo_buddy.bot.translator import LocaleStr, Translator +from hoyo_buddy.bot.translator import LevelStr, LocaleStr, Translator from hoyo_buddy.draw.drawer import BLACK, TRANSPARENT, WHITE, Drawer if TYPE_CHECKING: @@ -82,12 +82,11 @@ def _get_pills(self) -> list[Image.Image]: pills = [ self._draw_rank_pill( most_defeats, - LocaleStr("Most Defeats: {val}", key="abyss.most_defeats", val=most_defeats.value), + LocaleStr(key="abyss.most_defeats", val=most_defeats.value), ), self._draw_rank_pill( strongest_strike, LocaleStr( - "Strongest Single Strike: {val}", key="abyss.strongest_strike", val=strongest_strike.value, ), @@ -95,22 +94,17 @@ def _get_pills(self) -> list[Image.Image]: self._draw_rank_pill( most_dmg_taken, LocaleStr( - "Most Damage Taken: {val}", key="abyss.most_dmg_taken", val=most_dmg_taken.value, ), ), self._draw_rank_pill( most_ults, - LocaleStr( - "Most Bursts Unleashed: {val}", key="abyss.most_ults", val=most_ults.value - ), + LocaleStr(key="abyss.most_ults", val=most_ults.value), ), self._draw_rank_pill( most_skills, - LocaleStr( - "Most Skills Casted: {val}", key="abyss.most_skills", val=most_skills.value - ), + LocaleStr(key="abyss.most_skills", val=most_skills.value), ), ] @@ -119,7 +113,7 @@ def _get_pills(self) -> list[Image.Image]: def _write_overview_texts(self) -> None: drawer = self._drawer textbbox = drawer.write( - LocaleStr("Spiral Abyss Overview", key="abyss.overview"), + LocaleStr(key="abyss.overview"), position=(2425, 40), size=90, style="bold", @@ -133,7 +127,6 @@ def _write_overview_texts(self) -> None: ) textbbox = drawer.write( LocaleStr( - "Battles Won/Fought: {val1}/{val2}", key="abyss.battles_won_fought", val1=self._abyss.total_wins, val2=self._abyss.total_battles, @@ -144,7 +137,6 @@ def _write_overview_texts(self) -> None: ) textbbox = drawer.write( LocaleStr( - "Deepest Descent: {val}", key="abyss.deepest_descent", val=self._abyss.max_floor, ), @@ -154,7 +146,6 @@ def _write_overview_texts(self) -> None: ) textbbox = drawer.write( LocaleStr( - "Total Stars: {val}", key="abyss.total_stars", val=self._abyss.total_stars, ), @@ -175,7 +166,7 @@ def _write_floor_texts(self) -> None: for floor in range(9, 13): start_pos = pos[floor] drawer.write( - LocaleStr("Floor {val}", key="abyss.floor", val=floor), + LocaleStr(key="abyss.floor", val=floor), position=start_pos, size=64, style="medium", @@ -267,8 +258,13 @@ def _draw_battle_characters(self, battle: genshin.models.Battle) -> Image.Image: style="medium", anchor="mm", ) - level_str = LocaleStr("Lv.{level}", key="level_str", level=abyss_chara.level) - bk_drawer.write(level_str, position=(57, 132), size=24, style="medium", anchor="mm") + bk_drawer.write( + LevelStr(abyss_chara.level), + position=(57, 132), + size=24, + style="medium", + anchor="mm", + ) im.paste(bk, (i * (padding + 116), 0), bk) diff --git a/hoyo_buddy/draw/funcs/hoyo/genshin/characters.py b/hoyo_buddy/draw/funcs/hoyo/genshin/characters.py index fd6e1dac..e1c21512 100644 --- a/hoyo_buddy/draw/funcs/hoyo/genshin/characters.py +++ b/hoyo_buddy/draw/funcs/hoyo/genshin/characters.py @@ -7,7 +7,7 @@ from discord import Locale from PIL import Image, ImageDraw -from hoyo_buddy.bot.translator import LocaleStr +from hoyo_buddy.bot.translator import LevelStr, LocaleStr from hoyo_buddy.draw.drawer import BLACK, DARK_SURFACE, LIGHT_SURFACE, WHITE, Drawer from hoyo_buddy.hoyo.clients.gpy import GenshinClient from hoyo_buddy.models import DynamicBKInput, UnownedCharacter @@ -132,14 +132,14 @@ def draw_small_gi_chara_card( return im text = LocaleStr( - "C{const}R{refine}", key="const_refine_str", const=character.constellation, refine=character.weapon.refinement, ) drawer.write(text, size=31, position=(236, 32), locale=locale, style="medium") - text = LocaleStr("Lv.{level}", key="level_str", level=character.level) - drawer.write(text, size=31, position=(236, 72), locale=locale, style="medium") + drawer.write( + LevelStr(character.level), size=31, position=(236, 72), locale=locale, style="medium" + ) friend_textbbox = drawer.write( str(character.friendship), size=18, position=(284, 151), anchor="mm" diff --git a/hoyo_buddy/draw/funcs/hoyo/genshin/exploration.py b/hoyo_buddy/draw/funcs/hoyo/genshin/exploration.py index ab17e083..3f1c4467 100644 --- a/hoyo_buddy/draw/funcs/hoyo/genshin/exploration.py +++ b/hoyo_buddy/draw/funcs/hoyo/genshin/exploration.py @@ -6,7 +6,7 @@ from discord import Locale from PIL import Image, ImageDraw -from hoyo_buddy.bot.translator import LocaleStr, Translator +from hoyo_buddy.bot.translator import LevelStr, LocaleStr, Translator from hoyo_buddy.draw.drawer import Drawer if TYPE_CHECKING: @@ -62,10 +62,8 @@ def _get_exploration(self, exploration_id: int) -> Exploration | None: return next((e for e in self._user.explorations if e.id == exploration_id), None) def _get_offering_text(self, exploration: Exploration | None) -> str: - level_str = LocaleStr( - "Lv.{level}", - key="level_str", - level=0 if exploration is None else exploration.offerings[0].level, + level_str = LevelStr( + 0 if exploration is None else exploration.offerings[0].level ).translate(self._translator, self.locale) if exploration is None: return f"{self._placeholder}: {level_str}" @@ -81,7 +79,7 @@ def _draw_waypoint_card(self) -> Image.Image: translator=self._drawer.translator, ) self._write_title( - LocaleStr("Waypoints Unlocked", key="exploration.waypoints"), + LocaleStr(key="exploration.waypoints"), position=(35, 20), drawer=drawer, ) @@ -112,17 +110,17 @@ def _draw_chest_card(self) -> Image.Image: translator=self._drawer.translator, ) self._write_title( - LocaleStr("Chests Unlocked", key="exploration.chests"), + LocaleStr(key="exploration.chests"), position=(21, 20), drawer=drawer, ) chest_types: dict[LocaleStr, tuple[int, int]] = { - LocaleStr("Common", key="exploration.common_chests"): (78, 167), - LocaleStr("Exquisite", key="exploration.exquisite_chests"): (210, 167), - LocaleStr("Precious", key="exploration.precious_chests"): (343, 167), - LocaleStr("Luxurious", key="exploration.luxurious_chests"): (476, 167), - LocaleStr("Remarkable", key="exploration.remarkable_chests"): (611, 167), + LocaleStr(key="exploration.common_chests"): (78, 167), + LocaleStr(key="exploration.exquisite_chests"): (210, 167), + LocaleStr(key="exploration.precious_chests"): (343, 167), + LocaleStr(key="exploration.luxurious_chests"): (476, 167), + LocaleStr(key="exploration.remarkable_chests"): (611, 167), } chest_nums: dict[int, tuple[int, int]] = { self._user.stats.common_chests: (79, 196), @@ -180,17 +178,14 @@ def _draw_mondstadt_card(self) -> Image.Image: exploration = self._get_exploration(1) texts: dict[LocaleStr | str, tuple[int, int]] = { LocaleStr( - "Exploration Progress: {progress}%", key="exploration.progress", progress=0 if exploration is None else exploration.explored, ): (75, 161), LocaleStr( - "Anemoculi: {anemoculi}", key="exploration.anemoculi", anemoculi=self._user.stats.anemoculi, ): (75, 207), LocaleStr( - "Reputation: Lv.{reputation}", key="exploration.reputation", reputation=0 if exploration is None else exploration.offerings[0].level, ): (75, 253), @@ -202,17 +197,14 @@ def _draw_liyue_card(self) -> Image.Image: exploration = self._get_exploration(2) texts: dict[LocaleStr | str, tuple[int, int]] = { LocaleStr( - "Exploration Progress: {progress}%", key="exploration.progress", progress=0 if exploration is None else exploration.explored, ): (75, 161), LocaleStr( - "Geoculi: {geoculi}", key="exploration.geoculi", geoculi=self._user.stats.geoculi, ): (75, 207), LocaleStr( - "Reputation: Lv.{reputation}", key="exploration.reputation", reputation=0 if exploration is None else exploration.offerings[0].level, ): (75, 253), @@ -224,17 +216,14 @@ def _draw_inazuma_card(self) -> Image.Image: exploration = self._get_exploration(4) texts = { LocaleStr( - "Exploration Progress: {progress}%", key="exploration.progress", progress=0 if exploration is None else exploration.explored, ): (75, 117), LocaleStr( - "Electroculi: {electroculi}", key="exploration.electroculi", electroculi=self._user.stats.electroculi, ): (75, 163), LocaleStr( - "Reputation: Lv.{reputation}", key="exploration.reputation", reputation=0 if exploration is None else exploration.offerings[1].level, ): (75, 209), @@ -247,17 +236,14 @@ def _draw_sumeru_card(self) -> Image.Image: exploration = self._get_exploration(8) texts = { LocaleStr( - "Exploration Progress: {progress}%", key="exploration.progress", progress=0 if exploration is None else exploration.explored, ): (75, 117), LocaleStr( - "Dendroculi: {dendroculi}", key="exploration.dendroculi", dendroculi=self._user.stats.dendroculi, ): (75, 163), LocaleStr( - "Reputation: Lv.{reputation}", key="exploration.reputation", reputation=0 if exploration is None else exploration.offerings[1].level, ): (75, 209), @@ -270,17 +256,14 @@ def _draw_fontaine_card(self) -> Image.Image: exploration = self._get_exploration(9) texts = { LocaleStr( - "Exploration Progress: {progress}%", key="exploration.progress", progress=0 if exploration is None else exploration.explored, ): (75, 117), LocaleStr( - "Hydroculi: {hydroculi}", key="exploration.hydroculi", hydroculi=self._user.stats.hydroculi, ): (75, 163), LocaleStr( - "Reputation: Lv.{reputation}", key="exploration.reputation", reputation=0 if exploration is None else exploration.offerings[1].level, ): (75, 209), @@ -301,15 +284,12 @@ def _draw_placeholder_card(self) -> Image.Image: ) self._write_title(self._placeholder, position=(34, 23), drawer=drawer) self._write_small_text( - LocaleStr("Yet to be released", key="exploration.placeholder"), + LocaleStr(key="exploration.placeholder"), position=(35, 113), drawer=drawer, ) self._write_small_text( - LocaleStr( - '"Every journey has its final day.Don\'t rush."\n-Zhongli', - key="exploration.placeholder_quote", - ), + LocaleStr(key="exploration.placeholder_quote"), position=(34, 181), drawer=drawer, ) @@ -319,7 +299,6 @@ def _draw_sea_of_bygone_eras_card(self) -> Image.Image: exploration = self._get_exploration(14) texts: dict[LocaleStr | str, tuple[int, int]] = { LocaleStr( - "Exploration Progress: {progress}%", key="exploration.progress", progress=0 if exploration is None else exploration.explored, ): (75, 117), @@ -357,7 +336,6 @@ def _draw_the_chasm_card(self) -> Image.Image: texts = { LocaleStr( - "Exploration Progress: {progress}%", key="exploration.progress", progress=0 if exploration is None else exploration.explored, ): (65, 152), @@ -372,7 +350,6 @@ def _draw_dragonspine_card(self) -> Image.Image: exploration = self._get_exploration(3) texts = { LocaleStr( - "Exploration Progress: {progress}%", key="exploration.progress", progress=0 if exploration is None else exploration.explored, ): (73, 120), @@ -385,7 +362,6 @@ def _draw_enkanomiya_card(self) -> Image.Image: exploration = self._get_exploration(5) texts: dict[LocaleStr | str, tuple[int, int]] = { LocaleStr( - "Exploration Progress: {progress}%", key="exploration.progress", progress=0 if exploration is None else exploration.explored, ): (73, 123), @@ -406,7 +382,7 @@ def draw(self) -> BytesIO: ) self._drawer.write( - LocaleStr("World Exploration", key="exploration.title"), + LocaleStr(key="exploration.title"), position=(114, 81), size=72, style="bold", diff --git a/hoyo_buddy/draw/funcs/hoyo/genshin/notes.py b/hoyo_buddy/draw/funcs/hoyo/genshin/notes.py index 7a3acaf7..2fd042b6 100644 --- a/hoyo_buddy/draw/funcs/hoyo/genshin/notes.py +++ b/hoyo_buddy/draw/funcs/hoyo/genshin/notes.py @@ -26,7 +26,7 @@ def draw_genshin_notes_card( drawer = Drawer(draw, folder="gi-notes", dark_mode=dark_mode, translator=translator) drawer.write( - LocaleStr("Real-Time Notes", key="notes-card.gi.realtime-notes"), + LocaleStr(key="notes-card.gi.realtime-notes"), size=64, position=(76, 67), style="bold", @@ -34,7 +34,7 @@ def draw_genshin_notes_card( ) drawer.write( - LocaleStr("Resin", key="notes-card.gi.resin"), + LocaleStr(key="notes-card.gi.resin"), size=35, position=(110, 400), style="light", @@ -45,7 +45,7 @@ def draw_genshin_notes_card( ) drawer.write( - LocaleStr("Daily Commissions", key="notes-card.gi.daily-commissions"), + LocaleStr(key="notes-card.gi.daily-commissions"), size=35, position=(110, 800), style="light", @@ -58,7 +58,7 @@ def draw_genshin_notes_card( style="medium", ) drawer.write( - LocaleStr("Completed", key="notes-card.gi.completed"), + LocaleStr(key="notes-card.gi.completed"), size=30, position=(textbbox[2] + 20, textbbox[3] - 5), anchor="ls", @@ -66,7 +66,7 @@ def draw_genshin_notes_card( ) drawer.write( - LocaleStr("Realm Currency", key="notes-card.gi.realm-currency"), + LocaleStr(key="notes-card.gi.realm-currency"), size=35, position=(596, 400), style="light", @@ -80,7 +80,7 @@ def draw_genshin_notes_card( ) drawer.write( - LocaleStr("Resin Discounts", key="notes-card.gi.resin-discounts"), + LocaleStr(key="notes-card.gi.resin-discounts"), size=35, position=(596, 800), style="light", @@ -93,7 +93,7 @@ def draw_genshin_notes_card( style="medium", ) drawer.write( - LocaleStr("Remaining", key="notes-card.gi.remaining"), + LocaleStr(key="notes-card.gi.remaining"), size=30, position=(textbbox[2] + 20, textbbox[3] - 5), anchor="ls", @@ -113,12 +113,10 @@ def draw_genshin_notes_card( text = ( LocaleStr( - "Finished", key="notes-card.gi.expedition-finished", ) if exped.finished else LocaleStr( - "{time} Remaining", key="notes-card.gi.expedition-remaining", time=format_timedelta(exped.remaining_time), ) diff --git a/hoyo_buddy/draw/funcs/hoyo/hsr/characters.py b/hoyo_buddy/draw/funcs/hoyo/hsr/characters.py index 0174d6ec..2d1f13d3 100644 --- a/hoyo_buddy/draw/funcs/hoyo/hsr/characters.py +++ b/hoyo_buddy/draw/funcs/hoyo/hsr/characters.py @@ -8,7 +8,7 @@ from genshin.models import StarRailDetailCharacter as HSRCharacter from PIL import Image, ImageDraw -from hoyo_buddy.bot.translator import LocaleStr +from hoyo_buddy.bot.translator import LevelStr, LocaleStr from hoyo_buddy.draw.drawer import DARK_SURFACE, LIGHT_SURFACE, Drawer from hoyo_buddy.models import DynamicBKInput, UnownedCharacter @@ -123,10 +123,9 @@ def draw_small_hsr_chara_card( if isinstance(character, UnownedCharacter): return im - text = LocaleStr("Lv.{level}", key="level_str", level=character.level) + text = LevelStr(character.level) drawer.write(text, size=31, position=(230, 35), locale=locale, style="medium") text = LocaleStr( - "E{eidolon}S{superimpose}", key="eidolon_superimpose_str", eidolon=character.rank, superimpose=character.equip.rank if character.equip else 0, diff --git a/hoyo_buddy/draw/funcs/hoyo/hsr/moc.py b/hoyo_buddy/draw/funcs/hoyo/hsr/moc.py index 2c7571b7..0b6a4602 100644 --- a/hoyo_buddy/draw/funcs/hoyo/hsr/moc.py +++ b/hoyo_buddy/draw/funcs/hoyo/hsr/moc.py @@ -6,7 +6,7 @@ from discord import Locale from PIL import Image, ImageDraw -from hoyo_buddy.bot.translator import LocaleStr, Translator +from hoyo_buddy.bot.translator import EnumStr, LocaleStr, Translator from hoyo_buddy.draw.drawer import TRANSPARENT, WHITE, Drawer from .....enums import ChallengeType @@ -40,7 +40,7 @@ def locale(self) -> Locale: def _write_title(self) -> None: self._drawer.write( - LocaleStr(ChallengeType.MOC.value, warn_no_key=False), + EnumStr(ChallengeType.MOC), size=80, position=(76, 75), style="bold", @@ -69,7 +69,6 @@ def _write_max_stars(self) -> None: def _write_farthest_stage(self) -> None: self._drawer.write( LocaleStr( - "Farthest Stage: {stage}", key="moc_card_farthest_stage", stage=self._data.max_floor.replace(self._season.name, "").strip(), ), @@ -81,7 +80,6 @@ def _write_farthest_stage(self) -> None: def _write_battles_fought(self) -> None: self._drawer.write( LocaleStr( - "Battles Fought: {battles}", key="moc_card_battles_fought", battles=self._data.total_battles, ), @@ -155,7 +153,7 @@ def _draw_stage(self, stage: StarRailFloor) -> Image.Image: ) if stage.round_num == 0: cycle_tbox = drawer.write( - LocaleStr("Quick Clear", key="moc_quick_clear"), + LocaleStr(key="moc_quick_clear"), size=25, position=(0, 60), color=WHITE, @@ -163,11 +161,7 @@ def _draw_stage(self, stage: StarRailFloor) -> Image.Image: ) else: cycle_tbox = drawer.write( - LocaleStr( - "Cycles Used: {cycles}", - key="moc_card_cycles_used", - cycles=stage.round_num, - ), + LocaleStr(key="moc_card_cycles_used", cycles=stage.round_num), size=25, position=(0, 60), color=WHITE, diff --git a/hoyo_buddy/draw/funcs/hoyo/hsr/notes.py b/hoyo_buddy/draw/funcs/hoyo/hsr/notes.py index 1bbf7152..e6bd6814 100644 --- a/hoyo_buddy/draw/funcs/hoyo/hsr/notes.py +++ b/hoyo_buddy/draw/funcs/hoyo/hsr/notes.py @@ -26,7 +26,7 @@ def draw_hsr_notes_card( drawer = Drawer(draw, folder="hsr-notes", dark_mode=dark_mode, translator=translator) drawer.write( - LocaleStr("Real-Time Notes", key="notes-card.gi.realtime-notes"), + LocaleStr(key="notes-card.gi.realtime-notes"), size=64, position=(76, 67), style="bold", @@ -34,7 +34,7 @@ def draw_hsr_notes_card( ) drawer.write( - LocaleStr("Daily Training", key="notes-card.hsr.daily-training"), + LocaleStr(key="notes-card.hsr.daily-training"), size=35, position=(110, 400), style="light", @@ -48,7 +48,7 @@ def draw_hsr_notes_card( ) drawer.write( - LocaleStr("Trailblaze Power", key="notes-card.hsr.trailblaze-power"), + LocaleStr(key="notes-card.hsr.trailblaze-power"), size=35, position=(110, 800), style="light", @@ -62,7 +62,7 @@ def draw_hsr_notes_card( ) drawer.write( - LocaleStr("Echo of War Discounts", key="notes-card.hsr.echo-of-war-discounts"), + LocaleStr(key="notes-card.hsr.echo-of-war-discounts"), size=35, position=(596, 400), style="light", @@ -75,7 +75,7 @@ def draw_hsr_notes_card( style="medium", ) drawer.write( - LocaleStr("Remaining", key="notes-card.gi.remaining"), + LocaleStr(key="notes-card.gi.remaining"), size=30, position=(textbbox[2] + 20, textbbox[3] - 5), anchor="ls", @@ -83,7 +83,7 @@ def draw_hsr_notes_card( ) drawer.write( - LocaleStr("Reserved Power", key="notes-card.hsr.reserved-power"), + LocaleStr(key="notes-card.hsr.reserved-power"), size=35, position=(596, 800), style="light", @@ -109,12 +109,10 @@ def draw_hsr_notes_card( text = ( LocaleStr( - "Finished", key="notes-card.gi.expedition-finished", ) if exped.finished else LocaleStr( - "{time} Remaining", key="notes-card.gi.expedition-remaining", time=format_timedelta(exped.remaining_time), ) diff --git a/hoyo_buddy/draw/funcs/hoyo/hsr/pure_fiction.py b/hoyo_buddy/draw/funcs/hoyo/hsr/pure_fiction.py index 0dc579a3..2cb6d55d 100644 --- a/hoyo_buddy/draw/funcs/hoyo/hsr/pure_fiction.py +++ b/hoyo_buddy/draw/funcs/hoyo/hsr/pure_fiction.py @@ -6,7 +6,7 @@ from discord import Locale from PIL import Image, ImageDraw -from hoyo_buddy.bot.translator import LocaleStr, Translator +from hoyo_buddy.bot.translator import EnumStr, LocaleStr, Translator from hoyo_buddy.draw.drawer import TRANSPARENT, WHITE, Drawer from .....enums import ChallengeType @@ -40,7 +40,7 @@ def locale(self) -> Locale: def _write_title(self) -> None: self._drawer.write( - LocaleStr(ChallengeType.PURE_FICTION.value, warn_no_key=False), + EnumStr(ChallengeType.PURE_FICTION), size=80, position=(76, 75), style="bold", @@ -66,7 +66,6 @@ def _write_max_stars(self) -> None: def _write_farthest_stage(self) -> None: self._drawer.write( LocaleStr( - "Farthest Stage: {stage}", key="moc_card_farthest_stage", stage=self._data.max_floor.replace(self._season.name, "").strip(), ), @@ -77,7 +76,6 @@ def _write_farthest_stage(self) -> None: def _write_battles_fought(self) -> None: self._drawer.write( LocaleStr( - "Battles Fought: {battles}", key="moc_card_battles_fought", battles=self._data.total_battles, ), @@ -150,7 +148,7 @@ def _draw_stage(self, stage: FictionFloor) -> Image.Image: ) if stage.round_num == 0: cycle_tbox = drawer.write( - LocaleStr("Quick Clear", key="moc_quick_clear"), + LocaleStr(key="moc_quick_clear"), size=25, position=(0, 60), color=WHITE, @@ -158,11 +156,7 @@ def _draw_stage(self, stage: FictionFloor) -> Image.Image: ) else: cycle_tbox = drawer.write( - LocaleStr( - "Cycles Used: {cycles}", - key="moc_card_cycles_used", - cycles=stage.round_num, - ), + LocaleStr(key="moc_card_cycles_used", cycles=stage.round_num), size=25, position=(0, 60), color=WHITE, @@ -181,11 +175,7 @@ def _draw_stage(self, stage: FictionFloor) -> Image.Image: pos = (pos[0] + 62, pos[1]) drawer.write( - LocaleStr( - "Total Score: {score}", - key="pf_card_total_score", - score=stage.score or 80000, - ), + LocaleStr(key="pf_card_total_score", score=stage.score or 80000), size=25, position=(rightmost + padding + 37, 60), color=WHITE, diff --git a/hoyo_buddy/emojis.py b/hoyo_buddy/emojis.py index f92c5349..4121fab7 100644 --- a/hoyo_buddy/emojis.py +++ b/hoyo_buddy/emojis.py @@ -131,17 +131,17 @@ def get_game_emoji(game: genshin.Game | Game) -> str: def get_gi_element_emoji(element: str) -> str: - return GENSHIN_ELEMENT_EMOJIS[GenshinElement(element.lower())] + return GENSHIN_ELEMENT_EMOJIS[GenshinElement(element.title())] def get_hsr_element_emoji(element: str) -> str: if element.lower() == "lightning": element = "thunder" - return HSR_ELEMENT_EMOJIS[HSRElement(element.lower())] + return HSR_ELEMENT_EMOJIS[HSRElement(element.title())] def get_hsr_path_emoji(path: str) -> str: - return HSR_PATH_EMOJIS[HSRPath(path.lower())] + return HSR_PATH_EMOJIS[HSRPath(path.title())] def get_artifact_pos_emoji(artifact_pos: str) -> str: diff --git a/hoyo_buddy/enums.py b/hoyo_buddy/enums.py index 308afee8..06c5b028 100644 --- a/hoyo_buddy/enums.py +++ b/hoyo_buddy/enums.py @@ -34,58 +34,48 @@ class NotesNotifyType(IntEnum): """Star Rail Reserved Trailblaze Power""" -class Weekday(IntEnum): - MONDAY = 1 - TUESDAY = 2 - WEDNESDAY = 3 - THURSDAY = 4 - FRIDAY = 5 - SATURDAY = 6 - SUNDAY = 7 - - class TalentBoost(IntEnum): BOOST_E = 1 BOOST_Q = 2 class GenshinElement(StrEnum): - ANEMO = "anemo" - GEO = "geo" - ELECTRO = "electro" - DENDRO = "dendro" - PYRO = "pyro" - CRYO = "cryo" - HYDRO = "hydro" + ANEMO = "Anemo" + GEO = "Geo" + ELECTRO = "Electro" + DENDRO = "Dendro" + PYRO = "Pyro" + CRYO = "Cryo" + HYDRO = "Hydro" class GenshinCity(StrEnum): - MONDSTADT = "mondstadt" - LIYUE = "liyue" - INAZUMA = "inazuma" - SUMERU = "sumeru" - FONTAINE = "fontaine" + MONDSTADT = "Mondstadt" + LIYUE = "Liyue" + INAZUMA = "Inazuma" + SUMERU = "Sumeru" + FONTAINE = "Fontaine" class HSRElement(StrEnum): - FIRE = "fire" - ICE = "ice" - IMAGINARY = "imaginary" - PHYSICAL = "physical" - QUANTUM = "quantum" + FIRE = "Fire" + ICE = "Ice" + IMAGINARY = "Imaginary" + PHYSICAL = "Physical" + QUANTUM = "Quantum" # LIGHTNING = "lightning" - WIND = "wind" - THUNDER = "thunder" + WIND = "Wind" + THUNDER = "Thunder" class HSRPath(StrEnum): - DESTRUCTION = "destruction" # 毀滅 - THE_HUNT = "the_hunt" # 巡獵 - ERUDITION = "erudition" # 智識 - HARMONY = "harmony" # 同諧 - NIHILITY = "nihility" # 虛無 - PRESERVATION = "preservation" # 存護 - ABUNDANCE = "abundance" # 豐饒 + DESTRUCTION = "Destruction" # 毀滅 + THE_HUNT = "The Hunt" # 巡獵 + ERUDITION = "Erudition" # 智識 + HARMONY = "Harmony" # 同諧 + NIHILITY = "Nihility" # 虛無 + PRESERVATION = "Preservation" # 存護 + ABUNDANCE = "Abundance" # 豐饒 class Platform(StrEnum): diff --git a/hoyo_buddy/exceptions.py b/hoyo_buddy/exceptions.py index 584edbc4..1f7e398f 100644 --- a/hoyo_buddy/exceptions.py +++ b/hoyo_buddy/exceptions.py @@ -5,7 +5,7 @@ from discord.app_commands.errors import AppCommandError from discord.utils import format_dt -from .bot.translator import LocaleStr +from .bot.translator import EnumStr, LocaleStr if TYPE_CHECKING: from collections.abc import Sequence @@ -23,7 +23,7 @@ def __init__(self, title: LocaleStr, message: LocaleStr | None = None) -> None: class InvalidInputError(HoyoBuddyError): def __init__(self, reason: LocaleStr) -> None: super().__init__( - title=LocaleStr("Invalid Input", key="invalid_input_error_title"), + title=LocaleStr(key="invalid_input_error_title"), message=reason, ) @@ -31,33 +31,26 @@ def __init__(self, reason: LocaleStr) -> None: class InvalidQueryError(HoyoBuddyError): def __init__(self) -> None: super().__init__( - title=LocaleStr("Invalid Query", key="invalid_query_error_title"), - message=LocaleStr( - "Unable to find anything with the provided query, please select choices from the autocomplete instead of typing your own query.", - key="invalid_query_error_message", - ), + title=LocaleStr(key="invalid_query_error_title"), + message=LocaleStr(key="invalid_query_error_message"), ) class AccountNotFoundError(HoyoBuddyError, AppCommandError): def __init__(self) -> None: super().__init__( - title=LocaleStr("Account Not Found", key="account_not_found_error_title"), - message=LocaleStr( - "Unable to find an account with the provided query, please select choices from the autocomplete instead of typing your own query.", - key="account_not_found_error_message", - ), + title=LocaleStr(key="account_not_found_error_title"), + message=LocaleStr(key="account_not_found_error_message"), ) class NoAccountFoundError(HoyoBuddyError): def __init__(self, games: Sequence[Game], platforms: Sequence[Platform]) -> None: - title = LocaleStr("No Account Found", key="no_account_found_for_games_error_title") + title = LocaleStr(key="no_account_found_for_games_error_title") message = LocaleStr( - "You don't have any accounts for games `{games}` and platforms `{platforms}` yet. Add one with ", key="no_account_found_for_games_error_message", - games=[LocaleStr(game.value, warn_no_key=False) for game in games], - platforms=[LocaleStr(platform.value, warn_no_key=False) for platform in platforms], + games=[EnumStr(game) for game in games], + platforms=[EnumStr(platform) for platform in platforms], ) super().__init__(title=title, message=message) @@ -66,94 +59,63 @@ class CardNotReadyError(HoyoBuddyError): def __init__(self, character_name: str) -> None: super().__init__( title=LocaleStr( - "Card Data for {character_name} is not Ready Yet.", key="exceptions.card_not_ready_error.title", character_name=character_name, ), - message=LocaleStr( - ( - "When new characters are released, I need to spend time to gather fanarts and optimize colors for their cards.\n" - "If you'd like to speed up this process, you can contribute to the card data by reaching me in the [Discord Server](https://dsc.gg/hoyo-buddy)." - ), - key="exceptions.card_not_ready_error.message", - ), + message=LocaleStr(key="exceptions.card_not_ready_error.message"), ) class InvalidImageURLError(HoyoBuddyError): def __init__(self) -> None: super().__init__( - title=LocaleStr("Invalid Image URL", key="invalid_image_url_error_title"), - message=LocaleStr( - "A valid image URL needs to be a direct URL to an image file that contains an image extension, and is publicly accessible.", - key="invalid_image_url_error_message", - ), + title=LocaleStr(key="invalid_image_url_error_title"), + message=LocaleStr(key="invalid_image_url_error_message"), ) class InvalidColorError(HoyoBuddyError): def __init__(self) -> None: super().__init__( - title=LocaleStr("Invalid Color", key="invalid_color_error_title"), - message=LocaleStr( - "A valid color needs to be a hexadecimal color code, e.g. #FF0000", - key="invalid_color_error_message", - ), + title=LocaleStr(key="invalid_color_error_title"), + message=LocaleStr(key="invalid_color_error_message"), ) class IncompleteParamError(HoyoBuddyError): def __init__(self, reason: LocaleStr) -> None: - super().__init__( - title=LocaleStr( - "The Given Command Parameters are Incomplete", key="incomplete_param_error_title" - ), - message=reason, - ) + super().__init__(title=LocaleStr(key="incomplete_param_error_title"), message=reason) class NSFWPromptError(HoyoBuddyError): def __init__(self) -> None: super().__init__( - title=LocaleStr("NSFW Prompt Detected", key="nsfw_prompt_error_title"), - message=LocaleStr( - "The prompt contains NSFW content, please try again with a different prompt.", - key="nsfw_prompt_error_message", - ), + title=LocaleStr(key="nsfw_prompt_error_title"), + message=LocaleStr(key="nsfw_prompt_error_message"), ) class GuildOnlyFeatureError(HoyoBuddyError): def __init__(self) -> None: super().__init__( - title=LocaleStr("Guild Only Feature", key="guild_only_feature_error_title"), - message=LocaleStr( - "This feature is only available in guilds, please try again in a guild.", - key="guild_only_feature_error_message", - ), + title=LocaleStr(key="guild_only_feature_error_title"), + message=LocaleStr(key="guild_only_feature_error_message"), ) class NoCharsFoundError(HoyoBuddyError): def __init__(self) -> None: super().__init__( - title=LocaleStr( - "No Characters Found With the Selected Filter", - key="no_characters_found_error_title", - ), - message=LocaleStr( - "Please try again with a different filter", - key="no_characters_found_error_message", - ), + title=LocaleStr(key="no_characters_found_error_title"), + message=LocaleStr(key="no_characters_found_error_message"), ) class ActionInCooldownError(HoyoBuddyError): def __init__(self, available_time: datetime) -> None: super().__init__( - title=LocaleStr("Action in Cooldown", key="action_in_cooldown_error_title"), + title=LocaleStr(key="action_in_cooldown_error_title"), message=LocaleStr( - "Please try again at {available_time}.", key="action_in_cooldown_error_message", available_time=format_dt(available_time, "T"), ), @@ -164,14 +126,12 @@ class NoChallengeDataError(HoyoBuddyError): def __init__(self, challenge_type: ChallengeType) -> None: super().__init__( title=LocaleStr( - "No {challenge} Data", key="no_challenge_data_err_title", - challenge=LocaleStr(challenge_type.value, warn_no_key=False), + challenge=EnumStr(challenge_type), ), message=LocaleStr( - "Unable to find any {challenge} data for this phase. Either you haven't started {challenge} yet or the data is not ready yet. Please try again later", # noqa: RUF027 key="no_challenge_data_err_message", - challenge=LocaleStr(challenge_type.value, warn_no_key=False), + challenge=EnumStr(challenge_type), ), ) @@ -179,70 +139,45 @@ def __init__(self, challenge_type: ChallengeType) -> None: class NoGameAccountsError(HoyoBuddyError): def __init__(self, platform: Platform) -> None: super().__init__( - title=LocaleStr("No Game Accounts", key="no_game_accounts_error_title"), - message=LocaleStr( - "This {platform} account has no game accounts.", - key="no_game_accounts_error_message", - platform=LocaleStr(platform.value, warn_no_key=False), - ), + title=LocaleStr(key="no_game_accounts_error_title"), + message=LocaleStr(key="no_game_accounts_error_message", platform=EnumStr(platform)), ) class TryOtherMethodError(HoyoBuddyError): def __init__(self) -> None: super().__init__( - title=LocaleStr("Invalid Cookies", key="try_other_method_error_title"), - message=LocaleStr( - "Please try other methods to login.\n" - "If you are entering cookies manually through DevTools, make sure you are copying them correctly.", - key="try_other_method_error_message", - ), + title=LocaleStr(key="try_other_method_error_title"), + message=LocaleStr(key="try_other_method_error_message"), ) class AIGenImageError(HoyoBuddyError): def __init__(self) -> None: super().__init__( - title=LocaleStr( - "An Error Occured While Generating Art With AI", - key="ai_gen_image_error_title", - ), - message=LocaleStr("Check your prompt and try again.", key="ai_gen_image_error_message"), + title=LocaleStr(key="ai_gen_image_error_title"), + message=LocaleStr(key="ai_gen_image_error_message"), ) class DownloadImageFailedError(HoyoBuddyError): def __init__(self, url: str, status: int) -> None: super().__init__( - title=LocaleStr("Image Download Failed", key="download_image_failed_error_title"), - message=LocaleStr( - "Unable to download image {url} with status code {status}.\n" - "Try again later, try with a different image, or check if the image URL is valid.", - key="download_image_failed_error_message", - url=url, - status=status, - ), + title=LocaleStr(key="download_image_failed_error_title"), + message=LocaleStr(key="download_image_failed_error_message", url=url, status=status), ) class AutocompleteNotDoneYetError(HoyoBuddyError): def __init__(self) -> None: - super().__init__( - title=LocaleStr( - "Search autocomplete choices not set up yet, please try again later.", - key="search_autocomplete_not_setup", - ), - ) + super().__init__(title=LocaleStr(key="search_autocomplete_not_setup")) class FeatureNotImplementedError(HoyoBuddyError): def __init__(self, *, platform: Platform, game: Game) -> None: super().__init__( - title=LocaleStr("Not Implemented", key="not_implemented_error_title"), + title=LocaleStr(key="not_implemented_error_title"), message=LocaleStr( - "This feature is not implemented for `{game}` under platform `{platform}` yet.", - key="not_implemented_error_message", - game=LocaleStr(game.value, warn_no_key=False), - platform=LocaleStr(platform.value, warn_no_key=False), + key="not_implemented_error_message", game=EnumStr(game), platform=EnumStr(platform) ), ) diff --git a/hoyo_buddy/hoyo/auto_tasks/auto_redeem.py b/hoyo_buddy/hoyo/auto_tasks/auto_redeem.py index 04011d7c..ed654d45 100644 --- a/hoyo_buddy/hoyo/auto_tasks/auto_redeem.py +++ b/hoyo_buddy/hoyo/auto_tasks/auto_redeem.py @@ -48,11 +48,7 @@ async def _redeem_codes(cls, codes: list[str], account: HoyoAccount) -> None: embed = await account.client.redeem_codes( codes, locale=locale, translator=cls._bot.translator, inline=True, blur=False ) - embed.set_footer( - text=LocaleStr( - "Turn off auto code redemption with /redeem", key="auto_redeem_footer" - ) - ) + embed.set_footer(text=LocaleStr(key="auto_redeem_footer")) except Exception as e: embed = await cls._handle_error(account, locale, e) else: @@ -75,12 +71,7 @@ async def _handle_error(cls, account: HoyoAccount, locale: Locale, e: Exception) if not recognized: cls._bot.capture_exception(e) - content = LocaleStr( - "An error occurred while redeeming codes automatically.\n" - "Hoyo Buddy has disabled this feature for this account, you can turn it back on using \n" - "If this error persists or you don't know how to fix it, please contact the developer via .\n", - key="auto_redeem_error.content", - ) + content = LocaleStr(key="auto_redeem_error.content") await cls._bot.dm_user( account.user.id, embed=embed, diff --git a/hoyo_buddy/hoyo/auto_tasks/farm_check.py b/hoyo_buddy/hoyo/auto_tasks/farm_check.py index 855b28c5..5bd49543 100644 --- a/hoyo_buddy/hoyo/auto_tasks/farm_check.py +++ b/hoyo_buddy/hoyo/auto_tasks/farm_check.py @@ -36,18 +36,12 @@ async def _notify_user(cls, item: CharacterOrWeapon, farm_notify: FarmNotify) -> locale, cls._translator, title=LocaleStr( - "Materials For {name} is Farmable Today", key="farm_check.farmable_today", name=cls._item_id_to_name[locale.value][str(item.id)], ), ) embed.set_thumbnail(url=item.icon) - embed.set_footer( - text=LocaleStr( - "Use /farm reminder to configure reminder settings\nUse /farm view to view all items farmable today", - key="farm_check.use_farm_notify", - ) - ) + embed.set_footer(text=LocaleStr(key="farm_check.use_farm_notify")) embed.add_acc_info(farm_notify.account, blur=False) message = await cls._bot.dm_user(farm_notify.account.user.id, embed=embed) diff --git a/hoyo_buddy/hoyo/auto_tasks/notes_check.py b/hoyo_buddy/hoyo/auto_tasks/notes_check.py index 7d546745..b333ef7e 100644 --- a/hoyo_buddy/hoyo/auto_tasks/notes_check.py +++ b/hoyo_buddy/hoyo/auto_tasks/notes_check.py @@ -57,11 +57,9 @@ def _get_notify_embed(cls, notify: NotesNotify, locale: Locale) -> DefaultEmbed: embed = DefaultEmbed( locale, translator, - title=LocaleStr("Resin Reminder", key="resin_reminder_button.label"), + title=LocaleStr(key="resin_reminder_button.label"), description=LocaleStr( - "Threshold ({threshold}) is reached", - key="threshold.embed.description", - threshold=notify.threshold, + key="threshold.embed.description", threshold=notify.threshold ), ) embed.set_thumbnail(url=RESIN_ICON) @@ -69,11 +67,9 @@ def _get_notify_embed(cls, notify: NotesNotify, locale: Locale) -> DefaultEmbed: embed = DefaultEmbed( locale, translator, - title=LocaleStr("Trailblaze Power Reminder", key="tbp_reminder_button.label"), + title=LocaleStr(key="tbp_reminder_button.label"), description=LocaleStr( - "Threshold ({threshold}) is reached", - key="threshold.embed.description", - threshold=notify.threshold, + key="threshold.embed.description", threshold=notify.threshold ), ) embed.set_thumbnail(url=TBP_ICON) @@ -81,14 +77,9 @@ def _get_notify_embed(cls, notify: NotesNotify, locale: Locale) -> DefaultEmbed: embed = DefaultEmbed( locale, translator, - title=LocaleStr( - "Reserved Trailblaze Power Reminder", - key="rtbp_reminder_button.label", - ), + title=LocaleStr(key="rtbp_reminder_button.label"), description=LocaleStr( - "Threshold ({threshold}) is reached", - key="threshold.embed.description", - threshold=notify.threshold, + key="threshold.embed.description", threshold=notify.threshold ), ) embed.set_thumbnail(url=RTBP_ICON) @@ -96,32 +87,24 @@ def _get_notify_embed(cls, notify: NotesNotify, locale: Locale) -> DefaultEmbed: embed = DefaultEmbed( locale, translator, - title=LocaleStr("Expedition Reminder", key="exped_button.label"), - description=LocaleStr( - "One (or more) expedetions are finished", - key="exped.embed.description", - ), + title=LocaleStr(key="exped_button.label"), + description=LocaleStr(key="exped.embed.description"), ) case NotesNotifyType.PT: embed = DefaultEmbed( locale, translator, - title=LocaleStr("Parametric Transformer Reminder", key="pt_button.label"), - description=LocaleStr( - "Parametric Transformer is ready", - key="pt.embed.description", - ), + title=LocaleStr(key="pt_button.label"), + description=LocaleStr(key="pt.embed.description"), ) embed.set_thumbnail(url=PT_ICON) case NotesNotifyType.REALM_CURRENCY: embed = DefaultEmbed( locale, translator, - title=LocaleStr("Realm Currency Reminder", key="realm_curr_button.label"), + title=LocaleStr(key="realm_curr_button.label"), description=LocaleStr( - "Threshold ({threshold}) is reached", - key="threshold.embed.description", - threshold=notify.threshold, + key="threshold.embed.description", threshold=notify.threshold ), ) embed.set_thumbnail(url=REALM_CURRENCY_ICON) @@ -129,43 +112,29 @@ def _get_notify_embed(cls, notify: NotesNotify, locale: Locale) -> DefaultEmbed: embed = DefaultEmbed( locale, translator, - title=LocaleStr("Daily Commision Reminder", key="daily_button.label"), - description=LocaleStr( - "Daily commisions or adventure encounters are not completed yet", - key="gi_daily.embed.description", - ), + title=LocaleStr(key="daily_button.label"), + description=LocaleStr(key="gi_daily.embed.description"), ) embed.set_thumbnail(url=COMMISSION_ICON) case NotesNotifyType.HSR_DAILY: embed = DefaultEmbed( locale, translator, - title=LocaleStr("Daily Training Reminder", key="daily_training_button.label"), - description=LocaleStr( - "Daily trainings are not completed yet", - key="hsr_daily.embed.description", - ), + title=LocaleStr(key="daily_training_button.label"), + description=LocaleStr(key="hsr_daily.embed.description"), ) case NotesNotifyType.RESIN_DISCOUNT | NotesNotifyType.ECHO_OF_WAR: embed = DefaultEmbed( locale, translator, - title=LocaleStr("Weekly Boss Discount Reminder", key="week_boss_button.label"), - description=LocaleStr( - "Weekly boss discounts are not used up yet", - key="resin_discount.embed.description", - ), + title=LocaleStr(key="week_boss_button.label"), + description=LocaleStr(key="resin_discount.embed.description"), ) case _: raise NotImplementedError embed.add_acc_info(notify.account, blur=False) - embed.set_footer( - text=LocaleStr( - "Click the button below to change notification settings.\nIf it is expired, use the /notes command.", - key="notif.embed.footer", - ) - ) + embed.set_footer(text=LocaleStr(key="notif.embed.footer")) embed.set_image(url="attachment://notes.webp") return embed @@ -353,12 +322,7 @@ async def _process_notify(cls, notify: NotesNotify, notes: Notes | StarRailNote) @classmethod async def _handle_notify_error(cls, notify: NotesNotify, e: Exception) -> None: - content = LocaleStr( - "An error occurred while processing your real-time notes reminder.\n" - "Hoyo Buddy has disabled this reminder for this account, you can turn it back on using \n" - "If this error persists or you don't know how to fix it, please contact the developer via .\n", - key="process_notify_error.content", - ) + content = LocaleStr(key="process_notify_error.content") locale = await cls._get_locale(notify) embed = cls._get_notify_error_embed(e, await cls._get_locale(notify)) embed.add_acc_info(notify.account, blur=False) diff --git a/hoyo_buddy/hoyo/clients/ambr.py b/hoyo_buddy/hoyo/clients/ambr.py index e2696b38..f2848466 100644 --- a/hoyo_buddy/hoyo/clients/ambr.py +++ b/hoyo_buddy/hoyo/clients/ambr.py @@ -12,8 +12,8 @@ from hoyo_buddy.emojis import COMFORT_ICON, DICE_EMOJIS, LOAD_ICON, get_gi_element_emoji -from ...bot.translator import LocaleStr, Translator -from ...constants import LOCALE_TO_AMBR_LANG, WEEKDAYS, contains_traveler_id +from ...bot.translator import LevelStr, LocaleStr, Translator, WeekdayStr +from ...constants import LOCALE_TO_AMBR_LANG, contains_traveler_id from ...embeds import DefaultEmbed from ...enums import TalentBoost from ...models import ItemWithDescription @@ -125,25 +125,12 @@ def get_character_embed( formatted_stat_values, manual_weapon ) - level_str = self.translator.translate( - LocaleStr( - "Lv.{level}", - key="level_str", - level=level, - ), - self.locale, - ) + level_str = self.translator.translate(LevelStr(level), self.locale) embed = DefaultEmbed( self.locale, self.translator, title=f"{character.name} ({level_str})", description=LocaleStr( - ( - "{rarity}★ {element}\n" - "Birthday: {birthday}\n" - "Constellation: {constellation}\n" - "Affiliation: {affiliation}\n" - ), key="character_embed_description", rarity=character.rarity, element=get_gi_element_emoji(character.element.name), @@ -154,7 +141,7 @@ def get_character_embed( ) embed.add_field( - name=LocaleStr("Stats", key="stats_embed_field_name"), + name=LocaleStr(key="stats_embed_field_name"), value="\n".join(f"{k}: {v}" for k, v in named_stat_values.items()), ) embed.set_footer(text=character.info.detail) @@ -181,11 +168,7 @@ def get_character_talent_embed(self, talent: ambr.Talent, level: int) -> Default level = level_upgrade.level embed.add_field( - name=LocaleStr( - "Skill Attributes (Lv.{level})", - key="skill_attributes_embed_field_name", - level=level, - ), + name=LocaleStr(key="skill_attributes_embed_field_name", level=level), value=autils.get_skill_attributes(level_upgrade.description, level_upgrade.params), ) embed.set_thumbnail(url=talent.icon) @@ -267,11 +250,7 @@ def get_weapon_embed( sub_stat_name = manual_weapon[sub_stat.prop_type] if sub_stat.prop_type else None sub_stat_value = stat_values[sub_stat.prop_type] if sub_stat.prop_type else None - level_str = LocaleStr( - "Lv.{level}", - key="level_str", - level=level, - ).translate(self.translator, self.locale) + level_str = LevelStr(level).translate(self.translator, self.locale) embed = DefaultEmbed( self.locale, self.translator, @@ -285,7 +264,7 @@ def get_weapon_embed( if weapon.affix: embed.add_field( - name=LocaleStr("Refinement {r}", r=refinement, key="refinement_indicator"), + name=LocaleStr(r=refinement, key="refinement_indicator"), value=weapon.affix.upgrades[refinement - 1].description, ) embed.set_thumbnail(url=weapon.icon) @@ -318,7 +297,6 @@ def get_artifact_embed( description = self.translator.translate( LocaleStr( - "2-Pieces: {bonus_2}", bonus_2=artifact_set.affix_list[0].effect, key="artifact_set_two_piece_embed_description", ), @@ -326,7 +304,6 @@ def get_artifact_embed( ) if len(artifact_set.affix_list) == 2: four_piece = LocaleStr( - "4-Pieces: {bonus_4}", bonus_4=artifact_set.affix_list[1].effect, key="artifact_set_four_piece_embed_description", ) @@ -370,7 +347,10 @@ def get_material_embed(self, material: ambr.MaterialDetail) -> DefaultEmbed: for source in material.sources: if source.days: days_str = ", ".join( - [self.translator.translate(WEEKDAYS[d], self.locale) for d in source.days] + [ + self.translator.translate(WeekdayStr(day), self.locale) + for day in source.days + ] ) names.append(f"{source.name} ({days_str})") else: @@ -404,10 +384,6 @@ def get_furniture_embed(self, furniture: ambr.FurnitureDetail) -> DefaultEmbed: self.translator, title=f"{furniture.name}\n{'★' * furniture.rarity}", description=LocaleStr( - "{comfort_icon} Comfort: {comfort}\n" - "{load_icon} Load: {load}\n" - "Trust: {trust}\n" - "Creation Time: {hour}h", key="furniture_embed_description", comfort_icon=COMFORT_ICON, load_icon=LOAD_ICON, @@ -530,9 +506,7 @@ def get_tcg_card_talent_embed( name=dictionary.name, value=dictionary.description, inline=False ) - embed.add_field( - name=LocaleStr("Dice Cost", key="dice_cost_embed_field_name"), value=dice_str - ) + embed.add_field(name=LocaleStr(key="dice_cost_embed_field_name"), value=dice_str) embed.set_author(name="/".join([t.name for t in talent.tags])) embed.set_thumbnail(url=talent.icon) @@ -554,7 +528,6 @@ def get_abyss_chamber_embed_with_floor_info( self.locale, self.translator, title=LocaleStr( - "Floor {floor_index} - Chamber {chamber_index}", floor_index=floor_index + 1, chamber_index=chamber_index + 1, key="abyss_chamber.embed.title", @@ -562,26 +535,22 @@ def get_abyss_chamber_embed_with_floor_info( ) embed.add_field( - name=LocaleStr("Enemy Level", key="abyss_chamber.enemy_level.embed.field.name"), + name=LocaleStr(key="abyss_chamber.enemy_level.embed.field.name"), value=str(floor.override_enemy_level), inline=False, ) embed.add_field( - name=LocaleStr("Blessing", key="abyss_chamber.blessing.embed.field.name"), + name=LocaleStr(key="abyss_chamber.blessing.embed.field.name"), value=blessing.description, inline=False, ) embed.add_field( - name=LocaleStr( - "Challenge Target", key="abyss_chamber.challenge_target.embed.field.name" - ), + name=LocaleStr(key="abyss_chamber.challenge_target.embed.field.name"), value=chamber.challenge_target.formatted, inline=False, ) embed.add_field( - name=LocaleStr( - "Ley Line Disorder", key="abyss_chamber.ley_line_disorder.embed.field.name" - ), + name=LocaleStr(key="abyss_chamber.ley_line_disorder.embed.field.name"), value=create_bullet_list( [lld.description for lld in floor.ley_line_disorders if lld.visible] ), @@ -621,7 +590,6 @@ def _get_abyss_enemy_item( prop_values[prop] *= multiplier title_locale_str = LocaleStr( - "HP: {HP}", key="abyss_enemy.item_description", HP=f"{round(prop_values['FIGHT_PROP_BASE_HP']):,}", ) diff --git a/hoyo_buddy/hoyo/clients/gpy.py b/hoyo_buddy/hoyo/clients/gpy.py index a5d6f2de..52d09ff2 100644 --- a/hoyo_buddy/hoyo/clients/gpy.py +++ b/hoyo_buddy/hoyo/clients/gpy.py @@ -65,7 +65,7 @@ def get_daily_reward_embed( DefaultEmbed( locale, translator, - title=LocaleStr("Daily Check-In Reward Claimed", key="reward_claimed_title"), + title=LocaleStr(key="reward_claimed_title"), description=f"{daily_reward.name} x{daily_reward.amount}", ) .set_thumbnail(url=daily_reward.icon) @@ -325,7 +325,7 @@ async def redeem_codes( embed = DefaultEmbed( locale, translator, - title=LocaleStr("Code Redemption Results", key="redeem_command_embed.title"), + title=LocaleStr(key="redeem_command_embed.title"), ).add_acc_info(self._account, blur=blur) for result in results: name = f"{'✅' if result[2] else '❌'} {result[0]}" @@ -369,8 +369,6 @@ async def redeem_code( return f"{embed.title}\n{embed.description}", success else: success = True - msg = LocaleStr("Successfully redeemed", key="redeem_code.success").translate( - translator, locale - ) + msg = LocaleStr(key="redeem_code.success").translate(translator, locale) return msg, success diff --git a/hoyo_buddy/hoyo/clients/hakushin.py b/hoyo_buddy/hoyo/clients/hakushin.py index 1a22f017..29f48ed8 100644 --- a/hoyo_buddy/hoyo/clients/hakushin.py +++ b/hoyo_buddy/hoyo/clients/hakushin.py @@ -7,7 +7,7 @@ import hakushin import yatta -from ...bot.translator import LocaleStr, Translator +from ...bot.translator import LevelStr, LocaleStr, Translator from ...constants import LOCALE_TO_HAKUSHIN_LANG, YATTA_PATH_TO_HSR_PATH, contains_traveler_id from ...embeds import DefaultEmbed from ...emojis import get_hsr_path_emoji @@ -62,14 +62,7 @@ def get_character_embed( formatted_stat_values, manual_weapon ) - level_str = self._translator.translate( - LocaleStr( - "Lv.{level}", - key="level_str", - level=level, - ), - self._locale, - ) + level_str = self._translator.translate(LevelStr(level), self._locale) embed = DefaultEmbed( self._locale, self._translator, @@ -78,7 +71,7 @@ def get_character_embed( ) embed.add_field( - name=LocaleStr("Stats", key="stats_embed_field_name"), + name=LocaleStr(key="stats_embed_field_name"), value="\n".join(f"{k}: {v}" for k, v in named_stat_values.items()), ) embed.set_footer(text=character.description) @@ -105,11 +98,7 @@ def get_character_skill_embed( if isinstance(skill, hakushin.gi.CharacterSkill): level_upgrade = skill.upgrade_info[str(level - 1)] embed.add_field( - name=LocaleStr( - "Skill Attributes (Lv.{level})", - key="skill_attributes_embed_field_name", - level=level, - ), + name=LocaleStr(key="skill_attributes_embed_field_name", level=level), value=hakushin.utils.get_skill_attributes( level_upgrade.attributes, level_upgrade.parameters ), @@ -118,11 +107,7 @@ def get_character_skill_embed( else: level_upgrade = skill.level_info[str(level)] embed.add_field( - name=LocaleStr( - "Skill Attributes (Lv.{level})", - key="skill_attributes_embed_field_name", - level=level, - ), + name=LocaleStr(key="skill_attributes_embed_field_name", level=level), value=hakushin.utils.replace_placeholders( skill.description, level_upgrade.parameters ), @@ -186,11 +171,7 @@ def get_weapon_embed( formatted_stat_values, manual_weapon ) - level_str = LocaleStr( - "Lv.{level}", - key="level_str", - level=level, - ).translate(self._translator, self._locale) + level_str = self._translator.translate(LevelStr(level), self._locale) embed = DefaultEmbed( self._locale, self._translator, @@ -200,13 +181,13 @@ def get_weapon_embed( if weapon.refinments: embed.add_field( - name=LocaleStr("Refinement {r}", r=refinement, key="refinement_indicator"), + name=LocaleStr(r=refinement, key="refinement_indicator"), value=weapon.refinments[str(refinement)].description, inline=False, ) embed.add_field( - name=LocaleStr("Stats", key="stats_embed_field_name"), + name=LocaleStr(key="stats_embed_field_name"), value="\n".join(f"{k}: {v}" for k, v in named_stat_values.items()), inline=False, ) @@ -225,14 +206,7 @@ def get_light_cone_embed( self._check_translator() assert self._translator is not None - level_str = self._translator.translate( - LocaleStr( - "Lv.{level}", - key="level_str", - level=level, - ), - self._locale, - ) + level_str = self._translator.translate(LevelStr(level), self._locale) embed = DefaultEmbed( self._locale, self._translator, @@ -253,7 +227,7 @@ def get_light_cone_embed( result = hakushin.utils.replace_fight_prop_with_name(result, manual_weapon) embed.add_field( - name=LocaleStr("Stats", key="stats_embed_field_name"), + name=LocaleStr(key="stats_embed_field_name"), value="\n".join(f"{k}: {v}" for k, v in result.items()), inline=False, ) @@ -278,7 +252,6 @@ def get_relic_embed( set_effects = relic_set.set_effects description = self._translator.translate( LocaleStr( - "2-Pieces: {bonus_2}", bonus_2=hakushin.utils.replace_placeholders( set_effects.two_piece.description, set_effects.two_piece.parameters ), @@ -288,7 +261,6 @@ def get_relic_embed( ) if set_effects.four_piece is not None: four_piece = LocaleStr( - "4-Pieces: {bonus_4}", bonus_4=hakushin.utils.replace_placeholders( set_effects.four_piece.description, set_effects.four_piece.parameters ), @@ -316,7 +288,6 @@ def get_artifact_embed( description = self._translator.translate( LocaleStr( - "2-Pieces: {bonus_2}", bonus_2=artifact_set.set_effect.two_piece.description, key="artifact_set_two_piece_embed_description", ), @@ -324,7 +295,6 @@ def get_artifact_embed( ) if artifact_set.set_effect.four_piece is not None: four_piece = LocaleStr( - "4-Pieces: {bonus_4}", bonus_4=artifact_set.set_effect.four_piece.description, key="artifact_set_four_piece_embed_description", ) @@ -360,8 +330,9 @@ async def fetch_characters( return characters for character in characters: - assert isinstance(character, hakushin.gi.Character) - if contains_traveler_id(str(character.id)): + if isinstance(character, hakushin.gi.Character) and contains_traveler_id( + str(character.id) + ): character.name = self._translator.get_traveler_name( character, self._locale, gender_symbol=traveler_gender_symbol ) diff --git a/hoyo_buddy/hoyo/clients/yatta.py b/hoyo_buddy/hoyo/clients/yatta.py index f1ee8aa2..bed11ae0 100644 --- a/hoyo_buddy/hoyo/clients/yatta.py +++ b/hoyo_buddy/hoyo/clients/yatta.py @@ -11,7 +11,7 @@ from seria.utils import create_bullet_list from yatta import Language -from ...bot.translator import LocaleStr +from ...bot.translator import LevelStr, LocaleStr from ...constants import LOCALE_TO_YATTA_LANG, TRAILBLAZER_IDS, YATTA_PATH_TO_HSR_PATH from ...embeds import DefaultEmbed from ...emojis import get_hsr_element_emoji, get_hsr_path_emoji @@ -175,20 +175,12 @@ def get_character_details_embed( msg = "Translator is not set" raise RuntimeError(msg) - level_str = self.translator.translate( - LocaleStr( - "Lv.{level}", - key="level_str", - level=level, - ), - self.locale, - ) + level_str = self.translator.translate(LevelStr(level), self.locale) embed = DefaultEmbed( self.locale, self.translator, title=f"{character.name} ({level_str})", description=LocaleStr( - ("{rarity}\nElement: {element}\nPath: {path}\nWorld: {world}\n"), key="yatta_character_embed_description", rarity="★" * character.rarity, element=f"{get_hsr_element_emoji(character.types.combat_type.id)} {character.types.combat_type.name}", @@ -214,7 +206,7 @@ def get_character_details_embed( named_stat_values[named_stat] = value_ embed.add_field( - name=LocaleStr("Stats", key="stats_embed_field_name"), + name=LocaleStr(key="stats_embed_field_name"), value="\n".join(f"{k}: {v}" for k, v in named_stat_values.items()), ) embed.set_footer(text=character.info.description) @@ -231,14 +223,7 @@ def get_character_main_skill_embed( raise RuntimeError(msg) skill = base_skill.skill_list[0] - level_str = self.translator.translate( - LocaleStr( - "Lv.{level}", - key="level_str", - level=level, - ), - self.locale, - ) + level_str = self.translator.translate(LevelStr(level), self.locale) embed = DefaultEmbed( self.locale, @@ -259,7 +244,6 @@ def get_character_main_skill_embed( energy_value_strs.append( self.translator.translate( LocaleStr( - "Generation: {energy_generation}", key="yatta_character_skill_energy_generation_field_value", energy_generation=energy_generation.value, ), @@ -270,7 +254,6 @@ def get_character_main_skill_embed( energy_value_strs.append( self.translator.translate( LocaleStr( - "Cost: {energy_need}", key="yatta_character_skill_energy_need_field_value", energy_need=energy_need.value, ), @@ -279,7 +262,7 @@ def get_character_main_skill_embed( ) if energy_value_strs: embed.add_field( - name=LocaleStr("Energy", key="yatta_character_skill_energy_field_name"), + name=LocaleStr(key="yatta_character_skill_energy_field_name"), value="/".join(energy_value_strs), ) @@ -292,7 +275,6 @@ def get_character_main_skill_embed( weakness_break_value_strs.append( self.translator.translate( LocaleStr( - "Single: {single_weakness_break}", key="yatta_character_skill_single_weakness_break_field_value", single_weakness_break=single_weakness_break.value, ), @@ -303,7 +285,6 @@ def get_character_main_skill_embed( weakness_break_value_strs.append( self.translator.translate( LocaleStr( - "Spread: {spread_weakness_break}", key="yatta_character_skill_spread_weakness_break_field_value", spread_weakness_break=spread_weakness_break.value, ), @@ -314,7 +295,6 @@ def get_character_main_skill_embed( weakness_break_value_strs.append( self.translator.translate( LocaleStr( - "AoE: {aoe_weakness_break}", key="yatta_character_skill_aoe_weakness_break_field_value", aoe_weakness_break=aoe_weakness_break.value, ), @@ -323,9 +303,7 @@ def get_character_main_skill_embed( ) if weakness_break_value_strs: embed.add_field( - name=LocaleStr( - "Weakness Break", key="yatta_character_skill_weakness_break_field_name" - ), + name=LocaleStr(key="yatta_character_skill_weakness_break_field_name"), value="/".join(weakness_break_value_strs), ) @@ -413,7 +391,7 @@ def get_item_embed(self, item: yatta.ItemDetail) -> DefaultEmbed: ) if item.sources: embed.add_field( - name=LocaleStr("Sources", key="yatta_item_sources_field_name"), + name=LocaleStr(key="yatta_item_sources_field_name"), value=create_bullet_list([source.description for source in item.sources]), ) embed.set_footer(text=item.story) @@ -433,14 +411,7 @@ def get_light_cone_embed( msg = "Translator is not set" raise RuntimeError(msg) - level_str = self.translator.translate( - LocaleStr( - "Lv.{level}", - key="level_str", - level=level, - ), - self.locale, - ) + level_str = self.translator.translate(LevelStr(level), self.locale) lc_path = yatta.PathType(light_cone.type.id) path_emoji = get_hsr_path_emoji(YATTA_PATH_TO_HSR_PATH[lc_path].value) @@ -460,7 +431,7 @@ def get_light_cone_embed( named_stat_values[named_stat] = int(value[level - 1]) embed.add_field( - name=LocaleStr("Stats", key="stats_embed_field_name"), + name=LocaleStr(key="stats_embed_field_name"), value="\n".join(f"{k}: {v}" for k, v in named_stat_values.items()), inline=False, ) @@ -501,7 +472,6 @@ def get_relic_embed(self, relic_set: yatta.RelicSetDetail, relic: yatta.Relic) - set_effects = relic_set.set_effects description = self.translator.translate( LocaleStr( - "2-Pieces: {bonus_2}", bonus_2=self._process_description_params( set_effects.two_piece.description, set_effects.two_piece.params ), @@ -511,7 +481,6 @@ def get_relic_embed(self, relic_set: yatta.RelicSetDetail, relic: yatta.Relic) - ) if set_effects.four_piece is not None: four_piece = LocaleStr( - "4-Pieces: {bonus_4}", bonus_4=self._process_description_params( set_effects.four_piece.description, set_effects.four_piece.params ), diff --git a/hoyo_buddy/hoyo/farm_data.py b/hoyo_buddy/hoyo/farm_data.py index e7a45a67..4b4ec7ee 100644 --- a/hoyo_buddy/hoyo/farm_data.py +++ b/hoyo_buddy/hoyo/farm_data.py @@ -4,7 +4,7 @@ from discord import Locale -from ..enums import GenshinCity +from ..constants import AMBR_CITY_TO_CITY from ..models import FarmData from .clients.ambr import AmbrAPIClient @@ -12,6 +12,7 @@ import ambr from ..bot.translator import Translator + from ..enums import GenshinCity class FarmDataFetcher: @@ -61,7 +62,7 @@ async def fetch( domains_ = cls._get_domains(domains) for domain in domains_: - if city and GenshinCity(domain.city.name.lower()) != city: + if city is not None and AMBR_CITY_TO_CITY[domain.city] != city: continue farm_data = FarmData(domain) reward_ids = [r.id for r in domain.rewards] diff --git a/hoyo_buddy/hoyo/transformers.py b/hoyo_buddy/hoyo/transformers.py index 061fa2e2..724bd161 100644 --- a/hoyo_buddy/hoyo/transformers.py +++ b/hoyo_buddy/hoyo/transformers.py @@ -19,8 +19,14 @@ async def transform(self, i: Interaction, value: str) -> HoyoAccount: raise AccountNotFoundError from e user: User = i.namespace.user - user = user or i.user - account = await HoyoAccount.get_or_none(id=account_id) + account = ( + await HoyoAccount.get_or_none( + id=account_id, user_id=user.id if user is not None else i.user.id + ) + if (user is None or (user is not None and i.user.id == user.id)) + else await HoyoAccount.get_or_none(id=account_id, user_id=user.id, public=True) + ) if account is None: raise AccountNotFoundError + return account diff --git a/hoyo_buddy/ui/account/geetest_handler.py b/hoyo_buddy/ui/account/geetest_handler.py index f759291b..0e249654 100644 --- a/hoyo_buddy/ui/account/geetest_handler.py +++ b/hoyo_buddy/ui/account/geetest_handler.py @@ -113,11 +113,8 @@ async def handle_geetest_notifs(self, notif: asyncpg_listen.NotificationOrTimeou embed = DefaultEmbed( self._view.locale, self._view.translator, - title=LocaleStr("Verification timeout", key="geeetest_verification_timeout"), - description=LocaleStr( - "The verification has timed out. Please use the comand to try again.", - key="accounts.geeetest_verification_timeout_description", - ), + title=LocaleStr(key="geeetest_verification_timeout"), + description=LocaleStr(key="accounts.geeetest_verification_timeout_description"), ) await self._interaction.edit_original_response(embed=embed, view=None) self._bot.login_notif_tasks.pop(self._user_id).cancel() diff --git a/hoyo_buddy/ui/account/items/acc_settings.py b/hoyo_buddy/ui/account/items/acc_settings.py index eed0f259..06b49a58 100644 --- a/hoyo_buddy/ui/account/items/acc_settings.py +++ b/hoyo_buddy/ui/account/items/acc_settings.py @@ -17,7 +17,7 @@ class AutoRedeemToggle(ToggleButton["AccountManager"]): def __init__(self, current_toggle: bool) -> None: super().__init__( current_toggle, - LocaleStr("Auto code redemption", key="auto_redeem_toggle.label"), + LocaleStr(key="auto_redeem_toggle.label"), row=2, emoji=GIFT_OUTLINE, custom_id="auto_redeem_toggle", @@ -35,7 +35,7 @@ class AutoCheckinToggle(ToggleButton["AccountManager"]): def __init__(self, current_toggle: bool) -> None: super().__init__( current_toggle, - LocaleStr("Auto daily check-in", key="auto_checkin_button_label"), + LocaleStr(key="auto_checkin_button_label"), row=2, emoji=SMART_TOY, custom_id="auto_checkin_toggle", @@ -53,7 +53,7 @@ class AccountPublicToggle(ToggleButton["AccountManager"]): def __init__(self, current_toggle: bool) -> None: super().__init__( current_toggle, - LocaleStr("Set account as public", key="public_account_toggle.label"), + LocaleStr(key="public_account_toggle.label"), row=2, emoji=PUBLIC, custom_id="public_account_toggle", diff --git a/hoyo_buddy/ui/account/items/add_acc_btn.py b/hoyo_buddy/ui/account/items/add_acc_btn.py index c2134b7e..0a3bbda8 100644 --- a/hoyo_buddy/ui/account/items/add_acc_btn.py +++ b/hoyo_buddy/ui/account/items/add_acc_btn.py @@ -4,7 +4,7 @@ from discord import ButtonStyle -from hoyo_buddy.bot.translator import LocaleStr +from hoyo_buddy.bot.translator import EnumStr, LocaleStr from hoyo_buddy.embeds import DefaultEmbed from hoyo_buddy.emojis import ADD, HOYOLAB, MIYOUSHE from hoyo_buddy.enums import Platform @@ -26,20 +26,15 @@ def __init__(self) -> None: super().__init__( custom_id="add_miyoushe_account", emoji=MIYOUSHE, - label=LocaleStr(Platform.MIYOUSHE.value, warn_no_key=False), + label=EnumStr(Platform.MIYOUSHE), ) async def callback(self, i: Interaction) -> None: embed = DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr( - "Select a Method to add Your Accounts", key="add_hoyolab_acc.embed.title" - ), - description=LocaleStr( - "1. With modded Miyoushe app: Available only for Android devices", - key="add_miyoushe_acc.embed.description", - ), + title=LocaleStr(key="add_hoyolab_acc.embed.title"), + description=LocaleStr(key="add_miyoushe_acc.embed.description"), ) go_back_button = GoBackButton(self.view.children, self.view.get_embeds(i.message)) self.view.clear_items() @@ -59,24 +54,15 @@ def __init__(self) -> None: super().__init__( custom_id="add_hoyolab_account", emoji=HOYOLAB, - label=LocaleStr(Platform.HOYOLAB.value, warn_no_key=False), + label=EnumStr(Platform.HOYOLAB), ) async def callback(self, i: Interaction) -> None: embed = DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr( - "Select a Method to add Your Accounts", key="add_hoyolab_acc.embed.title" - ), - description=LocaleStr( - ( - "1. With email and password: Most recommended, it's the easiest\n" - "2. With DevTools: Only work on desktop, a safer option if you have security concerns with the first one\n" - "3. With JavaScript: Outdated method, won't work for most accounts. Works on Google Chrome or Microsoft Edge on both desktop and mobile\n\n" - ), - key="add_hoyolab_acc.embed.description", - ), + title=LocaleStr(key="add_hoyolab_acc.embed.title"), + description=LocaleStr(key="add_hoyolab_acc.embed.description"), ) go_back_button = GoBackButton(self.view.children, self.view.get_embeds(i.message)) self.view.clear_items() @@ -94,7 +80,7 @@ def __init__(self) -> None: super().__init__( custom_id="add_account", emoji=ADD, - label=LocaleStr("Add accounts", key="add_account_button_label"), + label=LocaleStr(key="add_account_button_label"), style=ButtonStyle.primary, ) @@ -102,14 +88,8 @@ async def callback(self, i: Interaction) -> None: embed = DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr("Select Your Account's Platform", key="adding_accounts_title"), - description=LocaleStr( - ( - "Welcome to Hoyo Buddy! Enjoy various features by spending less than 1 minute to add your accounts.\n\n" - "Regarding account security, please read the [Wiki page](https://github.com/seriaati/hoyo-buddy/wiki/Account-Security), for how we use and collect your data, please read the [Privacy Policy](https://github.com/seriaati/hoyo-buddy/blob/main/PRIVACY.md)" - ), - key="adding_accounts_description", - ), + title=LocaleStr(key="adding_accounts_title"), + description=LocaleStr(key="adding_accounts_description"), ) go_back_button = GoBackButton(self.view.children, self.view.get_embeds(i.message)) self.view.clear_items() diff --git a/hoyo_buddy/ui/account/items/add_acc_select.py b/hoyo_buddy/ui/account/items/add_acc_select.py index f0a2fdda..402bbf11 100644 --- a/hoyo_buddy/ui/account/items/add_acc_select.py +++ b/hoyo_buddy/ui/account/items/add_acc_select.py @@ -6,7 +6,7 @@ from genshin import Game as GenshinGame from tortoise.exceptions import IntegrityError -from hoyo_buddy.bot.translator import LocaleStr +from hoyo_buddy.bot.translator import LevelStr, LocaleStr from hoyo_buddy.constants import GPY_GAME_TO_HB_GAME from hoyo_buddy.db.models import AccountNotifSettings, HoyoAccount from hoyo_buddy.emojis import get_game_emoji @@ -49,7 +49,6 @@ def __init__( options=options, max_values=len(options), placeholder=LocaleStr( - "Select the accounts you want to add...", key="select_accounts_to_add_placeholder", ), ) @@ -57,14 +56,7 @@ def __init__( def get_account_options(self) -> Generator[SelectOption, None, None]: for account in self.accounts: if isinstance(account.game, GenshinGame): - level_str = self.translator.translate( - LocaleStr( - "Lv.{level}", - key="level_str", - level=account.level, - ), - self.locale, - ) + level_str = self.translator.translate(LevelStr(account.level), self.locale) yield SelectOption( label=f"[{account.uid}] {account.nickname}", diff --git a/hoyo_buddy/ui/account/items/del_acc_btn.py b/hoyo_buddy/ui/account/items/del_acc_btn.py index ee4b8ac3..31ac764d 100644 --- a/hoyo_buddy/ui/account/items/del_acc_btn.py +++ b/hoyo_buddy/ui/account/items/del_acc_btn.py @@ -21,7 +21,7 @@ class DeleteAccountContinue(Button["AccountManager"]): def __init__(self) -> None: super().__init__( custom_id="delete_account_continue", - label=LocaleStr("Continue", key="continue_button_label"), + label=LocaleStr(key="continue_button_label"), emoji=FORWARD, style=ButtonStyle.blurple, ) @@ -36,7 +36,7 @@ def __init__(self) -> None: custom_id="delete_account", style=ButtonStyle.red, emoji=DELETE, - label=LocaleStr("Delete selected account", key="delete_account_button_label"), + label=LocaleStr(key="delete_account_button_label"), row=3, ) @@ -53,12 +53,8 @@ async def callback(self, i: Interaction) -> None: embed = DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr("Account Deleted", key="account_deleted_title"), - description=LocaleStr( - "{account} has been deleted.", - key="account_deleted_description", - account=str(account), - ), + title=LocaleStr(key="account_deleted_title"), + description=LocaleStr(key="account_deleted_description", account=str(account)), ) self.view.clear_items() self.view.add_item(DeleteAccountContinue()) diff --git a/hoyo_buddy/ui/account/items/edit_nickname_btn.py b/hoyo_buddy/ui/account/items/edit_nickname_btn.py index 7020c1ae..76bb021e 100644 --- a/hoyo_buddy/ui/account/items/edit_nickname_btn.py +++ b/hoyo_buddy/ui/account/items/edit_nickname_btn.py @@ -17,15 +17,15 @@ class NicknameModal(Modal): nickname = TextInput( - label=LocaleStr("Nickname", key="nickname_modal_label"), - placeholder=LocaleStr("Main account, Asia account...", key="nickname_modal_placeholder"), + label=LocaleStr(key="nickname_modal_label"), + placeholder=LocaleStr(key="nickname_modal_placeholder"), required=False, style=TextStyle.short, max_length=32, ) def __init__(self, current_nickname: str | None = None) -> None: - super().__init__(title=LocaleStr("Edit Nickname", key="edit_nickname_modal_title")) + super().__init__(title=LocaleStr(key="edit_nickname_modal_title")) self.nickname.default = current_nickname @@ -34,7 +34,7 @@ def __init__(self) -> None: super().__init__( custom_id="edit_nickname", emoji=EDIT, - label=LocaleStr("Edit nickname", key="edit_nickname_button_label"), + label=LocaleStr(key="edit_nickname_button_label"), ) async def callback(self, i: Interaction) -> None: diff --git a/hoyo_buddy/ui/account/items/enter_cookies_btn.py b/hoyo_buddy/ui/account/items/enter_cookies_btn.py index deb31228..fbec9417 100644 --- a/hoyo_buddy/ui/account/items/enter_cookies_btn.py +++ b/hoyo_buddy/ui/account/items/enter_cookies_btn.py @@ -20,7 +20,7 @@ class CookiesModal(Modal): cookies_input = TextInput( label="Cookies", - placeholder=LocaleStr("Paste your cookies here...", key="cookies_modal_placeholder"), + placeholder=LocaleStr(key="cookies_modal_placeholder"), style=TextStyle.paragraph, ) @@ -44,7 +44,7 @@ def cookies(self) -> str: class EnterCookiesButton(Button["AccountManager"]): def __init__(self, *, platform: Platform, dev_tools: bool = False) -> None: super().__init__( - label=LocaleStr("Enter cookies", key="cookies_button_label"), + label=LocaleStr(key="cookies_button_label"), style=ButtonStyle.blurple, emoji=COOKIE, ) @@ -53,8 +53,8 @@ def __init__(self, *, platform: Platform, dev_tools: bool = False) -> None: def _get_cookies_modal(self) -> DevToolCookiesModal | CookiesModal: if self._is_dev_tools: - return DevToolCookiesModal(title=LocaleStr("Enter Cookies", key="cookies_button_label")) - return CookiesModal(title=LocaleStr("Enter Cookies", key="cookies_button_label")) + return DevToolCookiesModal(title=LocaleStr(key="cookies_button_label")) + return CookiesModal(title=LocaleStr(key="cookies_button_label")) async def callback(self, i: Interaction) -> None: modal = self._get_cookies_modal() diff --git a/hoyo_buddy/ui/account/items/enter_email_pswd.py b/hoyo_buddy/ui/account/items/enter_email_pswd.py index f997b257..be571a7a 100644 --- a/hoyo_buddy/ui/account/items/enter_email_pswd.py +++ b/hoyo_buddy/ui/account/items/enter_email_pswd.py @@ -21,7 +21,7 @@ class EmailVerificationCodeModal(Modal): code = TextInput( - label=LocaleStr("Verification Code", key="email_verification_code_modal_code_input_label"), + label=LocaleStr(key="email_verification_code_modal_code_input_label"), placeholder="123456", min_length=6, max_length=6, @@ -33,7 +33,7 @@ def __init__( self, email: str, password: str, action_ticket: genshin.models.ActionTicket ) -> None: super().__init__( - label=LocaleStr("Enter verification code", key="email-verification-code.button.label"), + label=LocaleStr(key="email-verification-code.button.label"), style=ButtonStyle.blurple, emoji=PASSWORD, ) @@ -44,7 +44,7 @@ def __init__( async def callback(self, i: Interaction) -> Any: modal = EmailVerificationCodeModal( - title=LocaleStr("Enter Verification Code", key="email-verification-code.button.label") + title=LocaleStr(key="email-verification-code.button.label") ) modal.translate(self.view.locale, i.client.translator) await i.response.send_modal(modal) @@ -68,11 +68,11 @@ async def callback(self, i: Interaction) -> Any: class EmailPasswordModal(Modal): email = TextInput( - label=LocaleStr("email or username", key="email_password_modal_email_input_label"), + label=LocaleStr(key="email_password_modal_email_input_label"), placeholder="a@gmail.com", ) password = TextInput( - label=LocaleStr("password", key="email_password_modal_password_input_label"), + label=LocaleStr(key="email_password_modal_password_input_label"), placeholder="12345678", ) @@ -80,9 +80,7 @@ class EmailPasswordModal(Modal): class EnterEmailPassword(Button["AccountManager"]): def __init__(self, platform: Platform) -> None: super().__init__( - label=LocaleStr( - "Enter email/username and password", key="enter_email_password_button_label" - ), + label=LocaleStr(key="enter_email_password_button_label"), emoji=PASSWORD, style=ButtonStyle.blurple, ) @@ -90,11 +88,7 @@ def __init__(self, platform: Platform) -> None: self._platform = platform async def callback(self, i: Interaction) -> Any: - modal = EmailPasswordModal( - title=LocaleStr( - "Enter Email/Username and Password", key="enter_email_password_button_label" - ) - ) + modal = EmailPasswordModal(title=LocaleStr(key="enter_email_password_button_label")) modal.translate(self.view.locale, i.client.translator) await i.response.send_modal(modal) await modal.wait() diff --git a/hoyo_buddy/ui/account/items/enter_mobile.py b/hoyo_buddy/ui/account/items/enter_mobile.py index c34dfbdb..5b9cc584 100644 --- a/hoyo_buddy/ui/account/items/enter_mobile.py +++ b/hoyo_buddy/ui/account/items/enter_mobile.py @@ -20,14 +20,14 @@ class VerifyCodeInput(Modal): code = TextInput( - label=LocaleStr("Verification code", key="add_miyoushe_acc.verify_code"), + label=LocaleStr(key="add_miyoushe_acc.verify_code"), placeholder="123456", ) class PhoneNumberInput(Modal): mobile = TextInput( - label=LocaleStr("Phone number", key="add_miyoushe_acc.mobile_number"), + label=LocaleStr(key="add_miyoushe_acc.mobile_number"), placeholder="1234567890", ) @@ -36,20 +36,14 @@ class EnterVerificationCode(Button["AccountManager"]): def __init__(self, mobile: str) -> None: super().__init__( custom_id="enter_verification_code", - label=LocaleStr( - "Enter verification code", key="add_miyoushe_acc.enter_verification_code" - ), + label=LocaleStr(key="add_miyoushe_acc.enter_verification_code"), emoji=PASSWORD, style=ButtonStyle.green, ) self._mobile = mobile async def callback(self, i: Interaction) -> None: - modal = VerifyCodeInput( - title=LocaleStr( - "Enter Verification Code", key="add_miyoushe_acc.enter_verification_code" - ) - ) + modal = VerifyCodeInput(title=LocaleStr(key="add_miyoushe_acc.enter_verification_code")) modal.translate(self.view.locale, i.client.translator) await i.response.send_modal(modal) await modal.wait() @@ -67,15 +61,13 @@ class EnterPhoneNumber(Button["AccountManager"]): def __init__(self) -> None: super().__init__( custom_id="enter_mobile_number", - label=LocaleStr("Enter phone number", key="add_miyoushe_acc.enter_mobile_number"), + label=LocaleStr(key="add_miyoushe_acc.enter_mobile_number"), emoji=PHONE, style=ButtonStyle.blurple, ) async def callback(self, i: Interaction) -> None: - modal = PhoneNumberInput( - title=LocaleStr("Enter Phone Number", key="add_miyoushe_acc.enter_mobile_number") - ) + modal = PhoneNumberInput(title=LocaleStr(key="add_miyoushe_acc.enter_mobile_number")) modal.translate(self.view.locale, i.client.translator) await i.response.send_modal(modal) await modal.wait() diff --git a/hoyo_buddy/ui/account/items/with_dev_tools.py b/hoyo_buddy/ui/account/items/with_dev_tools.py index ec4ce074..f7e34585 100644 --- a/hoyo_buddy/ui/account/items/with_dev_tools.py +++ b/hoyo_buddy/ui/account/items/with_dev_tools.py @@ -17,30 +17,15 @@ class WithDevTools(Button["AccountManager"]): def __init__(self, platform: Platform) -> None: - super().__init__( - label=LocaleStr("With DevTools (desktop only)", key="devtools_button_label") - ) + super().__init__(label=LocaleStr(key="devtools_button_label")) self._platform = platform async def callback(self, i: Interaction) -> None: embed = DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr("Instructions", key="instructions_title"), - description=LocaleStr( - ( - "1. Login to [HoYoLAB](https://www.hoyolab.com/home) or [Miyoushe](https://www.miyoushe.com/ys/) (for CN players)\n" - "2. Open the DevTools by pressing F12 or Ctrl+Shift+I\n" - "3. Press the >> icon on the top navigation bar\n" - "4. Click on the `Application` tab\n" - "5. Click on `Cookies` on the left sidebar\n" - "6. Click on the website you're on (e.g. https://www.hoyolab.com)\n" - "7. Type `v2` in the `Filter` box\n" - "8. Click the button below\n" - "9. Copy the `Value` of each cookie and paste them in the boxes\n" - ), - key="devtools_instructions_description", - ), + title=LocaleStr(key="instructions_title"), + description=LocaleStr(key="devtools_instructions_description"), ) embed.set_image(url="https://i.imgur.com/HWMZhVe.gif") go_back_button = GoBackButton(self.view.children, self.view.get_embeds(i.message)) diff --git a/hoyo_buddy/ui/account/items/with_email_pswd.py b/hoyo_buddy/ui/account/items/with_email_pswd.py index d13bb5ae..7c9c7ce9 100644 --- a/hoyo_buddy/ui/account/items/with_email_pswd.py +++ b/hoyo_buddy/ui/account/items/with_email_pswd.py @@ -4,7 +4,6 @@ from hoyo_buddy.bot.translator import LocaleStr from hoyo_buddy.embeds import DefaultEmbed -from hoyo_buddy.emojis import INFO from ...components import Button, GoBackButton from .enter_email_pswd import EnterEmailPassword @@ -18,25 +17,15 @@ class WithEmailPassword(Button["AccountManager"]): def __init__(self, platform: Platform) -> None: - super().__init__( - label=LocaleStr("With email and password", key="email_password_button_label") - ) + super().__init__(label=LocaleStr(key="email_password_button_label")) self._platform = platform async def callback(self, i: Interaction) -> Any: embed = DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr("Instructions", key="instructions_title"), - description=LocaleStr( - f"{INFO} This method requires you to enter your private information.\n\n" - "• In exchange, your `cookie_token` can be refreshed automatically, which is used in features related to code redemption (for HoYoLAB users only).\n" - "• Your email and password are **NOT** saved in the database **AT ALL**, so it's practically impossible for them to be leaked.\n" - "• Additionally, this bot is open-sourced on [GitHub](https://github.com/seriaati/hoyo-buddy), so you can verify that yourself.\n" - "• It is ultimately your choice to decide whether to trust this bot or not.\n\n" - "Click on the button below to start.\n", - key="enter_email_password_instructions_description", - ), + title=LocaleStr(key="instructions_title"), + description=LocaleStr(key="enter_email_password_instructions_description"), ) go_back_button = GoBackButton(self.view.children, self.view.get_embeds(i.message)) self.view.clear_items() diff --git a/hoyo_buddy/ui/account/items/with_js.py b/hoyo_buddy/ui/account/items/with_js.py index 3dd2f2ac..0cb4eca9 100644 --- a/hoyo_buddy/ui/account/items/with_js.py +++ b/hoyo_buddy/ui/account/items/with_js.py @@ -4,7 +4,6 @@ from hoyo_buddy.bot.translator import LocaleStr from hoyo_buddy.embeds import DefaultEmbed -from hoyo_buddy.emojis import INFO from hoyo_buddy.enums import Platform from ...components import Button, GoBackButton @@ -18,25 +17,14 @@ class WithJavaScript(Button["AccountManager"]): def __init__(self) -> None: - super().__init__(label=LocaleStr("With JavaScript", key="javascript_button_label")) + super().__init__(label=LocaleStr(key="javascript_button_label")) async def callback(self, i: Interaction) -> None: embed = DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr("Instructions", key="instructions_title"), - description=LocaleStr( - ( - f"{INFO} Note: This method should work for all major browsers on desktop, but on mobile, it only works for **Chrome** and **Edge**.\n\n" - "1. Login to [HoYoLAB](https://www.hoyolab.com/home) or [Miyoushe](https://www.miyoushe.com/ys/) (for CN players)\n" - "2. Copy the code below\n" - "3. Click on the address bar and type `java`\n" - "4. Paste the code and press enter. Make sure there are **NO SPACES** between `java` and `script`\n" - "5. Select all and copy the text that appears\n" - "6. Click the button below and paste the text in the box\n" - ), - key="javascript_instructions_description", - ), + title=LocaleStr(key="instructions_title"), + description=LocaleStr(key="javascript_instructions_description"), ) embed.set_image(url="https://i.imgur.com/PxO0Wr6.gif") code = "script:document.write(document.cookie)" diff --git a/hoyo_buddy/ui/account/items/with_mobile.py b/hoyo_buddy/ui/account/items/with_mobile.py index f90dd37c..3683177b 100644 --- a/hoyo_buddy/ui/account/items/with_mobile.py +++ b/hoyo_buddy/ui/account/items/with_mobile.py @@ -18,22 +18,15 @@ class WithMobileNumber(Button["AccountManager"]): def __init__(self) -> None: super().__init__( custom_id="with_mobile_number", - label=LocaleStr("With phone number", key="add_miyoushe_acc.with_mobile_number"), + label=LocaleStr(key="add_miyoushe_acc.with_mobile_number"), ) async def callback(self, i: Interaction) -> None: embed = DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr("Instructions", key="instructions_title"), - description=LocaleStr( - ( - "1. Click the button below to enter your phone number\n" - "2. You will receive a verification code via SMS\n" - "3. Click the button below to enter the verification code\n" - ), - key="mobile_instructions_description", - ), + title=LocaleStr(key="instructions_title"), + description=LocaleStr(key="mobile_instructions_description"), ) go_back_button = GoBackButton(self.view.children, self.view.get_embeds(i.message)) diff --git a/hoyo_buddy/ui/account/items/with_mod_app.py b/hoyo_buddy/ui/account/items/with_mod_app.py index 3e5da5e2..c880d4a1 100644 --- a/hoyo_buddy/ui/account/items/with_mod_app.py +++ b/hoyo_buddy/ui/account/items/with_mod_app.py @@ -19,24 +19,17 @@ class WithModApp(Button["AccountManager"]): def __init__(self) -> None: - super().__init__(label=LocaleStr("With modded app", key="modded_app_button_label")) + super().__init__(label=LocaleStr(key="modded_app_button_label")) @property def _instructions_embed(self) -> list[DefaultEmbed]: embed = DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr("Instructions", key="instructions_title"), + title=LocaleStr(key="instructions_title"), description=LocaleStr( - "1. If you have Miyoushe installed on your device, uninstall it.\n" - "2. Download the modded apk by clicking the button below.\n" - "3. Install the modded app and open it.\n" - "4. Ignore any update prompts and log in with your account.\n" - "5. Click 'my account' and click on the key icon.\n" - "6. Click 'copy login details'.\n" - "7. Click the '{label}' button below and paste the copied details.", key="modded_app_login_instructions.desc", - label=LocaleStr("Enter login details", key="enter_login_details_button_label"), + label=LocaleStr(key="enter_login_details_button_label"), ), url="https://github.com/seriaati/hoyo-buddy", ) @@ -55,7 +48,7 @@ async def callback(self, i: Interaction) -> Any: self.view.add_item(go_back_button) self.view.add_item( Button( - label=LocaleStr("Download app", key="download_app_button_label"), + label=LocaleStr(key="download_app_button_label"), url="https://github.com/PaiGramTeam/GetToken/releases/latest/download/miyoushe-361-lspatched.apk", ) ) @@ -65,14 +58,14 @@ async def callback(self, i: Interaction) -> Any: class LoginDetailModal(Modal): login_detail = TextInput( - label=LocaleStr("Login details", key="login_detail_modal.input_label"), style=TextStyle.long + label=LocaleStr(key="login_detail_modal.input_label"), style=TextStyle.long ) class EnterLoginDetails(Button["AccountManager"]): def __init__(self) -> None: super().__init__( - label=LocaleStr("Enter login details", key="enter_login_details_button_label"), + label=LocaleStr(key="enter_login_details_button_label"), style=ButtonStyle.primary, ) @@ -80,9 +73,7 @@ async def callback(self, i: Interaction) -> Any: self.view.clear_items() self.view.add_item(GoBackButton(self.view.children, self.view.get_embeds(i.message))) - modal = LoginDetailModal( - title=LocaleStr("Enter login details", key="enter_login_details_button_label") - ) + modal = LoginDetailModal(title=LocaleStr(key="enter_login_details_button_label")) modal.translate(self.view.locale, self.view.translator) await i.response.send_modal(modal) await modal.wait() diff --git a/hoyo_buddy/ui/account/items/with_qrcode.py b/hoyo_buddy/ui/account/items/with_qrcode.py index 812b1a19..876d9550 100644 --- a/hoyo_buddy/ui/account/items/with_qrcode.py +++ b/hoyo_buddy/ui/account/items/with_qrcode.py @@ -23,18 +23,15 @@ class WithQRCode(Button["AccountManager"]): def __init__(self) -> None: - super().__init__(label=LocaleStr("With QR code", key="qrcode_button_label")) + super().__init__(label=LocaleStr(key="qrcode_button_label")) @property def _instructions_embed(self) -> DefaultEmbed: embed = DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr("Instructions", key="instructions_title"), - description=LocaleStr( - "Scan the QR code below with your Miyoushe app to log in.", - key="qrcode_login_instructions.desc", - ), + title=LocaleStr(key="instructions_title"), + description=LocaleStr(key="qrcode_login_instructions.desc"), ) embed.set_image(url="attachment://qrcode.webp") return embed @@ -44,11 +41,8 @@ def _scanned_embed(self) -> DefaultEmbed: return DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr("Instructions", key="instructions_title"), - description=LocaleStr( - "Successfully scanned the QR code. Please confirm the login on your device.", - key="qrcode_scanned.desc", - ), + title=LocaleStr(key="instructions_title"), + description=LocaleStr(key="qrcode_scanned.desc"), ) @property @@ -56,8 +50,8 @@ def _confirmed_embed(self) -> DefaultEmbed: return DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr("Instructions", key="instructions_title"), - description=LocaleStr("Successfully logged in", key="qrcode_confirmed.desc"), + title=LocaleStr(key="instructions_title"), + description=LocaleStr(key="qrcode_confirmed.desc"), ) @staticmethod @@ -112,10 +106,8 @@ async def callback(self, i: Interaction) -> Any: embed=DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr("QR code expired", key="qrcode_expired_title"), - description=LocaleStr( - "Please try again with a new QR code", key="qrcode_expired.desc" - ), + title=LocaleStr(key="qrcode_expired_title"), + description=LocaleStr(key="qrcode_expired.desc"), ), attachments=[], ) diff --git a/hoyo_buddy/ui/account/view.py b/hoyo_buddy/ui/account/view.py index 00ca94c8..30a92db1 100644 --- a/hoyo_buddy/ui/account/view.py +++ b/hoyo_buddy/ui/account/view.py @@ -4,7 +4,7 @@ import genshin -from ...bot.translator import LocaleStr, Translator +from ...bot.translator import EnumStr, LocaleStr, Translator from ...constants import GEETEST_SERVERS from ...db.models import HoyoAccount, User from ...embeds import DefaultEmbed @@ -55,11 +55,8 @@ def _acc_embed(self) -> DefaultEmbed: embed = DefaultEmbed( self.locale, self.translator, - title=LocaleStr("Account Manager", key="account_manager_title"), - description=LocaleStr( - "You don't have any accounts yet.", - key="account_manager_no_accounts_description", - ), + title=LocaleStr(key="account_manager_title"), + description=LocaleStr(key="account_manager_no_accounts_description"), ) return embed @@ -69,20 +66,15 @@ def _acc_embed(self) -> DefaultEmbed: title=str(account), ) embed.add_field( - name=LocaleStr("Game", key="account_game"), - value=LocaleStr(account.game.value, warn_no_key=False), + name=LocaleStr(key="account_game"), + value=EnumStr(account.game), ) if account.nickname: embed.add_field( - name=LocaleStr("Username", key="account_username"), + name=LocaleStr(key="account_username"), value=account.username, ) - embed.set_footer( - text=LocaleStr( - "Selected account will be the default one used for all commands", - key="account_manager_footer", - ) - ) + embed.set_footer(text=LocaleStr(key="account_manager_footer")) return embed def _add_items(self) -> None: @@ -177,11 +169,8 @@ async def finish_cookie_setup( embed = DefaultEmbed( self.locale, self.translator, - title=LocaleStr("🎉 Welcome to Hoyo Buddy!", key="select_account.embed.title"), - description=LocaleStr( - "Select the accounts you want to add.", - key="select_account.embed.description", - ), + title=LocaleStr(key="select_account.embed.title"), + description=LocaleStr(key="select_account.embed.description"), ) device_id = cookies.pop("x-rpc-device_id", None) @@ -233,26 +222,16 @@ async def prompt_user_to_solve_geetest( go_back_button = GoBackButton(self.children, self.get_embeds(i.message)) self.clear_items() - self.add_item( - Button( - label=LocaleStr("Complete CAPTCHA", key="complete_captcha_button_label"), url=url - ) - ) + self.add_item(Button(label=LocaleStr(key="complete_captcha_button_label"), url=url)) self.add_item(go_back_button) embed = DefaultEmbed( self.locale, self.translator, - title=LocaleStr( - "😥 Need to Solve CAPTCHA Before Sending the Verification Code", - key="email-geetest.embed.title", - ) + title=LocaleStr(key="email-geetest.embed.title") if for_code - else LocaleStr("😅 Need to solve CAPTCHA before logging in", key="geetest.embed.title"), - description=LocaleStr( - "Click on the button below to complete CAPTCHA.\n", - key="captcha.embed.description", - ), + else LocaleStr(key="geetest.embed.title"), + description=LocaleStr(key="captcha.embed.description"), ) await i.edit_original_response(embed=embed, view=self) @@ -273,17 +252,8 @@ async def prompt_user_to_enter_email_code( embed = DefaultEmbed( self.locale, self.translator, - title=LocaleStr( - "👍 Almost Done! Just Need to Verify Your Email", - key="email-verification.embed.title", - ), - description=LocaleStr( - ( - "1. Go to the inbox of the email your entered and find the verification code sent from Hoyoverse.\n" - "2. Click the button below to enter the code received.\n" - ), - key="email-verification.embed.description", - ), + title=LocaleStr(key="email-verification.embed.title"), + description=LocaleStr(key="email-verification.embed.description"), ) await i.edit_original_response(embed=embed, view=self) @@ -303,13 +273,7 @@ async def prompt_user_to_enter_mobile_otp(self, i: Interaction, mobile: str) -> embed = DefaultEmbed( self.locale, self.translator, - title=LocaleStr( - "Verification Code Sent", - key="add_miyoushe_acc.verification_code_sent", - ), - description=LocaleStr( - "Please check your phone for the verification code and click the button below to enter it", - key="add_miyoushe_acc.verification_code_sent_description", - ), + title=LocaleStr(key="add_miyoushe_acc.verification_code_sent"), + description=LocaleStr(key="add_miyoushe_acc.verification_code_sent_description"), ) await i.edit_original_response(embed=embed, view=self) diff --git a/hoyo_buddy/ui/components.py b/hoyo_buddy/ui/components.py index 458bb5fc..5d91d080 100644 --- a/hoyo_buddy/ui/components.py +++ b/hoyo_buddy/ui/components.py @@ -106,11 +106,8 @@ async def interaction_check(self, i: Interaction) -> bool: embed = ErrorEmbed( locale or i.locale, self.translator, - title=LocaleStr("Interaction Failed", key="interaction_failed_title"), - description=LocaleStr( - "This view is not initiated by you, therefore you cannot use it.", - key="interaction_failed_description", - ), + title=LocaleStr(key="interaction_failed_title"), + description=LocaleStr(key="interaction_failed_description"), ) await i.response.send_message(embed=embed, ephemeral=True) return False @@ -245,9 +242,7 @@ async def set_loading_state(self, i: Interaction, **kwargs: Any) -> None: self.disabled = True self.emoji = emojis.LOADING - self.label = self.view.translator.translate( - LocaleStr("Loading...", key="loading_text"), self.view.locale - ) + self.label = self.view.translator.translate(LocaleStr(key="loading_text"), self.view.locale) await self.view.absolute_edit(i, view=self.view, **kwargs) @@ -323,13 +318,12 @@ def _get_style(self) -> discord.ButtonStyle: def _get_label(self) -> LocaleStr: return LocaleStr( - "{toggle_label}: {toggle}", - key="toggle_button_label", + custom_str="{toggle_label}: {toggle}", toggle_label=self.toggle_label, toggle=( - LocaleStr("on", key="toggle_on_text") + LocaleStr(key="toggle_on_text") if self.current_toggle - else LocaleStr("off", key="toggle_off_text") + else LocaleStr(key="toggle_off_text") ), translate=False, ) @@ -356,7 +350,7 @@ def __init__( default: bool = False, ) -> None: super().__init__( - label=label if isinstance(label, str) else label.message, + label=label if isinstance(label, str) else label.identifier, value=value, emoji=emoji, default=default, @@ -436,7 +430,7 @@ async def set_loading_state(self, i: Interaction) -> None: self.options = [ SelectOption( label=self.view.translator.translate( - LocaleStr("Loading...", key="loading_text"), self.view.locale + LocaleStr(key="loading_text"), self.view.locale ), value="loading", default=True, @@ -478,12 +472,12 @@ def update_options_defaults(self, *, values: list[str] | None = None) -> None: NEXT_PAGE = SelectOption( - label=LocaleStr("Next page", key="next_page_option_label"), + label=LocaleStr(key="next_page_option_label"), value="next_page", emoji=emojis.FORWARD, ) PREV_PAGE = SelectOption( - label=LocaleStr("Previous page", key="prev_page_option_label"), + label=LocaleStr(key="prev_page_option_label"), value="prev_page", emoji=emojis.BACK, ) @@ -641,7 +635,6 @@ def validate_inputs(self) -> None: except ValueError as e: raise InvalidInputError( LocaleStr( - "Input `{input}` needs to be an integer", key="invalid_input.input_needs_to_be_int", input=item.label, ) @@ -649,7 +642,6 @@ def validate_inputs(self) -> None: if item.max_value is not None and value > item.max_value: raise InvalidInputError( LocaleStr( - "Input `{input}` needs to be less than or equal to {max_value}", key="invalid_input.input_out_of_range.max_value", input=item.label, max_value=item.max_value, @@ -658,7 +650,6 @@ def validate_inputs(self) -> None: if item.min_value is not None and value < item.min_value: raise InvalidInputError( LocaleStr( - "Input `{input}` needs to be greater than or equal to {min_value}", key="invalid_input.input_out_of_range.min_value", min_value=item.min_value, input=item.label, @@ -667,11 +658,7 @@ def validate_inputs(self) -> None: elif isinstance(item, TextInput) and item.is_bool: if item.value not in {"0", "1"}: raise InvalidInputError( - LocaleStr( - "Input `{input}` needs to be either `0` (for false) or `1` (for true)", - key="invalid_input.input_needs_to_be_bool", - input=item.label, - ) + LocaleStr(key="invalid_input.input_needs_to_be_bool", input=item.label) ) @property diff --git a/hoyo_buddy/ui/feedback.py b/hoyo_buddy/ui/feedback.py index 05488745..4b157281 100644 --- a/hoyo_buddy/ui/feedback.py +++ b/hoyo_buddy/ui/feedback.py @@ -24,18 +24,16 @@ def __init__( class FeedbackModal(Modal): feedback = TextInput( - label=LocaleStr("Feedback", key="feedback_modal.feedback.label"), style=TextStyle.paragraph + label=LocaleStr(key="feedback_modal.feedback.label"), style=TextStyle.paragraph ) class FeedbackButton(Button[FeedbackView]): def __init__(self) -> None: - super().__init__( - label=LocaleStr("Give feedback", key="feedback_button.label"), style=ButtonStyle.blurple - ) + super().__init__(label=LocaleStr(key="feedback_button.label"), style=ButtonStyle.blurple) async def callback(self, i: Interaction) -> None: - modal = FeedbackModal(title=LocaleStr("Give Feedback", key="feedback_button.label")) + modal = FeedbackModal(title=LocaleStr(key="feedback_button.label")) modal.translate(self.view.locale, self.view.translator) await i.response.send_modal(modal) await modal.wait() @@ -60,10 +58,7 @@ async def callback(self, i: Interaction) -> None: embed = DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr("Feedback Sent", key="feedback_button.feedback_sent.title"), - description=LocaleStr( - "🥰 Thank you very much for your feedback!", - key="feedback_button.feedback_sent.description", - ), + title=LocaleStr(key="feedback_button.feedback_sent.title"), + description=LocaleStr(key="feedback_button.feedback_sent.description"), ) await i.edit_original_response(embed=embed, view=None) diff --git a/hoyo_buddy/ui/hoyo/challenge.py b/hoyo_buddy/ui/hoyo/challenge.py index d76bfddc..f9cd619e 100644 --- a/hoyo_buddy/ui/hoyo/challenge.py +++ b/hoyo_buddy/ui/hoyo/challenge.py @@ -12,7 +12,7 @@ StarRailPureFiction, ) -from hoyo_buddy.bot.translator import LocaleStr +from hoyo_buddy.bot.translator import EnumStr, LocaleStr from hoyo_buddy.draw.main_funcs import draw_moc_card, draw_pure_fiction_card, draw_spiral_abyss_card from hoyo_buddy.embeds import DefaultEmbed from hoyo_buddy.exceptions import NoChallengeDataError @@ -175,7 +175,6 @@ def _add_buff_detail(self, embed: DefaultEmbed) -> DefaultEmbed: n1_buff = floor.node_1.buff if n1_buff is not None: team_str = LocaleStr( - "team {team}", key="challenge_view.team", team=1, ).translate(self.translator, self.locale) @@ -188,7 +187,6 @@ def _add_buff_detail(self, embed: DefaultEmbed) -> DefaultEmbed: n2_buff = floor.node_2.buff if n2_buff is not None: team_str = LocaleStr( - "team {team}", key="challenge_view.team", team=2, ).translate(self.translator, self.locale) @@ -200,7 +198,6 @@ def _add_buff_detail(self, embed: DefaultEmbed) -> DefaultEmbed: for buff in buffs: used_in = LocaleStr( - "Used in: {floors}", key="challenge_view.buff_used_in", floors=", ".join(buff_usage[buff]), ).translate(self.translator, self.locale) @@ -253,15 +250,15 @@ async def start(self, i: Interaction) -> None: class PhaseSelect(Select[ChallengeView]): def __init__(self, previous: bool) -> None: super().__init__( - placeholder=LocaleStr("Select a phase", key="abyss.phase_select.placeholder"), + placeholder=LocaleStr(key="abyss.phase_select.placeholder"), options=[ SelectOption( - label=LocaleStr("Current phase", key="abyss.current"), + label=LocaleStr(key="abyss.current"), value="current", default=not previous, ), SelectOption( - label=LocaleStr("Previous phase", key="abyss.previous"), + label=LocaleStr(key="abyss.previous"), value="previous", default=previous, ), @@ -280,14 +277,8 @@ async def callback(self, i: Interaction) -> None: class ChallengeTypeSelect(Select[ChallengeView]): def __init__(self, types: list[ChallengeType]) -> None: super().__init__( - placeholder=LocaleStr("Select a game mode", key="challenge_type_select.placeholder"), - options=[ - SelectOption( - label=LocaleStr(type_.value, warn_no_key=False), - value=type_.value, - ) - for type_ in types - ], + placeholder=LocaleStr(key="challenge_type_select.placeholder"), + options=[SelectOption(label=EnumStr(type_), value=type_.value) for type_ in types], ) async def callback(self, i: Interaction) -> None: diff --git a/hoyo_buddy/ui/hoyo/characters.py b/hoyo_buddy/ui/hoyo/characters.py index 58b3e326..b9b36af2 100644 --- a/hoyo_buddy/ui/hoyo/characters.py +++ b/hoyo_buddy/ui/hoyo/characters.py @@ -8,7 +8,7 @@ from genshin.models import Character as GICharacter from genshin.models import StarRailDetailCharacter as HSRCharacter -from hoyo_buddy.bot.translator import LocaleStr +from hoyo_buddy.bot.translator import EnumStr, LocaleStr from hoyo_buddy.draw.main_funcs import draw_gi_characters_card, draw_hsr_characters_card from hoyo_buddy.enums import Game, GenshinElement, HSRElement, HSRPath from hoyo_buddy.hoyo.clients.gpy import GenshinClient @@ -277,7 +277,7 @@ def _get_embed(self, char_num: int) -> DefaultEmbed: embed = DefaultEmbed( self.locale, self.translator, - title=LocaleStr("Character Overview", key="characters.embed.title"), + title=LocaleStr(key="characters.embed.title"), ) if self._filter in {GIFilter.MAX_FRIENDSHIP, GIFilter.NOT_MAX_FRIENDSHIP}: @@ -293,34 +293,22 @@ def _get_embed(self, char_num: int) -> DefaultEmbed: if self._filter is GIFilter.MAX_FRIENDSHIP: embed.add_field( name=LocaleStr( - "Max Friendship {element} Characters", key="characters.embed.element_max_friendship", - element=[ - LocaleStr(element.value.title(), warn_no_key=False) - for element in self._element_filters - ], + element=[EnumStr(element) for element in self._element_filters], ) if self._element_filters - else LocaleStr( - "Max Friendship Characters", key="characters.embed.max_friendship" - ), + else LocaleStr(key="characters.embed.max_friendship"), value=f"{char_num}/{total_chars}", inline=False, ) else: embed.add_field( name=LocaleStr( - "Not Max Friendship {element} Characters", key="characters.embed.element_not_max_friendship", - element=[ - LocaleStr(element.value.title(), warn_no_key=False) - for element in self._element_filters - ], + element=[EnumStr(element) for element in self._element_filters], ) if self._element_filters - else LocaleStr( - "Not Max Friendship Characters", key="characters.embed.not_max_friendship" - ), + else LocaleStr(key="characters.embed.not_max_friendship"), value=f"{char_num}/{total_chars}", inline=False, ) @@ -331,12 +319,8 @@ def _get_embed(self, char_num: int) -> DefaultEmbed: ) embed.add_field( name=LocaleStr( - "{element} Characters", key="characters.embed.element_filters", - element=[ - LocaleStr(element.value.title(), warn_no_key=False) - for element in self._element_filters - ], + element=[EnumStr(element) for element in self._element_filters], ), value=f"{char_num}/{total_chars}", inline=False, @@ -346,12 +330,8 @@ def _get_embed(self, char_num: int) -> DefaultEmbed: total_chars = sum(self._path_char_counts[path.value] for path in self._path_filters) embed.add_field( name=LocaleStr( - "{path} Characters", key="characters.embed.path_filters", - path=[ - LocaleStr(path.value.title().replace("_", " "), warn_no_key=False) - for path in self._path_filters - ], + path=[EnumStr(path) for path in self._path_filters], ), value=f"{char_num}/{total_chars}", inline=False, @@ -360,28 +340,15 @@ def _get_embed(self, char_num: int) -> DefaultEmbed: if self._filter is GIFilter.NONE and not self._element_filters and not self._path_filters: total_chars = sum(self._element_char_counts.values()) + 1 # Traveler/Trailblazer embed.add_field( - name=LocaleStr("Owned Characters", key="characters.embed.owned_characters"), + name=LocaleStr(key="characters.embed.owned_characters"), value=f"{char_num}/{total_chars}", inline=False, ) if self._game is Game.GENSHIN: - embed.set_footer( - text=LocaleStr( - "Level order: Normal ATK/Skill/Burst", - key="characters.gi.embed.footer", - ) - ) + embed.set_footer(text=LocaleStr(key="characters.gi.embed.footer")) elif self._game is Game.STARRAIL: - embed.set_footer( - text=LocaleStr( - ( - "Level order: Basic ATK/Skill/Ultimate/Talent\n" - "Use /profile to view details of a character" - ), - key="characters.hsr.embed.footer", - ) - ) + embed.set_footer(text=LocaleStr(key="characters.hsr.embed.footer")) else: raise NotImplementedError @@ -408,18 +375,10 @@ async def start(self, i: Interaction, *, show_first_time_msg: bool = False) -> N embed = DefaultEmbed( self.locale, self.translator, - description=LocaleStr( - ( - "If this is your first time using this command, this may take a while.\n" - "This is because the command needs to fetch data from many sources.\n" - "It should be faster next time you use this command.\n" - "Please be patient and wait for the resources to be fetched." - ), - key="characters.first_time.embed.description", - ), + description=LocaleStr(key="characters.first_time.embed.description"), ).set_author( icon_url=LOADING_ICON, - name=LocaleStr("Fetching resources...", key="characters.first_time.title"), + name=LocaleStr(key="characters.first_time.title"), ) await i.edit_original_response(embed=embed) @@ -464,21 +423,21 @@ class FilterSelector(Select[CharactersView]): def __init__(self) -> None: options = [ SelectOption( - label=LocaleStr("None", key="characters.filter.none"), + label=LocaleStr(key="characters.filter.none"), value=GIFilter.NONE, default=True, ), SelectOption( - label=LocaleStr("Max friendship", key="characters.filter.max_friendship"), + label=LocaleStr(key="characters.filter.max_friendship"), value=GIFilter.MAX_FRIENDSHIP, ), SelectOption( - label=LocaleStr("Not max friendship", key="characters.filter.not_max_friendship"), + label=LocaleStr(key="characters.filter.not_max_friendship"), value=GIFilter.NOT_MAX_FRIENDSHIP, ), ] super().__init__( - placeholder=LocaleStr("Select a filter...", key="characters.filter.placeholder"), + placeholder=LocaleStr(key="characters.filter.placeholder"), options=options, ) @@ -500,7 +459,7 @@ class ElementFilterSelector(Select[CharactersView]): def __init__(self, elements: Iterable[GenshinElement | HSRElement]) -> None: options = [ SelectOption( - label=LocaleStr(element.value.title(), warn_no_key=False), + label=EnumStr(element), value=element.value, emoji=get_gi_element_emoji(element) if isinstance(element, GenshinElement) @@ -509,9 +468,7 @@ def __init__(self, elements: Iterable[GenshinElement | HSRElement]) -> None: for element in elements ] super().__init__( - placeholder=LocaleStr( - "Select element filters...", key="characters.filter.element.placeholder" - ), + placeholder=LocaleStr(key="characters.filter.element.placeholder"), options=options, min_values=0, max_values=len(options), @@ -540,17 +497,11 @@ async def callback(self, i: Interaction) -> None: class PathFilterSelector(Select[CharactersView]): def __init__(self) -> None: options = [ - SelectOption( - label=LocaleStr(path.value.title().replace("_", " "), warn_no_key=False), - value=path.value, - emoji=get_hsr_path_emoji(path), - ) + SelectOption(label=EnumStr(path), value=path.value, emoji=get_hsr_path_emoji(path)) for path in HSRPath ] super().__init__( - placeholder=LocaleStr( - "Select path filters...", key="characters.filter.path.placeholder" - ), + placeholder=LocaleStr(key="characters.filter.path.placeholder"), options=options, min_values=0, max_values=len(options), @@ -574,14 +525,14 @@ class GISorterSelector(Select[CharactersView]): def __init__(self, current: GISorter | HSRSorter) -> None: options = [ SelectOption( - label=LocaleStr(sorter.name.title(), key=f"characters.sorter.{sorter.value}"), + label=LocaleStr(key=f"characters.sorter.{sorter.value}"), value=sorter.value, default=sorter == current, ) for sorter in GISorter ] super().__init__( - placeholder=LocaleStr("Select a sorter...", key="characters.sorter.placeholder"), + placeholder=LocaleStr(key="characters.sorter.placeholder"), options=options, ) @@ -603,15 +554,14 @@ class HSRSorterSelector(Select[CharactersView]): def __init__(self, current: GISorter | HSRSorter) -> None: options = [ SelectOption( - label=LocaleStr(sorter.name.title(), key=f"characters.sorter.{sorter.value}"), + label=LocaleStr(key=f"characters.sorter.{sorter.value}"), value=sorter.value, default=sorter == current, ) for sorter in HSRSorter ] super().__init__( - placeholder=LocaleStr("Select a sorter...", key="characters.sorter.placeholder"), - options=options, + placeholder=LocaleStr(key="characters.sorter.placeholder"), options=options ) async def callback(self, i: Interaction) -> None: @@ -631,7 +581,7 @@ async def callback(self, i: Interaction) -> None: class UpdateTalentData(Button[CharactersView]): def __init__(self) -> None: super().__init__( - label=LocaleStr("Update talent level data", key="characters.update_talent_data"), + label=LocaleStr(key="characters.update_talent_data"), style=ButtonStyle.green, row=3, ) @@ -646,15 +596,10 @@ async def callback(self, i: Interaction) -> None: embed = DefaultEmbed( self.view.locale, self.view.translator, - description=LocaleStr( - "This may take a while, if you own a lot of characters, this can take even longer. Please be patient.", - key="characters.update_talent_data.embed.description", - ), + description=LocaleStr(key="characters.update_talent_data.embed.description"), ).set_author( icon_url=LOADING_ICON, - name=LocaleStr( - "Updating talent level data...", key="characters.update_talent_data.title" - ), + name=LocaleStr(key="characters.update_talent_data.title"), ) self.view.clear_items() await i.response.edit_message(embed=embed, view=self.view, attachments=[]) @@ -668,7 +613,7 @@ class ShowOwnedOnly(ToggleButton[CharactersView]): def __init__(self) -> None: super().__init__( current_toggle=True, - toggle_label=LocaleStr("Show owned characters only", key="characters.show_owned_only"), + toggle_label=LocaleStr(key="characters.show_owned_only"), row=4, ) diff --git a/hoyo_buddy/ui/hoyo/checkin.py b/hoyo_buddy/ui/hoyo/checkin.py index f261fcc7..6c71e9e8 100644 --- a/hoyo_buddy/ui/hoyo/checkin.py +++ b/hoyo_buddy/ui/hoyo/checkin.py @@ -58,7 +58,7 @@ def add_items(self) -> None: self.add_item( Button( url=CHECK_IN_URLS[self.client.game], - label=LocaleStr("Make up for check-in", key="make_up_for_checkin_button_label"), + label=LocaleStr(key="make_up_for_checkin_button_label"), ) ) self.add_item(AutoCheckInToggle(self.account.daily_checkin)) @@ -124,9 +124,8 @@ async def get_embed_and_image( embed = DefaultEmbed( self.locale, self.translator, - title=LocaleStr("Daily Check-In", key="daily_checkin_embed_title"), + title=LocaleStr(key="daily_checkin_embed_title"), description=LocaleStr( - "Checked in {day} day(s) this month\n" "Missed check-in for {missed} day(s)\n", key="daily_checkin_embed_description", day=info.claimed_rewards, missed=info.missed_rewards, @@ -152,7 +151,7 @@ class CheckInButton(Button[CheckInUI]): def __init__(self) -> None: super().__init__( style=discord.ButtonStyle.primary, - label=LocaleStr("Check-in", key="checkin_button_label"), + label=LocaleStr(key="checkin_button_label"), emoji=emojis.FREE_CANCELLATION, ) @@ -179,7 +178,7 @@ class AutoCheckInToggle(ToggleButton[CheckInUI]): def __init__(self, current_toggle: bool) -> None: super().__init__( current_toggle, - LocaleStr("Auto daily check-in", key="auto_checkin_button_label"), + LocaleStr(key="auto_checkin_button_label"), emoji=emojis.SMART_TOY, ) @@ -192,7 +191,7 @@ async def callback(self, i: Interaction) -> Any: class NotificationSettingsButton(Button[CheckInUI]): def __init__(self) -> None: super().__init__( - label=LocaleStr("Notification settings", key="notification_settings_button_label"), + label=LocaleStr(key="notification_settings_button_label"), emoji=emojis.SETTINGS, row=1, ) @@ -219,7 +218,7 @@ class NotifyOnFailureToggle(ToggleButton[CheckInUI]): def __init__(self, current_toggle: bool) -> None: super().__init__( current_toggle, - LocaleStr("Notify on check-in failure", key="notify_on_failure_button_label"), + LocaleStr(key="notify_on_failure_button_label"), ) async def callback(self, i: Interaction) -> Any: @@ -233,7 +232,7 @@ class NotifyOnSuccessToggle(ToggleButton[CheckInUI]): def __init__(self, current_toggle: bool) -> None: super().__init__( current_toggle, - LocaleStr("Notify on check-in success", key="notify_on_success_button_label"), + LocaleStr(key="notify_on_success_button_label"), ) async def callback(self, i: Interaction) -> Any: diff --git a/hoyo_buddy/ui/hoyo/farm.py b/hoyo_buddy/ui/hoyo/farm.py index 9546a98b..8f67c33d 100644 --- a/hoyo_buddy/ui/hoyo/farm.py +++ b/hoyo_buddy/ui/hoyo/farm.py @@ -5,7 +5,7 @@ from discord import ButtonStyle, Locale, Member, User -from ...bot.translator import LocaleStr, Translator +from ...bot.translator import EnumStr, LocaleStr, Translator, WeekdayStr from ...constants import UID_TZ_OFFSET, WEEKDAYS from ...draw.main_funcs import draw_farm_card from ...embeds import DefaultEmbed @@ -60,8 +60,8 @@ async def start(self, i: Interaction) -> None: embed = DefaultEmbed( self.locale, self.translator, - title=LocaleStr("Every Domain is Available on Sunday", key="farm_view.sundays"), - description=LocaleStr("🌾 Happy farming!", key="farm_view.happy_farming"), + title=LocaleStr(key="farm_view.sundays"), + description=LocaleStr(key="farm_view.happy_farming"), ) await i.edit_original_response(embed=embed, view=self, attachments=[]) self.message = await i.original_response() @@ -88,14 +88,12 @@ async def start(self, i: Interaction) -> None: class WeekdaySelect(Select[FarmView]): def __init__(self, current: int) -> None: super().__init__( - placeholder=LocaleStr("Select a weekday", key="farm_view.weekday_select.placeholder"), + placeholder=LocaleStr(key="farm_view.weekday_select.placeholder"), options=[ SelectOption( - label=LocaleStr(label, warn_no_key=False), - value=str(value), - default=value == current, + label=WeekdayStr(weekday), value=str(weekday), default=weekday == current ) - for value, label in WEEKDAYS.items() + for weekday in WEEKDAYS ], row=0, ) @@ -109,7 +107,7 @@ async def callback(self, i: Interaction) -> None: class ReminderButton(Button[FarmView]): def __init__(self) -> None: super().__init__( - label=LocaleStr("Set reminders", key="farm_view.set_reminder"), + label=LocaleStr(key="farm_view.set_reminder"), style=ButtonStyle.green, emoji=BELL_OUTLINE, row=2, @@ -119,10 +117,7 @@ async def callback(self, i: Interaction) -> None: embed = DefaultEmbed( self.view.locale, self.view.translator, - description=LocaleStr( - "To set reminders, use the command", - key="farm_view.set_reminder.embed.description", - ), + description=LocaleStr(key="farm_view.set_reminder.embed.description"), ) await i.response.send_message(embed=embed, ephemeral=True) @@ -130,7 +125,7 @@ async def callback(self, i: Interaction) -> None: class CityButton(Button[FarmView]): def __init__(self, city: GenshinCity, current: GenshinCity) -> None: super().__init__( - label=LocaleStr(city.value.title(), warn_no_key=False), + label=EnumStr(city), style=ButtonStyle.blurple if city == current else ButtonStyle.secondary, emoji=GENSHIN_CITY_EMOJIS[city], custom_id=f"city_{city.value.lower()}_btn", diff --git a/hoyo_buddy/ui/hoyo/farm_notify.py b/hoyo_buddy/ui/hoyo/farm_notify.py index aa5c683f..082e925c 100644 --- a/hoyo_buddy/ui/hoyo/farm_notify.py +++ b/hoyo_buddy/ui/hoyo/farm_notify.py @@ -46,15 +46,11 @@ def __init__( embed=DefaultEmbed( locale, translator, - title=LocaleStr("Farm Reminder List", key="farm_notify.title"), - description=LocaleStr( - "You will be reminded when the materials of characters/weapons in this list are farmable.", - key="farm_notify.description", - ), + title=LocaleStr(key="farm_notify.title"), + description=LocaleStr(key="farm_notify.description"), ) .set_footer( text=LocaleStr( - "Page {current_page}/{total_pages}", key="page_footer", current_page=i + 1, total_pages=len(self._split_item_ids), @@ -117,13 +113,8 @@ async def start(self, i: Interaction) -> None: embed = DefaultEmbed( self.locale, self.translator, - title=LocaleStr( - "You Have no Items in Your Farm Reminder List", key="farm_notify.empty" - ), - description=LocaleStr( - "Add items to your farm reminder list by using the command", - key="farm_notify.empty_description", - ), + title=LocaleStr(key="farm_notify.empty"), + description=LocaleStr(key="farm_notify.empty_description"), ) embed.add_acc_info(self._notify.account) return await i.response.send_message(embed=embed) @@ -136,7 +127,7 @@ async def start(self, i: Interaction) -> None: class AddItemButton(Button[FarmNotifyView]): def __init__(self) -> None: super().__init__( - label=LocaleStr("Add item", key="farm_notify.add_item"), + label=LocaleStr(key="farm_notify.add_item"), style=ButtonStyle.blurple, emoji=ADD, row=1, @@ -146,10 +137,7 @@ async def callback(self, i: Interaction) -> None: embed = DefaultEmbed( self.view.locale, self.view.translator, - description=LocaleStr( - "To add items, use the command", - key="farm_notify.add_item.embed.description", - ), + description=LocaleStr(key="farm_notify.add_item.embed.description"), ) await i.response.send_message(embed=embed, ephemeral=True) @@ -157,7 +145,7 @@ async def callback(self, i: Interaction) -> None: class RemoveItemButton(Button[FarmNotifyView]): def __init__(self) -> None: super().__init__( - label=LocaleStr("Remove item", key="farm_notify.remove_item"), + label=LocaleStr(key="farm_notify.remove_item"), style=ButtonStyle.red, emoji=DELETE, row=1, @@ -167,17 +155,14 @@ async def callback(self, i: Interaction) -> None: embed = DefaultEmbed( self.view.locale, self.view.translator, - description=LocaleStr( - "To remove items, use the command", - key="farm_notify.remove_item.embed.description", - ), + description=LocaleStr(key="farm_notify.remove_item.embed.description"), ) await i.response.send_message(embed=embed, ephemeral=True) class NotifyToggle(ToggleButton[FarmNotifyView]): def __init__(self, current_toggle: bool) -> None: - super().__init__(current_toggle, LocaleStr("Reminder", key="reminder_toggle"), row=1) + super().__init__(current_toggle, LocaleStr(key="reminder_toggle"), row=1) async def callback(self, i: Interaction) -> None: await super().callback(i, edit=True) diff --git a/hoyo_buddy/ui/hoyo/genshin/abyss_enemy.py b/hoyo_buddy/ui/hoyo/genshin/abyss_enemy.py index a4aa7fea..f7ad06ea 100644 --- a/hoyo_buddy/ui/hoyo/genshin/abyss_enemy.py +++ b/hoyo_buddy/ui/hoyo/genshin/abyss_enemy.py @@ -162,9 +162,7 @@ def __init__(self, floor_index: int) -> None: super().__init__( options=[ SelectOption( - label=LocaleStr( - "Floor {value}", key="floor_select_label", value=str(index + 1) - ), + label=LocaleStr(key="floor_select_label", value=str(index + 1)), value=str(index), default=index == floor_index, ) @@ -184,9 +182,7 @@ async def callback(self, i: Interaction) -> None: class ChamberButton(Button[AbyssEnemyView]): def __init__(self, chamber_index: int) -> None: super().__init__( - label=LocaleStr( - "Chamber {value}", key="chamber_button_label", value=str(chamber_index + 1) - ), + label=LocaleStr(key="chamber_button_label", value=str(chamber_index + 1)), custom_id=f"chamber_{chamber_index}_btn", row=2, ) @@ -202,7 +198,7 @@ async def callback(self, i: Interaction) -> None: class WaveButton(Button[AbyssEnemyView]): def __init__(self, wave_index: int) -> None: super().__init__( - label=LocaleStr("Wave {value}", key="wave_button_label", value=str(wave_index + 1)), + label=LocaleStr(key="wave_button_label", value=str(wave_index + 1)), custom_id=f"wave_{wave_index}_btn", row=3, ) diff --git a/hoyo_buddy/ui/hoyo/genshin/search/book.py b/hoyo_buddy/ui/hoyo/genshin/search/book.py index 03196b83..7f492d31 100644 --- a/hoyo_buddy/ui/hoyo/genshin/search/book.py +++ b/hoyo_buddy/ui/hoyo/genshin/search/book.py @@ -61,7 +61,7 @@ async def start(self, i: Interaction) -> None: class VolumeSelector(Select["BookVolumeUI"]): def __init__(self, volumes: list[BookVolume], selected_volume: BookVolume) -> None: super().__init__( - placeholder=LocaleStr("Select a volume to read", key="volume_selector_placeholder"), + placeholder=LocaleStr(key="volume_selector_placeholder"), options=[ SelectOption( label=shorten(volume.name, 100), diff --git a/hoyo_buddy/ui/hoyo/genshin/search/character.py b/hoyo_buddy/ui/hoyo/genshin/search/character.py index a0ce18ff..cafec16b 100644 --- a/hoyo_buddy/ui/hoyo/genshin/search/character.py +++ b/hoyo_buddy/ui/hoyo/genshin/search/character.py @@ -139,19 +139,13 @@ async def update(self, i: Interaction) -> None: case 0: embed = await self.fetch_character_embed() self.add_item( - EnterCharacterLevel( - label=LocaleStr( - "Change character level", key="change_character_level_label" - ) - ) + EnterCharacterLevel(label=LocaleStr(key="change_character_level_label")) ) case 1: embed, upgradeable, talents = await self.fetch_talent_embed() if upgradeable: self.add_item( - EnterTalentLevel( - label=LocaleStr("Change talent level", key="change_talent_level_label") - ) + EnterTalentLevel(label=LocaleStr(key="change_talent_level_label")) ) self.add_item( ItemSelector( @@ -212,11 +206,7 @@ async def update(self, i: Interaction) -> None: ) case 5: embed, skills = await self.fetch_hakushin_skill_embed() - self.add_item( - EnterTalentLevel( - label=LocaleStr("Change skill level", key="change_skill_level_label") - ) - ) + self.add_item(EnterTalentLevel(label=LocaleStr(key="change_skill_level_label"))) self.add_item( ItemSelector( [ @@ -263,11 +253,7 @@ async def update(self, i: Interaction) -> None: case 8: embed = await self.fetch_hakushin_character_embed() self.add_item( - EnterCharacterLevel( - label=LocaleStr( - "Change character level", key="change_character_level_label" - ) - ) + EnterCharacterLevel(label=LocaleStr(key="change_character_level_label")) ) case _: msg = f"Invalid page index: {self.selected_page}" @@ -279,7 +265,7 @@ async def update(self, i: Interaction) -> None: class TalentLevelModal(Modal): level = TextInput( - label=LocaleStr("Level", key="level_label"), + label=LocaleStr(key="level_label"), placeholder="10", is_digit=True, min_value=1, @@ -292,9 +278,7 @@ def __init__(self, label: LocaleStr) -> None: super().__init__(label=label, style=ButtonStyle.blurple) async def callback(self, i: Interaction) -> Any: - modal = TalentLevelModal( - title=LocaleStr("Enter Talent Level", key="talent_level.modal.title") - ) + modal = TalentLevelModal(title=LocaleStr(key="talent_level.modal.title")) modal.translate(self.view.locale, self.view.translator) await i.response.send_modal(modal) await modal.wait() @@ -307,7 +291,7 @@ async def callback(self, i: Interaction) -> Any: class CharacterLevelModal(Modal): level = TextInput( - label=LocaleStr("Level", key="level_label"), + label=LocaleStr(key="level_label"), placeholder="90", is_digit=True, min_value=1, @@ -320,9 +304,7 @@ def __init__(self, label: LocaleStr) -> None: super().__init__(label=label, style=ButtonStyle.blurple) async def callback(self, i: Interaction) -> Any: - modal = CharacterLevelModal( - title=LocaleStr("Enter Character Level", key="chara_level.modal.title") - ) + modal = CharacterLevelModal(title=LocaleStr(key="chara_level.modal.title")) modal.translate(self.view.locale, self.view.translator) await i.response.send_modal(modal) await modal.wait() @@ -339,22 +321,22 @@ def __init__(self, current: int, hakushin: bool) -> None: if hakushin: options = [ SelectOption( - label=LocaleStr("Profile", key="character_profile_page_label"), + label=LocaleStr(key="character_profile_page_label"), value="8", default=current == 8, ), SelectOption( - label=LocaleStr("Skills", key="character_skills_page_label"), + label=LocaleStr(key="character_skills_page_label"), value="5", default=current == 5, ), SelectOption( - label=LocaleStr("Passives", key="character_passives_page_label"), + label=LocaleStr(key="character_passives_page_label"), value="6", default=current == 6, ), SelectOption( - label=LocaleStr("Constellations", key="character_const_page_label"), + label=LocaleStr(key="character_const_page_label"), value="7", default=current == 7, ), @@ -362,27 +344,27 @@ def __init__(self, current: int, hakushin: bool) -> None: else: options = [ SelectOption( - label=LocaleStr("Profile", key="character_profile_page_label"), + label=LocaleStr(key="character_profile_page_label"), value="0", default=current == 0, ), SelectOption( - label=LocaleStr("Talents", key="character_talents_page_label"), + label=LocaleStr(key="character_talents_page_label"), value="1", default=current == 1, ), SelectOption( - label=LocaleStr("Constellations", key="character_const_page_label"), + label=LocaleStr(key="character_const_page_label"), value="2", default=current == 2, ), SelectOption( - label=LocaleStr("Stories", key="character_stories_page_label"), + label=LocaleStr(key="character_stories_page_label"), value="3", default=current == 3, ), SelectOption( - label=LocaleStr("Quotes", key="character_quotes_page_label"), + label=LocaleStr(key="character_quotes_page_label"), value="4", default=current == 4, ), diff --git a/hoyo_buddy/ui/hoyo/genshin/search/tcg.py b/hoyo_buddy/ui/hoyo/genshin/search/tcg.py index 7c0bb08b..4754cbff 100644 --- a/hoyo_buddy/ui/hoyo/genshin/search/tcg.py +++ b/hoyo_buddy/ui/hoyo/genshin/search/tcg.py @@ -67,10 +67,10 @@ async def start(self, i: Interaction) -> None: await i.edit_original_response(embed=self.card_embed, view=self) -class ViewCardButton(Button["TCGCardUI"]): +class ViewCardButton(Button[TCGCardUI]): def __init__(self) -> None: super().__init__( - label=LocaleStr("Card", key="view_card_button_label"), + label=LocaleStr(key="view_card_button_label"), style=ButtonStyle.primary, ) @@ -83,10 +83,10 @@ async def callback(self, i: Interaction) -> None: await i.response.edit_message(embed=self.view.card_embed, view=self.view) -class ViewDictionaryButton(Button["TCGCardUI"]): +class ViewDictionaryButton(Button[TCGCardUI]): def __init__(self) -> None: super().__init__( - label=LocaleStr("Dictionary", key="view_dictionary_button_label"), + label=LocaleStr(key="view_dictionary_button_label"), style=ButtonStyle.primary, ) @@ -99,7 +99,7 @@ async def callback(self, i: Interaction) -> None: await i.response.edit_message(embed=self.view.dictionary_embed, view=self.view) -class CardTalentSelector(Select["TCGCardUI"]): +class CardTalentSelector(Select[TCGCardUI]): def __init__( self, talents: list[CardTalent], diff --git a/hoyo_buddy/ui/hoyo/genshin/search/weapon.py b/hoyo_buddy/ui/hoyo/genshin/search/weapon.py index db2baec6..49d87091 100644 --- a/hoyo_buddy/ui/hoyo/genshin/search/weapon.py +++ b/hoyo_buddy/ui/hoyo/genshin/search/weapon.py @@ -85,11 +85,7 @@ async def _get_embed(self) -> DefaultEmbed: def _setup_items(self) -> None: self.clear_items() - self.add_item( - EnterWeaponLevel( - label=LocaleStr("Change weapon level", key="change_weapon_level_label"), - ) - ) + self.add_item(EnterWeaponLevel(label=LocaleStr(key="change_weapon_level_label"))) self.add_item( RefinementSelector( min_refinement=1, @@ -108,7 +104,7 @@ async def start(self, i: Interaction) -> None: class WeaponLevelModal(Modal): level = TextInput( - label=LocaleStr("Level", key="level_label"), + label=LocaleStr(key="level_label"), placeholder="90", is_digit=True, min_value=1, @@ -121,9 +117,7 @@ def __init__(self, label: LocaleStr) -> None: super().__init__(label=label, style=ButtonStyle.blurple) async def callback(self, i: Interaction) -> Any: - modal = WeaponLevelModal( - title=LocaleStr("Enter Weapon Level", key="weapon_level.modal.title") - ) + modal = WeaponLevelModal(title=LocaleStr(key="weapon_level.modal.title")) modal.translate(self.view.locale, self.view.translator) await i.response.send_modal(modal) await modal.wait() @@ -144,7 +138,7 @@ def __init__( super().__init__( options=[ SelectOption( - label=LocaleStr("Refinement {r}", r=i, key="refinement_indicator"), + label=LocaleStr(r=i, key="refinement_indicator"), value=str(i), default=current_refinement == i, ) diff --git a/hoyo_buddy/ui/hoyo/hsr/search/character.py b/hoyo_buddy/ui/hoyo/hsr/search/character.py index 23de9962..f38e1984 100644 --- a/hoyo_buddy/ui/hoyo/hsr/search/character.py +++ b/hoyo_buddy/ui/hoyo/hsr/search/character.py @@ -143,15 +143,13 @@ async def update(self, i: Interaction) -> None: # noqa: PLR0912 case 0: embed = self._character_embed self.add_item( - EnterCharacterLevel( - LocaleStr("Change character level", key="change_character_level_label") - ) + EnterCharacterLevel(LocaleStr(key="change_character_level_label")) ) case 1: embed = self._main_skill_embeds[self._main_skill_index] self.add_item( EnterSkilLevel( - label=LocaleStr("Change skill level", key="change_skill_level_label"), + label=LocaleStr(key="change_skill_level_label"), skill_max_level=self._character_detail.traces.main_skills[ self._main_skill_index ].max_level, @@ -238,15 +236,13 @@ async def update(self, i: Interaction) -> None: # noqa: PLR0912 case 0: embed = self._character_embed self.add_item( - EnterCharacterLevel( - LocaleStr("Change character level", key="change_character_level_label") - ) + EnterCharacterLevel(LocaleStr(key="change_character_level_label")) ) case 1: embed = self._main_skill_embeds[self._main_skill_index] self.add_item( EnterSkilLevel( - label=LocaleStr("Change skill level", key="change_skill_level_label"), + label=LocaleStr(key="change_skill_level_label"), skill_max_level=list(self._character_detail.skills.values())[ self._main_skill_index ].max_level, @@ -297,17 +293,17 @@ def __init__(self, current: int, hakushin: bool) -> None: if hakushin: options = [ SelectOption( - label=LocaleStr("Details", key="yatta_character_detail_page_label"), + label=LocaleStr(key="yatta_character_detail_page_label"), value="0", default=current == 0, ), SelectOption( - label=LocaleStr("Skills", key="yatta_character_skill_page_label"), + label=LocaleStr(key="yatta_character_skill_page_label"), value="1", default=current == 1, ), SelectOption( - label=LocaleStr("Eidolons", key="yatta_character_eidolon_page_label"), + label=LocaleStr(key="yatta_character_eidolon_page_label"), value="2", default=current == 2, ), @@ -315,32 +311,32 @@ def __init__(self, current: int, hakushin: bool) -> None: else: options = [ SelectOption( - label=LocaleStr("Details", key="yatta_character_detail_page_label"), + label=LocaleStr(key="yatta_character_detail_page_label"), value="0", default=current == 0, ), SelectOption( - label=LocaleStr("Skills", key="yatta_character_skill_page_label"), + label=LocaleStr(key="yatta_character_skill_page_label"), value="1", default=current == 1, ), SelectOption( - label=LocaleStr("Eidolons", key="yatta_character_eidolon_page_label"), + label=LocaleStr(key="yatta_character_eidolon_page_label"), value="2", default=current == 2, ), SelectOption( - label=LocaleStr("Traces", key="yatta_character_trace_page_label"), + label=LocaleStr(key="yatta_character_trace_page_label"), value="3", default=current == 3, ), SelectOption( - label=LocaleStr("Stories", key="character_stories_page_label"), + label=LocaleStr(key="character_stories_page_label"), value="4", default=current == 4, ), SelectOption( - label=LocaleStr("Voices", key="character_voices_page_label"), + label=LocaleStr(key="character_voices_page_label"), value="5", default=current == 5, ), @@ -364,13 +360,13 @@ async def callback(self, i: Interaction) -> Any: class SkillLevelModal(Modal): level = TextInput( - label=LocaleStr("Level", key="level_label"), + label=LocaleStr(key="level_label"), is_digit=True, min_value=1, ) def __init__(self, max_level: int) -> None: - super().__init__(title=LocaleStr("Enter Skill Level", key="skill_level.modal.title")) + super().__init__(title=LocaleStr(key="skill_level.modal.title")) self.level.max_value = max_level @@ -417,7 +413,7 @@ async def callback(self, i: Interaction) -> Any: class CharacterLevelModal(Modal): level = TextInput( - label=LocaleStr("Level", key="level_label"), + label=LocaleStr(key="level_label"), is_digit=True, min_value=1, max_value=80, @@ -429,9 +425,7 @@ def __init__(self, label: LocaleStr) -> None: super().__init__(label=label, style=ButtonStyle.blurple) async def callback(self, i: Interaction) -> Any: - modal = CharacterLevelModal( - title=LocaleStr("Enter Character Level", key="chara_level.modal.title") - ) + modal = CharacterLevelModal(title=LocaleStr(key="chara_level.modal.title")) modal.translate(self.view.locale, self.view.translator) await i.response.send_modal(modal) await modal.wait() diff --git a/hoyo_buddy/ui/hoyo/hsr/search/light_cone.py b/hoyo_buddy/ui/hoyo/hsr/search/light_cone.py index 41a26a52..dac9d1c3 100644 --- a/hoyo_buddy/ui/hoyo/hsr/search/light_cone.py +++ b/hoyo_buddy/ui/hoyo/hsr/search/light_cone.py @@ -82,9 +82,7 @@ def _setup_items(self) -> None: self.clear_items() self.add_item( EnterLightConeLevel( - label=LocaleStr( - "Change light cone level", key="enter_light_cone_level.button.label" - ), + label=LocaleStr(key="enter_light_cone_level.button.label"), ) ) self.add_item( @@ -106,7 +104,7 @@ async def start(self, i: Interaction) -> None: class LightConeLevelModal(Modal): level = TextInput( - label=LocaleStr("Level", key="level_label"), + label=LocaleStr(key="level_label"), placeholder="80", is_digit=True, min_value=1, @@ -119,9 +117,7 @@ def __init__(self, label: LocaleStr) -> None: super().__init__(label=label, style=ButtonStyle.blurple) async def callback(self, i: Interaction) -> Any: - modal = LightConeLevelModal( - title=LocaleStr("Enter Weapon Level", key="weapon_level.modal.title") - ) + modal = LightConeLevelModal(title=LocaleStr(key="weapon_level.modal.title")) modal.translate(self.view.locale, self.view.translator) await i.response.send_modal(modal) await modal.wait() @@ -142,7 +138,7 @@ def __init__( super().__init__( options=[ SelectOption( - label=LocaleStr("Superposition {s}", s=i, key="superposition_indicator"), + label=LocaleStr(s=i, key="superposition_indicator"), value=str(i), default=current_superposition == i, ) @@ -159,7 +155,7 @@ async def callback(self, i: Interaction) -> Any: class ShowStoryButton(Button[LightConeUI]): def __init__(self) -> None: - super().__init__(label=LocaleStr("Read Story", key="read_story.button.label")) + super().__init__(label=LocaleStr(key="read_story.button.label")) async def callback(self, i: Interaction) -> Any: assert self.view._lc_detail is not None diff --git a/hoyo_buddy/ui/hoyo/notes/buttons/daily.py b/hoyo_buddy/ui/hoyo/notes/buttons/daily.py index 3ec94a58..505c824f 100644 --- a/hoyo_buddy/ui/hoyo/notes/buttons/daily.py +++ b/hoyo_buddy/ui/hoyo/notes/buttons/daily.py @@ -16,7 +16,7 @@ class DailyReminder(Button[NotesView]): def __init__(self, *, row: int) -> None: - super().__init__(label=LocaleStr("Daily reminder", key="daily_button.label"), row=row) + super().__init__(label=LocaleStr(key="daily_button.label"), row=row) async def callback(self, i: Interaction) -> None: notify_type = ( @@ -27,9 +27,7 @@ async def callback(self, i: Interaction) -> None: notify = await NotesNotify.get_or_none(account=self.view._account, type=notify_type) modal = TypeThreeModal( - notify, - title=LocaleStr("Daily Reminder Settings", key="daily_modal.title"), - min_notify_interval=30, + notify, title=LocaleStr(key="daily_modal.title"), min_notify_interval=30 ) modal.translate(self.view.locale, self.view.translator) await i.response.send_modal(modal) diff --git a/hoyo_buddy/ui/hoyo/notes/buttons/expedition.py b/hoyo_buddy/ui/hoyo/notes/buttons/expedition.py index 497d0fab..53ffe6b1 100644 --- a/hoyo_buddy/ui/hoyo/notes/buttons/expedition.py +++ b/hoyo_buddy/ui/hoyo/notes/buttons/expedition.py @@ -16,7 +16,7 @@ class ExpeditionReminder(Button[NotesView]): def __init__(self, *, row: int) -> None: - super().__init__(label=LocaleStr("Expedition reminder", key="exped_button.label"), row=row) + super().__init__(label=LocaleStr(key="exped_button.label"), row=row) async def callback(self, i: Interaction) -> None: notify_type = ( @@ -27,9 +27,7 @@ async def callback(self, i: Interaction) -> None: notify = await NotesNotify.get_or_none(account=self.view._account, type=notify_type) modal = TypeTwoModal( - notify, - title=LocaleStr("Expedition Reminder Settings", key="exped_modal.title"), - min_notify_interval=30, + notify, title=LocaleStr(key="exped_modal.title"), min_notify_interval=30 ) modal.translate(self.view.locale, self.view.translator) await i.response.send_modal(modal) diff --git a/hoyo_buddy/ui/hoyo/notes/buttons/parametric_transformer.py b/hoyo_buddy/ui/hoyo/notes/buttons/parametric_transformer.py index b71e6593..87d8d645 100644 --- a/hoyo_buddy/ui/hoyo/notes/buttons/parametric_transformer.py +++ b/hoyo_buddy/ui/hoyo/notes/buttons/parametric_transformer.py @@ -18,7 +18,7 @@ class PTReminder(Button[NotesView]): def __init__(self, *, row: int) -> None: super().__init__( - label=LocaleStr("Parametric transformer reminder", key="pt_button.label"), + label=LocaleStr(key="pt_button.label"), emoji=PT_EMOJI, row=row, ) @@ -26,11 +26,7 @@ def __init__(self, *, row: int) -> None: async def callback(self, i: Interaction) -> None: notify = await NotesNotify.get_or_none(account=self.view._account, type=NotesNotifyType.PT) - modal = TypeTwoModal( - notify, - title=LocaleStr("Parametric Transformer Reminder Settings", key="pt_modal.title"), - min_notify_interval=30, - ) + modal = TypeTwoModal(notify, title=LocaleStr(key="pt_modal.title"), min_notify_interval=30) modal.translate(self.view.locale, self.view.translator) await i.response.send_modal(modal) await modal.wait() diff --git a/hoyo_buddy/ui/hoyo/notes/buttons/realm_currency.py b/hoyo_buddy/ui/hoyo/notes/buttons/realm_currency.py index ca8b6ad5..e2cfad3a 100644 --- a/hoyo_buddy/ui/hoyo/notes/buttons/realm_currency.py +++ b/hoyo_buddy/ui/hoyo/notes/buttons/realm_currency.py @@ -18,9 +18,7 @@ class RealmCurrencyReminder(Button[NotesView]): def __init__(self, *, row: int) -> None: super().__init__( - emoji=REALM_CURRENCY, - label=LocaleStr("Realm currency reminder", key="realm_curr_button.label"), - row=row, + emoji=REALM_CURRENCY, label=LocaleStr(key="realm_curr_button.label"), row=row ) async def callback(self, i: Interaction) -> None: @@ -30,7 +28,7 @@ async def callback(self, i: Interaction) -> None: modal = TypeOneModal( notify, - title=LocaleStr("Realm Currency Reminder Settings", key="realm_curr_modal.title"), + title=LocaleStr(key="realm_curr_modal.title"), threshold_max_value=2400, min_notify_interval=30, ) diff --git a/hoyo_buddy/ui/hoyo/notes/buttons/reserved_tbp.py b/hoyo_buddy/ui/hoyo/notes/buttons/reserved_tbp.py index 5f323915..e5b03168 100644 --- a/hoyo_buddy/ui/hoyo/notes/buttons/reserved_tbp.py +++ b/hoyo_buddy/ui/hoyo/notes/buttons/reserved_tbp.py @@ -19,7 +19,7 @@ class ReservedTBPReminder(Button[NotesView]): def __init__(self, *, row: int) -> None: super().__init__( emoji=RESERVED_TRAILBLAZE_POWER, - label=LocaleStr("Reserved trailblaze power reminder", key="rtbp_reminder_button.label"), + label=LocaleStr(key="rtbp_reminder_button.label"), row=row, ) @@ -30,9 +30,7 @@ async def callback(self, i: Interaction) -> None: modal = TypeOneModal( notify, - title=LocaleStr( - "Reserved Trailblaze Power Reminder Settings", key="rtbp_reminder_modal.title" - ), + title=LocaleStr(key="rtbp_reminder_modal.title"), threshold_max_value=2400, min_notify_interval=30, ) diff --git a/hoyo_buddy/ui/hoyo/notes/buttons/resin.py b/hoyo_buddy/ui/hoyo/notes/buttons/resin.py index 04131f5e..b7e5ed3d 100644 --- a/hoyo_buddy/ui/hoyo/notes/buttons/resin.py +++ b/hoyo_buddy/ui/hoyo/notes/buttons/resin.py @@ -17,11 +17,7 @@ class ResinReminder(Button[NotesView]): def __init__(self, *, row: int) -> None: - super().__init__( - emoji=RESIN, - label=LocaleStr("Resin reminder", key="resin_reminder_button.label"), - row=row, - ) + super().__init__(emoji=RESIN, label=LocaleStr(key="resin_reminder_button.label"), row=row) async def callback(self, i: Interaction) -> None: notify = await NotesNotify.get_or_none( @@ -30,7 +26,7 @@ async def callback(self, i: Interaction) -> None: modal = TypeOneModal( notify, - title=LocaleStr("Resin Reminder Settings", key="resin_reminder_modal.title"), + title=LocaleStr(key="resin_reminder_modal.title"), threshold_max_value=200, min_notify_interval=10, ) diff --git a/hoyo_buddy/ui/hoyo/notes/buttons/trailblaze_power.py b/hoyo_buddy/ui/hoyo/notes/buttons/trailblaze_power.py index 37fec7e6..88f1d7f4 100644 --- a/hoyo_buddy/ui/hoyo/notes/buttons/trailblaze_power.py +++ b/hoyo_buddy/ui/hoyo/notes/buttons/trailblaze_power.py @@ -19,7 +19,7 @@ class TBPReminder(Button[NotesView]): def __init__(self, *, row: int) -> None: super().__init__( emoji=TRAILBLAZE_POWER, - label=LocaleStr("Trailblaze power reminder", key="tbp_reminder_button.label"), + label=LocaleStr(key="tbp_reminder_button.label"), row=row, ) @@ -30,7 +30,7 @@ async def callback(self, i: Interaction) -> None: modal = TypeOneModal( notify, - title=LocaleStr("Trailblaze Power Reminder Settings", key="tbp_reminder_modal.title"), + title=LocaleStr(key="tbp_reminder_modal.title"), threshold_max_value=240, min_notify_interval=10, ) diff --git a/hoyo_buddy/ui/hoyo/notes/buttons/week_boss.py b/hoyo_buddy/ui/hoyo/notes/buttons/week_boss.py index 991f5f9b..1d5a5f3c 100644 --- a/hoyo_buddy/ui/hoyo/notes/buttons/week_boss.py +++ b/hoyo_buddy/ui/hoyo/notes/buttons/week_boss.py @@ -16,9 +16,7 @@ class WeekBossReminder(Button[NotesView]): def __init__(self, *, row: int) -> None: - super().__init__( - label=LocaleStr("Weekly boss discount reminder", key="week_boss_button.label"), row=row - ) + super().__init__(label=LocaleStr(key="week_boss_button.label"), row=row) async def callback(self, i: Interaction) -> None: notify_type = ( @@ -30,7 +28,7 @@ async def callback(self, i: Interaction) -> None: modal = TypeFourModal( notify, - title=LocaleStr("Weekly Boss Discount Reminder Settings", key="week_boss_modal.title"), + title=LocaleStr(key="week_boss_modal.title"), min_notify_interval=30, ) modal.translate(self.view.locale, self.view.translator) diff --git a/hoyo_buddy/ui/hoyo/notes/modals/type_four.py b/hoyo_buddy/ui/hoyo/notes/modals/type_four.py index 66a900ef..f00e89b9 100644 --- a/hoyo_buddy/ui/hoyo/notes/modals/type_four.py +++ b/hoyo_buddy/ui/hoyo/notes/modals/type_four.py @@ -12,35 +12,29 @@ class TypeFourModal(Modal): enabled = TextInput( - label=LocaleStr("Enabled", key="notif_modal.enabled.label"), + label=LocaleStr(key="notif_modal.enabled.label"), is_bool=True, ) notify_interval = TextInput( - label=LocaleStr("Notify Interval (in minutes)", key="notif_modal.notify_interval.label"), + label=LocaleStr(key="notif_modal.notify_interval.label"), is_digit=True, min_value=10, max_value=DB_SMALLINT_MAX, ) max_notif_count = TextInput( - label=LocaleStr("Max Notify Count", key="notif_modal.max_notif_count.label"), + label=LocaleStr(key="notif_modal.max_notif_count.label"), is_digit=True, min_value=1, max_value=DB_SMALLINT_MAX, ) notify_time = TextInput( - label=LocaleStr( - "Notify X hours before server resets (4:00 AM)", - key="notif_modal.notify_time.label", - ), + label=LocaleStr(key="notif_modal.notify_time.label"), is_digit=True, min_value=1, max_value=24, ) notify_weekday = TextInput( - label=LocaleStr( - "The weekday to notify", - key="notif_modal.notify_weekday.label", - ), + label=LocaleStr(key="notif_modal.notify_weekday.label"), is_digit=True, min_value=1, max_value=7, diff --git a/hoyo_buddy/ui/hoyo/notes/modals/type_one.py b/hoyo_buddy/ui/hoyo/notes/modals/type_one.py index 203df543..4492ff78 100644 --- a/hoyo_buddy/ui/hoyo/notes/modals/type_one.py +++ b/hoyo_buddy/ui/hoyo/notes/modals/type_one.py @@ -12,23 +12,23 @@ class TypeOneModal(Modal): enabled = TextInput( - label=LocaleStr("Enabled", key="notif_modal.enabled.label"), + label=LocaleStr(key="notif_modal.enabled.label"), is_bool=True, ) threshold = TextInput( - label=LocaleStr("Threshold", key="notif_modal.threshold.label"), + label=LocaleStr(key="notif_modal.threshold.label"), is_digit=True, min_value=0, max_value=240, ) notify_interval = TextInput( - label=LocaleStr("Notify Interval (in minutes)", key="notif_modal.notify_interval.label"), + label=LocaleStr(key="notif_modal.notify_interval.label"), is_digit=True, min_value=10, max_value=DB_SMALLINT_MAX, ) max_notif_count = TextInput( - label=LocaleStr("Max Notify Count", key="notif_modal.max_notif_count.label"), + label=LocaleStr(key="notif_modal.max_notif_count.label"), is_digit=True, min_value=1, max_value=DB_SMALLINT_MAX, diff --git a/hoyo_buddy/ui/hoyo/notes/modals/type_three.py b/hoyo_buddy/ui/hoyo/notes/modals/type_three.py index 9d17f1b0..e3ad4021 100644 --- a/hoyo_buddy/ui/hoyo/notes/modals/type_three.py +++ b/hoyo_buddy/ui/hoyo/notes/modals/type_three.py @@ -12,26 +12,23 @@ class TypeThreeModal(Modal): enabled = TextInput( - label=LocaleStr("Enabled", key="notif_modal.enabled.label"), + label=LocaleStr(key="notif_modal.enabled.label"), is_bool=True, ) notify_interval = TextInput( - label=LocaleStr("Notify Interval (in minutes)", key="notif_modal.notify_interval.label"), + label=LocaleStr(key="notif_modal.notify_interval.label"), is_digit=True, min_value=10, max_value=DB_SMALLINT_MAX, ) max_notif_count = TextInput( - label=LocaleStr("Max Notify Count", key="notif_modal.max_notif_count.label"), + label=LocaleStr(key="notif_modal.max_notif_count.label"), is_digit=True, min_value=1, max_value=DB_SMALLINT_MAX, ) notify_time = TextInput( - label=LocaleStr( - "Notify X hours before server resets (4:00 AM)", - key="notif_modal.notify_time.label", - ), + label=LocaleStr(key="notif_modal.notify_time.label"), is_digit=True, min_value=1, max_value=24, diff --git a/hoyo_buddy/ui/hoyo/notes/modals/type_two.py b/hoyo_buddy/ui/hoyo/notes/modals/type_two.py index b99ebc6a..23cc8aa5 100644 --- a/hoyo_buddy/ui/hoyo/notes/modals/type_two.py +++ b/hoyo_buddy/ui/hoyo/notes/modals/type_two.py @@ -12,17 +12,17 @@ class TypeTwoModal(Modal): enabled = TextInput( - label=LocaleStr("Enabled", key="notif_modal.enabled.label"), + label=LocaleStr(key="notif_modal.enabled.label"), is_bool=True, ) notify_interval = TextInput( - label=LocaleStr("Notify Interval (in minutes)", key="notif_modal.notify_interval.label"), + label=LocaleStr(key="notif_modal.notify_interval.label"), is_digit=True, min_value=10, max_value=DB_SMALLINT_MAX, ) max_notif_count = TextInput( - label=LocaleStr("Max Notify Count", key="notif_modal.max_notif_count.label"), + label=LocaleStr(key="notif_modal.max_notif_count.label"), is_digit=True, min_value=1, max_value=DB_SMALLINT_MAX, diff --git a/hoyo_buddy/ui/hoyo/notes/view.py b/hoyo_buddy/ui/hoyo/notes/view.py index c8a0f034..bcd21829 100644 --- a/hoyo_buddy/ui/hoyo/notes/view.py +++ b/hoyo_buddy/ui/hoyo/notes/view.py @@ -7,7 +7,7 @@ from genshin.models import Notes as GenshinNotes from genshin.models import StarRailNote as StarRailNotes -from hoyo_buddy.bot.translator import LocaleStr +from hoyo_buddy.bot.translator import LocaleStr, WeekdayStr from hoyo_buddy.db.models import NotesNotify from hoyo_buddy.draw.main_funcs import draw_gi_notes_card, draw_hsr_notes_card from hoyo_buddy.embeds import DefaultEmbed @@ -19,7 +19,7 @@ TOGGLE_EMOJIS, TRAILBLAZE_POWER, ) -from hoyo_buddy.enums import Game, NotesNotifyType, Weekday +from hoyo_buddy.enums import Game, NotesNotifyType from hoyo_buddy.models import DrawInput from ...components import Button, GoBackButton, View @@ -61,14 +61,8 @@ def __init__( @staticmethod def _get_type1_value(notify: NotesNotify | None) -> LocaleStr: if notify is None: - return LocaleStr("Not set", key="reminder_settings.not_set") + return LocaleStr(key="reminder_settings.not_set") return LocaleStr( - ( - "Status: {status}\n" - "Threshold: {threshold}\n" - "Notify Interval: {notify_interval} minutes\n" - "Max Notify Count: {max_notif_count}" - ), key="reminder_settings.reminde.set.type1", status=TOGGLE_EMOJIS[notify.enabled], threshold=notify.threshold, @@ -79,13 +73,8 @@ def _get_type1_value(notify: NotesNotify | None) -> LocaleStr: @staticmethod def _get_type2_value(notify: NotesNotify | None) -> LocaleStr: if notify is None: - return LocaleStr("Not set", key="reminder_settings.not_set") + return LocaleStr(key="reminder_settings.not_set") return LocaleStr( - ( - "Status: {status}\n" - "Notify Interval: {notify_interval} minutes\n" - "Max Notify Count: {max_notif_count}" - ), key="reminder_settings.reminde.set.type2", status=TOGGLE_EMOJIS[notify.enabled], notify_interval=notify.notify_interval, @@ -95,14 +84,8 @@ def _get_type2_value(notify: NotesNotify | None) -> LocaleStr: @staticmethod def _get_type3_value(notify: NotesNotify | None) -> LocaleStr: if notify is None: - return LocaleStr("Not set", key="reminder_settings.not_set") + return LocaleStr(key="reminder_settings.not_set") return LocaleStr( - ( - "Status: {status}\n" - "Notify Interval: {notify_interval} minutes\n" - "Max Notify Count: {max_notif_count}\n" - "Notify Time: {notify_time} hours before the server resets\n" - ), key="reminder_settings.reminde.set.type3", status=TOGGLE_EMOJIS[notify.enabled], notify_interval=notify.notify_interval, @@ -113,30 +96,26 @@ def _get_type3_value(notify: NotesNotify | None) -> LocaleStr: @staticmethod def _get_type4_value(notify: NotesNotify | None) -> LocaleStr: if notify is None: - return LocaleStr("Not set", key="reminder_settings.not_set") + return LocaleStr(key="reminder_settings.not_set") + + if notify.notify_weekday is None: + msg = "notify_weekday is None" + raise ValueError(msg) + return LocaleStr( - ( - "Status: {status}\n" - "Notify Interval: {notify_interval} minutes\n" - "Max Notify Count: {max_notif_count}\n" - "Notify Time: {notify_time} hours before the server resets\n" - "Notify Weekday: {notify_weekday}" - ), key="reminder_settings.reminde.set.type4", status=TOGGLE_EMOJIS[notify.enabled], notify_interval=notify.notify_interval, max_notif_count=notify.max_notif_count, notify_time=notify.notify_time, - notify_weekday=LocaleStr( - Weekday(notify.notify_weekday).name.title(), warn_no_key=False - ), + notify_weekday=WeekdayStr(notify.notify_weekday), ) async def _get_reminder_embed(self) -> DefaultEmbed: embed = DefaultEmbed( self.locale, self.translator, - title=LocaleStr("Real-Time Notes Reminders", key="reminder_settings_title"), + title=LocaleStr(key="reminder_settings_title"), ) if self._account.game is Game.GENSHIN: @@ -144,7 +123,7 @@ async def _get_reminder_embed(self) -> DefaultEmbed: account=self._account, type=NotesNotifyType.RESIN ) embed.add_field( - name=LocaleStr("Resin Reminder", key="resin_reminder_button.label"), + name=LocaleStr(key="resin_reminder_button.label"), value=self._get_type1_value(resin_notify), inline=False, ) @@ -153,7 +132,7 @@ async def _get_reminder_embed(self) -> DefaultEmbed: account=self._account, type=NotesNotifyType.REALM_CURRENCY ) embed.add_field( - name=LocaleStr("Realm Currency Reminder", key="realm_curr_button.label"), + name=LocaleStr(key="realm_curr_button.label"), value=self._get_type1_value(realm_currency_notify), inline=False, ) @@ -162,7 +141,7 @@ async def _get_reminder_embed(self) -> DefaultEmbed: account=self._account, type=NotesNotifyType.PT ) embed.add_field( - name=LocaleStr("Parametric Transformer Reminder", key="pt_button.label"), + name=LocaleStr(key="pt_button.label"), value=self._get_type2_value(pt_notify), inline=False, ) @@ -171,7 +150,7 @@ async def _get_reminder_embed(self) -> DefaultEmbed: account=self._account, type=NotesNotifyType.GI_EXPED ) embed.add_field( - name=LocaleStr("Expedition Reminder", key="exped_button.label"), + name=LocaleStr(key="exped_button.label"), value=self._get_type2_value(expedition_notify), inline=False, ) @@ -180,7 +159,7 @@ async def _get_reminder_embed(self) -> DefaultEmbed: account=self._account, type=NotesNotifyType.GI_DAILY ) embed.add_field( - name=LocaleStr("Daily Reminder", key="daily_button.label"), + name=LocaleStr(key="daily_button.label"), value=self._get_type3_value(daily_notify), inline=False, ) @@ -189,7 +168,7 @@ async def _get_reminder_embed(self) -> DefaultEmbed: account=self._account, type=NotesNotifyType.RESIN_DISCOUNT ) embed.add_field( - name=LocaleStr("Weekly Boss Discount Reminder", key="week_boss_button.label"), + name=LocaleStr(key="week_boss_button.label"), value=self._get_type4_value(resin_discount_notify), inline=False, ) @@ -199,7 +178,7 @@ async def _get_reminder_embed(self) -> DefaultEmbed: account=self._account, type=NotesNotifyType.TB_POWER ) embed.add_field( - name=LocaleStr("Trailblaze Power Reminder", key="tbp_reminder_button.label"), + name=LocaleStr(key="tbp_reminder_button.label"), value=self._get_type1_value(tbp_notify), inline=False, ) @@ -208,9 +187,7 @@ async def _get_reminder_embed(self) -> DefaultEmbed: account=self._account, type=NotesNotifyType.RESERVED_TB_POWER ) embed.add_field( - name=LocaleStr( - "Reserved Trailblaze Power Reminder", key="rtbp_reminder_button.label" - ), + name=LocaleStr(key="rtbp_reminder_button.label"), value=self._get_type1_value(reserved_tbp_notify), inline=False, ) @@ -219,7 +196,7 @@ async def _get_reminder_embed(self) -> DefaultEmbed: account=self._account, type=NotesNotifyType.HSR_EXPED ) embed.add_field( - name=LocaleStr("Expedition Reminder", key="exped_button.label"), + name=LocaleStr(key="exped_button.label"), value=self._get_type2_value(expedition_notify), inline=False, ) @@ -228,7 +205,7 @@ async def _get_reminder_embed(self) -> DefaultEmbed: account=self._account, type=NotesNotifyType.HSR_DAILY ) embed.add_field( - name=LocaleStr("Daily Reminder", key="daily_button.label"), + name=LocaleStr(key="daily_button.label"), value=self._get_type3_value(daily_notify), inline=False, ) @@ -237,7 +214,7 @@ async def _get_reminder_embed(self) -> DefaultEmbed: account=self._account, type=NotesNotifyType.ECHO_OF_WAR ) embed.add_field( - name=LocaleStr("Weekly Boss Discount Reminder", key="week_boss_button.label"), + name=LocaleStr(key="week_boss_button.label"), value=self._get_type4_value(echo_of_war_notify), inline=False, ) @@ -434,7 +411,6 @@ def _get_notes_embed(self, notes: GenshinNotes | StarRailNotes) -> DefaultEmbed: if notes.remaining_resin_recovery_time.seconds > 0: descriptions.append( LocaleStr( - "{emoji} full {in_time}", key="notes.item_full_in_time", emoji=RESIN, in_time=format_dt(notes.resin_recovery_time, style="R"), @@ -443,7 +419,6 @@ def _get_notes_embed(self, notes: GenshinNotes | StarRailNotes) -> DefaultEmbed: if notes.remaining_realm_currency_recovery_time.seconds > 0: descriptions.append( LocaleStr( - "{emoji} full {in_time}", key="notes.item_full_in_time", emoji=REALM_CURRENCY, in_time=format_dt(notes.realm_currency_recovery_time, style="R"), @@ -456,7 +431,6 @@ def _get_notes_embed(self, notes: GenshinNotes | StarRailNotes) -> DefaultEmbed: assert notes.transformer_recovery_time is not None descriptions.append( LocaleStr( - "{emoji} available {in_time}", key="notes_available", emoji=PT_EMOJI, in_time=format_dt(notes.transformer_recovery_time, style="R"), @@ -465,7 +439,6 @@ def _get_notes_embed(self, notes: GenshinNotes | StarRailNotes) -> DefaultEmbed: elif isinstance(notes, StarRailNotes) and notes.stamina_recover_time.seconds > 0: descriptions.append( LocaleStr( - "{emoji} full {in_time}", key="notes.item_full_in_time", emoji=TRAILBLAZE_POWER, in_time=format_dt(notes.stamina_recovery_time, style="R"), @@ -498,7 +471,7 @@ def __init__(self) -> None: super().__init__( style=ButtonStyle.blurple, emoji=BELL_OUTLINE, - label=LocaleStr("Reminder settings", key="reminder_button.label"), + label=LocaleStr(key="reminder_button.label"), ) async def callback(self, i: Interaction) -> None: diff --git a/hoyo_buddy/ui/hoyo/profile/items/add_img_btn.py b/hoyo_buddy/ui/hoyo/profile/items/add_img_btn.py index f064f3aa..b539ae41 100644 --- a/hoyo_buddy/ui/hoyo/profile/items/add_img_btn.py +++ b/hoyo_buddy/ui/hoyo/profile/items/add_img_btn.py @@ -20,19 +20,19 @@ class AddImageModal(Modal): image_url = TextInput( - label=LocaleStr("Image URL", key="profile.add_image_modal.image_url.label"), + label=LocaleStr(key="profile.add_image_modal.image_url.label"), placeholder="https://example.com/image.png", style=TextStyle.short, ) def __init__(self) -> None: - super().__init__(title=LocaleStr("Add Custom Image", key="profile.add_image_modal.title")) + super().__init__(title=LocaleStr(key="profile.add_image_modal.title")) class AddImageButton(Button["ProfileView"]): def __init__(self) -> None: super().__init__( - label=LocaleStr("Add custom image", key="profile.add_image.button.label"), + label=LocaleStr(key="profile.add_image.button.label"), style=ButtonStyle.green, emoji=ADD, row=3, diff --git a/hoyo_buddy/ui/hoyo/profile/items/build_select.py b/hoyo_buddy/ui/hoyo/profile/items/build_select.py index 21369de7..0ae59565 100644 --- a/hoyo_buddy/ui/hoyo/profile/items/build_select.py +++ b/hoyo_buddy/ui/hoyo/profile/items/build_select.py @@ -16,7 +16,7 @@ class BuildSelect(Select["ProfileView"]): def __init__(self) -> None: super().__init__( - placeholder=LocaleStr("Select a build...", key="profile.build.select.placeholder"), + placeholder=LocaleStr(key="profile.build.select.placeholder"), options=[SelectOption(label="Placeholder", value="0")], disabled=True, custom_id="profile_build_select", @@ -31,7 +31,7 @@ def set_options(self, builds: list[enka.gi.Build] | list[enka.hsr.Build]) -> Non self._builds = builds self.options = [ SelectOption( - label=build.name or LocaleStr("Current", key="profile.build.current.label"), + label=build.name or LocaleStr(key="profile.build.current.label"), value=str(build.id), default=self.view._build_id == build.id, ) diff --git a/hoyo_buddy/ui/hoyo/profile/items/card_info_btn.py b/hoyo_buddy/ui/hoyo/profile/items/card_info_btn.py index 03885dd7..4049780d 100644 --- a/hoyo_buddy/ui/hoyo/profile/items/card_info_btn.py +++ b/hoyo_buddy/ui/hoyo/profile/items/card_info_btn.py @@ -21,12 +21,8 @@ async def callback(self, i: Interaction) -> None: embed = DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr("About Character Build Cards", key="profile.card_info.embed.title"), + title=LocaleStr(key="profile.card_info.embed.title"), description=LocaleStr( - "- All assets used in the cards belong to Hoyoverse, I do not own them.\n" - "- All fanarts used in the cards are credited to their respective artists.\n" - "- The Hoyo Buddy templates' designs are original, you are not allowed to modify them or claim that you made them without my permission.\n" - "- Game data is provided by {provider}.\n", key="profile.card_info.embed.description", provider="[Enka.Network](https://api.enka.network/)", ), diff --git a/hoyo_buddy/ui/hoyo/profile/items/card_settings_btn.py b/hoyo_buddy/ui/hoyo/profile/items/card_settings_btn.py index 23bddf6d..2b5e9285 100644 --- a/hoyo_buddy/ui/hoyo/profile/items/card_settings_btn.py +++ b/hoyo_buddy/ui/hoyo/profile/items/card_settings_btn.py @@ -26,7 +26,7 @@ class CardSettingsButton(Button["ProfileView"]): def __init__(self) -> None: super().__init__( - label=LocaleStr("Card settings", key="profile.card_settings.button.label"), + label=LocaleStr(key="profile.card_settings.button.label"), disabled=True, custom_id="profile_card_settings", emoji=SETTINGS, diff --git a/hoyo_buddy/ui/hoyo/profile/items/card_settings_info_btn.py b/hoyo_buddy/ui/hoyo/profile/items/card_settings_info_btn.py index cb8d2e09..b5bb493b 100644 --- a/hoyo_buddy/ui/hoyo/profile/items/card_settings_info_btn.py +++ b/hoyo_buddy/ui/hoyo/profile/items/card_settings_info_btn.py @@ -21,47 +21,26 @@ async def callback(self, i: Interaction) -> None: embed = DefaultEmbed( self.view.locale, self.view.translator, - title=LocaleStr("About Card Settings", key="profile.info.embed.title"), + title=LocaleStr(key="profile.info.embed.title"), ) embed.add_field( - name=LocaleStr("Primary Color", key="profile.info.embed.primary_color.name"), - value=LocaleStr( - "- Only hex color codes are supported.", - key="profile.info.embed.primary_color.value", - ), + name=LocaleStr(key="profile.info.embed.primary_color.name"), + value=LocaleStr(key="profile.info.embed.primary_color.value"), inline=False, ) embed.add_field( - name=LocaleStr("Dark Mode", key="profile.info.embed.dark_mode.name"), - value=LocaleStr( - "- This setting is independent from the one in , defaults to light mode.\n" - "- Light mode cards tend to look better because the colors are not optimized for dark mode.\n" - "- Suggestions for dark mode colors are welcome!", - key="profile.info.embed.dark_mode.value", - ), + name=LocaleStr(key="profile.info.embed.dark_mode.name"), + value=LocaleStr(key="profile.info.embed.dark_mode.value"), inline=False, ) embed.add_field( - name=LocaleStr("Custom Images", key="profile.info.embed.custom_images.name"), - value=LocaleStr( - "- Hoyo Buddy comes with some preset arts that I liked, but you can add your own images too.\n" - "- Only direct image URLs are supported, and they must be publicly accessible; GIFs are not supported.\n" - "- For Hoyo Buddy's templates, vertical images are recommended.\n" - "- For server owners, I am not responsible for any NSFW images that you or your members add.\n" - "- The red button removes the current custom image and reverts to the default one.", - key="profile.info.embed.custom_images.value", - ), + name=LocaleStr(key="profile.info.embed.custom_images.name"), + value=LocaleStr(key="profile.info.embed.custom_images.value"), inline=False, ) embed.add_field( - name=LocaleStr("Templates", key="profile.info.embed.templates.name"), - value=LocaleStr( - "- Hoyo Buddy has its own template made by me, but I also added templates made by other developers.\n" - "- Code of 3rd party templates are not maintained by me, so I cannot guarantee their quality; I am also not responsible for any issues with them.\n" - "- 3rd party templates may have feature limitations compared to Hoyo Buddy's.\n" - "- Cached data characters can only use Hoyo Buddy's templates.", - key="profile.info.embed.templates.value", - ), + name=LocaleStr(key="profile.info.embed.templates.name"), + value=LocaleStr(key="profile.info.embed.templates.value"), inline=False, ) await i.response.send_message(embed=embed, ephemeral=True) diff --git a/hoyo_buddy/ui/hoyo/profile/items/card_template_select.py b/hoyo_buddy/ui/hoyo/profile/items/card_template_select.py index 922fa787..8d795d2f 100644 --- a/hoyo_buddy/ui/hoyo/profile/items/card_template_select.py +++ b/hoyo_buddy/ui/hoyo/profile/items/card_template_select.py @@ -28,12 +28,10 @@ def __init__(self, current_template: str, hb_only: bool, game: Game) -> None: options.append( SelectOption( label=LocaleStr( - "Hoyo Buddy template {num}", key="profile.card_template_select.hb.label", num=1, ), description=LocaleStr( - "Designed and programmed by {author}", key="profile.card_template_select.same_author.description", author="@seriaati", ), @@ -49,12 +47,10 @@ def __init__(self, current_template: str, hb_only: bool, game: Game) -> None: options.append( SelectOption( label=LocaleStr( - "StarRailCard template {num}", key="profile.card_template_select.src.label", num=template_num, ), description=LocaleStr( - "Designed and programmed by {author}", key="profile.card_template_select.same_author.description", author="@korzzex", ), @@ -67,11 +63,9 @@ def __init__(self, current_template: str, hb_only: bool, game: Game) -> None: [ SelectOption( label=LocaleStr( - "Classic Enka template", key="profile.card_template_select.enka_classic.label", ), description=LocaleStr( - "Designed by {author1} and programmed by {author2}", key="profile.card_template_select.diff_author.description", author1="@algoinde", author2="@hattvr", @@ -81,12 +75,10 @@ def __init__(self, current_template: str, hb_only: bool, game: Game) -> None: ), SelectOption( label=LocaleStr( - "ENCard template {num}", key="profile.card_template_select.encard.label", num=1, ), description=LocaleStr( - "Designed and programmed by {author}", key="profile.card_template_select.same_author.description", author="@korzzex", ), @@ -100,19 +92,16 @@ def __init__(self, current_template: str, hb_only: bool, game: Game) -> None: options.append( SelectOption( label=LocaleStr( - "EnkaCard template {num}", key="profile.card_template_select.enkacard.label", num=template_num, ), description=LocaleStr( - "Designed by {author1} and programmed by {author2}", key="profile.card_template_select.diff_author.description", author1="@algoinde", author2="@korzzex", ) if template_num == 3 else LocaleStr( - "Designed and programmed by {author}", key="profile.card_template_select.same_author.description", author="@korzzex", ), @@ -123,9 +112,7 @@ def __init__(self, current_template: str, hb_only: bool, game: Game) -> None: super().__init__( options=options, - placeholder=LocaleStr( - "Select a template", key="profile.card_template_select.placeholder" - ), + placeholder=LocaleStr(key="profile.card_template_select.placeholder"), row=1, custom_id="profile_card_template_select", ) diff --git a/hoyo_buddy/ui/hoyo/profile/items/chara_select.py b/hoyo_buddy/ui/hoyo/profile/items/chara_select.py index f722cd88..7f1d846a 100644 --- a/hoyo_buddy/ui/hoyo/profile/items/chara_select.py +++ b/hoyo_buddy/ui/hoyo/profile/items/chara_select.py @@ -5,7 +5,7 @@ import enka -from hoyo_buddy.bot.translator import LocaleStr +from hoyo_buddy.bot.translator import LevelStr, LocaleStr from hoyo_buddy.emojis import get_gi_element_emoji, get_hsr_element_emoji from hoyo_buddy.enums import CharacterType from hoyo_buddy.models import HoyolabHSRCharacter @@ -22,15 +22,9 @@ Builds: TypeAlias = dict[str, list[enka.gi.Build]] | dict[str, list[enka.hsr.Build]] DATA_TYPES: Final[dict[CharacterType, LocaleStr]] = { - CharacterType.BUILD: LocaleStr( - "Enka Network build", key="profile.character_select.enka_network.description" - ), - CharacterType.LIVE: LocaleStr( - "Real-time data", key="profile.character_select.live_data.description" - ), - CharacterType.CACHE: LocaleStr( - "Cached data", key="profile.character_select.cached_data.description" - ), + CharacterType.BUILD: LocaleStr(key="profile.character_select.enka_network.description"), + CharacterType.LIVE: LocaleStr(key="profile.character_select.live_data.description"), + CharacterType.CACHE: LocaleStr(key="profile.character_select.cached_data.description"), } @@ -65,7 +59,6 @@ def __init__( if isinstance(character, enka.hsr.Character): description = LocaleStr( - "Lv.{level} | E{eidolons}S{superposition} | {data_type} | From in-game showcase", key="profile.character_select.description", level=character.level, superposition=character.light_cone.superimpose if character.light_cone else 0, @@ -75,7 +68,6 @@ def __init__( emoji = get_hsr_element_emoji(character.element.value) elif isinstance(character, HoyolabHSRCharacter): description = LocaleStr( - "Lv.{level} | E{eidolons}S{superposition} | {data_type} | From HoYoLAB", key="profile.character_select.hoyolab.description", level=character.level, superposition=character.light_cone.superimpose if character.light_cone else 0, @@ -85,7 +77,6 @@ def __init__( emoji = get_hsr_element_emoji(character.element) else: description = LocaleStr( - "Lv.{level} | C{const}R{refine} | {data_type}", key="profile.genshin.character_select.description", level=character.level, const=character.constellations_unlocked, @@ -96,7 +87,12 @@ def __init__( options.append( SelectOption( - label=character.name, + label=LocaleStr( + custom_str="{name} ({level_str})", + translate=False, + name=character.name, + level_str=LevelStr(character.level), + ), description=description, value=str(character.id), emoji=emoji, @@ -105,7 +101,7 @@ def __init__( super().__init__( options, - placeholder=LocaleStr("Select a character", key="profile.character_select.placeholder"), + placeholder=LocaleStr(key="profile.character_select.placeholder"), custom_id="profile_character_select", ) @@ -143,6 +139,7 @@ async def callback(self, i: Interaction) -> None: self.view._build_id = builds[0].id build_select: BuildSelect = self.view.get_item("profile_build_select") build_select.set_options(builds) + build_select.translate(self.view.locale, self.view.translator) self.update_options_defaults() await self.set_loading_state(i) diff --git a/hoyo_buddy/ui/hoyo/profile/items/dark_mode_btn.py b/hoyo_buddy/ui/hoyo/profile/items/dark_mode_btn.py index b9c0b18c..53e0a71a 100644 --- a/hoyo_buddy/ui/hoyo/profile/items/dark_mode_btn.py +++ b/hoyo_buddy/ui/hoyo/profile/items/dark_mode_btn.py @@ -15,7 +15,7 @@ class DarkModeButton(ToggleButton["ProfileView"]): def __init__(self, current_toggle: bool, disabled: bool) -> None: super().__init__( current_toggle, - LocaleStr("Dark Mode", key="profile.dark_mode.button.label"), + LocaleStr(key="profile.dark_mode.button.label"), row=2, custom_id="profile_dark_mode", disabled=disabled, diff --git a/hoyo_buddy/ui/hoyo/profile/items/gen_ai_art_btn.py b/hoyo_buddy/ui/hoyo/profile/items/gen_ai_art_btn.py index fdc0272e..1eeedf16 100644 --- a/hoyo_buddy/ui/hoyo/profile/items/gen_ai_art_btn.py +++ b/hoyo_buddy/ui/hoyo/profile/items/gen_ai_art_btn.py @@ -19,16 +19,14 @@ class GenerateAIArtModal(Modal): prompt = TextInput( - label=LocaleStr("Prompt", key="profile.generate_ai_art_modal.prompt.label"), + label=LocaleStr(key="profile.generate_ai_art_modal.prompt.label"), placeholder="navia(genshin impact), foaml dress, idol, beautiful dress, elegant, best quality, aesthetic...", style=TextStyle.paragraph, max_length=250, ) negative_prompt = TextInput( - label=LocaleStr( - "Negative Prompt", key="profile.generate_ai_art_modal.negative_prompt.label" - ), + label=LocaleStr(key="profile.generate_ai_art_modal.negative_prompt.label"), placeholder="bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs...", style=TextStyle.paragraph, max_length=200, @@ -39,7 +37,7 @@ class GenerateAIArtModal(Modal): class GenerateAIArtButton(Button): def __init__(self, disabled: bool) -> None: super().__init__( - label=LocaleStr("Generate AI art", key="profile.generate_ai_art.button.label"), + label=LocaleStr(key="profile.generate_ai_art.button.label"), style=ButtonStyle.blurple, row=3, custom_id="profile_generate_ai_art", @@ -50,9 +48,7 @@ async def callback(self, i: Interaction) -> None: if i.guild is None: raise GuildOnlyFeatureError - modal = GenerateAIArtModal( - title=LocaleStr("Generate AI Art", key="profile.generate_ai_art_modal.title") - ) + modal = GenerateAIArtModal(title=LocaleStr(key="profile.generate_ai_art_modal.title")) modal.translate(self.view.locale, self.view.translator) await i.response.send_modal(modal) await modal.wait() diff --git a/hoyo_buddy/ui/hoyo/profile/items/image_select.py b/hoyo_buddy/ui/hoyo/profile/items/image_select.py index e8ece758..29e1ddf0 100644 --- a/hoyo_buddy/ui/hoyo/profile/items/image_select.py +++ b/hoyo_buddy/ui/hoyo/profile/items/image_select.py @@ -28,7 +28,7 @@ def __init__( super().__init__( self.generate_options(), - placeholder=LocaleStr("Select an image", key="profile.image_select.placeholder"), + placeholder=LocaleStr(key="profile.image_select.placeholder"), custom_id="profile_image_select", row=0, disabled=disabled, @@ -42,7 +42,7 @@ def generate_options(self) -> list[SelectOption]: """ options: list[SelectOption] = [ SelectOption( - label=LocaleStr("Official art", key="profile.image_select.none.label"), + label=LocaleStr(key="profile.image_select.none.label"), value="none", default=self.current_image_url is None, ) @@ -69,17 +69,9 @@ def get_image_url_option(self, image_url: str, num: int) -> SelectOption: """ label = ( - LocaleStr( - "Hoyo Buddy Collection ({num})", - key="profile.image_select.default_collection.label", - num=num, - ) + LocaleStr(key="profile.image_select.default_collection.label", num=num) if image_url in self.default_collection - else LocaleStr( - "Custom Image ({num})", - key="profile.image_select.custom_image.label", - num=num, - ) + else LocaleStr(key="profile.image_select.custom_image.label", num=num) ) option = SelectOption( label=label, diff --git a/hoyo_buddy/ui/hoyo/profile/items/player_btn.py b/hoyo_buddy/ui/hoyo/profile/items/player_btn.py index acdff246..cdbea21a 100644 --- a/hoyo_buddy/ui/hoyo/profile/items/player_btn.py +++ b/hoyo_buddy/ui/hoyo/profile/items/player_btn.py @@ -19,7 +19,7 @@ class PlayerInfoButton(Button["ProfileView"]): def __init__(self) -> None: super().__init__( - label=LocaleStr("Player info", key="profile.player_info.button.label"), + label=LocaleStr(key="profile.player_info.button.label"), style=ButtonStyle.blurple, emoji=BOOK_MULTIPLE, disabled=True, diff --git a/hoyo_buddy/ui/hoyo/profile/items/primary_color_btn.py b/hoyo_buddy/ui/hoyo/profile/items/primary_color_btn.py index e9985e52..03087ecf 100644 --- a/hoyo_buddy/ui/hoyo/profile/items/primary_color_btn.py +++ b/hoyo_buddy/ui/hoyo/profile/items/primary_color_btn.py @@ -17,7 +17,7 @@ class PrimaryColorModal(Modal): color = TextInput( - label=LocaleStr("Color (hex code)", key="profile.primary_color_modal.color.label"), + label=LocaleStr(key="profile.primary_color_modal.color.label"), placeholder="#000000", style=TextStyle.short, min_length=7, @@ -26,16 +26,14 @@ class PrimaryColorModal(Modal): ) def __init__(self, current_color: str | None) -> None: - super().__init__( - title=LocaleStr("Change Card Color", key="profile.primary_color_modal.title") - ) + super().__init__(title=LocaleStr(key="profile.primary_color_modal.title")) self.color.default = current_color class PrimaryColorButton(Button["ProfileView"]): def __init__(self, current_color: str | None, disabled: bool) -> None: super().__init__( - label=LocaleStr("Change color", key="profile.primary_color.button.label"), + label=LocaleStr(key="profile.primary_color.button.label"), style=ButtonStyle.blurple, row=2, custom_id="profile_primary_color", diff --git a/hoyo_buddy/ui/hoyo/profile/items/remove_img_btn.py b/hoyo_buddy/ui/hoyo/profile/items/remove_img_btn.py index 7cccd4df..6e241bf2 100644 --- a/hoyo_buddy/ui/hoyo/profile/items/remove_img_btn.py +++ b/hoyo_buddy/ui/hoyo/profile/items/remove_img_btn.py @@ -18,7 +18,7 @@ class RemoveImageButton(Button["ProfileView"]): def __init__(self, disabled: bool) -> None: super().__init__( - label=LocaleStr("Remove custom image", key="profile.remove_image.button.label"), + label=LocaleStr(key="profile.remove_image.button.label"), style=ButtonStyle.red, disabled=disabled, custom_id="profile_remove_image", diff --git a/hoyo_buddy/ui/hoyo/profile/items/rmv_from_cache_btn.py b/hoyo_buddy/ui/hoyo/profile/items/rmv_from_cache_btn.py index 6baa980a..394f7fc6 100644 --- a/hoyo_buddy/ui/hoyo/profile/items/rmv_from_cache_btn.py +++ b/hoyo_buddy/ui/hoyo/profile/items/rmv_from_cache_btn.py @@ -22,7 +22,7 @@ class RemoveFromCacheButton(Button["ProfileView"]): def __init__(self) -> None: super().__init__( - label=LocaleStr("Remove from cache", key="profile.remove_from_cache.button.label"), + label=LocaleStr(key="profile.remove_from_cache.button.label"), style=ButtonStyle.red, emoji=DELETE, row=3, diff --git a/hoyo_buddy/ui/hoyo/profile/view.py b/hoyo_buddy/ui/hoyo/profile/view.py index cf62e01a..a795f032 100644 --- a/hoyo_buddy/ui/hoyo/profile/view.py +++ b/hoyo_buddy/ui/hoyo/profile/view.py @@ -145,12 +145,6 @@ def player_embed(self) -> DefaultEmbed: self.translator, title=f"{player.nickname} ({self.uid})", description=LocaleStr( - "Trailblaze Level: {level}\n" - "Equilibrium Level: {world_level}\n" - "Friend Count: {friend_count}\n" - "Light Cones: {light_cones}\n" - "Characters: {characters}\n" - "Achievements: {achievements}\n", key="profile.player_info.embed.description", level=player.level, world_level=player.equilibrium_level, @@ -170,9 +164,6 @@ def player_embed(self) -> DefaultEmbed: self.translator, title=f"{player.nickname} ({self.uid})", description=LocaleStr( - "Adventure Rank: {adventure_rank}\n" - "Spiral Abyss: {spiral_abyss}\n" - "Achievements: {achievements}\n", key="profile.player_info.gi.embed.description", adventure_rank=player.level, spiral_abyss=f"{player.abyss_floor}-{player.abyss_level}", @@ -192,11 +183,6 @@ def player_embed(self) -> DefaultEmbed: self.translator, title=f"{player.nickname} ({self.uid})", description=LocaleStr( - "Trailblaze Level: {level}\n" - "Characters: {characters}\n" - "Chests: {chest}\n" - "Memory of Chaos: {moc}\n" - "Achievements: {achievements}\n", key="profile.player_info.hoyolab.embed.description", level=player.level, characters=stats.avatar_num, @@ -209,11 +195,8 @@ def player_embed(self) -> DefaultEmbed: embed = DefaultEmbed( self.locale, self.translator, - title=LocaleStr("No data available", key="profile.no_data.title"), - description=LocaleStr( - "Game services are currently down; luckily, Hoyo Buddy helped you to cache your character data, so you can still view your character cards as normal.", - key="profile.no_data.description", - ), + title=LocaleStr(key="profile.no_data.title"), + description=LocaleStr(key="profile.no_data.description"), ) return embed diff --git a/hoyo_buddy/ui/hoyo/redeem.py b/hoyo_buddy/ui/hoyo/redeem.py index 9bcff77d..d9fd3b25 100644 --- a/hoyo_buddy/ui/hoyo/redeem.py +++ b/hoyo_buddy/ui/hoyo/redeem.py @@ -17,21 +17,21 @@ class GiftCodeModal(Modal): - code_1 = TextInput(label=LocaleStr("Code {num}", key="gift_code_modal.code_input.label", num=1)) + code_1 = TextInput(label=LocaleStr(key="gift_code_modal.code_input.label", num=1)) code_2 = TextInput( - label=LocaleStr("Code {num}", key="gift_code_modal.code_input.label", num=2), + label=LocaleStr(key="gift_code_modal.code_input.label", num=2), required=False, ) code_3 = TextInput( - label=LocaleStr("Code {num}", key="gift_code_modal.code_input.label", num=3), + label=LocaleStr(key="gift_code_modal.code_input.label", num=3), required=False, ) code_4 = TextInput( - label=LocaleStr("Code {num}", key="gift_code_modal.code_input.label", num=4), + label=LocaleStr(key="gift_code_modal.code_input.label", num=4), required=False, ) code_5 = TextInput( - label=LocaleStr("Code {num}", key="gift_code_modal.code_input.label", num=5), + label=LocaleStr(key="gift_code_modal.code_input.label", num=5), required=False, ) @@ -56,12 +56,8 @@ def start_embed(self) -> DefaultEmbed: return DefaultEmbed( self.locale, self.translator, - title=LocaleStr("Redeem Codes", key="redeem_codes_button.label"), - description=LocaleStr( - "Enter up to 5 redemption codes to redeem.\n" - "Alternatively, you can enable automatic code redemption.", - key="redeem_command_embed.description", - ), + title=LocaleStr(key="redeem_codes_button.label"), + description=LocaleStr(key="redeem_command_embed.description"), ).add_acc_info(self.account) @property @@ -69,11 +65,8 @@ def cooldown_embed(self) -> DefaultEmbed: return DefaultEmbed( self.locale, self.translator, - title=LocaleStr("Redeeming Codes", key="redeem_cooldown_embed.title"), - description=LocaleStr( - "Due to redeem cooldowns, this may take a while.", - key="redeem_cooldown_embed.description", - ), + title=LocaleStr(key="redeem_cooldown_embed.title"), + description=LocaleStr(key="redeem_cooldown_embed.description"), ) def _add_items(self) -> None: @@ -84,15 +77,13 @@ def _add_items(self) -> None: class RedeemCodesButton(Button[RedeemUI]): def __init__(self) -> None: super().__init__( - label=LocaleStr("Redeem codes", key="redeem_codes_button.label"), + label=LocaleStr(key="redeem_codes_button.label"), emoji=GIFT_OUTLINE, style=ButtonStyle.blurple, ) async def callback(self, i: Interaction) -> None: - modal = GiftCodeModal( - title=LocaleStr("Enter redemption codes", key="gift_code_modal.title") - ) + modal = GiftCodeModal(title=LocaleStr(key="gift_code_modal.title")) modal.translate(self.view.locale, self.view.translator) await i.response.send_modal(modal) @@ -116,9 +107,7 @@ async def callback(self, i: Interaction) -> None: class AutoRedeemToggle(ToggleButton[RedeemUI]): def __init__(self, current_toggle: bool) -> None: - super().__init__( - current_toggle, LocaleStr("Auto code redemption", key="auto_redeem_toggle.label"), row=0 - ) + super().__init__(current_toggle, LocaleStr(key="auto_redeem_toggle.label"), row=0) async def callback(self, i: Interaction) -> None: await super().callback(i) diff --git a/hoyo_buddy/ui/settings.py b/hoyo_buddy/ui/settings.py index 03bd2b51..1f36c2f9 100644 --- a/hoyo_buddy/ui/settings.py +++ b/hoyo_buddy/ui/settings.py @@ -58,6 +58,7 @@ async def update_ui_and_save_settings(self, i: Interaction) -> None: ) # NOTE: This is a workaround for a bug in tortoise ORM + await i.client.cache.set(i.user.id, self.settings.lang) await Settings.filter(user_id=i.user.id).update( lang=self.settings.lang, dark_mode=self.settings.dark_mode ) @@ -72,7 +73,7 @@ def __init__(self, current_locale: discord.Locale | None) -> None: def _get_options(current_locale: discord.Locale | None) -> list[SelectOption]: options: list[SelectOption] = [ SelectOption( - label=LocaleStr("Follow client language", key="auto_locale_option_label"), + label=LocaleStr(key="auto_locale_option_label"), value="auto", emoji="🏳️", default=not current_locale, @@ -104,7 +105,7 @@ class DarkModeToggle(ToggleButton["SettingsUI"]): def __init__(self, current_toggle: bool) -> None: super().__init__( current_toggle, - LocaleStr("Dark mode", key="dark_mode_button_label"), + LocaleStr(key="dark_mode_button_label"), ) async def callback(self, i: Interaction) -> Any: diff --git a/l10n/de.yaml b/l10n/de.yaml index f2725df4..2f488396 100644 --- a/l10n/de.yaml +++ b/l10n/de.yaml @@ -1,505 +1,505 @@ -about_command.contribute: '' -about_command.developer: '' -about_command.discord_server: '' -about_command.guild_count: '' -about_command.invite: '' -about_command.latest_changes: '' -about_command.ram_usage: '' -about_command.support: '' -about_command.translators: '' -about_command.uptime: '' -about_command.website: '' -about_command_description: '' -about_embed.description: '' -abundance: '' -abyss.battles_won_fought: '' -abyss.current: '' -abyss.deepest_descent: '' -abyss.floor: '' -abyss.most_defeats: '' -abyss.most_dmg_taken: '' -abyss.most_skills: '' -abyss.most_ults: '' -abyss.overview: '' -abyss.phase_select.placeholder: '' -abyss.previous: '' -abyss.strongest_strike: '' -abyss.total_stars: '' -abyss__command_description: '' -abyss_chamber.challenge_target.embed.field.name: '' -abyss_chamber.embed.title: '' -abyss_chamber.enemy_level.embed.field.name: '' -abyss_chamber.ley_line_disorder.embed.field.name: '' -abyss_command_description: '' -abyss_enemy.item_description: '' -account_autocomplete_no_default_param_description: '' -account_autocomplete_param_description: '' -account_autocomplete_param_name: '' -account_deleted_description: '' -account_deleted_title: '' -account_game: '' -account_manager_footer: '' -account_manager_no_accounts_description: '' -account_manager_title: '' -account_not_found_error_message: '' -account_not_found_error_title: '' -account_server: '' -account_username: '' -accounts_command_description: '' -action_in_cooldown_error_message: '' -action_in_cooldown_error_title: '' -add_account_button_label: '' -add_hoyolab_acc.embed.description: '' -add_hoyolab_acc.embed.title: '' -add_miyoushe_acc.embed.description: '' -add_miyoushe_acc.enter_mobile_number: '' -add_miyoushe_acc.mobile_number: '' -add_miyoushe_acc.with_mobile_number: '' -adding_accounts_description: '' -adding_accounts_title: '' -ai_gen_image_error_message: '' -ai_gen_image_error_title: '' -already_claimed_description: '' -already_claimed_title: '' -anemo: '' -artifact_set_four_piece_embed_description: '' -artifact_set_two_piece_embed_description: '' -artifact_sets: '' -auto_checkin_button_label: '' -auto_locale_option_label: '' -auto_redeem_error.content: '' -auto_redeem_footer: '' -auto_redeem_toggle.label: '' -books: '' -captcha.embed.description: '' -challenge_command_description: '' -challenge_type_select.placeholder: '' -chamber_button_label: '' -change_character_level_label: '' -change_skill_level_label: '' -change_talent_level_label: '' -change_weapon_level_label: '' -chara_level.modal.title: '' -character_const_page_label: '' -character_embed_description: '' -character_passives_page_label: '' -character_profile_page_label: '' -character_quotes_page_label: '' -character_skills_page_label: '' -character_stories_page_label: '' -character_talents_page_label: '' -character_voices_page_label: '' -characters: '' -characters.embed.element_filters: '' -characters.embed.element_max_friendship: '' -characters.embed.element_not_max_friendship: '' -characters.embed.max_friendship: '' -characters.embed.not_max_friendship: '' -characters.embed.owned_characters: '' -characters.embed.path_filters: '' -characters.embed.title: '' -characters.filter.element.placeholder: '' -characters.filter.max_friendship: '' -characters.filter.none: '' -characters.filter.not_max_friendship: '' -characters.filter.path.placeholder: '' -characters.filter.placeholder: '' -characters.first_time.embed.description: '' -characters.first_time.title: '' -characters.gi.embed.footer: '' -characters.hsr.embed.footer: '' -characters.sorter.constellation: '' -characters.sorter.eidolon: '' -characters.sorter.element: '' -characters.sorter.friendship: '' -characters.sorter.level: '' -characters.sorter.path: '' -characters.sorter.placeholder: '' -characters.sorter.rarity: '' -characters.update_talent_data: '' -characters.update_talent_data.embed.description: '' -characters.update_talent_data.title: '' -characters_command_description: '' -checkin_button_label: '' -checkin_command_description: '' -complete_captcha_button_label: '' -complete_geetest_button_description: '' -complete_geetest_button_label: '' -const_refine_str: '' -continue_button_label: '' -cookies_button_label: '' -cookies_modal_placeholder: '' -cryo: '' -daily_button.label: '' -daily_check_in: '' -daily_checkin_embed_description: '' -daily_checkin_embed_title: '' -daily_modal.title: '' -daily_training_button.label: '' -dark_mode_button_label: '' -delete_account_button_label: '' -dendro: '' -destruction: '' -devtools_button_label: '' -devtools_instructions_description: '' -dice_cost_embed_field_name: '' -domain-type.characters: '' -domain-type.weapons: '' -download_image_failed_error_message: '' -download_image_failed_error_title: '' -edit_nickname_button_label: '' -edit_nickname_modal_title: '' -eidolon_superimpose_str: '' -electro: '' -email-geetest.embed.title: '' -email_password_button_label: '' -email_password_instructions_description: '' -email_password_modal_email_input_label: '' -email_password_modal_password_input_label: '' -enter_email_password_button_label: '' -enter_email_password_instructions_description: '' -enter_light_cone_level.button.label: '' -error_footer: '' -error_title: '' -erudition: '' -exceptions.card_not_ready_error.message: '' -exceptions.card_not_ready_error.title: '' -exped.embed.description: '' -exped_button.label: '' -exped_modal.title: '' -exploration.anemoculi: '' -exploration.chests: '' -exploration.common_chests: '' -exploration.dendroculi: '' -exploration.electroculi: '' -exploration.exquisite_chests: '' -exploration.geoculi: '' -exploration.hydroculi: '' -exploration.luxurious_chests: '' -exploration.placeholder: '' -exploration.placeholder_quote: '' -exploration.precious_chests: '' -exploration.progress: '' -exploration.remarkable_chests: '' -exploration.reputation: '' -exploration.title: '' -exploration.waypoints: '' -exploration_command_description: '' -farm_add_command.item_already_in_list: '' -farm_add_command.item_already_in_list_description: '' -farm_add_command_description: '' -farm_check.farmable_today: '' -farm_check.use_farm_notify: '' -farm_notify.add_item: '' -farm_notify.add_item.embed.description: '' -farm_notify.description: '' -farm_notify.empty: '' -farm_notify.empty_description: '' -farm_notify.remove_item: '' -farm_notify.remove_item.embed.description: '' -farm_notify.title: '' -farm_reminder_command_description: '' -farm_remove_command.item_not_found: '' -farm_remove_command.item_not_found_description: '' -farm_remove_command_description: '' -farm_view.happy_farming: '' -farm_view.set_reminder: '' -farm_view.set_reminder.embed.description: '' -farm_view.sundays: '' -farm_view.weekday_select.placeholder: '' -farm_view_command_description: '' -feedback_button.feedback_sent.description: '' -feedback_button.feedback_sent.title: '' -feedback_button.label: '' -feedback_command.description: '' -feedback_command_description: '' -feedback_modal.feedback.label: '' -fire: '' -floor_select_label: '' -fontaine: '' -food: '' -friday: '' -furnishing_sets: '' -furnishings: '' -furniture_embed_description: '' -game_maintenance_description: '' -game_maintenance_title: '' -game_value_incomplete_param_error_message: '' -geeetest_verification_complete: '' -geeetest_verification_timeout: '' -geeetest_verification_timeout_description: '' -geetest.embed.title: '' -geetest.no_need: '' -geetest.no_need.description: '' -geetest.required: '' -geetest.required.description: '' -geetest_command_description: '' -geetest_command_type_param_description: '' -geetest_command_type_param_name: '' -genshin_impact: '' -geo: '' -gi_daily.embed.description: '' -gift_code_modal.code_input.label: '' -gift_code_modal.title: '' -guild_only_feature_error_message: '' -guild_only_feature_error_title: '' -harmony: '' -honkai:_star_rail: '' -honkai_impact_3rd: '' -hoyolab: '' -hsr_daily.embed.description: '' -hydro: '' -ice: '' -imaginary: '' -inazuma: '' -incomplete_param_error_title: '' -instructions_title: '' -interaction_failed_description: '' -interaction_failed_title: '' -invalid_category_selected: '' -invalid_color_error_message: '' -invalid_color_error_title: '' -invalid_cookies_description: '' -invalid_cookies_title: '' -invalid_email_password_description: '' -invalid_email_password_title: '' -invalid_game_selected: '' -invalid_image_url_error_message: '' -invalid_image_url_error_title: '' -invalid_input.input_needs_to_be_bool: '' -invalid_input.input_needs_to_be_int: '' -invalid_input.input_out_of_range.max_value: '' -invalid_input.input_out_of_range.min_value: '' -invalid_input_error_title: '' -invalid_query_error_message: '' -invalid_query_error_title: '' -invalid_verification_code_description: '' -invalid_verification_code_title: '' -items: '' -javascript_button_label: '' -javascript_instructions_description: '' -level_label: '' -level_str: '' -light_cones: '' -living_beings: '' -liyue: '' -loading_text: '' -make_up_for_checkin_button_label: '' -materials: '' -memory_of_chaos: '' -miyoushe: '' -mobile_instructions_description: '' -monday: '' -mondstadt: '' -namecards: '' -next_page_option_label: '' -nickname_modal_label: '' -nickname_modal_placeholder: '' -nihility: '' -no_abyss_data_error_message: '' -no_abyss_data_error_title: '' -no_account_found_for_games_error_message: '' -no_account_found_for_games_error_title: '' -no_accounts_autocomplete_choice: '' -no_characters_found_error_message: '' -no_characters_found_error_title: '' -no_game_accounts_error_message: '' -no_game_accounts_error_title: '' -notes-card.gi.completed: '' -notes-card.gi.daily-commissions: '' -notes-card.gi.expedition-finished: '' -notes-card.gi.expedition-remaining: '' -notes-card.gi.realm-currency: '' -notes-card.gi.realtime-notes: '' -notes-card.gi.remaining: '' -notes-card.gi.resin: '' -notes-card.gi.resin-discounts: '' -notes-card.hsr.daily-training: '' -notes-card.hsr.echo-of-war-discounts: '' -notes-card.hsr.reserved-power: '' -notes-card.hsr.trailblaze-power: '' -notes.item_full_in_time: '' -notes_available: '' -notes_command_description: '' -notif.embed.footer: '' -notif_modal.enabled.label: '' -notif_modal.max_notif_count.label: '' -notif_modal.notify_interval.label: '' -notif_modal.notify_time.label: '' -notif_modal.notify_weekday.label: '' -notif_modal.threshold.label: '' -notification_settings_button_label: '' -notify_on_failure_button_label: '' -notify_on_success_button_label: '' -nsfw_prompt_error_message: '' -nsfw_prompt_error_title: '' -page_footer: '' -physical: '' -player_not_found_description: '' -player_not_found_title: '' -preservation: '' -prev_page_option_label: '' -primogems: '' -process_notify_error.content: '' -profile.add_image.button.label: '' -profile.add_image_modal.image_url.label: '' -profile.add_image_modal.title: '' -profile.build.select.placeholder: '' -profile.card_info.embed.description: '' -profile.card_info.embed.title: '' -profile.card_settings.button.label: '' -profile.card_template_select.diff_author.description: '' -profile.card_template_select.encard.label: '' -profile.card_template_select.enka_classic.label: '' -profile.card_template_select.enkacard.label: '' -profile.card_template_select.hb.label: '' -profile.card_template_select.placeholder: '' -profile.card_template_select.same_author.description: '' -profile.card_template_select.src.label: '' -profile.character_select.cached_data.description: '' -profile.character_select.description: '' -profile.character_select.enka_network.description: '' -profile.character_select.hoyolab.description: '' -profile.character_select.live_data.description: '' -profile.character_select.placeholder: '' -profile.dark_mode.button.label: '' -profile.generate_ai_art.button.label: '' -profile.generate_ai_art_modal.negative_prompt.label: '' -profile.generate_ai_art_modal.prompt.label: '' -profile.generate_ai_art_modal.title: '' -profile.genshin.character_select.description: '' -profile.image_select.custom_image.label: '' -profile.image_select.default_collection.label: '' -profile.image_select.none.label: '' -profile.image_select.placeholder: '' -profile.info.embed.custom_images.name: '' -profile.info.embed.custom_images.value: '' -profile.info.embed.dark_mode.name: '' -profile.info.embed.dark_mode.value: '' -profile.info.embed.primary_color.name: '' -profile.info.embed.primary_color.value: '' -profile.info.embed.templates.name: '' -profile.info.embed.templates.value: '' -profile.info.embed.title: '' -profile.player_info.button.label: '' -profile.player_info.embed.description: '' -profile.player_info.gi.embed.description: '' -profile.player_info.hoyolab.embed.description: '' -profile.primary_color.button.label: '' -profile.primary_color_modal.color.label: '' -profile.primary_color_modal.title: '' -profile.remove_from_cache.button.label: '' -profile.remove_image.button.label: '' -profile_command_description: '' -profile_command_game_value_description: '' -profile_command_uid_param_description: '' -pt_button.label: '' -pt_modal.title: '' -public_account_toggle.label: '' -pure_fiction: '' -pyro: '' -qrcode_button_label: '' -qrcode_confirmed.desc: '' -qrcode_expired.desc: '' -qrcode_expired_title: '' -qrcode_login_instructions.desc: '' -qrcode_scanned.desc: '' -quantum: '' -read_story.button.label: '' -real_time_notes: '' -realm_curr_button.label: '' -realm_curr_modal.title: '' -redeeem_code.cookie_token_expired_description: '' -redeeem_code.cookie_token_expired_title: '' -redeeem_code.cookie_token_refresh_failed_description: '' -redeeem_code.cookie_token_refresh_failed_title: '' -redeem_code.already_claimed: '' -redeem_code.cooldown: '' -redeem_code.expired: '' -redeem_code.invalid: '' -redeem_code.success: '' -redeem_codes_button.label: '' -redeem_command_description: '' -redeem_command_embed.description: '' -redeem_command_embed.title: '' -redeem_cooldown_embed.description: '' -redeem_cooldown_embed.title: '' -refinement_indicator: '' -relics: '' -reminder_button.label: '' -reminder_settings.not_set: '' -reminder_settings.reminde.set.type1: '' -reminder_settings.reminde.set.type2: '' -reminder_settings.reminde.set.type3: '' -reminder_settings.reminde.set.type4: '' -reminder_settings_title: '' -reminder_toggle: '' -resin_discount.embed.description: '' -resin_reminder_button.label: '' -resin_reminder_modal.title: '' -reward_claimed_title: '' -rtbp_reminder_button.label: '' -rtbp_reminder_modal.title: '' -saturday: '' -search_autocomplete_no_results: '' -search_autocomplete_not_setup: '' -search_command_category_param_description: '' -search_command_category_param_name: '' -search_command_description: '' -search_command_game_param_description: '' -search_command_game_param_name: '' -search_command_query_param_description: '' -search_command_query_param_name: '' -select_account.embed.description: '' -select_account.embed.title: '' -select_accounts_to_add_placeholder: '' -settings_command_description: '' -skill_attributes_embed_field_name: '' -skill_level.modal.title: '' -spiral_abyss: '' -stats_embed_field_name: '' -sumeru: '' -sunday: '' -superposition_indicator: '' -talent_level.modal.title: '' -tbp_reminder_button.label: '' -tbp_reminder_modal.title: '' -tcg: '' -the_hunt: '' -threshold.embed.description: '' -thunder: '' -thursday: '' -toggle_off_text: '' -toggle_on_text: '' -traditional_chinese_server: '' -try_other_method_error_message: '' -try_other_method_error_title: '' -tuesday: '' -unreleased_content: '' -user_autocomplete_param_description: '' -user_autocomplete_param_name: '' -user_no_accounts_autocomplete_choice: '' -view_card_button_label: '' -view_dictionary_button_label: '' -volume_selector_placeholder: '' -wave_button_label: '' -weapon_level.modal.title: '' -weapons: '' -wednesday: '' -week_boss_button.label: '' -week_boss_modal.title: '' -wind: '' -yatta_character_detail_page_label: '' -yatta_character_eidolon_page_label: '' -yatta_character_embed_description: '' -yatta_character_skill_aoe_weakness_break_field_value: '' -yatta_character_skill_energy_field_name: '' -yatta_character_skill_energy_generation_field_value: '' -yatta_character_skill_energy_need_field_value: '' -yatta_character_skill_page_label: '' -yatta_character_skill_single_weakness_break_field_value: '' -yatta_character_skill_spread_weakness_break_field_value: '' -yatta_character_skill_weakness_break_field_name: '' -yatta_character_trace_page_label: '' -yatta_item_sources_field_name: '' -yatta_light_cone_ability_field_name: '' +about_command.contribute: "" +about_command.developer: "" +about_command.discord_server: "" +about_command.guild_count: "" +about_command.invite: "" +about_command.latest_changes: "" +about_command.ram_usage: "" +about_command.support: "" +about_command.translators: "" +about_command.uptime: "" +about_command.website: "" +about_command_description: "" +about_embed.description: "" +abundance: "" +abyss.battles_won_fought: "" +abyss.current: "" +abyss.deepest_descent: "" +abyss.floor: "" +abyss.most_defeats: "" +abyss.most_dmg_taken: "" +abyss.most_skills: "" +abyss.most_ults: "" +abyss.overview: "" +abyss.phase_select.placeholder: "" +abyss.previous: "" +abyss.strongest_strike: "" +abyss.total_stars: "" +abyss__command_description: "" +abyss_chamber.challenge_target.embed.field.name: "" +abyss_chamber.embed.title: "" +abyss_chamber.enemy_level.embed.field.name: "" +abyss_chamber.ley_line_disorder.embed.field.name: "" +abyss_command_description: "" +abyss_enemy.item_description: "" +acc_no_default_param_desc: "" +account_autocomplete_param_description: "" +account_autocomplete_param_name: "" +account_deleted_description: "" +account_deleted_title: "" +account_game: "" +account_manager_footer: "" +account_manager_no_accounts_description: "" +account_manager_title: "" +account_not_found_error_message: "" +account_not_found_error_title: "" +account_server: "" +account_username: "" +accounts_command_description: "" +action_in_cooldown_error_message: "" +action_in_cooldown_error_title: "" +add_account_button_label: "" +add_hoyolab_acc.embed.description: "" +add_hoyolab_acc.embed.title: "" +add_miyoushe_acc.embed.description: "" +add_miyoushe_acc.enter_mobile_number: "" +add_miyoushe_acc.mobile_number: "" +add_miyoushe_acc.with_mobile_number: "" +adding_accounts_description: "" +adding_accounts_title: "" +ai_gen_image_error_message: "" +ai_gen_image_error_title: "" +already_claimed_description: "" +already_claimed_title: "" +anemo: "" +artifact_set_four_piece_embed_description: "" +artifact_set_two_piece_embed_description: "" +artifact_sets: "" +auto_checkin_button_label: "" +auto_locale_option_label: "" +auto_redeem_error.content: "" +auto_redeem_footer: "" +auto_redeem_toggle.label: "" +books: "" +captcha.embed.description: "" +challenge_command_description: "" +challenge_type_select.placeholder: "" +chamber_button_label: "" +change_character_level_label: "" +change_skill_level_label: "" +change_talent_level_label: "" +change_weapon_level_label: "" +chara_level.modal.title: "" +character_const_page_label: "" +character_embed_description: "" +character_passives_page_label: "" +character_profile_page_label: "" +character_quotes_page_label: "" +character_skills_page_label: "" +character_stories_page_label: "" +character_talents_page_label: "" +character_voices_page_label: "" +characters: "" +characters.embed.element_filters: "" +characters.embed.element_max_friendship: "" +characters.embed.element_not_max_friendship: "" +characters.embed.max_friendship: "" +characters.embed.not_max_friendship: "" +characters.embed.owned_characters: "" +characters.embed.path_filters: "" +characters.embed.title: "" +characters.filter.element.placeholder: "" +characters.filter.max_friendship: "" +characters.filter.none: "" +characters.filter.not_max_friendship: "" +characters.filter.path.placeholder: "" +characters.filter.placeholder: "" +characters.first_time.embed.description: "" +characters.first_time.title: "" +characters.gi.embed.footer: "" +characters.hsr.embed.footer: "" +characters.sorter.constellation: "" +characters.sorter.eidolon: "" +characters.sorter.element: "" +characters.sorter.friendship: "" +characters.sorter.level: "" +characters.sorter.path: "" +characters.sorter.placeholder: "" +characters.sorter.rarity: "" +characters.update_talent_data: "" +characters.update_talent_data.embed.description: "" +characters.update_talent_data.title: "" +characters_command_description: "" +checkin_button_label: "" +checkin_command_description: "" +complete_captcha_button_label: "" +complete_geetest_button_description: "" +complete_geetest_button_label: "" +const_refine_str: "" +continue_button_label: "" +cookies_button_label: "" +cookies_modal_placeholder: "" +cryo: "" +daily_button.label: "" +daily_check_in: "" +daily_checkin_embed_description: "" +daily_checkin_embed_title: "" +daily_modal.title: "" +daily_training_button.label: "" +dark_mode_button_label: "" +delete_account_button_label: "" +dendro: "" +destruction: "" +devtools_button_label: "" +devtools_instructions_description: "" +dice_cost_embed_field_name: "" +domain-type.characters: "" +domain-type.weapons: "" +download_image_failed_error_message: "" +download_image_failed_error_title: "" +edit_nickname_button_label: "" +edit_nickname_modal_title: "" +eidolon_superimpose_str: "" +electro: "" +email-geetest.embed.title: "" +email_password_button_label: "" +email_password_instructions_description: "" +email_password_modal_email_input_label: "" +email_password_modal_password_input_label: "" +enter_email_password_button_label: "" +enter_email_password_instructions_description: "" +enter_light_cone_level.button.label: "" +error_footer: "" +error_title: "" +erudition: "" +exceptions.card_not_ready_error.message: "" +exceptions.card_not_ready_error.title: "" +exped.embed.description: "" +exped_button.label: "" +exped_modal.title: "" +exploration.anemoculi: "" +exploration.chests: "" +exploration.common_chests: "" +exploration.dendroculi: "" +exploration.electroculi: "" +exploration.exquisite_chests: "" +exploration.geoculi: "" +exploration.hydroculi: "" +exploration.luxurious_chests: "" +exploration.placeholder: "" +exploration.placeholder_quote: "" +exploration.precious_chests: "" +exploration.progress: "" +exploration.remarkable_chests: "" +exploration.reputation: "" +exploration.title: "" +exploration.waypoints: "" +exploration_command_description: "" +farm_add_command.item_already_in_list: "" +farm_add_command.item_already_in_list_description: "" +farm_add_command_description: "" +farm_check.farmable_today: "" +farm_check.use_farm_notify: "" +farm_notify.add_item: "" +farm_notify.add_item.embed.description: "" +farm_notify.description: "" +farm_notify.empty: "" +farm_notify.empty_description: "" +farm_notify.remove_item: "" +farm_notify.remove_item.embed.description: "" +farm_notify.title: "" +farm_reminder_command_description: "" +farm_remove_command.item_not_found: "" +farm_remove_command.item_not_found_description: "" +farm_remove_command_description: "" +farm_view.happy_farming: "" +farm_view.set_reminder: "" +farm_view.set_reminder.embed.description: "" +farm_view.sundays: "" +farm_view.weekday_select.placeholder: "" +farm_view_command_description: "" +feedback_button.feedback_sent.description: "" +feedback_button.feedback_sent.title: "" +feedback_button.label: "" +feedback_command.description: "" +feedback_command_description: "" +feedback_modal.feedback.label: "" +fire: "" +floor_select_label: "" +fontaine: "" +food: "" +friday: "" +furnishing_sets: "" +furnishings: "" +furniture_embed_description: "" +game_maintenance_description: "" +game_maintenance_title: "" +game_value_incomplete_param_error_message: "" +geeetest_verification_complete: "" +geeetest_verification_timeout: "" +geeetest_verification_timeout_description: "" +geetest.embed.title: "" +geetest.no_need: "" +geetest.no_need.description: "" +geetest.required: "" +geetest.required.description: "" +geetest_command_description: "" +geetest_cmd_type_param_desc: "" +geetest_command_type_param_name: "" +genshin_impact: "" +geo: "" +gi_daily.embed.description: "" +gift_code_modal.code_input.label: "" +gift_code_modal.title: "" +guild_only_feature_error_message: "" +guild_only_feature_error_title: "" +harmony: "" +honkai:_star_rail: "" +honkai_impact_3rd: "" +hoyolab: "" +hsr_daily.embed.description: "" +hydro: "" +ice: "" +imaginary: "" +inazuma: "" +incomplete_param_error_title: "" +instructions_title: "" +interaction_failed_description: "" +interaction_failed_title: "" +invalid_category_selected: "" +invalid_color_error_message: "" +invalid_color_error_title: "" +invalid_cookies_description: "" +invalid_cookies_title: "" +invalid_email_password_description: "" +invalid_email_password_title: "" +invalid_game_selected: "" +invalid_image_url_error_message: "" +invalid_image_url_error_title: "" +invalid_input.input_needs_to_be_bool: "" +invalid_input.input_needs_to_be_int: "" +invalid_input.input_out_of_range.max_value: "" +invalid_input.input_out_of_range.min_value: "" +invalid_input_error_title: "" +invalid_query_error_message: "" +invalid_query_error_title: "" +invalid_verification_code_description: "" +invalid_verification_code_title: "" +items: "" +javascript_button_label: "" +javascript_instructions_description: "" +level_label: "" +level_str: "" +light_cones: "" +living_beings: "" +liyue: "" +loading_text: "" +make_up_for_checkin_button_label: "" +materials: "" +memory_of_chaos: "" +miyoushe: "" +mobile_instructions_description: "" +monday: "" +mondstadt: "" +namecards: "" +next_page_option_label: "" +nickname_modal_label: "" +nickname_modal_placeholder: "" +nihility: "" +no_abyss_data_error_message: "" +no_abyss_data_error_title: "" +no_account_found_for_games_error_message: "" +no_account_found_for_games_error_title: "" +no_accounts_autocomplete_choice: "" +no_characters_found_error_message: "" +no_characters_found_error_title: "" +no_game_accounts_error_message: "" +no_game_accounts_error_title: "" +notes-card.gi.completed: "" +notes-card.gi.daily-commissions: "" +notes-card.gi.expedition-finished: "" +notes-card.gi.expedition-remaining: "" +notes-card.gi.realm-currency: "" +notes-card.gi.realtime-notes: "" +notes-card.gi.remaining: "" +notes-card.gi.resin: "" +notes-card.gi.resin-discounts: "" +notes-card.hsr.daily-training: "" +notes-card.hsr.echo-of-war-discounts: "" +notes-card.hsr.reserved-power: "" +notes-card.hsr.trailblaze-power: "" +notes.item_full_in_time: "" +notes_available: "" +notes_command_description: "" +notif.embed.footer: "" +notif_modal.enabled.label: "" +notif_modal.max_notif_count.label: "" +notif_modal.notify_interval.label: "" +notif_modal.notify_time.label: "" +notif_modal.notify_weekday.label: "" +notif_modal.threshold.label: "" +notification_settings_button_label: "" +notify_on_failure_button_label: "" +notify_on_success_button_label: "" +nsfw_prompt_error_message: "" +nsfw_prompt_error_title: "" +page_footer: "" +physical: "" +player_not_found_description: "" +player_not_found_title: "" +preservation: "" +prev_page_option_label: "" +primogems: "" +process_notify_error.content: "" +profile.add_image.button.label: "" +profile.add_image_modal.image_url.label: "" +profile.add_image_modal.title: "" +profile.build.select.placeholder: "" +profile.card_info.embed.description: "" +profile.card_info.embed.title: "" +profile.card_settings.button.label: "" +profile.card_template_select.diff_author.description: "" +profile.card_template_select.encard.label: "" +profile.card_template_select.enka_classic.label: "" +profile.card_template_select.enkacard.label: "" +profile.card_template_select.hb.label: "" +profile.card_template_select.placeholder: "" +profile.card_template_select.same_author.description: "" +profile.card_template_select.src.label: "" +profile.character_select.cached_data.description: "" +profile.character_select.description: "" +profile.character_select.enka_network.description: "" +profile.character_select.hoyolab.description: "" +profile.character_select.live_data.description: "" +profile.character_select.placeholder: "" +profile.dark_mode.button.label: "" +profile.generate_ai_art.button.label: "" +profile.generate_ai_art_modal.negative_prompt.label: "" +profile.generate_ai_art_modal.prompt.label: "" +profile.generate_ai_art_modal.title: "" +profile.genshin.character_select.description: "" +profile.image_select.custom_image.label: "" +profile.image_select.default_collection.label: "" +profile.image_select.none.label: "" +profile.image_select.placeholder: "" +profile.info.embed.custom_images.name: "" +profile.info.embed.custom_images.value: "" +profile.info.embed.dark_mode.name: "" +profile.info.embed.dark_mode.value: "" +profile.info.embed.primary_color.name: "" +profile.info.embed.primary_color.value: "" +profile.info.embed.templates.name: "" +profile.info.embed.templates.value: "" +profile.info.embed.title: "" +profile.player_info.button.label: "" +profile.player_info.embed.description: "" +profile.player_info.gi.embed.description: "" +profile.player_info.hoyolab.embed.description: "" +profile.primary_color.button.label: "" +profile.primary_color_modal.color.label: "" +profile.primary_color_modal.title: "" +profile.remove_from_cache.button.label: "" +profile.remove_image.button.label: "" +profile_command_description: "" +profile_command_game_value_description: "" +profile_command_uid_param_description: "" +pt_button.label: "" +pt_modal.title: "" +public_account_toggle.label: "" +pure_fiction: "" +pyro: "" +qrcode_button_label: "" +qrcode_confirmed.desc: "" +qrcode_expired.desc: "" +qrcode_expired_title: "" +qrcode_login_instructions.desc: "" +qrcode_scanned.desc: "" +quantum: "" +read_story.button.label: "" +real_time_notes: "" +realm_curr_button.label: "" +realm_curr_modal.title: "" +redeeem_code.cookie_token_expired_description: "" +redeeem_code.cookie_token_expired_title: "" +redeeem_code.cookie_token_refresh_failed_description: "" +redeeem_code.cookie_token_refresh_failed_title: "" +redeem_code.already_claimed: "" +redeem_code.cooldown: "" +redeem_code.expired: "" +redeem_code.invalid: "" +redeem_code.success: "" +redeem_codes_button.label: "" +redeem_command_description: "" +redeem_command_embed.description: "" +redeem_command_embed.title: "" +redeem_cooldown_embed.description: "" +redeem_cooldown_embed.title: "" +refinement_indicator: "" +relics: "" +reminder_button.label: "" +reminder_settings.not_set: "" +reminder_settings.reminde.set.type1: "" +reminder_settings.reminde.set.type2: "" +reminder_settings.reminde.set.type3: "" +reminder_settings.reminde.set.type4: "" +reminder_settings_title: "" +reminder_toggle: "" +resin_discount.embed.description: "" +resin_reminder_button.label: "" +resin_reminder_modal.title: "" +reward_claimed_title: "" +rtbp_reminder_button.label: "" +rtbp_reminder_modal.title: "" +saturday: "" +search_autocomplete_no_results: "" +search_autocomplete_not_setup: "" +search_command_category_param_description: "" +search_cmd_category_param_name: "" +search_command_description: "" +search_command_game_param_description: "" +search_command_game_param_name: "" +search_command_query_param_description: "" +search_command_query_param_name: "" +select_account.embed.description: "" +select_account.embed.title: "" +select_accounts_to_add_placeholder: "" +settings_command_description: "" +skill_attributes_embed_field_name: "" +skill_level.modal.title: "" +spiral_abyss: "" +stats_embed_field_name: "" +sumeru: "" +sunday: "" +superposition_indicator: "" +talent_level.modal.title: "" +tbp_reminder_button.label: "" +tbp_reminder_modal.title: "" +tcg: "" +the_hunt: "" +threshold.embed.description: "" +thunder: "" +thursday: "" +toggle_off_text: "" +toggle_on_text: "" +traditional_chinese_server: "" +try_other_method_error_message: "" +try_other_method_error_title: "" +tuesday: "" +unreleased_content: "" +user_autocomplete_param_description: "" +user_autocomplete_param_name: "" +user_no_accounts_autocomplete_choice: "" +view_card_button_label: "" +view_dictionary_button_label: "" +volume_selector_placeholder: "" +wave_button_label: "" +weapon_level.modal.title: "" +weapons: "" +wednesday: "" +week_boss_button.label: "" +week_boss_modal.title: "" +wind: "" +yatta_character_detail_page_label: "" +yatta_character_eidolon_page_label: "" +yatta_character_embed_description: "" +yatta_character_skill_aoe_weakness_break_field_value: "" +yatta_character_skill_energy_field_name: "" +yatta_character_skill_energy_generation_field_value: "" +yatta_character_skill_energy_need_field_value: "" +yatta_character_skill_page_label: "" +yatta_character_skill_single_weakness_break_field_value: "" +yatta_character_skill_spread_weakness_break_field_value: "" +yatta_character_skill_weakness_break_field_name: "" +yatta_character_trace_page_label: "" +yatta_item_sources_field_name: "" +yatta_light_cone_ability_field_name: "" diff --git a/l10n/en_US.yaml b/l10n/en_US.yaml index 57a5561d..5ad00fb4 100644 --- a/l10n/en_US.yaml +++ b/l10n/en_US.yaml @@ -31,7 +31,7 @@ abyss_chamber.enemy_level.embed.field.name: Enemy Level abyss_chamber.ley_line_disorder.embed.field.name: Ley Line Disorder abyss_command_description: View the current abyss enemies abyss_enemy.item_description: "HP: {HP}" -account_autocomplete_no_default_param_description: Account to run this command with +acc_no_default_param_desc: Account to run this command with account_autocomplete_param_description: "Account to run this command with, defaults to the selected one in /accounts" account_autocomplete_param_name: account account_deleted_description: "{account} has been deleted." @@ -237,7 +237,7 @@ geetest.no_need.description: "You never needed to do a geetest! What are you her geetest.required: Geetest Verification Required geetest.required.description: "Use the command, choose the account that triggered the geetest, and choose `{geetest_type}` to complete the verification" geetest_command_description: Complete geetest verification -geetest_command_type_param_description: Type of geetest verification +geetest_cmd_type_param_desc: Type of geetest verification geetest_command_type_param_name: type genshin_impact: Genshin Impact geo: Geo @@ -259,7 +259,7 @@ incomplete_param_error_title: The Given Command Parameters are Incomplete instructions_title: Instructions interaction_failed_description: "This view is not initiated by you, therefore you cannot use it." interaction_failed_title: Interaction Failed -invalid_category_selected: Invalid game selected +invalid_category_selected: Invalid category selected invalid_color_error_message: "A valid color needs to be a hexadecimal color code, e.g. #FF0000" invalid_color_error_title: Invalid Color invalid_cookies_description: Refresh your cookies by adding your accounts again using @@ -365,9 +365,9 @@ profile.card_template_select.placeholder: Select a template profile.card_template_select.same_author.description: "Designed and programmed by {author}" profile.card_template_select.src.label: "StarRailCard template {num}" profile.character_select.cached_data.description: Cached data -profile.character_select.description: "Lv.{level} | E{eidolons}S{superposition} | {data_type} | From in-game showcase" +profile.character_select.description: "E{eidolons}S{superposition} | {data_type} | In-game showcase" profile.character_select.enka_network.description: Enka Network build -profile.character_select.hoyolab.description: "Lv.{level} | E{eidolons}S{superposition} | {data_type} | From HoYoLAB" +profile.character_select.hoyolab.description: "E{eidolons}S{superposition} | {data_type} | HoYoLAB" profile.character_select.live_data.description: Real-time data profile.character_select.placeholder: Select a character profile.dark_mode.button.label: Dark Mode @@ -375,7 +375,7 @@ profile.generate_ai_art.button.label: Generate AI art profile.generate_ai_art_modal.negative_prompt.label: Negative Prompt profile.generate_ai_art_modal.prompt.label: Prompt profile.generate_ai_art_modal.title: Generate AI Art -profile.genshin.character_select.description: "Lv.{level} | C{const}R{refine} | {data_type}" +profile.genshin.character_select.description: "C{const}R{refine} | {data_type}" profile.image_select.custom_image.label: "Custom Image ({num})" profile.image_select.default_collection.label: "Hoyo Buddy Collection ({num})" profile.image_select.none.label: Official art @@ -452,7 +452,7 @@ saturday: Saturday search_autocomplete_no_results: No results found search_autocomplete_not_setup: "Search autocomplete choices not set up yet, please try again later." search_command_category_param_description: Category to search in -search_command_category_param_name: category +search_cmd_category_param_name: category search_command_description: Search anything game related search_command_game_param_description: Game to search in search_command_game_param_name: game @@ -522,3 +522,4 @@ login_detail_modal.input_label: Login details enter_login_details_button_label: Enter login details not_implemented_error_title: Not Implemented not_implemented_error_message: "This feature is not implemented for `{game}` under platform `{platform}` yet." +profile.build.current.label: Current diff --git a/l10n/fr.yaml b/l10n/fr.yaml index 7f59bd64..1fdc8ec0 100644 --- a/l10n/fr.yaml +++ b/l10n/fr.yaml @@ -31,7 +31,7 @@ abyss_chamber.enemy_level.embed.field.name: Niveau des ennemis abyss_chamber.ley_line_disorder.embed.field.name: "" abyss_command_description: Voir les ennemis actuels de l'abysse abyss_enemy.item_description: "PV: {HP}" -account_autocomplete_no_default_param_description: "" +acc_no_default_param_desc: "" account_autocomplete_param_description: "Compte avec lequel exécuter cette commande, par défaut le compte sélectionné dans /accounts" account_autocomplete_param_name: compte account_deleted_description: "{account}a été supprimé" @@ -178,7 +178,7 @@ exploration.geoculi: "" exploration.hydroculi: "" exploration.luxurious_chests: "" exploration.placeholder: "" -exploration.placeholder_quote: '' +exploration.placeholder_quote: "" exploration.precious_chests: "" exploration.progress: "" exploration.remarkable_chests: "" @@ -235,7 +235,7 @@ geetest.no_need.description: "" geetest.required: "" geetest.required.description: "" geetest_command_description: "" -geetest_command_type_param_description: "" +geetest_cmd_type_param_desc: "" geetest_command_type_param_name: "" genshin_impact: Genshin Impact geo: "" @@ -450,7 +450,7 @@ saturday: Samedi search_autocomplete_no_results: "" search_autocomplete_not_setup: "" search_command_category_param_description: Dans quelle catégorie rechercher -search_command_category_param_name: catégorie +search_cmd_category_param_name: catégorie search_command_description: Recherchez tout ce qui concerne les jeux search_command_game_param_description: Dans quelle jeux rechercher search_command_game_param_name: jeux diff --git a/l10n/id.yaml b/l10n/id.yaml index c7ff3dd5..5f9c31d1 100644 --- a/l10n/id.yaml +++ b/l10n/id.yaml @@ -31,7 +31,7 @@ abyss_chamber.enemy_level.embed.field.name: Level Musuh abyss_chamber.ley_line_disorder.embed.field.name: Gangguan Ley Line abyss_command_description: Lihat musuh abyss saat ini abyss_enemy.item_description: "HP: {HP}" -account_autocomplete_no_default_param_description: Akun untuk menjalankan perintah ini +acc_no_default_param_desc: Akun untuk menjalankan perintah ini account_autocomplete_param_description: "Akun untuk menjalankan perintah ini, defaultnya adalah akun yang dipilih di /accounts" account_autocomplete_param_name: akun account_deleted_description: "{account} sudah dihapus." @@ -178,7 +178,8 @@ exploration.geoculi: "Geoculus: {geoculi}" exploration.hydroculi: "Hydroculus: {hydroculi}" exploration.luxurious_chests: Luxurious exploration.placeholder: Belum rilis -exploration.placeholder_quote: '"Setiap perjalanan pasti ada akhirnya, tidak perlu terburu-buru." +exploration.placeholder_quote: + '"Setiap perjalanan pasti ada akhirnya, tidak perlu terburu-buru." -Zhongli' exploration.precious_chests: Precious @@ -237,7 +238,7 @@ geetest.no_need.description: "Kamu tidak perlu melalukan geetest! Kenapa kamu di geetest.required: Diperlukan Verifikasi Geetest geetest.required.description: "" geetest_command_description: Lengkapi verifikasi geetest -geetest_command_type_param_description: Jenis untuk verifikasi geetest +geetest_cmd_type_param_desc: Jenis untuk verifikasi geetest geetest_command_type_param_name: jenis genshin_impact: Genshin Impact geo: Geo @@ -452,7 +453,7 @@ saturday: Sabtu search_autocomplete_no_results: Hasil tidak ditemukan search_autocomplete_not_setup: "Pilihan pelengkapan otomatis penelusuran belum disiapkan, coba lagi nanti." search_command_category_param_description: Pencarian kategori -search_command_category_param_name: kategori +search_cmd_category_param_name: kategori search_command_description: Cari apa pun yang berhubungan dengan game search_command_game_param_description: Pencarian game search_command_game_param_name: game diff --git a/l10n/ja.yaml b/l10n/ja.yaml index 7594a0fe..991140a9 100644 --- a/l10n/ja.yaml +++ b/l10n/ja.yaml @@ -31,7 +31,7 @@ abyss_chamber.enemy_level.embed.field.name: 敵レベル abyss_chamber.ley_line_disorder.embed.field.name: 地脈異常 abyss_command_description: 現在の深境螺旋の敵を見る abyss_enemy.item_description: "HP:{HP}" -account_autocomplete_no_default_param_description: このコマンドを実行するアカウントを選択 +acc_no_default_param_desc: このコマンドを実行するアカウントを選択 account_autocomplete_param_description: "このコマンドを実行するアカウント。デフォルトは/accountsで選択したアカウントです。" account_autocomplete_param_name: アカウント account_deleted_description: "{account}は削除されました" @@ -178,7 +178,7 @@ exploration.geoculi: "" exploration.hydroculi: "" exploration.luxurious_chests: "" exploration.placeholder: "" -exploration.placeholder_quote: '' +exploration.placeholder_quote: "" exploration.precious_chests: "" exploration.progress: "" exploration.remarkable_chests: "" @@ -235,7 +235,7 @@ geetest.no_need.description: "" geetest.required: "" geetest.required.description: "" geetest_command_description: "" -geetest_command_type_param_description: "" +geetest_cmd_type_param_desc: "" geetest_command_type_param_name: "" genshin_impact: 原神 geo: "" @@ -450,7 +450,7 @@ saturday: "" search_autocomplete_no_results: "" search_autocomplete_not_setup: "" search_command_category_param_description: 検索対象のカテゴリー -search_command_category_param_name: カテゴリー +search_cmd_category_param_name: カテゴリー search_command_description: ゲーム関連についてなんでも検索 search_command_game_param_description: 検索対象のゲーム search_command_game_param_name: ゲーム diff --git a/l10n/nl.yaml b/l10n/nl.yaml index 6f14a0c0..66686b72 100644 --- a/l10n/nl.yaml +++ b/l10n/nl.yaml @@ -31,7 +31,7 @@ abyss_chamber.enemy_level.embed.field.name: Vijand Niveau abyss_chamber.ley_line_disorder.embed.field.name: Ley Lijn Stoornis abyss_command_description: Bekijk de huidige vijanden van de abyss abyss_enemy.item_description: "HP: {HP}" -account_autocomplete_no_default_param_description: "" +acc_no_default_param_desc: "" account_autocomplete_param_description: "Account om deze commando mee uit te voeren, standaard de geselecteerde account in /accounts" account_autocomplete_param_name: account account_deleted_description: "{account} is verwijderd." @@ -178,7 +178,8 @@ exploration.geoculi: "Geoculi: {geoculi}" exploration.hydroculi: "Hydroculi: {hydroculi}" exploration.luxurious_chests: Luxe exploration.placeholder: Wordt nog vrijgegeven -exploration.placeholder_quote: '"Elke reis heeft zijn laatste dag. Haast je niet." +exploration.placeholder_quote: + '"Elke reis heeft zijn laatste dag. Haast je niet." - Zhongli' exploration.precious_chests: Waardevol @@ -237,7 +238,7 @@ geetest.no_need.description: "" geetest.required: "" geetest.required.description: "" geetest_command_description: "" -geetest_command_type_param_description: "" +geetest_cmd_type_param_desc: "" geetest_command_type_param_name: "" genshin_impact: Genshin Impact geo: Geo @@ -452,7 +453,7 @@ saturday: Zaterdag search_autocomplete_no_results: "" search_autocomplete_not_setup: "Autocomplete zoekkeuzes nog niet ingesteld, probeer het later nog eens." search_command_category_param_description: Categorie om in te zoeken -search_command_category_param_name: categorie +search_cmd_category_param_name: categorie search_command_description: Zoek alles wat met het spel te maken heeft search_command_game_param_description: Spel om in te zoeken search_command_game_param_name: spel diff --git a/l10n/pt_BR.yaml b/l10n/pt_BR.yaml index 53d088f0..ddd3e09c 100644 --- a/l10n/pt_BR.yaml +++ b/l10n/pt_BR.yaml @@ -31,7 +31,7 @@ abyss_chamber.enemy_level.embed.field.name: "" abyss_chamber.ley_line_disorder.embed.field.name: "" abyss_command_description: "" abyss_enemy.item_description: "" -account_autocomplete_no_default_param_description: "" +acc_no_default_param_desc: "" account_autocomplete_param_description: "" account_autocomplete_param_name: conta account_deleted_description: "{account} foi excluído " @@ -178,7 +178,7 @@ exploration.geoculi: "" exploration.hydroculi: "" exploration.luxurious_chests: "" exploration.placeholder: "" -exploration.placeholder_quote: '' +exploration.placeholder_quote: "" exploration.precious_chests: "" exploration.progress: "" exploration.remarkable_chests: "" @@ -235,7 +235,7 @@ geetest.no_need.description: "" geetest.required: "" geetest.required.description: "" geetest_command_description: "" -geetest_command_type_param_description: "" +geetest_cmd_type_param_desc: "" geetest_command_type_param_name: "" genshin_impact: Genshin Impact geo: "" @@ -450,7 +450,7 @@ saturday: "" search_autocomplete_no_results: "" search_autocomplete_not_setup: "" search_command_category_param_description: Categoria para pesquisar -search_command_category_param_name: categoria +search_cmd_category_param_name: categoria search_command_description: Pesquisar qualquer coisa relacionado a jogos search_command_game_param_description: Jogos para pesquisar search_command_game_param_name: jogo diff --git a/l10n/zh_CN.yaml b/l10n/zh_CN.yaml index 81a33f51..23b3ccf0 100644 --- a/l10n/zh_CN.yaml +++ b/l10n/zh_CN.yaml @@ -31,7 +31,7 @@ abyss_chamber.enemy_level.embed.field.name: 敌人等级 abyss_chamber.ley_line_disorder.embed.field.name: 地脉异常 abyss_command_description: 查看当前深境螺旋的敌人 abyss_enemy.item_description: "生命值:{HP}" -account_autocomplete_no_default_param_description: 用于运行此指令的帐户 +acc_no_default_param_desc: 用于运行此指令的帐户 account_autocomplete_param_description: "选择用该命令运行的账户,默认为/accounts中选择的" account_autocomplete_param_name: 账号 account_deleted_description: "{account} 已被删除" @@ -178,9 +178,9 @@ exploration.geoculi: "岩神瞳:{geoculi}" exploration.hydroculi: "水神瞳:{hydroculi}" exploration.luxurious_chests: 华丽宝箱数 exploration.placeholder: 待公开内容 -exploration.placeholder_quote: '“旅程总有一天会迎来终点,不必匆忙。” +exploration.placeholder_quote: "“旅程总有一天会迎来终点,不必匆忙。” - ————钟离' + ————钟离" exploration.precious_chests: 珍贵宝箱数 exploration.progress: "探索度:{progress}%" exploration.remarkable_chests: 奇馈宝箱数 @@ -237,7 +237,7 @@ geetest.no_need.description: "从来不需要进行 geetest 验证!你怎么 geetest.required: 需要Geetest验证 geetest.required.description: "使用指令,选择触发此验证的帐户,并选择 `{geetest_type}` 来完成验证" geetest_command_description: 完成 Geetest 验证 -geetest_command_type_param_description: Geetest 验证的类别 +geetest_cmd_type_param_desc: Geetest 验证的类别 geetest_command_type_param_name: 类别 genshin_impact: 原神 geo: 岩 @@ -452,7 +452,7 @@ saturday: 星期六 search_autocomplete_no_results: 未能找到任何结果 search_autocomplete_not_setup: "搜索自动完成选项还未设置,请稍后再试。" search_command_category_param_description: 要搜索的类别 -search_command_category_param_name: 类别 +search_cmd_category_param_name: 类别 search_command_description: 搜寻任何与游戏相关的内容 search_command_game_param_description: 要搜索的游戏 search_command_game_param_name: 游戏 diff --git a/l10n/zh_TW.yaml b/l10n/zh_TW.yaml index da100f26..7b02eb2d 100644 --- a/l10n/zh_TW.yaml +++ b/l10n/zh_TW.yaml @@ -31,7 +31,7 @@ abyss_chamber.enemy_level.embed.field.name: 敵人等級 abyss_chamber.ley_line_disorder.embed.field.name: 地脈異常 abyss_command_description: 查看當前深境螺旋的敵人 abyss_enemy.item_description: "血量: {HP}" -account_autocomplete_no_default_param_description: 用於運行此指令的帳戶 +acc_no_default_param_desc: 用於運行此指令的帳戶 account_autocomplete_param_description: "選擇用來運行指令的帳戶,默認為在 /accounts 中選擇的" account_autocomplete_param_name: 帳戶 account_deleted_description: "{account} 已被刪除。" @@ -178,9 +178,9 @@ exploration.geoculi: "岩神瞳: {geoculi}" exploration.hydroculi: "水神瞳: {hydroculi}" exploration.luxurious_chests: 華麗 exploration.placeholder: 尚未釋出 -exploration.placeholder_quote: '「旅程總有一天會迎來終點,不必匆忙。」 +exploration.placeholder_quote: "「旅程總有一天會迎來終點,不必匆忙。」 - - 鍾離' + - 鍾離" exploration.precious_chests: 珍貴 exploration.progress: "探索進度: {progress}%" exploration.remarkable_chests: 奇饋 @@ -237,7 +237,7 @@ geetest.no_need.description: "你從來不需要做 geetest 驗證!你為什 geetest.required: 需要進行 Geetest 驗證 geetest.required.description: "使用指令,選擇觸發此驗證的帳戶,並選擇 `{geetest_type}` 來完成驗證" geetest_command_description: 完成 Geetest 驗證 -geetest_command_type_param_description: Geetest 驗證的類別 +geetest_cmd_type_param_desc: Geetest 驗證的類別 geetest_command_type_param_name: 類別 genshin_impact: 原神 geo: 岩 @@ -400,7 +400,7 @@ profile.remove_from_cache.button.label: 從快取中移除 profile.remove_image.button.label: 移除自定義圖片 profile_command_description: 查看遊戲內的個人資料並生成角色面板卡片 profile_command_game_value_description: UID 所屬的遊戲 -profile_command_uid_param_description: "玩家的UID,如果提供了帳戶參數,则覆蓋該參數。" +profile_command_uid_param_description: "玩家的UID,如果提供了帳戶參數,則覆蓋該參數。" pt_button.label: 質變儀通知 pt_modal.title: 質變儀通知設定 public_account_toggle.label: 設置帳戶為公開 @@ -452,7 +452,7 @@ saturday: 星期六 search_autocomplete_no_results: 未能找到任何結果 search_autocomplete_not_setup: "搜尋自動完成選項尚未設置完成,請稍後再試。" search_command_category_param_description: 欲搜尋的分類 -search_command_category_param_name: 分類 +search_cmd_category_param_name: 分類 search_command_description: 搜尋任何與遊戲相關的內容 search_command_game_param_description: 欲搜尋的遊戲 search_command_game_param_name: 遊戲 diff --git a/poetry.lock b/poetry.lock index 360d5223..00a31222 100644 --- a/poetry.lock +++ b/poetry.lock @@ -22,6 +22,22 @@ tortoise-orm = "*" asyncmy = ["asyncmy (>=0.2.8rc1,<0.3.0)"] asyncpg = ["asyncpg"] +[[package]] +name = "aiocache" +version = "0.12.2" +description = "multi backend asyncio cache" +optional = false +python-versions = "*" +files = [ + {file = "aiocache-0.12.2-py2.py3-none-any.whl", hash = "sha256:9b6fa30634ab0bfc3ecc44928a91ff07c6ea16d27d55469636b296ebc6eb5918"}, + {file = "aiocache-0.12.2.tar.gz", hash = "sha256:b41c9a145b050a5dcbae1599f847db6dd445193b1f3bd172d8e0fe0cb9e96684"}, +] + +[package.extras] +memcached = ["aiomcache (>=0.5.2)"] +msgpack = ["msgpack (>=0.5.5)"] +redis = ["redis (>=4.2.0)"] + [[package]] name = "aiofiles" version = "23.2.1" @@ -655,7 +671,7 @@ pydantic = "^2.5.3" type = "git" url = "https://github.com/seriaati/enka-py" reference = "HEAD" -resolved_reference = "22b01ac5afba41f1876fdb550d8460e3c328dd99" +resolved_reference = "21c43b5345ed7928fe5c18029f82d7ff8389d9e9" [[package]] name = "executing" @@ -2199,4 +2215,4 @@ pydantic = ">=2.5.2,<3.0.0" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "572f0f243889832bf332cb4cb8c8e865bef482172f4591e678c78b76cc535852" +content-hash = "9218fdd10f3e9904318e5e562a280c3a82d9cbb9db163e738fd3f976cf861557" diff --git a/pyproject.toml b/pyproject.toml index 8f04e4de..31d9c353 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,6 +37,7 @@ sentry-sdk = "^2.4.0" seria-library = {git = "https://github.com/seriaati/seria-library"} tortoise-orm = {extras = ["asyncpg"], version = "^0.21.0"} yatta-py = "^1.3.6" +aiocache = "^0.12.2" [tool.poetry.group.dev] optional = true