feat: some more localized links

This commit is contained in:
tresabhi committed 2024-12-27 14:01:59 -06:00
1 parent 8203db3dc2
commit e0daf85561
19 files changed
+182 -81

No files matched your search

@@ -1,8 +1,10 @@
import { assertSecret, idToRegion } from '@blitzkit/core'; import { assertSecret, idToRegion } from '@blitzkit/core';
import { Button, Flex, Heading, Link, Text } from '@radix-ui/themes'; import { Button, Flex, Heading, Text } from '@radix-ui/themes';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useLocale } from '../../hooks/useLocale';
import { App } from '../../stores/app'; import { App } from '../../stores/app';
import { CURRENT_POLICIES_AGREEMENT_INDEX } from '../../stores/app/constants'; import { CURRENT_POLICIES_AGREEMENT_INDEX } from '../../stores/app/constants';
import { LinkI18n } from '../LinkI18n';
import './index.css'; import './index.css';
type Extension = type Extension =
@@ -30,6 +32,7 @@ export function Checks() {
* Wargaming: 14 (refresh: 7) * Wargaming: 14 (refresh: 7)
*/ */
function Content() { function Content() {
const { locale } = useLocale();
const logins = App.use((state) => state.logins); const logins = App.use((state) => state.logins);
const mutateApp = App.useMutation(); const mutateApp = App.useMutation();
const appStore = App.useStore(); const appStore = App.useStore();
@@ -118,9 +121,14 @@ function Content() {
<Text> <Text>
This website utilizes cookies to perform analytics and personalize This website utilizes cookies to perform analytics and personalize
your experience. You can learn more through{' '} your experience. You can learn more through{' '}
<Link href="/docs/legal/privacy-policy">our privacy policy</Link>. <LinkI18n locale={locale} href="/docs/legal/privacy-policy">
By using BlitzKit, you also agree to our{' '} our privacy policy
<Link href="/docs/legal/terms-of-service">terms of service</Link>. </LinkI18n>
. By using BlitzKit, you also agree to our{' '}
<LinkI18n locale={locale} href="/docs/legal/terms-of-service">
terms of service
</LinkI18n>
.
</Text> </Text>
</Flex> </Flex>
@@ -1,9 +1,11 @@
import { ExternalLinkIcon, LoopIcon, TrashIcon } from '@radix-ui/react-icons'; import { ExternalLinkIcon, LoopIcon, TrashIcon } from '@radix-ui/react-icons';
import { Dialog, Flex, IconButton, Link } from '@radix-ui/themes'; import { Dialog, Flex, IconButton } from '@radix-ui/themes';
import { useState } from 'react'; import { useState } from 'react';
import { awaitableProvisionDefinitions } from '../../core/awaitables/provisionDefinitions'; import { awaitableProvisionDefinitions } from '../../core/awaitables/provisionDefinitions';
import { tankToCompareMember } from '../../core/blitzkit/tankToCompareMember'; import { tankToCompareMember } from '../../core/blitzkit/tankToCompareMember';
import { useLocale } from '../../hooks/useLocale';
import { CompareEphemeral } from '../../stores/compareEphemeral'; import { CompareEphemeral } from '../../stores/compareEphemeral';
import { LinkI18n } from '../LinkI18n';
import { TankSearch } from '../TankSearch'; import { TankSearch } from '../TankSearch';
interface TankControlProps { interface TankControlProps {
@@ -14,6 +16,7 @@ interface TankControlProps {
const provisionDefinitions = await awaitableProvisionDefinitions; const provisionDefinitions = await awaitableProvisionDefinitions;
export function TankControl({ index, id }: TankControlProps) { export function TankControl({ index, id }: TankControlProps) {
const { locale } = useLocale();
const [switchTankDialogOpen, setSwitchTankDialogOpen] = useState(false); const [switchTankDialogOpen, setSwitchTankDialogOpen] = useState(false);
const mutateCompareEphemeral = CompareEphemeral.useMutation(); const mutateCompareEphemeral = CompareEphemeral.useMutation();
@@ -69,11 +72,15 @@ export function TankControl({ index, id }: TankControlProps) {
</Dialog.Content> </Dialog.Content>
</Dialog.Root> </Dialog.Root>
<Link href={`/tools/tankopedia/${id}`} target="_blank"> <LinkI18n
locale={locale}
href={`/tools/tankopedia/${id}`}
target="_blank"
>
<IconButton variant="ghost"> <IconButton variant="ghost">
<ExternalLinkIcon /> <ExternalLinkIcon />
</IconButton> </IconButton>
</Link> </LinkI18n>
</Flex> </Flex>
); );
} }
@@ -3,6 +3,7 @@ import { EyeOpenIcon } from '@radix-ui/react-icons';
import { Box, Flex, Heading, Text } from '@radix-ui/themes'; import { Box, Flex, Heading, Text } from '@radix-ui/themes';
import { google } from 'googleapis'; import { google } from 'googleapis';
import { awaitableTankDefinitions } from '../core/awaitables/tankDefinitions'; import { awaitableTankDefinitions } from '../core/awaitables/tankDefinitions';
import { LocaleProvider } from '../hooks/useLocale';
import { TankopediaPersistent } from '../stores/tankopediaPersistent'; import { TankopediaPersistent } from '../stores/tankopediaPersistent';
import { TankCard } from './TankCard'; import { TankCard } from './TankCard';
@@ -63,11 +64,17 @@ const hotTanks = report.data.rows
views, views,
})); }));
export function HomePageHotTanks() { interface HomePageHotTanksProps {
locale: string | undefined;
}
export function HomePageHotTanks({ locale }: HomePageHotTanksProps) {
return ( return (
<TankopediaPersistent.Provider> <LocaleProvider locale={locale}>
<Content /> <TankopediaPersistent.Provider>
</TankopediaPersistent.Provider> <Content />
</TankopediaPersistent.Provider>
</LocaleProvider>
); );
} }
+1 -4
View File
@@ -11,9 +11,6 @@ export function LinkI18n({ locale, href, ...props }: LinkI18nProps) {
const prefix = resolvedLocale === undefined ? '' : `/${resolvedLocale}`; const prefix = resolvedLocale === undefined ? '' : `/${resolvedLocale}`;
return ( return (
<Link <Link href={href?.startsWith('/') ? `${prefix}${href}` : href} {...props} />
href={href === undefined ? undefined : `${prefix}${href}`}
{...props}
/>
); );
} }
+14 -8
View File
@@ -20,11 +20,13 @@ import {
import { resolveBranchName } from '../core/blitzkit/branches'; import { resolveBranchName } from '../core/blitzkit/branches';
import { homeTool, TOOLS } from '../constants/tools'; import { homeTool, TOOLS } from '../constants/tools';
import { NavbarAccount } from './NavbarAccount'; import { NavbarAccount } from './NavbarAccount';
import { LinkI18n } from './LinkI18n';
const toolsFiltered = TOOLS.filter((tool) => !('href' in tool)); const toolsFiltered = TOOLS.filter((tool) => !('href' in tool));
const tools = [homeTool, ...toolsFiltered]; const tools = [homeTool, ...toolsFiltered];
const branchName = resolveBranchName(); const branchName = resolveBranchName();
const isBranchNamed = branchName !== undefined; const isBranchNamed = branchName !== undefined;
const { locale } = Astro.params;
--- ---
<style> <style>
@@ -108,7 +110,8 @@ const isBranchNamed = branchName !== undefined;
<Flex className="expander" data-expanded="false" direction="column" gap="2"> <Flex className="expander" data-expanded="false" direction="column" gap="2">
<Flex justify="center"> <Flex justify="center">
<Flex flexGrow="1" maxWidth="1024px" p="3" align="center"> <Flex flexGrow="1" maxWidth="1024px" p="3" align="center">
<Link <LinkI18n
{locale}
color="gray" color="gray"
highContrast highContrast
href="/" href="/"
@@ -125,7 +128,7 @@ const isBranchNamed = branchName !== undefined;
) )
} }
</Flex> </Flex>
</Link> </LinkI18n>
<Box flexGrow="1" /> <Box flexGrow="1" />
@@ -145,7 +148,8 @@ const isBranchNamed = branchName !== undefined;
return ( return (
<Fragment key={tool.title}> <Fragment key={tool.title}>
{index > 0 && <Separator orientation="vertical" size="1" />} {index > 0 && <Separator orientation="vertical" size="1" />}
<Link <LinkI18n
{locale}
color="gray" color="gray"
highContrast={selected} highContrast={selected}
size="2" size="2"
@@ -153,7 +157,7 @@ const isBranchNamed = branchName !== undefined;
underline={selected ? 'always' : 'hover'} underline={selected ? 'always' : 'hover'}
> >
{tool.title} {tool.title}
</Link> </LinkI18n>
</Fragment> </Fragment>
); );
}) })
@@ -173,14 +177,15 @@ const isBranchNamed = branchName !== undefined;
<DiscordLogoIcon /> <DiscordLogoIcon />
</Link> </Link>
<Link <LinkI18n
{locale}
style={{ display: 'flex', alignContent: 'center' }} style={{ display: 'flex', alignContent: 'center' }}
color="gray" color="gray"
href="/settings" href="/settings"
underline="none" underline="none"
> >
<GearIcon /> <GearIcon />
</Link> </LinkI18n>
<NavbarAccount client:idle /> <NavbarAccount client:idle />
@@ -226,7 +231,8 @@ const isBranchNamed = branchName !== undefined;
aspectRatio: '2 / 1', aspectRatio: '2 / 1',
}} }}
> >
<Link <LinkI18n
{locale}
href={tool.id.length === 0 ? '/' : `/tools/${tool.id}`} href={tool.id.length === 0 ? '/' : `/tools/${tool.id}`}
style={{ style={{
display: 'flex', display: 'flex',
@@ -261,7 +267,7 @@ const isBranchNamed = branchName !== undefined;
> >
<Text>{tool.title}</Text> <Text>{tool.title}</Text>
</Flex> </Flex>
</Link> </LinkI18n>
</Flex> </Flex>
); );
}) })
@@ -1,9 +1,11 @@
import { asset, TankType, type TankDefinition } from '@blitzkit/core'; import { asset, TankType, type TankDefinition } from '@blitzkit/core';
import { Flex, Link, Text, type TextProps } from '@radix-ui/themes'; import { Flex, Text, type TextProps } from '@radix-ui/themes';
import { uniq } from 'lodash-es'; import { uniq } from 'lodash-es';
import { forwardRef, type ReactNode } from 'react'; import { forwardRef, type ReactNode } from 'react';
import { useLocale } from '../../hooks/useLocale';
import { TankopediaPersistent } from '../../stores/tankopediaPersistent'; import { TankopediaPersistent } from '../../stores/tankopediaPersistent';
import { classIcons } from '../ClassIcon'; import { classIcons } from '../ClassIcon';
import { LinkI18n } from '../LinkI18n';
import { MAX_RECENTLY_VIEWED } from '../TankSearch/constants'; import { MAX_RECENTLY_VIEWED } from '../TankSearch/constants';
import './index.css'; import './index.css';
@@ -26,6 +28,7 @@ export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>(
}: TankCardProps, }: TankCardProps,
ref, ref,
) => { ) => {
const { locale } = useLocale();
const provideLink = !noLink && onSelect === undefined; const provideLink = !noLink && onSelect === undefined;
const mutateTankopediaPersistent = TankopediaPersistent.useMutation(); const mutateTankopediaPersistent = TankopediaPersistent.useMutation();
const Icon = classIcons[tank.class]; const Icon = classIcons[tank.class];
@@ -60,7 +63,8 @@ export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>(
}} }}
{...props} {...props}
> >
<Link <LinkI18n
locale={locale}
className="link" className="link"
underline="hover" underline="hover"
href={provideLink ? `/tools/tankopedia/${tank.id}` : '#'} href={provideLink ? `/tools/tankopedia/${tank.id}` : '#'}
@@ -102,7 +106,7 @@ export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>(
{discriminator} {discriminator}
</Text> </Text>
)} )}
</Link> </LinkI18n>
</Text> </Text>
); );
}, },
@@ -1,7 +1,8 @@
import { type TankDefinition, tankIcon, TankType } from '@blitzkit/core'; import { type TankDefinition, tankIcon, TankType } from '@blitzkit/core';
import { Link } from '@radix-ui/themes'; import { useLocale } from '../hooks/useLocale';
import { classIcons } from './ClassIcon'; import { classIcons } from './ClassIcon';
import { ExperimentIcon } from './ExperimentIcon'; import { ExperimentIcon } from './ExperimentIcon';
import { LinkI18n } from './LinkI18n';
import { StickyRowHeaderCell } from './StickyRowHeaderCell'; import { StickyRowHeaderCell } from './StickyRowHeaderCell';
interface TankRowHeaderCellProps { interface TankRowHeaderCellProps {
@@ -9,6 +10,7 @@ interface TankRowHeaderCellProps {
} }
export function TankRowHeaderCell({ tank }: TankRowHeaderCellProps) { export function TankRowHeaderCell({ tank }: TankRowHeaderCellProps) {
const { locale } = useLocale();
const Icon = classIcons[tank.class]; const Icon = classIcons[tank.class];
return ( return (
@@ -16,7 +18,11 @@ export function TankRowHeaderCell({ tank }: TankRowHeaderCellProps) {
width={{ initial: '144px', sm: '240px' }} width={{ initial: '144px', sm: '240px' }}
style={{ overflow: 'hidden' }} style={{ overflow: 'hidden' }}
> >
<Link href={`/tools/tankopedia/${tank.id}`} tabIndex={-1}> <LinkI18n
locale={locale}
href={`/tools/tankopedia/${tank.id}`}
tabIndex={-1}
>
<img <img
alt={tank.name} alt={tank.name}
draggable={false} draggable={false}
@@ -28,9 +34,10 @@ export function TankRowHeaderCell({ tank }: TankRowHeaderCellProps) {
objectFit: 'cover', objectFit: 'cover',
}} }}
/> />
</Link> </LinkI18n>
<Link <LinkI18n
locale={locale}
color={ color={
tank.type === TankType.COLLECTOR tank.type === TankType.COLLECTOR
? 'blue' ? 'blue'
@@ -64,7 +71,7 @@ export function TankRowHeaderCell({ tank }: TankRowHeaderCellProps) {
)} )}
{tank.name} {tank.name}
</Link> </LinkI18n>
</StickyRowHeaderCell> </StickyRowHeaderCell>
); );
} }
@@ -1,8 +1,10 @@
import { type TankDefinition } from '@blitzkit/core'; import { type TankDefinition } from '@blitzkit/core';
import { useStore } from '@nanostores/react'; import { useStore } from '@nanostores/react';
import { CaretRightIcon } from '@radix-ui/react-icons'; import { CaretRightIcon } from '@radix-ui/react-icons';
import { Button, Link, TextField } from '@radix-ui/themes'; import { Button, TextField } from '@radix-ui/themes';
import { useLocale } from '../../../hooks/useLocale';
import { $tankFilters } from '../../../stores/tankFilters'; import { $tankFilters } from '../../../stores/tankFilters';
import { LinkI18n } from '../../LinkI18n';
interface QuickLinkProps { interface QuickLinkProps {
topResult?: TankDefinition; topResult?: TankDefinition;
@@ -10,16 +12,17 @@ interface QuickLinkProps {
export function QuickLink({ topResult }: QuickLinkProps) { export function QuickLink({ topResult }: QuickLinkProps) {
const tankFilters = useStore($tankFilters); const tankFilters = useStore($tankFilters);
const { locale } = useLocale();
if (!tankFilters.search || !topResult || tankFilters.searching) return null; if (!tankFilters.search || !topResult || tankFilters.searching) return null;
return ( return (
<TextField.Slot> <TextField.Slot>
<Link href={`/tools/tankopedia/${topResult.id}`}> <LinkI18n locale={locale} href={`/tools/tankopedia/${topResult.id}`}>
<Button variant="ghost"> <Button variant="ghost">
{topResult.name} <CaretRightIcon /> {topResult.name} <CaretRightIcon />
</Button> </Button>
</Link> </LinkI18n>
</TextField.Slot> </TextField.Slot>
); );
} }
@@ -17,11 +17,12 @@ import {
Flex, Flex,
Heading, Heading,
IconButton, IconButton,
Link,
Text, Text,
} from '@radix-ui/themes'; } from '@radix-ui/themes';
import { awaitableTankDefinitions } from '../../../../core/awaitables/tankDefinitions'; import { awaitableTankDefinitions } from '../../../../core/awaitables/tankDefinitions';
import { useLocale } from '../../../../hooks/useLocale';
import { Duel } from '../../../../stores/duel'; import { Duel } from '../../../../stores/duel';
import { LinkI18n } from '../../../LinkI18n';
import { ConfigurationChildWrapper } from './ConfigurationChildWrapper'; import { ConfigurationChildWrapper } from './ConfigurationChildWrapper';
type ModuleDefinition = type ModuleDefinition =
@@ -63,6 +64,8 @@ function ModuleButton({
onClick: () => void; onClick: () => void;
}) { }) {
const isTank = unlock.type === ModuleType.VEHICLE; const isTank = unlock.type === ModuleType.VEHICLE;
const { locale } = useLocale();
const button = ( const button = (
<IconButton <IconButton
size="4" size="4"
@@ -132,7 +135,9 @@ function ModuleButton({
); );
return isTank ? ( return isTank ? (
<Link href={`/tools/tankopedia/${unlock.id}`}>{button}</Link> <LinkI18n locale={locale} href={`/tools/tankopedia/${unlock.id}`}>
{button}
</LinkI18n>
) : ( ) : (
button button
); );
@@ -12,10 +12,12 @@ import { useState } from 'react';
import { awaitableModelDefinitions } from '../../../core/awaitables/modelDefinitions'; import { awaitableModelDefinitions } from '../../../core/awaitables/modelDefinitions';
import { awaitableProvisionDefinitions } from '../../../core/awaitables/provisionDefinitions'; import { awaitableProvisionDefinitions } from '../../../core/awaitables/provisionDefinitions';
import { tankToDuelMember } from '../../../core/blitzkit/tankToDuelMember'; import { tankToDuelMember } from '../../../core/blitzkit/tankToDuelMember';
import { useLocale } from '../../../hooks/useLocale';
import { App } from '../../../stores/app'; import { App } from '../../../stores/app';
import { Duel } from '../../../stores/duel'; import { Duel } from '../../../stores/duel';
import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral'; import { TankopediaEphemeral } from '../../../stores/tankopediaEphemeral';
import { classIcons } from '../../ClassIcon'; import { classIcons } from '../../ClassIcon';
import { LinkI18n } from '../../LinkI18n';
import { ScienceIcon } from '../../ScienceIcon'; import { ScienceIcon } from '../../ScienceIcon';
import { TankSearch } from '../../TankSearch'; import { TankSearch } from '../../TankSearch';
import { Listing } from './components/Listing'; import { Listing } from './components/Listing';
@@ -37,24 +39,28 @@ export function MetaSection() {
const mutateDuel = Duel.useMutation(); const mutateDuel = Duel.useMutation();
const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation(); const mutateTankopediaEphemeral = TankopediaEphemeral.useMutation();
const [showSwapDialog, setShowSwapDialog] = useState(false); const [showSwapDialog, setShowSwapDialog] = useState(false);
const { locale } = useLocale();
return ( return (
<Flex justify="center" align="center"> <Flex justify="center" align="center">
<Flex direction="column" align="center" gap="6"> <Flex direction="column" align="center" gap="6">
<Flex gap="2" wrap="wrap" justify="center" align="center"> <Flex gap="2" wrap="wrap" justify="center" align="center">
<Link href="/tools/tankopedia"> <LinkI18n locale={locale} href="/tools/tankopedia">
<Button variant="outline"> <Button variant="outline">
<ChevronLeftIcon /> <ChevronLeftIcon />
Back Back
</Button> </Button>
</Link> </LinkI18n>
<Link href={`/tools/compare?tanks=${compareTanks.join('%2C')}`}> <LinkI18n
locale={locale}
href={`/tools/compare?tanks=${compareTanks.join('%2C')}`}
>
<Button variant="outline"> <Button variant="outline">
<MixIcon /> <MixIcon />
Compare Compare
</Button> </Button>
</Link> </LinkI18n>
{assertSecret(import.meta.env.PUBLIC_PROMOTE_OPENTEST) === 'true' && ( {assertSecret(import.meta.env.PUBLIC_PROMOTE_OPENTEST) === 'true' && (
<Link <Link
@@ -1,9 +1,11 @@
import { asset, formatCompact, TIER_ROMAN_NUMERALS } from '@blitzkit/core'; import { asset, formatCompact, TIER_ROMAN_NUMERALS } from '@blitzkit/core';
import { Box, Flex, Link, 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 { 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';
import { LinkI18n } from '../../../LinkI18n';
type NodeProps = MaybeSkeletonComponentProps & { type NodeProps = MaybeSkeletonComponentProps & {
id: number; id: number;
@@ -17,6 +19,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 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]);
@@ -40,7 +43,8 @@ export function Node({ id, highlight, nextIds, skeleton }: NodeProps) {
averages && nextTanks ? Math.round(nextTanksXp! / averageXp!) : undefined; averages && nextTanks ? Math.round(nextTanksXp! / averageXp!) : undefined;
return ( return (
<Link <LinkI18n
locale={locale}
href={`/tools/tankopedia/${id}`} href={`/tools/tankopedia/${id}`}
key={id} key={id}
style={{ style={{
@@ -135,6 +139,6 @@ export function Node({ id, highlight, nextIds, skeleton }: NodeProps) {
</Flex> </Flex>
</Flex> </Flex>
</Box> </Box>
</Link> </LinkI18n>
); );
} }
@@ -1,8 +1,9 @@
--- ---
import { assertSecret, imgur, ImgurSize } from '@blitzkit/core'; import { assertSecret, imgur, ImgurSize } from '@blitzkit/core';
import { CaretRightIcon } from '@radix-ui/react-icons'; import { CaretRightIcon } from '@radix-ui/react-icons';
import { Box, Button, Code, Flex, Heading, Link, Text } from '@radix-ui/themes'; import { Box, Button, Code, Flex, Heading, Text } from '@radix-ui/themes';
import type { Tool } from '../constants/tools'; import type { Tool } from '../constants/tools';
import { LinkI18n } from './LinkI18n';
interface Props { interface Props {
tool: Tool; tool: Tool;
@@ -12,6 +13,7 @@ const { tool } = Astro.props;
const disabled = tool.branches?.every( const disabled = tool.branches?.every(
(branch) => branch !== assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH), (branch) => branch !== assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH),
); );
const { locale } = Astro.params;
--- ---
<style> <style>
@@ -54,7 +56,8 @@ const disabled = tool.branches?.every(
flexGrow={tool.significant ? undefined : '1'} flexGrow={tool.significant ? undefined : '1'}
flexBasis={tool.significant ? undefined : { initial: undefined, sm: '0' }} flexBasis={tool.significant ? undefined : { initial: undefined, sm: '0' }}
> >
<Link <LinkI18n
{locale}
className="link" className="link"
underline="none" underline="none"
href={disabled ? '#' : (tool.href ?? `/tools/${tool.id}`)} href={disabled ? '#' : (tool.href ?? `/tools/${tool.id}`)}
@@ -135,5 +138,5 @@ const disabled = tool.branches?.every(
) )
} }
</Flex> </Flex>
</Link> </LinkI18n>
</Flex> </Flex>
+28
View File
@@ -0,0 +1,28 @@
import { createContext, useContext, type ReactNode } from 'react';
const LocaleContext = createContext<{ locale: string | undefined } | null>(
null,
);
interface LocaleProviderProps {
locale: string | undefined;
children: ReactNode;
}
export function LocaleProvider({ locale, children }: LocaleProviderProps) {
return (
<LocaleContext.Provider value={{ locale }}>
{children}
</LocaleContext.Provider>
);
}
export function useLocale() {
const context = useContext(LocaleContext);
if (!context) {
throw new Error('useLocale must be used within a LocaleProvider');
}
return { locale: context.locale };
}
+5 -2
View File
@@ -1,8 +1,11 @@
--- ---
import { DiscordLogoIcon, HomeIcon } from '@radix-ui/react-icons'; import { DiscordLogoIcon, HomeIcon } from '@radix-ui/react-icons';
import { Button, Flex, Heading, Link, Text } from '@radix-ui/themes'; import { Button, Flex, Heading, Link, Text } from '@radix-ui/themes';
import { LinkI18n } from '../components/LinkI18n';
import { PageWrapper } from '../components/PageWrapper'; import { PageWrapper } from '../components/PageWrapper';
import BaseLayout from '../layouts/BaseLayout.astro'; import BaseLayout from '../layouts/BaseLayout.astro';
const { locale } = Astro.params;
--- ---
<BaseLayout> <BaseLayout>
@@ -12,11 +15,11 @@ import BaseLayout from '../layouts/BaseLayout.astro';
<Text color="gray">Where would you like to go?</Text> <Text color="gray">Where would you like to go?</Text>
<Flex mt="4" gap="2"> <Flex mt="4" gap="2">
<Link href="/"> <LinkI18n {locale} href="/">
<Button> <Button>
<HomeIcon /> Home <HomeIcon /> Home
</Button> </Button>
</Link> </LinkI18n>
<Link href="https://discord.gg/nDt7AjGJQH"> <Link href="https://discord.gg/nDt7AjGJQH">
<Button variant="outline"> <Button variant="outline">
<DiscordLogoIcon /> Discord <DiscordLogoIcon /> Discord
@@ -1,7 +1,8 @@
--- ---
import { MagicWandIcon, StarFilledIcon } from '@radix-ui/react-icons'; import { MagicWandIcon, StarFilledIcon } from '@radix-ui/react-icons';
import { Flex, Heading, Link } from '@radix-ui/themes'; import { Flex, Heading } from '@radix-ui/themes';
import { compareVersions } from 'compare-versions'; import { compareVersions } from 'compare-versions';
import { LinkI18n } from '../../../../components/LinkI18n';
import { PageWrapper } from '../../../../components/PageWrapper'; import { PageWrapper } from '../../../../components/PageWrapper';
import BaseLayout from '../../../../layouts/BaseLayout.astro'; import BaseLayout from '../../../../layouts/BaseLayout.astro';
@@ -16,6 +17,7 @@ const versions = Object.keys(
.map((file) => file.replace(ROOT, '').replace('.md', '')) .map((file) => file.replace(ROOT, '').replace('.md', ''))
.sort(compareVersions) .sort(compareVersions)
.reverse(); .reverse();
const { locale } = Astro.params;
--- ---
<title>BlitzKit Patches</title> <title>BlitzKit Patches</title>
@@ -31,7 +33,8 @@ const versions = Object.keys(
const isMajor = split[2] === 0; const isMajor = split[2] === 0;
return ( return (
<Link <LinkI18n
{locale}
size="5" size="5"
href={`/docs/changelogs/${version}`} href={`/docs/changelogs/${version}`}
mb={isMajor ? '6' : '0'} mb={isMajor ? '6' : '0'}
@@ -41,7 +44,7 @@ const versions = Object.keys(
{isMajor && <StarFilledIcon />} {isMajor && <StarFilledIcon />}
{version} {version}
</Flex> </Flex>
</Link> </LinkI18n>
); );
}) })
} }
@@ -21,6 +21,7 @@ import {
import BaseLayout from '../../layouts/BaseLayout.astro'; import BaseLayout from '../../layouts/BaseLayout.astro';
const branch = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH); const branch = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH);
const { locale } = Astro.params;
export const getStaticPaths = (() => { export const getStaticPaths = (() => {
return [ return [
@@ -47,7 +48,7 @@ export const getStaticPaths = (() => {
<Flex maxWidth="64rem" flexGrow="1" gap="4" direction="column"> <Flex maxWidth="64rem" flexGrow="1" gap="4" direction="column">
<ToolCard tool={tankopediaTool} /> <ToolCard tool={tankopediaTool} />
<HomePageHotTanks /> <HomePageHotTanks {locale} />
<Flex gap="4" direction={{ initial: 'column', sm: 'row' }}> <Flex gap="4" direction={{ initial: 'column', sm: 'row' }}>
{/* <ToolCard tool={playerStatsTool} /> */} {/* <ToolCard tool={playerStatsTool} /> */}
@@ -2,12 +2,14 @@ import { imgur, ImgurSize } from '@blitzkit/core';
import { Box, Flex, Link, Text } from '@radix-ui/themes'; import { Box, Flex, Link, Text } from '@radix-ui/themes';
import { capitalize } from 'lodash-es'; import { capitalize } from 'lodash-es';
import { PreviewWrapper } from '../../../../components/Embeds/PreviewWrapper'; import { PreviewWrapper } from '../../../../components/Embeds/PreviewWrapper';
import { LinkI18n } from '../../../../components/LinkI18n';
import { PageWrapper } from '../../../../components/PageWrapper'; import { PageWrapper } from '../../../../components/PageWrapper';
import { import {
embedConfigurations, embedConfigurations,
extractEmbedConfigDefaults, extractEmbedConfigDefaults,
} from '../../../../constants/embeds'; } from '../../../../constants/embeds';
import { Var } from '../../../../core/radix/var'; import { Var } from '../../../../core/radix/var';
import { useLocale } from '../../../../hooks/useLocale';
import { App } from '../../../../stores/app'; import { App } from '../../../../stores/app';
import { EmbedState } from '../../../../stores/embedState'; import { EmbedState } from '../../../../stores/embedState';
@@ -26,6 +28,8 @@ function Content() {
// expires: 0, // expires: 0,
// }); // });
const { locale } = useLocale();
return ( return (
<PageWrapper color="red"> <PageWrapper color="red">
{/* {!wargaming && ( {/* {!wargaming && (
@@ -61,7 +65,8 @@ function Content() {
key={embed} key={embed}
data={extractEmbedConfigDefaults(config)} data={extractEmbedConfigDefaults(config)}
> >
<Link <LinkI18n
locale={locale}
href={`/tools/embed/${embed}`} href={`/tools/embed/${embed}`}
color="gray" color="gray"
highContrast highContrast
@@ -101,7 +106,7 @@ function Content() {
/> />
</Box> </Box>
</Flex> </Flex>
</Link> </LinkI18n>
</EmbedState.Provider> </EmbedState.Provider>
))} ))}
</Flex> </Flex>
@@ -12,6 +12,7 @@ import { VideoSection } from '../../../../../components/Tankopedia/VideoSection'
import { awaitableModelDefinitions } from '../../../../../core/awaitables/modelDefinitions'; import { awaitableModelDefinitions } from '../../../../../core/awaitables/modelDefinitions';
import { awaitableProvisionDefinitions } from '../../../../../core/awaitables/provisionDefinitions'; import { awaitableProvisionDefinitions } from '../../../../../core/awaitables/provisionDefinitions';
import { awaitableTankDefinitions } from '../../../../../core/awaitables/tankDefinitions'; import { awaitableTankDefinitions } from '../../../../../core/awaitables/tankDefinitions';
import { LocaleProvider } from '../../../../../hooks/useLocale';
import { App } from '../../../../../stores/app'; import { App } from '../../../../../stores/app';
import { Duel } from '../../../../../stores/duel'; import { Duel } from '../../../../../stores/duel';
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral'; import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral';
@@ -20,6 +21,7 @@ import type { MaybeSkeletonComponentProps } from '../../../../../types/maybeSkel
type PageProps = MaybeSkeletonComponentProps & { type PageProps = MaybeSkeletonComponentProps & {
id: number; id: number;
locale: string | undefined;
}; };
const [tankDefinitions, provisionDefinitions, modelDefinitions] = const [tankDefinitions, provisionDefinitions, modelDefinitions] =
@@ -29,33 +31,35 @@ const [tankDefinitions, provisionDefinitions, modelDefinitions] =
awaitableModelDefinitions, awaitableModelDefinitions,
]); ]);
export function Page({ id, skeleton }: PageProps) { export function Page({ id, skeleton, locale }: PageProps) {
const tank = tankDefinitions.tanks[id]; const tank = tankDefinitions.tanks[id];
const model = modelDefinitions.models[id]; const model = modelDefinitions.models[id];
return ( return (
<TankopediaEphemeral.Provider data={model}> <LocaleProvider locale={locale}>
<App.Provider> <TankopediaEphemeral.Provider data={model}>
<TankopediaPersistent.Provider> <App.Provider>
<Duel.Provider <TankopediaPersistent.Provider>
data={{ tank, provisionDefinitions: provisionDefinitions }} <Duel.Provider
> data={{ tank, provisionDefinitions: provisionDefinitions }}
<PageWrapper p="0" maxWidth="unset" color="purple" gap="9" pb="9"> >
<HeroSection skeleton={skeleton} /> <PageWrapper p="0" maxWidth="unset" color="purple" gap="9" pb="9">
<CalloutsSection /> <HeroSection skeleton={skeleton} />
<MetaSection /> <CalloutsSection />
{tank.type === TankType.RESEARCHABLE && !tank.deprecated && ( <MetaSection />
<TechTreeSection skeleton={skeleton} /> {tank.type === TankType.RESEARCHABLE && !tank.deprecated && (
)} <TechTreeSection skeleton={skeleton} />
<CharacteristicsSection /> )}
<GameModeSection /> <CharacteristicsSection />
<TankopediaCharts /> <GameModeSection />
<VideoSection skeleton={skeleton} /> <TankopediaCharts />
<HistorySection /> <VideoSection skeleton={skeleton} />
</PageWrapper> <HistorySection />
</Duel.Provider> </PageWrapper>
</TankopediaPersistent.Provider> </Duel.Provider>
</App.Provider> </TankopediaPersistent.Provider>
</TankopediaEphemeral.Provider> </App.Provider>
</TankopediaEphemeral.Provider>
</LocaleProvider>
); );
} }
@@ -31,7 +31,7 @@ export const getStaticPaths = (async () => {
.flat(); .flat();
}) satisfies GetStaticPaths; }) satisfies GetStaticPaths;
const { id } = Astro.params; const { id, locale } = Astro.params;
const tankDefinitions = await fetchTankDefinitions(); const tankDefinitions = await fetchTankDefinitions();
const skillDefinitions = await fetchSkillDefinitions(); const skillDefinitions = await fetchSkillDefinitions();
@@ -96,7 +96,7 @@ const description = `${
<meta name="twitter:image:src" content={icon} /> <meta name="twitter:image:src" content={icon} />
<BaseLayout> <BaseLayout>
<Page id={id} client:only="react"> <Page {locale} id={id} client:only="react">
<Page id={id} skeleton slot="fallback" /> <Page {locale} id={id} skeleton slot="fallback" />
</Page> </Page>
</BaseLayout> </BaseLayout>