feat: update bot chunk 1

This commit is contained in:
tresabhi committed 2025-01-15 20:14:05 -06:00
1 parent bb557a7dd7
commit d2b24fc953
42 files changed
+370 -389

No files matched your search

+13 -9
View File
@@ -3,6 +3,7 @@ import {
Region,
regionToRegionSubdomain,
} from '@blitzkit/core';
import { literals } from '@blitzkit/i18n';
import { tankDefinitions } from '../core/blitzkit/nonBlockingPromises';
import { chunkLines } from '../core/discord/chunkLines';
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
@@ -75,7 +76,7 @@ export const auctionCommand = new Promise<CommandRegistry>((resolve) => {
command: createLocalizedCommand('auction'),
async handler(interaction) {
const { t, translate } = translator(interaction.locale);
const { strings } = translator(interaction.locale);
const awaitedTankDefinitions = await tankDefinitions;
const region: Region = 'com';
const pageSize = 80;
@@ -90,13 +91,13 @@ export const auctionCommand = new Promise<CommandRegistry>((resolve) => {
const saleableTanks = data.results.filter((result) => result.available);
if (saleableTanks.length === 0) {
return t`bot.commands.auction.errors.no_auction`;
return strings.bot.commands.auction.errors.no_auction;
}
const nextPricesTimestamp = saleableTanks[0].next_price_timestamp;
const title = `# ${t`bot.commands.auction.body.title`}`;
const subtitle = `${translate('bot.commands.auction.body.subtitle', [
const title = `# ${strings.bot.commands.auction.body.title}`;
const subtitle = `${literals(strings.bot.commands.auction.body.subtitle, [
`${saleableTanks.length} / ${data.results.length}`,
`<t:${nextPricesTimestamp}:R>`,
'<https://wotblitz.com/auction/>',
@@ -112,15 +113,18 @@ export const auctionCommand = new Promise<CommandRegistry>((resolve) => {
const next =
data.next_price === null
? ''
: `\n-# ${translate('bot.commands.auction.body.next', [
: `\n-# ${literals(strings.bot.commands.auction.body.next, [
`<:gold:1317173197082333244> ${data.next_price.value.toLocaleString(
interaction.locale,
)}`,
])}`;
const available = translate('bot.commands.auction.body.available', [
data.current_count.toLocaleString(interaction.locale),
data.initial_count.toLocaleString(interaction.locale),
]);
const available = literals(
strings.bot.commands.auction.body.available,
[
data.current_count.toLocaleString(interaction.locale),
data.initial_count.toLocaleString(interaction.locale),
],
);
const isOut = data.current_count === 0;
const outString = isOut ? '~~' : '';
const isLow = data.current_count <= WARNING_COUNT;
+9 -7
View File
@@ -1,4 +1,5 @@
import { getAccountInfo, getClanInfo } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n';
import { Locale } from 'discord.js';
import { CommandWrapper } from '../components/CommandWrapper';
import { GenericStats } from '../components/GenericStats';
@@ -19,7 +20,7 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
command: createLocalizedCommand('inactive')
.addStringOption(addClanChoices)
.addNumberOption((option) => {
const { translate } = translator(Locale.EnglishUS);
const { strings } = translator(Locale.EnglishUS);
return option
.setName('threshold')
@@ -31,7 +32,7 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
),
)
.setDescription(
translate('bot.commands.inactive.options.threshold.description'),
strings.bot.commands.inactive.options.threshold.description,
)
.setDescriptionLocalizations(
localizationObject(
@@ -42,7 +43,7 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
}),
async handler(interaction) {
const { translate } = translator(interaction.locale);
const { strings } = translator(interaction.locale);
const { region, id } = await resolveClanFromCommand(interaction);
const threshold =
interaction.options.getNumber('threshold')! ?? DEFAULT_THRESHOLD;
@@ -63,7 +64,7 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
([name, days]) =>
[
name,
translate('bot.commands.inactive.body.listing', [
literals(strings.bot.commands.inactive.body.listing, [
days.toFixed(0),
]),
] as [string, string],
@@ -75,9 +76,10 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
<TitleBar
title={clanInfo.name}
image={`https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanInfo.emblem_set_id}.png`}
description={`${translate('bot.commands.inactive.body.subtitle', [
`${threshold}`,
])} • ${new Date().toLocaleDateString(interaction.locale)}`}
description={`${literals(
strings.bot.commands.inactive.body.subtitle,
[`${threshold}`],
)} • ${new Date().toLocaleDateString(interaction.locale)}`}
/>
{!hasInactiveMembers && (
@@ -16,39 +16,67 @@ export function addPeriodSubCommands(
option: SlashCommandSubcommandBuilder,
) => SlashCommandSubcommandBuilder = (option) => option,
) {
const { translate } = translator(Locale.EnglishUS);
const { strings } = translator(Locale.EnglishUS);
const subcommandNameLocalizations = {
today: localizationObject('bot.common.subcommands.today', undefined, true),
30: localizationObject('bot.common.subcommands.30', undefined, true),
60: localizationObject('bot.common.subcommands.60', undefined, true),
90: localizationObject('bot.common.subcommands.90', undefined, true),
today: localizationObject(
(strings) => strings.bot.common.subcommands.today.$,
undefined,
true,
),
30: localizationObject(
(strings) => strings.bot.common.subcommands[30].$,
undefined,
true,
),
60: localizationObject(
(strings) => strings.bot.common.subcommands[60].$,
undefined,
true,
),
90: localizationObject(
(strings) => strings.bot.common.subcommands[90].$,
undefined,
true,
),
career: localizationObject(
'bot.common.subcommands.career',
(strings) => strings.bot.common.subcommands.career.$,
undefined,
true,
),
custom: localizationObject(
'bot.common.subcommands.custom',
(strings) => strings.bot.common.subcommands.custom.$,
undefined,
true,
),
};
const subcommandDescriptionLocalizations = {
today: localizationObject('bot.common.subcommands.today.description'),
30: localizationObject('bot.common.subcommands.30.description'),
60: localizationObject('bot.common.subcommands.60.description'),
90: localizationObject('bot.common.subcommands.90.description'),
career: localizationObject('bot.common.subcommands.career.description'),
custom: localizationObject('bot.common.subcommands.custom.description'),
today: localizationObject(
(strings) => strings.bot.common.subcommands.today.description,
),
30: localizationObject(
(strings) => strings.bot.common.subcommands[30].description,
),
60: localizationObject(
(strings) => strings.bot.common.subcommands[60].description,
),
90: localizationObject(
(strings) => strings.bot.common.subcommands[90].description,
),
career: localizationObject(
(strings) => strings.bot.common.subcommands.career.description,
),
custom: localizationObject(
(strings) => strings.bot.common.subcommands.custom.description,
),
};
option
.addSubcommand((option) =>
extra(
option
.setName(translate('bot.common.subcommands.today'))
.setName(strings.bot.common.subcommands.today.$)
.setNameLocalizations(subcommandNameLocalizations.today)
.setDescription(translate('bot.common.subcommands.today.description'))
.setDescription(strings.bot.common.subcommands.today.description)
.setDescriptionLocalizations(
subcommandDescriptionLocalizations.today,
),
@@ -57,38 +85,36 @@ export function addPeriodSubCommands(
.addSubcommand((option) =>
extra(
option
.setName(translate('bot.common.subcommands.30'))
.setName(strings.bot.common.subcommands[30].$)
.setNameLocalizations(subcommandNameLocalizations[30])
.setDescription(translate('bot.common.subcommands.30.description'))
.setDescription(strings.bot.common.subcommands[30].description)
.setDescriptionLocalizations(subcommandDescriptionLocalizations[30]),
),
)
.addSubcommand((option) =>
extra(
option
.setName(translate('bot.common.subcommands.60'))
.setName(strings.bot.common.subcommands[60].$)
.setNameLocalizations(subcommandNameLocalizations[60])
.setDescription(translate('bot.common.subcommands.60.description'))
.setDescription(strings.bot.common.subcommands[60].description)
.setDescriptionLocalizations(subcommandDescriptionLocalizations[60]),
),
)
.addSubcommand((option) =>
extra(
option
.setName(translate('bot.common.subcommands.90'))
.setName(strings.bot.common.subcommands[90].$)
.setNameLocalizations(subcommandNameLocalizations[90])
.setDescription(translate('bot.common.subcommands.90.description'))
.setDescription(strings.bot.common.subcommands[90].description)
.setDescriptionLocalizations(subcommandDescriptionLocalizations[90]),
),
)
.addSubcommand((option) =>
extra(
option
.setName(translate('bot.common.subcommands.career'))
.setName(strings.bot.common.subcommands.career.$)
.setNameLocalizations(subcommandNameLocalizations.career)
.setDescription(
translate('bot.common.subcommands.career.description'),
)
.setDescription(strings.bot.common.subcommands.career.description)
.setDescriptionLocalizations(
subcommandDescriptionLocalizations.career,
),
@@ -97,31 +123,25 @@ export function addPeriodSubCommands(
.addSubcommand((option) =>
extra(
option
.setName(translate('bot.common.subcommands.custom'))
.setName(strings.bot.common.subcommands.custom.$)
.setNameLocalizations(subcommandNameLocalizations.custom)
.setDescription(
translate('bot.common.subcommands.custom.description'),
)
.setDescription(strings.bot.common.subcommands.custom.description)
.setDescriptionLocalizations(
subcommandDescriptionLocalizations.custom,
)
.addIntegerOption((option) =>
option
.setName(translate('bot.common.subcommands.custom.options.start'))
.setName(strings.bot.common.subcommands.custom.options.start.$)
.setDescription(
translate(
'bot.common.subcommands.custom.options.start.description',
),
strings.bot.common.subcommands.custom.options.start.description,
)
.setRequired(true),
)
.addIntegerOption((option) =>
option
.setName(translate('bot.common.subcommands.custom.options.end'))
.setName(strings.bot.common.subcommands.custom.options.end.$)
.setDescription(
translate(
'bot.common.subcommands.custom.options.end.description',
),
strings.bot.common.subcommands.custom.options.end.description,
)
.setRequired(true),
),
@@ -8,25 +8,31 @@ import { translator } from '../localization/translator';
import { localizationObject } from './localizationObject';
export function addRegionChoices(option: SlashCommandStringOption) {
const { t, translate } = translator(Locale.EnglishUS);
const { strings } = translator(Locale.EnglishUS);
return option
.setName(t`bot.common.options.region`)
.setName(strings.bot.common.options.region.$)
.setNameLocalizations(
localizationObject('bot.common.options.region', undefined, true),
localizationObject(
(strings) => strings.bot.common.options.region.$,
undefined,
true,
),
)
.setDescription(t`bot.common.options.region.description`)
.setDescription(strings.bot.common.options.region.description)
.setDescriptionLocalizations(
localizationObject('bot.common.options.region.description'),
localizationObject(
(strings) => strings.bot.common.options.region.description,
),
)
.addChoices(
...REGIONS.map(
(region) =>
({
value: region,
name: translate(`common.regions.normal.${region}`),
name: strings.common.regions.normal[region],
name_localizations: localizationObject(
`common.regions.normal.${region}`,
(strings) => strings.common.regions.normal[region],
),
}) satisfies APIApplicationCommandOptionChoice,
),
@@ -3,16 +3,22 @@ import { translator } from '../localization/translator';
import { localizationObject } from './localizationObject';
export function addTankChoices(option: SlashCommandStringOption) {
const { translate } = translator(Locale.EnglishUS);
const { strings } = translator(Locale.EnglishUS);
return option
.setName(translate('bot.common.options.tank'))
.setName(strings.bot.common.options.tank.$)
.setNameLocalizations(
localizationObject('bot.common.options.tank', undefined, true),
localizationObject(
(strings) => strings.bot.common.options.tank.$,
undefined,
true,
),
)
.setDescription(translate('bot.common.options.tank.description'))
.setDescription(strings.bot.common.options.tank.description)
.setDescriptionLocalizations(
localizationObject('bot.common.options.tank.description'),
localizationObject(
(strings) => strings.bot.common.options.tank.description,
),
)
.setAutocomplete(true)
.setRequired(true);
@@ -1,4 +1,5 @@
import { numberToRomanNumeral } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n';
import {
APIApplicationCommandOptionChoice,
Locale,
@@ -9,28 +10,34 @@ import { translator } from '../localization/translator';
import { localizationObject } from './localizationObject';
export function addTierChoices(option: SlashCommandStringOption) {
const { t, translate } = translator(Locale.EnglishUS);
const { strings } = translator(Locale.EnglishUS);
return option
.setName(t`bot.common.options.tier`)
.setName(strings.bot.common.options.tier.$)
.setNameLocalizations(
localizationObject('bot.common.options.tier', undefined, true),
localizationObject(
(strings) => strings.bot.common.options.tier.$,
undefined,
true,
),
)
.setDescription(t`bot.common.options.tier.description`)
.setDescription(strings.bot.common.options.tier.description)
.setDescriptionLocalizations(
localizationObject('bot.common.options.tier.description'),
localizationObject(
(strings) => strings.bot.common.options.tier.description,
),
)
.setChoices(
...range(10, 0).map(
(tier) =>
({
name: translate('bot.common.options.tier.choices.tier', [
name: literals(strings.bot.common.options.tier.choices.tier, [
`${tier}`,
numberToRomanNumeral(tier),
]),
value: `${tier}`,
name_localizations: localizationObject(
'bot.common.options.tier.choices.tier',
(strings) => strings.bot.common.options.tier.choices.tier,
[`${tier}`, numberToRomanNumeral(tier)],
),
}) satisfies APIApplicationCommandOptionChoice,
@@ -10,7 +10,7 @@ import { DISCORD_CHOICES_MAX_NAME_SIZE, OVERFLOW_SUFFIX } from './constants';
export async function autocompleteClan(
interaction: AutocompleteInteraction<CacheType>,
) {
const { translate } = translator(interaction.locale);
const { strings } = translator(interaction.locale);
const focusedOption = interaction.options.getFocused(true);
if (focusedOption.name !== 'clan') return;
if (focusedOption.value.length < 2) return interaction.respond([]);
@@ -19,9 +19,7 @@ export async function autocompleteClan(
await interaction.respond(
clans
? clans.map((clan) => {
let name = `${clan.name} (${translate(
`common.regions.short.${clan.region}`,
)})`;
let name = `${clan.name} (${strings.common.regions.short[clan.region]})`;
if (name.length > DISCORD_CHOICES_MAX_NAME_SIZE) {
const overSize = name.length - DISCORD_CHOICES_MAX_NAME_SIZE;
@@ -29,9 +27,7 @@ export async function autocompleteClan(
name = `${clan.name.slice(
0,
clan.name.length - overSize - OVERFLOW_SUFFIX.length,
)}${OVERFLOW_SUFFIX} (${translate(
`common.regions.short.${clan.region}`,
)})`;
)}${OVERFLOW_SUFFIX} (${strings.common.regions.short[clan.region]})`;
}
return {
@@ -13,7 +13,7 @@ import {
export async function autocompleteUsername(
interaction: AutocompleteInteraction<CacheType>,
) {
const { translate } = translator(interaction.locale);
const { strings } = translator(interaction.locale);
const focusedOption = interaction.options.getFocused(true);
if (focusedOption.name !== 'username') return;
const players = await searchPlayersAcrossRegions(focusedOption.value);
@@ -22,9 +22,9 @@ export async function autocompleteUsername(
await interaction.respond(
players
? players.map((player) => {
let name = `${player.nickname} (${translate(
`common.regions.short.${player.region}`,
)})`;
let name = `${player.nickname} (${
strings.common.regions.short[player.region]
})`;
if (name.length > DISCORD_CHOICES_MAX_NAME_SIZE) {
const overSize = name.length - DISCORD_CHOICES_MAX_NAME_SIZE;
@@ -32,9 +32,9 @@ export async function autocompleteUsername(
name = `${player.nickname.slice(
0,
player.nickname.length - overSize - OVERFLOW_SUFFIX.length,
)}${OVERFLOW_SUFFIX} (${translate(
`common.regions.short.${player.region}`,
)})`;
)}${OVERFLOW_SUFFIX} (${
strings.common.regions.short[player.region]
})`;
}
return {
@@ -1,3 +1,4 @@
import { BlitzKitStrings } from '@blitzkit/i18n';
import {
Locale,
SlashCommandBuilder,
@@ -23,28 +24,47 @@ export function createLocalizedCommand(
| CreateLocalizedCommandSubcommand[]
| CreateLocalizedCommandSubcommandGroup[],
) {
const commandPathItem = command.replaceAll('-', '_');
const { translate } = translator(Locale.EnglishUS);
const commandPathItem = command.replaceAll(
'-',
'_',
) as keyof BlitzKitStrings['bot']['commands'];
const { strings } = translator(Locale.EnglishUS);
const slashCommand = new SlashCommandBuilder()
.setName(command)
.setNameLocalizations(
localizationObject(`bot.commands.${commandPathItem}`, undefined, true),
localizationObject(
(strings) => strings.bot.commands[commandPathItem].$,
undefined,
true,
),
)
.setDescription(translate(`bot.commands.${commandPathItem}.description`))
.setDescription(strings.bot.commands[commandPathItem].description)
.setDescriptionLocalizations(
localizationObject(`bot.commands.${commandPathItem}.description`),
localizationObject(
(strings) => strings.bot.commands[commandPathItem].description,
),
);
if (sub) {
sub.map((subItem) => {
if ('subcommand' in subItem) {
const subcommandNameLocalizations = localizationObject(
`bot.commands.${commandPathItem}.subcommands.${subItem.subcommand}`,
(strings) =>
(
strings.bot.commands[commandPathItem] as unknown as {
subcommands: Record<string, { $: string }>;
}
).subcommands[subItem.subcommand].$,
undefined,
true,
);
const subcommandDescriptionLocalizations = localizationObject(
`bot.commands.${commandPathItem}.subcommands.${subItem.subcommand}.description`,
(strings) =>
(
strings.bot.commands[commandPathItem] as unknown as {
subcommands: Record<string, { description: string }>;
}
).subcommands[subItem.subcommand].description,
);
slashCommand.addSubcommand((option) => {
@@ -54,20 +74,32 @@ export function createLocalizedCommand(
.setName(subItem.subcommand)
.setNameLocalizations(subcommandNameLocalizations)
.setDescription(
translate(
`bot.commands.${commandPathItem}.subcommands.${subItem.subcommand}.description`,
),
(
strings.bot.commands[commandPathItem] as unknown as {
subcommands: Record<string, { description: string }>;
}
).subcommands[subItem.subcommand].description,
)
.setDescriptionLocalizations(subcommandDescriptionLocalizations);
});
} else {
const subcommandNameLocalizations = localizationObject(
`bot.commands.${commandPathItem}.groups.${subItem.group}`,
(strings) =>
(
strings.bot.commands[commandPathItem] as unknown as {
groups: Record<string, { $: string }>;
}
).groups[subItem.group].$,
undefined,
true,
);
const subcommandDescriptionLocalizations = localizationObject(
`bot.commands.${commandPathItem}.groups.${subItem.group}.description`,
(strings) =>
(
strings.bot.commands[commandPathItem] as unknown as {
groups: Record<string, { description: string }>;
}
).groups[subItem.group].description,
);
slashCommand.addSubcommandGroup((option) => {
@@ -77,9 +109,11 @@ export function createLocalizedCommand(
.setName(subItem.group)
.setNameLocalizations(subcommandNameLocalizations)
.setDescription(
translate(
`bot.commands.${commandPathItem}.groups.${subItem.group}.description`,
),
(
strings.bot.commands[commandPathItem] as unknown as {
groups: Record<string, { description: string }>;
}
).groups[subItem.group].description,
)
.setDescriptionLocalizations(subcommandDescriptionLocalizations);
});
@@ -1,10 +1,11 @@
import { literals } from '@blitzkit/i18n';
import { Locale } from 'discord.js';
import { translator } from '../localization/translator';
import { PeriodSize } from './addPeriodSubCommands';
export function getPeriodOptionName(period: PeriodSize, locale: Locale) {
const { translate } = translator(locale);
if (period === 'career') return translate('bot.common.periods.career');
if (period === 'today') return translate('bot.common.periods.today');
return translate('bot.common.periods.days', [period]);
const { strings } = translator(locale);
if (period === 'career') return strings.bot.common.periods.career;
if (period === 'today') return strings.bot.common.periods.today;
return literals(strings.bot.common.periods.days, [period]);
}
@@ -1,3 +1,4 @@
import { BlitzKitStrings, literals as literalsFunc } from '@blitzkit/i18n';
import { Locale } from 'discord.js';
import { SUPPORTED_LOCALES_DISCORD } from '../localization/strings/constants';
import { translator } from '../localization/translator';
@@ -5,14 +6,14 @@ import { translator } from '../localization/translator';
const validNameRegex = /^[-_\p{L}\p{N}\p{sc=Deva}\p{sc=Thai}]{1,32}$/u;
export function localizationObject(
path: string,
literals?: string[],
path: (strings: BlitzKitStrings) => string,
literals: string[] = [],
strict = false,
) {
return SUPPORTED_LOCALES_DISCORD.reduce<Partial<Record<Locale, string>>>(
(localizations, locale) => {
const { translate } = translator(locale);
const translation = translate(path, literals);
const { strings } = translator(locale);
const translation = literalsFunc(path(strings), literals);
const isValid = !strict || validNameRegex.test(translation);
if (!isValid) {
@@ -1,4 +1,5 @@
import { Region } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n';
import { ChatInputCommandInteraction } from 'discord.js';
import markdownEscape from 'markdown-escape';
import { searchClansAcrossRegionsBotWrapper } from '../blitz/searchClansAcrossRegionsBotWrapper';
@@ -10,7 +11,7 @@ export const serverAndIdPattern = /(com|eu|asia)\/[0-9]+/;
export async function resolveClanFromCommand(
interaction: ChatInputCommandInteraction,
) {
const { translate } = translator(interaction.locale);
const { strings } = translator(interaction.locale);
const clan = interaction.options.getString('clan', true);
if (serverAndIdPattern.test(clan)) {
@@ -26,7 +27,9 @@ export async function resolveClanFromCommand(
return { region: accounts[0].region, id: accounts[0].clan_id };
} else {
throw new UserError(
translate('bot.common.errors.clan_not_found', [markdownEscape(clan)]),
literals(strings.bot.common.errors.clan_not_found, [
markdownEscape(clan),
]),
);
}
}
@@ -1,4 +1,5 @@
import { getTimeDaysAgo, Region } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n';
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
import { getPeriodNow } from '../blitzkit/getPeriodNow';
import { getPeriodStart } from '../blitzkit/getPeriodStart';
@@ -17,7 +18,7 @@ export function resolvePeriodFromCommand(
interaction: ChatInputCommandInteraction<CacheType>,
forcedPeriod?: PeriodType,
) {
const { translate } = translator(interaction.locale);
const { strings } = translator(interaction.locale);
let name: string;
let start: number;
let end: number;
@@ -31,7 +32,7 @@ export function resolvePeriodFromCommand(
const startDaysAgoMin = Math.min(startOption, endOption);
const endDaysAgoMax = Math.max(startOption, endOption);
name = translate('bot.common.periods.custom', [
name = literals(strings.bot.common.periods.custom, [
`${startDaysAgoMin}`,
`${endDaysAgoMax}`,
]);
@@ -1,4 +1,5 @@
import { idToRegion, Region } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n';
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
import markdownEscape from 'markdown-escape';
import { searchPlayersAcrossRegionsBotWrapper } from '../../blitz/searchPlayersAcrossRegionsBotWrapper';
@@ -14,7 +15,7 @@ export interface ResolvedPlayer {
export async function resolvePlayerFromCommand(
interaction: ChatInputCommandInteraction<CacheType>,
) {
const { t, translate } = translator(interaction.locale);
const { strings } = translator(interaction.locale);
const commandUsername = interaction.options.getString('username');
if (commandUsername !== null) {
@@ -36,7 +37,7 @@ export async function resolvePlayerFromCommand(
} satisfies ResolvedPlayer;
} else {
throw new UserError(
translate('bot.common.errors.player_not_found', [
literals(strings.bot.common.errors.player_not_found, [
markdownEscape(commandUsername),
]),
);
@@ -47,6 +48,6 @@ export async function resolvePlayerFromCommand(
if (account) return account;
throw new UserError(t`bot.common.errors.player_not_linked`);
throw new UserError(strings.bot.common.errors.player_not_linked);
}
}
@@ -1,24 +0,0 @@
import { Locale } from 'discord.js';
import {
SUPPORTED_LOCALES_DISCORD,
SUPPORTED_LOCALES_DISCORD_MAP_INVERSE,
} from './constants';
export type TranslationFragmentTree = {
[key: string]: TranslationFragment;
} & {
$?: string;
};
export type TranslationFragment = string | TranslationFragmentTree;
export const translations = SUPPORTED_LOCALES_DISCORD.reduce<
Partial<Record<Locale, TranslationFragment>>
>(
(table, locale) => ({
...table,
[locale]: require(
`@blitzkit/i18n/strings/${SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale]}.json`,
),
}),
{},
);
@@ -1,6 +1,5 @@
import { unwrapper } from '@blitzkit/i18n';
import { STRINGS, unwrapper } from '@blitzkit/i18n';
import { Locale } from 'discord.js';
import { translations } from './strings';
import {
DEFAULT_LOCALE_DISCORD,
SUPPORTED_LOCALES_DISCORD,
@@ -13,70 +12,10 @@ export function translator(localeRaw: Locale) {
SUPPORTED_LOCALES_DISCORD.includes(localeRaw)
? localeRaw
: DEFAULT_LOCALE_DISCORD;
const strings = translations[locale]!;
function translate(path: string, literals?: string[]): string {
const pathArray = path.split('.');
let fragment = strings;
let resolvedString: string;
for (const pathItem of pathArray) {
if (typeof fragment === 'string') {
throw new SyntaxError(
`Attempted to access string with key "${pathItem}" in "${path}" from within a string instead of an object in locale "${locale}"`,
);
} else {
fragment = fragment[pathItem];
if (typeof fragment === 'undefined') {
const message = `Undefined translation at "${pathItem}" in "${path}" for locale "${locale}"`;
if (locale === DEFAULT_LOCALE_DISCORD) {
throw new Error(message);
} else {
console.warn(`${message} falling back to en-US`);
return translator(DEFAULT_LOCALE_DISCORD).translate(path, literals);
}
}
}
}
if (typeof fragment === 'string') {
resolvedString = fragment;
} else if (fragment.$) {
resolvedString = fragment.$!;
} else {
throw new Error(
`Unresolved tree ending for "${path}" in locale "${locale}"`,
);
}
if (literals) {
const chunks = resolvedString.split('%s');
let embeddedString = '';
chunks.forEach((chunk, index) => {
if (index !== 0) embeddedString += literals[index - 1];
embeddedString += chunk;
});
return embeddedString;
}
return resolvedString;
}
function t(paths: TemplateStringsArray, ...embeds: string[]) {
return paths
.map((path, index) =>
path.length === 0
? ''
: `${translate(path)}${index === embeds.length ? '' : embeds[index]}`,
)
.join('');
}
STRINGS;
const strings = STRINGS[SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale]];
const unwrap = unwrapper(SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale]);
return { locale, translate, t, unwrap };
return { locale, strings, unwrap };
}
@@ -2,7 +2,6 @@ import {
ActionRowBuilder,
AttachmentBuilder,
ButtonBuilder,
ButtonStyle,
CacheType,
ChatInputCommandInteraction,
InteractionReplyOptions,
@@ -14,7 +13,6 @@ import { normalizeInteractionReturnable } from '../../../core/discord/normalizeI
import { psa } from '../../../core/discord/psa';
import { translator } from '../../../core/localization/translator';
import { Writeable } from '../../../types/writable';
import { UserError } from '../../../core/blitzkit/userError';
export async function handleChatInputCommand(
interaction: ChatInputCommandInteraction<CacheType>,
@@ -127,27 +125,25 @@ export async function handleChatInputCommand(
}
} catch (error) {
const { t } = translator(interaction.locale);
const components = [
new ActionRowBuilder<ButtonBuilder>().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 components = [
// new ActionRowBuilder<ButtonBuilder>().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,
// });
// }
}
}
@@ -1,4 +1,3 @@
import { assertSecret } from '@blitzkit/core';
import {
AttachmentBuilder,
AutocompleteInteraction,
@@ -8,35 +7,12 @@ 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 =
@@ -64,71 +40,72 @@ interface CommandRegistryBase {
autocomplete?: (interaction: AutocompleteInteraction<CacheType>) => void;
button?: (interaction: ButtonInteraction<CacheType>) => InteractionReturnable;
}
interface CommandRegistryImplicit extends CommandRegistryBase {
handlesInteraction: true;
handler: (interaction: ChatInputCommandInteraction<CacheType>) => void;
}
interface CommandRegistryExplicit extends CommandRegistryBase {
handlesInteraction?: false;
handler: (
interaction: ChatInputCommandInteraction<CacheType>,
) => InteractionReturnable;
}
export type CommandRegistry = CommandRegistryImplicit | CommandRegistryExplicit;
export const COMMANDS_RAW: Promise<CommandRegistry>[] = [
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<Record<string, CommandRegistry>>(
(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<Record<string, CommandRegistry>>(
// (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<CacheType>) {
if (interaction.isAutocomplete()) {
@@ -136,6 +113,6 @@ export async function interactionCreate(interaction: Interaction<CacheType>) {
} else if (interaction.isChatInputCommand()) {
handleChatInputCommand(interaction);
} else if (interaction.isButton()) {
handleButton(interaction);
// handleButton(interaction);
}
}
+1 -1
View File
@@ -1,3 +1,3 @@
export * from './literals';
export * from './strings';
export * from './supportedLocales';
export * from './unwrapper';
File renamed without changes.
+80 -30
View File
@@ -1,38 +1,21 @@
import { merge } from 'lodash-es';
import type en from '../strings/en.json';
import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from './supportedLocales';
import en from '../strings/en.json';
import es from '../strings/es.json';
import fr from '../strings/fr.json';
import ja from '../strings/ja.json';
import pl from '../strings/pl.json';
import pt from '../strings/pt.json';
import ru from '../strings/ru.json';
import uk from '../strings/uk.json';
import zh from '../strings/zh.json';
export type TranslationTree = { [key: string]: TranslationNode };
export type BlitzKitStrings = typeof en;
export type TranslationNode = string | TranslationTree;
const stringsRaw = { en, es, fr, ja, pl, pt, ru, uk, zh };
const files = import.meta.glob('../strings/*.json', { eager: true });
export const localizedStrings: Record<string, typeof en> = {};
export const SUPPORTED_LOCALES = Object.keys(stringsRaw) as SupportedLocale[];
function nuke(object: TranslationTree) {
for (const key in object) {
const typedKey = key as keyof typeof object;
if (typeof object[typedKey] === 'string') {
const value = object[typedKey];
object[typedKey] = redact(value as string);
} else nuke(object[typedKey] as TranslationTree);
}
}
SUPPORTED_LOCALES.forEach((locale) => {
const defaultStrings = files[`../strings/${DEFAULT_LOCALE}.json`];
const strings = files[`../strings/${locale}.json`];
const mergedStrings = merge({}, defaultStrings, strings);
/**
* For some reason, this won't load on the server on the first render so I am
* not asserting this one lol
*/
if (import.meta.env.PUBLIC_DEBUG_MISSING_I18N === 'true') nuke(mergedStrings);
localizedStrings[locale] = mergedStrings as typeof en;
});
export const DEFAULT_LOCALE = SUPPORTED_LOCALES[0];
function redact(string: string) {
const matches = [...string.matchAll(/%s\d+/g)];
@@ -50,3 +33,70 @@ function redact(string: string) {
return characters.join('');
}
function nuke(object: TranslationTree) {
for (const key in object) {
const typedKey = key as keyof typeof object;
if (typeof object[typedKey] === 'string') {
const value = object[typedKey];
object[typedKey] = redact(value as string);
} else nuke(object[typedKey] as TranslationTree);
}
}
const stringsPartial: Partial<Record<SupportedLocale, TranslationTree>> = {};
for (const locale in stringsRaw) {
if (locale === DEFAULT_LOCALE) {
stringsPartial[DEFAULT_LOCALE] = stringsRaw[DEFAULT_LOCALE];
continue;
}
const localeStrings = stringsRaw[locale as SupportedLocale];
stringsPartial[locale as SupportedLocale] = merge(
{},
stringsRaw[DEFAULT_LOCALE],
localeStrings,
);
if (import.meta.env.PUBLIC_DEBUG_MISSING_I18N === 'true') {
nuke(stringsPartial[locale as SupportedLocale]!);
}
}
export const STRINGS = stringsPartial as Record<
SupportedLocale,
BlitzKitStrings
>;
export type SupportedLocale = keyof typeof stringsRaw;
export const SUPPORTED_LOCALE_BLITZ_MAP: Record<SupportedLocale, string> = {
en: 'en',
es: 'es',
fr: 'fr',
ja: 'ja',
pt: 'pt',
ru: 'ru',
uk: 'uk',
zh: 'zh-Hans',
pl: 'pl',
};
export const SUPPORTED_LOCALE_FLAGS: Record<SupportedLocale, string> = {
en: '🇺🇸',
es: '🇪🇸',
fr: '🇫🇷',
ja: '🇯🇵',
pt: '🇵🇹',
ru: '🇷🇺',
uk: '🇺🇦',
zh: '🇨🇳',
pl: '🇵🇱',
};
export type TranslationTree = { [key: string]: TranslationNode };
export type TranslationNode = string | TranslationTree;
-39
View File
@@ -1,39 +0,0 @@
export const SUPPORTED_LOCALES = [
'en',
'es',
'fr',
'ja',
'pl',
'pt',
'ru',
'uk',
'zh',
] as const;
export type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];
export const DEFAULT_LOCALE = SUPPORTED_LOCALES[0];
export const SUPPORTED_LOCALE_BLITZ_MAP: Record<SupportedLocale, string> = {
en: 'en',
es: 'es',
fr: 'fr',
ja: 'ja',
pt: 'pt',
ru: 'ru',
uk: 'uk',
zh: 'zh-Hans',
pl: 'pl',
};
export const SUPPORTED_LOCALE_FLAGS: Record<SupportedLocale, string> = {
en: '🇺🇸',
es: '🇪🇸',
fr: '🇫🇷',
ja: '🇯🇵',
pt: '🇵🇹',
ru: '🇷🇺',
uk: '🇺🇦',
zh: '🇨🇳',
pl: '🇵🇱',
};
+1 -1
View File
@@ -1,5 +1,5 @@
import { I18nString } from '@blitzkit/core';
import { DEFAULT_LOCALE } from './supportedLocales';
import { DEFAULT_LOCALE } from './strings';
export function unwrapper(locale: string) {
return function (i18nString: I18nString) {
@@ -1,3 +1,4 @@
import { literals } from '@blitzkit/i18n/src/literals';
import {
Card,
Flex,
@@ -8,7 +9,6 @@ import {
} from '@radix-ui/themes';
import type { ComponentProps } from 'react';
import { radToDeg } from 'three/src/math/MathUtils.js';
import { literals } from '../../../core/i18n/literals';
import { useLocale } from '../../../hooks/useLocale';
import type { Shot, ShotLayer } from '../../../stores/tankopediaEphemeral';
import { shotStatusColors } from './ShotDisplay';
@@ -3,6 +3,7 @@ import {
type AccountListItem,
type AccountListWithServer,
} from '@blitzkit/core';
import { literals } from '@blitzkit/i18n/src/literals';
import { CaretLeftIcon, Link2Icon, PersonIcon } from '@radix-ui/react-icons';
import {
Badge,
@@ -18,7 +19,6 @@ import { debounce } from 'lodash-es';
import { useCallback, useRef, useState } from 'react';
import { stringify } from 'urlon';
import type { embedConfigurations } from '../../constants/embeds';
import { literals } from '../../core/i18n/literals';
import { useLocale } from '../../hooks/useLocale';
import { EmbedState, type EmbedStateStore } from '../../stores/embedState';
import { CopyButton } from '../CopyButton';
@@ -1,8 +1,8 @@
import { literals } from '@blitzkit/i18n/src/literals';
import { Flex, Text } from '@radix-ui/themes';
import fuzzysort from 'fuzzysort';
import { times } from 'lodash-es';
import { useMemo, useState } from 'react';
import { literals } from '../../core/i18n/literals';
import { useLocale } from '../../hooks/useLocale';
import { GalleryEphemeral } from '../../stores/galleryEphemeral';
import { GalleryCard } from './Card';
@@ -2,7 +2,7 @@
import { Code, Flex, Heading, Text } from '@radix-ui/themes';
import { resolveBranchName } from '../core/blitzkit/branches';
import { getStrings } from '../core/i18n/getStrings';
import { literals } from '../core/i18n/literals';
import { literals } from '@blitzkit/i18n/src/literals';
const { locale } = Astro.params;
const branchName = resolveBranchName(locale);
@@ -1,9 +1,9 @@
import { assertSecret } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n/src/literals';
import { EyeOpenIcon } from '@radix-ui/react-icons';
import { Box, Flex, Heading, Text } from '@radix-ui/themes';
import { google } from 'googleapis';
import { awaitableTankDefinitions } from '../core/awaitables/tankDefinitions';
import { literals } from '../core/i18n/literals';
import {
LocaleProvider,
useLocale,
@@ -1,9 +1,9 @@
import { formatCompact } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n/src/literals';
import { InfoCircledIcon } from '@radix-ui/react-icons';
import { Callout, Flex } from '@radix-ui/themes';
import { awaitableAverageDefinitions } from '../../core/awaitables/averageDefinitions';
import { awaitableDiscoveredIdsDefinitions } from '../../core/awaitables/discoveredIdsDefinitions';
import { literals } from '../../core/i18n/literals';
import { useLocale } from '../../hooks/useLocale';
import type { MaybeSkeletonComponentProps } from '../../types/maybeSkeletonComponentProps';
import { InlineSkeleton } from '../InlineSkeleton';
@@ -5,6 +5,7 @@ import {
unionBoundingBox,
type TankDefinition,
} from '@blitzkit/core';
import { literals } from '@blitzkit/i18n/src/literals';
import { useStore } from '@nanostores/react';
import { Callout, Flex, Link, Text, type FlexProps } from '@radix-ui/themes';
import fuzzysort from 'fuzzysort';
@@ -16,7 +17,6 @@ import { awaitableTankDefinitions } from '../../core/awaitables/tankDefinitions'
import { awaitableTankNames } from '../../core/awaitables/tankNames';
import { filterTank } from '../../core/blitzkit/filterTank';
import { resolveReload } from '../../core/blitzkit/resolveReload';
import { literals } from '../../core/i18n/literals';
import { useLocale } from '../../hooks/useLocale';
import { $tankFilters } from '../../stores/tankFilters';
import { TankopediaPersistent } from '../../stores/tankopediaPersistent';
@@ -1,6 +1,6 @@
import { TIER_ROMAN_NUMERALS } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n/src/literals';
import { Flex, Heading, SegmentedControl, Text } from '@radix-ui/themes';
import { literals } from '../../../../../../core/i18n/literals';
import { useLocale } from '../../../../../../hooks/useLocale';
import { Duel } from '../../../../../../stores/duel';
import {
@@ -6,6 +6,7 @@ import {
isExplosive,
resolvePenetrationCoefficient,
} from '@blitzkit/core';
import { literals } from '@blitzkit/i18n/src/literals';
import { AccessibilityIcon, InfoCircledIcon } from '@radix-ui/react-icons';
import {
Flex,
@@ -25,7 +26,6 @@ import { awaitableEquipmentDefinitions } from '../../../../../core/awaitables/eq
import { awaitableProvisionDefinitions } from '../../../../../core/awaitables/provisionDefinitions';
import { applyPitchYawLimits } from '../../../../../core/blitz/applyPitchYawLimits';
import { tankCharacteristics } from '../../../../../core/blitzkit/tankCharacteristics';
import { literals } from '../../../../../core/i18n/literals';
import { useEquipment } from '../../../../../hooks/useEquipment';
import { useLocale } from '../../../../../hooks/useLocale';
import { useTankModelDefinition } from '../../../../../hooks/useTankModelDefinition';
@@ -1,4 +1,5 @@
import { imgur, ShellType } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n/src/literals';
import {
Button,
Flex,
@@ -11,7 +12,6 @@ import {
} from '@radix-ui/themes';
import { throttle } from 'lodash-es';
import { type ChangeEvent } from 'react';
import { literals } from '../../../../../../core/i18n/literals';
import { useLocale } from '../../../../../../hooks/useLocale';
import { Duel } from '../../../../../../stores/duel';
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
@@ -1,7 +1,7 @@
import { literals } from '@blitzkit/i18n/src/literals';
import { EyeClosedIcon, EyeOpenIcon, ReloadIcon } from '@radix-ui/react-icons';
import { Button, Checkbox, Flex, Text } from '@radix-ui/themes';
import { Suspense } from 'react';
import { literals } from '../../../../../../core/i18n/literals';
import { useLocale } from '../../../../../../hooks/useLocale';
import { TankopediaEphemeral } from '../../../../../../stores/tankopediaEphemeral';
import { TankopediaPersistent } from '../../../../../../stores/tankopediaPersistent';
@@ -5,6 +5,7 @@ import {
TIER_ROMAN_NUMERALS,
uniqueGuns,
} from '@blitzkit/core';
import { literals } from '@blitzkit/i18n/src/literals';
import {
CameraIcon,
CopyIcon,
@@ -30,7 +31,6 @@ import {
} from '@radix-ui/themes';
import { Suspense, useState, type RefObject } from 'react';
import { Pose, poseEvent } from '../../../../../core/blitzkit/pose';
import { literals } from '../../../../../core/i18n/literals';
import { useEquipment } from '../../../../../hooks/useEquipment';
import { useFullScreen } from '../../../../../hooks/useFullScreen';
import { useFullscreenAvailability } from '../../../../../hooks/useFullscreenAvailability';
@@ -1,8 +1,8 @@
import { asset, formatCompact, TIER_ROMAN_NUMERALS } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n/src/literals';
import { Box, Flex, Skeleton, Text } from '@radix-ui/themes';
import { awaitableAverageDefinitions } from '../../../../core/awaitables/averageDefinitions';
import { awaitableTankDefinitions } from '../../../../core/awaitables/tankDefinitions';
import { literals } from '../../../../core/i18n/literals';
import { useLocale } from '../../../../hooks/useLocale';
import { TankopediaEphemeral } from '../../../../stores/tankopediaEphemeral';
import type { MaybeSkeletonComponentProps } from '../../../../types/maybeSkeletonComponentProps';
@@ -1,9 +1,9 @@
import { asset, imgur, TankType } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n/src/literals';
import { CaretLeftIcon, CaretRightIcon, PlusIcon } from '@radix-ui/react-icons';
import { Flex, Heading, IconButton, ScrollArea, Text } from '@radix-ui/themes';
import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
import { awaitableTankDefinitions } from '../../../core/awaitables/tankDefinitions';
import { literals } from '../../../core/i18n/literals';
import { useLocale } from '../../../hooks/useLocale';
import { Duel } from '../../../stores/duel';
import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral';
@@ -1,7 +1,7 @@
import { youtubers } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n/src/literals';
import { Box, Flex, Heading, Link, Skeleton, Text } from '@radix-ui/themes';
import { awaitableReviews } from '../../core/awaitables/reviews';
import { literals } from '../../core/i18n/literals';
import { Var } from '../../core/radix/var';
import { useLocale } from '../../hooks/useLocale';
import { Duel } from '../../stores/duel';
@@ -21,7 +21,7 @@ import {
tierListTool,
} from '../../constants/tools';
import { getStrings } from '../../core/i18n/getStrings';
import { literals } from '../../core/i18n/literals';
import { literals } from '@blitzkit/i18n/src/literals';
import BaseLayout from '../../layouts/BaseLayout.astro';
const PUBLIC_ASSET_BRANCH = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH);
@@ -1,9 +1,9 @@
import { literals } from '@blitzkit/i18n/src/literals';
import { CalendarIcon } from '@radix-ui/react-icons';
import { Callout, Flex } from '@radix-ui/themes';
import { GalleryList, type Avatar } from '../../../../components/Gallery/List';
import { GallerySearch } from '../../../../components/Gallery/Search';
import { PageWrapper } from '../../../../components/PageWrapper';
import { literals } from '../../../../core/i18n/literals';
import {
LocaleProvider,
useLocale,
@@ -13,6 +13,7 @@ import {
type IndividualAccountInfo,
type IndividualTankStats,
} from '@blitzkit/core';
import { literals } from '@blitzkit/i18n/src/literals';
import {
ArrowDownIcon,
MagnifyingGlassIcon,
@@ -38,7 +39,6 @@ import { StickyTableRoot } from '../../../../components/StickyTableRoot';
import { TankRowHeaderCell } from '../../../../components/TankRowHeaderCell';
import { awaitableAverageDefinitions } from '../../../../core/awaitables/averageDefinitions';
import { awaitableTankDefinitions } from '../../../../core/awaitables/tankDefinitions';
import { literals } from '../../../../core/i18n/literals';
import {
LocaleProvider,
useLocale,
@@ -14,7 +14,7 @@ import { DEFAULT_LOCALE, unwrapper } from '@blitzkit/i18n';
import type { GetStaticPaths } from 'astro';
import { tankCharacteristics } from '../../../../../core/blitzkit/tankCharacteristics';
import { getStrings } from '../../../../../core/i18n/getStrings';
import { literals } from '../../../../../core/i18n/literals';
import { literals } from '@blitzkit/i18n/src/literals';
import BaseLayout from '../../../../../layouts/BaseLayout.astro';
import { genericDefaultEquipmentMatrix } from '../../../../../stores/duel/constants';
import { getStaticPaths as parentGetStaticPaths } from '../index.astro';