feat: implement strings

This commit is contained in:
TrèsAbhi committed 2025-11-28 14:13:03 -06:00
1 parent ef154f99d5
commit 6a958da390
8 files changed
+136 -47

No files matched your search

+1
View File
@@ -187,6 +187,7 @@
"searchtanks", "searchtanks",
"SHAREDEXP", "SHAREDEXP",
"SKLLD", "SKLLD",
"sluggify",
"smoothstep", "smoothstep",
"Smri", "Smri",
"Specularity", "Specularity",
+1
View File
@@ -209,6 +209,7 @@
"typescript": "^5.9.3", "typescript": "^5.9.3",
"varuna": "workspace:*", "varuna": "workspace:*",
"vite": "^7.1.9", "vite": "^7.1.9",
"yaml": "^2.8.1",
}, },
}, },
}, },
+42 -41
View File
@@ -1,49 +1,50 @@
export * from './assertSecret'; export * from "./assertSecret";
export * from './asset'; export * from "./asset";
export * from './availableProvisions'; export * from "./availableProvisions";
export * from './averageDefinitions'; export * from "./averageDefinitions";
// export * from './camouflageDefinitions'; // export * from './camouflageDefinitions';
// export * from './checkConsumableProvisionInclusivity'; // export * from './checkConsumableProvisionInclusivity';
export * from './coefficient'; export * from "./coefficient";
export * from './consumableDefinitions'; export * from "./consumableDefinitions";
// export * from './context'; // export * from './context';
export * from './createDefaultSkills'; export * from "./createDefaultSkills";
export * from './degressiveStat'; export * from "./degressiveStat";
export * from './discoveredIdDefinitions'; export * from "./discoveredIdDefinitions";
export * from './emblemURL'; export * from "./emblemURL";
export * from './equipmentDefinitions'; export * from "./equipmentDefinitions";
export * from './eventManager'; export * from "./eventManager";
export * from './gameDefinitions'; export * from "./gameDefinitions";
export * from './getArchivedLatestSeasonNumber'; export * from "./getArchivedLatestSeasonNumber";
// export * from './getArchivedRatingInfo'; // export * from './getArchivedRatingInfo';
export * from './getArchivedRatingLeaderboard'; export * from "./getArchivedRatingLeaderboard";
// export * from './getArchivedRatingMidnightLeaderboard'; // export * from './getArchivedRatingMidnightLeaderboard';
export * from './getTimeDaysAgo'; export * from "./getTimeDaysAgo";
export * from './isExplosive'; export * from "./isExplosive";
export * from './mapDefinitions'; export * from "./mapDefinitions";
export * from './modelDefinitions'; export * from "./modelDefinitions";
export * from './normalizeBoundingBox'; export * from "./normalizeBoundingBox";
// export * from './parseBkni'; // export * from './parseBkni';
// export * from './patientFetch'; // export * from './patientFetch';
export * from './patientFetchJSON'; export * from "./patientFetchJSON";
export * from './progressiveStat'; export * from "./progressiveStat";
export * from './provisionDefinitions'; export * from "./provisionDefinitions";
export * from './resolveDpm'; export * from "./resolveDpm";
export * from './resolvePenetrationCoefficient'; export * from "./resolvePenetrationCoefficient";
export * from './reviews'; export * from "./reviews";
export * from './skillDefinitions'; export * from "./skillDefinitions";
export * from './sum'; export * from "./sum";
export * from './tankDefinitions'; export * from "./tankDefinitions";
export * from './tankIcon'; export * from "./tankIcon";
export * from './tankNames'; export * from "./tankNames";
export * from './unionBoundingBox'; export * from "./unionBoundingBox";
export * from './uniqueGuns'; export * from "./uniqueGuns";
export * from './unwrapBlitzkitResponse'; export * from "./unwrapBlitzkitResponse";
export * from './votes'; export * from "./votes";
// export * from './withCORSProxy'; // export * from './withCORSProxy';
export * from './createDefaultProvisions'; export * from "./createDefaultProvisions";
export * from './gallery'; export * from "./gallery";
export * from './metaSortTank'; export * from "./metaSortTank";
export * from './popularTanks'; export * from "./popularTanks";
export * from './romanize'; export * from "./romanize";
export * from './youtubers'; export * from "./sluggify.ts";
export * from "./youtubers";
+16
View File
@@ -0,0 +1,16 @@
import { deburr } from "lodash-es";
const nonAlphanumericRegex = /[^a-z0-9]/g;
const multipleDashesRegex = /--+/g;
const trailingDashRegex = /-$/g;
const leadingDashRegex = /^-/g;
export function sluggify(value: string) {
let slug = deburr(value).toLowerCase();
slug = slug.replaceAll(nonAlphanumericRegex, "-");
slug = slug.replaceAll(multipleDashesRegex, "-");
slug = slug.replaceAll(trailingDashRegex, "");
slug = slug.replaceAll(leadingDashRegex, "");
return slug;
}
+3 -2
View File
@@ -13,8 +13,8 @@
"@astrojs/node": "^9.4.4", "@astrojs/node": "^9.4.4",
"@astrojs/react": "^4.4.0", "@astrojs/react": "^4.4.0",
"@astrolib/seo": "^1.0.0-beta.8", "@astrolib/seo": "^1.0.0-beta.8",
"@blitzkit/core": "workspace:*",
"@blitzkit/closed": "workspace:*", "@blitzkit/closed": "workspace:*",
"@blitzkit/core": "workspace:*",
"@blitzkit/i18n": "workspace:*", "@blitzkit/i18n": "workspace:*",
"@radix-ui/colors": "^3.0.0", "@radix-ui/colors": "^3.0.0",
"@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-icons": "^1.3.2",
@@ -39,6 +39,7 @@
"three-stdlib": "^2.36.0", "three-stdlib": "^2.36.0",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"varuna": "workspace:*", "varuna": "workspace:*",
"vite": "^7.1.9" "vite": "^7.1.9",
"yaml": "^2.8.1"
} }
} }
@@ -2,4 +2,9 @@ import type { Tanks } from "../../protos/tanks";
export abstract class AbstractAPI { export abstract class AbstractAPI {
abstract tanks(): Promise<Tanks>; abstract tanks(): Promise<Tanks>;
abstract strings(
locale: string,
prefix?: string
): Promise<Record<string, string>>;
} }
+67 -3
View File
@@ -1,23 +1,87 @@
import type { MetadataAccessor } from "@blitzkit/closed"; import type { MetadataAccessor } from "@blitzkit/closed";
import { sluggify } from "@blitzkit/core";
import type { RemoteStorageComponent } from "@protos/blitz_static_remote_storage_component";
import { parse } from "yaml";
import type { TanksEntry } from "../../protos/tanks"; import type { TanksEntry } from "../../protos/tanks";
import { AbstractAPI } from "./abstract"; import { AbstractAPI } from "./abstract";
interface LocalizationConfig {
namespaces: string[];
}
export class ServerAPI extends AbstractAPI { export class ServerAPI extends AbstractAPI {
constructor(private metadata: MetadataAccessor) { constructor(private metadata: MetadataAccessor) {
super(); super();
}
console.log(Object.keys(metadata.groups).join("\n")); async strings(locale: string) {
const clientConfig = this.metadata.item("ClientConfigsEntity.prod");
const localizationResources = clientConfig.LocalizationResources();
if (!localizationResources.remote_storage) {
throw new Error("Localization resources not found");
}
let remoteStorage: RemoteStorageComponent | undefined = undefined;
for (const candidateId of localizationResources.remote_storage
.remote_urls) {
const item = this.metadata.item(candidateId);
const candidate = item.RemoteStorage();
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}/${remoteStorage.relative_path}/config.yaml`
)
.then((response) => response.text())
.then((text) => parse(text) as LocalizationConfig);
const strings: Record<string, string> = {};
for (const namespace of config.namespaces) {
Object.assign(
strings,
await fetch(
`${remoteStorage.url}/${remoteStorage.relative_path}/${namespace}/${locale}.yaml`
)
.then((response) => response.text())
.then((text) => {
const strings: Record<string, string> = {};
const parsed = parse(text) as Record<string, string>;
for (const key in parsed) {
strings[key] = parsed[key].replaceAll('\\"', '"');
}
return strings;
})
);
}
return strings;
} }
async tanks() { async tanks() {
const group = this.metadata.group("TankEntity"); const group = this.metadata.group("TankEntity");
const tanks: TanksEntry[] = []; const tanks: TanksEntry[] = [];
const strings = await this.strings("en");
for (const item of group) { for (const item of group) {
const tankCatalog = item.TankCatalog(); const tankCatalog = item.TankCatalog();
const name = strings[tankCatalog.name!.value];
const id = item.id; const id = item.name;
const slug = tankCatalog.name?.value; const slug = sluggify(name);
tanks.push({ id, slug }); tanks.push({ id, slug });
} }