mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 02:37:05 +02:00
feat: more hot garbage
This commit is contained in:
1 parent
d0170d53e4
commit
788edf5bdf
30 files changed
+198
-240
No files matched your search
@@ -45,14 +45,20 @@
|
|||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"protobufjs": "^7.5.2",
|
"protobufjs": "^7.5.2",
|
||||||
|
"react": "^19.1.0",
|
||||||
|
"react-dom": "^19.1.0",
|
||||||
"quicklime": "^1.2.0",
|
"quicklime": "^1.2.0",
|
||||||
"sharp": "^0.33.5"
|
"sharp": "^0.33.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@astrojs/react": "^4.3.0",
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
"@types/js-yaml": "^4.0.9",
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
"@types/react": "^19.1.5",
|
||||||
|
"@types/react-dom": "^19.1.5",
|
||||||
"@types/node": "^22.14.1",
|
"@types/node": "^22.14.1",
|
||||||
|
"astro": "^5.8.0",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"prisma": "^6.6.0",
|
"prisma": "^6.6.0",
|
||||||
"typescript": "^5.8.3"
|
"typescript": "^5.8.3"
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
"satori": "^0.10.14",
|
"satori": "^0.10.14",
|
||||||
"@resvg/resvg-js": "^2.6.2",
|
"@resvg/resvg-js": "^2.6.2",
|
||||||
"discord.js": "^14.16.3",
|
"discord.js": "^14.16.3",
|
||||||
"react": "^18.3.1",
|
|
||||||
"@radix-ui/colors": "^3.0.0",
|
"@radix-ui/colors": "^3.0.0",
|
||||||
"fuzzysort": "^2.0.4",
|
"fuzzysort": "^2.0.4",
|
||||||
"bepaint": "^0.1.0-beta.3",
|
"bepaint": "^0.1.0-beta.3",
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { CatalogItem } from '@protos/blitz_items';
|
||||||
|
import { Any } from '@protos/google/protobuf/any';
|
||||||
|
import { MessageFns } from '../protos';
|
||||||
|
|
||||||
|
export class CatalogItemAccessor {
|
||||||
|
private components: Record<string, Any> = {};
|
||||||
|
|
||||||
|
constructor(item: CatalogItem) {
|
||||||
|
for (const component of item.components) {
|
||||||
|
if (
|
||||||
|
component.value === undefined ||
|
||||||
|
component.value.component === undefined
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.components[component.key] = component.value.component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get<Type>(Message: MessageFns<Type>, component: string) {
|
||||||
|
if (component in this.components) {
|
||||||
|
return Message.decode(this.components[component].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Unknown component: ${component}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from './canSplash';
|
export * from './canSplash';
|
||||||
|
export * from './catalogItemAccessor';
|
||||||
export * from './clans';
|
export * from './clans';
|
||||||
export * from './classes';
|
export * from './classes';
|
||||||
export * from './constants';
|
export * from './constants';
|
||||||
|
|||||||
@@ -1,10 +1,38 @@
|
|||||||
|
import { CatalogItem } from '@protos/blitz_items';
|
||||||
import { Metadata } from '@protos/blitz_metadata';
|
import { Metadata } from '@protos/blitz_metadata';
|
||||||
|
import { CatalogItemAccessor } from './catalogItemAccessor';
|
||||||
|
|
||||||
export class MetadataAccessor {
|
export class UnpackedMetadataAccessor {
|
||||||
constructor() {}
|
private items: Record<string, CatalogItemAccessor> = {};
|
||||||
|
|
||||||
loadMetadata(metadata: Metadata) {
|
constructor(metadata: Metadata) {
|
||||||
for (const catalogItem of metadata.catalog_items) {
|
for (const item of metadata.catalog_items) {
|
||||||
|
if (item.catalog_id in this.items) {
|
||||||
|
throw new Error(`Duplicate catalog ID: ${item.catalog_id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.items[item.catalog_id] = new CatalogItemAccessor(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get(item: string) {
|
||||||
|
if (item in this.items) return this.items[item];
|
||||||
|
|
||||||
|
throw new Error(`Unknown catalog ID: ${item}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DiscreteMetadataAccessor {
|
||||||
|
constructor(private base: string) {}
|
||||||
|
|
||||||
|
async get(item: string) {
|
||||||
|
const response = await fetch(`${this.base}/${item}.pb`);
|
||||||
|
|
||||||
|
if (!response.ok) throw new Error(`Unknown catalog ID: ${item}`);
|
||||||
|
|
||||||
|
const buffer = await response.arrayBuffer();
|
||||||
|
const catalogItem = CatalogItem.decode(new Uint8Array(buffer));
|
||||||
|
|
||||||
|
return new CatalogItemAccessor(catalogItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import locales from '@blitzkit/i18n/locales.json' with { type: 'json' };
|
||||||
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';
|
||||||
@@ -26,8 +26,8 @@ export async function fetchTankNames() {
|
|||||||
searchableNameDeburr,
|
searchableNameDeburr,
|
||||||
camouflages: tank.camouflages
|
camouflages: tank.camouflages
|
||||||
?.map((id) =>
|
?.map((id) =>
|
||||||
SUPPORTED_LOCALES.map(
|
locales.supported.map(
|
||||||
(locale) =>
|
({ locale }) =>
|
||||||
camouflageDefinitions.camouflages[id]?.name.locales[locale],
|
camouflageDefinitions.camouflages[id]?.name.locales[locale],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -42,9 +42,11 @@ export async function fetchTankNames() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const SEARCH_KEYS = [
|
export const SEARCH_KEYS = [
|
||||||
...SUPPORTED_LOCALES.map((locale) => [
|
...locales.supported
|
||||||
`searchableName.locales.${locale}`,
|
.map(({ locale }) => [
|
||||||
`searchableNameDeburr.locales.${locale}`,
|
`searchableName.locales.${locale}`,
|
||||||
]).flat(),
|
`searchableNameDeburr.locales.${locale}`,
|
||||||
|
])
|
||||||
|
.flat(),
|
||||||
'camouflages',
|
'camouflages',
|
||||||
];
|
];
|
||||||
@@ -1,89 +1,8 @@
|
|||||||
import { merge } from 'ts-deepmerge';
|
import type en from '../strings/en.json';
|
||||||
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 BlitzKitStrings = typeof en;
|
export type BlitzKitStrings = typeof en;
|
||||||
|
|
||||||
const stringsRaw = { en, es, fr, ja, pl, pt, ru, uk, zh };
|
export const SUPPORTED_LOCALE_FLAGS: Record<string, string> = {
|
||||||
|
|
||||||
export const SUPPORTED_LOCALES = Object.keys(stringsRaw) as SupportedLocale[];
|
|
||||||
|
|
||||||
export const DEFAULT_LOCALE = SUPPORTED_LOCALES[0];
|
|
||||||
|
|
||||||
function redact(string: string) {
|
|
||||||
const matches = [...string.matchAll(/%s\d+/g)];
|
|
||||||
const characters = string
|
|
||||||
.split('')
|
|
||||||
.map((char) => (char === ' ' ? ' ' : '█')) as string[];
|
|
||||||
|
|
||||||
matches.forEach((match) => {
|
|
||||||
const start = match.index;
|
|
||||||
const matchText = match[0];
|
|
||||||
for (let i = 0; i < matchText.length; i++) {
|
|
||||||
characters[start + i] = matchText[i];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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<Record<SupportedLocale, TranslationTree>> = {};
|
|
||||||
|
|
||||||
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<SupportedLocale, string> = {
|
|
||||||
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<SupportedLocale, string> = {
|
|
||||||
en: '🇺🇸',
|
en: '🇺🇸',
|
||||||
es: '🇪🇸',
|
es: '🇪🇸',
|
||||||
fr: '🇫🇷',
|
fr: '🇫🇷',
|
||||||
@@ -94,7 +13,3 @@ export const SUPPORTED_LOCALE_FLAGS: Record<SupportedLocale, string> = {
|
|||||||
zh: '🇨🇳',
|
zh: '🇨🇳',
|
||||||
pl: '🇵🇱',
|
pl: '🇵🇱',
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TranslationTree = { [key: string]: TranslationNode };
|
|
||||||
|
|
||||||
export type TranslationNode = string | TranslationTree;
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { I18nString } from '@blitzkit/core';
|
import { I18nString } from '@blitzkit/core';
|
||||||
import { DEFAULT_LOCALE } from './strings';
|
import locales from '../locales.json' with { type: 'json' };
|
||||||
|
|
||||||
export function unwrapper(locale: string) {
|
export function unwrapper(locale: string) {
|
||||||
return function (i18nString: I18nString) {
|
return function (i18nString: I18nString) {
|
||||||
@@ -7,6 +7,6 @@ export function unwrapper(locale: string) {
|
|||||||
return i18nString.locales[locale];
|
return i18nString.locales[locale];
|
||||||
}
|
}
|
||||||
|
|
||||||
return i18nString.locales[DEFAULT_LOCALE];
|
return i18nString.locales[locales.default];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Avatar, encodePBBuffer, fetchGlossary, Gallery } from '@blitzkit/core';
|
import { Avatar, encodePBBuffer, fetchGlossary, Gallery } from '@blitzkit/core';
|
||||||
import locales from '@blitzkit/i18n/locales.json';
|
import locales from '@blitzkit/i18n/locales.json' with { type: 'json' };
|
||||||
import { extname } from 'path';
|
import { extname } from 'path';
|
||||||
import ProgressBar from 'progress';
|
import ProgressBar from 'progress';
|
||||||
import { commitAssets } from '../core/github/commitAssets';
|
import { commitAssets } from '../core/github/commitAssets';
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
import partytown from '@astrojs/partytown';
|
import partytown from '@astrojs/partytown';
|
||||||
import react from '@astrojs/react';
|
import react from '@astrojs/react';
|
||||||
import sitemap from '@astrojs/sitemap';
|
import sitemap from '@astrojs/sitemap';
|
||||||
import { SUPPORTED_LOCALES } from '@blitzkit/i18n';
|
import locales from '@blitzkit/i18n/locales.json' with { type: 'json' };
|
||||||
import { defineConfig } from 'astro/config';
|
import { defineConfig } from 'astro/config';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
i18n: {
|
i18n: {
|
||||||
defaultLocale: 'en',
|
defaultLocale: locales.default,
|
||||||
locales: [...SUPPORTED_LOCALES],
|
locales: locales.supported.map(({ locale }) => locale),
|
||||||
routing: {
|
routing: {
|
||||||
prefixDefaultLocale: false,
|
prefixDefaultLocale: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -12,19 +12,19 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/partytown": "^2.1.4",
|
"@astrojs/partytown": "^2.1.4",
|
||||||
"@astrolib/seo": "^1.0.0-beta.8",
|
"@astrolib/seo": "^1.0.0-beta.8",
|
||||||
|
"@blitzkit/closed": "workspace:*",
|
||||||
"@blitzkit/core": "workspace:*",
|
"@blitzkit/core": "workspace:*",
|
||||||
"@blitzkit/i18n": "workspace:*",
|
"@blitzkit/i18n": "workspace:*",
|
||||||
"@blitzkit/closed": "workspace:*",
|
|
||||||
"@fontsource/inter": "^5.2.5",
|
"@fontsource/inter": "^5.2.5",
|
||||||
"@nanostores/persistent": "^0.10.2",
|
"@nanostores/persistent": "^0.10.2",
|
||||||
"@nanostores/react": "^0.7.3",
|
"@nanostores/react": "^0.7.3",
|
||||||
"@nivo/bar": "^0.87.0",
|
"@nivo/bar": "^0.87.0",
|
||||||
"@nivo/line": "^0.88.0",
|
"@nivo/line": "^0.88.0",
|
||||||
"@radix-ui/colors": "^3.0.0",
|
"@radix-ui/colors": "^3.0.0",
|
||||||
"@radix-ui/react-icons": "^1.3.0",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@radix-ui/themes": "^3.1.4",
|
"@radix-ui/themes": "^3.2.1",
|
||||||
"@react-three/drei": "^9.115.0",
|
"@react-three/drei": "^10.0.8",
|
||||||
"@react-three/fiber": "^8.17.10",
|
"@react-three/fiber": "^9.1.2",
|
||||||
"compare-versions": "^6.1.1",
|
"compare-versions": "^6.1.1",
|
||||||
"echarts": "^5.5.1",
|
"echarts": "^5.5.1",
|
||||||
"immer": "^10.1.1",
|
"immer": "^10.1.1",
|
||||||
@@ -32,9 +32,7 @@
|
|||||||
"markdown-to-jsx": "^7.5.0",
|
"markdown-to-jsx": "^7.5.0",
|
||||||
"nanostores": "^0.11.3",
|
"nanostores": "^0.11.3",
|
||||||
"quicklime": "^1.2.0",
|
"quicklime": "^1.2.0",
|
||||||
"react": "^18.3.1",
|
|
||||||
"react-device-detect": "^2.2.3",
|
"react-device-detect": "^2.2.3",
|
||||||
"react-dom": "^18.3.1",
|
|
||||||
"react-promise-suspense": "^0.3.4",
|
"react-promise-suspense": "^0.3.4",
|
||||||
"three": "^0.169.0",
|
"three": "^0.169.0",
|
||||||
"urlon": "^3.1.0",
|
"urlon": "^3.1.0",
|
||||||
@@ -47,10 +45,7 @@
|
|||||||
"@playform/compress": "^0.1.9",
|
"@playform/compress": "^0.1.9",
|
||||||
"@playform/inline": "^0.1.2",
|
"@playform/inline": "^0.1.2",
|
||||||
"@types/js-cookie": "^3.0.6",
|
"@types/js-cookie": "^3.0.6",
|
||||||
"@types/react": "^18.3.12",
|
|
||||||
"@types/react-dom": "^18.3.1",
|
|
||||||
"@types/three": "^0.160.0",
|
"@types/three": "^0.160.0",
|
||||||
"astro": "^4.16.7",
|
"astro": "^4.16.7"
|
||||||
"astro-compressor": "^1.0.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import locales from '@blitzkit/i18n/locales.json';
|
import locales from '@blitzkit/i18n/locales.json' with { type: 'json' };
|
||||||
import { literals } from '@blitzkit/i18n/src/literals';
|
import { literals } from '@blitzkit/i18n/src/literals';
|
||||||
import { Flex, Text } from '@radix-ui/themes';
|
import { Flex, Text } from '@radix-ui/themes';
|
||||||
import fuzzysort from 'fuzzysort';
|
import fuzzysort from 'fuzzysort';
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import type { BlitzKitStrings } from 'packages/i18n/src';
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
locale: string;
|
locale: string;
|
||||||
strings: BlitzKitStrings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { strings, locale } = Astro.props;
|
const { locale } = Astro.props;
|
||||||
|
const strings = await getStrings(locale);
|
||||||
const branchName = resolveBranchName(locale);
|
const branchName = resolveBranchName(locale);
|
||||||
const isBranchNamed = branchName !== undefined;
|
const isBranchNamed = branchName !== undefined;
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
type CompositeStats,
|
type CompositeStats,
|
||||||
type CompositeStatsKey,
|
type CompositeStatsKey,
|
||||||
} from '@blitzkit/core';
|
} from '@blitzkit/core';
|
||||||
import strings from '@blitzkit/i18n/strings/en.json';
|
|
||||||
import { amberDark, blueDark } from '@radix-ui/colors';
|
import { amberDark, blueDark } from '@radix-ui/colors';
|
||||||
import { Flex, Text, type FlexProps } from '@radix-ui/themes';
|
import { Flex, Text, type FlexProps } from '@radix-ui/themes';
|
||||||
import { times } from 'lodash-es';
|
import { times } from 'lodash-es';
|
||||||
@@ -53,7 +52,7 @@ export function BreakdownEmbedCard({
|
|||||||
}: BreakdownEmbedCardProps) {
|
}: BreakdownEmbedCardProps) {
|
||||||
const { useEmbedState, useRichText } =
|
const { useEmbedState, useRichText } =
|
||||||
useEmbedStateCurry<typeof breakdownConfig>();
|
useEmbedStateCurry<typeof breakdownConfig>();
|
||||||
const { unwrap } = useLocale();
|
const { unwrap, strings } = useLocale();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
export function TestComponent({ data }: { data: any }) {
|
export function TestComponent({ data }: { data: any }) {
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(data);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return 'TestComponent';
|
return 'TestComponent';
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import { DiscreteMetadataAccessor } from 'packages/core/src';
|
||||||
|
|
||||||
|
export const discreteMetadata = new DiscreteMetadataAccessor('/api/catalog');
|
||||||
+3
-6
@@ -1,11 +1,8 @@
|
|||||||
import {
|
import { requestAutoProxyClient, unpackMetadata } from '@blitzkit/closed';
|
||||||
MetadataAccessor,
|
|
||||||
requestAutoProxyClient,
|
|
||||||
unpackMetadata,
|
|
||||||
} from '@blitzkit/closed';
|
|
||||||
import type { GetPackedMetadataAsyncResponse } from '@blitzkit/closed/src/unreal/protos/auto_legacy_proxy_client';
|
import type { GetPackedMetadataAsyncResponse } from '@blitzkit/closed/src/unreal/protos/auto_legacy_proxy_client';
|
||||||
|
import { UnpackedMetadataAccessor } from 'packages/core/src';
|
||||||
|
|
||||||
export const metadata = new MetadataAccessor(
|
export const unpackedMetadata = new UnpackedMetadataAccessor(
|
||||||
await requestAutoProxyClient<GetPackedMetadataAsyncResponse>(
|
await requestAutoProxyClient<GetPackedMetadataAsyncResponse>(
|
||||||
'GetPackedMetadataAsyncRequest',
|
'GetPackedMetadataAsyncRequest',
|
||||||
).then(unpackMetadata),
|
).then(unpackMetadata),
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { STRINGS, type SupportedLocale } from '@blitzkit/i18n';
|
import en from '@strings/en.json' with { type: 'json' };
|
||||||
|
import { merge } from 'lodash-es';
|
||||||
|
import type { BlitzKitStrings } from 'packages/i18n/src';
|
||||||
|
|
||||||
export function getStrings(locale: string) {
|
export async function getStrings(locale: string) {
|
||||||
if (locale in STRINGS) return STRINGS[locale as SupportedLocale];
|
const strings = await import(`../../../../i18n/strings/${locale}.json`);
|
||||||
throw new Error(`Unsupported locale: ${locale}`);
|
return merge({}, en, strings) as BlitzKitStrings;
|
||||||
}
|
}
|
||||||
@@ -1,41 +1,30 @@
|
|||||||
import { type BlitzKitStrings } from '@blitzkit/i18n';
|
import locales from '@blitzkit/i18n/locales.json' with { type: 'json' };
|
||||||
import { createContext, useContext, type ReactNode } from 'react';
|
import type { BlitzKitStrings } from 'packages/i18n/src';
|
||||||
|
import { createContext, use, useContext } from 'react';
|
||||||
interface LocaleContextContent {
|
const LocaleContext = createContext<string | null>(null);
|
||||||
locale: string;
|
|
||||||
strings: BlitzKitStrings;
|
|
||||||
gameStrings: Record<string, string>;
|
|
||||||
}
|
|
||||||
|
|
||||||
type LocaleContextData = Omit<LocaleContextContent, 'gameStrings'> & {
|
|
||||||
gameStrings?: Record<string, string>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const LocaleContext = createContext<LocaleContextContent | null>(null);
|
|
||||||
|
|
||||||
interface LocaleProviderProps {
|
interface LocaleProviderProps {
|
||||||
data: LocaleContextData;
|
locale: string;
|
||||||
children: ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LocaleProvider({ data, children }: LocaleProviderProps) {
|
export function LocaleProvider({ locale, children }: LocaleProviderProps) {
|
||||||
|
const isSupported = locales.supported.some(
|
||||||
|
(supported) => supported.locale === locale,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isSupported) throw new Error(`Unsupported locale: ${locale}`);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LocaleContext.Provider value={{ gameStrings: {}, ...data }}>
|
<LocaleContext.Provider value={locale}>{children}</LocaleContext.Provider>
|
||||||
{children}
|
|
||||||
</LocaleContext.Provider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useLocale() {
|
export function useLocale() {
|
||||||
const context = useContext(LocaleContext);
|
const locale = useContext(LocaleContext);
|
||||||
|
const strings = use<BlitzKitStrings>(
|
||||||
|
fetch(`/api/strings/${locale}.json`).then((response) => response.json()),
|
||||||
|
);
|
||||||
|
|
||||||
if (!context) {
|
return { locale, strings };
|
||||||
throw new Error('useLocale must be used within a LocaleProvider');
|
|
||||||
}
|
|
||||||
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LocaleAcceptorProps {
|
|
||||||
localeContext: LocaleContextContent;
|
|
||||||
}
|
}
|
||||||
@@ -7,16 +7,17 @@ import Navbar from '../components/Navbar.astro';
|
|||||||
import Party3 from '../components/Party3.astro';
|
import Party3 from '../components/Party3.astro';
|
||||||
import './base.css';
|
import './base.css';
|
||||||
import type { BlitzKitStrings } from 'packages/i18n/src';
|
import type { BlitzKitStrings } from 'packages/i18n/src';
|
||||||
|
import { getStrings } from '../core/i18n/getStrings';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
noFooter?: boolean;
|
noFooter?: boolean;
|
||||||
noNavbar?: boolean;
|
noNavbar?: boolean;
|
||||||
integrated?: boolean;
|
integrated?: boolean;
|
||||||
locale: string;
|
locale: string;
|
||||||
strings: BlitzKitStrings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { noFooter, noNavbar, integrated, locale, strings } = Astro.props;
|
const { noFooter, noNavbar, integrated, locale } = Astro.props;
|
||||||
|
const strings = await getStrings(locale);
|
||||||
---
|
---
|
||||||
|
|
||||||
<html lang={locale}>
|
<html lang={locale}>
|
||||||
@@ -30,25 +31,26 @@ const { noFooter, noNavbar, integrated, locale, strings } = Astro.props;
|
|||||||
<Party3 />
|
<Party3 />
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { SUPPORTED_LOCALES } from '@blitzkit/i18n';
|
import locales from '@blitzkit/i18n/locales.json' with { type: 'json' };
|
||||||
import { getBestLocale } from '../core/i18n/getBestLocale';
|
import { getBestLocale } from '../core/i18n/getBestLocale';
|
||||||
const isAPI = window.location.pathname.startsWith('/api');
|
const isAPI = window.location.pathname.startsWith('/api');
|
||||||
const isI18nPath = SUPPORTED_LOCALES.some((locale) =>
|
const isI18nPath = locales.supported.some(({ locale }) =>
|
||||||
window.location.pathname.startsWith(`/${locale}`),
|
window.location.pathname.startsWith(`/${locale}`),
|
||||||
);
|
);
|
||||||
const bestLocale = getBestLocale();
|
const bestLocale = getBestLocale();
|
||||||
const currentPathLocale = SUPPORTED_LOCALES.find((locale) =>
|
const currentPathLocale = locales.supported.find(({ locale }) =>
|
||||||
window.location.pathname.startsWith(`/${locale}`),
|
window.location.pathname.startsWith(`/${locale}`),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!isAPI && // not an api, duh!
|
!isAPI && // not an api, duh!
|
||||||
localStorage.getItem('preferred-locale') !== null && // no preference, so probably google's crawler
|
localStorage.getItem('preferred-locale') !== null && // no preference, so probably google's crawler
|
||||||
bestLocale !== currentPathLocale // we need to redirect
|
currentPathLocale &&
|
||||||
|
bestLocale !== currentPathLocale.locale // we need to redirect
|
||||||
) {
|
) {
|
||||||
window.location.pathname = isI18nPath
|
window.location.pathname = isI18nPath
|
||||||
? window.location.pathname.replace(
|
? window.location.pathname.replace(
|
||||||
`/${currentPathLocale}`,
|
`/${currentPathLocale.locale}`,
|
||||||
bestLocale === undefined ? '' : `/${bestLocale}`,
|
bestLocale === undefined ? '' : `/${bestLocale}`,
|
||||||
)
|
)
|
||||||
: `/${bestLocale}${window.location.pathname}`;
|
: `/${bestLocale}${window.location.pathname}`;
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
---
|
---
|
||||||
import { AstroSeo } from '@astrolib/seo';
|
import { AstroSeo } from '@astrolib/seo';
|
||||||
import { assertSecret } from '@blitzkit/core';
|
import { assertSecret } from '@blitzkit/core';
|
||||||
import { DEFAULT_LOCALE, STRINGS, type SupportedLocale } from '@blitzkit/i18n';
|
import locales from '@blitzkit/i18n/locales.json' with { type: 'json' };
|
||||||
import locales from '@blitzkit/i18n/locales.json';
|
|
||||||
import { literals } from '@blitzkit/i18n/src/literals';
|
import { literals } from '@blitzkit/i18n/src/literals';
|
||||||
import { Box, Flex, Heading, Link } from '@radix-ui/themes';
|
import { Box, Flex, Heading, Link } from '@radix-ui/themes';
|
||||||
import type { GetStaticPaths } from 'astro';
|
import type { GetStaticPaths } from 'astro';
|
||||||
@@ -21,20 +20,18 @@ import {
|
|||||||
tankopediaTool,
|
tankopediaTool,
|
||||||
tierListTool,
|
tierListTool,
|
||||||
} from '../../constants/tools';
|
} from '../../constants/tools';
|
||||||
|
import { getStrings } from '../../core/i18n/getStrings';
|
||||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||||
|
|
||||||
const PUBLIC_ASSET_BRANCH = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH);
|
const PUBLIC_ASSET_BRANCH = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH);
|
||||||
const { strings, locale } = Astro.props;
|
const { locale } = Astro.props;
|
||||||
|
const strings = await getStrings(locale);
|
||||||
|
|
||||||
export const getStaticPaths = (() => {
|
export const getStaticPaths = (() => {
|
||||||
return locales.supported.map(({ locale, blitz }) => {
|
return locales.supported.map(({ locale, blitz }) => {
|
||||||
return {
|
return {
|
||||||
params: { locale: locale === locales.default ? undefined : locale },
|
params: { locale: locale === locales.default ? undefined : locale },
|
||||||
props: {
|
props: { locale, blitzLocale: blitz ?? locale },
|
||||||
locale,
|
|
||||||
strings: STRINGS[locale as SupportedLocale],
|
|
||||||
blitzLocale: blitz ?? locale,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}) satisfies GetStaticPaths;
|
}) satisfies GetStaticPaths;
|
||||||
@@ -53,8 +50,8 @@ export const getStaticPaths = (() => {
|
|||||||
twitter={{ cardType: 'summary_large_image' }}
|
twitter={{ cardType: 'summary_large_image' }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<BaseLayout {locale} {strings}>
|
<BaseLayout {locale}>
|
||||||
<HomeHero {locale} {strings} />
|
<HomeHero {locale} />
|
||||||
|
|
||||||
<!-- <Flex justify="center" py="6" px="4" justify="center">
|
<!-- <Flex justify="center" py="6" px="4" justify="center">
|
||||||
<Flex
|
<Flex
|
||||||
@@ -73,7 +70,7 @@ export const getStaticPaths = (() => {
|
|||||||
</Flex> -->
|
</Flex> -->
|
||||||
|
|
||||||
{
|
{
|
||||||
locale !== DEFAULT_LOCALE && (
|
locale !== locales.default && (
|
||||||
<Flex justify="center" mb="4">
|
<Flex justify="center" mb="4">
|
||||||
<Link
|
<Link
|
||||||
href="https://crowdin.com/project/blitzkrieg"
|
href="https://crowdin.com/project/blitzkrieg"
|
||||||
|
|||||||
@@ -5,29 +5,30 @@ import type {
|
|||||||
TankCatalogComponent,
|
TankCatalogComponent,
|
||||||
} from '@blitzkit/closed/src/unreal/protos';
|
} from '@blitzkit/closed/src/unreal/protos';
|
||||||
import { slugify } from '@blitzkit/core';
|
import { slugify } from '@blitzkit/core';
|
||||||
import locales from '@blitzkit/i18n/locales.json';
|
import locales from '@blitzkit/i18n/locales.json' with { type: 'json' };
|
||||||
import type { GetStaticPaths } from 'astro';
|
import type { GetStaticPaths } from 'astro';
|
||||||
import { tankToSet } from 'packages/website/src/core/blitz/tankToSet';
|
import { tankToSet } from 'packages/website/src/core/blitz/tankToSet';
|
||||||
import type { TankopediaEphemeral_ue } from 'packages/website/src/stores/tankopediaEphemeral_ue';
|
import type { TankopediaEphemeral_ue } from 'packages/website/src/stores/tankopediaEphemeral_ue';
|
||||||
import { metadata } from '../../../../core/blitz/metadata';
|
import { unpackedMetadata } from '../../../../core/blitz/unpackedMetadata';
|
||||||
import BaseLayout from '../../../../layouts/BaseLayout.astro';
|
import BaseLayout from '../../../../layouts/BaseLayout.astro';
|
||||||
import { getStaticPaths as parentGetStaticPaths } from '../index.astro';
|
import { getStaticPaths as parentGetStaticPaths } from '../index.astro';
|
||||||
import { Page } from './_index';
|
import { Page } from './_index';
|
||||||
|
|
||||||
export const getStaticPaths = (async () => {
|
export const getStaticPaths = (async () => {
|
||||||
const tanks = await metadata.getComponent<CatalogItemsComponent>(
|
const tanks = await unpackedMetadata.getComponent<CatalogItemsComponent>(
|
||||||
'CatalogItemsGroupEntity.all_tanks',
|
'CatalogItemsGroupEntity.all_tanks',
|
||||||
'catalogItemsGroupComponent',
|
'catalogItemsGroupComponent',
|
||||||
);
|
);
|
||||||
const gameStringsDefault = await metadata.stringsSubset(locales.default, [
|
const gameStringsDefault = await unpackedMetadata.stringsSubset(
|
||||||
'TankEntity',
|
locales.default,
|
||||||
]);
|
['TankEntity'],
|
||||||
|
);
|
||||||
const parentPaths = parentGetStaticPaths();
|
const parentPaths = parentGetStaticPaths();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
tanks.catalog_items.map(async (item) => {
|
tanks.catalog_items.map(async (item) => {
|
||||||
const tank = await metadata.get(item).then((components) => {
|
const tank = await unpackedMetadata.get(item).then((components) => {
|
||||||
return components.get<TankCatalogComponent>('tankCatalogComponent');
|
return components.get<TankCatalogComponent>('tankCatalogComponent');
|
||||||
});
|
});
|
||||||
const nameEn = gameStringsDefault[tank.name!.value];
|
const nameEn = gameStringsDefault[tank.name!.value];
|
||||||
@@ -45,11 +46,11 @@ export const getStaticPaths = (async () => {
|
|||||||
}) satisfies GetStaticPaths;
|
}) satisfies GetStaticPaths;
|
||||||
|
|
||||||
const { entity, locale, strings, blitzLocale } = Astro.props;
|
const { entity, locale, strings, blitzLocale } = Astro.props;
|
||||||
const set = await tankToSet(metadata, entity);
|
const set = await tankToSet(unpackedMetadata, entity);
|
||||||
const gameStrings = await metadata.stringsSubset(blitzLocale, [
|
const gameStrings = await unpackedMetadata.stringsSubset(blitzLocale, [
|
||||||
set.tank_set_ui!.tank_set_displayed_name,
|
set.tank_set_ui!.tank_set_displayed_name,
|
||||||
]);
|
]);
|
||||||
const tankEntity = await metadata.get(entity);
|
const tankEntity = await unpackedMetadata.get(entity);
|
||||||
const tank = await tankEntity.get<TankCatalogComponent>('tankCatalogComponent');
|
const tank = await tankEntity.get<TankCatalogComponent>('tankCatalogComponent');
|
||||||
const compensation = await tankEntity.get<CompensationComponent>(
|
const compensation = await tankEntity.get<CompensationComponent>(
|
||||||
'compensationComponent',
|
'compensationComponent',
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
import { CatalogItemsComponent } from '@protos/blitz_static_catalog_items_group_component';
|
||||||
|
import { Link } from '@radix-ui/themes';
|
||||||
|
import { PageWrapper } from 'packages/website/src/components/PageWrapper';
|
||||||
|
import { unpackedMetadata } from 'packages/website/src/core/blitz/unpackedMetadata';
|
||||||
|
import BaseLayout from 'packages/website/src/layouts/BaseLayout.astro';
|
||||||
|
|
||||||
|
export { getStaticPaths } from '../index.astro';
|
||||||
|
|
||||||
|
const { locale } = Astro.props;
|
||||||
|
|
||||||
|
const allTanks = unpackedMetadata
|
||||||
|
.get('CatalogItemsGroupEntity.all_tanks')
|
||||||
|
.get(CatalogItemsComponent, 'catalogItemsGroupComponent');
|
||||||
|
---
|
||||||
|
|
||||||
|
<BaseLayout {locale}>
|
||||||
|
<PageWrapper>
|
||||||
|
{allTanks.catalog_items.map((tank) => <Link>{tank}</Link>)}
|
||||||
|
</PageWrapper>
|
||||||
|
</BaseLayout>
|
||||||
@@ -1,52 +1,17 @@
|
|||||||
---
|
---
|
||||||
import { slugify } from '@blitzkit/core';
|
import { CatalogItemsComponent } from '@protos/blitz_static_catalog_items_group_component';
|
||||||
import locales from '@blitzkit/i18n/locales.json';
|
|
||||||
import type { CatalogItemsComponent } from '@protos/blitz_static_catalog_items_group_component';
|
|
||||||
import { TankCatalogComponent } from '@protos/blitz_static_tank_component';
|
|
||||||
import { TestComponent } from 'packages/website/src/components/TestComponent';
|
import { TestComponent } from 'packages/website/src/components/TestComponent';
|
||||||
import { metadata } from '../../../core/blitz/metadata';
|
import { unpackedMetadata } from 'packages/website/src/core/blitz/unpackedMetadata';
|
||||||
|
import { getStrings } from 'packages/website/src/core/i18n/getStrings';
|
||||||
|
|
||||||
export { getStaticPaths } from '../index.astro';
|
export { getStaticPaths } from '../index.astro';
|
||||||
|
|
||||||
const { blitzLocale } = Astro.props;
|
const { locale } = Astro.props;
|
||||||
const allTanks = await metadata.getComponent<CatalogItemsComponent>(
|
const strings = await getStrings(locale);
|
||||||
'CatalogItemsGroupEntity.all_tanks',
|
|
||||||
'catalogItemsGroupComponent',
|
|
||||||
);
|
|
||||||
const gameStrings = await metadata.stringsSubset(blitzLocale, ['TankEntity']);
|
|
||||||
const gameStringsDefault = await metadata.stringsSubset(locales.default, [
|
|
||||||
'TankEntity',
|
|
||||||
]);
|
|
||||||
const tanks: { tank: TankCatalogComponent; slug: string; id: string }[] = [];
|
|
||||||
|
|
||||||
for (const tankComponentId of allTanks.catalog_items) {
|
const allTanks = unpackedMetadata
|
||||||
const tank = await metadata.getComponent<TankCatalogComponent>(
|
.get('CatalogItemsGroupEntity.all_tanks')
|
||||||
tankComponentId,
|
.get(CatalogItemsComponent, 'catalogItemsGroupComponent');
|
||||||
'tankCatalogComponent',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (tank.name === undefined) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nameEn = gameStringsDefault[tank.name.value];
|
|
||||||
const slug = slugify(nameEn);
|
|
||||||
|
|
||||||
tanks.push({ tank, slug, id: tankComponentId });
|
|
||||||
}
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<TestComponent client:load data={metadata} />
|
<TestComponent client:load data={allTanks} />
|
||||||
|
|
||||||
{
|
|
||||||
tanks.map(({ tank, slug, id }) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<a href={`/tanks-ue/${slug}`}>
|
|
||||||
{gameStrings[tank.name!.value] ?? `MISSING NAME (${id})`}
|
|
||||||
</a>
|
|
||||||
<br />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import en from '@blitzkit/i18n/strings/en.json';
|
import en from '@blitzkit/i18n/strings/en.json' with { type: 'json' };
|
||||||
import type { TankPerformanceSortType } from '.';
|
import type { TankPerformanceSortType } from '.';
|
||||||
|
|
||||||
export const TankPerformanceSortTypeNamesArray = Object.keys(
|
export const TankPerformanceSortTypeNamesArray = Object.keys(
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type en from '@blitzkit/i18n/strings/en.json';
|
import type { BlitzKitStrings } from 'packages/i18n/src';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { createContextualStore } from '../../core/zustand/createContextualStore';
|
import { createContextualStore } from '../../core/zustand/createContextualStore';
|
||||||
|
|
||||||
export type TankPerformanceSortType =
|
export type TankPerformanceSortType =
|
||||||
keyof typeof en.website.tools.performance.table.stats;
|
keyof BlitzKitStrings['website']['tools']['performance']['table']['stats'];
|
||||||
|
|
||||||
export interface TankPerformanceSort {
|
export interface TankPerformanceSort {
|
||||||
type: TankPerformanceSortType;
|
type: TankPerformanceSortType;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import type en from '@blitzkit/i18n/strings/en.json';
|
|
||||||
import * as lodash from 'lodash-es';
|
import * as lodash from 'lodash-es';
|
||||||
|
import type { BlitzKitStrings } from 'packages/i18n/src';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
import { persist, subscribeWithSelector } from 'zustand/middleware';
|
import { persist, subscribeWithSelector } from 'zustand/middleware';
|
||||||
import { createContextualStore } from '../../core/zustand/createContextualStore';
|
import { createContextualStore } from '../../core/zustand/createContextualStore';
|
||||||
|
|
||||||
export type TankopediaSortBy = keyof typeof en.website.common.tank_search.sort;
|
export type TankopediaSortBy =
|
||||||
|
keyof BlitzKitStrings['website']['common']['tank_search']['sort'];
|
||||||
export type TankopediaSortDirection = 'ascending' | 'descending';
|
export type TankopediaSortDirection = 'ascending' | 'descending';
|
||||||
export type TankopediaTestTankDisplay = 'include' | 'exclude' | 'only';
|
export type TankopediaTestTankDisplay = 'include' | 'exclude' | 'only';
|
||||||
|
|
||||||
|
|||||||
Submodule submodules/blitzkit-closed updated: accc9ee26b...2fde7c0096.
+2
-1
@@ -23,7 +23,8 @@
|
|||||||
|
|
||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@protos/*": ["submodules/blitzkit-closed/src/unreal/protos/*"]
|
"@protos/*": ["submodules/blitzkit-closed/src/unreal/protos/*"],
|
||||||
|
"@strings/*": ["packages/i18n/strings/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules/**/*", "dist", ".next"]
|
"exclude": ["node_modules/**/*", "dist", ".next"]
|
||||||
|
|||||||
Reference in new issue
Block a user