diff --git a/src/commands/breakdown.tsx b/src/commands/breakdown.tsx index 2eb6a3af1..a231eda2d 100644 --- a/src/commands/breakdown.tsx +++ b/src/commands/breakdown.tsx @@ -51,11 +51,11 @@ export async function renderBreakdown( const { t, translate } = translator(locale); const awaitedTankDefinitions = await tankDefinitions; const awaitedTankAverages = await tankAverages; - const statsInPeriod = await getStatsInPeriod(region, id, start, end); + const statsInPeriod = await getStatsInPeriod(region, id, start, end, locale); const { filteredOrder } = await filterStats(statsInPeriod, filters); const accountInfo = await getAccountInfo(region, id); const clanData = await getClanAccountInfo(region, id, ['clan']); - const tankStats = await getTankStats(region, id); + const tankStats = await getTankStats(region, id, locale); const filterDescriptions = await filtersToDescription(filters, locale); const orderedCurrentStats: AllStats[] = []; const orderedCareerStats: AllStats[] = []; diff --git a/src/commands/evolution.tsx b/src/commands/evolution.tsx index fce791045..52dd4c4d4 100644 --- a/src/commands/evolution.tsx +++ b/src/commands/evolution.tsx @@ -48,7 +48,7 @@ async function render( includeLatestHistories: true, includePreviousHistories: true, }) - : getTankHistories(region, id, { + : getTankHistories(region, id, locale, { tankId: tankId!, start, end, @@ -140,7 +140,9 @@ export const evolutionCommand = new Promise( const period = resolvePeriodFromCommand(player.region, interaction); const tankIdRaw = interaction.options.getString('tank')!; const tankId = - commandGroup === 'tank' ? await resolveTankId(tankIdRaw) : null; + commandGroup === 'tank' + ? await resolveTankId(tankIdRaw, interaction.locale) + : null; const path = commandToURL(interaction, { ...player, ...getCustomPeriodParams(interaction), diff --git a/src/commands/fullStats.tsx b/src/commands/fullStats.tsx index df7d870d9..2463fb113 100644 --- a/src/commands/fullStats.tsx +++ b/src/commands/fullStats.tsx @@ -41,7 +41,13 @@ async function render( const { nickname } = await getAccountInfo(region, id); const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan; const clanImage = clan ? emblemIdToURL(clan.emblem_set_id) : undefined; - const diffedTankStats = await getStatsInPeriod(region, id, start, end); + const diffedTankStats = await getStatsInPeriod( + region, + id, + start, + end, + locale, + ); const { stats, supplementary, filteredOrder } = await filterStats( diffedTankStats, filters, diff --git a/src/commands/ownedTanks.tsx b/src/commands/ownedTanks.tsx index d8e0d1abd..3b5f41033 100644 --- a/src/commands/ownedTanks.tsx +++ b/src/commands/ownedTanks.tsx @@ -37,7 +37,7 @@ export const ownedTanksCommand = new Promise((resolve) => { const account = await resolvePlayerFromCommand(interaction); const { id, region: server } = account; const accountInfo = await getAccountInfo(server, id); - const tankStats = await getTankStats(server, id); + const tankStats = await getTankStats(server, id, interaction.locale); const filteredTanks = ( await Promise.all( tankStats.map(async (tankData) => ({ diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index 060bc9f6c..eb909643e 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -39,7 +39,13 @@ async function render( const { nickname } = await getAccountInfo(region, id); const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan; const clanImage = clan ? emblemIdToURL(clan.emblem_set_id) : undefined; - const diffedTankStats = await getStatsInPeriod(region, id, start, end); + const diffedTankStats = await getStatsInPeriod( + region, + id, + start, + end, + locale, + ); const { stats, supplementary } = await filterStats(diffedTankStats, filters); const filterDescriptions = await filtersToDescription(filters, locale); diff --git a/src/core/blitz/getTankStats.ts b/src/core/blitz/getTankStats.ts index be11ffe10..918afc7ee 100644 --- a/src/core/blitz/getTankStats.ts +++ b/src/core/blitz/getTankStats.ts @@ -1,18 +1,23 @@ +import { Locale } from 'discord.js'; import { Region } from '../../constants/regions'; import { WARGAMING_APPLICATION_ID } from '../../constants/wargamingApplicationID'; import { UserError } from '../../hooks/userError'; import { TanksStats } from '../../types/tanksStats'; +import { translator } from '../localization/translator'; import fetchBlitz from './fetchBlitz'; -export default async function getTankStats(region: Region, id: number) { +export default async function getTankStats( + region: Region, + id: number, + locale: Locale, +) { + const { t } = translator(locale); const tankStats = await fetchBlitz( `https://api.wotblitz.${region}/wotb/tanks/stats/?application_id=${WARGAMING_APPLICATION_ID}&account_id=${id}`, ); if (tankStats[id] === null) { - throw new UserError( - "# No tank stats available\nThis player doesn't have any stats available. This may not be the player you are looking for.", - ); + throw new UserError(t`bot.common.errors.no_tank_stats`); } return tankStats[id]; diff --git a/src/core/blitz/resolveTankId.ts b/src/core/blitz/resolveTankId.ts index c9d555d98..ee4883ee8 100644 --- a/src/core/blitz/resolveTankId.ts +++ b/src/core/blitz/resolveTankId.ts @@ -1,12 +1,18 @@ +import { Locale } from 'discord.js'; import { go } from 'fuzzysort'; -import { UserError } from '../../hooks/userError'; import markdownEscape from 'markdown-escape'; +import { UserError } from '../../hooks/userError'; import { tankDefinitions, tanksDefinitionsArray, } from '../blitzkrieg/tankDefinitions'; +import { translator } from '../localization/translator'; -export default async function resolveTankId(tank: string | number) { +export default async function resolveTankId( + tank: string | number, + locale: Locale, +) { + const { translate } = translator(locale); const number = typeof tank === 'string' ? parseInt(tank) : tank; if (Number.isNaN(number)) { @@ -17,7 +23,9 @@ export default async function resolveTankId(tank: string | number) { if (searchResult.length === 0) { throw new UserError( - `# Tank not found\nCould not find tank by the name "${markdownEscape(`${tank}`)}".`, + translate('bot.common.errors.tank_name_not_found', [ + markdownEscape(`${tank}`), + ]), ); } else { return searchResult[0].obj.id; @@ -27,7 +35,7 @@ export default async function resolveTankId(tank: string | number) { return number; } else { throw new UserError( - `# Tank not found\nCould not find tank by the ID "${number}". Try typing the name of the tank instead of a number.`, + translate('bot.common.errors.tank_id_not_found', [`${number}`]), ); } } diff --git a/src/core/blitzkrieg/getTankHistories.ts b/src/core/blitzkrieg/getTankHistories.ts index 8ee89de4d..542a777c7 100644 --- a/src/core/blitzkrieg/getTankHistories.ts +++ b/src/core/blitzkrieg/getTankHistories.ts @@ -1,3 +1,4 @@ +import { Locale } from 'discord.js'; import { Region } from '../../constants/regions'; import { GetHistoriesOptions, @@ -34,6 +35,7 @@ export const getTankHistoriesDefaultOptions: GetTankHistoriesOptions = { export default async function getTankHistories( server: Region, id: number, + locale: Locale, options?: Partial, ) { const mergedOptions = { ...getTankHistoriesDefaultOptions, ...options }; @@ -76,7 +78,7 @@ export default async function getTankHistories( const latestNodes: TankHistories = []; if (mergedOptions.includeLatestHistories) { - (await getTankStats(server, id)).forEach((tankHistory) => { + (await getTankStats(server, id, locale)).forEach((tankHistory) => { if ( tankHistory.all.battles > (lastBattles[tankHistory.tank_id] ?? 0) && (mergedOptions.tankId === undefined || diff --git a/src/core/blitzstars/getStatsInPeriod.ts b/src/core/blitzstars/getStatsInPeriod.ts index 0a703ff07..9b20c2e64 100644 --- a/src/core/blitzstars/getStatsInPeriod.ts +++ b/src/core/blitzstars/getStatsInPeriod.ts @@ -1,3 +1,4 @@ +import { Locale } from 'discord.js'; import { Region } from '../../constants/regions'; import { AllStats } from '../blitz/getAccountInfo'; import getTankHistories, { @@ -45,8 +46,9 @@ export default async function getStatsInPeriod( id: number, start: number, end: number, + locale: Locale, ) { - const history = await getTankHistories(server, id, { + const history = await getTankHistories(server, id, locale, { includeLatestHistories: true, }); diff --git a/src/core/discord/getFiltersFromCommand.ts b/src/core/discord/getFiltersFromCommand.ts index 171316635..0ebf09157 100644 --- a/src/core/discord/getFiltersFromCommand.ts +++ b/src/core/discord/getFiltersFromCommand.ts @@ -15,6 +15,9 @@ export async function getFiltersFromCommand( treeType: (interaction.options.getString('tree-type') as TreeType | undefined) ?? undefined, - tank: tankRaw === null ? undefined : await resolveTankId(tankRaw), + tank: + tankRaw === null + ? undefined + : await resolveTankId(tankRaw, interaction.locale), } satisfies StatFilters; } diff --git a/src/core/discord/resolveClanFromCommand.ts b/src/core/discord/resolveClanFromCommand.ts index 1efe29028..ff2e709c5 100644 --- a/src/core/discord/resolveClanFromCommand.ts +++ b/src/core/discord/resolveClanFromCommand.ts @@ -3,11 +3,13 @@ import markdownEscape from 'markdown-escape'; import { Region } from '../../constants/regions'; import { UserError } from '../../hooks/userError'; import searchClansAcrossRegions from '../blitz/searchClansAcrossRegions'; +import { translator } from '../localization/translator'; import { serverAndIdPattern } from './resolvePlayerFromCommand'; export default async function resolveClanFromCommand( interaction: ChatInputCommandInteraction, ) { + const { translate } = translator(interaction.locale); const clan = interaction.options.getString('clan', true); if (serverAndIdPattern.test(clan)) { @@ -20,7 +22,7 @@ export default async function resolveClanFromCommand( return { region: accounts[0].region, id: accounts[0].clan_id }; } else { throw new UserError( - `# Could not find clan\nCouldn't find "${markdownEscape(clan)}". Try selecting a clan from the search result.`, + translate('bot.common.errors.clan_not_found', [markdownEscape(clan)]), ); } } diff --git a/src/core/discord/resolvePlayerFromCommand.ts b/src/core/discord/resolvePlayerFromCommand.ts index 93d6bc3b9..74044a20e 100644 --- a/src/core/discord/resolvePlayerFromCommand.ts +++ b/src/core/discord/resolvePlayerFromCommand.ts @@ -4,6 +4,7 @@ import { Region } from '../../constants/regions'; import { UserError } from '../../hooks/userError'; import searchPlayersAcrossRegions from '../blitz/searchPlayersAcrossRegions'; import { getBlitzFromDiscord } from '../blitzkrieg/discordBlitz'; +import { translator } from '../localization/translator'; export const serverAndIdPattern = /(com|eu|asia)\/[0-9]+/; @@ -15,6 +16,7 @@ export interface ResolvedPlayer { export default async function resolvePlayerFromCommand( interaction: ChatInputCommandInteraction, ) { + const { t, translate } = translator(interaction.locale); const commandUsername = interaction.options.getString('username'); if (commandUsername) { @@ -35,9 +37,9 @@ export default async function resolvePlayerFromCommand( } satisfies ResolvedPlayer; } else { throw new UserError( - `# Could not find user\nI couldn't find user "${markdownEscape( - commandUsername, - )}". Try picking an user from the search result, typing in a valid username, or using the \`/link\` command.`, + translate('bot.common.errors.player_not_found', [ + markdownEscape(commandUsername), + ]), ); } } @@ -47,9 +49,7 @@ export default async function resolvePlayerFromCommand( if (account) { return { region: account.region, id: account.blitz }; } else { - throw new UserError( - "# I don't know who you are\nUse the `/link` command to get started.", - ); + throw new UserError(t`bot.common.errors.player_not_linked`); } } } diff --git a/src/lang/en-US.json b/src/lang/en-US.json index c438702a2..9aeab2dbc 100644 --- a/src/lang/en-US.json +++ b/src/lang/en-US.json @@ -176,6 +176,15 @@ "battles_in_period": "No battles played in this period", "players_in_period": "No players in this period", "tanks_found": "No tanks found" + }, + + "errors": { + "clan_not_found": "# Could not find clan\nCouldn't find \"%s\". Try selecting a clan from the search result.", + "player_not_found": "# Could not find user\nI couldn't find user \"%s\". Try picking an user from the search result, typing in a valid username, or using the `/link` command.", + "player_not_linked": "# I don't know who you are\nUse the `/link` command to get started.", + "tank_name_not_found": "# Tank not found\nCould not find tank by the name \"%s\".", + "tank_id_not_found": "# Tank not found\nCould not find tank by the ID \"%s\". Try typing the name of the tank instead of a number.", + "no_tank_stats": "# No tank stats available\nThis player doesn't have any stats available. This may not be the player you are looking for." } }, @@ -478,7 +487,7 @@ "description": "Basic information about a player", "body": { - "title": "%'s information", + "title": "%s's information", "nickname": "Nickname", "battles": "Battles", "winrate": "Winrate", diff --git a/src/lang/hr-HR.json b/src/lang/hr-HR.json deleted file mode 100644 index 483211636..000000000 --- a/src/lang/hr-HR.json +++ /dev/null @@ -1,348 +0,0 @@ -{ - "common": { - "nations": { - "ussr": "U.S.S.R.", - "germany": "Germany", - "usa": "U.S.A.", - "china": "China", - "uk": "U.K.", - "france": "France", - "japan": "Japan", - "european": "European nation", - "other": "Hybrid nation" - }, - "tank_class_short": { - "lightTank": "Light", - "mediumTank": "Medium", - "heavyTank": "Heavy", - "AT-SPG": "TD" - }, - "tree_type": { - "researchable": "Tech tree", - "premium": "Premium", - "collector": "Collector" - }, - "regions": { - "normal": { - "com": "North America", - "eu": "Europe", - "asia": "Asia-Pacific" - }, - "short": { - "com": "NA", - "eu": "EU", - "asia": "APAC" - } - }, - "leagues": { - "diamond": "Diamond", - "platinum": "Platinum", - "gold": "Gold", - "silver": "Silver", - "bronze": "Bronze" - } - }, - "bot": { - "common": { - "wn8": { - "$": "WN8", - "very_bad": "Very bad", - "bad": "Bad", - "below_average": "Below average", - "average": "Average", - "above_average": "Above average", - "good": "Good", - "very_good": "Very good", - "great": "Great", - "unicum": "Unicum", - "super_unicum": "Super unicum" - }, - "subcommands": { - "today": { - "$": "today", - "description": "Today" - }, - "30": { - "$": "30", - "description": "30 days" - }, - "60": { - "$": "60", - "description": "60 days" - }, - "90": { - "$": "90", - "description": "90 days" - }, - "career": { - "$": "career", - "description": "Career" - }, - "custom": { - "$": "custom", - "description": "Custom range", - "options": { - "start": { - "$": "start", - "description": "Start in number of days ago from today" - }, - "end": { - "$": "end", - "description": "End in number of days ago from today" - } - } - } - }, - "options": { - "clan": { - "$": "clan", - "description": "The clan name or tag" - }, - "tank": { - "$": "tank", - "description": "The tank to get stats for" - }, - "username": { - "$": "username", - "description": "The Blitz username of the player" - }, - "filters": { - "nation": { - "$": "nation", - "description": "Nation" - }, - "tank_class": { - "$": "tank-class", - "description": "Tank class" - }, - "tree_type": { - "$": "tree-type", - "description": "Tree type" - } - }, - "region": { - "$": "region", - "description": "Region" - } - }, - "periods": { - "career": "Career", - "today": "Today", - "days": "%s days", - "custom": "%s - %s days" - }, - "filters": { - "none": "No filters", - "tier": "Tier %s" - }, - "no_data": { - "battles_in_period": "No battles played in this period", - "players_in_period": "No players in this period", - "tanks_found": "No tanks found" - } - }, - "commands": { - "about": { - "$": "about", - "description": "All the info you need about the bot", - "subcommands": { - "commands": { - "$": "commands", - "description": "List of all commands and their descriptions", - "body": "# Commands\n\nBlitzkrieg offers the following commands:\n\n" - }, - "embeds": { - "$": "embeds", - "description": "How embeds work" - }, - "introduction": { - "$": "introduction", - "description": "About the bot" - }, - "invite": { - "$": "invite", - "description": "How to invite the bot" - }, - "timezones": { - "$": "timezones", - "description": "How Blitzkrieg infers and uses your timezone" - }, - "creators": { - "$": "creators", - "description": "People who have worked on the bot" - } - } - }, - "breakdown": { - "$": "breakdown", - "description": "A period's breakdown by tanks played", - "body": { - "total": "Total", - "battles": "Battles", - "wn8": "WN8", - "winrate": "Winrate", - "damage": "Damage", - "unknown_tank": "Unknown tank %s" - } - }, - "debug": { - "$": "debug", - "description": "Debug information about the bot", - "body": { - "title": "# Debug\n\n", - "version": "Version", - "shard": { - "$": "Shard", - "default": "default" - }, - "uptime": "Uptime" - } - }, - "evolution": { - "$": "evolution", - "description": "Evolution of statistics", - "groups": { - "player": { - "$": "player", - "description": "Player statistics" - }, - "tank": { - "$": "tank", - "description": "Tank statistics" - } - } - }, - "inactive": { - "$": "inactive", - "description": "Lists all inactive players in a clan above a threshold", - "options": { - "threshold": { - "$": "threshold", - "description": "The number of days inactive (default: %s days)" - } - }, - "body": { - "subtitle": "Inactive for %s+ days", - "listing": "%s days" - } - }, - "full_stats": { - "$": "full-stats", - "description": "Full in-game statistics", - "body": { - "cards": { - "games": { - "$": "Games", - "winrate": "Winrate", - "battles": "Battles", - "wins_losses": "Wins / losses" - }, - "efficiency": { - "$": "Efficiency", - "wn8": "WN8", - "survival": "Survival", - "accuracy": "Accuracy" - }, - "lethality": { - "$": "Lethality", - "average_damage": "Average damage", - "damage_per_tier": "Damage per tier", - "damage_ratio": "Damage ratio", - "average_kills": "Average kills" - }, - "miscellaneous": { - "$": "Miscellaneous", - "average_tier": "Average tier", - "average_spots": "Average spots", - "average_xp": "Average XP", - "kills_to_death_ratio": "Kills to death ratio" - } - } - } - }, - "link": { - "$": "link", - "description": "Links your Blitz and Discord account", - "body": { - "accounts_linked": "Accounts linked", - "no_role_permissions": { - "$": "%s failed to verify", - "description": "I don't have the permission to manage roles." - } - }, - "embed": { - "title": "Incorrect account?", - "description": "Use the command again and select a username from the search results." - } - }, - "search_clans": { - "$": "search-clans", - "description": "Search clans", - "options": { - "limit": { - "$": "limit", - "description": "The max number of clan results (default: %s)" - } - }, - "body": { - "title": "Clan search for %s in region %s", - "no_results": "No clans found" - } - }, - "search_players": { - "$": "search-players", - "description": "Search players", - "options": { - "limit": { - "$": "limit", - "description": "The max number of player results (default: %s)" - } - }, - "body": { - "title": "Player search for %s in region %s", - "no_results": "No players found" - } - }, - "ratings": { - "$": "ratings", - "description": "Ratings battles statistics", - "subcommands": { - "neighbors": { - "$": "neighbors", - "description": "Neighboring players on the leaderboard" - }, - "league": { - "$": "league", - "description": "Top players of a league" - } - }, - "options": { - "limit": { - "$": "limit", - "description": "How many neighbors to display (default: %s)" - }, - "season": { - "$": "season", - "description": "Season number (default: current)", - "choices": { - "current": "%s (current)" - } - }, - "league": { - "$": "league", - "description": "The league to display" - } - }, - "body": { - "top_players": "Top %s players", - "no_participation": "# %s didn't play ratings in season %s\n\nThis player did not participate in this season or did not get past calibration.", - "no_ongoing_season": "# No ongoing season\n\nThere isn't a currently running ratings season.", - "deleted_player": "Deleted %s", - "neighbors": "Ratings neighbors", - "more": "+%s more" - } - } - } - }, - "website": {} -}