mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 12:09:51 +02:00
feat: game strings context
This commit is contained in:
1 parent
9bf1554c30
commit
1eca71d28c
21 files changed
+207
-136
No files matched your search
@@ -19,8 +19,6 @@ export * from './idToRegion';
|
|||||||
export * from './isOnGoingRatingSeason';
|
export * from './isOnGoingRatingSeason';
|
||||||
export * from './isValidBlitzId';
|
export * from './isValidBlitzId';
|
||||||
export * from './metadata';
|
export * from './metadata';
|
||||||
export * from './metadata.remote';
|
|
||||||
export * from './metadata.socket';
|
|
||||||
export * from './nations';
|
export * from './nations';
|
||||||
export * from './normalizeExtra';
|
export * from './normalizeExtra';
|
||||||
export * from './normalizeIds';
|
export * from './normalizeIds';
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
import { BlitzkitAllAvatarsComponent } from '@protos/blitzkit_static_all_avatars_component';
|
|
||||||
import { CatalogItemAccessor } from './catalogItemAccessor';
|
|
||||||
|
|
||||||
export abstract class MetadataAccessor {
|
|
||||||
abstract get(item: string): Promise<CatalogItemAccessor>;
|
|
||||||
|
|
||||||
abstract add(item: CatalogItemAccessor): void;
|
|
||||||
|
|
||||||
abstract filter(predicate: (item: string) => boolean): CatalogItemAccessor[];
|
|
||||||
|
|
||||||
injectBlitzkit() {
|
|
||||||
this.injectBlitzkitProfileAvatars();
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
injectBlitzkitProfileAvatars() {
|
|
||||||
const allAvatars: BlitzkitAllAvatarsComponent = {
|
|
||||||
avatars: this.filter((item) =>
|
|
||||||
item.startsWith('ProfileAvatarEntity.'),
|
|
||||||
).map((avatar) => avatar.pack()),
|
|
||||||
};
|
|
||||||
|
|
||||||
this.add(
|
|
||||||
CatalogItemAccessor.fromComponent(
|
|
||||||
'BlitzkitAllAvatarsEntity.blitzkit_all_avatars',
|
|
||||||
{
|
|
||||||
type_url:
|
|
||||||
'./blitzkit_static_all_avatars_component.BlitzkitAllAvatarsComponent',
|
|
||||||
value: BlitzkitAllAvatarsComponent.encode(allAvatars).finish(),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
import { LocalizationResourcesComponent } from '@protos/blitz_static_localization_resources_component';
|
||||||
|
import { RemoteStorageComponent } from '@protos/blitz_static_remote_storage_component';
|
||||||
|
import { BlitzkitAllAvatarsComponent } from '@protos/blitzkit_static_all_avatars_component';
|
||||||
|
import { load } from 'js-yaml';
|
||||||
|
import { minimatch } from 'minimatch';
|
||||||
|
import { CatalogItemAccessor } from '../catalogItemAccessor';
|
||||||
|
|
||||||
|
interface LocalizationConfig {
|
||||||
|
namespaces: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class MetadataAccessor {
|
||||||
|
abstract get(item: string): Promise<CatalogItemAccessor>;
|
||||||
|
|
||||||
|
abstract add(item: CatalogItemAccessor): void;
|
||||||
|
|
||||||
|
abstract filter(predicate: (item: string) => boolean): CatalogItemAccessor[];
|
||||||
|
|
||||||
|
async strings(locale: string) {
|
||||||
|
const clientConfig = await this.get(
|
||||||
|
'ClientConfigsEntity.default_client_config',
|
||||||
|
);
|
||||||
|
const localizationResources = clientConfig.get(
|
||||||
|
LocalizationResourcesComponent,
|
||||||
|
'localizationResourcesComponent',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!localizationResources.remote_storage) {
|
||||||
|
throw new Error('Localization resources not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { relative_path } = localizationResources.remote_storage;
|
||||||
|
|
||||||
|
let remoteStorage: RemoteStorageComponent | undefined = undefined;
|
||||||
|
|
||||||
|
for (const candidateId of localizationResources.remote_storage.production) {
|
||||||
|
const item = await this.get(candidateId);
|
||||||
|
const candidate = item.get(
|
||||||
|
RemoteStorageComponent,
|
||||||
|
'remoteStorageComponent',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
remoteStorage === undefined ||
|
||||||
|
candidate.download_speed_weight > remoteStorage.download_speed_weight
|
||||||
|
) {
|
||||||
|
remoteStorage = candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remoteStorage === undefined) {
|
||||||
|
throw new Error('No suitable production remote storage found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = await fetch(
|
||||||
|
`${remoteStorage.url}/${relative_path}/config.yaml`,
|
||||||
|
)
|
||||||
|
.then((response) => response.text())
|
||||||
|
.then((text) => load(text) as LocalizationConfig);
|
||||||
|
const strings: Record<string, string> = {};
|
||||||
|
|
||||||
|
for (const namespace of config.namespaces) {
|
||||||
|
Object.assign(
|
||||||
|
strings,
|
||||||
|
await fetch(
|
||||||
|
`${remoteStorage.url}/${relative_path}/${namespace}/${locale}.yaml`,
|
||||||
|
)
|
||||||
|
.then((response) => response.text())
|
||||||
|
.then((text) => load(text) as Record<string, string>),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
async stringsPartial(locale: string, patterns: string[]) {
|
||||||
|
const strings = await this.strings(locale);
|
||||||
|
const filtered: Record<string, string> = {};
|
||||||
|
|
||||||
|
for (const key in strings) {
|
||||||
|
if (patterns.some((pattern) => minimatch(key, pattern))) {
|
||||||
|
filtered[key] = strings[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
injectBlitzkit() {
|
||||||
|
this.injectBlitzkitProfileAvatars();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
injectBlitzkitProfileAvatars() {
|
||||||
|
const allAvatars: BlitzkitAllAvatarsComponent = {
|
||||||
|
avatars: this.filter((item) =>
|
||||||
|
item.startsWith('ProfileAvatarEntity.'),
|
||||||
|
).map((avatar) => avatar.pack()),
|
||||||
|
};
|
||||||
|
|
||||||
|
this.add(
|
||||||
|
CatalogItemAccessor.fromComponent(
|
||||||
|
'BlitzkitAllAvatarsEntity.blitzkit_all_avatars',
|
||||||
|
{
|
||||||
|
type_url:
|
||||||
|
'./blitzkit_static_all_avatars_component.BlitzkitAllAvatarsComponent',
|
||||||
|
value: BlitzkitAllAvatarsComponent.encode(allAvatars).finish(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export * from './abstract';
|
||||||
|
export * from './remote';
|
||||||
|
export * from './socket';
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
import { CatalogItem } from '@protos/blitz_items';
|
import { CatalogItem } from '@protos/blitz_items';
|
||||||
import { CatalogItemAccessor } from './catalogItemAccessor';
|
import { CatalogItemAccessor } from '../catalogItemAccessor';
|
||||||
import { MetadataAccessor } from './metadata';
|
import { MetadataAccessor } from './abstract';
|
||||||
|
|
||||||
export class RemoteMetadataAccessor extends MetadataAccessor {
|
export class RemoteMetadataAccessor extends MetadataAccessor {
|
||||||
constructor(private base: string) {
|
constructor(private base: string) {
|
||||||
+3
-2
@@ -1,7 +1,7 @@
|
|||||||
import { CatalogItem } from '@protos/blitz_items';
|
import { CatalogItem } from '@protos/blitz_items';
|
||||||
import { Metadata } from '@protos/blitz_metadata';
|
import { Metadata } from '@protos/blitz_metadata';
|
||||||
import { CatalogItemAccessor } from './catalogItemAccessor';
|
import { CatalogItemAccessor } from '../catalogItemAccessor';
|
||||||
import { MetadataAccessor } from './metadata';
|
import { MetadataAccessor } from './abstract';
|
||||||
|
|
||||||
export class SocketMetadataAccessor extends MetadataAccessor {
|
export class SocketMetadataAccessor extends MetadataAccessor {
|
||||||
items: Record<string, CatalogItem> = {};
|
items: Record<string, CatalogItem> = {};
|
||||||
@@ -16,6 +16,7 @@ export class SocketMetadataAccessor extends MetadataAccessor {
|
|||||||
|
|
||||||
async get(item: string) {
|
async get(item: string) {
|
||||||
if (item in this.items) return new CatalogItemAccessor(this.items[item]);
|
if (item in this.items) return new CatalogItemAccessor(this.items[item]);
|
||||||
|
|
||||||
throw new Error(`Item ${item} does not exist in socket metadata`);
|
throw new Error(`Item ${item} does not exist in socket metadata`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8,19 +8,22 @@
|
|||||||
"astro": "astro"
|
"astro": "astro"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@astrojs/react": "^4.3.0",
|
||||||
|
"@astrolib/seo": "^1.0.0-beta.8",
|
||||||
|
"@blitzkit/closed": "workspace:*",
|
||||||
|
"@blitzkit/core": "workspace:*",
|
||||||
"@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.0",
|
||||||
"@radix-ui/themes": "^3.1.4",
|
"@radix-ui/themes": "^3.1.4",
|
||||||
"@astrolib/seo": "^1.0.0-beta.8",
|
"@types/js-yaml": "^4.0.9",
|
||||||
"@blitzkit/core": "workspace:*",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@blitzkit/closed": "workspace:*",
|
|
||||||
"@astrojs/react": "^4.3.0",
|
|
||||||
"@types/react": "^19.1.5",
|
"@types/react": "^19.1.5",
|
||||||
"@types/react-dom": "^19.1.5",
|
"@types/react-dom": "^19.1.5",
|
||||||
"astro": "^5.8.0",
|
"astro": "^5.8.0",
|
||||||
|
"js-yaml": "^4.1.0",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
|
"minimatch": "^10.0.1",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0"
|
||||||
"@types/lodash-es": "^4.17.12",
|
|
||||||
"lodash-es": "^4.17.21"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,9 +25,9 @@ type Extension =
|
|||||||
status: 'error';
|
status: 'error';
|
||||||
};
|
};
|
||||||
|
|
||||||
export function Checks({ locale }: LocaleAcceptorProps) {
|
export function Checks({ localeData }: LocaleAcceptorProps) {
|
||||||
return (
|
return (
|
||||||
<LocaleProvider locale={locale}>
|
<LocaleProvider localeData={localeData}>
|
||||||
<App.Provider>
|
<App.Provider>
|
||||||
<Content />
|
<Content />
|
||||||
</App.Provider>
|
</App.Provider>
|
||||||
@@ -39,7 +39,7 @@ export function Checks({ locale }: LocaleAcceptorProps) {
|
|||||||
* Wargaming: 14 (refresh: 7)
|
* Wargaming: 14 (refresh: 7)
|
||||||
*/
|
*/
|
||||||
function Content() {
|
function Content() {
|
||||||
const { locale } = useLocale();
|
const localeData = 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();
|
||||||
@@ -128,11 +128,17 @@ 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{' '}
|
||||||
<LinkI18n locale={locale} href="/docs/legal/privacy-policy">
|
<LinkI18n
|
||||||
|
localeData={localeData}
|
||||||
|
href="/docs/legal/privacy-policy"
|
||||||
|
>
|
||||||
our privacy policy
|
our privacy policy
|
||||||
</LinkI18n>
|
</LinkI18n>
|
||||||
. By using BlitzKit, you also agree to our{' '}
|
. By using BlitzKit, you also agree to our{' '}
|
||||||
<LinkI18n locale={locale} href="/docs/legal/terms-of-service">
|
<LinkI18n
|
||||||
|
localeData={localeData}
|
||||||
|
href="/docs/legal/terms-of-service"
|
||||||
|
>
|
||||||
terms of service
|
terms of service
|
||||||
</LinkI18n>
|
</LinkI18n>
|
||||||
.
|
.
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
---
|
---
|
||||||
import { assertSecret, fetchGameDefinitions } from '@blitzkit/core';
|
import { assertSecret, fetchGameDefinitions } from '@blitzkit/core';
|
||||||
import locales from '@blitzkit/i18n/locales.json' with { type: 'json' };
|
|
||||||
import { Box, Code, Flex, Heading, Link, Text } from '@radix-ui/themes';
|
import { Box, Code, Flex, Heading, Link, Text } from '@radix-ui/themes';
|
||||||
import packageJson from '../../../../package.json';
|
import packageJson from '../../../../package.json';
|
||||||
import { getStrings } from '../core/i18n/getStrings';
|
import { getStrings } from '../core/i18n/getStrings';
|
||||||
import { LinkI18n } from './LinkI18n';
|
import { LinkI18n } from './LinkI18n';
|
||||||
import { LocaleSwitcherThemeWrapper } from './LocaleSwitcher';
|
import { LocaleSwitcherThemeWrapper } from './LocaleSwitcher';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
locale: string;
|
||||||
|
}
|
||||||
|
|
||||||
const gameDefinitions = await fetchGameDefinitions();
|
const gameDefinitions = await fetchGameDefinitions();
|
||||||
const PUBLIC_ASSET_BRANCH = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH);
|
const PUBLIC_ASSET_BRANCH = assertSecret(import.meta.env.PUBLIC_ASSET_BRANCH);
|
||||||
const locale = Astro.params.locale ?? locales.default;
|
const { locale } = Astro.props;
|
||||||
|
const localeData = { locale };
|
||||||
const strings = await getStrings(locale);
|
const strings = await getStrings(locale);
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -44,7 +48,7 @@ const strings = await getStrings(locale);
|
|||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Box mt="2">
|
<Box mt="2">
|
||||||
<LocaleSwitcherThemeWrapper {locale} client:load />
|
<LocaleSwitcherThemeWrapper {localeData} client:load />
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
@@ -79,7 +83,7 @@ const strings = await getStrings(locale);
|
|||||||
sm: 'start',
|
sm: 'start',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<LinkI18n {locale} href="/docs/about/credits" color="gray">
|
<LinkI18n {localeData} href="/docs/about/credits" color="gray">
|
||||||
{strings.website.footer.about.credits}
|
{strings.website.footer.about.credits}
|
||||||
</LinkI18n>
|
</LinkI18n>
|
||||||
<Link
|
<Link
|
||||||
@@ -96,7 +100,7 @@ const strings = await getStrings(locale);
|
|||||||
>
|
>
|
||||||
{strings.website.footer.about.github}
|
{strings.website.footer.about.github}
|
||||||
</Link>
|
</Link>
|
||||||
<LinkI18n {locale} href="/docs/patches" color="gray">
|
<LinkI18n {localeData} href="/docs/patches" color="gray">
|
||||||
{strings.website.footer.about.patches}
|
{strings.website.footer.about.patches}
|
||||||
</LinkI18n>
|
</LinkI18n>
|
||||||
</Flex>
|
</Flex>
|
||||||
@@ -116,10 +120,14 @@ const strings = await getStrings(locale);
|
|||||||
>
|
>
|
||||||
<Heading size="3">{strings.website.footer.legal.title}</Heading>
|
<Heading size="3">{strings.website.footer.legal.title}</Heading>
|
||||||
<Flex direction="column">
|
<Flex direction="column">
|
||||||
<LinkI18n {locale} href="/docs/legal/privacy-policy" color="gray">
|
<LinkI18n {localeData} href="/docs/legal/privacy-policy" color="gray">
|
||||||
{strings.website.footer.legal.privacy}
|
{strings.website.footer.legal.privacy}
|
||||||
</LinkI18n>
|
</LinkI18n>
|
||||||
<LinkI18n {locale} href="/docs/legal/terms-of-service" color="gray">
|
<LinkI18n
|
||||||
|
{localeData}
|
||||||
|
href="/docs/legal/terms-of-service"
|
||||||
|
color="gray"
|
||||||
|
>
|
||||||
{strings.website.footer.legal.terms}
|
{strings.website.footer.legal.terms}
|
||||||
</LinkI18n>
|
</LinkI18n>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ import { Link, type LinkProps } from '@radix-ui/themes';
|
|||||||
import type { LocaleAcceptorProps } from '../hooks/useLocale';
|
import type { LocaleAcceptorProps } from '../hooks/useLocale';
|
||||||
|
|
||||||
export function LinkI18n({
|
export function LinkI18n({
|
||||||
locale,
|
localeData,
|
||||||
href,
|
href,
|
||||||
...props
|
...props
|
||||||
}: LinkProps & LocaleAcceptorProps) {
|
}: LinkProps & LocaleAcceptorProps) {
|
||||||
const prefix = locale === locales.default ? '' : `/${locale}`;
|
const prefix =
|
||||||
|
localeData.locale === locales.default ? '' : `/${localeData.locale}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href={href?.startsWith('/') ? `${prefix}${href}` : href} {...props} />
|
<Link href={href?.startsWith('/') ? `${prefix}${href}` : href} {...props} />
|
||||||
|
|||||||
@@ -4,18 +4,20 @@ import { LOCALE_NAMES, SUPPORTED_LOCALE_FLAGS } from 'packages/i18n/src';
|
|||||||
import type { LocaleAcceptorProps } from '../hooks/useLocale';
|
import type { LocaleAcceptorProps } from '../hooks/useLocale';
|
||||||
import { BlitzKitTheme } from './BlitzKitTheme';
|
import { BlitzKitTheme } from './BlitzKitTheme';
|
||||||
|
|
||||||
export function LocaleSwitcherThemeWrapper({ locale }: LocaleAcceptorProps) {
|
export function LocaleSwitcherThemeWrapper({
|
||||||
|
localeData,
|
||||||
|
}: LocaleAcceptorProps) {
|
||||||
return (
|
return (
|
||||||
<BlitzKitTheme style={{ background: 'transparent' }}>
|
<BlitzKitTheme style={{ background: 'transparent' }}>
|
||||||
<LocaleSwitcher locale={locale} />
|
<LocaleSwitcher localeData={localeData} />
|
||||||
</BlitzKitTheme>
|
</BlitzKitTheme>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LocaleSwitcher({ locale }: LocaleAcceptorProps) {
|
export function LocaleSwitcher({ localeData }: LocaleAcceptorProps) {
|
||||||
return (
|
return (
|
||||||
<Select.Root
|
<Select.Root
|
||||||
defaultValue={locale}
|
defaultValue={localeData.locale}
|
||||||
onValueChange={(locale) => {
|
onValueChange={(locale) => {
|
||||||
localStorage.setItem('preferred-locale', locale);
|
localStorage.setItem('preferred-locale', locale);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
---
|
---
|
||||||
import { assertSecret } from '@blitzkit/core';
|
|
||||||
import {
|
import {
|
||||||
Cross1Icon,
|
Cross1Icon,
|
||||||
DiscordLogoIcon,
|
DiscordLogoIcon,
|
||||||
@@ -19,8 +18,9 @@ export interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { integrated, locale } = Astro.props;
|
const { integrated, locale } = Astro.props;
|
||||||
|
const localeData = { locale };
|
||||||
const toolsFiltered = tools.filter((tool) => tool.enabled);
|
const toolsFiltered = tools.filter((tool) => tool.enabled);
|
||||||
const branchName = resolveBranchName(locale);
|
const branchName = resolveBranchName();
|
||||||
const isBranchNamed = branchName !== undefined;
|
const isBranchNamed = branchName !== undefined;
|
||||||
const strings = await getStrings(locale);
|
const strings = await getStrings(locale);
|
||||||
---
|
---
|
||||||
@@ -107,7 +107,7 @@ const strings = await getStrings(locale);
|
|||||||
<Flex gap="4" direction="column" maxWidth="80rem" width="100%">
|
<Flex gap="4" direction="column" maxWidth="80rem" width="100%">
|
||||||
<Flex align="center">
|
<Flex align="center">
|
||||||
<LinkI18n
|
<LinkI18n
|
||||||
{locale}
|
{localeData}
|
||||||
color="gray"
|
color="gray"
|
||||||
highContrast
|
highContrast
|
||||||
href="/"
|
href="/"
|
||||||
@@ -146,7 +146,7 @@ const strings = await getStrings(locale);
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<LinkI18n
|
<LinkI18n
|
||||||
{locale}
|
{localeData}
|
||||||
weight={selected ? 'medium' : 'regular'}
|
weight={selected ? 'medium' : 'regular'}
|
||||||
color="gray"
|
color="gray"
|
||||||
highContrast={selected}
|
highContrast={selected}
|
||||||
@@ -175,7 +175,7 @@ const strings = await getStrings(locale);
|
|||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<LinkI18n
|
<LinkI18n
|
||||||
{locale}
|
{localeData}
|
||||||
style={{ display: 'flex', alignContent: 'center' }}
|
style={{ display: 'flex', alignContent: 'center' }}
|
||||||
color="gray"
|
color="gray"
|
||||||
href="/settings"
|
href="/settings"
|
||||||
@@ -184,8 +184,6 @@ const strings = await getStrings(locale);
|
|||||||
<GearIcon width="1em" height="1em" />
|
<GearIcon width="1em" height="1em" />
|
||||||
</LinkI18n>
|
</LinkI18n>
|
||||||
|
|
||||||
<!-- <NavbarAccount client:idle /> -->
|
|
||||||
|
|
||||||
<Flex align="center" display={{ initial: 'flex', sm: 'none' }}>
|
<Flex align="center" display={{ initial: 'flex', sm: 'none' }}>
|
||||||
<IconButton variant="ghost" color="gray" className="hamburger">
|
<IconButton variant="ghost" color="gray" className="hamburger">
|
||||||
<Cross1Icon data-expanded />
|
<Cross1Icon data-expanded />
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import {
|
|
||||||
LocaleProvider,
|
|
||||||
useLocale,
|
|
||||||
type LocaleAcceptorProps,
|
|
||||||
} from '../hooks/useLocale';
|
|
||||||
|
|
||||||
function Content() {
|
|
||||||
const { locale, strings } = useLocale();
|
|
||||||
const content = JSON.stringify(strings, null, 2);
|
|
||||||
|
|
||||||
return <span>{strings.common.units.deg_s}</span>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function TestComponent({ locale }: LocaleAcceptorProps) {
|
|
||||||
return (
|
|
||||||
<LocaleProvider locale={locale}>
|
|
||||||
<Content />
|
|
||||||
</LocaleProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,25 +1,39 @@
|
|||||||
import locales from '@blitzkit/i18n/locales.json' with { type: 'json' };
|
import locales from '@blitzkit/i18n/locales.json' with { type: 'json' };
|
||||||
import type { BlitzKitStrings } from 'packages/i18n/src';
|
import type { BlitzKitStrings } from 'packages/i18n/src';
|
||||||
import { createContext, use, useContext } from 'react';
|
import { createContext, use, useContext } from 'react';
|
||||||
const LocaleContext = createContext<string | null>(null);
|
|
||||||
|
const LocaleContext = createContext<{
|
||||||
|
locale: string;
|
||||||
|
gameStrings: Record<string, string>;
|
||||||
|
} | null>(null);
|
||||||
|
|
||||||
export interface LocaleAcceptorProps {
|
export interface LocaleAcceptorProps {
|
||||||
|
localeData: {
|
||||||
locale: string;
|
locale: string;
|
||||||
|
gameStrings?: Record<string, string>;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LocaleProviderProps extends LocaleAcceptorProps {
|
interface LocaleProviderProps extends LocaleAcceptorProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LocaleProvider({ locale, children }: LocaleProviderProps) {
|
export function LocaleProvider({ localeData, children }: LocaleProviderProps) {
|
||||||
const isSupported = locales.supported.some(
|
const isSupported = locales.supported.some(
|
||||||
(supported) => supported.locale === locale,
|
(supported) => supported.locale === localeData.locale,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isSupported) throw new Error(`Unsupported locale: ${locale}`);
|
if (!isSupported) throw new Error(`Unsupported locale: ${localeData.locale}`);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LocaleContext.Provider value={locale}>{children}</LocaleContext.Provider>
|
<LocaleContext.Provider
|
||||||
|
value={{
|
||||||
|
locale: localeData.locale,
|
||||||
|
gameStrings: localeData.gameStrings ?? {},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</LocaleContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,13 +55,13 @@ function loadLocale(locale: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useLocale() {
|
export function useLocale() {
|
||||||
const locale = useContext(LocaleContext);
|
const localeData = useContext(LocaleContext);
|
||||||
|
|
||||||
if (locale === null) {
|
if (localeData === null) {
|
||||||
throw new Error('useLocale must be used within a LocaleProvider');
|
throw new Error('useLocale must be used within a LocaleProvider');
|
||||||
}
|
}
|
||||||
|
|
||||||
const strings = use(loadLocale(locale));
|
const strings = use(loadLocale(localeData.locale));
|
||||||
|
|
||||||
return { locale, strings };
|
return { ...localeData, strings };
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,7 @@ export interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { noFooter, noNavbar, integrated, locale } = Astro.props;
|
const { noFooter, noNavbar, integrated, locale } = Astro.props;
|
||||||
|
const localeData = { locale };
|
||||||
---
|
---
|
||||||
|
|
||||||
<html lang={locale}>
|
<html lang={locale}>
|
||||||
@@ -69,11 +70,11 @@ const { noFooter, noNavbar, integrated, locale } = Astro.props;
|
|||||||
<Flex direction="column" minHeight="100vh">
|
<Flex direction="column" minHeight="100vh">
|
||||||
<Navbar {locale} {integrated} />
|
<Navbar {locale} {integrated} />
|
||||||
|
|
||||||
<Checks {locale} client:only="react" />
|
<Checks {localeData} client:only="react" />
|
||||||
|
|
||||||
<slot />
|
<slot />
|
||||||
|
|
||||||
{!noFooter && <Footer />}
|
{!noFooter && <Footer {locale} />}
|
||||||
</Flex>
|
</Flex>
|
||||||
</BlitzKitTheme>
|
</BlitzKitTheme>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { PageWrapper } from '../components/PageWrapper';
|
|||||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||||
|
|
||||||
const locale = locales.default;
|
const locale = locales.default;
|
||||||
|
const localeData = { locale };
|
||||||
---
|
---
|
||||||
|
|
||||||
<BaseLayout {locale}>
|
<BaseLayout {locale}>
|
||||||
@@ -15,7 +16,7 @@ const locale = locales.default;
|
|||||||
<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">
|
||||||
<LinkI18n {locale} href="/">
|
<LinkI18n {localeData} href="/">
|
||||||
<Button>
|
<Button>
|
||||||
<HomeIcon /> Home
|
<HomeIcon /> Home
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Flex, Text } from '@radix-ui/themes';
|
|||||||
import { CatalogItemAccessor } from 'packages/core/src/blitz/catalogItemAccessor';
|
import { CatalogItemAccessor } from 'packages/core/src/blitz/catalogItemAccessor';
|
||||||
import { metadata } from 'packages/website-ue/src/core/blitz/metadata';
|
import { metadata } from 'packages/website-ue/src/core/blitz/metadata';
|
||||||
import { Var } from 'packages/website-ue/src/core/radix/var';
|
import { Var } from 'packages/website-ue/src/core/radix/var';
|
||||||
|
import type { LocaleAcceptorProps } from 'packages/website-ue/src/hooks/useLocale';
|
||||||
|
|
||||||
const allAvatars = await metadata
|
const allAvatars = await metadata
|
||||||
.get('BlitzkitAllAvatarsEntity.blitzkit_all_avatars')
|
.get('BlitzkitAllAvatarsEntity.blitzkit_all_avatars')
|
||||||
@@ -14,7 +15,7 @@ const allAvatars = await metadata
|
|||||||
.avatars,
|
.avatars,
|
||||||
);
|
);
|
||||||
|
|
||||||
export function Page() {
|
export function Page({ localeData }: LocaleAcceptorProps) {
|
||||||
return (
|
return (
|
||||||
<Flex wrap="wrap" gapX="4" gapY="6" justify="center" p="9">
|
<Flex wrap="wrap" gapX="4" gapY="6" justify="center" p="9">
|
||||||
{allAvatars.map((avatar) => {
|
{allAvatars.map((avatar) => {
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
---
|
---
|
||||||
|
import { metadata } from 'packages/website-ue/src/core/blitz/metadata';
|
||||||
import BaseLayout from 'packages/website-ue/src/layouts/BaseLayout.astro';
|
import BaseLayout from 'packages/website-ue/src/layouts/BaseLayout.astro';
|
||||||
import { Page } from './_index';
|
import { Page } from './_index';
|
||||||
|
|
||||||
export { getStaticPaths } from '../index.astro';
|
export { getStaticPaths } from '../index.astro';
|
||||||
|
|
||||||
const { locale } = Astro.props;
|
const { locale } = Astro.props;
|
||||||
|
|
||||||
|
const gameStrings = await metadata.stringsPartial(locale, [
|
||||||
|
'ProfileAvatarEntity__*',
|
||||||
|
]);
|
||||||
---
|
---
|
||||||
|
|
||||||
<BaseLayout {locale}>
|
<BaseLayout {locale}>
|
||||||
<Page client:load />
|
<Page localeData={{ locale, gameStrings }} client:load />
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import { TankCatalogComponent } from '@protos/blitz_static_tank_component';
|
|
||||||
import { BlitzkitAllTanksComponent } from '@protos/blitzkit_static_all_tanks_component';
|
|
||||||
import { SocketCatalogAccessor } from 'packages/core/src';
|
|
||||||
import { remoteCatalog } from 'packages/website-ue/src/core/blitz/remoteCatalog';
|
|
||||||
|
|
||||||
const data = await remoteCatalog
|
|
||||||
.get('BlitzKitAllTanksEntity.blitzkit_all_tanks')
|
|
||||||
.then((components) =>
|
|
||||||
components.get(BlitzkitAllTanksComponent, 'blitzkitAllTanksComponent'),
|
|
||||||
);
|
|
||||||
|
|
||||||
export function Page() {
|
|
||||||
const tankCatalog = new SocketCatalogAccessor(data.tanks);
|
|
||||||
|
|
||||||
const content = tankCatalog
|
|
||||||
.get('TankEntity.A92_M60')
|
|
||||||
.get(TankCatalogComponent, 'tankCatalogComponent');
|
|
||||||
|
|
||||||
return <pre children={JSON.stringify(content, null, 2)} />;
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
---
|
|
||||||
import { Page } from './_index';
|
|
||||||
|
|
||||||
export { getStaticPaths } from '../index.astro';
|
|
||||||
|
|
||||||
const { locale } = Astro.props;
|
|
||||||
---
|
|
||||||
|
|
||||||
<Page client:load />
|
|
||||||
Reference in new issue
Block a user