diff --git a/bun.lockb b/bun.lockb index 350daac17..9c71f03bf 100644 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/packages/bot/src/commands/inactive.tsx b/packages/bot/src/commands/inactive.tsx index 3e8fd4c69..55c3f2d70 100644 --- a/packages/bot/src/commands/inactive.tsx +++ b/packages/bot/src/commands/inactive.tsx @@ -26,7 +26,7 @@ export const inactiveCommand = new Promise((resolve) => { .setName('threshold') .setNameLocalizations( localizationObject( - 'bot.commands.inactive.options.threshold', + (strings) => strings.bot.commands.inactive.options.threshold.$, undefined, true, ), @@ -36,7 +36,8 @@ export const inactiveCommand = new Promise((resolve) => { ) .setDescriptionLocalizations( localizationObject( - 'bot.commands.inactive.options.threshold.description', + (strings) => + strings.bot.commands.inactive.options.threshold.description, ), ) .setMinValue(0); diff --git a/packages/bot/src/core/localization/translator.ts b/packages/bot/src/core/localization/translator.ts index de62d1505..133bf10cc 100644 --- a/packages/bot/src/core/localization/translator.ts +++ b/packages/bot/src/core/localization/translator.ts @@ -12,9 +12,7 @@ export function translator(localeRaw: Locale) { SUPPORTED_LOCALES_DISCORD.includes(localeRaw) ? localeRaw : DEFAULT_LOCALE_DISCORD; - STRINGS; const strings = STRINGS[SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale]]; - const unwrap = unwrapper(SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale]); return { locale, strings, unwrap }; diff --git a/packages/bot/src/events/interactionCreate/handlers/chatInputCommand.ts b/packages/bot/src/events/interactionCreate/handlers/chatInputCommand.ts index 02e567185..a6228f3f2 100644 --- a/packages/bot/src/events/interactionCreate/handlers/chatInputCommand.ts +++ b/packages/bot/src/events/interactionCreate/handlers/chatInputCommand.ts @@ -2,11 +2,13 @@ import { ActionRowBuilder, AttachmentBuilder, ButtonBuilder, + ButtonStyle, CacheType, ChatInputCommandInteraction, InteractionReplyOptions, } from 'discord.js'; import { InteractionRawReturnable, commands } from '..'; +import { UserError } from '../../../core/blitzkit/userError'; import { buttonLink } from '../../../core/discord/buttonLink'; import { embedWarning } from '../../../core/discord/embedWarning'; import { normalizeInteractionReturnable } from '../../../core/discord/normalizeInteractionReturnable'; @@ -124,26 +126,27 @@ export async function handleChatInputCommand( index++; } } catch (error) { - const { t } = translator(interaction.locale); - // const components = [ - // new ActionRowBuilder().addComponents( - // new ButtonBuilder() - // .setLabel(t`bot.common.errors.get_help`) - // .setURL('https://discord.gg/nDt7AjGJQH') - // .setStyle(ButtonStyle.Link), - // ), - // ]; - // if (error instanceof UserError) { - // interaction.editReply({ - // content: error.message, - // components, - // }); - // } else { - // console.error(interaction.commandName, error); - // interaction.editReply({ - // content: t`bot.common.errors.uncaught_error`, - // components, - // }); - // } + const { strings } = translator(interaction.locale); + + const components = [ + new ActionRowBuilder().addComponents( + new ButtonBuilder() + .setLabel(strings.bot.common.errors.get_help) + .setURL('https://discord.gg/nDt7AjGJQH') + .setStyle(ButtonStyle.Link), + ), + ]; + if (error instanceof UserError) { + interaction.editReply({ + content: error.message, + components, + }); + } else { + console.error(interaction.commandName, error); + interaction.editReply({ + content: strings.bot.common.errors.uncaught_error, + components, + }); + } } } diff --git a/packages/bot/src/events/interactionCreate/index.ts b/packages/bot/src/events/interactionCreate/index.ts index e9b1c7a48..9b9f097b3 100644 --- a/packages/bot/src/events/interactionCreate/index.ts +++ b/packages/bot/src/events/interactionCreate/index.ts @@ -1,3 +1,4 @@ +import { assertSecret } from '@blitzkit/core'; import { AttachmentBuilder, AutocompleteInteraction, @@ -7,11 +8,36 @@ import { ChatInputCommandInteraction, EmbedBuilder, Interaction, + REST, + Routes, SlashCommandBuilder, SlashCommandOptionsOnlyBuilder, SlashCommandSubcommandsOnlyBuilder, } from 'discord.js'; +import { aboutCommand } from '../../commands/about'; +import { auctionCommand } from '../../commands/auction'; +import { breakdownCommand } from '../../commands/breakdown'; +import { debugCommand } from '../../commands/debug'; +import { evolutionCommand } from '../../commands/evolution'; +import { fullStatsCommand } from '../../commands/fullStats'; +import { inactiveCommand } from '../../commands/inactive'; +import { verifyCommand } from '../../commands/link'; +import { ownedTanksCommand } from '../../commands/ownedTanks'; +import { permissionsCommand } from '../../commands/permissions'; +import { pingCommand } from '../../commands/ping'; +import { playerInfoCommand } from '../../commands/playerInfo'; +import { ratingCommand } from '../../commands/rating'; +import { ratingLeaderboardCommand } from '../../commands/ratingLeaderboard'; +import { replayCommand } from '../../commands/replay'; +import { researchCommand } from '../../commands/research'; +import { searchClansCommand } from '../../commands/searchClans'; +import { searchPlayersCommand } from '../../commands/searchPlayers'; +import { statsCommand } from '../../commands/stats'; +import { todayCommand } from '../../commands/today'; import { RenderConfiguration } from '../../core/blitzkit/renderConfiguration'; +import { handleAutocomplete } from './handlers/autocomplete'; +import { handleButton } from './handlers/button'; +import { handleChatInputCommand } from './handlers/chatInputCommand'; export type InteractionRawReturnable = | string @@ -54,63 +80,63 @@ interface CommandRegistryExplicit extends CommandRegistryBase { export type CommandRegistry = CommandRegistryImplicit | CommandRegistryExplicit; export const COMMANDS_RAW: Promise[] = [ - // auctionCommand, - // permissionsCommand, - // debugCommand, - // aboutCommand, - // inactiveCommand, - // ownedTanksCommand, - // playerInfoCommand, - // searchClansCommand, - // searchPlayersCommand, - // fullStatsCommand, - // breakdownCommand, - // verifyCommand, - // pingCommand, - // evolutionCommand, - // statsCommand, - // ratingLeaderboardCommand, - // todayCommand, - // researchCommand, - // ratingCommand, - // replayCommand, + auctionCommand, + permissionsCommand, + debugCommand, + aboutCommand, + inactiveCommand, + ownedTanksCommand, + playerInfoCommand, + searchClansCommand, + searchPlayersCommand, + fullStatsCommand, + breakdownCommand, + verifyCommand, + pingCommand, + evolutionCommand, + statsCommand, + ratingLeaderboardCommand, + todayCommand, + researchCommand, + ratingCommand, + replayCommand, ]; export const commands = Promise.allSettled(COMMANDS_RAW).then((rawCommands) => { - // return rawCommands.reduce>( - // (commands, registry, index) => { - // if (registry.status === 'rejected') { - // console.warn( - // `Command ${index} failed to load; skipping...`, - // registry.reason, - // ); - // return commands; - // } - // return { ...commands, [registry.value.command.name]: registry.value }; - // }, - // {}, - // ); + return rawCommands.reduce>( + (commands, registry, index) => { + if (registry.status === 'rejected') { + console.warn( + `Command ${index} failed to load; skipping...`, + registry.reason, + ); + return commands; + } + return { ...commands, [registry.value.command.name]: registry.value }; + }, + {}, + ); }); -// const rest = new REST().setToken(assertSecret(import.meta.env.DISCORD_TOKEN)); +const rest = new REST().setToken(assertSecret(import.meta.env.DISCORD_TOKEN)); -// commands.then((awaitedCommands) => { -// const body = Object.values(awaitedCommands).map((registry) => -// registry.command.toJSON(), -// ); +commands.then((awaitedCommands) => { + const body = Object.values(awaitedCommands).map((registry) => + registry.command.toJSON(), + ); -// rest.put( -// Routes.applicationCommands(assertSecret(import.meta.env.DISCORD_CLIENT_ID)), -// { body }, -// ); -// }); + rest.put( + Routes.applicationCommands(assertSecret(import.meta.env.DISCORD_CLIENT_ID)), + { body }, + ); +}); export async function interactionCreate(interaction: Interaction) { if (interaction.isAutocomplete()) { - // handleAutocomplete(interaction); + handleAutocomplete(interaction); } else if (interaction.isChatInputCommand()) { - // handleChatInputCommand(interaction); + handleChatInputCommand(interaction); } else if (interaction.isButton()) { - // handleButton(interaction); + handleButton(interaction); } } diff --git a/packages/i18n/package.json b/packages/i18n/package.json index 3dd28cd05..6e5d9d87d 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -3,6 +3,8 @@ "private": true, "type": "module", "main": "src/index.ts", - "dependencies": {}, + "dependencies": { + "ts-deepmerge": "^7.0.2" + }, "devDependencies": {} } diff --git a/packages/i18n/src/strings.ts b/packages/i18n/src/strings.ts index 687eb2e7e..93d17a32e 100644 --- a/packages/i18n/src/strings.ts +++ b/packages/i18n/src/strings.ts @@ -1,4 +1,5 @@ -import { merge } from 'lodash-es'; +import { writeFile } from 'fs/promises'; +import { merge } from 'ts-deepmerge'; import en from '../strings/en.json'; import es from '../strings/es.json'; import fr from '../strings/fr.json'; @@ -54,9 +55,7 @@ for (const locale in stringsRaw) { } const localeStrings = stringsRaw[locale as SupportedLocale]; - stringsPartial[locale as SupportedLocale] = merge( - {}, stringsRaw[DEFAULT_LOCALE], localeStrings, ); @@ -71,6 +70,8 @@ export const STRINGS = stringsPartial as Record< BlitzKitStrings >; +writeFile('test.json', JSON.stringify(STRINGS, null, 2)); + export type SupportedLocale = keyof typeof stringsRaw; export const SUPPORTED_LOCALE_BLITZ_MAP: Record = { diff --git a/packages/website/src/components/Embeds/breakdown.tsx b/packages/website/src/components/Embeds/breakdown.tsx index 14ca3a885..d98b9ecf5 100644 --- a/packages/website/src/components/Embeds/breakdown.tsx +++ b/packages/website/src/components/Embeds/breakdown.tsx @@ -8,7 +8,7 @@ import { sumCompositeStats, type IndividualTankStats, } from '@blitzkit/core'; -import { localizedStrings } from '@blitzkit/i18n'; +import { STRINGS } from '@blitzkit/i18n'; import { ReloadIcon } from '@radix-ui/react-icons'; import { ContextMenu } from '@radix-ui/themes'; import { useEffect, useMemo, useState } from 'react'; @@ -21,15 +21,12 @@ import { BreakdownEmbedCard, BreakdownEmbedWrapper } from '../TanksEmbed'; export const compositeStatsKeysOptions = compositeStatsKeys.map((value) => ({ value, - locales: Object.entries(localizedStrings).reduce( - (accumulator, [locale, strings]) => { - return { - ...accumulator, - [locale]: strings.common.composite_stats[value], - }; - }, - {}, - ), + locales: Object.entries(STRINGS).reduce((accumulator, [locale, strings]) => { + return { + ...accumulator, + [locale]: strings.common.composite_stats[value], + }; + }, {}), })); const [tankDefinitions, averageDefinitions] = await Promise.all([ diff --git a/packages/website/src/components/LocaleSwitcher.tsx b/packages/website/src/components/LocaleSwitcher.tsx index 78eab08ff..3b9b37261 100644 --- a/packages/website/src/components/LocaleSwitcher.tsx +++ b/packages/website/src/components/LocaleSwitcher.tsx @@ -1,9 +1,9 @@ import {} from '@blitzkit/core'; import { DEFAULT_LOCALE, + STRINGS, SUPPORTED_LOCALES, SUPPORTED_LOCALE_FLAGS, - localizedStrings, } from '@blitzkit/i18n'; import { Select } from '@radix-ui/themes'; import type { LocaleAcceptorProps } from '../hooks/useLocale'; @@ -44,7 +44,7 @@ export function LocaleSwitcher({ locale }: LocaleAcceptorProps) { {SUPPORTED_LOCALES.map((locale) => ( {SUPPORTED_LOCALE_FLAGS[locale]}{' '} - {localizedStrings[locale].common.locales[locale]} + {STRINGS[locale].common.locales[locale]} ))} diff --git a/packages/website/src/core/blitzkit/branches.ts b/packages/website/src/core/blitzkit/branches.ts index 2f3f6933b..8c8158063 100644 --- a/packages/website/src/core/blitzkit/branches.ts +++ b/packages/website/src/core/blitzkit/branches.ts @@ -1,8 +1,10 @@ import { assertSecret } from '@blitzkit/core'; -import { DEFAULT_LOCALE, localizedStrings } from '@blitzkit/i18n'; +import { DEFAULT_LOCALE, STRINGS, type SupportedLocale } from '@blitzkit/i18n'; export function resolveBranchName(locale: string = DEFAULT_LOCALE) { - const strings = localizedStrings[locale]; + if (!(locale in STRINGS)) throw new Error(`Unsupported locale: ${locale}`); + + const strings = STRINGS[locale as SupportedLocale]; const secret = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH); if ( diff --git a/packages/website/src/core/i18n/getStrings.ts b/packages/website/src/core/i18n/getStrings.ts index a83acbe33..ccd3480bc 100644 --- a/packages/website/src/core/i18n/getStrings.ts +++ b/packages/website/src/core/i18n/getStrings.ts @@ -1,5 +1,6 @@ -import { DEFAULT_LOCALE, localizedStrings } from '@blitzkit/i18n'; +import { DEFAULT_LOCALE, STRINGS, type SupportedLocale } from '@blitzkit/i18n'; export function getStrings(locale: string = DEFAULT_LOCALE) { - return localizedStrings[locale]; + if (locale in STRINGS) return STRINGS[locale as SupportedLocale]; + throw new Error(`Unsupported locale: ${locale}`); }