mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
feat: update bot chunk 1
This commit is contained in:
1 parent
bb557a7dd7
commit
d2b24fc953
42 files changed
+370
-389
No files matched your search
@@ -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;
|
||||
|
||||
@@ -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,3 +1,3 @@
|
||||
export * from './literals';
|
||||
export * from './strings';
|
||||
export * from './supportedLocales';
|
||||
export * from './unwrapper';
|
||||
File renamed without changes.
@@ -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;
|
||||
@@ -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,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
-1
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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
-1
@@ -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
-1
@@ -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';
|
||||
|
||||
Reference in new issue
Block a user