feat: add settings menu
All checks were successful
Deploy to VPS (dist) / deploy (push) Successful in 1m40s
All checks were successful
Deploy to VPS (dist) / deploy (push) Successful in 1m40s
This commit is contained in:
97
plugins/i18nextTypesPlugin.ts
Normal file
97
plugins/i18nextTypesPlugin.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import { readFileSync, readdirSync, writeFileSync } from "node:fs";
|
||||
import { join, resolve } from "node:path";
|
||||
import { normalizePath } from "vite";
|
||||
import type { Plugin, ResolvedConfig } from "vite";
|
||||
|
||||
interface Options {
|
||||
sourceDir: string;
|
||||
destination: string;
|
||||
}
|
||||
|
||||
type JsonValue = string | number | boolean | null | JsonObject | JsonValue[];
|
||||
type JsonObject = { [key: string]: JsonValue };
|
||||
|
||||
function flattenKeys(obj: JsonObject, prefix: string, result: Map<string, Set<string>>): void {
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
const fullKey = prefix ? `${prefix}.${key}` : key;
|
||||
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
||||
flattenKeys(value as JsonObject, fullKey, result);
|
||||
} else if (typeof value === "string") {
|
||||
if (!result.has(fullKey)) {
|
||||
result.set(fullKey, new Set());
|
||||
}
|
||||
result.get(fullKey)!.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateTypes(sourceDir: string, destination: string): void {
|
||||
const files = readdirSync(sourceDir).filter((f) => f.endsWith(".json"));
|
||||
|
||||
const keyValues = new Map<string, Set<string>>();
|
||||
|
||||
for (const file of files) {
|
||||
const content = JSON.parse(readFileSync(join(sourceDir, file), "utf-8")) as JsonObject;
|
||||
|
||||
flattenKeys(content, "", keyValues);
|
||||
}
|
||||
|
||||
const sortedKeys = Array.from(keyValues.keys()).sort();
|
||||
|
||||
const lines: string[] = [
|
||||
"// Auto-generated by i18nextTypesPlugin — do not edit manually",
|
||||
"declare const resources: {",
|
||||
];
|
||||
|
||||
for (const key of sortedKeys) {
|
||||
const values = Array.from(keyValues.get(key)!);
|
||||
const union = values.map((v) => JSON.stringify(v)).join(" | ");
|
||||
lines.push(` ${JSON.stringify(key)}: ${union};`);
|
||||
}
|
||||
|
||||
lines.push("};");
|
||||
lines.push("export default resources;");
|
||||
lines.push("");
|
||||
|
||||
writeFileSync(destination, lines.join("\n"), "utf-8");
|
||||
}
|
||||
|
||||
export function i18nextTypesPlugin(options: Options): Plugin {
|
||||
let resolvedSourceDir: string;
|
||||
let resolvedDestination: string;
|
||||
|
||||
return {
|
||||
name: "i18next-types",
|
||||
|
||||
configResolved(config: ResolvedConfig) {
|
||||
resolvedSourceDir = normalizePath(resolve(config.root, options.sourceDir));
|
||||
resolvedDestination = normalizePath(resolve(config.root, options.destination));
|
||||
},
|
||||
|
||||
buildStart() {
|
||||
generateTypes(resolvedSourceDir, resolvedDestination);
|
||||
},
|
||||
|
||||
configureServer(server) {
|
||||
server.watcher.add(resolvedSourceDir);
|
||||
|
||||
server.watcher.on("change", (file: string) => {
|
||||
if (file.startsWith(resolvedSourceDir) && file.endsWith(".json")) {
|
||||
generateTypes(resolvedSourceDir, resolvedDestination);
|
||||
}
|
||||
});
|
||||
|
||||
server.watcher.on("add", (file: string) => {
|
||||
if (file.startsWith(resolvedSourceDir) && file.endsWith(".json")) {
|
||||
generateTypes(resolvedSourceDir, resolvedDestination);
|
||||
}
|
||||
});
|
||||
|
||||
server.watcher.on("unlink", (file: string) => {
|
||||
if (file.startsWith(resolvedSourceDir) && file.endsWith(".json")) {
|
||||
generateTypes(resolvedSourceDir, resolvedDestination);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user