Compare commits

...
22 Commits
Author SHA1 Message Date
tresabhi cf04fe21b3 fix: logs 2025-01-18 13:59:14 -06:00
tresabhi 84eb3c2da3 fix: version 2025-01-18 13:49:37 -06:00
tresabhi 22bf2dc1d8 feat: logs 2025-01-18 13:49:18 -06:00
tresabhi b9c339daa7 fix: search keys 2025-01-18 13:47:31 -06:00
tresabhi ef3006cac1 fix: double full stops 2025-01-18 13:42:52 -06:00
TrèsAbhi e482fd40c1 Update applyPatches.ts 2025-01-18 11:41:45 -06:00
TrèsAbhi cc4569966e Update applyPatches.ts 2025-01-18 09:19:38 -06:00
tresabhi 3708a3ced7 fix: handle deleted tanks 2025-01-17 20:29:33 -06:00
tresabhi 0ae59c2fd7 fix: check dir exists 2025-01-17 20:15:09 -06:00
tresabhi 7027f63236 feat: prune 2025-01-17 19:56:46 -06:00
TrèsAbhi 6725e79021 New Crowdin updates (#140) 2025-01-17 19:36:39 -06:00
tresabhi 5ca3cee9da feat: verbose 2025-01-17 19:22:02 -06:00
tresabhi 602a5a1e99 fix: move env 2025-01-17 19:19:45 -06:00
tresabhi bfbf3bdc39 fix: no double dvpl 2025-01-17 19:17:39 -06:00
tresabhi 644686582e fix: icon api 2025-01-17 19:06:07 -06:00
TrèsAbhi 1c00bc81f8 New Crowdin updates (#139)
* New translations en.json (French)

* New translations en.json (Spanish)

* New translations en.json (Japanese)

* New translations en.json (Polish)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Ukrainian)

* New translations en.json (Chinese Simplified)

* New translations en.json (Portuguese)

* New translations en.json (Portuguese)

* New translations en.json (Russian)

* New translations en.json (Russian)

* New translations en.json (Russian)

* New translations en.json (Chinese Simplified)
2025-01-17 12:46:05 -06:00
TrèsAbhi ac3b69bec5 Update assets.yml 2025-01-17 12:45:12 -06:00
TrèsAbhi 3e14c943b6 Update assets.yml 2025-01-16 23:05:13 -06:00
TrèsAbhi d33633be2c Update assets.yml 2025-01-16 22:15:24 -06:00
TrèsAbhi 4bf70d02d0 Update Crowdin configuration file 2025-01-16 20:48:29 -06:00
tresabhi 377bcf0e38 fix: env 2025-01-16 20:44:55 -06:00
tresabhi 884b6d4318 fix: run tests even on dev 2025-01-16 20:36:49 -06:00
27 changed files with 7529 additions and 3685 deletions

No files matched your search

+15 -1
View File
@@ -39,6 +39,17 @@ env:
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }} PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }} PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
PUBLIC_ASSET_BRANCH: ${{ github.event.inputs.cdn_branch || secrets.PUBLIC_ASSET_BRANCH }} PUBLIC_ASSET_BRANCH: ${{ github.event.inputs.cdn_branch || secrets.PUBLIC_ASSET_BRANCH }}
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
ALLOW_ROBOTS: true
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
PUBLIC_PATREON_CLIENT_ID: ${{ secrets.PUBLIC_PATREON_CLIENT_ID }}
PUBLIC_PATREON_REDIRECT_URI: ${{ secrets.PUBLIC_PATREON_REDIRECT_URI }}
PATREON_CLIENT_SECRET: ${{ secrets.PATREON_CLIENT_SECRET }}
PUBLIC_NITROPAY_ID: ${{ secrets.PUBLIC_NITROPAY_ID }}
PUBLIC_DEBUG_MISSING_I18N: false
jobs: jobs:
download_client: download_client:
@@ -106,6 +117,9 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with:
submodules: recursive
token: ${{ secrets.GH_TOKEN }}
- name: Setup bun - name: Setup bun
uses: oven-sh/setup-bun@v1 uses: oven-sh/setup-bun@v1
@@ -127,7 +141,7 @@ jobs:
- name: Start server and build assets - name: Start server and build assets
run: | run: |
bun dev:website & bun dev:website --verbosepa &
SERVER_PID=$! SERVER_PID=$!
bun run build:assets --all-targets --depot --production bun run build:assets --all-targets --depot --production
+3 -1
View File
@@ -2,7 +2,6 @@ name: Website
on: on:
push: push:
branches: main
workflow_dispatch: workflow_dispatch:
schedule: schedule:
@@ -27,6 +26,8 @@ env:
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }} PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }} PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }} GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
jobs: jobs:
build: build:
@@ -53,6 +54,7 @@ jobs:
path: dist/website path: dist/website
deploy-github-pages: deploy-github-pages:
if: ${{ github.ref == 'refs/heads/main' }}
name: Deploy to GitHub Pages name: Deploy to GitHub Pages
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build needs: build
+1 -1
View File
@@ -1,3 +1,3 @@
files: files:
- source: /packages/core/lang/en.json - source: /packages/i18n/strings/en.json
translation: /%original_path%/%locale%.json translation: /%original_path%/%locale%.json
+7
View File
@@ -0,0 +1,7 @@
# BlitzKit 1.27.1
## Fixes
- Fixed a crash that occurs if tanks are deleted in Blitz and were once available in BlitzKit
- All tank icons are now back
- The tank search once again returns results
+3 -2
View File
@@ -1,7 +1,7 @@
{ {
"name": "blitzkit", "name": "blitzkit",
"private": true, "private": true,
"version": "1.27.0", "version": "1.27.1",
"description": "🎉 Tools for everything World of Tanks Blitz", "description": "🎉 Tools for everything World of Tanks Blitz",
"type": "module", "type": "module",
"types": "./types.d.ts", "types": "./types.d.ts",
@@ -35,7 +35,8 @@
"build:protos": "bun packages/scripts/src/protos.ts", "build:protos": "bun packages/scripts/src/protos.ts",
"preview:website": "cd packages/website && bun run preview", "preview:website": "cd packages/website && bun run preview",
"build:reviews": "cd packages/scripts && bun build:reviews", "build:reviews": "cd packages/scripts && bun build:reviews",
"build:ids": "cd packages/scripts && bun build:ids" "build:ids": "cd packages/scripts && bun build:ids",
"prunestrings": "cd packages/scripts && bun prunestrings"
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
+2 -4
View File
@@ -1,3 +1,4 @@
import { SEARCH_KEYS } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n'; import { literals } from '@blitzkit/i18n';
import { Locale } from 'discord.js'; import { Locale } from 'discord.js';
import { go } from 'fuzzysort'; import { go } from 'fuzzysort';
@@ -19,10 +20,7 @@ export async function resolveTankId(
const searchResult = go( const searchResult = go(
`${tank}`, `${tank}`,
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames), await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
{ { keys: SEARCH_KEYS, limit: 1 },
keys: ['searchableName', 'searchableNameDeburr', 'camouflages'],
limit: 1,
},
); );
if (searchResult.length === 0) { if (searchResult.length === 0) {
@@ -1,5 +1,4 @@
import { fetchTankNames, TankType } from '@blitzkit/core'; import { fetchTankNames, SEARCH_KEYS, TankType } from '@blitzkit/core';
import { SUPPORTED_LOCALES } from '@blitzkit/i18n';
import { import {
ApplicationCommandOptionChoiceData, ApplicationCommandOptionChoiceData,
AutocompleteInteraction, AutocompleteInteraction,
@@ -32,16 +31,7 @@ export async function autocompleteTanks(
go( go(
focusedOption.value, focusedOption.value,
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames), await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
{ { keys: SEARCH_KEYS, limit: 10 },
keys: [
...SUPPORTED_LOCALES.map((locale) => [
`searchableName.{locale}`,
`searchableNameDeburr.{locale}`,
]).flat(),
'camouflages',
],
limit: 10,
},
).map(async (item) => { ).map(async (item) => {
let name = unwrap(item.obj.searchableName); let name = unwrap(item.obj.searchableName);
+9
View File
@@ -1,4 +1,5 @@
import { deburr } from 'lodash-es'; import { deburr } from 'lodash-es';
import { SUPPORTED_LOCALES } from '../../../i18n/src/strings';
import { I18nString } from '../protos'; import { I18nString } from '../protos';
import { fetchCamouflageDefinitions } from './camouflageDefinitions'; import { fetchCamouflageDefinitions } from './camouflageDefinitions';
import { fetchTankDefinitions } from './tankDefinitions'; import { fetchTankDefinitions } from './tankDefinitions';
@@ -33,3 +34,11 @@ export async function fetchTankNames() {
}), }),
); );
} }
export const SEARCH_KEYS = [
...SUPPORTED_LOCALES.map((locale) => [
`searchableName.locales.${locale}`,
`searchableNameDeburr.locales.${locale}`,
]).flat(),
'camouflages',
];
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+2 -1
View File
@@ -10,7 +10,8 @@
"build:reviews": "bun src/reviews.ts", "build:reviews": "bun src/reviews.ts",
"build:ids": "bun src/discoverIds.ts", "build:ids": "bun src/discoverIds.ts",
"build:bot": "bun src/buildBot.ts", "build:bot": "bun src/buildBot.ts",
"build:ratingleaderboard": "bun src/buildRatingLeaderboard.ts" "build:ratingleaderboard": "bun src/buildRatingLeaderboard.ts",
"prunestrings": "bun src/pruneStrings.ts"
}, },
"dependencies": { "dependencies": {
"@blitzkit/core": "workspace:*", "@blitzkit/core": "workspace:*",
+16 -10
View File
@@ -1,4 +1,5 @@
import { assertSecret } from '@blitzkit/core'; import { assertSecret } from '@blitzkit/core';
import { existsSync } from 'fs';
import { mkdir, writeFile } from 'fs/promises'; import { mkdir, writeFile } from 'fs/promises';
import { parse as parsePath } from 'path'; import { parse as parsePath } from 'path';
import ProgressBar from 'progress'; import ProgressBar from 'progress';
@@ -45,19 +46,24 @@ while (true) {
files.length, files.length,
); );
await Promise.all( for (const { path, data } of files) {
files.map(async ({ path, data }) => { console.log(`Patching "${path}"...`);
const { dir } = parsePath(path);
const { dir } = parsePath(path);
try {
await mkdir(`${DATA}/${dir}`, { recursive: true }); await mkdir(`${DATA}/${dir}`, { recursive: true });
await writeFile( } catch (error) {
`${DATA}/${path}`, console.warn(`Failed to make directory "${dir}"`);
new Uint8Array(writeDVPL(Buffer.from(data))), }
);
bar.tick(); await writeFile(
}), `${DATA}/${path}`,
); new Uint8Array(writeDVPL(Buffer.from(data))),
);
bar.tick();
}
if ('dynamicContentLocalizationsDir' in data) { if ('dynamicContentLocalizationsDir' in data) {
console.log('Found dynamic content localizations; patching...'); console.log('Found dynamic content localizations; patching...');
@@ -3,7 +3,7 @@ import { DATA_COMPRESSED } from '../../buildAssets/constants';
import { readDVPL } from './readDVPL'; import { readDVPL } from './readDVPL';
export async function readDVPLFile(file: string) { export async function readDVPLFile(file: string) {
if (DATA_COMPRESSED) { if (DATA_COMPRESSED && !file.endsWith('.dvpl')) {
return readDVPL(await readFile(`${file}.dvpl`)); return readDVPL(await readFile(`${file}.dvpl`));
} }
+49
View File
@@ -0,0 +1,49 @@
import {
DEFAULT_LOCALE,
SUPPORTED_LOCALES,
TranslationTree,
} from '@blitzkit/i18n';
import { writeFile } from 'fs/promises';
const ROOT = '@blitzkit/i18n/strings';
const WORKING_ROOT = '../../packages/i18n/strings';
const defaultStrings = await import(`${ROOT}/${DEFAULT_LOCALE}.json`);
const nonDefaultLocales = SUPPORTED_LOCALES.filter(
(locale) => locale !== DEFAULT_LOCALE,
);
function prune(defaultStrings: TranslationTree, strings: TranslationTree) {
for (const key in strings) {
if (key in defaultStrings) {
if (typeof defaultStrings[key] === typeof strings[key]) {
if (typeof strings[key] === 'string') {
if (
(defaultStrings[key] as string).replaceAll(/%s\d/g, '%s') ===
(strings[key] as string).replaceAll(/%s\d/g, '%s') ||
strings[key] === ''
) {
delete strings[key];
}
} else {
prune(defaultStrings[key] as TranslationTree, strings[key]);
}
} else {
delete strings[key];
}
} else {
delete strings[key];
}
}
return strings;
}
for (const locale of nonDefaultLocales) {
console.log(`Pruning ${locale}...`);
const strings = await import(`${ROOT}/${locale}.json`);
const pruned = prune(defaultStrings, strings);
writeFile(`${WORKING_ROOT}/${locale}.json`, JSON.stringify(pruned, null, 2));
}
@@ -1,4 +1,9 @@
import { asset, TankType, type TankDefinition } from '@blitzkit/core'; import {
asset,
fetchTankDefinitions,
TankType,
type TankDefinition,
} from '@blitzkit/core';
import { Flex, 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';
@@ -16,6 +21,8 @@ type TankCardProps = TextProps & {
noLink?: boolean; noLink?: boolean;
}; };
const tankDefinitions = await fetchTankDefinitions();
export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>( export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>(
( (
{ {
@@ -49,10 +56,9 @@ export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>(
onClick={() => { onClick={() => {
onSelect?.(tank); onSelect?.(tank);
mutateTankopediaPersistent((draft) => { mutateTankopediaPersistent((draft) => {
draft.recentlyViewed = uniq([ draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed])
tank.id, .filter((id) => id in tankDefinitions.tanks)
...draft.recentlyViewed, .slice(0, MAX_RECENTLY_VIEWED);
]).slice(0, MAX_RECENTLY_VIEWED);
}); });
}} }}
className="tank-search-card" className="tank-search-card"
@@ -12,7 +12,7 @@ export function NoResults({ type = 'filters' }: NoResultsProps) {
return ( return (
<Flex flexGrow="1" align="center" justify="center"> <Flex flexGrow="1" align="center" justify="center">
<Text color="gray"> <Text color="gray">
{strings.website.common.tank_search.no_tanks_found.body}.{' '} {strings.website.common.tank_search.no_tanks_found.body}{' '}
<Link <Link
href="#" href="#"
underline="always" underline="always"
@@ -25,7 +25,6 @@ export function NoResults({ type = 'filters' }: NoResultsProps) {
? strings.website.common.tank_search.no_tanks_found.clear_filters ? strings.website.common.tank_search.no_tanks_found.clear_filters
: strings.website.common.tank_search.no_tanks_found.search_again} : strings.website.common.tank_search.no_tanks_found.search_again}
</Link> </Link>
.
</Text> </Text>
</Flex> </Flex>
); );
@@ -16,7 +16,9 @@ export function RecentlyViewed() {
const tankopediaPersistentStore = TankopediaPersistent.useStore(); const tankopediaPersistentStore = TankopediaPersistent.useStore();
const filters = useStore($tankFilters); const filters = useStore($tankFilters);
// non-reactive because it is a little weird that it updates instantly even before the page loads // non-reactive because it is a little weird that it updates instantly even before the page loads
const recentlyViewed = tankopediaPersistentStore.getState().recentlyViewed; const recentlyViewed = tankopediaPersistentStore
.getState()
.recentlyViewed.filter((id) => id in tankDefinitions.tanks);
const sort = useStore($tankopediaSort); const sort = useStore($tankopediaSort);
const hasFilters = useMemo( const hasFilters = useMemo(
() => () =>
@@ -2,6 +2,7 @@ import {
metaSortTank, metaSortTank,
normalizeBoundingBox, normalizeBoundingBox,
resolveDpm, resolveDpm,
SEARCH_KEYS,
unionBoundingBox, unionBoundingBox,
type TankDefinition, type TankDefinition,
} from '@blitzkit/core'; } from '@blitzkit/core';
@@ -410,7 +411,7 @@ export const TankSearch = memo<TankSearchProps>(
: sorted.reverse(); : sorted.reverse();
} else { } else {
const searchedRaw = fuzzysort.go(tankFilters.search, tankNames, { const searchedRaw = fuzzysort.go(tankFilters.search, tankNames, {
keys: ['searchableName', 'searchableNameDeburr', 'camouflages'], keys: SEARCH_KEYS,
}); });
const searchedTanks = searchedRaw.map( const searchedTanks = searchedRaw.map(
(result) => tankDefinitions.tanks[result.obj.id], (result) => tankDefinitions.tanks[result.obj.id],
@@ -456,7 +457,9 @@ export const TankSearch = memo<TankSearchProps>(
draft.recentlyViewed = uniq([ draft.recentlyViewed = uniq([
...tanksFiltered.map(({ id }) => id), ...tanksFiltered.map(({ id }) => id),
...draft.recentlyViewed, ...draft.recentlyViewed,
]).slice(0, MAX_RECENTLY_VIEWED); ])
.filter((id) => id in tankDefinitions.tanks)
.slice(0, MAX_RECENTLY_VIEWED);
}); });
}} }}
> >
@@ -1,4 +1,4 @@
import { assertSecret } from '@blitzkit/core'; import { assertSecret, fetchTankDefinitions } from '@blitzkit/core';
import { MinusCircledIcon } from '@radix-ui/react-icons'; import { MinusCircledIcon } from '@radix-ui/react-icons';
import { Callout, Flex } from '@radix-ui/themes'; import { Callout, Flex } from '@radix-ui/themes';
import { uniq } from 'lodash-es'; import { uniq } from 'lodash-es';
@@ -9,6 +9,8 @@ import { AesonPlug } from '../AesonPlug';
import { ExperimentIcon } from '../ExperimentIcon'; import { ExperimentIcon } from '../ExperimentIcon';
import { MAX_RECENTLY_VIEWED } from '../TankSearch/constants'; import { MAX_RECENTLY_VIEWED } from '../TankSearch/constants';
const tankDefinitions = await fetchTankDefinitions();
export function CalloutsSection() { export function CalloutsSection() {
const tank = Duel.use((state) => state.protagonist.tank); const tank = Duel.use((state) => state.protagonist.tank);
const mutateTankopediaPersistent = TankopediaPersistent.useMutation(); const mutateTankopediaPersistent = TankopediaPersistent.useMutation();
@@ -17,10 +19,9 @@ export function CalloutsSection() {
useEffect(() => { useEffect(() => {
mutateTankopediaPersistent((draft) => { mutateTankopediaPersistent((draft) => {
draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed]).slice( draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed])
0, .filter((id) => id in tankDefinitions.tanks)
MAX_RECENTLY_VIEWED, .slice(0, MAX_RECENTLY_VIEWED);
);
}); });
}, [tank]); }, [tank]);
@@ -30,6 +30,7 @@ const locale = Astro.params.locale ?? DEFAULT_LOCALE;
import { SUPPORTED_LOCALES } from '@blitzkit/i18n'; import { SUPPORTED_LOCALES } from '@blitzkit/i18n';
import { getBestLocale } from '../core/i18n/getBestLocale'; import { getBestLocale } from '../core/i18n/getBestLocale';
const isAPI = window.location.pathname.startsWith('/api');
const isI18nPath = SUPPORTED_LOCALES.some((locale) => const isI18nPath = SUPPORTED_LOCALES.some((locale) =>
window.location.pathname.startsWith(`/${locale}`), window.location.pathname.startsWith(`/${locale}`),
); );
@@ -38,7 +39,7 @@ const locale = Astro.params.locale ?? DEFAULT_LOCALE;
window.location.pathname.startsWith(`/${locale}`), window.location.pathname.startsWith(`/${locale}`),
); );
if (bestLocale !== currentPathLocale) { if (!isAPI && bestLocale !== currentPathLocale) {
window.location.pathname = isI18nPath window.location.pathname = isI18nPath
? window.location.pathname.replace( ? window.location.pathname.replace(
`/${currentPathLocale}`, `/${currentPathLocale}`,
@@ -2,6 +2,7 @@ import { TankSandbox } from '../../../../../components/Tankopedia/HeroSection/co
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';
@@ -23,15 +24,17 @@ export function Page({ id }: PageProps) {
const model = modelDefinitions.models[id]; const model = modelDefinitions.models[id];
return ( return (
<App.Provider> <LocaleProvider locale="en">
<TankopediaPersistent.Provider> <App.Provider>
<Duel.Provider data={{ provisionDefinitions, tank }}> <TankopediaPersistent.Provider>
<TankopediaEphemeral.Provider data={model}> <Duel.Provider data={{ provisionDefinitions, tank }}>
<Content /> <TankopediaEphemeral.Provider data={model}>
</TankopediaEphemeral.Provider> <Content />
</Duel.Provider> </TankopediaEphemeral.Provider>
</TankopediaPersistent.Provider> </Duel.Provider>
</App.Provider> </TankopediaPersistent.Provider>
</App.Provider>
</LocaleProvider>
); );
} }