From b3a50f2b27869d06134515ff5c2c9fdea054363a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Fri, 8 Mar 2024 20:29:35 -0600 Subject: [PATCH] feat: more command locales --- src/commands/ownedTanks.tsx | 12 +-- src/commands/permissions.ts | 16 ++-- src/commands/ping.ts | 25 +++--- src/commands/ratings.tsx | 2 + src/commands/searchPlayers.ts | 1 + src/commands/stats.tsx | 21 ++--- src/commands/today.ts | 14 ++- .../components/WN8Display/index.tsx | 27 ++---- src/components/AllStatsOverview/index.tsx | 24 ++++-- src/core/discord/addTierChoices.ts | 36 ++++++-- src/lang/en-US.json | 85 +++++++++++++++++++ 11 files changed, 185 insertions(+), 78 deletions(-) diff --git a/src/commands/ownedTanks.tsx b/src/commands/ownedTanks.tsx index a5584bb1e..d8e0d1abd 100644 --- a/src/commands/ownedTanks.tsx +++ b/src/commands/ownedTanks.tsx @@ -1,4 +1,3 @@ -import { SlashCommandBuilder } from 'discord.js'; import CommandWrapper from '../components/CommandWrapper'; import NoData from '../components/NoData'; import * as Tanks from '../components/Tanks'; @@ -18,7 +17,9 @@ import { tankIcon } from '../core/blitzkrieg/tankIcon'; import addTierChoices from '../core/discord/addTierChoices'; import addUsernameChoices from '../core/discord/addUsernameChoices'; import autocompleteUsername from '../core/discord/autocompleteUsername'; +import { createLocalizedCommand } from '../core/discord/createLocalizedCommand'; import resolvePlayerFromCommand from '../core/discord/resolvePlayerFromCommand'; +import { translator } from '../core/localization/translator'; import { CommandRegistry } from '../events/interactionCreate'; export const ownedTanksCommand = new Promise((resolve) => { @@ -26,13 +27,12 @@ export const ownedTanksCommand = new Promise((resolve) => { inProduction: true, inPublic: true, - command: new SlashCommandBuilder() - .setName('owned-tanks') - .setDescription("Shows a player's owned tanks") + command: createLocalizedCommand('owned-tanks') .addStringOption(addTierChoices) .addStringOption(addUsernameChoices), async handler(interaction) { + const { translate } = translator(interaction.locale); const tier = Number(interaction.options.getString('tier')); const account = await resolvePlayerFromCommand(interaction); const { id, region: server } = account; @@ -70,7 +70,9 @@ export const ownedTanksCommand = new Promise((resolve) => { ? emblemIdToURL(clanAccountInfo.clan.emblem_set_id) : undefined } - description={`Tier ${TIER_ROMAN_NUMERALS[tier as Tier]} tanks`} + description={translate('bot.commands.owned_tanks.body.subtitle', [ + TIER_ROMAN_NUMERALS[tier as Tier], + ])} /> {filteredTanks.length === 0 && ( diff --git a/src/commands/permissions.ts b/src/commands/permissions.ts index 367364d8e..186119f29 100644 --- a/src/commands/permissions.ts +++ b/src/commands/permissions.ts @@ -1,4 +1,5 @@ -import { SlashCommandBuilder } from 'discord.js'; +import { createLocalizedCommand } from '../core/discord/createLocalizedCommand'; +import { translator } from '../core/localization/translator'; import { CommandRegistry } from '../events/interactionCreate'; export const permissionsCommand = new Promise((resolve) => { @@ -6,26 +7,25 @@ export const permissionsCommand = new Promise((resolve) => { inProduction: true, inPublic: true, - command: new SlashCommandBuilder() - .setName('permissions') - .setDescription('Checks wether the bot has the required permissions'), + command: createLocalizedCommand('permissions'), async handler(interaction) { + const { t, translate } = translator(interaction.locale); // friday the 13th permissions easter egg const isFridayThe13th = new Date().getDay() === 5 && new Date().getDate() === 13; const permissions = [ [ interaction.appPermissions?.has('ViewChannel'), - 'View channels: needed for the refresh button to work', + t`bot.commands.permissions.body.view_channel`, ], [ interaction.appPermissions?.has('ReadMessageHistory'), - 'Read message history: also needed for the refresh button to work', + t`bot.commands.permissions.body.read_message_history`, ], [ interaction.appPermissions?.has('AttachFiles'), - 'Attach files: needed for image-based commands to work', + t`bot.commands.permissions.body.attach_files`, ], ]; const body = permissions @@ -38,7 +38,7 @@ export const permissionsCommand = new Promise((resolve) => { }) .join('\n'); - return `# Permissions\n${body}`; + return translate('bot.commands.permissions.body.title', [body]); }, }); }); diff --git a/src/commands/ping.ts b/src/commands/ping.ts index e02eabcd0..105cc4b44 100644 --- a/src/commands/ping.ts +++ b/src/commands/ping.ts @@ -1,4 +1,5 @@ -import { SlashCommandBuilder } from 'discord.js'; +import { createLocalizedCommand } from '../core/discord/createLocalizedCommand'; +import { translator } from '../core/localization/translator'; import { CommandRegistry } from '../events/interactionCreate'; export const pingCommand = new Promise((resolve) => { @@ -7,28 +8,28 @@ export const pingCommand = new Promise((resolve) => { inPublic: true, handlesInteraction: true, - command: new SlashCommandBuilder() - .setName('ping') - .setDescription('Check if the bot is alive') - .addSubcommand((option) => - option.setName('blitzkrieg').setDescription('Ping Blitzkrieg'), - ) - .addSubcommand((option) => - option.setName('blitz').setDescription('Ping Blitz'), - ), + command: createLocalizedCommand('ping', [ + { subcommand: 'blitzkrieg' }, + { subcommand: 'wotb' }, + ]), async handler(interaction) { + const { t, translate } = translator(interaction.locale); const subcommand = interaction.options.getSubcommand(); const executionStart = Date.now(); if (subcommand === 'blitzkrieg') { - await interaction.editReply('Pong 🏓'); + await interaction.editReply(t`bot.commands.ping.body.pong`); } else { await fetch('https://api.wotblitz.com/'); } const executionTime = Date.now() - executionStart; - interaction.editReply(`Pong 🏓 - ${executionTime}ms`); + interaction.editReply( + translate('bot.commands.ping.body.pong_with_time', [ + `${Math.round(executionTime)}`, + ]), + ); }, }); }); diff --git a/src/commands/ratings.tsx b/src/commands/ratings.tsx index fcfbf4ac2..6496eb572 100644 --- a/src/commands/ratings.tsx +++ b/src/commands/ratings.tsx @@ -256,6 +256,8 @@ export const ratingsCommand = new Promise(async (resolve) => { }, ]), + // BIG TODO: title seems to be in english + async handler(interaction) { const { t, translate } = translator(interaction.locale); const subcommand = interaction.options.getSubcommand(true) as diff --git a/src/commands/searchPlayers.ts b/src/commands/searchPlayers.ts index aa93d115b..6ca66ff17 100644 --- a/src/commands/searchPlayers.ts +++ b/src/commands/searchPlayers.ts @@ -51,6 +51,7 @@ export const searchPlayersCommand = new Promise((resolve) => { ), async handler(interaction) { + const { translate } = translator(interaction.locale); const server = interaction.options.getString('region') as Region; const name = interaction.options.getString('username')!; const limit = interaction.options.getInteger('limit') ?? 25; diff --git a/src/commands/stats.tsx b/src/commands/stats.tsx index 71f24f588..060bc9f6c 100644 --- a/src/commands/stats.tsx +++ b/src/commands/stats.tsx @@ -1,4 +1,4 @@ -import { Locale, SlashCommandBuilder } from 'discord.js'; +import { Locale } from 'discord.js'; import AllStatsOverview from '../components/AllStatsOverview'; import CommandWrapper from '../components/CommandWrapper'; import NoData from '../components/NoData'; @@ -15,6 +15,7 @@ import autocompleteTanks from '../core/discord/autocompleteTanks'; import autocompleteUsername from '../core/discord/autocompleteUsername'; import { buttonRefresh } from '../core/discord/buttonRefresh'; import commandToURL from '../core/discord/commandToURL'; +import { createLocalizedCommand } from '../core/discord/createLocalizedCommand'; import { getCustomPeriodParams } from '../core/discord/getCustomPeriodParams'; import { getFiltersFromButton } from '../core/discord/getFiltersFromButton'; import { getFiltersFromCommand } from '../core/discord/getFiltersFromCommand'; @@ -52,25 +53,25 @@ async function render( {!stats.battles && } {stats.battles > 0 && ( - + )} ); } export const statsCommand = new Promise(async (resolve) => { - const command = await addPeriodicFilterOptions( - new SlashCommandBuilder() - .setName('stats') - .setDescription('Regular battles statistics'), - (option) => option.addStringOption(addUsernameChoices), - ); - resolve({ inProduction: true, inPublic: true, - command, + command: await addPeriodicFilterOptions( + createLocalizedCommand('stats'), + (option) => option.addStringOption(addUsernameChoices), + ), async handler(interaction) { const player = await resolvePlayerFromCommand(interaction); diff --git a/src/commands/today.ts b/src/commands/today.ts index 26ee17f9e..1e2bc06e7 100644 --- a/src/commands/today.ts +++ b/src/commands/today.ts @@ -1,4 +1,3 @@ -import { SlashCommandBuilder } from 'discord.js'; import { NATIONS } from '../core/blitzkrieg/tankDefinitions'; import { getBlitzStarsLinkButton } from '../core/blitzstars/getBlitzStarsLinkButton'; import { addFilterOptions } from '../core/discord/addFilterOptions'; @@ -7,6 +6,7 @@ import autocompleteTanks from '../core/discord/autocompleteTanks'; import autocompleteUsername from '../core/discord/autocompleteUsername'; import { buttonRefresh } from '../core/discord/buttonRefresh'; import commandToURL from '../core/discord/commandToURL'; +import { createLocalizedCommand } from '../core/discord/createLocalizedCommand'; import { getCustomPeriodParams } from '../core/discord/getCustomPeriodParams'; import { getFiltersFromButton } from '../core/discord/getFiltersFromButton'; import { getFiltersFromCommand } from '../core/discord/getFiltersFromCommand'; @@ -19,18 +19,14 @@ import { renderBreakdown } from './breakdown'; export const todayCommand = new Promise(async (resolve) => { const nations = await NATIONS; - const command = addFilterOptions( - new SlashCommandBuilder() - .setName('today') - .setDescription("Today's played tanks and statistics"), - nations, - ).addStringOption(addUsernameChoices); - resolve({ inProduction: true, inPublic: true, - command, + command: addFilterOptions( + createLocalizedCommand('today'), + nations, + ).addStringOption(addUsernameChoices), async handler(interaction) { const player = await resolvePlayerFromCommand(interaction); diff --git a/src/components/AllStatsOverview/components/WN8Display/index.tsx b/src/components/AllStatsOverview/components/WN8Display/index.tsx index 3e33af43b..8be77a70f 100644 --- a/src/components/AllStatsOverview/components/WN8Display/index.tsx +++ b/src/components/AllStatsOverview/components/WN8Display/index.tsx @@ -1,30 +1,21 @@ +import { Locale } from 'discord.js'; import { Percentile } from '../../../../constants/percentiles'; +import { translator } from '../../../../core/localization/translator'; import getWN8Percentile from '../../../../core/statistics/getWN8Percentile'; import { theme } from '../../../../stitches.config'; import { PERCENTILE_COLORS } from '../../../PercentileIndicator'; import { Glow } from './components/Glow'; export interface WN8DisplayProps { - WN8?: number; + wn8?: number; + locale: Locale; } -export const PERCENTILE_NAMES = { - [Percentile.VeryBad]: 'Very Bad', - [Percentile.Bad]: 'Bad', - [Percentile.BelowAverage]: 'Below Average', - [Percentile.Average]: 'Average', - [Percentile.AboveAverage]: 'Above Average', - [Percentile.Good]: 'Good', - [Percentile.VeryGood]: 'Very Good', - [Percentile.Great]: 'Great', - [Percentile.Unicum]: 'Unicum', - [Percentile.SuperUnicum]: 'Super Unicum', -}; - -export function WN8Display({ WN8 }: WN8DisplayProps) { +export function WN8Display({ wn8, locale }: WN8DisplayProps) { const percentile = - WN8 === undefined ? Percentile.VeryBad : getWN8Percentile(WN8); + wn8 === undefined ? Percentile.VeryBad : getWN8Percentile(wn8); const color = PERCENTILE_COLORS[percentile]; + const { translate } = translator(locale); return (
- {WN8 === undefined ? '--' : WN8.toFixed(0)} + {wn8 === undefined ? '--' : wn8.toFixed(0)} - {PERCENTILE_NAMES[percentile]} + {translate(`common.wn8_percentile.${percentile}`)}
diff --git a/src/components/AllStatsOverview/index.tsx b/src/components/AllStatsOverview/index.tsx index 5b3f4d0f3..6868b03c0 100644 --- a/src/components/AllStatsOverview/index.tsx +++ b/src/components/AllStatsOverview/index.tsx @@ -1,4 +1,6 @@ +import { Locale } from 'discord.js'; import { AllStats, SupplementaryStats } from '../../core/blitz/getAccountInfo'; +import { translator } from '../../core/localization/translator'; import { WN8Display } from './components/WN8Display'; import { WN8SurroundingStat, @@ -8,12 +10,16 @@ import { export interface AllStatsOverviewProps { stats: AllStats; supplementaryStats: SupplementaryStats; + locale: Locale; } export default function AllStatsOverview({ stats, + locale, supplementaryStats, }: AllStatsOverviewProps) { + const { t } = translator(locale); + return (
- +
({ - name: `Tier ${tier} - ${numberToRomanNumeral(tier)}`, - value: `${tier}`, - })), + ...range(10, 0).map( + (tier) => + ({ + name: translate('bot.common.options.tier.choices.tier', [ + `${tier}`, + numberToRomanNumeral(tier), + ]), + value: `${tier}`, + name_localizations: localizationObject( + 'bot.common.options.tier.choices.tier', + [`${tier}`, numberToRomanNumeral(tier)], + ), + }) satisfies APIApplicationCommandOptionChoice, + ), ) .setRequired(true); } diff --git a/src/lang/en-US.json b/src/lang/en-US.json index 40e4e7aa9..e33d38a45 100644 --- a/src/lang/en-US.json +++ b/src/lang/en-US.json @@ -1,5 +1,18 @@ { "common": { + "wn8_percentile": { + "0": "Very bad", + "1": "Bad", + "2": "Below average", + "3": "Average", + "4": "Above average", + "5": "Good", + "6": "Very good", + "7": "Great", + "8": "Unicum", + "9": "Super unicum" + }, + "nations": { "ussr": "U.S.S.R.", "germany": "Germany", @@ -135,6 +148,15 @@ "region": { "$": "region", "description": "Region" + }, + + "tier": { + "$": "tier", + "description": "Tier", + + "choices": { + "tier": "Tier %s - %s" + } } }, @@ -386,6 +408,69 @@ "neighbors": "Ratings neighbors", "more": "+%s more" } + }, + + "today": { + "$": "today", + "description": "Today's played tanks and statistics" + }, + + "stats": { + "$": "stats", + "description": "Quick statistics for a period", + + "body": { + "battles": "Battles", + "winrate": "Winrate", + "damage": "Damage", + "damage_ratio": "Damage ratio", + "tier": "Tier", + "survival": "Survival", + "accuracy": "Accuracy", + "kill_ratio": "Kill ratio" + } + }, + + "owned_tanks": { + "$": "owned-tanks", + "description": "Shows all own tanks in a tier", + + "body": { + "subtitle": "Tier %s tanks" + } + }, + + "permissions": { + "$": "permissions", + "description": "Checks wether the bot has the required permissions to function", + + "body": { + "title": "# Permissions\n\n%s", + "view_channels": "View channels: needed for the refresh button to work", + "read_message_history": "Read message history: needed for the refresh button to find the message to refresh", + "attach_files": "Attach files: needed for image-based commands to work" + } + }, + + "ping": { + "$": "ping", + "description": "Check wether the bot is alive.", + + "body": { + "pong": "Pong 🏓", + "pong_with_time": "Pong 🏓 - %sms" + }, + + "subcommands": { + "blitzkrieg": { + "$": "blitzkrieg", + "description": "Ping Blitzkrieg" + }, + "wotb": { + "$": "wotb", + "description": "Ping World of Tanks Blitz" + } + } } } },