diff --git a/packages/bot/src/commands/auction.ts b/packages/bot/src/commands/auction.ts index cc8da1920..b04a089b3 100644 --- a/packages/bot/src/commands/auction.ts +++ b/packages/bot/src/commands/auction.ts @@ -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((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((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}`, ``, '', @@ -112,15 +113,18 @@ export const auctionCommand = new Promise((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; diff --git a/packages/bot/src/commands/inactive.tsx b/packages/bot/src/commands/inactive.tsx index 333acbec8..3e8fd4c69 100644 --- a/packages/bot/src/commands/inactive.tsx +++ b/packages/bot/src/commands/inactive.tsx @@ -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((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((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((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((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((resolve) => { {!hasInactiveMembers && ( diff --git a/packages/bot/src/core/discord/addPeriodSubCommands.ts b/packages/bot/src/core/discord/addPeriodSubCommands.ts index cbb3af751..b2f1b8c97 100644 --- a/packages/bot/src/core/discord/addPeriodSubCommands.ts +++ b/packages/bot/src/core/discord/addPeriodSubCommands.ts @@ -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), ), diff --git a/packages/bot/src/core/discord/addRegionChoices.ts b/packages/bot/src/core/discord/addRegionChoices.ts index 940ce69af..4ebe8b9eb 100644 --- a/packages/bot/src/core/discord/addRegionChoices.ts +++ b/packages/bot/src/core/discord/addRegionChoices.ts @@ -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, ), diff --git a/packages/bot/src/core/discord/addTankChoices.ts b/packages/bot/src/core/discord/addTankChoices.ts index 9db698e2a..c14f42dac 100644 --- a/packages/bot/src/core/discord/addTankChoices.ts +++ b/packages/bot/src/core/discord/addTankChoices.ts @@ -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); diff --git a/packages/bot/src/core/discord/addTierChoices.ts b/packages/bot/src/core/discord/addTierChoices.ts index 693632df4..d3a96e7f7 100644 --- a/packages/bot/src/core/discord/addTierChoices.ts +++ b/packages/bot/src/core/discord/addTierChoices.ts @@ -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, diff --git a/packages/bot/src/core/discord/autocompleteClan/index.ts b/packages/bot/src/core/discord/autocompleteClan/index.ts index a36c15713..5ed5d8d3f 100644 --- a/packages/bot/src/core/discord/autocompleteClan/index.ts +++ b/packages/bot/src/core/discord/autocompleteClan/index.ts @@ -10,7 +10,7 @@ import { DISCORD_CHOICES_MAX_NAME_SIZE, OVERFLOW_SUFFIX } from './constants'; export async function autocompleteClan( interaction: AutocompleteInteraction, ) { - 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 { diff --git a/packages/bot/src/core/discord/autocompleteUsername.ts b/packages/bot/src/core/discord/autocompleteUsername.ts index 7c4c1dfe1..522721c84 100644 --- a/packages/bot/src/core/discord/autocompleteUsername.ts +++ b/packages/bot/src/core/discord/autocompleteUsername.ts @@ -13,7 +13,7 @@ import { export async function autocompleteUsername( interaction: AutocompleteInteraction, ) { - 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 { diff --git a/packages/bot/src/core/discord/createLocalizedCommand.ts b/packages/bot/src/core/discord/createLocalizedCommand.ts index 280b8c1a7..42d15fdfa 100644 --- a/packages/bot/src/core/discord/createLocalizedCommand.ts +++ b/packages/bot/src/core/discord/createLocalizedCommand.ts @@ -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; + } + ).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; + } + ).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; + } + ).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; + } + ).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; + } + ).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; + } + ).groups[subItem.group].description, ) .setDescriptionLocalizations(subcommandDescriptionLocalizations); }); diff --git a/packages/bot/src/core/discord/getPeriodOptionName.ts b/packages/bot/src/core/discord/getPeriodOptionName.ts index f4a58e3ad..d72d8027d 100644 --- a/packages/bot/src/core/discord/getPeriodOptionName.ts +++ b/packages/bot/src/core/discord/getPeriodOptionName.ts @@ -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]); } diff --git a/packages/bot/src/core/discord/localizationObject.ts b/packages/bot/src/core/discord/localizationObject.ts index c0f3298a3..295f9cb09 100644 --- a/packages/bot/src/core/discord/localizationObject.ts +++ b/packages/bot/src/core/discord/localizationObject.ts @@ -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>>( (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) { diff --git a/packages/bot/src/core/discord/resolveClanFromCommand.ts b/packages/bot/src/core/discord/resolveClanFromCommand.ts index b4cfa3a30..6603acacc 100644 --- a/packages/bot/src/core/discord/resolveClanFromCommand.ts +++ b/packages/bot/src/core/discord/resolveClanFromCommand.ts @@ -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), + ]), ); } } diff --git a/packages/bot/src/core/discord/resolvePeriodFromCommand.ts b/packages/bot/src/core/discord/resolvePeriodFromCommand.ts index 61569e087..4b8555d93 100644 --- a/packages/bot/src/core/discord/resolvePeriodFromCommand.ts +++ b/packages/bot/src/core/discord/resolvePeriodFromCommand.ts @@ -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, 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}`, ]); diff --git a/packages/bot/src/core/discord/resolvePlayerFromCommand/index.ts b/packages/bot/src/core/discord/resolvePlayerFromCommand/index.ts index 88c5d2264..2d6039b40 100644 --- a/packages/bot/src/core/discord/resolvePlayerFromCommand/index.ts +++ b/packages/bot/src/core/discord/resolvePlayerFromCommand/index.ts @@ -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, ) { - 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); } } diff --git a/packages/bot/src/core/localization/strings/index.ts b/packages/bot/src/core/localization/strings/index.ts deleted file mode 100644 index 8c3bd645b..000000000 --- a/packages/bot/src/core/localization/strings/index.ts +++ /dev/null @@ -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> ->( - (table, locale) => ({ - ...table, - [locale]: require( - `@blitzkit/i18n/strings/${SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale]}.json`, - ), - }), - {}, -); diff --git a/packages/bot/src/core/localization/translator.ts b/packages/bot/src/core/localization/translator.ts index 93a68bc70..de62d1505 100644 --- a/packages/bot/src/core/localization/translator.ts +++ b/packages/bot/src/core/localization/translator.ts @@ -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 }; } diff --git a/packages/bot/src/events/interactionCreate/handlers/chatInputCommand.ts b/packages/bot/src/events/interactionCreate/handlers/chatInputCommand.ts index e75a0f8d3..02e567185 100644 --- a/packages/bot/src/events/interactionCreate/handlers/chatInputCommand.ts +++ b/packages/bot/src/events/interactionCreate/handlers/chatInputCommand.ts @@ -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, @@ -127,27 +125,25 @@ export async function handleChatInputCommand( } } catch (error) { const { t } = translator(interaction.locale); - const components = [ - new ActionRowBuilder().addComponents( - new ButtonBuilder() - .setLabel(t`bot.common.errors.get_help`) - .setURL('https://discord.gg/nDt7AjGJQH') - .setStyle(ButtonStyle.Link), - ), - ]; - - if (error instanceof UserError) { - interaction.editReply({ - content: error.message, - components, - }); - } else { - console.error(interaction.commandName, error); - - interaction.editReply({ - content: t`bot.common.errors.uncaught_error`, - components, - }); - } + // const components = [ + // new ActionRowBuilder().addComponents( + // new ButtonBuilder() + // .setLabel(t`bot.common.errors.get_help`) + // .setURL('https://discord.gg/nDt7AjGJQH') + // .setStyle(ButtonStyle.Link), + // ), + // ]; + // if (error instanceof UserError) { + // interaction.editReply({ + // content: error.message, + // components, + // }); + // } else { + // console.error(interaction.commandName, error); + // interaction.editReply({ + // content: t`bot.common.errors.uncaught_error`, + // components, + // }); + // } } } diff --git a/packages/bot/src/events/interactionCreate/index.ts b/packages/bot/src/events/interactionCreate/index.ts index a7f2b3906..846fd3fd3 100644 --- a/packages/bot/src/events/interactionCreate/index.ts +++ b/packages/bot/src/events/interactionCreate/index.ts @@ -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) => void; button?: (interaction: ButtonInteraction) => InteractionReturnable; } + interface CommandRegistryImplicit extends CommandRegistryBase { handlesInteraction: true; handler: (interaction: ChatInputCommandInteraction) => void; } + interface CommandRegistryExplicit extends CommandRegistryBase { handlesInteraction?: false; handler: ( interaction: ChatInputCommandInteraction, ) => InteractionReturnable; } + export type CommandRegistry = CommandRegistryImplicit | CommandRegistryExplicit; export const COMMANDS_RAW: Promise[] = [ - auctionCommand, - permissionsCommand, - debugCommand, - aboutCommand, - inactiveCommand, - ownedTanksCommand, - playerInfoCommand, - searchClansCommand, - searchPlayersCommand, - fullStatsCommand, - breakdownCommand, - verifyCommand, - pingCommand, - evolutionCommand, - statsCommand, - ratingLeaderboardCommand, - todayCommand, - researchCommand, - ratingCommand, - replayCommand, + // auctionCommand, + // permissionsCommand, + // debugCommand, + // aboutCommand, + // inactiveCommand, + // ownedTanksCommand, + // playerInfoCommand, + // searchClansCommand, + // searchPlayersCommand, + // fullStatsCommand, + // breakdownCommand, + // verifyCommand, + // pingCommand, + // evolutionCommand, + // statsCommand, + // ratingLeaderboardCommand, + // todayCommand, + // researchCommand, + // ratingCommand, + // replayCommand, ]; export const commands = Promise.allSettled(COMMANDS_RAW).then((rawCommands) => { - return rawCommands.reduce>( - (commands, registry, index) => { - if (registry.status === 'rejected') { - console.warn( - `Command ${index} failed to load; skipping...`, - registry.reason, - ); - - return commands; - } - - return { ...commands, [registry.value.command.name]: registry.value }; - }, - {}, - ); + // return rawCommands.reduce>( + // (commands, registry, index) => { + // if (registry.status === 'rejected') { + // console.warn( + // `Command ${index} failed to load; skipping...`, + // registry.reason, + // ); + // return commands; + // } + // return { ...commands, [registry.value.command.name]: registry.value }; + // }, + // {}, + // ); }); -const rest = new REST().setToken(assertSecret(import.meta.env.DISCORD_TOKEN)); +// const rest = new REST().setToken(assertSecret(import.meta.env.DISCORD_TOKEN)); -commands.then((awaitedCommands) => { - const body = Object.values(awaitedCommands).map((registry) => - registry.command.toJSON(), - ); +// commands.then((awaitedCommands) => { +// const body = Object.values(awaitedCommands).map((registry) => +// registry.command.toJSON(), +// ); - rest.put( - Routes.applicationCommands(assertSecret(import.meta.env.DISCORD_CLIENT_ID)), - { body }, - ); -}); +// rest.put( +// Routes.applicationCommands(assertSecret(import.meta.env.DISCORD_CLIENT_ID)), +// { body }, +// ); +// }); export async function interactionCreate(interaction: Interaction) { if (interaction.isAutocomplete()) { @@ -136,6 +113,6 @@ export async function interactionCreate(interaction: Interaction) { } else if (interaction.isChatInputCommand()) { handleChatInputCommand(interaction); } else if (interaction.isButton()) { - handleButton(interaction); + // handleButton(interaction); } } diff --git a/packages/i18n/src/index.ts b/packages/i18n/src/index.ts index a403c6a03..1d7e6b8b6 100644 --- a/packages/i18n/src/index.ts +++ b/packages/i18n/src/index.ts @@ -1,3 +1,3 @@ +export * from './literals'; export * from './strings'; -export * from './supportedLocales'; export * from './unwrapper'; diff --git a/packages/website/src/core/i18n/literals.ts b/packages/i18n/src/literals.ts similarity index 100% rename from packages/website/src/core/i18n/literals.ts rename to packages/i18n/src/literals.ts diff --git a/packages/i18n/src/strings.ts b/packages/i18n/src/strings.ts index 679268e56..687eb2e7e 100644 --- a/packages/i18n/src/strings.ts +++ b/packages/i18n/src/strings.ts @@ -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 = {}; +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> = {}; + +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 = { + 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 = { + en: 'πŸ‡ΊπŸ‡Έ', + es: 'πŸ‡ͺπŸ‡Έ', + fr: 'πŸ‡«πŸ‡·', + ja: 'πŸ‡―πŸ‡΅', + pt: 'πŸ‡΅πŸ‡Ή', + ru: 'πŸ‡·πŸ‡Ί', + uk: 'πŸ‡ΊπŸ‡¦', + zh: 'πŸ‡¨πŸ‡³', + pl: 'πŸ‡΅πŸ‡±', +}; + +export type TranslationTree = { [key: string]: TranslationNode }; + +export type TranslationNode = string | TranslationTree; diff --git a/packages/i18n/src/supportedLocales.ts b/packages/i18n/src/supportedLocales.ts deleted file mode 100644 index 9ebaa2582..000000000 --- a/packages/i18n/src/supportedLocales.ts +++ /dev/null @@ -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 = { - 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 = { - en: 'πŸ‡ΊπŸ‡Έ', - es: 'πŸ‡ͺπŸ‡Έ', - fr: 'πŸ‡«πŸ‡·', - ja: 'πŸ‡―πŸ‡΅', - pt: 'πŸ‡΅πŸ‡Ή', - ru: 'πŸ‡·πŸ‡Ί', - uk: 'πŸ‡ΊπŸ‡¦', - zh: 'πŸ‡¨πŸ‡³', - pl: 'πŸ‡΅πŸ‡±', -}; diff --git a/packages/i18n/src/unwrapper.ts b/packages/i18n/src/unwrapper.ts index df57728c0..7c18ae5ba 100644 --- a/packages/i18n/src/unwrapper.ts +++ b/packages/i18n/src/unwrapper.ts @@ -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) { diff --git a/packages/website/src/components/Armor/components/ShotDisplayCard.tsx b/packages/website/src/components/Armor/components/ShotDisplayCard.tsx index 994e4a2c5..fb7d56ffc 100644 --- a/packages/website/src/components/Armor/components/ShotDisplayCard.tsx +++ b/packages/website/src/components/Armor/components/ShotDisplayCard.tsx @@ -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'; diff --git a/packages/website/src/components/Embeds/GenerateURL.tsx b/packages/website/src/components/Embeds/GenerateURL.tsx index 2143513cf..fcbca17c8 100644 --- a/packages/website/src/components/Embeds/GenerateURL.tsx +++ b/packages/website/src/components/Embeds/GenerateURL.tsx @@ -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'; diff --git a/packages/website/src/components/Gallery/List.tsx b/packages/website/src/components/Gallery/List.tsx index d83456f18..d4a7d21c2 100644 --- a/packages/website/src/components/Gallery/List.tsx +++ b/packages/website/src/components/Gallery/List.tsx @@ -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'; diff --git a/packages/website/src/components/HomeHero.astro b/packages/website/src/components/HomeHero.astro index 49cf52354..3105cc0e9 100644 --- a/packages/website/src/components/HomeHero.astro +++ b/packages/website/src/components/HomeHero.astro @@ -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); diff --git a/packages/website/src/components/HomePageHotTanks.tsx b/packages/website/src/components/HomePageHotTanks.tsx index 939be24b4..2a0aebac6 100644 --- a/packages/website/src/components/HomePageHotTanks.tsx +++ b/packages/website/src/components/HomePageHotTanks.tsx @@ -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, diff --git a/packages/website/src/components/Performance/PerformanceInfo.tsx b/packages/website/src/components/Performance/PerformanceInfo.tsx index 8a54752ea..6d63b4e53 100644 --- a/packages/website/src/components/Performance/PerformanceInfo.tsx +++ b/packages/website/src/components/Performance/PerformanceInfo.tsx @@ -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'; diff --git a/packages/website/src/components/TankSearch/index.tsx b/packages/website/src/components/TankSearch/index.tsx index 5f8ea8226..6fb6dae05 100644 --- a/packages/website/src/components/TankSearch/index.tsx +++ b/packages/website/src/components/TankSearch/index.tsx @@ -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'; diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/Heading.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/Heading.tsx index 675fc4ca8..f03b81077 100644 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/Heading.tsx +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/Heading.tsx @@ -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 { diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/index.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/index.tsx index 173cc2120..6e8e557eb 100644 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/index.tsx +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/index.tsx @@ -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'; diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/CustomShellButton.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/CustomShellButton.tsx index ff824c6f0..3a4d1b214 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/CustomShellButton.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/CustomShellButton.tsx @@ -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'; diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/Thicknesses.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/Thicknesses.tsx index f902ba16c..7aa365e85 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/Thicknesses.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/components/Thicknesses.tsx @@ -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'; diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx index cf5f90fe8..4a81b15ac 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/Options/index.tsx @@ -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'; diff --git a/packages/website/src/components/Tankopedia/TechTreeSection/components/Node.tsx b/packages/website/src/components/Tankopedia/TechTreeSection/components/Node.tsx index aa29504a1..6ea625045 100644 --- a/packages/website/src/components/Tankopedia/TechTreeSection/components/Node.tsx +++ b/packages/website/src/components/Tankopedia/TechTreeSection/components/Node.tsx @@ -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'; diff --git a/packages/website/src/components/Tankopedia/TechTreeSection/index.tsx b/packages/website/src/components/Tankopedia/TechTreeSection/index.tsx index f806ea284..d34874c68 100644 --- a/packages/website/src/components/Tankopedia/TechTreeSection/index.tsx +++ b/packages/website/src/components/Tankopedia/TechTreeSection/index.tsx @@ -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'; diff --git a/packages/website/src/components/Tankopedia/VideoSection.tsx b/packages/website/src/components/Tankopedia/VideoSection.tsx index 9ff16df1c..f910b2cde 100644 --- a/packages/website/src/components/Tankopedia/VideoSection.tsx +++ b/packages/website/src/components/Tankopedia/VideoSection.tsx @@ -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'; diff --git a/packages/website/src/pages/[...locale]/index.astro b/packages/website/src/pages/[...locale]/index.astro index 8a4d49d21..025a9ef1c 100644 --- a/packages/website/src/pages/[...locale]/index.astro +++ b/packages/website/src/pages/[...locale]/index.astro @@ -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); diff --git a/packages/website/src/pages/[...locale]/tools/gallery/_index.tsx b/packages/website/src/pages/[...locale]/tools/gallery/_index.tsx index 3d856b2b4..06a07c78a 100644 --- a/packages/website/src/pages/[...locale]/tools/gallery/_index.tsx +++ b/packages/website/src/pages/[...locale]/tools/gallery/_index.tsx @@ -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, diff --git a/packages/website/src/pages/[...locale]/tools/session/_index.tsx b/packages/website/src/pages/[...locale]/tools/session/_index.tsx index 53b4156a2..f231a4617 100644 --- a/packages/website/src/pages/[...locale]/tools/session/_index.tsx +++ b/packages/website/src/pages/[...locale]/tools/session/_index.tsx @@ -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, diff --git a/packages/website/src/pages/[...locale]/tools/tankopedia/[id]/index.astro b/packages/website/src/pages/[...locale]/tools/tankopedia/[id]/index.astro index b6b65eead..29fdad238 100644 --- a/packages/website/src/pages/[...locale]/tools/tankopedia/[id]/index.astro +++ b/packages/website/src/pages/[...locale]/tools/tankopedia/[id]/index.astro @@ -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';