mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 20:19:49 +02:00
feat: localize tankopedia tech tree
This commit is contained in:
1 parent
ceb7842d49
commit
7900c61a9b
7 files changed
+44
-27
No files matched your search
@@ -6,11 +6,12 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"common": {
|
"common": {
|
||||||
"units_suffix": {
|
"units": {
|
||||||
"m": "%s1m",
|
"m": "%s1m",
|
||||||
"mm": "%s1mm",
|
"mm": "%s1mm",
|
||||||
"deg": "%s1°",
|
"deg": "%s1°",
|
||||||
"hp": "%s1hp"
|
"hp": "%s1hp",
|
||||||
|
"x": "x%s1"
|
||||||
},
|
},
|
||||||
|
|
||||||
"shells": {
|
"shells": {
|
||||||
@@ -923,6 +924,13 @@
|
|||||||
"restoration": "Restoration price",
|
"restoration": "Restoration price",
|
||||||
"sale": "Sale price",
|
"sale": "Sale price",
|
||||||
"research": "Research XP"
|
"research": "Research XP"
|
||||||
|
},
|
||||||
|
|
||||||
|
"tech_tree": {
|
||||||
|
"title": "Tech tree",
|
||||||
|
"battle": "1 battle",
|
||||||
|
"battles": "%s1 battles",
|
||||||
|
"route": "Route %s1 of %s2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"compare": {
|
"compare": {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ function LayerEntry({
|
|||||||
{layer.type === null && (
|
{layer.type === null && (
|
||||||
<>
|
<>
|
||||||
<Text size="2" color={shotStatusColor} style={{ width: 64 }}>
|
<Text size="2" color={shotStatusColor} style={{ width: 64 }}>
|
||||||
{literals(strings.common.units_suffix.mm, [
|
{literals(strings.common.units.mm, [
|
||||||
Math.round(layer.distance * 1000).toLocaleString(locale),
|
Math.round(layer.distance * 1000).toLocaleString(locale),
|
||||||
])}
|
])}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -65,7 +65,7 @@ function LayerEntry({
|
|||||||
|
|
||||||
{layer.type === ArmorType.External && (
|
{layer.type === ArmorType.External && (
|
||||||
<Text size="2" color={shotStatusColor} style={{ width: 64 }}>
|
<Text size="2" color={shotStatusColor} style={{ width: 64 }}>
|
||||||
{literals(strings.common.units_suffix.mm, [
|
{literals(strings.common.units.mm, [
|
||||||
Math.round(layer.thickness).toLocaleString(locale),
|
Math.round(layer.thickness).toLocaleString(locale),
|
||||||
])}
|
])}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -77,7 +77,7 @@ function LayerEntry({
|
|||||||
<Text size="2" color={shotStatusColor} style={{ width: 80 }}>
|
<Text size="2" color={shotStatusColor} style={{ width: 80 }}>
|
||||||
{literals(
|
{literals(
|
||||||
angle === undefined
|
angle === undefined
|
||||||
? strings.common.units_suffix.mm
|
? strings.common.units.mm
|
||||||
: strings.website.tools.tankopedia.sandbox.dynamic.shot_card
|
: strings.website.tools.tankopedia.sandbox.dynamic.shot_card
|
||||||
.stats.thickness_and_angle,
|
.stats.thickness_and_angle,
|
||||||
[
|
[
|
||||||
|
|||||||
+4
-4
@@ -151,7 +151,7 @@ export function CustomShellButton() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TextField.Slot side="right">
|
<TextField.Slot side="right">
|
||||||
{literals(strings.common.units_suffix.mm, [''])}
|
{literals(strings.common.units.mm, [''])}
|
||||||
</TextField.Slot>
|
</TextField.Slot>
|
||||||
</TextField.Root>
|
</TextField.Root>
|
||||||
</Flex>
|
</Flex>
|
||||||
@@ -187,7 +187,7 @@ export function CustomShellButton() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TextField.Slot side="right">
|
<TextField.Slot side="right">
|
||||||
{literals(strings.common.units_suffix.mm, [''])}
|
{literals(strings.common.units.mm, [''])}
|
||||||
</TextField.Slot>
|
</TextField.Slot>
|
||||||
</TextField.Root>
|
</TextField.Root>
|
||||||
</Flex>
|
</Flex>
|
||||||
@@ -211,7 +211,7 @@ export function CustomShellButton() {
|
|||||||
minWidth="8rem"
|
minWidth="8rem"
|
||||||
>
|
>
|
||||||
<Text color="gray">
|
<Text color="gray">
|
||||||
{literals(strings.common.units_suffix.deg, [
|
{literals(strings.common.units.deg, [
|
||||||
(customShell.normalization ?? 0).toFixed(0),
|
(customShell.normalization ?? 0).toFixed(0),
|
||||||
])}
|
])}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -241,7 +241,7 @@ export function CustomShellButton() {
|
|||||||
|
|
||||||
<Flex align="center" gap="2" flexGrow="1" maxWidth="15rem">
|
<Flex align="center" gap="2" flexGrow="1" maxWidth="15rem">
|
||||||
<Text color="gray">
|
<Text color="gray">
|
||||||
{literals(strings.common.units_suffix.deg, [
|
{literals(strings.common.units.deg, [
|
||||||
(customShell.ricochet ?? 90).toFixed(0),
|
(customShell.ricochet ?? 90).toFixed(0),
|
||||||
])}
|
])}
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
+4
-4
@@ -55,7 +55,7 @@ export function Thicknesses({ thicknessRange }: ThicknessesProps) {
|
|||||||
>
|
>
|
||||||
<Flex direction="column" align="end" justify="between">
|
<Flex direction="column" align="end" justify="between">
|
||||||
<Text color="gray" size="1">
|
<Text color="gray" size="1">
|
||||||
{literals(strings.common.units_suffix.mm, [
|
{literals(strings.common.units.mm, [
|
||||||
(thicknessRange.value * 1.5).toFixed(0),
|
(thicknessRange.value * 1.5).toFixed(0),
|
||||||
])}
|
])}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -63,7 +63,7 @@ export function Thicknesses({ thicknessRange }: ThicknessesProps) {
|
|||||||
{strings.website.tools.tankopedia.sandbox.static.primary}
|
{strings.website.tools.tankopedia.sandbox.static.primary}
|
||||||
</Text>
|
</Text>
|
||||||
<Text color="gray" size="1">
|
<Text color="gray" size="1">
|
||||||
{literals(strings.common.units_suffix.mm, ['0'])}
|
{literals(strings.common.units.mm, ['0'])}
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ export function Thicknesses({ thicknessRange }: ThicknessesProps) {
|
|||||||
>
|
>
|
||||||
<Flex direction="column" align="end" justify="between">
|
<Flex direction="column" align="end" justify="between">
|
||||||
<Text color="gray" size="1">
|
<Text color="gray" size="1">
|
||||||
{literals(strings.common.units_suffix.mm, [
|
{literals(strings.common.units.mm, [
|
||||||
thicknessRange.value.toFixed(0),
|
thicknessRange.value.toFixed(0),
|
||||||
])}
|
])}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -104,7 +104,7 @@ export function Thicknesses({ thicknessRange }: ThicknessesProps) {
|
|||||||
{strings.website.tools.tankopedia.sandbox.static.spaced}
|
{strings.website.tools.tankopedia.sandbox.static.spaced}
|
||||||
</Text>
|
</Text>
|
||||||
<Text color="gray" size="1">
|
<Text color="gray" size="1">
|
||||||
{literals(strings.common.units_suffix.mm, ['0'])}
|
{literals(strings.common.units.mm, ['0'])}
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ export function Options({ thicknessRange, canvas }: OptionsProps) {
|
|||||||
>
|
>
|
||||||
{!hasCustomShell && (
|
{!hasCustomShell && (
|
||||||
<Text color="gray" size={{ initial: '1', sm: '2' }}>
|
<Text color="gray" size={{ initial: '1', sm: '2' }}>
|
||||||
{literals(strings.common.units_suffix.mm, [
|
{literals(strings.common.units.mm, [
|
||||||
(
|
(
|
||||||
resolvePenetrationCoefficient(
|
resolvePenetrationCoefficient(
|
||||||
hasCalibratedShells,
|
hasCalibratedShells,
|
||||||
@@ -202,7 +202,7 @@ export function Options({ thicknessRange, canvas }: OptionsProps) {
|
|||||||
}
|
}
|
||||||
secondaryDiscriminator={
|
secondaryDiscriminator={
|
||||||
<Text style={{ fontSize: '0.75em' }}>
|
<Text style={{ fontSize: '0.75em' }}>
|
||||||
{literals(strings.common.units_suffix.mm, [
|
{literals(strings.common.units.mm, [
|
||||||
gun.gun_type!.value.base.shells[0].caliber.toFixed(
|
gun.gun_type!.value.base.shells[0].caliber.toFixed(
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { asset, formatCompact, TIER_ROMAN_NUMERALS } from '@blitzkit/core';
|
|||||||
import { Box, Flex, Skeleton, Text } from '@radix-ui/themes';
|
import { Box, Flex, Skeleton, Text } from '@radix-ui/themes';
|
||||||
import { awaitableAverageDefinitions } from '../../../../core/awaitables/averageDefinitions';
|
import { awaitableAverageDefinitions } from '../../../../core/awaitables/averageDefinitions';
|
||||||
import { awaitableTankDefinitions } from '../../../../core/awaitables/tankDefinitions';
|
import { awaitableTankDefinitions } from '../../../../core/awaitables/tankDefinitions';
|
||||||
|
import { literals } from '../../../../core/i18n/literals';
|
||||||
import { useLocale } from '../../../../hooks/useLocale';
|
import { useLocale } from '../../../../hooks/useLocale';
|
||||||
import { TankopediaEphemeral } from '../../../../stores/tankopediaEphemeral';
|
import { TankopediaEphemeral } from '../../../../stores/tankopediaEphemeral';
|
||||||
import type { MaybeSkeletonComponentProps } from '../../../../types/maybeSkeletonComponentProps';
|
import type { MaybeSkeletonComponentProps } from '../../../../types/maybeSkeletonComponentProps';
|
||||||
@@ -19,7 +20,7 @@ const [tankDefinitions, averageDefinitions] = await Promise.all([
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
export function Node({ id, highlight, nextIds, skeleton }: NodeProps) {
|
export function Node({ id, highlight, nextIds, skeleton }: NodeProps) {
|
||||||
const { locale } = useLocale();
|
const { locale, strings } = useLocale();
|
||||||
const xpMultiplier = TankopediaEphemeral.use((state) => state.xpMultiplier);
|
const xpMultiplier = TankopediaEphemeral.use((state) => state.xpMultiplier);
|
||||||
const tank = tankDefinitions.tanks[id];
|
const tank = tankDefinitions.tanks[id];
|
||||||
const nextTanks = nextIds?.map((id) => tankDefinitions.tanks[id]);
|
const nextTanks = nextIds?.map((id) => tankDefinitions.tanks[id]);
|
||||||
@@ -106,7 +107,7 @@ export function Node({ id, highlight, nextIds, skeleton }: NodeProps) {
|
|||||||
objectPosition: 'center',
|
objectPosition: 'center',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{formatCompact(thisTankXp)}
|
{formatCompact(locale, thisTankXp)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Text>
|
</Text>
|
||||||
<Text color="gray" size="1" wrap="nowrap">
|
<Text color="gray" size="1" wrap="nowrap">
|
||||||
@@ -121,7 +122,7 @@ export function Node({ id, highlight, nextIds, skeleton }: NodeProps) {
|
|||||||
objectPosition: 'center',
|
objectPosition: 'center',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{formatCompact(tank.price.value)}
|
{formatCompact(locale, tank.price.value)}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
@@ -129,11 +130,13 @@ export function Node({ id, highlight, nextIds, skeleton }: NodeProps) {
|
|||||||
{averages && nextTanks && tank.tier !== 10 && (
|
{averages && nextTanks && tank.tier !== 10 && (
|
||||||
<Text color="gray" size="1" mt="2">
|
<Text color="gray" size="1" mt="2">
|
||||||
{skeleton && <Skeleton height="1em" width="4em" />}
|
{skeleton && <Skeleton height="1em" width="4em" />}
|
||||||
{!skeleton && (
|
{!skeleton &&
|
||||||
<>
|
(games === 1
|
||||||
{games!} {games === 1 ? 'battle' : 'battles'}
|
? strings.website.tools.tankopedia.tech_tree.battle
|
||||||
</>
|
: literals(
|
||||||
)}
|
strings.website.tools.tankopedia.tech_tree.battles,
|
||||||
|
[`${games}`],
|
||||||
|
))}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { CaretLeftIcon, CaretRightIcon, PlusIcon } from '@radix-ui/react-icons';
|
|||||||
import { Flex, Heading, IconButton, ScrollArea, Text } from '@radix-ui/themes';
|
import { Flex, Heading, IconButton, ScrollArea, Text } from '@radix-ui/themes';
|
||||||
import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
|
import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { awaitableTankDefinitions } from '../../../core/awaitables/tankDefinitions';
|
import { awaitableTankDefinitions } from '../../../core/awaitables/tankDefinitions';
|
||||||
|
import { literals } from '../../../core/i18n/literals';
|
||||||
import { useLocale } from '../../../hooks/useLocale';
|
import { useLocale } from '../../../hooks/useLocale';
|
||||||
import { Duel } from '../../../stores/duel';
|
import { Duel } from '../../../stores/duel';
|
||||||
import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral';
|
import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral';
|
||||||
@@ -17,7 +18,7 @@ const tankDefinitions = await awaitableTankDefinitions;
|
|||||||
export const XP_MULTIPLIERS = [1, 2, 3, 4, 5, 10];
|
export const XP_MULTIPLIERS = [1, 2, 3, 4, 5, 10];
|
||||||
|
|
||||||
export function TechTreeSection({ skeleton }: MaybeSkeletonComponentProps) {
|
export function TechTreeSection({ skeleton }: MaybeSkeletonComponentProps) {
|
||||||
const { locale } = useLocale();
|
const { locale, strings } = useLocale();
|
||||||
const master = Duel.use((state) => state.protagonist.tank);
|
const master = Duel.use((state) => state.protagonist.tank);
|
||||||
const xpMultiplier = TankopediaEphemeral.use((state) => state.xpMultiplier);
|
const xpMultiplier = TankopediaEphemeral.use((state) => state.xpMultiplier);
|
||||||
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
|
||||||
@@ -91,7 +92,9 @@ export function TechTreeSection({ skeleton }: MaybeSkeletonComponentProps) {
|
|||||||
py="6"
|
py="6"
|
||||||
>
|
>
|
||||||
<Flex direction="column" align="center">
|
<Flex direction="column" align="center">
|
||||||
<Heading size="6">Tech tree</Heading>
|
<Heading size="6">
|
||||||
|
{strings.website.tools.tankopedia.tech_tree.title}
|
||||||
|
</Heading>
|
||||||
|
|
||||||
{master.tier > 1 && (
|
{master.tier > 1 && (
|
||||||
<Flex gap="4" align="center">
|
<Flex gap="4" align="center">
|
||||||
@@ -156,7 +159,7 @@ export function TechTreeSection({ skeleton }: MaybeSkeletonComponentProps) {
|
|||||||
pl="1"
|
pl="1"
|
||||||
>
|
>
|
||||||
<Text size="2">
|
<Text size="2">
|
||||||
x<b>{multiplier}</b>
|
{literals(strings.common.units.x, [`${multiplier}`])}
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
@@ -216,7 +219,10 @@ export function TechTreeSection({ skeleton }: MaybeSkeletonComponentProps) {
|
|||||||
<CaretLeftIcon />
|
<CaretLeftIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Text>
|
<Text>
|
||||||
Route {lineIndex + 1} of {lines.length}
|
{literals(strings.website.tools.tankopedia.tech_tree.route, [
|
||||||
|
`${lineIndex + 1}`,
|
||||||
|
`${lines.length}`,
|
||||||
|
])}
|
||||||
</Text>
|
</Text>
|
||||||
<IconButton
|
<IconButton
|
||||||
size="2"
|
size="2"
|
||||||
|
|||||||
Reference in new issue
Block a user