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_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
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:
download_client:
@@ -106,6 +117,9 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
token: ${{ secrets.GH_TOKEN }}
- name: Setup bun
uses: oven-sh/setup-bun@v1
@@ -127,7 +141,7 @@ jobs:
- name: Start server and build assets
run: |
bun dev:website &
bun dev:website --verbosepa &
SERVER_PID=$!
bun run build:assets --all-targets --depot --production
+3 -1
View File
@@ -2,7 +2,6 @@ name: Website
on:
push:
branches: main
workflow_dispatch:
schedule:
@@ -27,6 +26,8 @@ env:
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
jobs:
build:
@@ -53,6 +54,7 @@ jobs:
path: dist/website
deploy-github-pages:
if: ${{ github.ref == 'refs/heads/main' }}
name: Deploy to GitHub Pages
runs-on: ubuntu-latest
needs: build
+1 -1
View File
@@ -1,3 +1,3 @@
files:
- source: /packages/core/lang/en.json
- source: /packages/i18n/strings/en.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",
"private": true,
"version": "1.27.0",
"version": "1.27.1",
"description": "🎉 Tools for everything World of Tanks Blitz",
"type": "module",
"types": "./types.d.ts",
@@ -35,7 +35,8 @@
"build:protos": "bun packages/scripts/src/protos.ts",
"preview:website": "cd packages/website && bun run preview",
"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",
"dependencies": {
+2 -4
View File
@@ -1,3 +1,4 @@
import { SEARCH_KEYS } from '@blitzkit/core';
import { literals } from '@blitzkit/i18n';
import { Locale } from 'discord.js';
import { go } from 'fuzzysort';
@@ -19,10 +20,7 @@ export async function resolveTankId(
const searchResult = go(
`${tank}`,
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
{
keys: ['searchableName', 'searchableNameDeburr', 'camouflages'],
limit: 1,
},
{ keys: SEARCH_KEYS, limit: 1 },
);
if (searchResult.length === 0) {
@@ -1,5 +1,4 @@
import { fetchTankNames, TankType } from '@blitzkit/core';
import { SUPPORTED_LOCALES } from '@blitzkit/i18n';
import { fetchTankNames, SEARCH_KEYS, TankType } from '@blitzkit/core';
import {
ApplicationCommandOptionChoiceData,
AutocompleteInteraction,
@@ -32,16 +31,7 @@ export async function autocompleteTanks(
go(
focusedOption.value,
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
{
keys: [
...SUPPORTED_LOCALES.map((locale) => [
`searchableName.{locale}`,
`searchableNameDeburr.{locale}`,
]).flat(),
'camouflages',
],
limit: 10,
},
{ keys: SEARCH_KEYS, limit: 10 },
).map(async (item) => {
let name = unwrap(item.obj.searchableName);
+9
View File
@@ -1,4 +1,5 @@
import { deburr } from 'lodash-es';
import { SUPPORTED_LOCALES } from '../../../i18n/src/strings';
import { I18nString } from '../protos';
import { fetchCamouflageDefinitions } from './camouflageDefinitions';
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:ids": "bun src/discoverIds.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": {
"@blitzkit/core": "workspace:*",
+16 -10
View File
@@ -1,4 +1,5 @@
import { assertSecret } from '@blitzkit/core';
import { existsSync } from 'fs';
import { mkdir, writeFile } from 'fs/promises';
import { parse as parsePath } from 'path';
import ProgressBar from 'progress';
@@ -45,19 +46,24 @@ while (true) {
files.length,
);
await Promise.all(
files.map(async ({ path, data }) => {
const { dir } = parsePath(path);
for (const { path, data } of files) {
console.log(`Patching "${path}"...`);
const { dir } = parsePath(path);
try {
await mkdir(`${DATA}/${dir}`, { recursive: true });
await writeFile(
`${DATA}/${path}`,
new Uint8Array(writeDVPL(Buffer.from(data))),
);
} catch (error) {
console.warn(`Failed to make directory "${dir}"`);
}
bar.tick();
}),
);
await writeFile(
`${DATA}/${path}`,
new Uint8Array(writeDVPL(Buffer.from(data))),
);
bar.tick();
}
if ('dynamicContentLocalizationsDir' in data) {
console.log('Found dynamic content localizations; patching...');
@@ -3,7 +3,7 @@ import { DATA_COMPRESSED } from '../../buildAssets/constants';
import { readDVPL } from './readDVPL';
export async function readDVPLFile(file: string) {
if (DATA_COMPRESSED) {
if (DATA_COMPRESSED && !file.endsWith('.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 { uniq } from 'lodash-es';
import { forwardRef, type ReactNode } from 'react';
@@ -16,6 +21,8 @@ type TankCardProps = TextProps & {
noLink?: boolean;
};
const tankDefinitions = await fetchTankDefinitions();
export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>(
(
{
@@ -49,10 +56,9 @@ export const TankCard = forwardRef<HTMLSpanElement, TankCardProps>(
onClick={() => {
onSelect?.(tank);
mutateTankopediaPersistent((draft) => {
draft.recentlyViewed = uniq([
tank.id,
...draft.recentlyViewed,
]).slice(0, MAX_RECENTLY_VIEWED);
draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed])
.filter((id) => id in tankDefinitions.tanks)
.slice(0, MAX_RECENTLY_VIEWED);
});
}}
className="tank-search-card"
@@ -12,7 +12,7 @@ export function NoResults({ type = 'filters' }: NoResultsProps) {
return (
<Flex flexGrow="1" align="center" justify="center">
<Text color="gray">
{strings.website.common.tank_search.no_tanks_found.body}.{' '}
{strings.website.common.tank_search.no_tanks_found.body}{' '}
<Link
href="#"
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.search_again}
</Link>
.
</Text>
</Flex>
);
@@ -16,7 +16,9 @@ export function RecentlyViewed() {
const tankopediaPersistentStore = TankopediaPersistent.useStore();
const filters = useStore($tankFilters);
// 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 hasFilters = useMemo(
() =>
@@ -2,6 +2,7 @@ import {
metaSortTank,
normalizeBoundingBox,
resolveDpm,
SEARCH_KEYS,
unionBoundingBox,
type TankDefinition,
} from '@blitzkit/core';
@@ -410,7 +411,7 @@ export const TankSearch = memo<TankSearchProps>(
: sorted.reverse();
} else {
const searchedRaw = fuzzysort.go(tankFilters.search, tankNames, {
keys: ['searchableName', 'searchableNameDeburr', 'camouflages'],
keys: SEARCH_KEYS,
});
const searchedTanks = searchedRaw.map(
(result) => tankDefinitions.tanks[result.obj.id],
@@ -456,7 +457,9 @@ export const TankSearch = memo<TankSearchProps>(
draft.recentlyViewed = uniq([
...tanksFiltered.map(({ id }) => id),
...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 { Callout, Flex } from '@radix-ui/themes';
import { uniq } from 'lodash-es';
@@ -9,6 +9,8 @@ import { AesonPlug } from '../AesonPlug';
import { ExperimentIcon } from '../ExperimentIcon';
import { MAX_RECENTLY_VIEWED } from '../TankSearch/constants';
const tankDefinitions = await fetchTankDefinitions();
export function CalloutsSection() {
const tank = Duel.use((state) => state.protagonist.tank);
const mutateTankopediaPersistent = TankopediaPersistent.useMutation();
@@ -17,10 +19,9 @@ export function CalloutsSection() {
useEffect(() => {
mutateTankopediaPersistent((draft) => {
draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed]).slice(
0,
MAX_RECENTLY_VIEWED,
);
draft.recentlyViewed = uniq([tank.id, ...draft.recentlyViewed])
.filter((id) => id in tankDefinitions.tanks)
.slice(0, MAX_RECENTLY_VIEWED);
});
}, [tank]);
@@ -30,6 +30,7 @@ const locale = Astro.params.locale ?? DEFAULT_LOCALE;
import { SUPPORTED_LOCALES } from '@blitzkit/i18n';
import { getBestLocale } from '../core/i18n/getBestLocale';
const isAPI = window.location.pathname.startsWith('/api');
const isI18nPath = SUPPORTED_LOCALES.some((locale) =>
window.location.pathname.startsWith(`/${locale}`),
);
@@ -38,7 +39,7 @@ const locale = Astro.params.locale ?? DEFAULT_LOCALE;
window.location.pathname.startsWith(`/${locale}`),
);
if (bestLocale !== currentPathLocale) {
if (!isAPI && bestLocale !== currentPathLocale) {
window.location.pathname = isI18nPath
? window.location.pathname.replace(
`/${currentPathLocale}`,
@@ -2,6 +2,7 @@ import { TankSandbox } from '../../../../../components/Tankopedia/HeroSection/co
import { awaitableModelDefinitions } from '../../../../../core/awaitables/modelDefinitions';
import { awaitableProvisionDefinitions } from '../../../../../core/awaitables/provisionDefinitions';
import { awaitableTankDefinitions } from '../../../../../core/awaitables/tankDefinitions';
import { LocaleProvider } from '../../../../../hooks/useLocale';
import { App } from '../../../../../stores/app';
import { Duel } from '../../../../../stores/duel';
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral';
@@ -23,15 +24,17 @@ export function Page({ id }: PageProps) {
const model = modelDefinitions.models[id];
return (
<App.Provider>
<TankopediaPersistent.Provider>
<Duel.Provider data={{ provisionDefinitions, tank }}>
<TankopediaEphemeral.Provider data={model}>
<Content />
</TankopediaEphemeral.Provider>
</Duel.Provider>
</TankopediaPersistent.Provider>
</App.Provider>
<LocaleProvider locale="en">
<App.Provider>
<TankopediaPersistent.Provider>
<Duel.Provider data={{ provisionDefinitions, tank }}>
<TankopediaEphemeral.Provider data={model}>
<Content />
</TankopediaEphemeral.Provider>
</Duel.Provider>
</TankopediaPersistent.Provider>
</App.Provider>
</LocaleProvider>
);
}