refactor(stylesheet): move Semantic CSS to the browser (#3329)

This commit is contained in:
Amruth Pillai
2026-08-16 16:50:27 +02:00
committed by GitHub
parent f848e57436
commit 9509b5bc2e
203 changed files with 11838 additions and 14842 deletions
-3
View File
@@ -52,7 +52,6 @@
"@reactive-resume/db": "workspace:*", "@reactive-resume/db": "workspace:*",
"@reactive-resume/env": "workspace:*", "@reactive-resume/env": "workspace:*",
"@reactive-resume/mcp": "workspace:*", "@reactive-resume/mcp": "workspace:*",
"@reactive-resume/pdf": "workspace:*",
"@reactive-resume/schema": "workspace:*", "@reactive-resume/schema": "workspace:*",
"@reactive-resume/utils": "workspace:*", "@reactive-resume/utils": "workspace:*",
"@sindresorhus/slugify": "^3.0.0", "@sindresorhus/slugify": "^3.0.0",
@@ -61,7 +60,6 @@
"ai": "^7.0.58", "ai": "^7.0.58",
"bcrypt": "^6.0.0", "bcrypt": "^6.0.0",
"better-auth": "1.6.26", "better-auth": "1.6.26",
"canonicalize": "^3.0.0",
"cjk-regex": "^3.4.0", "cjk-regex": "^3.4.0",
"css-tree": "^3.2.1", "css-tree": "^3.2.1",
"deepmerge-ts": "^7.1.5", "deepmerge-ts": "^7.1.5",
@@ -74,7 +72,6 @@
"node-html-parser": "^9.0.1", "node-html-parser": "^9.0.1",
"nodemailer": "^9.0.5", "nodemailer": "^9.0.5",
"ollama-ai-provider-v2": "^4.0.1", "ollama-ai-provider-v2": "^4.0.1",
"pdfjs-dist": "^6.2.108",
"pg": "^8.23.0", "pg": "^8.23.0",
"phosphor-icons-react-pdf": "^0.1.3", "phosphor-icons-react-pdf": "^0.1.3",
"react": "^19.2.8", "react": "^19.2.8",
+4 -4
View File
@@ -131,10 +131,10 @@ describe("createApp", () => {
it("uses the transport address for public PDF fallback despite rotated forwarding headers", async () => { it("uses the transport address for public PDF fallback despite rotated forwarding headers", async () => {
const { createApp } = await import("./app"); const { createApp } = await import("./app");
const app = createApp(); const app = createApp();
const first = new Request("http://localhost:3001/api/resumes/jane/resume/pdf?reason=render-data-hash", { const first = new Request("http://localhost:3001/api/resumes/jane/resume/pdf", {
headers: { "x-forwarded-for": "198.51.100.1" }, headers: { "x-forwarded-for": "198.51.100.1" },
}); });
const rotated = new Request("http://localhost:3001/api/resumes/jane/resume/pdf?reason=render-data-hash", { const rotated = new Request("http://localhost:3001/api/resumes/jane/resume/pdf", {
headers: { "x-forwarded-for": "198.51.100.2" }, headers: { "x-forwarded-for": "198.51.100.2" },
}); });
const env = transportEnv("203.0.113.9"); const env = transportEnv("203.0.113.9");
@@ -159,8 +159,8 @@ describe("createApp", () => {
const unknownRpcRequest = new Request("http://localhost:3001/api/rpc", { const unknownRpcRequest = new Request("http://localhost:3001/api/rpc", {
headers: { "cf-connecting-ip": "198.51.100.2" }, headers: { "cf-connecting-ip": "198.51.100.2" },
}); });
const trustedOpenApiRequest = new Request("http://localhost:3001/api/openapi/resumes/jane/resume/style-projection"); const trustedOpenApiRequest = new Request("http://localhost:3001/api/openapi/resumes/jane/resume");
const unknownOpenApiRequest = new Request("http://localhost:3001/api/openapi/resumes/jane/resume/style-projection"); const unknownOpenApiRequest = new Request("http://localhost:3001/api/openapi/resumes/jane/resume");
await app.fetch(trustedRpcRequest, transportEnv("203.0.113.9")); await app.fetch(trustedRpcRequest, transportEnv("203.0.113.9"));
await app.fetch(unknownRpcRequest); await app.fetch(unknownRpcRequest);
+11 -41
View File
@@ -6,16 +6,6 @@ const mocks = vi.hoisted(() => ({
vi.mock("@reactive-resume/api/features/resume/public-pdf", () => ({ vi.mock("@reactive-resume/api/features/resume/public-pdf", () => ({
createPublicResumePdf: mocks.createPublicResumePdf, createPublicResumePdf: mocks.createPublicResumePdf,
PUBLIC_RESUME_PDF_MISMATCH_REASONS: [
"missing-projection",
"format-version",
"language-version",
"semantic-tree-version",
"registry-fingerprint",
"adapter-fingerprint",
"render-data-hash",
"invalid-projection",
],
})); }));
const { handlePublicResumePdf } = await import("./public-resume-pdf"); const { handlePublicResumePdf } = await import("./public-resume-pdf");
@@ -24,18 +14,15 @@ const trustedClient = "203.0.113.9";
describe("handlePublicResumePdf", () => { describe("handlePublicResumePdf", () => {
beforeEach(() => vi.clearAllMocks()); beforeEach(() => vi.clearAllMocks());
it("returns the authorized fallback PDF with strict mismatch metadata and cache policy", async () => { it("returns the authorized on-demand PDF without forwarding compatibility metadata", async () => {
const body = new File(["%PDF"], "Ada_Lovelace.pdf", { type: "text/plain" }); const body = new File(["%PDF"], "Ada_Lovelace.pdf", { type: "text/plain" });
mocks.createPublicResumePdf.mockResolvedValueOnce({ mocks.createPublicResumePdf.mockResolvedValueOnce({
body, body,
filename: "Ada_Lovelace.pdf", filename: "Ada_Lovelace.pdf",
}); });
const registry = "0".repeat(64); const request = new Request("https://example.com/api/resumes/jane/resume/pdf?ignored=true", {
const adapter = "1".repeat(64); headers: { "x-forwarded-for": "203.0.113.7" },
const request = new Request( });
`https://example.com/api/resumes/jane/resume/pdf?reason=render-data-hash&registryFingerprint=${registry}&adapterFingerprint=${adapter}`,
{ headers: { "x-forwarded-for": "203.0.113.7" } },
);
const response = await handlePublicResumePdf(request, "jane", "resume", trustedClient); const response = await handlePublicResumePdf(request, "jane", "resume", trustedClient);
@@ -50,13 +37,10 @@ describe("handlePublicResumePdf", () => {
slug: "resume", slug: "resume",
requestHeaders: request.headers, requestHeaders: request.headers,
trustedClient, trustedClient,
mismatchReason: "render-data-hash",
clientRegistryFingerprint: registry,
clientAdapterFingerprint: adapter,
}); });
}); });
it("defaults a missing mismatch reason and keeps password/private responses uncacheable", async () => { it("keeps password and private responses uncacheable", async () => {
mocks.createPublicResumePdf.mockResolvedValueOnce({ mocks.createPublicResumePdf.mockResolvedValueOnce({
body: new File(["%PDF"], "resume.pdf", { type: "application/pdf" }), body: new File(["%PDF"], "resume.pdf", { type: "application/pdf" }),
filename: "resume.pdf", filename: "resume.pdf",
@@ -66,13 +50,15 @@ describe("handlePublicResumePdf", () => {
const response = await handlePublicResumePdf(request, "jane", "resume", trustedClient); const response = await handlePublicResumePdf(request, "jane", "resume", trustedClient);
expect(response.headers.get("Cache-Control")).toBe("private, no-store"); expect(response.headers.get("Cache-Control")).toBe("private, no-store");
expect(mocks.createPublicResumePdf).toHaveBeenCalledWith( expect(mocks.createPublicResumePdf).toHaveBeenCalledWith({
expect.objectContaining({ mismatchReason: "missing-projection" }), username: "jane",
); slug: "resume",
requestHeaders: request.headers,
trustedClient,
});
}); });
it.each([ it.each([
[{ code: "BAD_REQUEST" }, 400],
[{ code: "NEED_PASSWORD" }, 401], [{ code: "NEED_PASSWORD" }, 401],
[{ code: "NOT_FOUND" }, 404], [{ code: "NOT_FOUND" }, 404],
[{ code: "RATE_LIMIT_EXCEEDED" }, 429], [{ code: "RATE_LIMIT_EXCEEDED" }, 429],
@@ -90,20 +76,4 @@ describe("handlePublicResumePdf", () => {
expect(response.status).toBe(status); expect(response.status).toBe(status);
expect(response.headers.get("Cache-Control")).toBe("private, no-store"); expect(response.headers.get("Cache-Control")).toBe("private, no-store");
}); });
it.each(["?reason=private-source", "?registryFingerprint=unsafe", "?adapterFingerprint=unsafe"])(
"rejects invalid fallback metadata before the API service",
async (search) => {
const response = await handlePublicResumePdf(
new Request(`https://example.com/api/resumes/jane/resume/pdf${search}`),
"jane",
"resume",
trustedClient,
);
expect(response.status).toBe(400);
expect(response.headers.get("Cache-Control")).toBe("private, no-store");
expect(mocks.createPublicResumePdf).not.toHaveBeenCalled();
},
);
}); });
+1 -30
View File
@@ -1,57 +1,28 @@
import type { PublicResumePdfMismatchReason } from "@reactive-resume/api/features/resume/public-pdf"; import { createPublicResumePdf } from "@reactive-resume/api/features/resume/public-pdf";
import {
createPublicResumePdf,
PUBLIC_RESUME_PDF_MISMATCH_REASONS,
} from "@reactive-resume/api/features/resume/public-pdf";
const noStoreResponse = (body: string, status: number) => const noStoreResponse = (body: string, status: number) =>
new Response(body, { status, headers: { "Cache-Control": "private, no-store" } }); new Response(body, { status, headers: { "Cache-Control": "private, no-store" } });
const errorStatus = (error: unknown): number => { const errorStatus = (error: unknown): number => {
const code = typeof error === "object" && error && "code" in error ? (error as { code?: unknown }).code : undefined; const code = typeof error === "object" && error && "code" in error ? (error as { code?: unknown }).code : undefined;
if (code === "BAD_REQUEST") return 400;
if (code === "NEED_PASSWORD") return 401; if (code === "NEED_PASSWORD") return 401;
if (code === "NOT_FOUND") return 404; if (code === "NOT_FOUND") return 404;
if (code === "RATE_LIMIT_EXCEEDED") return 429; if (code === "RATE_LIMIT_EXCEEDED") return 429;
return 500; return 500;
}; };
const fingerprint = (value: string | null): string | undefined => {
if (value === null) return;
return /^[a-f0-9]{64}$/.test(value) ? value : undefined;
};
export async function handlePublicResumePdf( export async function handlePublicResumePdf(
request: Request, request: Request,
username: string, username: string,
slug: string, slug: string,
trustedClient = "unknown", trustedClient = "unknown",
): Promise<Response> { ): Promise<Response> {
const searchParams = new URL(request.url).searchParams;
const rawReason = searchParams.get("reason") ?? "missing-projection";
if (!PUBLIC_RESUME_PDF_MISMATCH_REASONS.includes(rawReason as PublicResumePdfMismatchReason)) {
return noStoreResponse("Invalid fallback metadata", 400);
}
const rawRegistryFingerprint = searchParams.get("registryFingerprint");
const rawAdapterFingerprint = searchParams.get("adapterFingerprint");
const clientRegistryFingerprint = fingerprint(rawRegistryFingerprint);
const clientAdapterFingerprint = fingerprint(rawAdapterFingerprint);
if (
(rawRegistryFingerprint !== null && clientRegistryFingerprint === undefined) ||
(rawAdapterFingerprint !== null && clientAdapterFingerprint === undefined)
) {
return noStoreResponse("Invalid fallback metadata", 400);
}
try { try {
const result = await createPublicResumePdf({ const result = await createPublicResumePdf({
username, username,
slug, slug,
requestHeaders: request.headers, requestHeaders: request.headers,
trustedClient, trustedClient,
mismatchReason: rawReason as PublicResumePdfMismatchReason,
...(clientRegistryFingerprint ? { clientRegistryFingerprint } : {}),
...(clientAdapterFingerprint ? { clientAdapterFingerprint } : {}),
}); });
return new Response(result.body, { return new Response(result.body, {
-5
View File
@@ -2,7 +2,6 @@ import { pathToFileURL } from "node:url";
import { serve } from "@hono/node-server"; import { serve } from "@hono/node-server";
import { env } from "@reactive-resume/env/server"; import { env } from "@reactive-resume/env/server";
import { createApp } from "./http/app"; import { createApp } from "./http/app";
import { stylesheetPreflightRunner } from "./services/stylesheet-preflight";
import { runStartupChecks } from "./startup/checks"; import { runStartupChecks } from "./startup/checks";
export { createApp } from "./http/app"; export { createApp } from "./http/app";
@@ -32,10 +31,6 @@ async function main() {
console.info(`🚀 Up and running on http://localhost:${info.port}`); console.info(`🚀 Up and running on http://localhost:${info.port}`);
}, },
); );
// Load the heavy PDF preflight runtime once, now, so the first semantic-CSS edit
// does not pay (and time out on) the cold worker start.
stylesheetPreflightRunner.warmup();
} }
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
-2
View File
@@ -3,7 +3,6 @@ import { RPCHandler } from "@orpc/server/fetch";
import { BatchHandlerPlugin, RequestHeadersPlugin, StrictGetMethodPlugin } from "@orpc/server/plugins"; import { BatchHandlerPlugin, RequestHeadersPlugin, StrictGetMethodPlugin } from "@orpc/server/plugins";
import router from "@reactive-resume/api/routers"; import router from "@reactive-resume/api/routers";
import { mergeResponseHeaders } from "../http/headers"; import { mergeResponseHeaders } from "../http/headers";
import { stylesheetPreflightRunner } from "../services/stylesheet-preflight";
import { getRequestLocale } from "./locale"; import { getRequestLocale } from "./locale";
const rpcHandler = new RPCHandler(router, { const rpcHandler = new RPCHandler(router, {
@@ -24,7 +23,6 @@ export async function handleRpc(request: Request, trustedClient = "unknown") {
reqHeaders: request.headers, reqHeaders: request.headers,
resHeaders, resHeaders,
trustedClient, trustedClient,
stylesheetPreflightRunner,
}, },
}); });
@@ -1,332 +0,0 @@
import { afterEach, describe, expect, it } from "vitest";
import { defaultResumeData } from "@reactive-resume/schema/resume/default";
import { createStylesheetPreflightRunner, STYLESHEET_PREFLIGHT_LIMITS } from "./stylesheet-preflight";
const validStylesheet = {
languageVersion: 1,
text: "@version 1;",
} as const;
const input = {
data: defaultResumeData,
template: defaultResumeData.metadata.template,
stylesheet: validStylesheet,
} as const;
// Runners now own a long-lived, reused worker; destroy them so no worker thread
// outlives its test.
const runners: Array<{ destroy(): Promise<void> }> = [];
const track = <T extends { destroy(): Promise<void> }>(runner: T): T => {
runners.push(runner);
return runner;
};
afterEach(async () => {
await Promise.all(runners.splice(0).map((runner) => runner.destroy()));
});
const memoryExhaustionWorker = new URL(
`data:text/javascript,${encodeURIComponent(`
const retained = [];
while (true) {
const batch = Array.from({ length: 100_000 }, (_, index) => ({ batch: retained.length, index }));
retained.push(batch);
}
`)}`,
);
const failedWorker = new URL(
`data:text/javascript,${encodeURIComponent('throw new Error("sensitive worker details");')}`,
);
// Counts how many preflights this single worker instance served so a reuse test
// can prove the worker is not respawned per request.
const reuseCountingWorker = new URL(
`data:text/javascript,${encodeURIComponent(`
import { parentPort } from "node:worker_threads";
let served = 0;
parentPort.postMessage({ type: "ready" });
parentPort.on("message", (message) => {
if (message?.type !== "preflight") return;
served += 1;
parentPort.postMessage({
type: "result",
requestId: message.requestId,
result: { ok: true, pageCount: 1, byteCount: served, diagnostics: [] },
});
});
`)}`,
);
const delayedSuccessfulWorker = new URL(
`data:text/javascript,${encodeURIComponent(`
import { parentPort } from "node:worker_threads";
parentPort.postMessage({ type: "ready" });
parentPort.on("message", (message) => {
if (message?.type !== "preflight") return;
setTimeout(() => {
parentPort.postMessage({
type: "result",
requestId: message.requestId,
result: {
ok: true,
pageCount: 1,
byteCount: Number(message.input.data.basics.name),
diagnostics: [],
},
});
}, 300);
});
`)}`,
);
const delayedReadyWorker = new URL(
`data:text/javascript,${encodeURIComponent(`
import { parentPort } from "node:worker_threads";
parentPort.on("message", (message) => {
if (message?.type !== "preflight") return;
setTimeout(() => {
parentPort.postMessage({
type: "result",
requestId: message.requestId,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [] },
});
}, 10);
});
setTimeout(() => parentPort.postMessage({ type: "ready" }), 50);
`)}`,
);
const neverCompletesWorker = new URL(
`data:text/javascript,${encodeURIComponent(`
import { parentPort } from "node:worker_threads";
parentPort.postMessage({ type: "ready" });
setInterval(() => {}, 1_000);
`)}`,
);
const synchronousFailureWorker = new URL("https://example.com/stylesheet-preflight.mjs");
const numberedInput = (number: number) => ({
...input,
data: {
...input.data,
basics: {
...input.data.basics,
name: String(number),
},
},
});
const invalidInput = () => {
const data = structuredClone(defaultResumeData);
data.customSections = [
{
id: "custom-experience",
type: "experience",
title: "Experience",
icon: "",
columns: 1,
hidden: false,
keepTogether: false,
startOnNewPage: false,
items: [{ id: "summary-shaped-item", hidden: false, content: "<p>Missing company</p>" }],
} as never,
];
return { ...input, data };
};
describe("stylesheet PDF preflight worker", () => {
it("keeps the production resource policy fixed and immutable", () => {
expect(STYLESHEET_PREFLIGHT_LIMITS).toEqual({
timeoutMs: 30_000,
maxPages: 20,
maxBytes: 10_000_000,
maxPageWidthPt: 2_000,
maxPageHeightPt: 20_000,
maxPageAreaPt2: 20_000_000,
maxOldGenerationMb: 256,
maxConcurrentWorkers: 1,
maxQueuedRequests: 32,
});
expect(Object.isFrozen(STYLESHEET_PREFLIGHT_LIMITS)).toBe(true);
});
it("accepts a bounded candidate render in an isolated worker", async () => {
const runner = track(createStylesheetPreflightRunner({ timeoutMs: 15_000 }));
const result = await runner.run(input);
expect(result).toEqual(
expect.objectContaining({
ok: true,
pageCount: 1,
byteCount: expect.any(Number),
}),
);
if (!result.ok) throw new Error(`Expected successful preflight, received ${result.code}.`);
expect(result.byteCount).toBeGreaterThan(0);
expect(runner.activeWorkerCount).toBe(0);
}, 45_000);
it("reuses one warm worker across sequential requests instead of cold-starting each one", async () => {
const runner = track(createStylesheetPreflightRunner({}, reuseCountingWorker));
const first = await runner.run(input);
const second = await runner.run(input);
const third = await runner.run(input);
// A single reused worker increments its per-instance counter; a per-request
// worker would report byteCount 1 every time.
expect([first, second, third].map((result) => (result.ok ? result.byteCount : -1))).toEqual([1, 2, 3]);
expect(runner.activeWorkerCount).toBe(0);
expect(runner.queuedPreflightCount).toBe(0);
});
it("preserves structured resume-data failures across the worker boundary", async () => {
const runner = track(createStylesheetPreflightRunner({ timeoutMs: 15_000 }));
const result = runner.run(invalidInput());
await expect(result).rejects.toMatchObject({
name: "ZodError",
issues: expect.arrayContaining([expect.objectContaining({ path: ["customSections", 0, "items", 0, "company"] })]),
});
expect(runner.activeWorkerCount).toBe(0);
expect(runner.queuedPreflightCount).toBe(0);
}, 20_000);
it("terminates a worker when the render exceeds its deadline", async () => {
const runner = track(createStylesheetPreflightRunner({ timeoutMs: 1 }, neverCompletesWorker));
const result = await runner.run(input);
expect(result).toEqual(expect.objectContaining({ ok: false, code: "STYLESHEET_PREFLIGHT_TIMEOUT" }));
expect(runner.activeWorkerCount).toBe(0);
expect(runner.queuedPreflightCount).toBe(0);
});
it("starts the authored render deadline after the worker runtime is ready", async () => {
const runner = track(createStylesheetPreflightRunner({ timeoutMs: 20 }, delayedReadyWorker));
await expect(runner.run(input)).resolves.toEqual(expect.objectContaining({ ok: true, pageCount: 1 }));
expect(runner.activeWorkerCount).toBe(0);
});
it("returns deterministic output byte and page limit codes", async () => {
const byteRunner = track(createStylesheetPreflightRunner({ maxBytes: 16 }));
const pageRunner = track(createStylesheetPreflightRunner({ maxPages: 0 }));
await expect(byteRunner.run(input)).resolves.toEqual(
expect.objectContaining({ ok: false, code: "STYLESHEET_PREFLIGHT_BYTE_LIMIT" }),
);
await expect(pageRunner.run(input)).resolves.toEqual(
expect.objectContaining({ ok: false, code: "STYLESHEET_PREFLIGHT_PAGE_LIMIT" }),
);
expect(byteRunner.activeWorkerCount).toBe(0);
expect(pageRunner.activeWorkerCount).toBe(0);
}, 30_000);
it("maps worker heap exhaustion to a controlled memory-limit result", async () => {
const runner = track(
createStylesheetPreflightRunner({ maxOldGenerationMb: 8, timeoutMs: 10_000 }, memoryExhaustionWorker),
);
const result = await runner.run(input);
expect(result).toEqual(expect.objectContaining({ ok: false, code: "STYLESHEET_PREFLIGHT_MEMORY_LIMIT" }));
expect(runner.activeWorkerCount).toBe(0);
}, 15_000);
it("does not expose internal errors from a failed worker bootstrap", async () => {
const runner = track(createStylesheetPreflightRunner({}, failedWorker));
const result = await runner.run(input);
expect(result).toEqual({
ok: false,
code: "STYLESHEET_PREFLIGHT_WORKER_FAILED",
message: "The PDF preflight worker failed.",
diagnostics: [],
});
expect(runner.activeWorkerCount).toBe(0);
expect(runner.queuedPreflightCount).toBe(0);
});
it("surfaces sanitized render failures from inside the worker catch path", async () => {
const throwingWorker = new URL(
`data:text/javascript,${encodeURIComponent(`
import { parentPort } from "node:worker_threads";
parentPort.postMessage({ type: "ready" });
parentPort.on("message", (message) => {
if (message?.type !== "preflight") return;
parentPort.postMessage({
type: "result",
requestId: message.requestId,
result: {
ok: false,
code: "STYLESHEET_PREFLIGHT_WORKER_FAILED",
message: "The PDF preflight worker failed. (Error: Canvas is already closed)",
diagnostics: [],
},
});
});
`)}`,
);
const runner = track(createStylesheetPreflightRunner({ timeoutMs: 5_000 }, throwingWorker));
const result = await runner.run(input);
expect(result).toEqual({
ok: false,
code: "STYLESHEET_PREFLIGHT_WORKER_FAILED",
message: "The PDF preflight worker failed. (Error: Canvas is already closed)",
diagnostics: [],
});
});
it("bounds concurrent workers and queued requests without charging queue time to the worker deadline", async () => {
const runner = track(
createStylesheetPreflightRunner(
{
timeoutMs: 500,
maxConcurrentWorkers: 1,
maxQueuedRequests: 2,
},
delayedSuccessfulWorker,
),
);
const completionOrder: number[] = [];
const accepted = [1, 2, 3].map((number) =>
runner.run(numberedInput(number)).then((result) => {
if (result.ok) completionOrder.push(result.byteCount);
return result;
}),
);
const rejected = runner.run(numberedInput(4));
expect(runner.activeWorkerCount).toBe(1);
expect(runner.queuedPreflightCount).toBe(2);
await expect(rejected).resolves.toEqual(
expect.objectContaining({
code: "STYLESHEET_PREFLIGHT_WORKER_FAILED",
message: "The PDF preflight queue is full.",
}),
);
const results = await Promise.all(accepted);
expect(results.every((result) => result.ok)).toBe(true);
expect(completionOrder).toEqual([1, 2, 3]);
expect(runner.activeWorkerCount).toBe(0);
expect(runner.queuedPreflightCount).toBe(0);
}, 5_000);
it("does not leak a slot when the worker constructor throws synchronously", async () => {
const runner = track(createStylesheetPreflightRunner({}, synchronousFailureWorker));
await expect(runner.run(input)).resolves.toEqual(
expect.objectContaining({ ok: false, code: "STYLESHEET_PREFLIGHT_WORKER_FAILED" }),
);
expect(runner.activeWorkerCount).toBe(0);
expect(runner.queuedPreflightCount).toBe(0);
});
});
@@ -1,362 +0,0 @@
import type {
PdfPreflightFailure,
PdfPreflightResult,
StylesheetPreflightInput,
StylesheetPreflightRunner,
} from "@reactive-resume/pdf/server";
import { fileURLToPath } from "node:url";
import { Worker } from "node:worker_threads";
import { STYLESHEET_PREFLIGHT_LIMITS } from "@reactive-resume/pdf/preflight-reference";
export { STYLESHEET_PREFLIGHT_LIMITS } from "@reactive-resume/pdf/preflight-reference";
type StylesheetPreflightLimits = {
timeoutMs: number;
maxPages: number;
maxBytes: number;
maxPageWidthPt: number;
maxPageHeightPt: number;
maxPageAreaPt2: number;
maxOldGenerationMb: number;
maxConcurrentWorkers: number;
maxQueuedRequests: number;
};
const SOURCE_WORKER_LOADER_HEAP_MB = 256;
// The worker is warmed once and reused, so the one-time cold load (which is
// super-linear in available CPU — measured ~9s at 0.5 vCPU, ~53s at 0.35, ~93s at
// 0.25) is paid at startup, not per request. This ceiling must exceed that cold
// load or warmup is killed mid-bootstrap and never completes on a throttled box;
// it only bounds a genuinely stuck bootstrap and is off the per-edit path.
const WORKER_READINESS_TIMEOUT_MS = 120_000;
type SerializedPreflightCause = {
name: string;
message: string;
issues: readonly unknown[];
};
type StylesheetPreflightWorkerMessage =
| { type: "ready" }
| { type: "load_error"; message: string }
| { type: "result"; requestId: number; result: PdfPreflightResult }
| { type: "preflight_error"; requestId: number; cause: SerializedPreflightCause };
export type NodeStylesheetPreflightRunner = StylesheetPreflightRunner & {
readonly activeWorkerCount: number;
readonly queuedPreflightCount: number;
warmup(): void;
destroy(): Promise<void>;
};
const failure = (code: PdfPreflightFailure["code"], message: string): PdfPreflightFailure => ({
ok: false,
code,
message,
diagnostics: [],
});
const workerFailure = (error: Error): PdfPreflightFailure => {
const code = (error as NodeJS.ErrnoException).code;
return code === "ERR_WORKER_OUT_OF_MEMORY" || /heap out of memory/i.test(error.message)
? failure("STYLESHEET_PREFLIGHT_MEMORY_LIMIT", "The PDF preflight worker exceeded its memory limit.")
: failure("STYLESHEET_PREFLIGHT_WORKER_FAILED", "The PDF preflight worker failed.");
};
const sourceWorkerExecArgv = () => {
const importIndex = process.execArgv.findIndex(
(argument, index, arguments_) =>
(argument === "--import" && arguments_[index + 1]?.includes("tsx")) ||
(argument.startsWith("--import=") && argument.includes("tsx")),
);
const inherited = process.execArgv[importIndex];
if (inherited?.startsWith("--import=")) return [inherited];
if (inherited === "--import") return [inherited, process.execArgv[importIndex + 1] as string];
return ["--import", import.meta.resolve("tsx")];
};
const workerLocation = () => {
const source = import.meta.url.endsWith(".ts");
return {
source,
url: source
? new URL("../workers/stylesheet-preflight.ts", import.meta.url)
: new URL("./stylesheet-preflight-worker.mjs", import.meta.url),
// Production must not inherit parent execArgv (e.g. --import/--input-type); source workers need tsx.
execArgv: source ? sourceWorkerExecArgv() : [],
...(source
? {
env: {
...process.env,
TSX_TSCONFIG_PATH: fileURLToPath(new URL("../../tsconfig.json", import.meta.url)),
},
}
: {}),
};
};
type PendingRequest = {
resolve: (result: PdfPreflightResult) => void;
reject: (cause: unknown) => void;
renderTimer?: ReturnType<typeof setTimeout>;
};
type Readiness = {
promise: Promise<Worker>;
resolve: (worker: Worker) => void;
reject: (error: Error) => void;
timer: ReturnType<typeof setTimeout>;
};
export function createStylesheetPreflightRunner(
overrides: Partial<StylesheetPreflightLimits> = {},
testWorkerUrl?: URL,
): NodeStylesheetPreflightRunner {
const limits = Object.freeze({ ...STYLESHEET_PREFLIGHT_LIMITS, ...overrides });
let worker: Worker | undefined;
let ready = false;
let readiness: Readiness | undefined;
let destroyed = false;
let requestSeq = 0;
const pending = new Map<number, PendingRequest>();
// ponytail: process-local, bounded admission; upgrade to a pooled/distributed queue only for multi-process coordination.
const queue: Array<{
input: StylesheetPreflightInput;
resolve: PendingRequest["resolve"];
reject: PendingRequest["reject"];
}> = [];
const teardownWorker = () => {
const dead = worker;
worker = undefined;
ready = false;
if (readiness) {
clearTimeout(readiness.timer);
readiness.reject(new Error("Stylesheet preflight worker did not become ready."));
readiness = undefined;
}
if (!dead) return;
dead.off("message", onMessage);
dead.off("error", onError);
dead.off("exit", onExit);
void dead.terminate().catch(() => undefined);
};
const clearPending = (requestId: number): PendingRequest | undefined => {
const entry = pending.get(requestId);
if (!entry) return undefined;
if (entry.renderTimer) clearTimeout(entry.renderTimer);
pending.delete(requestId);
return entry;
};
const drainQueue = () => {
while (!destroyed && pending.size < limits.maxConcurrentWorkers && queue.length > 0) {
const next = queue.shift();
if (!next) return;
dispatch(next.input, next.resolve, next.reject);
}
};
const resolveRequest = (requestId: number, result: PdfPreflightResult) => {
const entry = clearPending(requestId);
if (!entry) return;
entry.resolve(result);
drainQueue();
};
const rejectRequest = (requestId: number, cause: unknown) => {
const entry = clearPending(requestId);
if (!entry) return;
entry.reject(cause);
drainQueue();
};
// A crashed/exited/timed-out worker is torn down and its in-flight requests are
// failed; the next dispatch (including any queued requests) spawns a fresh one,
// so a poisoned render never lingers across requests.
const failWorker = (result: PdfPreflightFailure) => {
teardownWorker();
const stale = [...pending.keys()];
for (const requestId of stale) resolveRequest(requestId, result);
drainQueue();
};
function onMessage(message: StylesheetPreflightWorkerMessage) {
if (message.type === "ready") {
if (readiness) {
clearTimeout(readiness.timer);
ready = true;
const resolveReady = readiness.resolve;
const readyWorker = worker;
readiness = undefined;
if (readyWorker) resolveReady(readyWorker);
}
return;
}
if (message.type === "load_error") {
failWorker(failure("STYLESHEET_PREFLIGHT_WORKER_FAILED", message.message));
return;
}
if (message.type === "result") {
resolveRequest(message.requestId, message.result);
return;
}
if (message.type === "preflight_error") {
rejectRequest(
message.requestId,
Object.assign(new Error(message.cause.message), { name: message.cause.name, issues: message.cause.issues }),
);
}
}
function onError(error: Error) {
console.warn("[stylesheet-preflight] worker error:", error.message);
failWorker(workerFailure(error));
}
function onExit(code: number) {
if (destroyed || (!worker && pending.size === 0)) return;
console.warn(`[stylesheet-preflight] worker exited unexpectedly (code ${code})`);
failWorker(failure("STYLESHEET_PREFLIGHT_WORKER_FAILED", "The PDF preflight worker failed."));
}
const startWorker = (): Promise<Worker> => {
const location = testWorkerUrl ? { source: false, url: testWorkerUrl, execArgv: [] as string[] } : workerLocation();
let spawned: Worker;
try {
spawned = new Worker(location.url, {
name: "stylesheet-preflight",
resourceLimits: {
// The source-only tsx compiler heap is outside the production render budget.
maxOldGenerationSizeMb: limits.maxOldGenerationMb + (location.source ? SOURCE_WORKER_LOADER_HEAP_MB : 0),
},
execArgv: location.execArgv,
...("env" in location ? { env: location.env } : {}),
});
} catch (error) {
return Promise.reject(error instanceof Error ? error : new Error("Failed to start PDF preflight worker."));
}
worker = spawned;
ready = false;
// The idle reused worker must not keep the process (or a test run) alive; active
// requests stay alive through their ref'd readiness/render timers.
spawned.unref();
spawned.on("message", onMessage);
spawned.once("error", onError);
spawned.once("exit", onExit);
let resolve!: (value: Worker) => void;
let reject!: (error: Error) => void;
const promise = new Promise<Worker>((resolvePromise, rejectPromise) => {
resolve = resolvePromise;
reject = rejectPromise;
});
const timer = setTimeout(() => {
console.warn(`[stylesheet-preflight] worker did not become ready within ${WORKER_READINESS_TIMEOUT_MS}ms`);
teardownWorker();
}, WORKER_READINESS_TIMEOUT_MS);
readiness = { promise, resolve, reject, timer };
return promise;
};
const getReadyWorker = (): Promise<Worker> => {
if (destroyed) return Promise.reject(new Error("Stylesheet preflight worker was terminated."));
if (worker && ready) return Promise.resolve(worker);
if (readiness) return readiness.promise;
return startWorker();
};
// One retry: a worker that failed to become ready is torn down; a second
// attempt spawns a fresh worker before the request gives up.
const waitUntilReady = async (): Promise<Worker> => {
try {
return await getReadyWorker();
} catch {
return await getReadyWorker();
}
};
function dispatch(
input: StylesheetPreflightInput,
resolve: PendingRequest["resolve"],
reject: PendingRequest["reject"],
) {
const requestId = ++requestSeq;
pending.set(requestId, { resolve, reject });
void waitUntilReady()
.then((readyWorker) => {
const entry = pending.get(requestId);
if (!entry) return;
entry.renderTimer = setTimeout(() => {
// A stuck render poisons the reused worker: tear it down and respawn — but
// only the worker this request actually ran on, so a stale timer can never
// kill a newer worker already serving other requests.
clearPending(requestId);
if (worker === readyWorker) teardownWorker();
resolve(failure("STYLESHEET_PREFLIGHT_TIMEOUT", "The PDF preflight exceeded its deadline."));
drainQueue();
}, limits.timeoutMs);
readyWorker.postMessage({ type: "preflight", requestId, input, limits });
})
.catch((error: unknown) => {
resolveRequest(
requestId,
workerFailure(error instanceof Error ? error : new Error("Failed to start PDF preflight worker.")),
);
});
}
return {
get activeWorkerCount() {
return pending.size;
},
get queuedPreflightCount() {
return queue.length;
},
warmup() {
void waitUntilReady().catch(() => undefined);
},
run(input: StylesheetPreflightInput): Promise<PdfPreflightResult> {
return new Promise<PdfPreflightResult>((resolve, reject) => {
if (destroyed) {
resolve(failure("STYLESHEET_PREFLIGHT_WORKER_FAILED", "The PDF preflight worker was terminated."));
return;
}
if (pending.size < limits.maxConcurrentWorkers) {
dispatch(input, resolve, reject);
return;
}
if (queue.length >= limits.maxQueuedRequests) {
resolve(failure("STYLESHEET_PREFLIGHT_WORKER_FAILED", "The PDF preflight queue is full."));
return;
}
queue.push({ input, resolve, reject });
});
},
async destroy() {
destroyed = true;
const dead = worker;
teardownWorker();
await dead?.terminate().catch(() => undefined);
for (const requestId of [...pending.keys()]) {
resolveRequest(
requestId,
failure("STYLESHEET_PREFLIGHT_WORKER_FAILED", "The PDF preflight worker was terminated."),
);
}
while (queue.length > 0) {
const next = queue.shift();
next?.resolve(failure("STYLESHEET_PREFLIGHT_WORKER_FAILED", "The PDF preflight worker was terminated."));
}
},
};
}
export const stylesheetPreflightRunner = createStylesheetPreflightRunner();
@@ -1,78 +0,0 @@
import type {
PdfPreflightPageLimits,
PdfPreflightResult,
RenderPreflightPdfResult,
} from "@reactive-resume/pdf/preflight";
import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
type StylesheetPreflightInspectionLimits = PdfPreflightPageLimits & {
maxPages: number;
maxBytes: number;
};
type PdfLoadingTask = {
promise: PromiseLike<{ numPages: number }>;
destroy(): Promise<void>;
};
type LoadPdf = (options: { data: Uint8Array }) => PdfLoadingTask;
export async function inspectPreflightPdf(
rendered: Extract<RenderPreflightPdfResult, { ok: true }>,
limits: StylesheetPreflightInspectionLimits,
loadPdf: LoadPdf = getDocument,
): Promise<PdfPreflightResult> {
if (rendered.bytes.byteLength > limits.maxBytes) {
return {
ok: false,
code: "STYLESHEET_PREFLIGHT_BYTE_LIMIT",
message: "The rendered PDF exceeds the preflight byte limit.",
diagnostics: rendered.diagnostics,
};
}
const byteCount = rendered.bytes.byteLength;
let loadingTask: PdfLoadingTask;
try {
loadingTask = loadPdf({ data: rendered.bytes });
} catch {
return {
ok: false,
code: "STYLESHEET_PREFLIGHT_PARSE_FAILED",
message: "PDF inspection failed.",
diagnostics: rendered.diagnostics,
};
}
try {
let document: { numPages: number };
try {
document = await loadingTask.promise;
} catch {
return {
ok: false,
code: "STYLESHEET_PREFLIGHT_PARSE_FAILED",
message: "PDF inspection failed.",
diagnostics: rendered.diagnostics,
};
}
if (document.numPages > limits.maxPages) {
return {
ok: false,
code: "STYLESHEET_PREFLIGHT_PAGE_LIMIT",
message: "The rendered PDF exceeds the preflight page limit.",
diagnostics: rendered.diagnostics,
};
}
return {
ok: true,
pageCount: document.numPages,
byteCount,
diagnostics: rendered.diagnostics,
};
} finally {
await loadingTask.destroy().catch(() => undefined);
}
}
@@ -1,58 +0,0 @@
import { describe, expect, it, vi } from "vitest";
import { inspectPreflightPdf } from "./stylesheet-preflight-inspection";
const warning = {
code: "EXTREME_VALUE",
severity: "warning",
message: "The authored value is unusually large.",
range: {
start: { line: 1, column: 1, offset: 0 },
end: { line: 1, column: 10, offset: 9 },
},
} as const;
const rendered = {
ok: true as const,
bytes: new TextEncoder().encode("%PDF-1.7"),
diagnostics: [warning],
};
const limits = {
maxPages: 20,
maxBytes: 10_000_000,
maxPageWidthPt: 2_000,
maxPageHeightPt: 20_000,
maxPageAreaPt2: 20_000_000,
};
describe("stylesheet preflight PDF inspection", () => {
it("preserves compiler warnings and hides parser exceptions", async () => {
const destroy = vi.fn(async () => undefined);
const result = await inspectPreflightPdf(rendered, limits, () => ({
promise: Promise.reject(new Error("sensitive parser details")),
destroy,
}));
expect(result).toEqual({
ok: false,
code: "STYLESHEET_PREFLIGHT_PARSE_FAILED",
message: "PDF inspection failed.",
diagnostics: [warning],
});
expect(destroy).toHaveBeenCalledOnce();
});
it("preserves compiler warnings when PDF.js fails before returning a loading task", async () => {
const result = await inspectPreflightPdf(rendered, limits, () => {
throw new Error("sensitive parser setup details");
});
expect(result).toEqual({
ok: false,
code: "STYLESHEET_PREFLIGHT_PARSE_FAILED",
message: "PDF inspection failed.",
diagnostics: [warning],
});
});
});
@@ -1,90 +0,0 @@
import type {
PdfPreflightPageLimits,
PdfPreflightResult,
StylesheetPreflightInput,
} from "@reactive-resume/pdf/preflight";
import { parentPort } from "node:worker_threads";
import * as React from "react";
import { inspectPreflightPdf } from "./stylesheet-preflight-inspection";
(globalThis as typeof globalThis & { React: typeof React }).React = React;
type StylesheetPreflightWorkerLimits = PdfPreflightPageLimits & {
maxPages: number;
maxBytes: number;
};
// The worker is long-lived and reused across requests: the heavy PDF runtime is
// loaded once at startup and each preflight arrives as a message (input can no
// longer come from `workerData`, which is fixed at construction time).
type StylesheetPreflightWorkerRequest = {
type: "preflight";
requestId: number;
input: StylesheetPreflightInput;
limits: StylesheetPreflightWorkerLimits;
};
type SerializedPreflightCause = {
name: string;
message: string;
issues: readonly unknown[];
};
const sanitizeWorkerCause = (cause: unknown): string => {
if (!(cause instanceof Error)) return "The PDF preflight worker failed.";
const detail = cause.message.replace(/\s+/g, " ").trim().slice(0, 200);
if (!detail) return "The PDF preflight worker failed.";
return `The PDF preflight worker failed. (${cause.name}: ${detail})`;
};
const serializeZodCause = (cause: unknown): SerializedPreflightCause | undefined => {
if (!(cause instanceof Error) || cause.name !== "ZodError" || !("issues" in cause) || !Array.isArray(cause.issues)) {
return;
}
return { name: cause.name, message: cause.message, issues: cause.issues };
};
// Load the heavy PDF runtime once. A rejection here (missing/broken dependency in
// a pruned production install) is reported explicitly instead of becoming an
// unhandled rejection that silently kills the worker and surfaces as an opaque
// runner-side failure.
const initialization = import("@reactive-resume/pdf/preflight");
void initialization.then(
() => parentPort?.postMessage({ type: "ready" }),
(cause: unknown) => {
console.error("[stylesheet-preflight] worker runtime failed to load", cause);
parentPort?.postMessage({ type: "load_error", message: sanitizeWorkerCause(cause) });
},
);
const handle = async (request: StylesheetPreflightWorkerRequest): Promise<void> => {
try {
const { renderPreflightPdf } = await initialization;
const rendered = await renderPreflightPdf(request.input, request.limits);
const result: PdfPreflightResult = rendered.ok ? await inspectPreflightPdf(rendered, request.limits) : rendered;
parentPort?.postMessage({ type: "result", requestId: request.requestId, result });
} catch (cause) {
const serializedCause = serializeZodCause(cause);
if (serializedCause) {
parentPort?.postMessage({ type: "preflight_error", requestId: request.requestId, cause: serializedCause });
return;
}
console.error("[stylesheet-preflight]", cause);
parentPort?.postMessage({
type: "result",
requestId: request.requestId,
result: {
ok: false,
code: "STYLESHEET_PREFLIGHT_WORKER_FAILED",
message: sanitizeWorkerCause(cause),
diagnostics: [],
},
});
}
};
parentPort?.on("message", (message: StylesheetPreflightWorkerRequest) => {
if (message.type !== "preflight") return;
void handle(message);
});
+1 -4
View File
@@ -33,10 +33,7 @@ const promptAssetsPlugin: TsdownPlugin = {
}; };
export default defineConfig({ export default defineConfig({
entry: { entry: { index: "src/index.ts" },
index: "src/index.ts",
"stylesheet-preflight-worker": "src/workers/stylesheet-preflight.ts",
},
format: "esm", format: "esm",
platform: "node", platform: "node",
target: "node24", target: "node24",
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Aansoeke per week gestuur (laaste 8 weke)" msgstr "Aansoeke per week gestuur (laaste 8 weke)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Aansoek gedoen" msgstr "Aansoek gedoen"
@@ -534,10 +533,6 @@ msgstr "Aansoek gedoen"
msgid "Applied on" msgid "Applied on"
msgstr "Toegepas op" msgstr "Toegepas op"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Toegepas met waarskuwings"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabies" msgstr "Arabies"
@@ -1765,7 +1760,6 @@ msgstr "Voer jou wagwoord in om die opstel van twee-faktor-magtiging te bevestig
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Voer jou wagwoord in om twee-faktor-magtiging te deaktiveer. Jou rekening sal minder veilig wees sonder 2FA." msgstr "Voer jou wagwoord in om twee-faktor-magtiging te deaktiveer. Jou rekening sal minder veilig wees sonder 2FA."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Fout" msgstr "Fout"
@@ -2003,6 +1997,10 @@ msgstr "Misluk om jou rugsteunkodeverifikasie te voltooi. Probeer asseblief weer
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Misluk om jou kode te verifieer. Probeer asseblief weer." msgstr "Misluk om jou kode te verifieer. Probeer asseblief weer."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funksies" msgstr "Funksies"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Voorskou" msgstr "Voorskou"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Voorskou en uitvoer gebruik die laaste geldige weergawe." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Lees…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Gereed om te aktiveer" msgstr "Gereed om te aktiveer"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Gereed om te aktiveer met waarskuwings" msgstr "Gereed om te aktiveer met waarskuwings"
@@ -3663,10 +3669,6 @@ msgstr "Herstel"
msgid "Reset Password" msgid "Reset Password"
msgstr "Herstel wagwoord" msgstr "Herstel wagwoord"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Stel terug na toegepaste stylblad"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Herstel jou wagwoord" msgstr "Herstel jou wagwoord"
@@ -4195,6 +4197,10 @@ msgstr "Sommige aansoekstelsels vereis een voordat jy kan indien."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Sommige ontleders hanteer beelde verkeerd, en foto's word in sommige streke ontmoedig." msgstr "Sommige ontleders hanteer beelde verkeerd, en foto's word in sommige streke ontmoedig."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Iets het verkeerd geloop" msgstr "Iets het verkeerd geloop"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Stylbladredigeerder" msgstr "Stylbladredigeerder"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Stylblad bevat foute" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Gebruikers"
msgid "Uzbek" msgid "Uzbek"
msgstr "Oezbeeks" msgstr "Oezbeeks"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Geldige URL's moet met http:// of https:// begin." msgstr "Geldige URL's moet met http:// of https:// begin."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel KI-toegangspoort" msgstr "Vercel KI-toegangspoort"
@@ -5411,4 +5429,3 @@ msgstr "Zoem uit"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zoeloe" msgstr "Zoeloe"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "በሳምንት የተላኩ ማመልከቻዎች (ያለፉት 8 ሳምንታት)" msgstr "በሳምንት የተላኩ ማመልከቻዎች (ያለፉት 8 ሳምንታት)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "ተመልክቷል" msgstr "ተመልክቷል"
@@ -534,10 +533,6 @@ msgstr "ተመልክቷል"
msgid "Applied on" msgid "Applied on"
msgstr "የተተገበረው በ" msgstr "የተተገበረው በ"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "ከማስጠንቀቂያዎች ጋር ተተግብሯል"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "ዓረብኛ" msgstr "ዓረብኛ"
@@ -1765,7 +1760,6 @@ msgstr "ሁለት-ደረጃ ማረጋገጫን ስትቆጣጠሩ የሚሆን
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "ሁለት-ደረጃ ማረጋገጫን ለማቦዘን የይለፍ ቃልዎን ያስገቡ። 2FA ባቦዘነ ጊዜ መለያዎ ያነሰ ደህንነት ይኖረዋል።" msgstr "ሁለት-ደረጃ ማረጋገጫን ለማቦዘን የይለፍ ቃልዎን ያስገቡ። 2FA ባቦዘነ ጊዜ መለያዎ ያነሰ ደህንነት ይኖረዋል።"
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "ስህተት" msgstr "ስህተት"
@@ -2003,6 +1997,10 @@ msgstr "የመጠባበቂያ ኮድዎን ማረጋገጥ አልተሳካም።
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "ኮድዎን ማረጋገጥ አልተሳካም። እባክዎ እንደገና ይሞክሩ።" msgstr "ኮድዎን ማረጋገጥ አልተሳካም። እባክዎ እንደገና ይሞክሩ።"
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "መለያዎች" msgstr "መለያዎች"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "ቅድመ እይታ" msgstr "ቅድመ እይታ"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "ቅድመ እይታ እና ወደ ውጭ መላክ የመጨረሻውን ትክክለኛ ስሪት ይጠቀሙ።" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "ንባብ…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "ለማግበር ዝግጁ" msgstr "ለማግበር ዝግጁ"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "ከማስጠንቀቂያዎች ጋር ለማግበር ዝግጁ" msgstr "ከማስጠንቀቂያዎች ጋር ለማግበር ዝግጁ"
@@ -3663,10 +3669,6 @@ msgstr "ዳግም ለመጀመር"
msgid "Reset Password" msgid "Reset Password"
msgstr "የይለፍ ቃል ዳግም አስጀምር" msgstr "የይለፍ ቃል ዳግም አስጀምር"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "ወደ ተተገበረ የቅጥ ሉህ ዳግም አስጀምር"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "የይለፍ ቃልዎን ዳግም ያስጀምሩ" msgstr "የይለፍ ቃልዎን ዳግም ያስጀምሩ"
@@ -4195,6 +4197,10 @@ msgstr "ከማቅረብዎ በፊት አንዳንድ የመተግበሪያ ስ
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "አንዳንድ ተንታኞች ምስሎችን ያታልላሉ፣ እና ፎቶዎች በአንዳንድ ክልሎች ተስፋ ይቆርጣሉ።" msgstr "አንዳንድ ተንታኞች ምስሎችን ያታልላሉ፣ እና ፎቶዎች በአንዳንድ ክልሎች ተስፋ ይቆርጣሉ።"
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "የሆነ ችግር ተፈጥሯል" msgstr "የሆነ ችግር ተፈጥሯል"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "የቅጥ ሉህ አርታኢ" msgstr "የቅጥ ሉህ አርታኢ"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "የቅጥ ሉህ ስህተቶች አሉት" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "ተጠቃሚዎች"
msgid "Uzbek" msgid "Uzbek"
msgstr "ኡዝቤክኛ" msgstr "ኡዝቤክኛ"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "ትክክለኛ URL በ http:// ወይም https:// መጀመር አለባቸው።" msgstr "ትክክለኛ URL በ http:// ወይም https:// መጀመር አለባቸው።"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "አጉር"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "ዙሉ" msgstr "ዙሉ"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "الطلبات المرسلة أسبوعيًا (آخر 8 أسابيع)" msgstr "الطلبات المرسلة أسبوعيًا (آخر 8 أسابيع)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "تم التقديم" msgstr "تم التقديم"
@@ -534,10 +533,6 @@ msgstr "تم التقديم"
msgid "Applied on" msgid "Applied on"
msgstr "تم التقديم في" msgstr "تم التقديم في"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "تم استخدامه مع التحذيرات"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "العربية" msgstr "العربية"
@@ -1765,7 +1760,6 @@ msgstr "أدخِل كلمة المرور الخاصة بك لتأكيد إعدا
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "أدخِل كلمة المرور الخاصة بك لتعطيل المصادقة الثنائية. سيكون حسابك أقل أمانًا بدون تمكين المصادقة الثنائية (2FA)." msgstr "أدخِل كلمة المرور الخاصة بك لتعطيل المصادقة الثنائية. سيكون حسابك أقل أمانًا بدون تمكين المصادقة الثنائية (2FA)."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "خطأ" msgstr "خطأ"
@@ -2003,6 +1997,10 @@ msgstr "فشل التحقق من رمز النسخ الاحتياطي الخاص
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "فشل التحقق من الرمز الخاص بك. يرجى المحاولة مرة أخرى." msgstr "فشل التحقق من الرمز الخاص بك. يرجى المحاولة مرة أخرى."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "الميزات" msgstr "الميزات"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "معاينة" msgstr "معاينة"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "استخدم آخر نسخة صالحة للمعاينة والتصدير." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "قراءة…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "جاهز للتفعيل" msgstr "جاهز للتفعيل"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "جاهز للتفعيل مع التحذيرات" msgstr "جاهز للتفعيل مع التحذيرات"
@@ -3663,10 +3669,6 @@ msgstr "إعادة تعيين"
msgid "Reset Password" msgid "Reset Password"
msgstr "إعادة تعيين كلمة المرور" msgstr "إعادة تعيين كلمة المرور"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "إعادة ضبط نمط التنسيق المُطبق"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "إعادة تعيين كلمة المرور" msgstr "إعادة تعيين كلمة المرور"
@@ -4195,6 +4197,10 @@ msgstr "تتطلب بعض أنظمة التقديم واحدًا قبل أن ت
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "يسيء بعض المحللين التعامل مع الصور، ولا يُنصح باستخدام الصور في بعض المناطق." msgstr "يسيء بعض المحللين التعامل مع الصور، ولا يُنصح باستخدام الصور في بعض المناطق."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "حدث خطأ ما" msgstr "حدث خطأ ما"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "محرر أنماط CSS" msgstr "محرر أنماط CSS"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "يحتوي ملف الأنماط على أخطاء" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "المستخدمون"
msgid "Uzbek" msgid "Uzbek"
msgstr "الأوزبكية" msgstr "الأوزبكية"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "يجب أن تبدأ عناوين URL الصالحة بـ http:// أو https://." msgstr "يجب أن تبدأ عناوين URL الصالحة بـ http:// أو https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "بوابة فيركل للذكاء الاصطناعي" msgstr "بوابة فيركل للذكاء الاصطناعي"
@@ -5411,4 +5429,3 @@ msgstr "تصغير"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "الزولو" msgstr "الزولو"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Həftəlik göndərilən müraciətlər (son 8 həftə)" msgstr "Həftəlik göndərilən müraciətlər (son 8 həftə)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Müraciət edildi" msgstr "Müraciət edildi"
@@ -534,10 +533,6 @@ msgstr "Müraciət edildi"
msgid "Applied on" msgid "Applied on"
msgstr "Tətbiq edildiyi tarix" msgstr "Tətbiq edildiyi tarix"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Xəbərdarlıqlarla tətbiq olunur"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Ərəb" msgstr "Ərəb"
@@ -1765,7 +1760,6 @@ msgstr "İki mərhələli autentifikasiyanı qurmağı təsdiqləmək üçün pa
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "İki mərhələli autentifikasiyanı deaktiv etmək üçün parolunuzu daxil edin. 2FA deaktiv edildikdə, hesabınız daha az təhlükəsiz olacaq." msgstr "İki mərhələli autentifikasiyanı deaktiv etmək üçün parolunuzu daxil edin. 2FA deaktiv edildikdə, hesabınız daha az təhlükəsiz olacaq."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Xəta" msgstr "Xəta"
@@ -2003,6 +1997,10 @@ msgstr "Ehtiyat kodunuzu təsdiqləmək mümkün olmadı. Zəhmət olmasa yenid
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Kodunuzu təsdiqləmək mümkün olmadı. Zəhmət olmasa yenidən cəhd edin." msgstr "Kodunuzu təsdiqləmək mümkün olmadı. Zəhmət olmasa yenidən cəhd edin."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Xüsusiyyətlər" msgstr "Xüsusiyyətlər"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Önizləmə" msgstr "Önizləmə"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Önizləmə və ixrac üçün son etibarlı versiyadan istifadə edin." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "… oxunur"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Aktivləşdirməyə hazırdır" msgstr "Aktivləşdirməyə hazırdır"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Xəbərdarlıqlarla aktivləşdirməyə hazırdır" msgstr "Xəbərdarlıqlarla aktivləşdirməyə hazırdır"
@@ -3663,10 +3669,6 @@ msgstr "Sıfırla"
msgid "Reset Password" msgid "Reset Password"
msgstr "Parolu Sıfırla" msgstr "Parolu Sıfırla"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Tətbiq olunmuş stil cədvəlinə sıfırlayın"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Parolunuzu sıfırlayın" msgstr "Parolunuzu sıfırlayın"
@@ -4195,6 +4197,10 @@ msgstr "Bəzi proqram sistemləri təqdim etməzdən əvvəl birini tələb edir
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Bəzi təhlilçilər şəkilləri səhv idarə edir və bəzi bölgələrdə fotoşəkillər tövsiyə edilmir." msgstr "Bəzi təhlilçilər şəkilləri səhv idarə edir və bəzi bölgələrdə fotoşəkillər tövsiyə edilmir."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Nəsə səhv getdi" msgstr "Nəsə səhv getdi"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Stil cədvəli redaktoru" msgstr "Stil cədvəli redaktoru"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Stil cədvəlində səhvlər var" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "İstifadəçilər"
msgid "Uzbek" msgid "Uzbek"
msgstr "Özbək" msgstr "Özbək"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Etibarlı URLlər http:// və ya https:// ilə başlamalıdır." msgstr "Etibarlı URLlər http:// və ya https:// ilə başlamalıdır."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Qapısı" msgstr "Vercel AI Qapısı"
@@ -5411,4 +5429,3 @@ msgstr "Uzaqlaşdır"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Изпратени кандидатури на седмица (последните 8 седмици)" msgstr "Изпратени кандидатури на седмица (последните 8 седмици)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Кандидатствано" msgstr "Кандидатствано"
@@ -534,10 +533,6 @@ msgstr "Кандидатствано"
msgid "Applied on" msgid "Applied on"
msgstr "Приложено на" msgstr "Приложено на"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Прилага се с предупреждения"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Арабски" msgstr "Арабски"
@@ -1765,7 +1760,6 @@ msgstr "Въведете паролата си, за да потвърдите
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Въведете паролата си, за да изключите двуфакторното удостоверяване. Вашият профил ще бъде по-малко защитен без активирано 2FA." msgstr "Въведете паролата си, за да изключите двуфакторното удостоверяване. Вашият профил ще бъде по-малко защитен без активирано 2FA."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Грешка" msgstr "Грешка"
@@ -2003,6 +1997,10 @@ msgstr "Не успяхте да проверите кода си за архи
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Не успяхме да проверим кода ви. Моля, опитайте отново." msgstr "Не успяхме да проверим кода ви. Моля, опитайте отново."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Функции" msgstr "Функции"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Преглед" msgstr "Преглед"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Прегледът и експортът използват последната валидна версия." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Четене…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Готов за активиране" msgstr "Готов за активиране"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Готово за активиране с предупреждения" msgstr "Готово за активиране с предупреждения"
@@ -3663,10 +3669,6 @@ msgstr "Нулиране"
msgid "Reset Password" msgid "Reset Password"
msgstr "Нулиране на паролата" msgstr "Нулиране на паролата"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Възстановяване към приложения стилов лист"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Нулирайте паролата си" msgstr "Нулирайте паролата си"
@@ -4195,6 +4197,10 @@ msgstr "Някои системи за кандидатстване изискв
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Някои парсери обработват неправилно изображения и снимките не се препоръчват в някои региони." msgstr "Някои парсери обработват неправилно изображения и снимките не се препоръчват в някои региони."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Нещо се обърка" msgstr "Нещо се обърка"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Редактор на стилови листове" msgstr "Редактор на стилови листове"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Стилният лист съдържа грешки" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Потребители"
msgid "Uzbek" msgid "Uzbek"
msgstr "Узбекски" msgstr "Узбекски"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Валидните URL адреси трябва да започват с http:// или https://." msgstr "Валидните URL адреси трябва да започват с http:// или https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Намаляване"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Зулуски" msgstr "Зулуски"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "প্রতি সপ্তাহে পাঠানো আবেদন (শেষ 8 সপ্তাহ)" msgstr "প্রতি সপ্তাহে পাঠানো আবেদন (শেষ 8 সপ্তাহ)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "আবেদন করা হয়েছে" msgstr "আবেদন করা হয়েছে"
@@ -534,10 +533,6 @@ msgstr "আবেদন করা হয়েছে"
msgid "Applied on" msgid "Applied on"
msgstr "প্রয়োগ করা হয়েছে" msgstr "প্রয়োগ করা হয়েছে"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "সতর্কতাসহ প্রয়োগ করা হয়েছে"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "আরবি" msgstr "আরবি"
@@ -1765,7 +1760,6 @@ msgstr "টু‑ফ্যাক্টর প্রমাণীকরণ সে
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "টু‑ফ্যাক্টর প্রমাণীকরণ বন্ধ করতে আপনার পাসওয়ার্ড লিখুন। 2FA বন্ধ করলে আপনার অ্যাকাউন্ট কম সুরক্ষিত থাকবে।" msgstr "টু‑ফ্যাক্টর প্রমাণীকরণ বন্ধ করতে আপনার পাসওয়ার্ড লিখুন। 2FA বন্ধ করলে আপনার অ্যাকাউন্ট কম সুরক্ষিত থাকবে।"
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "ত্রুটি" msgstr "ত্রুটি"
@@ -2003,6 +1997,10 @@ msgstr "আপনার ব্যাকআপ কোড যাচাই কর
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "আপনার কোড যাচাই করতে ব্যর্থ হয়েছে। অনুগ্রহ করে আবার চেষ্টা করুন।" msgstr "আপনার কোড যাচাই করতে ব্যর্থ হয়েছে। অনুগ্রহ করে আবার চেষ্টা করুন।"
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "বৈশিষ্ট্যসমূহ" msgstr "বৈশিষ্ট্যসমূহ"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "প্রিভিউ" msgstr "প্রিভিউ"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "প্রিভিউ এবং এক্সপোর্টের জন্য সর্বশেষ বৈধ সংস্করণটি ব্যবহার করা হয়।" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "পড়া…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "সক্রিয় করার জন্য প্রস্তুত" msgstr "সক্রিয় করার জন্য প্রস্তুত"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "সতর্কতা সহ সক্রিয় করার জন্য প্রস্তুত" msgstr "সতর্কতা সহ সক্রিয় করার জন্য প্রস্তুত"
@@ -3663,10 +3669,6 @@ msgstr "রিসেট"
msgid "Reset Password" msgid "Reset Password"
msgstr "পাসওয়ার্ড রিসেট করুন" msgstr "পাসওয়ার্ড রিসেট করুন"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "প্রয়োগকৃত স্টাইলশীটে রিসেট করুন"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "আপনার পাসওয়ার্ড রিসেট করুন" msgstr "আপনার পাসওয়ার্ড রিসেট করুন"
@@ -4195,6 +4197,10 @@ msgstr "আপনি জমা দেওয়ার আগে কিছু অ
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "কিছু বিশ্লেষক চিত্রগুলিকে ভুলভাবে পরিচালনা করে এবং কিছু অঞ্চলে ফটোগুলিকে নিরুৎসাহিত করা হয়৷" msgstr "কিছু বিশ্লেষক চিত্রগুলিকে ভুলভাবে পরিচালনা করে এবং কিছু অঞ্চলে ফটোগুলিকে নিরুৎসাহিত করা হয়৷"
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "কিছু একটা ভুল হয়েছে" msgstr "কিছু একটা ভুল হয়েছে"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "স্টাইলশিট সম্পাদক" msgstr "স্টাইলশিট সম্পাদক"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "স্টাইলশিটে ত্রুটি আছে" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "ব্যবহারকারী"
msgid "Uzbek" msgid "Uzbek"
msgstr "উজবেক" msgstr "উজবেক"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "বৈধ URL অবশ্যই http:// বা https:// দিয়ে শুরু হতে হবে।" msgstr "বৈধ URL অবশ্যই http:// বা https:// দিয়ে শুরু হতে হবে।"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "ভার্সেল এআই গেটওয়ে" msgstr "ভার্সেল এআই গেটওয়ে"
@@ -5411,4 +5429,3 @@ msgstr "জুম আউট"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "জুলু" msgstr "জুলু"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Sol·licituds enviades per setmana (darreres 8 setmanes)" msgstr "Sol·licituds enviades per setmana (darreres 8 setmanes)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Sol·licitada" msgstr "Sol·licitada"
@@ -534,10 +533,6 @@ msgstr "Sol·licitada"
msgid "Applied on" msgid "Applied on"
msgstr "Aplicat a" msgstr "Aplicat a"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Aplicat amb avisos"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Àrab" msgstr "Àrab"
@@ -1765,7 +1760,6 @@ msgstr "Introdueix la contrasenya per confirmar la configuració de lautentic
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Introdueix la contrasenya per desactivar lautenticació en dos passos. El compte serà menys segur sense lA2F activada." msgstr "Introdueix la contrasenya per desactivar lautenticació en dos passos. El compte serà menys segur sense lA2F activada."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Error" msgstr "Error"
@@ -2003,6 +1997,10 @@ msgstr "No s'ha pogut verificar el vostre codi de recuperació. Torneu-ho a prov
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "S'ha fallat la verificació del vostre codi. Torneu-ho a provar." msgstr "S'ha fallat la verificació del vostre codi. Torneu-ho a provar."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funcions" msgstr "Funcions"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Vista prèvia" msgstr "Vista prèvia"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "La vista prèvia i l'exportació utilitzen l'última versió vàlida." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Llegint…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Llest per activar" msgstr "Llest per activar"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Llest per activar amb avisos" msgstr "Llest per activar amb avisos"
@@ -3663,10 +3669,6 @@ msgstr "Restableix"
msgid "Reset Password" msgid "Reset Password"
msgstr "Restableix la contrasenya" msgstr "Restableix la contrasenya"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Restableix al full d'estils aplicat"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Restableix la contrasenya" msgstr "Restableix la contrasenya"
@@ -4195,6 +4197,10 @@ msgstr "Alguns sistemes de sol·licitud en requereixen un abans de poder enviar-
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Alguns analitzadors analítics gestionen malament les imatges i, en algunes regions, no es recomanen les fotos." msgstr "Alguns analitzadors analítics gestionen malament les imatges i, en algunes regions, no es recomanen les fotos."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Alguna cosa ha anat malament" msgstr "Alguna cosa ha anat malament"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Editor de fulls d'estil" msgstr "Editor de fulls d'estil"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "El full d'estil té errors" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Usuaris"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbek" msgstr "Uzbek"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Les URL vàlides han de començar per http:// o https://." msgstr "Les URL vàlides han de començar per http:// o https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Allunya"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulú" msgstr "Zulú"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Žádosti odeslané týdně (posledních 8 týdnů)" msgstr "Žádosti odeslané týdně (posledních 8 týdnů)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Podáno" msgstr "Podáno"
@@ -534,10 +533,6 @@ msgstr "Podáno"
msgid "Applied on" msgid "Applied on"
msgstr "Aplikováno na" msgstr "Aplikováno na"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Použito s varováním"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabština" msgstr "Arabština"
@@ -1765,7 +1760,6 @@ msgstr "Zadejte své heslo pro potvrzení nastavení dvoufázového ověření.
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Zadejte své heslo pro deaktivaci dvoufázového ověření. Bez aktivního 2FA bude váš účet méně zabezpečený." msgstr "Zadejte své heslo pro deaktivaci dvoufázového ověření. Bez aktivního 2FA bude váš účet méně zabezpečený."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Chyba" msgstr "Chyba"
@@ -2003,6 +1997,10 @@ msgstr "Nepodařilo se ověřit váš záložní kód. Zkuste to prosím znovu."
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Nepodařilo se ověřit váš kód. Zkuste to prosím znovu." msgstr "Nepodařilo se ověřit váš kód. Zkuste to prosím znovu."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funkce" msgstr "Funkce"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Náhled" msgstr "Náhled"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Náhled a export použijí poslední platnou verzi." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Čtení…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Připraveno k aktivaci" msgstr "Připraveno k aktivaci"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Připraveno k aktivaci s varováními" msgstr "Připraveno k aktivaci s varováními"
@@ -3663,10 +3669,6 @@ msgstr "Resetovat"
msgid "Reset Password" msgid "Reset Password"
msgstr "Obnovit heslo" msgstr "Obnovit heslo"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Obnovit použitý stylový list"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Obnovte své heslo" msgstr "Obnovte své heslo"
@@ -4195,6 +4197,10 @@ msgstr "Některé aplikační systémy vyžadují jeden před odesláním."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Některé analyzátory špatně zacházejí s obrázky a v některých oblastech se fotografie nedoporučuje." msgstr "Některé analyzátory špatně zacházejí s obrázky a v některých oblastech se fotografie nedoporučuje."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Něco se pokazilo" msgstr "Něco se pokazilo"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Editor stylů" msgstr "Editor stylů"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Stylový list obsahuje chyby" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Uživatelé"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbečtina" msgstr "Uzbečtina"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Platné URL adresy musí začínat http:// nebo https://." msgstr "Platné URL adresy musí začínat http:// nebo https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Brána Vercel AI" msgstr "Brána Vercel AI"
@@ -5411,4 +5429,3 @@ msgstr "Oddálit"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Ansøgninger sendt pr. uge (sidste 8 uger)" msgstr "Ansøgninger sendt pr. uge (sidste 8 uger)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Ansøgt" msgstr "Ansøgt"
@@ -534,10 +533,6 @@ msgstr "Ansøgt"
msgid "Applied on" msgid "Applied on"
msgstr "Anvendt den" msgstr "Anvendt den"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Anvendt med advarsler"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabisk" msgstr "Arabisk"
@@ -1765,7 +1760,6 @@ msgstr "Indtast din adgangskode for at bekræfte opsætning af to-faktor-godkend
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Indtast din adgangskode for at deaktivere to-faktor-godkendelse. Din konto vil være mindre sikker uden 2FA aktiveret." msgstr "Indtast din adgangskode for at deaktivere to-faktor-godkendelse. Din konto vil være mindre sikker uden 2FA aktiveret."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Fejl" msgstr "Fejl"
@@ -2003,6 +1997,10 @@ msgstr "Det lykkedes ikke at bekræfte din backup-kode. Prøv venligst igen."
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Det lykkedes ikke at bekræfte din kode. Prøv venligst igen." msgstr "Det lykkedes ikke at bekræfte din kode. Prøv venligst igen."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funktioner" msgstr "Funktioner"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Forhåndsvisning" msgstr "Forhåndsvisning"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Forhåndsvisning og eksport med den seneste gyldige version." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Læsning…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Klar til aktivering" msgstr "Klar til aktivering"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Klar til aktivering med advarsler" msgstr "Klar til aktivering med advarsler"
@@ -3663,10 +3669,6 @@ msgstr "Nulstil"
msgid "Reset Password" msgid "Reset Password"
msgstr "Nulstil adgangskode" msgstr "Nulstil adgangskode"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Nulstil til anvendt stylesheet"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Nulstil din adgangskode" msgstr "Nulstil din adgangskode"
@@ -4195,6 +4197,10 @@ msgstr "Nogle ansøgningssystemer kræver et, før du kan indsende."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Nogle parsere mishandler billeder, og fotos frarådes i nogle regioner." msgstr "Nogle parsere mishandler billeder, og fotos frarådes i nogle regioner."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Noget gik galt" msgstr "Noget gik galt"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Stylesheet-editor" msgstr "Stylesheet-editor"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Stylesheet indeholder fejl" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Brugere"
msgid "Uzbek" msgid "Uzbek"
msgstr "Usbekisk" msgstr "Usbekisk"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Gyldige URL'er skal starte med http:// eller https://." msgstr "Gyldige URL'er skal starte med http:// eller https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Zoom ud"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Pro Woche gesendete Bewerbungen (letzte 8 Wochen)" msgstr "Pro Woche gesendete Bewerbungen (letzte 8 Wochen)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Beworben" msgstr "Beworben"
@@ -534,10 +533,6 @@ msgstr "Beworben"
msgid "Applied on" msgid "Applied on"
msgstr "Beworben am" msgstr "Beworben am"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Mit Warnungen angewendet"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabisch" msgstr "Arabisch"
@@ -1765,7 +1760,6 @@ msgstr "Geben Sie Ihr Passwort ein, um die Einrichtung der Zwei-Faktor-Authentif
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Geben Sie Ihr Passwort ein, um die Zwei-Faktor-Authentifizierung zu deaktivieren. Ihr Konto ist ohne 2FA weniger sicher." msgstr "Geben Sie Ihr Passwort ein, um die Zwei-Faktor-Authentifizierung zu deaktivieren. Ihr Konto ist ohne 2FA weniger sicher."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Fehler" msgstr "Fehler"
@@ -2003,6 +1997,10 @@ msgstr "Ihr Sicherungscode konnte nicht verifiziert werden. Bitte versuchen Sie
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Ihr Code konnte nicht verifiziert werden. Bitte versuchen Sie es erneut." msgstr "Ihr Code konnte nicht verifiziert werden. Bitte versuchen Sie es erneut."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funktionen" msgstr "Funktionen"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Vorschau" msgstr "Vorschau"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Vorschau und Export verwenden die letzte gültige Version." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Wird gelesen…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Bereit zur Aktivierung" msgstr "Bereit zur Aktivierung"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Bereit zur Aktivierung mit Warnungen" msgstr "Bereit zur Aktivierung mit Warnungen"
@@ -3663,10 +3669,6 @@ msgstr "Zurücksetzen"
msgid "Reset Password" msgid "Reset Password"
msgstr "Passwort zurücksetzen" msgstr "Passwort zurücksetzen"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Auf angewendetes Stylesheet zurücksetzen"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Setzen Sie Ihr Passwort zurück" msgstr "Setzen Sie Ihr Passwort zurück"
@@ -4195,6 +4197,10 @@ msgstr "Bei einigen Bewerbungssystemen ist ein Antrag erforderlich, bevor Sie ih
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Einige Parser verarbeiten Bilder falsch, und in einigen Regionen wird von Fotos abgeraten." msgstr "Einige Parser verarbeiten Bilder falsch, und in einigen Regionen wird von Fotos abgeraten."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Etwas ist schiefgelaufen." msgstr "Etwas ist schiefgelaufen."
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Stylesheet-Editor" msgstr "Stylesheet-Editor"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Das Stylesheet enthält Fehler." msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Nutzende"
msgid "Uzbek" msgid "Uzbek"
msgstr "Usbekisch" msgstr "Usbekisch"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Gültige URLs müssen mit http:// oder https:// beginnen." msgstr "Gültige URLs müssen mit http:// oder https:// beginnen."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Herauszoomen"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Αιτήσεις που στάλθηκαν ανά εβδομάδα (τελευταίες 8 εβδομάδες)" msgstr "Αιτήσεις που στάλθηκαν ανά εβδομάδα (τελευταίες 8 εβδομάδες)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Υποβλήθηκε" msgstr "Υποβλήθηκε"
@@ -534,10 +533,6 @@ msgstr "Υποβλήθηκε"
msgid "Applied on" msgid "Applied on"
msgstr "Ημερομηνία αίτησης" msgstr "Ημερομηνία αίτησης"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Εφαρμόζεται με προειδοποιήσεις"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Αραβικά" msgstr "Αραβικά"
@@ -1765,7 +1760,6 @@ msgstr "Εισαγάγετε τον κωδικό πρόσβασής σας γι
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Εισαγάγετε τον κωδικό πρόσβασής σας για να απενεργοποιήσετε τον έλεγχο ταυτότητας δύο παραγόντων. Ο λογαριασμός σας θα είναι λιγότερο ασφαλής χωρίς ενεργοποιημένο 2FA." msgstr "Εισαγάγετε τον κωδικό πρόσβασής σας για να απενεργοποιήσετε τον έλεγχο ταυτότητας δύο παραγόντων. Ο λογαριασμός σας θα είναι λιγότερο ασφαλής χωρίς ενεργοποιημένο 2FA."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Σφάλμα" msgstr "Σφάλμα"
@@ -2003,6 +1997,10 @@ msgstr "Απέτυχε η επαλήθευση του κωδικού αντιγ
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Απέτυχε η επαλήθευση του κωδικού σας. Προσπαθήστε ξανά." msgstr "Απέτυχε η επαλήθευση του κωδικού σας. Προσπαθήστε ξανά."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Λειτουργίες" msgstr "Λειτουργίες"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Πρεμιέρα" msgstr "Πρεμιέρα"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Η προεπισκόπηση και η εξαγωγή χρησιμοποιούν την τελευταία έγκυρη έκδοση." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Ανάγνωση…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Έτοιμο για ενεργοποίηση" msgstr "Έτοιμο για ενεργοποίηση"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Έτοιμο για ενεργοποίηση με προειδοποιήσεις" msgstr "Έτοιμο για ενεργοποίηση με προειδοποιήσεις"
@@ -3663,10 +3669,6 @@ msgstr "Επαναφορά"
msgid "Reset Password" msgid "Reset Password"
msgstr "Επαναφορά κωδικού πρόσβασης" msgstr "Επαναφορά κωδικού πρόσβασης"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Επαναφορά στο εφαρμοσμένο φύλλο στυλ"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Επαναφορά κωδικού πρόσβασης" msgstr "Επαναφορά κωδικού πρόσβασης"
@@ -4195,6 +4197,10 @@ msgstr "Ορισμένα συστήματα αιτήσεων απαιτούν έ
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Ορισμένοι αναλυτές χειρίζονται εσφαλμένα τις εικόνες και οι φωτογραφίες αποθαρρύνονται σε ορισμένες περιοχές." msgstr "Ορισμένοι αναλυτές χειρίζονται εσφαλμένα τις εικόνες και οι φωτογραφίες αποθαρρύνονται σε ορισμένες περιοχές."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Κάτι πήγε στραβά" msgstr "Κάτι πήγε στραβά"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Επεξεργαστής φύλλου στυλ" msgstr "Επεξεργαστής φύλλου στυλ"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Το φύλλο στυλ έχει σφάλματα" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Χρήστες"
msgid "Uzbek" msgid "Uzbek"
msgstr "Ουζμπεκικά" msgstr "Ουζμπεκικά"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Τα έγκυρα URLs πρέπει να ξεκινούν με http:// ή https://." msgstr "Τα έγκυρα URLs πρέπει να ξεκινούν με http:// ή https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Πύλη Vercel AI Gateway" msgstr "Πύλη Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Σμίκρυνση"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Ζουλού" msgstr "Ζουλού"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Applications sent per week (last 8 weeks)" msgstr "Applications sent per week (last 8 weeks)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Applied" msgstr "Applied"
@@ -534,10 +533,6 @@ msgstr "Applied"
msgid "Applied on" msgid "Applied on"
msgstr "Applied on" msgstr "Applied on"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Applied with warnings"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabic" msgstr "Arabic"
@@ -1765,7 +1760,6 @@ msgstr "Enter your password to confirm setting up two-factor authentication. Whe
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgstr "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Error" msgstr "Error"
@@ -2003,6 +1997,10 @@ msgstr "Failed to verify your backup code. Please try again."
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Failed to verify your code. Please try again." msgstr "Failed to verify your code. Please try again."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Features" msgstr "Features"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Preview" msgstr "Preview"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Preview and export use the last valid version." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Reading…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Ready to activate" msgstr "Ready to activate"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Ready to activate with warnings" msgstr "Ready to activate with warnings"
@@ -3663,10 +3669,6 @@ msgstr "Reset"
msgid "Reset Password" msgid "Reset Password"
msgstr "Reset Password" msgstr "Reset Password"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Reset to applied stylesheet"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Reset your password" msgstr "Reset your password"
@@ -4195,6 +4197,10 @@ msgstr "Some application systems require one before you can submit."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Some parsers mishandle images, and photos are discouraged in some regions." msgstr "Some parsers mishandle images, and photos are discouraged in some regions."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Something went wrong" msgstr "Something went wrong"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Stylesheet editor" msgstr "Stylesheet editor"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Stylesheet has errors" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Users"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbek" msgstr "Uzbek"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Valid URLs must start with http:// or https://." msgstr "Valid URLs must start with http:// or https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Zoom out"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -14
View File
@@ -521,7 +521,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Applications sent per week (last 8 weeks)" msgstr "Applications sent per week (last 8 weeks)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Applied" msgstr "Applied"
@@ -529,10 +528,6 @@ msgstr "Applied"
msgid "Applied on" msgid "Applied on"
msgstr "Applied on" msgstr "Applied on"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Applied with warnings"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabic" msgstr "Arabic"
@@ -1760,7 +1755,6 @@ msgstr "Enter your password to confirm setting up two-factor authentication. Whe
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgstr "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Error" msgstr "Error"
@@ -1998,6 +1992,10 @@ msgstr "Failed to verify your backup code. Please try again."
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Failed to verify your code. Please try again." msgstr "Failed to verify your code. Please try again."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr "Fatal error"
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Features" msgstr "Features"
@@ -3415,8 +3413,12 @@ msgid "Preview"
msgstr "Preview" msgstr "Preview"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Preview and export use the last valid version." msgstr "Preview and export fall back to base styles."
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr "Preview and export keep valid styles and ignore invalid styles."
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3537,6 +3539,10 @@ msgstr "Reading…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Ready to activate" msgstr "Ready to activate"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr "Ready to activate with errors"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Ready to activate with warnings" msgstr "Ready to activate with warnings"
@@ -3658,10 +3664,6 @@ msgstr "Reset"
msgid "Reset Password" msgid "Reset Password"
msgstr "Reset Password" msgstr "Reset Password"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Reset to applied stylesheet"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Reset your password" msgstr "Reset your password"
@@ -4190,6 +4192,10 @@ msgstr "Some application systems require one before you can submit."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Some parsers mishandle images, and photos are discouraged in some regions." msgstr "Some parsers mishandle images, and photos are discouraged in some regions."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr "Some styles were ignored"
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Something went wrong" msgstr "Something went wrong"
@@ -4333,8 +4339,8 @@ msgid "Stylesheet editor"
msgstr "Stylesheet editor" msgstr "Stylesheet editor"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Stylesheet has errors" msgstr "Stylesheet has fatal errors"
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5098,10 +5104,22 @@ msgstr "Users"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbek" msgstr "Uzbek"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr "Valid"
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Valid URLs must start with http:// or https://." msgstr "Valid URLs must start with http:// or https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr "Valid with errors"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr "Valid with warnings"
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Candidaturas enviadas por semana (últimas 8 semanas)" msgstr "Candidaturas enviadas por semana (últimas 8 semanas)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Enviada" msgstr "Enviada"
@@ -534,10 +533,6 @@ msgstr "Enviada"
msgid "Applied on" msgid "Applied on"
msgstr "Postulado el" msgstr "Postulado el"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Aplicado con advertencias"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Árabe" msgstr "Árabe"
@@ -1765,7 +1760,6 @@ msgstr "Introduce tu contraseña para confirmar la configuración de la autentic
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Introduce tu contraseña para deshabilitar la autenticación de doble factor. Tu cuenta será menos segura sin 2FA habilitada." msgstr "Introduce tu contraseña para deshabilitar la autenticación de doble factor. Tu cuenta será menos segura sin 2FA habilitada."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Error" msgstr "Error"
@@ -2003,6 +1997,10 @@ msgstr "No se ha podido verificar su código de copia de seguridad. Por favor, i
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "No se ha podido verificar su código. Por favor, inténtelo de nuevo." msgstr "No se ha podido verificar su código. Por favor, inténtelo de nuevo."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funciones" msgstr "Funciones"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Avance" msgstr "Avance"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "La vista previa y la exportación utilizan la última versión válida." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Leyendo…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Listo para activar" msgstr "Listo para activar"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Listo para activarse con advertencias" msgstr "Listo para activarse con advertencias"
@@ -3663,10 +3669,6 @@ msgstr "Restablecer"
msgid "Reset Password" msgid "Reset Password"
msgstr "Restablecer contraseña" msgstr "Restablecer contraseña"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Restablecer a la hoja de estilos aplicada"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Restablecer tu contraseña" msgstr "Restablecer tu contraseña"
@@ -4195,6 +4197,10 @@ msgstr "Algunos sistemas de solicitud requieren uno antes de poder enviarlo."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Algunos analizadores manejan mal las imágenes y en algunas regiones no se recomiendan las fotografías." msgstr "Algunos analizadores manejan mal las imágenes y en algunas regiones no se recomiendan las fotografías."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Algo salió mal" msgstr "Algo salió mal"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Editor de hojas de estilo" msgstr "Editor de hojas de estilo"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "La hoja de estilos tiene errores." msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Usuarios"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbeko" msgstr "Uzbeko"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Las URL válidas deben comenzar con http:// o https://." msgstr "Las URL válidas deben comenzar con http:// o https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Pasarela Vercel AI" msgstr "Pasarela Vercel AI"
@@ -5411,4 +5429,3 @@ msgstr "Alejar"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulú" msgstr "Zulú"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "درخواست‌های ارسال‌شده در هفته (۸ هفته گذشته)" msgstr "درخواست‌های ارسال‌شده در هفته (۸ هفته گذشته)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "ارسال‌شده" msgstr "ارسال‌شده"
@@ -534,10 +533,6 @@ msgstr "ارسال‌شده"
msgid "Applied on" msgid "Applied on"
msgstr "تاریخ درخواست" msgstr "تاریخ درخواست"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "با هشدارها اعمال می‌شود"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "عربی" msgstr "عربی"
@@ -1765,7 +1760,6 @@ msgstr "برای تأیید راه‌اندازی احراز هویت دو مر
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "برای غیرفعال کردن احراز هویت دو مرحله‌ای گذرواژهٔ خود را وارد کنید. بدون فعال بودن 2FA حساب شما امنیت کمتری خواهد داشت." msgstr "برای غیرفعال کردن احراز هویت دو مرحله‌ای گذرواژهٔ خود را وارد کنید. بدون فعال بودن 2FA حساب شما امنیت کمتری خواهد داشت."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "خطا" msgstr "خطا"
@@ -2003,6 +1997,10 @@ msgstr "کد پشتیبان شما تأیید نشد. لطفاً دوباره ت
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "تأیید کد شما ناموفق بود. لطفاً دوباره تلاش کنید." msgstr "تأیید کد شما ناموفق بود. لطفاً دوباره تلاش کنید."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "امکانات" msgstr "امکانات"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "پیش‌نمایش" msgstr "پیش‌نمایش"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "پیش‌نمایش و خروجی گرفتن از آخرین نسخه معتبر." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "در حال خواندن…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "آماده فعال سازی" msgstr "آماده فعال سازی"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "آماده فعال شدن با هشدارها" msgstr "آماده فعال شدن با هشدارها"
@@ -3663,10 +3669,6 @@ msgstr "ریست"
msgid "Reset Password" msgid "Reset Password"
msgstr "تنظیم مجدد گذرواژه" msgstr "تنظیم مجدد گذرواژه"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "تنظیم مجدد به شیوه‌نامه اعمال شده"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "تنظیم مجدد گذرواژهٔ شما" msgstr "تنظیم مجدد گذرواژهٔ شما"
@@ -4195,6 +4197,10 @@ msgstr "برخی سامانه‌های درخواست شغلی پیش از ار
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "برخی تجزیه‌گرها تصاویر را نادرست پردازش می‌کنند و در بعضی مناطق استفاده از عکس توصیه نمی‌شود." msgstr "برخی تجزیه‌گرها تصاویر را نادرست پردازش می‌کنند و در بعضی مناطق استفاده از عکس توصیه نمی‌شود."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "چیزی اشتباه پیش رفت" msgstr "چیزی اشتباه پیش رفت"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "ویرایشگر استایل‌شیت" msgstr "ویرایشگر استایل‌شیت"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "استایل‌شیت خطا دارد" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "کاربران"
msgid "Uzbek" msgid "Uzbek"
msgstr "ازبکی" msgstr "ازبکی"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "URLهای معتبر باید با http:// یا https:// شروع شوند." msgstr "URLهای معتبر باید با http:// یا https:// شروع شوند."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "دروازه ورچل ای‌آی" msgstr "دروازه ورچل ای‌آی"
@@ -5411,4 +5429,3 @@ msgstr "کوچک‌نمایی"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "زولو" msgstr "زولو"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Lähetetyt hakemukset viikoittain (viimeiset 8 viikkoa)" msgstr "Lähetetyt hakemukset viikoittain (viimeiset 8 viikkoa)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Haettu" msgstr "Haettu"
@@ -534,10 +533,6 @@ msgstr "Haettu"
msgid "Applied on" msgid "Applied on"
msgstr "Haettu" msgstr "Haettu"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Käytetty varoituksilla"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "arabia" msgstr "arabia"
@@ -1765,7 +1760,6 @@ msgstr "Syötä salasanasi vahvistaaksesi kaksivaiheisen todennuksen käyttöön
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Syötä salasanasi poistaaksesi kaksivaiheisen todennuksen käytöstä. Tilisi on vähemmän suojattu ilman 2FA:ta." msgstr "Syötä salasanasi poistaaksesi kaksivaiheisen todennuksen käytöstä. Tilisi on vähemmän suojattu ilman 2FA:ta."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Virhe" msgstr "Virhe"
@@ -2003,6 +1997,10 @@ msgstr "Varmuuskopiointikoodin vahvistaminen epäonnistui. Yritä uudelleen."
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Koodiasi ei onnistuttu tarkistamaan. Yritä uudelleen." msgstr "Koodiasi ei onnistuttu tarkistamaan. Yritä uudelleen."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Ominaisuudet" msgstr "Ominaisuudet"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Esikatselu" msgstr "Esikatselu"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Esikatsele ja vie käyttämällä viimeisintä kelvollista versiota." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Luetaan…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Valmis aktivoitavaksi" msgstr "Valmis aktivoitavaksi"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Valmis aktivoitavaksi varoituksilla" msgstr "Valmis aktivoitavaksi varoituksilla"
@@ -3663,10 +3669,6 @@ msgstr "Palauta"
msgid "Reset Password" msgid "Reset Password"
msgstr "Palauta salasana" msgstr "Palauta salasana"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Palauta käytettyyn tyylitiedostoon"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Palauta salasanasi" msgstr "Palauta salasanasi"
@@ -4195,6 +4197,10 @@ msgstr "Jotkin hakujärjestelmät vaativat sellaisen, ennen kuin voit lähettä
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Jotkut jäsentimet käsittelevät kuvia väärin, eikä valokuvia suositella joillain alueilla." msgstr "Jotkut jäsentimet käsittelevät kuvia väärin, eikä valokuvia suositella joillain alueilla."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Jokin meni pieleen" msgstr "Jokin meni pieleen"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Tyylitiedostoeditori" msgstr "Tyylitiedostoeditori"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Tyylitiedostossa on virheitä" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Käyttäjät"
msgid "Uzbek" msgid "Uzbek"
msgstr "uzbekki" msgstr "uzbekki"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Kelvollisten URL-osoitteiden on alettava http:// tai https:// ." msgstr "Kelvollisten URL-osoitteiden on alettava http:// tai https:// ."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Loitonna"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Candidatures envoyées par semaine (8 dernières semaines)" msgstr "Candidatures envoyées par semaine (8 dernières semaines)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Candidature envoyée" msgstr "Candidature envoyée"
@@ -534,10 +533,6 @@ msgstr "Candidature envoyée"
msgid "Applied on" msgid "Applied on"
msgstr "Postulé le" msgstr "Postulé le"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Appliqué avec avertissements"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabe" msgstr "Arabe"
@@ -1765,7 +1760,6 @@ msgstr "Saisissez votre mot de passe pour confirmer la configuration de l'authen
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Saisissez votre mot de passe pour désactiver l'authentification à deux facteurs. Votre compte sera moins sécurisé si l'authentification à deux facteurs n'est pas activée." msgstr "Saisissez votre mot de passe pour désactiver l'authentification à deux facteurs. Votre compte sera moins sécurisé si l'authentification à deux facteurs n'est pas activée."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Erreur" msgstr "Erreur"
@@ -2003,6 +1997,10 @@ msgstr "La vérification de votre code de sauvegarde a échoué. Veuillez réess
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "La vérification de votre code a échoué. Veuillez réessayer." msgstr "La vérification de votre code a échoué. Veuillez réessayer."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Fonctionnalités" msgstr "Fonctionnalités"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Aperçu" msgstr "Aperçu"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "L'aperçu et l'exportation utilisent la dernière version valide." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Lecture…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Prêt à activer" msgstr "Prêt à activer"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Prêt à être activé avec avertissements" msgstr "Prêt à être activé avec avertissements"
@@ -3663,10 +3669,6 @@ msgstr "Réinitialiser"
msgid "Reset Password" msgid "Reset Password"
msgstr "Réinitialiser le mot de passe" msgstr "Réinitialiser le mot de passe"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Réinitialiser la feuille de style appliquée"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Réinitialisez votre mot de passe" msgstr "Réinitialisez votre mot de passe"
@@ -4195,6 +4197,10 @@ msgstr "Certains systèmes de candidature en exigent un avant que vous puissiez
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Certains analyseurs traitent mal les images et les photos sont déconseillées dans certaines régions." msgstr "Certains analyseurs traitent mal les images et les photos sont déconseillées dans certaines régions."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Quelque chose s'est mal passé" msgstr "Quelque chose s'est mal passé"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Éditeur de feuilles de style" msgstr "Éditeur de feuilles de style"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "La feuille de style contient des erreurs" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Utilisateurs"
msgid "Uzbek" msgid "Uzbek"
msgstr "Ouzbékistanais" msgstr "Ouzbékistanais"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Les URL valides doivent commencer par http:// ou https://." msgstr "Les URL valides doivent commencer par http:// ou https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Passerelle Vercel AI" msgstr "Passerelle Vercel AI"
@@ -5411,4 +5429,3 @@ msgstr "Zoom arrière"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zoulou" msgstr "Zoulou"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "מועמדויות שנשלחו בשבוע (8 השבועות האחרונים)" msgstr "מועמדויות שנשלחו בשבוע (8 השבועות האחרונים)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "הוגש" msgstr "הוגש"
@@ -534,10 +533,6 @@ msgstr "הוגש"
msgid "Applied on" msgid "Applied on"
msgstr "הוגש בתאריך" msgstr "הוגש בתאריך"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "יושם עם אזהרות"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "ערבית" msgstr "ערבית"
@@ -1765,7 +1760,6 @@ msgstr "הזן את הסיסמה שלך כדי לאשר הגדרת אימות ד
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "הזן את הסיסמה שלך כדי להשבית אימות דו־שלבי. החשבון שלך יהיה פחות מאובטח ללא אימות דו־שלבי." msgstr "הזן את הסיסמה שלך כדי להשבית אימות דו־שלבי. החשבון שלך יהיה פחות מאובטח ללא אימות דו־שלבי."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "שְׁגִיאָה" msgstr "שְׁגִיאָה"
@@ -2003,6 +1997,10 @@ msgstr "לא הצלחנו לאמת את קוד הגיבוי שלך. אנא נס
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "לא הצלחנו לאמת את הקוד שלך. אנא נסה שוב." msgstr "לא הצלחנו לאמת את הקוד שלך. אנא נסה שוב."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "יכולות" msgstr "יכולות"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "תצוגה מקדימה" msgstr "תצוגה מקדימה"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "תצוגה מקדימה וייצוא משתמשים בגרסה התקינה האחרונה." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "קורא…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "מוכן להפעלה" msgstr "מוכן להפעלה"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "מוכן להפעלה עם אזהרות" msgstr "מוכן להפעלה עם אזהרות"
@@ -3663,10 +3669,6 @@ msgstr "איפוס"
msgid "Reset Password" msgid "Reset Password"
msgstr "איפוס סיסמה" msgstr "איפוס סיסמה"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "איפוס לגיליון הסגנונות שהוחל"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "איפוס הסיסמה שלך" msgstr "איפוס הסיסמה שלך"
@@ -4195,6 +4197,10 @@ msgstr "מערכות מועמדות מסוימות דורשות זאת לפני
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "מנתחים מסוימים מטפלים בתמונות באופן שגוי, ובאזורים מסוימים לא מומלץ להשתמש בתמונות." msgstr "מנתחים מסוימים מטפלים בתמונות באופן שגוי, ובאזורים מסוימים לא מומלץ להשתמש בתמונות."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "משהו השתבש" msgstr "משהו השתבש"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "עורך גיליון סגנונות" msgstr "עורך גיליון סגנונות"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "גיליון הסגנונות מכיל שגיאות" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "משתמשים"
msgid "Uzbek" msgid "Uzbek"
msgstr "אוזבקית" msgstr "אוזבקית"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "כתובות URL חוקיות חייבות להתחיל ב־http:// או https://." msgstr "כתובות URL חוקיות חייבות להתחיל ב־http:// או https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "התרחקות"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "זולו" msgstr "זולו"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "प्रति सप्ताह भेजे गए आवेदन (पिछले 8 सप्ताह)" msgstr "प्रति सप्ताह भेजे गए आवेदन (पिछले 8 सप्ताह)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "आवेदन किया" msgstr "आवेदन किया"
@@ -534,10 +533,6 @@ msgstr "आवेदन किया"
msgid "Applied on" msgid "Applied on"
msgstr "आवेदन की तारीख" msgstr "आवेदन की तारीख"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "चेतावनी सहित लागू"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "अरबी" msgstr "अरबी"
@@ -1765,7 +1760,6 @@ msgstr "दो‑कारक प्रमाणीकरण सेटअप क
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "दो‑कारक प्रमाणीकरण अक्षम करने के लिए अपना पासवर्ड दर्ज करें। 2FA सक्षम न होने पर आपका खाता कम सुरक्षित रहेगा।" msgstr "दो‑कारक प्रमाणीकरण अक्षम करने के लिए अपना पासवर्ड दर्ज करें। 2FA सक्षम न होने पर आपका खाता कम सुरक्षित रहेगा।"
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "गलती" msgstr "गलती"
@@ -2003,6 +1997,10 @@ msgstr "आपके बैकअप कोड को सत्यापित
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "आपके कोड का सत्यापन विफल हो गया। कृपया फिर से प्रयास करें।" msgstr "आपके कोड का सत्यापन विफल हो गया। कृपया फिर से प्रयास करें।"
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "विशेषताएँ" msgstr "विशेषताएँ"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "पूर्व दर्शन" msgstr "पूर्व दर्शन"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "पूर्वावलोकन और निर्यात के लिए अंतिम मान्य संस्करण का उपयोग करें।" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "पढ़ा जा रहा है…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "सक्रिय करने के लिए तैयार" msgstr "सक्रिय करने के लिए तैयार"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "चेतावनी सहित सक्रिय करने के लिए तैयार" msgstr "चेतावनी सहित सक्रिय करने के लिए तैयार"
@@ -3663,10 +3669,6 @@ msgstr "रीसेट"
msgid "Reset Password" msgid "Reset Password"
msgstr "पासवर्ड रीसेट करें" msgstr "पासवर्ड रीसेट करें"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "लागू स्टाइलशीट पर रीसेट करें"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "अपना पासवर्ड रीसेट करें" msgstr "अपना पासवर्ड रीसेट करें"
@@ -4195,6 +4197,10 @@ msgstr "आपके सबमिट करने से पहले कुछ
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "कुछ पार्सर्स छवियों को गलत तरीके से संभालते हैं, और कुछ क्षेत्रों में फ़ोटो को हतोत्साहित किया जाता है।" msgstr "कुछ पार्सर्स छवियों को गलत तरीके से संभालते हैं, और कुछ क्षेत्रों में फ़ोटो को हतोत्साहित किया जाता है।"
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "कुछ गलत हो गया" msgstr "कुछ गलत हो गया"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "स्टाइलशीट संपादक" msgstr "स्टाइलशीट संपादक"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "स्टाइलशीट में त्रुटियाँ हैं" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "उपयोगकर्ता"
msgid "Uzbek" msgid "Uzbek"
msgstr "उज़्बेक" msgstr "उज़्बेक"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "मान्य URL http:// या https:// से शुरू होना चाहिए।" msgstr "मान्य URL http:// या https:// से शुरू होना चाहिए।"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "वर्सेल एआई गेटवे" msgstr "वर्सेल एआई गेटवे"
@@ -5411,4 +5429,3 @@ msgstr "ज़ूम आउट"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "ज़ुलु" msgstr "ज़ुलु"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Hetente elküldött jelentkezések (az elmúlt 8 hét)" msgstr "Hetente elküldött jelentkezések (az elmúlt 8 hét)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Jelentkezve" msgstr "Jelentkezve"
@@ -534,10 +533,6 @@ msgstr "Jelentkezve"
msgid "Applied on" msgid "Applied on"
msgstr "Jelentkezés dátuma" msgstr "Jelentkezés dátuma"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Figyelmeztetésekkel alkalmazva"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "arab" msgstr "arab"
@@ -1765,7 +1760,6 @@ msgstr "Add meg a jelszavadat a kétlépcsős hitelesítés beállításának me
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Add meg a jelszavadat a kétlépcsős hitelesítés kikapcsolásához. A fiókod kevésbé lesz biztonságos 2FA nélkül." msgstr "Add meg a jelszavadat a kétlépcsős hitelesítés kikapcsolásához. A fiókod kevésbé lesz biztonságos 2FA nélkül."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Hiba" msgstr "Hiba"
@@ -2003,6 +1997,10 @@ msgstr "Nem sikerült ellenőrizni a biztonsági mentés kódját. Kérjük, pr
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Nem sikerült ellenőrizni a kódot. Kérjük, próbálja meg újra." msgstr "Nem sikerült ellenőrizni a kódot. Kérjük, próbálja meg újra."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funkciók" msgstr "Funkciók"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Előnézet" msgstr "Előnézet"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Az előnézet és az exportálás a legutóbbi érvényes verziót használja." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Olvasás…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Aktiválásra kész" msgstr "Aktiválásra kész"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Aktiválásra kész, figyelmeztetésekkel" msgstr "Aktiválásra kész, figyelmeztetésekkel"
@@ -3663,10 +3669,6 @@ msgstr "Visszaállítás"
msgid "Reset Password" msgid "Reset Password"
msgstr "Jelszó visszaállítása" msgstr "Jelszó visszaállítása"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Visszaállítás az alkalmazott stíluslapra"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Jelszó visszaállítása" msgstr "Jelszó visszaállítása"
@@ -4195,6 +4197,10 @@ msgstr "Egyes jelentkezési rendszereknek szüksége van egy ilyenre a benyújt
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Egyes elemzők rosszul kezelik a képeket, és egyes régiókban nem javasoljuk a fotók használatát." msgstr "Egyes elemzők rosszul kezelik a képeket, és egyes régiókban nem javasoljuk a fotók használatát."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Valami rosszul sült el" msgstr "Valami rosszul sült el"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Stíluslap-szerkesztő" msgstr "Stíluslap-szerkesztő"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "A stíluslap hibákat tartalmaz" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Felhasználók"
msgid "Uzbek" msgid "Uzbek"
msgstr "üzbég" msgstr "üzbég"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Az érvényes URL http:// vagy https:// előtaggal kezdődik." msgstr "Az érvényes URL http:// vagy https:// előtaggal kezdődik."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Kicsinyítés"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Lamaran dikirim per minggu (8 minggu terakhir)" msgstr "Lamaran dikirim per minggu (8 minggu terakhir)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Dilamar" msgstr "Dilamar"
@@ -534,10 +533,6 @@ msgstr "Dilamar"
msgid "Applied on" msgid "Applied on"
msgstr "Dilamar pada" msgstr "Dilamar pada"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Diterapkan dengan peringatan"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arab" msgstr "Arab"
@@ -1765,7 +1760,6 @@ msgstr "Masukkan kata sandi Anda untuk mengonfirmasi penyiapan autentikasi dua f
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Masukkan kata sandi Anda untuk menonaktifkan autentikasi dua faktor. Akun Anda akan menjadi kurang aman tanpa 2FA diaktifkan." msgstr "Masukkan kata sandi Anda untuk menonaktifkan autentikasi dua faktor. Akun Anda akan menjadi kurang aman tanpa 2FA diaktifkan."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Kesalahan" msgstr "Kesalahan"
@@ -2003,6 +1997,10 @@ msgstr "Gagal memverifikasi kode cadangan Anda. Silakan coba lagi."
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Gagal memverifikasi kode Anda. Silakan coba lagi." msgstr "Gagal memverifikasi kode Anda. Silakan coba lagi."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Fitur" msgstr "Fitur"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Pratinjau" msgstr "Pratinjau"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Pratinjau dan ekspor menggunakan versi valid terakhir." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Membaca…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Siap diaktifkan" msgstr "Siap diaktifkan"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Siap diaktifkan dengan peringatan" msgstr "Siap diaktifkan dengan peringatan"
@@ -3663,10 +3669,6 @@ msgstr "Atur Ulang"
msgid "Reset Password" msgid "Reset Password"
msgstr "Atur Ulang Kata Sandi" msgstr "Atur Ulang Kata Sandi"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Atur ulang ke stylesheet yang diterapkan"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Atur ulang kata sandi Anda" msgstr "Atur ulang kata sandi Anda"
@@ -4195,6 +4197,10 @@ msgstr "Beberapa sistem lamaran memerlukannya sebelum Anda dapat mengirimkannya.
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Beberapa parser salah menangani gambar, dan foto tidak disarankan di beberapa wilayah." msgstr "Beberapa parser salah menangani gambar, dan foto tidak disarankan di beberapa wilayah."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Terjadi kesalahan." msgstr "Terjadi kesalahan."
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Editor lembar gaya" msgstr "Editor lembar gaya"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Stylesheet memiliki kesalahan" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Pengguna"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbek" msgstr "Uzbek"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "URL yang valid harus dimulai dengan http:// atau https://." msgstr "URL yang valid harus dimulai dengan http:// atau https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Perkecil"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Candidature inviate a settimana (ultime 8 settimane)" msgstr "Candidature inviate a settimana (ultime 8 settimane)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Candidatura inviata" msgstr "Candidatura inviata"
@@ -534,10 +533,6 @@ msgstr "Candidatura inviata"
msgid "Applied on" msgid "Applied on"
msgstr "Candidatura inviata il" msgstr "Candidatura inviata il"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Applicato con avvertenze"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabo" msgstr "Arabo"
@@ -1765,7 +1760,6 @@ msgstr "Inserisci la tua password per confermare la configurazione dell'autentic
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Inserisci la tua password per disabilitare l'autenticazione a due fattori. Il tuo account sarà meno sicuro senza 2FA attiva." msgstr "Inserisci la tua password per disabilitare l'autenticazione a due fattori. Il tuo account sarà meno sicuro senza 2FA attiva."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Errore" msgstr "Errore"
@@ -2003,6 +1997,10 @@ msgstr "Impossibile verificare il suo codice di backup. Provi di nuovo."
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Non è stato possibile verificare il suo codice. La preghiamo di riprovare." msgstr "Non è stato possibile verificare il suo codice. La preghiamo di riprovare."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funzionalità" msgstr "Funzionalità"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Anteprima" msgstr "Anteprima"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "L'anteprima e l'esportazione utilizzano l'ultima versione valida." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Lettura…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Pronto per l'attivazione" msgstr "Pronto per l'attivazione"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Pronto per l'attivazione con avvisi" msgstr "Pronto per l'attivazione con avvisi"
@@ -3663,10 +3669,6 @@ msgstr "Ripristina"
msgid "Reset Password" msgid "Reset Password"
msgstr "Reimposta password" msgstr "Reimposta password"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Ripristina il foglio di stile applicato"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Reimposta la tua password" msgstr "Reimposta la tua password"
@@ -4195,6 +4197,10 @@ msgstr "Alcuni sistemi di candidatura ne richiedono uno prima di poter inviare."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Alcuni parser gestiscono male le immagini e le foto sono sconsigliate in alcune regioni." msgstr "Alcuni parser gestiscono male le immagini e le foto sono sconsigliate in alcune regioni."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Qualcosa è andato storto" msgstr "Qualcosa è andato storto"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Editor di fogli di stile" msgstr "Editor di fogli di stile"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Il foglio di stile presenta degli errori" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Utenti"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbeco" msgstr "Uzbeco"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Gli URL validi devono iniziare con http:// o https://." msgstr "Gli URL validi devono iniziare con http:// o https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Gateway Vercel AI" msgstr "Gateway Vercel AI"
@@ -5411,4 +5429,3 @@ msgstr "Rimpicciolisci"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "週ごとの応募送信数(直近8週間)" msgstr "週ごとの応募送信数(直近8週間)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "応募済み" msgstr "応募済み"
@@ -534,10 +533,6 @@ msgstr "応募済み"
msgid "Applied on" msgid "Applied on"
msgstr "応募日" msgstr "応募日"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "警告付きで適用"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "アラビア語" msgstr "アラビア語"
@@ -1765,7 +1760,6 @@ msgstr "二要素認証を設定することを確定するために、パスワ
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "二要素認証を無効にするには、パスワードを入力してください。2FA を無効化すると、アカウントのセキュリティレベルは下がります。" msgstr "二要素認証を無効にするには、パスワードを入力してください。2FA を無効化すると、アカウントのセキュリティレベルは下がります。"
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "エラー" msgstr "エラー"
@@ -2003,6 +1997,10 @@ msgstr "バックアップコードの検証に失敗しました。もう一度
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "コードの検証に失敗しました。もう一度やり直してください。" msgstr "コードの検証に失敗しました。もう一度やり直してください。"
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "機能" msgstr "機能"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "プレビュー" msgstr "プレビュー"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "プレビューとエクスポートには、最新の有効なバージョンを使用してください。" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "読み込み中…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "起動準備完了" msgstr "起動準備完了"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "警告付きで有効化準備完了" msgstr "警告付きで有効化準備完了"
@@ -3663,10 +3669,6 @@ msgstr "リセット"
msgid "Reset Password" msgid "Reset Password"
msgstr "パスワードをリセット" msgstr "パスワードをリセット"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "適用済みのスタイルシートにリセットします"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "パスワードをリセット" msgstr "パスワードをリセット"
@@ -4195,6 +4197,10 @@ msgstr "一部のアプリケーション システムでは、送信する前
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "一部のパーサーは画像を誤って処理するため、一部の地域では写真の使用が推奨されません。" msgstr "一部のパーサーは画像を誤って処理するため、一部の地域では写真の使用が推奨されません。"
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "何らかの問題が発生しました" msgstr "何らかの問題が発生しました"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "スタイルシートエディタ" msgstr "スタイルシートエディタ"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "スタイルシートにエラーがあります" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "ユーザー数"
msgid "Uzbek" msgid "Uzbek"
msgstr "ウズベク語" msgstr "ウズベク語"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "有効な URL は http:// または https:// で始まる必要があります。" msgstr "有効な URL は http:// または https:// で始まる必要があります。"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "ズームアウト"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "ズールー語" msgstr "ズールー語"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "ពាក្យសុំបានផ្ញើក្នុងមួយសប្តាហ៍ (៨ សប្តាហ៍ចុងក្រោយ)" msgstr "ពាក្យសុំបានផ្ញើក្នុងមួយសប្តាហ៍ (៨ សប្តាហ៍ចុងក្រោយ)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "បានដាក់ពាក្យ" msgstr "បានដាក់ពាក្យ"
@@ -534,10 +533,6 @@ msgstr "បានដាក់ពាក្យ"
msgid "Applied on" msgid "Applied on"
msgstr "បានដាក់ពាក្យនៅ" msgstr "បានដាក់ពាក្យនៅ"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "អនុវត្តជាមួយការព្រមាន"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabic" msgstr "Arabic"
@@ -1765,7 +1760,6 @@ msgstr "បញ្ចូល​ពាក្យសម្ងាត់​របស់
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "បញ្ចូល​ពាក្យសម្ងាត់​របស់​អ្នក ដើម្បី​បិទ​ការ​ផ្ទៀងផ្ទាត់​ពីរ​ជាន់។ គណនី​របស់​អ្នក​នឹង​កាន់តែ​មាន​ហានិភ័យ​នៅពេល​មិន​បាន​បើក 2FA ទៀត។" msgstr "បញ្ចូល​ពាក្យសម្ងាត់​របស់​អ្នក ដើម្បី​បិទ​ការ​ផ្ទៀងផ្ទាត់​ពីរ​ជាន់។ គណនី​របស់​អ្នក​នឹង​កាន់តែ​មាន​ហានិភ័យ​នៅពេល​មិន​បាន​បើក 2FA ទៀត។"
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "កំហុស" msgstr "កំហុស"
@@ -2003,6 +1997,10 @@ msgstr "បរាជ័យក្នុងការផ្ទៀងផ្ទាត
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "បរាជ័យក្នុងការផ្ទៀងផ្ទាត់កូដរបស់អ្នក។ សូមព្យាយាមម្ដងទៀត។" msgstr "បរាជ័យក្នុងការផ្ទៀងផ្ទាត់កូដរបស់អ្នក។ សូមព្យាយាមម្ដងទៀត។"
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "មុខងារ" msgstr "មុខងារ"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "មើលជាមុន" msgstr "មើលជាមុន"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "ការមើលជាមុន និងការនាំចេញប្រើប្រាស់កំណែដែលមានសុពលភាពចុងក្រោយ។" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "កំពុងអាន…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "រួចរាល់ដើម្បីធ្វើឱ្យសកម្ម" msgstr "រួចរាល់ដើម្បីធ្វើឱ្យសកម្ម"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "រួចរាល់ដើម្បីធ្វើឲ្យសកម្មជាមួយនឹងការព្រមាន" msgstr "រួចរាល់ដើម្បីធ្វើឲ្យសកម្មជាមួយនឹងការព្រមាន"
@@ -3663,10 +3669,6 @@ msgstr "កំណត់​ឡើងវិញ"
msgid "Reset Password" msgid "Reset Password"
msgstr "កំណត់​ពាក្យសម្ងាត់​ឡើងវិញ" msgstr "កំណត់​ពាក្យសម្ងាត់​ឡើងវិញ"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "កំណត់ឡើងវិញទៅសន្លឹករចនាប័ទ្មដែលបានអនុវត្ត"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "កំណត់​ពាក្យសម្ងាត់​របស់​អ្នក​ឡើងវិញ" msgstr "កំណត់​ពាក្យសម្ងាត់​របស់​អ្នក​ឡើងវិញ"
@@ -4195,6 +4197,10 @@ msgstr "ប្រព័ន្ធ​កម្មវិធី​មួយ​ចំ
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "ឧបករណ៍ញែកមួយចំនួនធ្វើឱ្យរូបភាពមិនត្រឹមត្រូវ ហើយរូបថតត្រូវបានលើកទឹកចិត្តនៅក្នុងតំបន់មួយចំនួន។" msgstr "ឧបករណ៍ញែកមួយចំនួនធ្វើឱ្យរូបភាពមិនត្រឹមត្រូវ ហើយរូបថតត្រូវបានលើកទឹកចិត្តនៅក្នុងតំបន់មួយចំនួន។"
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "មានអ្វីមួយខុសប្រក្រតី" msgstr "មានអ្វីមួយខុសប្រក្រតី"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "កម្មវិធីនិពន្ធសន្លឹករចនាប័ទ្ម" msgstr "កម្មវិធីនិពន្ធសន្លឹករចនាប័ទ្ម"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "សន្លឹករចនាប័ទ្មមានកំហុស" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "អ្នកប្រើ"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbek" msgstr "Uzbek"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "URL ត្រឹមត្រូវ ត្រូវតែ​ចាប់ផ្តើម​ដោយ http:// ឬ https://។" msgstr "URL ត្រឹមត្រូវ ត្រូវតែ​ចាប់ផ្តើម​ដោយ http:// ឬ https://។"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "បង្រួម"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "ಪ್ರತಿ ವಾರ ಕಳುಹಿಸಿದ ಅರ್ಜಿಗಳು (ಕೊನೆಯ 8 ವಾರಗಳು)" msgstr "ಪ್ರತಿ ವಾರ ಕಳುಹಿಸಿದ ಅರ್ಜಿಗಳು (ಕೊನೆಯ 8 ವಾರಗಳು)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "ಅರ್ಜಿಸಲಾಗಿದೆ" msgstr "ಅರ್ಜಿಸಲಾಗಿದೆ"
@@ -534,10 +533,6 @@ msgstr "ಅರ್ಜಿಸಲಾಗಿದೆ"
msgid "Applied on" msgid "Applied on"
msgstr "ಅರ್ಜಿ ಸಲ್ಲಿಸಿದ ದಿನಾಂಕ" msgstr "ಅರ್ಜಿ ಸಲ್ಲಿಸಿದ ದಿನಾಂಕ"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "ಎಚ್ಚರಿಕೆಗಳೊಂದಿಗೆ ಅನ್ವಯಿಸಲಾಗಿದೆ"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "ಅರೇಬಿಕ್" msgstr "ಅರೇಬಿಕ್"
@@ -1765,7 +1760,6 @@ msgstr "ಎರಡು ಅಂಶಗಳ ದೃಢೀಕರಣವನ್ನು ಹೊ
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "ಎರಡು ಅಂಶಗಳ ದೃಢೀಕರಣವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ನಮೂದಿಸಿ. 2FA ಸಕ್ರಿಯಗೊಳಿಸದಿದ್ದರೆ ನಿಮ್ಮ ಖಾತೆ ಕಡಿಮೆ ಸುರಕ್ಷಿತವಾಗಿರುತ್ತದೆ." msgstr "ಎರಡು ಅಂಶಗಳ ದೃಢೀಕರಣವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ನಮೂದಿಸಿ. 2FA ಸಕ್ರಿಯಗೊಳಿಸದಿದ್ದರೆ ನಿಮ್ಮ ಖಾತೆ ಕಡಿಮೆ ಸುರಕ್ಷಿತವಾಗಿರುತ್ತದೆ."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "ದೋಷ" msgstr "ದೋಷ"
@@ -2003,6 +1997,10 @@ msgstr "ನಿಮ್ಮ ಬ್ಯಾಕಪ್ ಕೋಡ್ ಅನ್ನು ಪ
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "ನಿಮ್ಮ ಕೋಡ್ ಅನ್ನು ಪರಿಶೀಲಿಸಲು ವಿಫಲವಾಗಿದೆ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ." msgstr "ನಿಮ್ಮ ಕೋಡ್ ಅನ್ನು ಪರಿಶೀಲಿಸಲು ವಿಫಲವಾಗಿದೆ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "ವೈಶಿಷ್ಟ್ಯಗಳು" msgstr "ವೈಶಿಷ್ಟ್ಯಗಳು"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "ಪೂರ್ವವೀಕ್ಷಣೆ" msgstr "ಪೂರ್ವವೀಕ್ಷಣೆ"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "ಕೊನೆಯ ಮಾನ್ಯ ಆವೃತ್ತಿಯನ್ನು ಬಳಸಿಕೊಂಡು ಪೂರ್ವವೀಕ್ಷಣೆ ಮತ್ತು ರಫ್ತು ಮಾಡಿ." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "ಓದುತ್ತಿದೆ…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "ಸಕ್ರಿಯಗೊಳಿಸಲು ಸಿದ್ಧವಾಗಿದೆ" msgstr "ಸಕ್ರಿಯಗೊಳಿಸಲು ಸಿದ್ಧವಾಗಿದೆ"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "ಎಚ್ಚರಿಕೆಗಳೊಂದಿಗೆ ಸಕ್ರಿಯಗೊಳಿಸಲು ಸಿದ್ಧವಾಗಿದೆ" msgstr "ಎಚ್ಚರಿಕೆಗಳೊಂದಿಗೆ ಸಕ್ರಿಯಗೊಳಿಸಲು ಸಿದ್ಧವಾಗಿದೆ"
@@ -3663,10 +3669,6 @@ msgstr "ಮರುಹೊಂದಿಸಿ"
msgid "Reset Password" msgid "Reset Password"
msgstr "ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಮರುಹೊಂದಿಸಿ" msgstr "ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಮರುಹೊಂದಿಸಿ"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "ಅನ್ವಯಿಸಲಾದ ಸ್ಟೈಲ್‌ಶೀಟ್‌ಗೆ ಮರುಹೊಂದಿಸಿ"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಮರುಹೊಂದಿಸಿ" msgstr "ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಮರುಹೊಂದಿಸಿ"
@@ -4195,6 +4197,10 @@ msgstr "ನೀವು ಸಲ್ಲಿಸುವ ಮೊದಲು ಕೆಲವು
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "ಕೆಲವು ಪಾರ್ಸರ್‌ಗಳು ಚಿತ್ರಗಳನ್ನು ತಪ್ಪಾಗಿ ನಿರ್ವಹಿಸುತ್ತವೆ ಮತ್ತು ಕೆಲವು ಪ್ರದೇಶಗಳಲ್ಲಿ ಫೋಟೋಗಳನ್ನು ನಿರುತ್ಸಾಹಗೊಳಿಸಲಾಗುತ್ತದೆ." msgstr "ಕೆಲವು ಪಾರ್ಸರ್‌ಗಳು ಚಿತ್ರಗಳನ್ನು ತಪ್ಪಾಗಿ ನಿರ್ವಹಿಸುತ್ತವೆ ಮತ್ತು ಕೆಲವು ಪ್ರದೇಶಗಳಲ್ಲಿ ಫೋಟೋಗಳನ್ನು ನಿರುತ್ಸಾಹಗೊಳಿಸಲಾಗುತ್ತದೆ."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "ಏನೋ ತಪ್ಪಾಗಿದೆ." msgstr "ಏನೋ ತಪ್ಪಾಗಿದೆ."
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "ಸ್ಟೈಲ್‌ಶೀಟ್ ಸಂಪಾದಕ" msgstr "ಸ್ಟೈಲ್‌ಶೀಟ್ ಸಂಪಾದಕ"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "ಸ್ಟೈಲ್‌ಶೀಟ್ ದೋಷಗಳನ್ನು ಹೊಂದಿದೆ." msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "ಬಳಕೆದಾರರು"
msgid "Uzbek" msgid "Uzbek"
msgstr "ಉಜ್ಬೇಕ್" msgstr "ಉಜ್ಬೇಕ್"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "ಮಾನ್ಯ URL ಗಳು http:// ಅಥವಾ https:// ನಿಂದ ಪ್ರಾರಂಭವಾಗಿರಬೇಕು." msgstr "ಮಾನ್ಯ URL ಗಳು http:// ಅಥವಾ https:// ನಿಂದ ಪ್ರಾರಂಭವಾಗಿರಬೇಕು."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "ಗಾತ್ರ ಕುಗ್ಗಿಸಿ"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "ಜೂಲೂ" msgstr "ಜೂಲೂ"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "주당 보낸 지원서 (최근 8주)" msgstr "주당 보낸 지원서 (최근 8주)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "지원함" msgstr "지원함"
@@ -534,10 +533,6 @@ msgstr "지원함"
msgid "Applied on" msgid "Applied on"
msgstr "지원일" msgstr "지원일"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "경고와 함께 적용됨"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "아랍어" msgstr "아랍어"
@@ -1765,7 +1760,6 @@ msgstr "2단계 인증을 설정하려면 비밀번호를 입력해 확인하세
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "2단계 인증을 비활성화하려면 비밀번호를 입력하세요. 2단계 인증을 사용하지 않으면 계정 보안이 낮아집니다." msgstr "2단계 인증을 비활성화하려면 비밀번호를 입력하세요. 2단계 인증을 사용하지 않으면 계정 보안이 낮아집니다."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "오류" msgstr "오류"
@@ -2003,6 +1997,10 @@ msgstr "백업 코드를 인증하지 못했습니다. 다시 시도해 주세
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "코드를 인증하지 못했습니다. 다시 시도해 주세요." msgstr "코드를 인증하지 못했습니다. 다시 시도해 주세요."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "기능" msgstr "기능"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "시사" msgstr "시사"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "미리보기 및 내보내기 시에는 마지막으로 유효한 버전을 사용합니다." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "읽는 중…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "활성화 준비 완료" msgstr "활성화 준비 완료"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "경고 메시지와 함께 활성화할 준비가 되었습니다." msgstr "경고 메시지와 함께 활성화할 준비가 되었습니다."
@@ -3663,10 +3669,6 @@ msgstr "초기화"
msgid "Reset Password" msgid "Reset Password"
msgstr "비밀번호 재설정" msgstr "비밀번호 재설정"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "적용된 스타일시트로 재설정"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "비밀번호 재설정" msgstr "비밀번호 재설정"
@@ -4195,6 +4197,10 @@ msgstr "일부 지원 시스템에서는 제출하기 전에 하나의 정보가
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "일부 파서는 이미지를 잘못 처리하므로 일부 지역에서는 사진을 사용하지 않는 것이 좋습니다." msgstr "일부 파서는 이미지를 잘못 처리하므로 일부 지역에서는 사진을 사용하지 않는 것이 좋습니다."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "뭔가 잘못됐어요" msgstr "뭔가 잘못됐어요"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "스타일시트 편집기" msgstr "스타일시트 편집기"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "스타일시트에 오류가 있습니다" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "사용자 수"
msgid "Uzbek" msgid "Uzbek"
msgstr "우즈베크어" msgstr "우즈베크어"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "유효한 URL은 http:// 또는 https://로 시작해야 합니다." msgstr "유효한 URL은 http:// 또는 https://로 시작해야 합니다."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "버셀 AI 게이트웨이" msgstr "버셀 AI 게이트웨이"
@@ -5411,4 +5429,3 @@ msgstr "축소"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "줄루어" msgstr "줄루어"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Per savaitę išsiųstos paraiškos (paskutinės 8 savaitės)" msgstr "Per savaitę išsiųstos paraiškos (paskutinės 8 savaitės)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Pateikta" msgstr "Pateikta"
@@ -534,10 +533,6 @@ msgstr "Pateikta"
msgid "Applied on" msgid "Applied on"
msgstr "Pateikta" msgstr "Pateikta"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Taikoma su įspėjimais"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabų" msgstr "Arabų"
@@ -1765,7 +1760,6 @@ msgstr "Įveskite slaptažodį, kad patvirtintumėte dviejų veiksnių tapatumo
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Įveskite slaptažodį, kad išjungtumėte dviejų veiksnių tapatumo patvirtinimą. Be įjungto 2FA jūsų paskyra bus mažiau saugi." msgstr "Įveskite slaptažodį, kad išjungtumėte dviejų veiksnių tapatumo patvirtinimą. Be įjungto 2FA jūsų paskyra bus mažiau saugi."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Klaida" msgstr "Klaida"
@@ -2003,6 +1997,10 @@ msgstr "Nepavyko patikrinti atsarginės kopijos kodo. Bandykite dar kartą."
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Nepavyko patikrinti jūsų kodo. Bandykite dar kartą." msgstr "Nepavyko patikrinti jūsų kodo. Bandykite dar kartą."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funkcijos" msgstr "Funkcijos"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Peržiūra" msgstr "Peržiūra"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Peržiūrai ir eksportui naudokite paskutinę galiojančią versiją." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Skaitoma…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Paruošta aktyvuoti" msgstr "Paruošta aktyvuoti"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Paruošta aktyvuoti su įspėjimais" msgstr "Paruošta aktyvuoti su įspėjimais"
@@ -3663,10 +3669,6 @@ msgstr "Nustatyti iš naujo"
msgid "Reset Password" msgid "Reset Password"
msgstr "Atkurti slaptažodį" msgstr "Atkurti slaptažodį"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Atkurti pritaikytą stiliaus lapą"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Atkurkite slaptažodį" msgstr "Atkurkite slaptažodį"
@@ -4195,6 +4197,10 @@ msgstr "Kai kurioms paraiškų teikimo sistemoms reikia, kad galėtumėte pateik
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Kai kurie analizatoriai netinkamai tvarko vaizdus, o kai kuriuose regionuose nuotraukos nerekomenduojamos." msgstr "Kai kurie analizatoriai netinkamai tvarko vaizdus, o kai kuriuose regionuose nuotraukos nerekomenduojamos."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Kažkas nutiko ne taip" msgstr "Kažkas nutiko ne taip"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Stilių lapų redaktorius" msgstr "Stilių lapų redaktorius"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Stiliaus lape yra klaidų" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Vartotojai"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbekų" msgstr "Uzbekų"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Teisingi URL turi prasidėti http:// arba https://." msgstr "Teisingi URL turi prasidėti http:// arba https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "\"Vercel AI Gateway" msgstr "\"Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Tolinti"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulų" msgstr "Zulų"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Nedēļā nosūtītie pieteikumi (pēdējās 8 nedēļas)" msgstr "Nedēļā nosūtītie pieteikumi (pēdējās 8 nedēļas)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Pieteikts" msgstr "Pieteikts"
@@ -534,10 +533,6 @@ msgstr "Pieteikts"
msgid "Applied on" msgid "Applied on"
msgstr "Pieteikts" msgstr "Pieteikts"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Pielietots ar brīdinājumiem"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arābu" msgstr "Arābu"
@@ -1765,7 +1760,6 @@ msgstr "Ievadiet savu paroli, lai apstiprinātu divu faktoru autentifikācijas i
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Ievadiet savu paroli, lai deaktivētu divu faktoru autentifikāciju. Bez ieslēgtas 2FA jūsu konts būs mazāk drošs." msgstr "Ievadiet savu paroli, lai deaktivētu divu faktoru autentifikāciju. Bez ieslēgtas 2FA jūsu konts būs mazāk drošs."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Kļūda" msgstr "Kļūda"
@@ -2003,6 +1997,10 @@ msgstr "Neizdevās pārbaudīt jūsu dublējuma kodu. Lūdzu, mēģiniet vēlrei
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Jūsu kodu neizdevās pārbaudīt. Lūdzu, mēģiniet vēlreiz." msgstr "Jūsu kodu neizdevās pārbaudīt. Lūdzu, mēģiniet vēlreiz."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funkcijas" msgstr "Funkcijas"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Priekšskatījums" msgstr "Priekšskatījums"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Priekšskatījumā un eksportā tiek izmantota pēdējā derīgā versija." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Lasa…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Gatavs aktivizēšanai" msgstr "Gatavs aktivizēšanai"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Gatavs aktivizēšanai ar brīdinājumiem" msgstr "Gatavs aktivizēšanai ar brīdinājumiem"
@@ -3663,10 +3669,6 @@ msgstr "Atiestatīt"
msgid "Reset Password" msgid "Reset Password"
msgstr "Atiestatīt paroli" msgstr "Atiestatīt paroli"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Atiestatīt uz lietoto stila lapu"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Atiestatīt paroli" msgstr "Atiestatīt paroli"
@@ -4195,6 +4197,10 @@ msgstr "Dažām pieteikumu sistēmām tas ir nepieciešams, lai to varētu iesni
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Daži parsētāji nepareizi apstrādā attēlus, un dažos reģionos fotoattēli nav ieteicami." msgstr "Daži parsētāji nepareizi apstrādā attēlus, un dažos reģionos fotoattēli nav ieteicami."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Kaut kas nogāja greizi" msgstr "Kaut kas nogāja greizi"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Stilu lapu redaktors" msgstr "Stilu lapu redaktors"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Stilu lapā ir kļūdas" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Lietotāji"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbeku" msgstr "Uzbeku"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Derīgiem URL jāsākas ar http:// vai https://." msgstr "Derīgiem URL jāsākas ar http:// vai https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI vārtejas" msgstr "Vercel AI vārtejas"
@@ -5411,4 +5429,3 @@ msgstr "Tālināt"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "ആഴ്ചയിൽ അയച്ച അപേക്ഷകൾ (കഴിഞ്ഞ 8 ആഴ്ച)" msgstr "ആഴ്ചയിൽ അയച്ച അപേക്ഷകൾ (കഴിഞ്ഞ 8 ആഴ്ച)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "അപേക്ഷിച്ചു" msgstr "അപേക്ഷിച്ചു"
@@ -534,10 +533,6 @@ msgstr "അപേക്ഷിച്ചു"
msgid "Applied on" msgid "Applied on"
msgstr "പ്രയോഗിച്ചു" msgstr "പ്രയോഗിച്ചു"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "മുന്നറിയിപ്പുകൾ ഉപയോഗിച്ച് പ്രയോഗിച്ചു"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "അറബിക്" msgstr "അറബിക്"
@@ -1765,7 +1760,6 @@ msgstr "ടു‑ഫാക്ടർ ഓത്‌ന്റിക്കേഷൻ
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "ടു‑ഫാക്ടർ ഓത്‌ന്റിക്കേഷൻ അപ്രാപ്തമാക്കാൻ നിങ്ങളുടെ പാസ്‌വേഡ് നൽകുക. 2FA പ്രാപ്തമാക്കിയിട്ടില്ലാത്തതിനാൽ നിങ്ങളുടെ അക്കൗണ്ട് കുറച്ച് കുറവായി സുരക്ഷിതമായിവരും." msgstr "ടു‑ഫാക്ടർ ഓത്‌ന്റിക്കേഷൻ അപ്രാപ്തമാക്കാൻ നിങ്ങളുടെ പാസ്‌വേഡ് നൽകുക. 2FA പ്രാപ്തമാക്കിയിട്ടില്ലാത്തതിനാൽ നിങ്ങളുടെ അക്കൗണ്ട് കുറച്ച് കുറവായി സുരക്ഷിതമായിവരും."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "പിശക്" msgstr "പിശക്"
@@ -2003,6 +1997,10 @@ msgstr "നിങ്ങളുടെ ബാക്കപ്പ് കോഡ് പ
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "നിങ്ങളുടെ കോഡ് പരിശോധിക്കുന്നതിൽ പരാജയപ്പെട്ടു. ദയവായി വീണ്ടും ശ്രമിക്കുക." msgstr "നിങ്ങളുടെ കോഡ് പരിശോധിക്കുന്നതിൽ പരാജയപ്പെട്ടു. ദയവായി വീണ്ടും ശ്രമിക്കുക."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "സവിശേഷതകൾ" msgstr "സവിശേഷതകൾ"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "പ്രിവ്യൂ" msgstr "പ്രിവ്യൂ"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "അവസാനത്തെ സാധുവായ പതിപ്പ് ഉപയോഗിച്ച് പ്രിവ്യൂ ചെയ്ത് എക്സ്പോർട്ട് ചെയ്യുക." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "വായിക്കുന്നു..."
msgid "Ready to activate" msgid "Ready to activate"
msgstr "സജീവമാക്കാൻ തയ്യാറാണ്" msgstr "സജീവമാക്കാൻ തയ്യാറാണ്"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "മുന്നറിയിപ്പുകൾ നൽകി സജീവമാക്കാൻ തയ്യാറാണ്" msgstr "മുന്നറിയിപ്പുകൾ നൽകി സജീവമാക്കാൻ തയ്യാറാണ്"
@@ -3663,10 +3669,6 @@ msgstr "റീസെറ്റ് ചെയ്യുക"
msgid "Reset Password" msgid "Reset Password"
msgstr "പാസ്‌വേഡ് റീസെറ്റ് ചെയ്യുക" msgstr "പാസ്‌വേഡ് റീസെറ്റ് ചെയ്യുക"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "പ്രയോഗിച്ച സ്റ്റൈൽഷീറ്റിലേക്ക് പുനഃസജ്ജമാക്കുക"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "നിങ്ങളുടെ പാസ്‌വേഡ് റീസെറ്റ് ചെയ്യുക" msgstr "നിങ്ങളുടെ പാസ്‌വേഡ് റീസെറ്റ് ചെയ്യുക"
@@ -4195,6 +4197,10 @@ msgstr "നിങ്ങൾ സമർപ്പിക്കുന്നതിന
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "ചില പാഴ്‌സർമാർ ചിത്രങ്ങൾ തെറ്റായി കൈകാര്യം ചെയ്യുന്നു, ചില പ്രദേശങ്ങളിൽ ഫോട്ടോകൾ നിരുത്സാഹപ്പെടുത്തുന്നു." msgstr "ചില പാഴ്‌സർമാർ ചിത്രങ്ങൾ തെറ്റായി കൈകാര്യം ചെയ്യുന്നു, ചില പ്രദേശങ്ങളിൽ ഫോട്ടോകൾ നിരുത്സാഹപ്പെടുത്തുന്നു."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "എന്തോ കുഴപ്പം സംഭവിച്ചു." msgstr "എന്തോ കുഴപ്പം സംഭവിച്ചു."
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "സ്റ്റൈൽഷീറ്റ് എഡിറ്റർ" msgstr "സ്റ്റൈൽഷീറ്റ് എഡിറ്റർ"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "സ്റ്റൈൽഷീറ്റിൽ പിശകുകൾ ഉണ്ട്" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "യൂസർമാർ"
msgid "Uzbek" msgid "Uzbek"
msgstr "ഉസ്‌ബെക്ക്" msgstr "ഉസ്‌ബെക്ക്"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "സാധുവായ URL‑കൾ http:// അല്ലെങ്കിൽ https:// കൊണ്ട് ആരംഭിക്കണം." msgstr "സാധുവായ URL‑കൾ http:// അല്ലെങ്കിൽ https:// കൊണ്ട് ആരംഭിക്കണം."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "വെർസെൽ എഐ ഗേറ്റ്‌വേ" msgstr "വെർസെൽ എഐ ഗേറ്റ്‌വേ"
@@ -5411,4 +5429,3 @@ msgstr "സൂം ഔട്ട് ചെയ്യുക"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "സൂളു" msgstr "സൂളു"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "दर आठवड्याला पाठवलेले अर्ज (मागील 8 आठवडे)" msgstr "दर आठवड्याला पाठवलेले अर्ज (मागील 8 आठवडे)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "अर्ज केला" msgstr "अर्ज केला"
@@ -534,10 +533,6 @@ msgstr "अर्ज केला"
msgid "Applied on" msgid "Applied on"
msgstr "वर अर्ज केला" msgstr "वर अर्ज केला"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "इशाऱ्यांसह लागू केले"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "अरबी" msgstr "अरबी"
@@ -1765,7 +1760,6 @@ msgstr "दुहेरी घटक ओथेंटिकेशन सेटअ
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "दुहेरी घटक ओथेंटिकेशन अक्षम करण्यासाठी तुमचा पासवर्ड टाका. 2FA शिवाय तुमचे खाते कमी सुरक्षित राहील." msgstr "दुहेरी घटक ओथेंटिकेशन अक्षम करण्यासाठी तुमचा पासवर्ड टाका. 2FA शिवाय तुमचे खाते कमी सुरक्षित राहील."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "त्रुटी" msgstr "त्रुटी"
@@ -2003,6 +1997,10 @@ msgstr "आपला बॅकअप कोड पडताळणी करण
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "तुमचा कोड पडताळणी करण्यात अयशस्वी झाला. कृपया पुन्हा प्रयत्न करा." msgstr "तुमचा कोड पडताळणी करण्यात अयशस्वी झाला. कृपया पुन्हा प्रयत्न करा."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "वैशिष्ट्ये" msgstr "वैशिष्ट्ये"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "पूर्वावलोकन" msgstr "पूर्वावलोकन"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "पूर्वावलोकन आणि निर्यातीसाठी शेवटची वैध आवृत्ती वापरली जाते." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "वाचत आहे…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "सक्रिय करण्यासाठी तयार" msgstr "सक्रिय करण्यासाठी तयार"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "इशाऱ्यांसह सक्रिय करण्यास तयार" msgstr "इशाऱ्यांसह सक्रिय करण्यास तयार"
@@ -3663,10 +3669,6 @@ msgstr "रीसेट करा"
msgid "Reset Password" msgid "Reset Password"
msgstr "पासवर्ड रीसेट करा" msgstr "पासवर्ड रीसेट करा"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "लागू केलेल्या स्टाईलशीटवर रीसेट करा"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "तुमचा पासवर्ड रीसेट करा" msgstr "तुमचा पासवर्ड रीसेट करा"
@@ -4195,6 +4197,10 @@ msgstr "तुम्ही सबमिट करण्यापूर्वी
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "काही विश्लेषक प्रतिमांची चुकीची हाताळणी करतात आणि काही प्रदेशांमध्ये फोटोंना परावृत्त केले जाते." msgstr "काही विश्लेषक प्रतिमांची चुकीची हाताळणी करतात आणि काही प्रदेशांमध्ये फोटोंना परावृत्त केले जाते."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "काहीतरी चूक झाली." msgstr "काहीतरी चूक झाली."
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "स्टाईलशीट संपादक" msgstr "स्टाईलशीट संपादक"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "स्टाईलशीटमध्ये त्रुटी आहेत" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "वापरकर्ते"
msgid "Uzbek" msgid "Uzbek"
msgstr "उझबेक" msgstr "उझबेक"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "वैध URL ची सुरुवात http:// किंवा https:// ने होणे आवश्यक आहे." msgstr "वैध URL ची सुरुवात http:// किंवा https:// ने होणे आवश्यक आहे."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "व्हर्सेल एआय गेटवे" msgstr "व्हर्सेल एआय गेटवे"
@@ -5411,4 +5429,3 @@ msgstr "बाहेर झूम करा"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "झुलू" msgstr "झुलू"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Permohonan dihantar setiap minggu (8 minggu lepas)" msgstr "Permohonan dihantar setiap minggu (8 minggu lepas)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Dimohon" msgstr "Dimohon"
@@ -534,10 +533,6 @@ msgstr "Dimohon"
msgid "Applied on" msgid "Applied on"
msgstr "Digunakan pada" msgstr "Digunakan pada"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Digunakan dengan amaran"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Bahasa Arab" msgstr "Bahasa Arab"
@@ -1765,7 +1760,6 @@ msgstr "Masukkan kata laluan anda untuk mengesahkan penyediaan pengesahan dua fa
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Masukkan kata laluan anda untuk melumpuhkan pengesahan dua faktor. Akaun anda akan menjadi kurang selamat tanpa 2FA diaktifkan." msgstr "Masukkan kata laluan anda untuk melumpuhkan pengesahan dua faktor. Akaun anda akan menjadi kurang selamat tanpa 2FA diaktifkan."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Ralat" msgstr "Ralat"
@@ -2003,6 +1997,10 @@ msgstr "Gagal mengesahkan kod sandaran anda. Sila cuba lagi."
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Gagal mengesahkan kod anda. Sila cuba lagi." msgstr "Gagal mengesahkan kod anda. Sila cuba lagi."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Ciri" msgstr "Ciri"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Pratonton" msgstr "Pratonton"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Pratonton dan eksport gunakan versi terakhir yang sah." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Membaca…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Bersedia untuk diaktifkan" msgstr "Bersedia untuk diaktifkan"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Bersedia untuk diaktifkan dengan amaran" msgstr "Bersedia untuk diaktifkan dengan amaran"
@@ -3663,10 +3669,6 @@ msgstr "Tetapkan Semula"
msgid "Reset Password" msgid "Reset Password"
msgstr "Tetapkan Semula Kata Laluan" msgstr "Tetapkan Semula Kata Laluan"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Tetapkan semula kepada helaian gaya yang digunakan"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Tetapkan semula kata laluan anda" msgstr "Tetapkan semula kata laluan anda"
@@ -4195,6 +4197,10 @@ msgstr "Sesetengah sistem aplikasi memerlukan satu sebelum anda boleh menyerahka
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Sesetengah penghurai salah mengendalikan imej, dan foto tidak digalakkan di sesetengah wilayah." msgstr "Sesetengah penghurai salah mengendalikan imej, dan foto tidak digalakkan di sesetengah wilayah."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Ada yang tidak kena" msgstr "Ada yang tidak kena"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Editor helaian gaya" msgstr "Editor helaian gaya"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Helaian gaya mempunyai ralat" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Pengguna"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbek" msgstr "Uzbek"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "URL yang sah mesti bermula dengan http:// atau https://." msgstr "URL yang sah mesti bermula dengan http:// atau https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Pintu Gerbang AI Vercel" msgstr "Pintu Gerbang AI Vercel"
@@ -5411,4 +5429,3 @@ msgstr "Zum keluar"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "प्रति हप्ता पठाइएका आवेदनहरू (पछिल्ला 8 हप्ता)" msgstr "प्रति हप्ता पठाइएका आवेदनहरू (पछिल्ला 8 हप्ता)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "आवेदन गरियो" msgstr "आवेदन गरियो"
@@ -534,10 +533,6 @@ msgstr "आवेदन गरियो"
msgid "Applied on" msgid "Applied on"
msgstr "मा लागू गरियो" msgstr "मा लागू गरियो"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "चेतावनीहरू सहित लागू गरियो"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "अरबी" msgstr "अरबी"
@@ -1765,7 +1760,6 @@ msgstr "दुई-कारक प्रमाणीकरण सेटअप
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "दुई-कारक प्रमाणीकरण अक्षम गर्न आफ्नो पासवर्ड प्रविष्ट गर्नुहोस्। २FA सक्रिय नभएको अवस्थामा तपाईंको खाता कम सुरक्षित हुनेछ।" msgstr "दुई-कारक प्रमाणीकरण अक्षम गर्न आफ्नो पासवर्ड प्रविष्ट गर्नुहोस्। २FA सक्रिय नभएको अवस्थामा तपाईंको खाता कम सुरक्षित हुनेछ।"
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "त्रुटि" msgstr "त्रुटि"
@@ -2003,6 +1997,10 @@ msgstr "तपाईंको ब्याकअप कोड प्रमाण
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "तपाईंको कोड प्रमाणित गर्न असफल भयो। कृपया फेरि प्रयास गर्नुहोस्।" msgstr "तपाईंको कोड प्रमाणित गर्न असफल भयो। कृपया फेरि प्रयास गर्नुहोस्।"
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "विशेषताहरू" msgstr "विशेषताहरू"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "पूर्वावलोकन" msgstr "पूर्वावलोकन"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "पूर्वावलोकन र निर्यात अन्तिम मान्य संस्करण प्रयोग गर्नुहोस्।" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "पढ्दै…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "सक्रिय गर्न तयार छ" msgstr "सक्रिय गर्न तयार छ"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "चेतावनी सहित सक्रिय गर्न तयार" msgstr "चेतावनी सहित सक्रिय गर्न तयार"
@@ -3663,10 +3669,6 @@ msgstr "रिसेट गर्नुहोस्"
msgid "Reset Password" msgid "Reset Password"
msgstr "पासवर्ड रिसेट गर्नुहोस्" msgstr "पासवर्ड रिसेट गर्नुहोस्"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "लागू गरिएको शैली पानामा रिसेट गर्नुहोस्"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "तपाईंको पासवर्ड रिसेट गर्नुहोस्" msgstr "तपाईंको पासवर्ड रिसेट गर्नुहोस्"
@@ -4195,6 +4197,10 @@ msgstr "तपाईंले पेश गर्न सक्नु अघि
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "केही पार्सरहरूले तस्बिरहरूलाई गलत प्रयोग गर्छन्, र फोटोहरू केही क्षेत्रहरूमा निरुत्साहित हुन्छन्।" msgstr "केही पार्सरहरूले तस्बिरहरूलाई गलत प्रयोग गर्छन्, र फोटोहरू केही क्षेत्रहरूमा निरुत्साहित हुन्छन्।"
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "केही गडबड भयो।" msgstr "केही गडबड भयो।"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "स्टाइलसिट सम्पादक" msgstr "स्टाइलसिट सम्पादक"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "स्टाइलसिटमा त्रुटिहरू छन्" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "प्रयोगकर्ताहरू"
msgid "Uzbek" msgid "Uzbek"
msgstr "उज्बेक" msgstr "उज्बेक"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "मान्य URL http:// वा https:// बाट सुरु हुनुुपर्छ।" msgstr "मान्य URL http:// वा https:// बाट सुरु हुनुुपर्छ।"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "वर्सेल एआई गेटवे" msgstr "वर्सेल एआई गेटवे"
@@ -5411,4 +5429,3 @@ msgstr "जूम आउट"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "जुलु" msgstr "जुलु"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Sollicitaties per week verstuurd (laatste 8 weken)" msgstr "Sollicitaties per week verstuurd (laatste 8 weken)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Gesolliciteerd" msgstr "Gesolliciteerd"
@@ -534,10 +533,6 @@ msgstr "Gesolliciteerd"
msgid "Applied on" msgid "Applied on"
msgstr "Toegepast op" msgstr "Toegepast op"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Toegepast met waarschuwingen"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabisch" msgstr "Arabisch"
@@ -1765,7 +1760,6 @@ msgstr "Voer uw wachtwoord in om het instellen van tweestapsverificatie te beves
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Voer uw wachtwoord in om tweestapsverificatie uit te schakelen. Uw account is minder goed beveiligd zonder 2FA." msgstr "Voer uw wachtwoord in om tweestapsverificatie uit te schakelen. Uw account is minder goed beveiligd zonder 2FA."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Fout" msgstr "Fout"
@@ -2003,6 +1997,10 @@ msgstr "Het is niet gelukt om uw back-upcode te verifiëren. Probeer het opnieuw
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Het is niet gelukt om uw code te verifiëren. Probeer het opnieuw." msgstr "Het is niet gelukt om uw code te verifiëren. Probeer het opnieuw."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Functies" msgstr "Functies"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Voorbeeld" msgstr "Voorbeeld"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Voor het bekijken en exporteren wordt de laatst geldige versie gebruikt." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Lezen…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Klaar om te activeren" msgstr "Klaar om te activeren"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Klaar voor activering met waarschuwingen" msgstr "Klaar voor activering met waarschuwingen"
@@ -3663,10 +3669,6 @@ msgstr "Resetten"
msgid "Reset Password" msgid "Reset Password"
msgstr "Wachtwoord resetten" msgstr "Wachtwoord resetten"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Terugzetten naar toegepaste stijlblad"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Reset uw wachtwoord" msgstr "Reset uw wachtwoord"
@@ -4195,6 +4197,10 @@ msgstr "Sommige parsers verwerken afbeeldingen verkeerd en fotos worden in so
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Wissel de begin- en einddatum om." msgstr "Wissel de begin- en einddatum om."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Er is iets misgegaan." msgstr "Er is iets misgegaan."
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Stijlpagina-editor" msgstr "Stijlpagina-editor"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Het stylesheet bevat fouten." msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Gebruikers"
msgid "Uzbek" msgid "Uzbek"
msgstr "Oezbeeks" msgstr "Oezbeeks"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Geldige URL's moeten beginnen met http:// of https://." msgstr "Geldige URL's moeten beginnen met http:// of https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Uitzoomen"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Søknader sendt per uke (siste 8 uker)" msgstr "Søknader sendt per uke (siste 8 uker)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Søkt" msgstr "Søkt"
@@ -534,10 +533,6 @@ msgstr "Søkt"
msgid "Applied on" msgid "Applied on"
msgstr "Påført på" msgstr "Påført på"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Brukes med advarsler"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabisk" msgstr "Arabisk"
@@ -1765,7 +1760,6 @@ msgstr "Skriv inn passordet ditt for å bekrefte at du vil sette opp tofaktoraut
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Skriv inn passordet ditt for å deaktivere tofaktorautentisering. Kontoen din vil være mindre sikker uten aktivert 2FA." msgstr "Skriv inn passordet ditt for å deaktivere tofaktorautentisering. Kontoen din vil være mindre sikker uten aktivert 2FA."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Feil" msgstr "Feil"
@@ -2003,6 +1997,10 @@ msgstr "Kunne ikke bekrefte reservekoden din. Prøv igjen."
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Kunne ikke bekrefte koden din. Prøv igjen." msgstr "Kunne ikke bekrefte koden din. Prøv igjen."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funksjoner" msgstr "Funksjoner"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Forhåndsvisning" msgstr "Forhåndsvisning"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Forhåndsvisning og eksport med den siste gyldige versjonen." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Leser …"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Klar til å aktiveres" msgstr "Klar til å aktiveres"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Klar til aktivering med advarsler" msgstr "Klar til aktivering med advarsler"
@@ -3663,10 +3669,6 @@ msgstr "Tilbakestill"
msgid "Reset Password" msgid "Reset Password"
msgstr "Tilbakestill passord" msgstr "Tilbakestill passord"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Tilbakestill til brukt stilark"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Tilbakestill passordet ditt" msgstr "Tilbakestill passordet ditt"
@@ -4195,6 +4197,10 @@ msgstr "Noen søknadssystemer krever dette før du kan sende inn."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Noen parsere håndterer bilder dårlig, og bilder frarådes i enkelte regioner." msgstr "Noen parsere håndterer bilder dårlig, og bilder frarådes i enkelte regioner."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Noe gikk galt" msgstr "Noe gikk galt"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Stilarkredigeringsprogram" msgstr "Stilarkredigeringsprogram"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Stilarket inneholder feil" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Brukere"
msgid "Uzbek" msgid "Uzbek"
msgstr "Usbekisk" msgstr "Usbekisk"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Gyldige URL-er må starte med http:// eller https://." msgstr "Gyldige URL-er må starte med http:// eller https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Zoom ut"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "ପ୍ରତି ସପ୍ତାହରେ ପଠାଯାଇଥିବା ଆବେଦନ (ଗତ 8 ସପ୍ତାହ)" msgstr "ପ୍ରତି ସପ୍ତାହରେ ପଠାଯାଇଥିବା ଆବେଦନ (ଗତ 8 ସପ୍ତାହ)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "ଆବେଦନ କରାଯାଇଛି" msgstr "ଆବେଦନ କରାଯାଇଛି"
@@ -534,10 +533,6 @@ msgstr "ଆବେଦନ କରାଯାଇଛି"
msgid "Applied on" msgid "Applied on"
msgstr "ପ୍ରୟୋଗ ହୋଇଛି |" msgstr "ପ୍ରୟୋଗ ହୋଇଛି |"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "ଚେତାବନୀ ସହିତ ଲାଗୁ କରାଯାଇଛି"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "ଆରବୀ" msgstr "ଆରବୀ"
@@ -1765,7 +1760,6 @@ msgstr "ଦ୍ୱି-ଘଟକ ପରିଚୟ ପ୍ରମାଣିକରଣ
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "ଦ୍ୱି-ଘଟକ ପରିଚୟ ପ୍ରମାଣିକରଣ ଅସକ୍ରିୟ କରିବା ପାଇଁ ଆପଣଙ୍କ ପାସୱାର୍ଡ ପ୍ରବେଶ କରନ୍ତୁ। 2FA ସକ୍ରିୟ ନ ଥିଲେ ଆପଣଙ୍କ ଆକାଉଣ୍ଟ କମ୍ ସୁରକ୍ଷିତ ହେବ।" msgstr "ଦ୍ୱି-ଘଟକ ପରିଚୟ ପ୍ରମାଣିକରଣ ଅସକ୍ରିୟ କରିବା ପାଇଁ ଆପଣଙ୍କ ପାସୱାର୍ଡ ପ୍ରବେଶ କରନ୍ତୁ। 2FA ସକ୍ରିୟ ନ ଥିଲେ ଆପଣଙ୍କ ଆକାଉଣ୍ଟ କମ୍ ସୁରକ୍ଷିତ ହେବ।"
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "ତ୍ରୁଟି" msgstr "ତ୍ରୁଟି"
@@ -2003,6 +1997,10 @@ msgstr "ଆପଣଙ୍କ ବ୍ୟାକଅପ୍ କୋଡ୍ ସତ୍ୟା
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "ଆପଣଙ୍କ କୋଡ୍ ସତ୍ୟାପନ କରିବାରେ ବିଫଳ ହେଲା। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।" msgstr "ଆପଣଙ୍କ କୋଡ୍ ସତ୍ୟାପନ କରିବାରେ ବିଫଳ ହେଲା। ଦୟାକରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "ବିଶେଷତାଗୁଡିକ" msgstr "ବିଶେଷତାଗୁଡିକ"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "ପୂର୍ବାବଲୋକନ" msgstr "ପୂର୍ବାବଲୋକନ"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "ପୂର୍ବାବଲୋକନ ଏବଂ ରପ୍ତାନି ଶେଷ ବୈଧ ସଂସ୍କରଣ ବ୍ୟବହାର କରନ୍ତୁ।" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "ପ Reading ିବା…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "ସକ୍ରିୟ କରିବାକୁ ପ୍ରସ୍ତୁତ" msgstr "ସକ୍ରିୟ କରିବାକୁ ପ୍ରସ୍ତୁତ"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "ଚେତାବନୀ ସହିତ ସକ୍ରିୟ କରିବାକୁ ପ୍ରସ୍ତୁତ" msgstr "ଚେତାବନୀ ସହିତ ସକ୍ରିୟ କରିବାକୁ ପ୍ରସ୍ତୁତ"
@@ -3663,10 +3669,6 @@ msgstr "ରିସେଟ୍ କରନ୍ତୁ"
msgid "Reset Password" msgid "Reset Password"
msgstr "ପାସୱାର୍ଡ ରିସେଟ୍ କରନ୍ତୁ" msgstr "ପାସୱାର୍ଡ ରିସେଟ୍ କରନ୍ତୁ"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "ଲାଗୁ ହୋଇଥିବା ଷ୍ଟାଇଲସିଟକୁ ରିସେଟ୍ କରନ୍ତୁ"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "ଆପଣଙ୍କ ପାସୱାର୍ଡ ରିସେଟ୍ କରନ୍ତୁ" msgstr "ଆପଣଙ୍କ ପାସୱାର୍ଡ ରିସେଟ୍ କରନ୍ତୁ"
@@ -4195,6 +4197,10 @@ msgstr "କିଛି ଆବେଦନ ସିଷ୍ଟମ୍‌ରେ ଦାଖଲ
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "କିଛି ପାର୍ସର୍ ଚିତ୍ରକୁ ଠିକ୍‌ଭାବେ ପ୍ରକ୍ରିୟା କରିପାରେ ନାହିଁ, ଏବଂ କିଛି ଅଞ୍ଚଳରେ ଫଟୋ ନିରୁତ୍ସାହିତ କରାଯାଏ।" msgstr "କିଛି ପାର୍ସର୍ ଚିତ୍ରକୁ ଠିକ୍‌ଭାବେ ପ୍ରକ୍ରିୟା କରିପାରେ ନାହିଁ, ଏବଂ କିଛି ଅଞ୍ଚଳରେ ଫଟୋ ନିରୁତ୍ସାହିତ କରାଯାଏ।"
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "କିଛି ତ୍ରୁଟି ହୋଇଗଲା" msgstr "କିଛି ତ୍ରୁଟି ହୋଇଗଲା"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "ଷ୍ଟାଇଲସିଟ୍ ଏଡିଟର୍" msgstr "ଷ୍ଟାଇଲସିଟ୍ ଏଡିଟର୍"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "ଷ୍ଟାଇଲସିଟରେ ତ୍ରୁଟି ଅଛି" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "ଉପଯୋଗକର୍ତ୍ତାମାନେ"
msgid "Uzbek" msgid "Uzbek"
msgstr "ଉଜବେକ୍" msgstr "ଉଜବେକ୍"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "ବୈଧ URL http:// କିମ୍ବା https:// ସହ ଆରମ୍ଭ ହେବା ଉଚିତ।" msgstr "ବୈଧ URL http:// କିମ୍ବା https:// ସହ ଆରମ୍ଭ ହେବା ଉଚିତ।"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "ଜୁମ୍ ଆଉଟ୍ କରନ୍ତୁ"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "ଜୁଲୁ" msgstr "ଜୁଲୁ"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Aplikacje wysłane tygodniowo (ostatnie 8 tygodni)" msgstr "Aplikacje wysłane tygodniowo (ostatnie 8 tygodni)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Złożono aplikację" msgstr "Złożono aplikację"
@@ -534,10 +533,6 @@ msgstr "Złożono aplikację"
msgid "Applied on" msgid "Applied on"
msgstr "Zastosowano" msgstr "Zastosowano"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Zastosowano z ostrzeżeniami"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabski" msgstr "Arabski"
@@ -1765,7 +1760,6 @@ msgstr "Wprowadź hasło, aby potwierdzić konfigurację uwierzytelniania dwusk
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Wprowadź hasło, aby wyłączyć uwierzytelnianie dwuskładnikowe. Twoje konto będzie mniej bezpieczne bez włączonego 2FA." msgstr "Wprowadź hasło, aby wyłączyć uwierzytelnianie dwuskładnikowe. Twoje konto będzie mniej bezpieczne bez włączonego 2FA."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Błąd" msgstr "Błąd"
@@ -2003,6 +1997,10 @@ msgstr "Nie udało się zweryfikować kodu kopii zapasowej. Proszę spróbować
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Nie udało się zweryfikować kodu. Proszę spróbować ponownie." msgstr "Nie udało się zweryfikować kodu. Proszę spróbować ponownie."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funkcje" msgstr "Funkcje"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Zapowiedź" msgstr "Zapowiedź"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Podczas podglądu i eksportu użyj ostatniej ważnej wersji." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Czytanie…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Gotowy do aktywacji" msgstr "Gotowy do aktywacji"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Gotowy do aktywacji z ostrzeżeniami" msgstr "Gotowy do aktywacji z ostrzeżeniami"
@@ -3663,10 +3669,6 @@ msgstr "Zresetuj"
msgid "Reset Password" msgid "Reset Password"
msgstr "Zresetuj hasło" msgstr "Zresetuj hasło"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Resetuj do zastosowanego arkusza stylów"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Zresetuj swoje hasło" msgstr "Zresetuj swoje hasło"
@@ -4195,6 +4197,10 @@ msgstr "Niektóre systemy rekrutacyjne wymagają go przed wysłaniem zgłoszenia
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Niektóre parsery nieprawidłowo obsługują obrazy, a w niektórych regionach odradza się dodawanie zdjęć." msgstr "Niektóre parsery nieprawidłowo obsługują obrazy, a w niektórych regionach odradza się dodawanie zdjęć."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Coś poszło nie tak" msgstr "Coś poszło nie tak"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Edytor arkuszy stylów" msgstr "Edytor arkuszy stylów"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Arkusz stylów zawiera błędy" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Użytkownicy"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbecki" msgstr "Uzbecki"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Prawidłowe adresy URL muszą zaczynać się od http:// lub https://." msgstr "Prawidłowe adresy URL muszą zaczynać się od http:// lub https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Pomniejsz"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Candidaturas enviadas por semana (últimas 8 semanas)" msgstr "Candidaturas enviadas por semana (últimas 8 semanas)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Aplicado" msgstr "Aplicado"
@@ -534,10 +533,6 @@ msgstr "Aplicado"
msgid "Applied on" msgid "Applied on"
msgstr "Aplicado em" msgstr "Aplicado em"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Aplicado com ressalvas."
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Árabe" msgstr "Árabe"
@@ -1765,7 +1760,6 @@ msgstr "Digite sua senha para confirmar a configuração da autenticação de do
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Digite sua senha para desativar a autenticação de dois fatores. Sua conta ficará menos segura sem o 2FA ativado." msgstr "Digite sua senha para desativar a autenticação de dois fatores. Sua conta ficará menos segura sem o 2FA ativado."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Erro" msgstr "Erro"
@@ -2003,6 +1997,10 @@ msgstr "Falha ao verificar seu código de backup. Tente novamente."
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Falha ao verificar seu código. Por favor, tente novamente." msgstr "Falha ao verificar seu código. Por favor, tente novamente."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Recursos" msgstr "Recursos"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Pré-visualização" msgstr "Pré-visualização"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "A pré-visualização e a exportação utilizam a última versão válida." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Lendo…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Pronto para ativar" msgstr "Pronto para ativar"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Pronto para ativar com avisos" msgstr "Pronto para ativar com avisos"
@@ -3663,10 +3669,6 @@ msgstr "Redefinir"
msgid "Reset Password" msgid "Reset Password"
msgstr "Redefinir senha" msgstr "Redefinir senha"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Redefinir para a folha de estilo aplicada"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Redefinir a sua senha" msgstr "Redefinir a sua senha"
@@ -4195,6 +4197,10 @@ msgstr "Alguns sistemas de candidatura exigem um número de telefone antes que v
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Alguns analisadores lidam mal com imagens, e fotos são desencorajadas em algumas regiões." msgstr "Alguns analisadores lidam mal com imagens, e fotos são desencorajadas em algumas regiões."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Algo deu errado" msgstr "Algo deu errado"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Editor de folhas de estilo" msgstr "Editor de folhas de estilo"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "A folha de estilo contém erros." msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Usuários"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbeque" msgstr "Uzbeque"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "URLs válidos devem começar com http:// ou https://." msgstr "URLs válidos devem começar com http:// ou https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Gateway de IA da Vercel" msgstr "Gateway de IA da Vercel"
@@ -5411,4 +5429,3 @@ msgstr "Diminuir zoom"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Candidaturas enviadas por semana (últimas 8 semanas)" msgstr "Candidaturas enviadas por semana (últimas 8 semanas)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Candidatura enviada" msgstr "Candidatura enviada"
@@ -534,10 +533,6 @@ msgstr "Candidatura enviada"
msgid "Applied on" msgid "Applied on"
msgstr "Aplicado em" msgstr "Aplicado em"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Aplicado com reservas."
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Árabe" msgstr "Árabe"
@@ -1765,7 +1760,6 @@ msgstr "Introduza a sua senha para confirmar a configuração da autenticação
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Introduza a sua senha para desativar a autenticação de dois fatores. A sua conta ficará menos segura sem a 2FA ativada." msgstr "Introduza a sua senha para desativar a autenticação de dois fatores. A sua conta ficará menos segura sem a 2FA ativada."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Erro" msgstr "Erro"
@@ -2003,6 +1997,10 @@ msgstr "Não foi possível verificar o seu código de cópia de segurança. Tent
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Não foi possível verificar o seu código. Por favor, tente novamente." msgstr "Não foi possível verificar o seu código. Por favor, tente novamente."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funcionalidades" msgstr "Funcionalidades"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Pré-visualização" msgstr "Pré-visualização"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "A pré-visualização e a exportação utilizam a última versão válida." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Leitura…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Pronto para ativar" msgstr "Pronto para ativar"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Pronto para ativar com avisos" msgstr "Pronto para ativar com avisos"
@@ -3663,10 +3669,6 @@ msgstr "Repor"
msgid "Reset Password" msgid "Reset Password"
msgstr "Repor senha" msgstr "Repor senha"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Repor para a folha de estilo aplicada"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Repor a sua senha" msgstr "Repor a sua senha"
@@ -4195,6 +4197,10 @@ msgstr "Alguns sistemas de inscrição exigem um antes que você possa enviar."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Alguns analisadores manipulam imagens incorretamente e as fotos são desencorajadas em algumas regiões." msgstr "Alguns analisadores manipulam imagens incorretamente e as fotos são desencorajadas em algumas regiões."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Algo correu mal" msgstr "Algo correu mal"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Editor de folhas de estilo" msgstr "Editor de folhas de estilo"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "A folha de estilos contém erros." msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Utilizadores"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbeque" msgstr "Uzbeque"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "URLs válidos devem começar por http:// ou https://." msgstr "URLs válidos devem começar por http:// ou https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Afastar"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Candidaturi trimise pe săptămână (ultimele 8 săptămâni)" msgstr "Candidaturi trimise pe săptămână (ultimele 8 săptămâni)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Candidatură trimisă" msgstr "Candidatură trimisă"
@@ -534,10 +533,6 @@ msgstr "Candidatură trimisă"
msgid "Applied on" msgid "Applied on"
msgstr "Aplicat pe" msgstr "Aplicat pe"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Aplicat cu avertismente"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabă" msgstr "Arabă"
@@ -1765,7 +1760,6 @@ msgstr "Introduceți parola pentru a confirma configurarea autentificării cu do
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Introduceți parola pentru a dezactiva autentificarea cu doi factori. Contul va fi mai puțin sigur fără 2FA activat." msgstr "Introduceți parola pentru a dezactiva autentificarea cu doi factori. Contul va fi mai puțin sigur fără 2FA activat."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Eroare" msgstr "Eroare"
@@ -2003,6 +1997,10 @@ msgstr "Nu s-a reușit verificarea codului dvs. de rezervă. Vă rugăm să înc
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Nu s-a reușit verificarea codului dvs. Vă rugăm să încercați din nou." msgstr "Nu s-a reușit verificarea codului dvs. Vă rugăm să încercați din nou."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funcționalități" msgstr "Funcționalități"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Previzualizare" msgstr "Previzualizare"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Previzualizarea și exportarea utilizează ultima versiune validă." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Lectură…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Gata de activare" msgstr "Gata de activare"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Gata de activare cu avertismente" msgstr "Gata de activare cu avertismente"
@@ -3663,10 +3669,6 @@ msgstr "Resetează"
msgid "Reset Password" msgid "Reset Password"
msgstr "Resetați parola" msgstr "Resetați parola"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Resetare la foaia de stil aplicată"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Resetați-vă parola" msgstr "Resetați-vă parola"
@@ -4195,6 +4197,10 @@ msgstr "Unele sisteme de aplicații necesită unul înainte de a putea trimite."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Unii analizatori gestionează greșit imaginile, iar fotografiile sunt descurajate în unele regiuni." msgstr "Unii analizatori gestionează greșit imaginile, iar fotografiile sunt descurajate în unele regiuni."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Ceva nu a mers bine" msgstr "Ceva nu a mers bine"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Editor de foi de stil" msgstr "Editor de foi de stil"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Foaia de stil conține erori" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Utilizatori"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbecă" msgstr "Uzbecă"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "URL-urile valide trebuie să înceapă cu http:// sau https://." msgstr "URL-urile valide trebuie să înceapă cu http:// sau https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Micșorează"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Заявки, отправленные за неделю (последние 8 недель)" msgstr "Заявки, отправленные за неделю (последние 8 недель)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Отклик отправлен" msgstr "Отклик отправлен"
@@ -534,10 +533,6 @@ msgstr "Отклик отправлен"
msgid "Applied on" msgid "Applied on"
msgstr "Применяется на" msgstr "Применяется на"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Применяется с предупреждениями."
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Арабский" msgstr "Арабский"
@@ -1765,7 +1760,6 @@ msgstr "Введите пароль, чтобы подтвердить наст
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Введите пароль, чтобы отключить двухфакторную аутентификацию. Без 2FA ваша учетная запись будет менее защищена." msgstr "Введите пароль, чтобы отключить двухфакторную аутентификацию. Без 2FA ваша учетная запись будет менее защищена."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Ошибка" msgstr "Ошибка"
@@ -2003,6 +1997,10 @@ msgstr "Не удалось проверить Ваш код резервног
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Не удалось проверить Ваш код. Пожалуйста, попробуйте еще раз." msgstr "Не удалось проверить Ваш код. Пожалуйста, попробуйте еще раз."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Возможности" msgstr "Возможности"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Предварительный просмотр" msgstr "Предварительный просмотр"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Для предварительного просмотра и экспорта используется последняя действующая версия." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Чтение…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Готово к активации" msgstr "Готово к активации"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Готов к активации с предупреждениями." msgstr "Готов к активации с предупреждениями."
@@ -3663,10 +3669,6 @@ msgstr "Сброс"
msgid "Reset Password" msgid "Reset Password"
msgstr "Сбросить пароль" msgstr "Сбросить пароль"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Сбросить до примененной таблицы стилей"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Сбросить пароль" msgstr "Сбросить пароль"
@@ -4195,6 +4197,10 @@ msgstr "Некоторые системы подачи заявок требую
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Некоторые парсеры неправильно обрабатывают изображения, а в некоторых регионах фотографии не рекомендуются." msgstr "Некоторые парсеры неправильно обрабатывают изображения, а в некоторых регионах фотографии не рекомендуются."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Что-то пошло не так." msgstr "Что-то пошло не так."
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Редактор таблиц стилей" msgstr "Редактор таблиц стилей"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "В таблице стилей обнаружены ошибки." msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Пользователи"
msgid "Uzbek" msgid "Uzbek"
msgstr "Узбекский" msgstr "Узбекский"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Корректные URL должны начинаться с http:// или https://." msgstr "Корректные URL должны начинаться с http:// или https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Уменьшить"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Зулу" msgstr "Зулу"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Žiadosti odoslané za týždeň (posledných 8 týždňov)" msgstr "Žiadosti odoslané za týždeň (posledných 8 týždňov)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Odoslané" msgstr "Odoslané"
@@ -534,10 +533,6 @@ msgstr "Odoslané"
msgid "Applied on" msgid "Applied on"
msgstr "Aplikované dňa" msgstr "Aplikované dňa"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Použité s upozorneniami"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabčina" msgstr "Arabčina"
@@ -1765,7 +1760,6 @@ msgstr "Zadaj svoje heslo na potvrdenie nastavenia dvojfaktorového overenia. Po
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Zadaj svoje heslo na vypnutie dvojfaktorového overenia. Bez zapnutého 2FA bude tvoj účet menej zabezpečený." msgstr "Zadaj svoje heslo na vypnutie dvojfaktorového overenia. Bez zapnutého 2FA bude tvoj účet menej zabezpečený."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Chyba" msgstr "Chyba"
@@ -2003,6 +1997,10 @@ msgstr "Nepodarilo sa overiť váš záložný kód. Skúste to prosím znova."
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Nepodarilo sa overiť váš kód. Skúste to prosím znova." msgstr "Nepodarilo sa overiť váš kód. Skúste to prosím znova."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funkcie" msgstr "Funkcie"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Náhľad" msgstr "Náhľad"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Pri ukážke a exporte sa použije posledná platná verzia." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Číta sa…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Pripravené na aktiváciu" msgstr "Pripravené na aktiváciu"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Pripravené na aktiváciu s upozorneniami" msgstr "Pripravené na aktiváciu s upozorneniami"
@@ -3663,10 +3669,6 @@ msgstr "Resetovať"
msgid "Reset Password" msgid "Reset Password"
msgstr "Obnoviť heslo" msgstr "Obnoviť heslo"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Obnoviť na použitý štýlový hárok"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Obnov svoje heslo" msgstr "Obnov svoje heslo"
@@ -4195,6 +4197,10 @@ msgstr "Niektoré aplikačné systémy vyžadujú pred odoslaním žiadosť."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Niektoré analyzátory nesprávne narábajú s obrázkami a v niektorých regiónoch sa fotografie neodporúčajú." msgstr "Niektoré analyzátory nesprávne narábajú s obrázkami a v niektorých regiónoch sa fotografie neodporúčajú."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Niečo sa pokazilo" msgstr "Niečo sa pokazilo"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Editor štýlov" msgstr "Editor štýlov"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Štýlový hárok obsahuje chyby" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Používatelia"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbečtina" msgstr "Uzbečtina"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Platné URL adresy musia začínať http:// alebo https://." msgstr "Platné URL adresy musia začínať http:// alebo https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Brána Vercel AI" msgstr "Brána Vercel AI"
@@ -5411,4 +5429,3 @@ msgstr "Oddialiť"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Prijave, poslane na teden (zadnjih 8 tednov)" msgstr "Prijave, poslane na teden (zadnjih 8 tednov)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Prijavljeno" msgstr "Prijavljeno"
@@ -534,10 +533,6 @@ msgstr "Prijavljeno"
msgid "Applied on" msgid "Applied on"
msgstr "Uporabljeno na" msgstr "Uporabljeno na"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Uporabljeno z opozorili"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabščina" msgstr "Arabščina"
@@ -1765,7 +1760,6 @@ msgstr "Vnesite svoje geslo, da potrdite nastavitev dvostopenjskega preverjanja
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Vnesite svoje geslo za onemogočanje dvostopenjskega preverjanja pristnosti. Vaš račun bo brez omogočenega 2FA manj varen." msgstr "Vnesite svoje geslo za onemogočanje dvostopenjskega preverjanja pristnosti. Vaš račun bo brez omogočenega 2FA manj varen."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Napaka" msgstr "Napaka"
@@ -2003,6 +1997,10 @@ msgstr "Varnostne kode ni uspelo preveriti. Poskusite znova."
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Ni uspelo preveriti vaše kode. Poskusite znova." msgstr "Ni uspelo preveriti vaše kode. Poskusite znova."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funkcionalnosti" msgstr "Funkcionalnosti"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Predogled" msgstr "Predogled"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Predogled in izvoz uporabljata zadnjo veljavno različico." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Branje ..."
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Pripravljeno za aktivacijo" msgstr "Pripravljeno za aktivacijo"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Pripravljeno za aktivacijo z opozorili" msgstr "Pripravljeno za aktivacijo z opozorili"
@@ -3663,10 +3669,6 @@ msgstr "Ponastavi"
msgid "Reset Password" msgid "Reset Password"
msgstr "Ponastavi geslo" msgstr "Ponastavi geslo"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Ponastavi na uporabljeno slogovno predlogo"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Ponastavite svoje geslo" msgstr "Ponastavite svoje geslo"
@@ -4195,6 +4197,10 @@ msgstr "Nekateri sistemi prijav zahtevajo, da jo lahko oddate."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Nekateri razčlenjevalniki napačno obravnavajo slike, zato fotografije v nekaterih regijah odsvetujejo." msgstr "Nekateri razčlenjevalniki napačno obravnavajo slike, zato fotografije v nekaterih regijah odsvetujejo."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Nekaj je šlo narobe" msgstr "Nekaj je šlo narobe"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Urejevalnik slogovnih predlog" msgstr "Urejevalnik slogovnih predlog"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Slogovna predloga vsebuje napake" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Uporabniki"
msgid "Uzbek" msgid "Uzbek"
msgstr "uzbeščina" msgstr "uzbeščina"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Veljavni URL-ji se morajo začeti z http:// ali https://." msgstr "Veljavni URL-ji se morajo začeti z http:// ali https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Oddalji"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zuluščina" msgstr "Zuluščina"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Aplikimet e dërguara për javë (8 javët e fundit)" msgstr "Aplikimet e dërguara për javë (8 javët e fundit)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Aplikuar" msgstr "Aplikuar"
@@ -534,10 +533,6 @@ msgstr "Aplikuar"
msgid "Applied on" msgid "Applied on"
msgstr "Aplikuar në" msgstr "Aplikuar në"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Zbatuar me paralajmërime"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabisht" msgstr "Arabisht"
@@ -1765,7 +1760,6 @@ msgstr "Shkruani fjalëkalimin tuaj për të konfirmuar konfigurimin e vërtetim
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Shkruani fjalëkalimin tuaj për të çaktivizuar vërtetimin me dy faktorë. Llogaria juaj do të jetë më pak e sigurt pa 2FA të aktivizuar." msgstr "Shkruani fjalëkalimin tuaj për të çaktivizuar vërtetimin me dy faktorë. Llogaria juaj do të jetë më pak e sigurt pa 2FA të aktivizuar."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Gabim" msgstr "Gabim"
@@ -2003,6 +1997,10 @@ msgstr "Dështoi verifikimi i kodit tuaj të rezervës. Ju lutemi provoni përs
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Dështoi verifikimi i kodit tuaj. Ju lutemi provoni përsëri." msgstr "Dështoi verifikimi i kodit tuaj. Ju lutemi provoni përsëri."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Veçori" msgstr "Veçori"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Pamje paraprake" msgstr "Pamje paraprake"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Parapamja dhe eksportimi përdorin versionin e fundit të vlefshëm." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Duke lexuar…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Gati për t'u aktivizuar" msgstr "Gati për t'u aktivizuar"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Gati për t'u aktivizuar me paralajmërime" msgstr "Gati për t'u aktivizuar me paralajmërime"
@@ -3663,10 +3669,6 @@ msgstr "Rivendos"
msgid "Reset Password" msgid "Reset Password"
msgstr "Rivendos fjalëkalimin" msgstr "Rivendos fjalëkalimin"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Rivendos në fletën e stilit të aplikuar"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Rivendosni fjalëkalimin tuaj" msgstr "Rivendosni fjalëkalimin tuaj"
@@ -4195,6 +4197,10 @@ msgstr "Disa sisteme aplikimi kërkojnë një para se të mund të dorëzoni."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Disa analizues i keqpërdorin imazhet dhe fotot dekurajohen në disa rajone." msgstr "Disa analizues i keqpërdorin imazhet dhe fotot dekurajohen në disa rajone."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Diçka shkoi keq" msgstr "Diçka shkoi keq"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Redaktuesi i fletës së stilit" msgstr "Redaktuesi i fletës së stilit"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Fleta e stilit ka gabime" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Përdorues"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbeke" msgstr "Uzbeke"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "URL-të e vlefshme duhet të fillojnë me http:// ose https://." msgstr "URL-të e vlefshme duhet të fillojnë me http:// ose https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Porta Vercel AI" msgstr "Porta Vercel AI"
@@ -5411,4 +5429,3 @@ msgstr "Zvogëlo"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Пријаве послате недељно (последњих 8 недеља)" msgstr "Пријаве послате недељно (последњих 8 недеља)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Пријављено" msgstr "Пријављено"
@@ -534,10 +533,6 @@ msgstr "Пријављено"
msgid "Applied on" msgid "Applied on"
msgstr "Примењено на" msgstr "Примењено на"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Примењено са упозорењима"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Арапски" msgstr "Арапски"
@@ -1765,7 +1760,6 @@ msgstr "Унесите своју лозинку да потврдите под
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Унесите своју лозинку да бисте онемогућили двофакторску аутентификацију. Ваш налог ће бити мање безбедан без омогућеног 2FA." msgstr "Унесите своју лозинку да бисте онемогућили двофакторску аутентификацију. Ваш налог ће бити мање безбедан без омогућеног 2FA."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Грешка" msgstr "Грешка"
@@ -2003,6 +1997,10 @@ msgstr "Није успело да се потврди ваш резервни
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Није успело да се потврди ваш код. Молимо покушајте поново." msgstr "Није успело да се потврди ваш код. Молимо покушајте поново."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Функције" msgstr "Функције"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Преглед" msgstr "Преглед"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Преглед и извоз користе последњу важећу верзију." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Читање…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Спремно за активирање" msgstr "Спремно за активирање"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Спремно за активирање са упозорењима" msgstr "Спремно за активирање са упозорењима"
@@ -3663,10 +3669,6 @@ msgstr "Ресетуј"
msgid "Reset Password" msgid "Reset Password"
msgstr "Ресетуј лозинку" msgstr "Ресетуј лозинку"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Врати на примењени стилски лист"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Ресетујте своју лозинку" msgstr "Ресетујте своју лозинку"
@@ -4195,6 +4197,10 @@ msgstr "Неки системи апликација захтевају једа
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Неки парсери погрешно рукују сликама, а фотографије су обесхрабрене у неким регионима." msgstr "Неки парсери погрешно рукују сликама, а фотографије су обесхрабрене у неким регионима."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Нешто је пошло наопако" msgstr "Нешто је пошло наопако"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Уређивач стилских листова" msgstr "Уређивач стилских листова"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Стилски лист садржи грешке" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Корисници"
msgid "Uzbek" msgid "Uzbek"
msgstr "Узбечки" msgstr "Узбечки"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Важећи URL-ови морају да почињу са http:// или https://." msgstr "Важећи URL-ови морају да почињу са http:// или https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Версел АИ Гејтвеј" msgstr "Версел АИ Гејтвеј"
@@ -5411,4 +5429,3 @@ msgstr "Умањи"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Зулу" msgstr "Зулу"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Ansökningar skickade per vecka (senaste 8 veckorna)" msgstr "Ansökningar skickade per vecka (senaste 8 veckorna)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Ansökt" msgstr "Ansökt"
@@ -534,10 +533,6 @@ msgstr "Ansökt"
msgid "Applied on" msgid "Applied on"
msgstr "Tillämpas på" msgstr "Tillämpas på"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Tillämpas med varningar"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arabiska" msgstr "Arabiska"
@@ -1765,7 +1760,6 @@ msgstr "Ange ditt lösenord för att bekräfta att du vill ställa in tvåfaktor
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Ange ditt lösenord för att inaktivera tvåfaktorsautentisering. Ditt konto blir mindre säkert utan aktiverad 2FA." msgstr "Ange ditt lösenord för att inaktivera tvåfaktorsautentisering. Ditt konto blir mindre säkert utan aktiverad 2FA."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Fel" msgstr "Fel"
@@ -2003,6 +1997,10 @@ msgstr "Det gick inte att verifiera din säkerhetskopieringskod. Vänligen förs
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Det gick inte att verifiera din kod. Vänligen försök igen." msgstr "Det gick inte att verifiera din kod. Vänligen försök igen."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Funktioner" msgstr "Funktioner"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Förhandsvisning" msgstr "Förhandsvisning"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Förhandsgranska och exportera med den senast giltiga versionen." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Läsning…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Klar att aktiveras" msgstr "Klar att aktiveras"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Klar att aktiveras med varningar" msgstr "Klar att aktiveras med varningar"
@@ -3663,10 +3669,6 @@ msgstr "Återställ"
msgid "Reset Password" msgid "Reset Password"
msgstr "Återställ lösenord" msgstr "Återställ lösenord"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Återställ till tillämpat formatmall"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Återställ ditt lösenord" msgstr "Återställ ditt lösenord"
@@ -4195,6 +4197,10 @@ msgstr "Vissa ansökningssystem kräver ett innan du kan skicka in."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Vissa tolkar hanterar bilder felaktigt och foton avråds från vissa regioner." msgstr "Vissa tolkar hanterar bilder felaktigt och foton avråds från vissa regioner."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Något gick fel" msgstr "Något gick fel"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Stilarksredigerare" msgstr "Stilarksredigerare"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Stilarket innehåller fel" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Användare"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbekiska" msgstr "Uzbekiska"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Giltiga URL:er måste börja med http:// eller https://." msgstr "Giltiga URL:er måste börja med http:// eller https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Zooma ut"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "வாரத்திற்கு அனுப்பப்பட்ட விண்ணப்பங்கள் (கடைசி 8 வாரங்கள்)" msgstr "வாரத்திற்கு அனுப்பப்பட்ட விண்ணப்பங்கள் (கடைசி 8 வாரங்கள்)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "விண்ணப்பிக்கப்பட்டது" msgstr "விண்ணப்பிக்கப்பட்டது"
@@ -534,10 +533,6 @@ msgstr "விண்ணப்பிக்கப்பட்டது"
msgid "Applied on" msgid "Applied on"
msgstr "அன்று விண்ணப்பித்தது" msgstr "அன்று விண்ணப்பித்தது"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "எச்சரிக்கைகளுடன் கூடிய அறிவு"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "அரபிக்" msgstr "அரபிக்"
@@ -1765,7 +1760,6 @@ msgstr "இரண்டு நிலை அங்கீகாரத்தை அ
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "இரண்டு நிலை அங்கீகாரத்தை முடக்க உங்கள் கடவுச்சொல்லை உள்ளிடவும். 2FA இயங்காவிட்டால் உங்கள் கணக்கு குறைந்த பாதுகாப்புடன் இருக்கும்." msgstr "இரண்டு நிலை அங்கீகாரத்தை முடக்க உங்கள் கடவுச்சொல்லை உள்ளிடவும். 2FA இயங்காவிட்டால் உங்கள் கணக்கு குறைந்த பாதுகாப்புடன் இருக்கும்."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "பிழை" msgstr "பிழை"
@@ -2003,6 +1997,10 @@ msgstr "உங்கள் காப்புக் குறியீட்ட
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "உங்கள் குறியீட்டைச் சரிபார்க்கத் தவறியது. மீண்டும் முயற்சிக்கவும்." msgstr "உங்கள் குறியீட்டைச் சரிபார்க்கத் தவறியது. மீண்டும் முயற்சிக்கவும்."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "அம்சங்கள்" msgstr "அம்சங்கள்"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "முன்னோட்டம்" msgstr "முன்னோட்டம்"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "முன்னோட்டம் மற்றும் ஏற்றுமதிக்கு, கடைசியாகச் செல்லுபடியாகும் பதிப்பைப் பயன்படுத்தவும்." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "படிக்கிறது…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "செயல்படுத்தத் தயார்" msgstr "செயல்படுத்தத் தயார்"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "எச்சரிக்கைகளுடன் செயல்படுத்தத் தயார்" msgstr "எச்சரிக்கைகளுடன் செயல்படுத்தத் தயார்"
@@ -3663,10 +3669,6 @@ msgstr "மீட்டமை"
msgid "Reset Password" msgid "Reset Password"
msgstr "கடவுச்சொல்லை மீட்டமைக்கவும்" msgstr "கடவுச்சொல்லை மீட்டமைக்கவும்"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "பயன்படுத்தப்பட்ட பாணித் தாளுக்கு மீட்டமைக்கவும்"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "உங்கள் கடவுச்சொல்லை மீட்டமைக்கவும்" msgstr "உங்கள் கடவுச்சொல்லை மீட்டமைக்கவும்"
@@ -4195,6 +4197,10 @@ msgstr "நீங்கள் சமர்ப்பிக்கும் மு
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "சில பாகுபடுத்துபவர்கள் படங்களை தவறாகக் கையாளுகின்றனர், மேலும் சில பகுதிகளில் புகைப்படங்கள் ஊக்கமளிக்கவில்லை." msgstr "சில பாகுபடுத்துபவர்கள் படங்களை தவறாகக் கையாளுகின்றனர், மேலும் சில பகுதிகளில் புகைப்படங்கள் ஊக்கமளிக்கவில்லை."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "ஏதோ தவறு நடந்துவிட்டது" msgstr "ஏதோ தவறு நடந்துவிட்டது"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "ஸ்டைல்ஷீட் எடிட்டர்" msgstr "ஸ்டைல்ஷீட் எடிட்டர்"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "ஸ்டைல்ஷீட்டில் பிழைகள் உள்ளன" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "பயனர்கள்"
msgid "Uzbek" msgid "Uzbek"
msgstr "உஸ்பெக்" msgstr "உஸ்பெக்"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "சரியான URL-கள் http:// அல்லது https:// கொண்டு தொடங்க வேண்டும்." msgstr "சரியான URL-கள் http:// அல்லது https:// கொண்டு தொடங்க வேண்டும்."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "வெர்சல் ஏஐ கேட்வே" msgstr "வெர்சல் ஏஐ கேட்வே"
@@ -5411,4 +5429,3 @@ msgstr "சிறிதாக்கு"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "ஜூலு" msgstr "ஜூலு"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "వారానికి పంపిన దరఖాస్తులు (చివరి 8 వారాలు)" msgstr "వారానికి పంపిన దరఖాస్తులు (చివరి 8 వారాలు)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "దరఖాస్తు చేశారు" msgstr "దరఖాస్తు చేశారు"
@@ -534,10 +533,6 @@ msgstr "దరఖాస్తు చేశారు"
msgid "Applied on" msgid "Applied on"
msgstr "దరఖాస్తు చేసిన తేదీ" msgstr "దరఖాస్తు చేసిన తేదీ"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "హెచ్చరికలతో వర్తింపజేయబడింది"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "అరబిక్" msgstr "అరబిక్"
@@ -1765,7 +1760,6 @@ msgstr "రెండు దశల ధృవీకరణ ఏర్పాటున
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "రెండు దశల ధృవీకరణను నిలిపివేయడానికి మీ పాస్‌వర్డ్‌ని నమోదు చేయండి. 2FA ప్రారంభించబడకుండా ఉంటే మీ ఖాతా తక్కువ భద్రతగా ఉంటుంది." msgstr "రెండు దశల ధృవీకరణను నిలిపివేయడానికి మీ పాస్‌వర్డ్‌ని నమోదు చేయండి. 2FA ప్రారంభించబడకుండా ఉంటే మీ ఖాతా తక్కువ భద్రతగా ఉంటుంది."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "లోపం" msgstr "లోపం"
@@ -2003,6 +1997,10 @@ msgstr "మీ బ్యాకప్ కోడ్‌ను ధృవీకరి
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "మీ కోడ్‌ను ధృవీకరించడంలో విఫలమయ్యాము. దయచేసి మళ్ళీ ప్రయత్నించండి." msgstr "మీ కోడ్‌ను ధృవీకరించడంలో విఫలమయ్యాము. దయచేసి మళ్ళీ ప్రయత్నించండి."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "ఫీచర్లు" msgstr "ఫీచర్లు"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "ప్రివ్యూ" msgstr "ప్రివ్యూ"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "ప్రివ్యూ మరియు ఎక్స్‌పోర్ట్ చివరి చెల్లుబాటు అయ్యే వెర్షన్‌ను ఉపయోగిస్తాయి." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "చదువుతోంది…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "యాక్టివేట్ చేయడానికి సిద్ధంగా ఉంది" msgstr "యాక్టివేట్ చేయడానికి సిద్ధంగా ఉంది"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "హెచ్చరికలతో యాక్టివేట్ చేయడానికి సిద్ధంగా ఉంది" msgstr "హెచ్చరికలతో యాక్టివేట్ చేయడానికి సిద్ధంగా ఉంది"
@@ -3663,10 +3669,6 @@ msgstr "రీసెట్ చేయండి"
msgid "Reset Password" msgid "Reset Password"
msgstr "పాస్‌వర్డ్ రీసెట్ చేయండి" msgstr "పాస్‌వర్డ్ రీసెట్ చేయండి"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "వర్తింపజేసిన స్టైల్‌షీట్‌కు రీసెట్ చేయండి"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "మీ పాస్‌వర్డ్‌ను రీసెట్ చేయండి" msgstr "మీ పాస్‌వర్డ్‌ను రీసెట్ చేయండి"
@@ -4195,6 +4197,10 @@ msgstr "మీరు సమర్పించే ముందు కొన్న
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "కొంతమంది పార్సర్‌లు చిత్రాలను తప్పుగా నిర్వహిస్తారు మరియు కొన్ని ప్రాంతాలలో ఫోటోలు నిరుత్సాహపరుస్తాయి." msgstr "కొంతమంది పార్సర్‌లు చిత్రాలను తప్పుగా నిర్వహిస్తారు మరియు కొన్ని ప్రాంతాలలో ఫోటోలు నిరుత్సాహపరుస్తాయి."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "ఏదో తప్పు జరిగింది" msgstr "ఏదో తప్పు జరిగింది"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "స్టైల్‌షీట్ ఎడిటర్" msgstr "స్టైల్‌షీట్ ఎడిటర్"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "స్టైల్‌షీట్‌లో లోపాలు ఉన్నాయి" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "వినియోగదారులు"
msgid "Uzbek" msgid "Uzbek"
msgstr "ఉజ్‌బెక్" msgstr "ఉజ్‌బెక్"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "చెల్లే URLలు తప్పనిసరిగా http:// లేదా https://తో ప్రారంభించాలి." msgstr "చెల్లే URLలు తప్పనిసరిగా http:// లేదా https://తో ప్రారంభించాలి."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "వర్సెల్ AI గేట్‌వే" msgstr "వర్సెల్ AI గేట్‌వే"
@@ -5411,4 +5429,3 @@ msgstr "జూమ్ అవుట్ చేయండి"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "జులు" msgstr "జులు"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "ใบสมัครที่ส่งต่อสัปดาห์ (8 สัปดาห์ล่าสุด)" msgstr "ใบสมัครที่ส่งต่อสัปดาห์ (8 สัปดาห์ล่าสุด)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "สมัครแล้ว" msgstr "สมัครแล้ว"
@@ -534,10 +533,6 @@ msgstr "สมัครแล้ว"
msgid "Applied on" msgid "Applied on"
msgstr "สมัครเมื่อ" msgstr "สมัครเมื่อ"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "ใช้งานโดยมีคำเตือน"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "อารบิก" msgstr "อารบิก"
@@ -1765,7 +1760,6 @@ msgstr "กรอกรหัสผ่านของคุณเพื่อย
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "กรอกรหัสผ่านของคุณเพื่อปิดการใช้งานการยืนยันตัวตนสองขั้นตอน บัญชีของคุณจะไม่ปลอดภัยเท่าเดิมหากไม่ได้เปิดใช้งาน 2FA" msgstr "กรอกรหัสผ่านของคุณเพื่อปิดการใช้งานการยืนยันตัวตนสองขั้นตอน บัญชีของคุณจะไม่ปลอดภัยเท่าเดิมหากไม่ได้เปิดใช้งาน 2FA"
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "ข้อผิดพลาด" msgstr "ข้อผิดพลาด"
@@ -2003,6 +1997,10 @@ msgstr "ไม่สามารถยืนยันรหัสสำรอง
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "ไม่สามารถยืนยันรหัสของคุณได้ กรุณาลองอีกครั้ง" msgstr "ไม่สามารถยืนยันรหัสของคุณได้ กรุณาลองอีกครั้ง"
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "คุณสมบัติ" msgstr "คุณสมบัติ"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "ตัวอย่าง" msgstr "ตัวอย่าง"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "ให้ใช้เวอร์ชันล่าสุดที่ถูกต้องในการแสดงตัวอย่างและการส่งออก" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "กำลังอ่าน…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "พร้อมใช้งานแล้ว" msgstr "พร้อมใช้งานแล้ว"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "พร้อมใช้งานพร้อมคำเตือน" msgstr "พร้อมใช้งานพร้อมคำเตือน"
@@ -3663,10 +3669,6 @@ msgstr "รีเซ็ต"
msgid "Reset Password" msgid "Reset Password"
msgstr "รีเซ็ตรหัสผ่าน" msgstr "รีเซ็ตรหัสผ่าน"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "รีเซ็ตเป็นสไตล์ชีตที่ใช้งานอยู่"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "รีเซ็ตรหัสผ่านของคุณ" msgstr "รีเซ็ตรหัสผ่านของคุณ"
@@ -4195,6 +4197,10 @@ msgstr "ระบบการสมัครบางระบบจำเป็
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "โปรแกรมแยกวิเคราะห์บางคนจัดการรูปภาพในทางที่ผิด และรูปภาพไม่ได้รับการสนับสนุนในบางภูมิภาค" msgstr "โปรแกรมแยกวิเคราะห์บางคนจัดการรูปภาพในทางที่ผิด และรูปภาพไม่ได้รับการสนับสนุนในบางภูมิภาค"
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "เกิดข้อผิดพลาดบางอย่าง" msgstr "เกิดข้อผิดพลาดบางอย่าง"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "ตัวแก้ไขสไตล์ชีต" msgstr "ตัวแก้ไขสไตล์ชีต"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "ไฟล์สไตล์ชีตมีข้อผิดพลาด" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "ผู้ใช้"
msgid "Uzbek" msgid "Uzbek"
msgstr "อุซเบก" msgstr "อุซเบก"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "URL ที่ถูกต้องต้องขึ้นต้นด้วย http:// หรือ https://." msgstr "URL ที่ถูกต้องต้องขึ้นต้นด้วย http:// หรือ https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "เกตเวย์ AI ของ Vercel" msgstr "เกตเวย์ AI ของ Vercel"
@@ -5411,4 +5429,3 @@ msgstr "ซูมออก"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "ซูลู" msgstr "ซูลู"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Haftalık gönderilen başvurular (son 8 hafta)" msgstr "Haftalık gönderilen başvurular (son 8 hafta)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Başvuruldu" msgstr "Başvuruldu"
@@ -534,10 +533,6 @@ msgstr "Başvuruldu"
msgid "Applied on" msgid "Applied on"
msgstr "Başvuru tarihi" msgstr "Başvuru tarihi"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Uyarılarla birlikte uygulandı."
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arapça" msgstr "Arapça"
@@ -1765,7 +1760,6 @@ msgstr "İki faktörlü kimlik doğrulamayı kurmayı onaylamak için şifrenizi
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "İki faktörlü kimlik doğrulamayı devre dışı bırakmak için şifrenizi girin. 2FA etkin olmadığında hesabınız daha az güvenli olur." msgstr "İki faktörlü kimlik doğrulamayı devre dışı bırakmak için şifrenizi girin. 2FA etkin olmadığında hesabınız daha az güvenli olur."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Hata" msgstr "Hata"
@@ -2003,6 +1997,10 @@ msgstr "Yedekleme kodunuz doğrulanamadı. Lütfen tekrar deneyin."
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Kodunuz doğrulanamadı. Lütfen tekrar deneyin." msgstr "Kodunuz doğrulanamadı. Lütfen tekrar deneyin."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Özellikler" msgstr "Özellikler"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Önizleme" msgstr "Önizleme"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Önizleme ve dışa aktarma işlemleri için en son geçerli sürüm kullanılır." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Okunuyor…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Etkinleştirmeye hazır" msgstr "Etkinleştirmeye hazır"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Uyarılarla birlikte etkinleştirmeye hazır." msgstr "Uyarılarla birlikte etkinleştirmeye hazır."
@@ -3663,10 +3669,6 @@ msgstr "Sıfırla"
msgid "Reset Password" msgid "Reset Password"
msgstr "Şifreyi Sıfırla" msgstr "Şifreyi Sıfırla"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Uygulanan stil sayfasına sıfırla"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Şifrenizi sıfırlayın" msgstr "Şifrenizi sıfırlayın"
@@ -4195,6 +4197,10 @@ msgstr "Bazı başvuru sistemleri, gönderebilmeniz için bir başvuru gerektiri
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Bazı ayrıştırıcılar görüntüleri yanlış kullanıyor ve bazı bölgelerde fotoğraf kullanılması önerilmez." msgstr "Bazı ayrıştırıcılar görüntüleri yanlış kullanıyor ve bazı bölgelerde fotoğraf kullanılması önerilmez."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Bir şeyler ters gitti." msgstr "Bir şeyler ters gitti."
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Stil sayfası düzenleyici" msgstr "Stil sayfası düzenleyici"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Stil dosyasında hatalar var." msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Kullanıcılar"
msgid "Uzbek" msgid "Uzbek"
msgstr "Özbekçe" msgstr "Özbekçe"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Geçerli URL'ler http:// veya https:// ile başlamalıdır." msgstr "Geçerli URL'ler http:// veya https:// ile başlamalıdır."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Ağ Geçidi" msgstr "Vercel AI Ağ Geçidi"
@@ -5411,4 +5429,3 @@ msgstr "Uzaklaştır"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Заявки, надіслані за тиждень (останні 8 тижнів)" msgstr "Заявки, надіслані за тиждень (останні 8 тижнів)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Подано" msgstr "Подано"
@@ -534,10 +533,6 @@ msgstr "Подано"
msgid "Applied on" msgid "Applied on"
msgstr "Подано" msgstr "Подано"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Застосовується з попередженнями"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Арабська" msgstr "Арабська"
@@ -1765,7 +1760,6 @@ msgstr "Введіть пароль для підтвердження налаш
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Введіть свій пароль для вимикання двофакторної автентифікації. Ваш профіль буде менш захищений без увімкненого 2FA." msgstr "Введіть свій пароль для вимикання двофакторної автентифікації. Ваш профіль буде менш захищений без увімкненого 2FA."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Помилка" msgstr "Помилка"
@@ -2003,6 +1997,10 @@ msgstr "Не вдалося підтвердити код резервної к
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Не вдалося підтвердити ваш код. Спробуйте ще раз." msgstr "Не вдалося підтвердити ваш код. Спробуйте ще раз."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Функції" msgstr "Функції"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Попередній перегляд" msgstr "Попередній перегляд"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Для попереднього перегляду та експорту використовується остання дійсна версія." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Читання…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Готовий до активації" msgstr "Готовий до активації"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Готовий до активації з попередженнями" msgstr "Готовий до активації з попередженнями"
@@ -3663,10 +3669,6 @@ msgstr "Скинути"
msgid "Reset Password" msgid "Reset Password"
msgstr "Скинути пароль" msgstr "Скинути пароль"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Скинути до застосованого таблиці стилів"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Скинути пароль" msgstr "Скинути пароль"
@@ -4195,6 +4197,10 @@ msgstr "Деякі системи заявок вимагають її, перш
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Деякі аналізатори неправильно обробляють зображення, тому в деяких регіонах фотографії не рекомендуються." msgstr "Деякі аналізатори неправильно обробляють зображення, тому в деяких регіонах фотографії не рекомендуються."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Щось пішло не так" msgstr "Щось пішло не так"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Редактор таблиць стилів" msgstr "Редактор таблиць стилів"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Таблиця стилів містить помилки" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Користувачі"
msgid "Uzbek" msgid "Uzbek"
msgstr "Узбецька" msgstr "Узбецька"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Дійсні URL-адреси мають починатися з http:// або https://." msgstr "Дійсні URL-адреси мають починатися з http:// або https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Шлюз штучного інтелекту Vercel" msgstr "Шлюз штучного інтелекту Vercel"
@@ -5411,4 +5429,3 @@ msgstr "Зменшити"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Зулу" msgstr "Зулу"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Haftasiga yuborilgan arizalar (songgi 8 hafta)" msgstr "Haftasiga yuborilgan arizalar (songgi 8 hafta)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Topshirildi" msgstr "Topshirildi"
@@ -534,10 +533,6 @@ msgstr "Topshirildi"
msgid "Applied on" msgid "Applied on"
msgstr "Ariza sanasi" msgstr "Ariza sanasi"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Ogohlantirishlar bilan qo'llanildi"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Arab tili" msgstr "Arab tili"
@@ -1765,7 +1760,6 @@ msgstr "Ikki bosqichli autentifikatsiyani yoqishni tasdiqlash uchun parolingizni
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Ikki bosqichli autentifikatsiyani ochirishni tasdiqlash uchun parolingizni kiriting. 2BShT yoqilmagan holda hisobingiz kamroq xavfsiz boʻladi." msgstr "Ikki bosqichli autentifikatsiyani ochirishni tasdiqlash uchun parolingizni kiriting. 2BShT yoqilmagan holda hisobingiz kamroq xavfsiz boʻladi."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Xato" msgstr "Xato"
@@ -2003,6 +1997,10 @@ msgstr "Zaxira kodingizni tasdiqlash muvaffaqiyatsiz bo'ldi. Iltimos, yana urini
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Kodingizni tekshirish muvaffaqiyatsiz bo'ldi. Iltimos, yana urinib ko'ring." msgstr "Kodingizni tekshirish muvaffaqiyatsiz bo'ldi. Iltimos, yana urinib ko'ring."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Xususiyatlar" msgstr "Xususiyatlar"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Oldindan ko'rish" msgstr "Oldindan ko'rish"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Oldindan ko'rish va eksport qilish uchun oxirgi amaldagi versiyadan foydalaning." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "O'qilmoqda…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Faollashtirishga tayyor" msgstr "Faollashtirishga tayyor"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Ogohlantirishlar bilan faollashtirishga tayyor" msgstr "Ogohlantirishlar bilan faollashtirishga tayyor"
@@ -3663,10 +3669,6 @@ msgstr "Tiklash"
msgid "Reset Password" msgid "Reset Password"
msgstr "Parolni tiklash" msgstr "Parolni tiklash"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Qo'llanilgan uslublar jadvaliga qayta o'rnatish"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Parolingizni tiklang" msgstr "Parolingizni tiklang"
@@ -4195,6 +4197,10 @@ msgstr "Ba'zi dastur tizimlari siz yuborishingizdan oldin uni talab qiladi."
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Ba'zi tahlilchilar tasvirlarni noto'g'ri ishlatishadi va ba'zi hududlarda fotosuratlar tavsiya etilmaydi." msgstr "Ba'zi tahlilchilar tasvirlarni noto'g'ri ishlatishadi va ba'zi hududlarda fotosuratlar tavsiya etilmaydi."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Nimadir noto'g'ri ketdi" msgstr "Nimadir noto'g'ri ketdi"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Uslublar jadvali muharriri" msgstr "Uslublar jadvali muharriri"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Uslublar jadvalida xatolar mavjud" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Foydalanuvchilar"
msgid "Uzbek" msgid "Uzbek"
msgstr "O'zbek tili" msgstr "O'zbek tili"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "Toʻgʻri URL http:// yoki https:// bilan boshlanishi kerak." msgstr "Toʻgʻri URL http:// yoki https:// bilan boshlanishi kerak."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "Kichraytirish"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "Đơn ứng tuyển đã gửi mỗi tuần (8 tuần gần nhất)" msgstr "Đơn ứng tuyển đã gửi mỗi tuần (8 tuần gần nhất)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "Đã ứng tuyển" msgstr "Đã ứng tuyển"
@@ -534,10 +533,6 @@ msgstr "Đã ứng tuyển"
msgid "Applied on" msgid "Applied on"
msgstr "Đã ứng tuyển vào" msgstr "Đã ứng tuyển vào"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "Được áp dụng kèm theo cảnh báo"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "Tiếng Ả Rập" msgstr "Tiếng Ả Rập"
@@ -1765,7 +1760,6 @@ msgstr "Nhập mật khẩu của bạn để xác nhận thiết lập xác th
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "Nhập mật khẩu của bạn để tắt xác thực hai yếu tố. Tài khoản của bạn sẽ kém an toàn hơn nếu không bật 2FA." msgstr "Nhập mật khẩu của bạn để tắt xác thực hai yếu tố. Tài khoản của bạn sẽ kém an toàn hơn nếu không bật 2FA."
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "Lỗi" msgstr "Lỗi"
@@ -2003,6 +1997,10 @@ msgstr "Không thể xác minh mã dự phòng của bạn. Vui lòng thử lạ
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "Không thể xác minh mã của bạn. Vui lòng thử lại." msgstr "Không thể xác minh mã của bạn. Vui lòng thử lại."
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "Tính năng" msgstr "Tính năng"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "Xem trước" msgstr "Xem trước"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "Chức năng xem trước và xuất khẩu sử dụng phiên bản hợp lệ mới nhất." msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "Đang đọc…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "Sẵn sàng kích hoạt" msgstr "Sẵn sàng kích hoạt"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "Sẵn sàng kích hoạt kèm cảnh báo" msgstr "Sẵn sàng kích hoạt kèm cảnh báo"
@@ -3663,10 +3669,6 @@ msgstr "Thiết lập lại"
msgid "Reset Password" msgid "Reset Password"
msgstr "Đặt mật khẩu mới" msgstr "Đặt mật khẩu mới"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "Đặt lại về kiểu định dạng đã áp dụng"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "Đặt lại mật khẩu" msgstr "Đặt lại mật khẩu"
@@ -4195,6 +4197,10 @@ msgstr "Một số hệ thống ứng dụng yêu cầu phải có trước khi
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "Một số trình phân tích cú pháp xử lý sai hình ảnh và ảnh không được khuyến khích ở một số vùng." msgstr "Một số trình phân tích cú pháp xử lý sai hình ảnh và ảnh không được khuyến khích ở một số vùng."
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "Đã xảy ra lỗi" msgstr "Đã xảy ra lỗi"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "Trình chỉnh sửa bảng định kiểu" msgstr "Trình chỉnh sửa bảng định kiểu"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "Tệp định kiểu có lỗi" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "Người dùng"
msgid "Uzbek" msgid "Uzbek"
msgstr "Uzbek" msgstr "Uzbek"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "URL hợp lệ phải bắt đầu với http:// hoặc https://." msgstr "URL hợp lệ phải bắt đầu với http:// hoặc https://."
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Cổng AI Vercel" msgstr "Cổng AI Vercel"
@@ -5411,4 +5429,3 @@ msgstr "Thu nhỏ"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "Zulu" msgstr "Zulu"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "每周发送的申请(最近 8 周)" msgstr "每周发送的申请(最近 8 周)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "已申请" msgstr "已申请"
@@ -534,10 +533,6 @@ msgstr "已申请"
msgid "Applied on" msgid "Applied on"
msgstr "申请日期" msgstr "申请日期"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "附带警告"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "阿拉伯语" msgstr "阿拉伯语"
@@ -1765,7 +1760,6 @@ msgstr "请输入你的密码以确认设置双重身份验证。启用后,你
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "请输入你的密码以禁用双重身份验证。关闭 2FA 后,你的账号将不再那么安全。" msgstr "请输入你的密码以禁用双重身份验证。关闭 2FA 后,你的账号将不再那么安全。"
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "错误" msgstr "错误"
@@ -2003,6 +1997,10 @@ msgstr "验证备份代码失败。请重试。"
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "验证您的代码失败。请重试。" msgstr "验证您的代码失败。请重试。"
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "功能" msgstr "功能"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "预览" msgstr "预览"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "预览和导出时请使用最新有效版本。" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "正在读取…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "准备激活" msgstr "准备激活"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "准备激活并发出警告" msgstr "准备激活并发出警告"
@@ -3663,10 +3669,6 @@ msgstr "重置"
msgid "Reset Password" msgid "Reset Password"
msgstr "重置密码" msgstr "重置密码"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "重置为已应用的样式表"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "重置密码" msgstr "重置密码"
@@ -4195,6 +4197,10 @@ msgstr "有些申请系统需要先有一个,然后才能提交。”"
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "一些解析器错误地处理图像,并且在某些地区不鼓励使用照片。”" msgstr "一些解析器错误地处理图像,并且在某些地区不鼓励使用照片。”"
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "出问题了" msgstr "出问题了"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "样式表编辑器" msgstr "样式表编辑器"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "样式表存在错误" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "用户数"
msgid "Uzbek" msgid "Uzbek"
msgstr "乌兹别克语" msgstr "乌兹别克语"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "有效的 URL 必须以 http:// 或 https:// 开头。" msgstr "有效的 URL 必须以 http:// 或 https:// 开头。"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel 人工智能网关" msgstr "Vercel 人工智能网关"
@@ -5411,4 +5429,3 @@ msgstr "缩小"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "祖鲁语" msgstr "祖鲁语"
+32 -15
View File
@@ -526,7 +526,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "每週送出的申請(最近 8 週)" msgstr "每週送出的申請(最近 8 週)"
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "已申請" msgstr "已申請"
@@ -534,10 +533,6 @@ msgstr "已申請"
msgid "Applied on" msgid "Applied on"
msgstr "應徵日期" msgstr "應徵日期"
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr "附帶警告"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "阿拉伯文" msgstr "阿拉伯文"
@@ -1765,7 +1760,6 @@ msgstr "請輸入您的密碼以確認設定雙因子驗證。啟用後,每次
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "請輸入您的密碼以停用雙因子驗證。停用後,您的帳戶將會比較不安全。" msgstr "請輸入您的密碼以停用雙因子驗證。停用後,您的帳戶將會比較不安全。"
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "錯誤" msgstr "錯誤"
@@ -2003,6 +1997,10 @@ msgstr "驗證您的備份碼失敗。請再試一次。"
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "驗證您的驗證碼失敗。請再試一次。" msgstr "驗證您的驗證碼失敗。請再試一次。"
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "功能" msgstr "功能"
@@ -3420,8 +3418,12 @@ msgid "Preview"
msgstr "預覽" msgstr "預覽"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr "預覽和匯出時請使用最新有效版本。" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
msgid "Primary Color" msgid "Primary Color"
@@ -3542,6 +3544,10 @@ msgstr "正在讀取…"
msgid "Ready to activate" msgid "Ready to activate"
msgstr "準備啟用" msgstr "準備啟用"
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "準備啟動並發出警告" msgstr "準備啟動並發出警告"
@@ -3663,10 +3669,6 @@ msgstr "重置"
msgid "Reset Password" msgid "Reset Password"
msgstr "重設密碼" msgstr "重設密碼"
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr "重設為已套用的樣式表"
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "重設您的密碼" msgstr "重設您的密碼"
@@ -4195,6 +4197,10 @@ msgstr "有些申請系統需要先有一個,然後再提交。 」"
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "有些解析器錯誤地處理圖像,並且在某些地區不鼓勵使用照片。 」" msgstr "有些解析器錯誤地處理圖像,並且在某些地區不鼓勵使用照片。 」"
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "出問題了" msgstr "出問題了"
@@ -4338,8 +4344,8 @@ msgid "Stylesheet editor"
msgstr "樣式表編輯器" msgstr "樣式表編輯器"
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "樣式表存在錯誤" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
msgid "Subreddit" msgid "Subreddit"
@@ -5103,10 +5109,22 @@ msgstr "使用者"
msgid "Uzbek" msgid "Uzbek"
msgstr "烏茲別克語" msgstr "烏茲別克語"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "有效的 URL 必須以 http:// 或 https:// 開頭。" msgstr "有效的 URL 必須以 http:// 或 https:// 開頭。"
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "Vercel AI Gateway" msgstr "Vercel AI Gateway"
@@ -5411,4 +5429,3 @@ msgstr "縮小"
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Zulu" msgid "Zulu"
msgstr "祖魯語" msgstr "祖魯語"
+30 -12
View File
@@ -521,7 +521,6 @@ msgid "Applications sent per week (last 8 weeks)"
msgstr "" msgstr ""
#: src/features/applications/components/table-view.tsx #: src/features/applications/components/table-view.tsx
#: src/features/resume/stylesheet/status.tsx
msgid "Applied" msgid "Applied"
msgstr "" msgstr ""
@@ -529,10 +528,6 @@ msgstr ""
msgid "Applied on" msgid "Applied on"
msgstr "" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Applied with warnings"
msgstr ""
#: src/libs/locale.ts #: src/libs/locale.ts
msgid "Arabic" msgid "Arabic"
msgstr "" msgstr ""
@@ -1760,7 +1755,6 @@ msgstr ""
msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled." msgid "Enter your password to disable two-factor authentication. Your account will be less secure without 2FA enabled."
msgstr "" msgstr ""
#: src/features/resume/stylesheet/status.tsx
#: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/ats-check.tsx
msgid "Error" msgid "Error"
msgstr "" msgstr ""
@@ -1998,6 +1992,10 @@ msgstr ""
msgid "Failed to verify your code. Please try again." msgid "Failed to verify your code. Please try again."
msgstr "" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Fatal error"
msgstr ""
#: src/routes/_home/-sections/features.tsx #: src/routes/_home/-sections/features.tsx
msgid "Features" msgid "Features"
msgstr "" msgstr ""
@@ -3415,7 +3413,11 @@ msgid "Preview"
msgstr "" msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Preview and export use the last valid version." msgid "Preview and export fall back to base styles."
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Preview and export keep valid styles and ignore invalid styles."
msgstr "" msgstr ""
#: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx #: src/routes/builder/$resumeId/-sidebar/right/sections/design.tsx
@@ -3537,6 +3539,10 @@ msgstr ""
msgid "Ready to activate" msgid "Ready to activate"
msgstr "" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Ready to activate with warnings" msgid "Ready to activate with warnings"
msgstr "" msgstr ""
@@ -3658,10 +3664,6 @@ msgstr ""
msgid "Reset Password" msgid "Reset Password"
msgstr "" msgstr ""
#: src/features/resume/stylesheet/toolbar.tsx
msgid "Reset to applied stylesheet"
msgstr ""
#: src/features/auth/pages/reset-password.tsx #: src/features/auth/pages/reset-password.tsx
msgid "Reset your password" msgid "Reset your password"
msgstr "" msgstr ""
@@ -4190,6 +4192,10 @@ msgstr ""
msgid "Some parsers mishandle images, and photos are discouraged in some regions." msgid "Some parsers mishandle images, and photos are discouraged in some regions."
msgstr "" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Some styles were ignored"
msgstr ""
#: src/components/layout/error-screen.tsx #: src/components/layout/error-screen.tsx
msgid "Something went wrong" msgid "Something went wrong"
msgstr "" msgstr ""
@@ -4333,7 +4339,7 @@ msgid "Stylesheet editor"
msgstr "" msgstr ""
#: src/features/resume/stylesheet/status.tsx #: src/features/resume/stylesheet/status.tsx
msgid "Stylesheet has errors" msgid "Stylesheet has fatal errors"
msgstr "" msgstr ""
#: src/routes/_home/-sections/footer.tsx #: src/routes/_home/-sections/footer.tsx
@@ -5098,10 +5104,22 @@ msgstr ""
msgid "Uzbek" msgid "Uzbek"
msgstr "" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid"
msgstr ""
#: src/components/input/rich-input.tsx #: src/components/input/rich-input.tsx
msgid "Valid URLs must start with http:// or https://." msgid "Valid URLs must start with http:// or https://."
msgstr "" msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with errors"
msgstr ""
#: src/features/resume/stylesheet/status.tsx
msgid "Valid with warnings"
msgstr ""
#: src/features/settings/integrations/components/ai-section.tsx #: src/features/settings/integrations/components/ai-section.tsx
msgid "Vercel AI Gateway" msgid "Vercel AI Gateway"
msgstr "" msgstr ""
@@ -35,10 +35,6 @@ const toastMocks = vi.hoisted(() => ({
error: vi.fn(() => "sync-error-toast"), error: vi.fn(() => "sync-error-toast"),
})); }));
const stylesheetMocks = vi.hoisted(() => ({
refresh: vi.fn(),
}));
vi.mock("@orpc/client", () => ({ vi.mock("@orpc/client", () => ({
consumeEventIterator: consumeEventIteratorMock, consumeEventIterator: consumeEventIteratorMock,
})); }));
@@ -81,10 +77,6 @@ vi.mock("sonner", () => ({
toast: toastMocks, toast: toastMocks,
})); }));
vi.mock("@/features/resume/stylesheet/store", () => ({
refreshStylesheetStore: stylesheetMocks.refresh,
}));
function cloneResumeData(data: ResumeData): ResumeData { function cloneResumeData(data: ResumeData): ResumeData {
return structuredClone(data); return structuredClone(data);
} }
@@ -135,7 +127,6 @@ describe("builder resume autosave", () => {
i18n.loadAndActivate({ locale: "en-US", messages: {} }); i18n.loadAndActivate({ locale: "en-US", messages: {} });
toastMocks.dismiss.mockClear(); toastMocks.dismiss.mockClear();
toastMocks.error.mockClear(); toastMocks.error.mockClear();
stylesheetMocks.refresh.mockReset();
useResumeStore.getState().reset(); useResumeStore.getState().reset();
}); });
@@ -169,6 +160,26 @@ describe("builder resume autosave", () => {
expect(orpcMocks.patchResume).not.toHaveBeenCalled(); expect(orpcMocks.patchResume).not.toHaveBeenCalled();
}); });
it("autosaves stylesheet source through the ordinary full-data update", async () => {
const initial = makeResume("resume-stylesheet-autosave");
const source = { languageVersion: 1, text: "@version 1;\nname { color: blue; }\n" };
const updated = makeResume(initial.id);
updated.data.metadata.stylesheet = { mode: "semantic", source };
orpcMocks.updateResume.mockResolvedValue(updated);
useResumeStore.getState().initialize(initial);
useResumeStore.getState().updateResumeData((draft) => {
draft.metadata.stylesheet = { mode: "semantic", source };
});
vi.advanceTimersByTime(500);
await flushMicrotasks();
expect(orpcMocks.updateResume).toHaveBeenCalledWith(
{ id: initial.id, data: updated.data },
expect.objectContaining({ signal: expect.any(AbortSignal) }),
);
});
it("saves the latest pending snapshot after an in-flight save resolves", async () => { it("saves the latest pending snapshot after an in-flight save resolves", async () => {
const initial = makeResume("resume-in-flight"); const initial = makeResume("resume-in-flight");
const first = withBasicsName(initial, "First Name"); const first = withBasicsName(initial, "First Name");
@@ -507,25 +518,13 @@ describe("resume update stream subscription", () => {
expect(useResumeStore.getState().resume?.data.basics.name).toBe("Local Name"); expect(useResumeStore.getState().resume?.data.basics.name).toBe("Local Name");
}); });
it("refetches canonical stylesheet state for stylesheet SSE events", async () => { it("applies stylesheet source from the ordinary resume SSE flow", async () => {
const initial = makeResume("resume-stylesheet"); const initial = makeResume("resume-stylesheet");
consumeEventIteratorMock.mockReturnValue(vi.fn().mockResolvedValue(undefined)); const remote = makeResume("resume-stylesheet");
routerParamsMock.value = { resumeId: initial.id }; remote.data.metadata.stylesheet = {
useResumeStore.getState().initialize(initial); mode: "semantic",
source: { languageVersion: 1, text: "@version 1;\nname { color: blue; }\n" },
renderHook(() => useBuilderResumeUpdateSubscription());
const handlers = consumeEventIteratorMock.mock.calls[0]?.[1] as {
onEvent: (event: { mutation: string }) => Promise<void>;
}; };
await act(async () => handlers.onEvent({ mutation: "stylesheet" }));
expect(stylesheetMocks.refresh).toHaveBeenCalledWith(initial.id);
expect(orpcMocks.getResumeById).not.toHaveBeenCalled();
});
it("refreshes the render-data version after content SSE events", async () => {
const initial = makeResume("resume-content");
const remote = withBasicsName(initial, "Remote");
consumeEventIteratorMock.mockReturnValue(vi.fn().mockResolvedValue(undefined)); consumeEventIteratorMock.mockReturnValue(vi.fn().mockResolvedValue(undefined));
orpcMocks.getResumeById.mockResolvedValue(remote); orpcMocks.getResumeById.mockResolvedValue(remote);
routerParamsMock.value = { resumeId: initial.id }; routerParamsMock.value = { resumeId: initial.id };
@@ -537,6 +536,7 @@ describe("resume update stream subscription", () => {
}; };
await act(async () => handlers.onEvent({ mutation: "update" })); await act(async () => handlers.onEvent({ mutation: "update" }));
expect(stylesheetMocks.refresh).toHaveBeenCalledWith(initial.id, remote.data); expect(orpcMocks.getResumeById).toHaveBeenCalledWith({ id: initial.id });
expect(useResumeStore.getState().resume?.data.metadata.stylesheet).toEqual(remote.data.metadata.stylesheet);
}); });
}); });
@@ -10,7 +10,6 @@ import { useCallback, useEffect, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { immer } from "zustand/middleware/immer"; import { immer } from "zustand/middleware/immer";
import { create } from "zustand/react"; import { create } from "zustand/react";
import { refreshStylesheetStore } from "@/features/resume/stylesheet/store";
import { orpc, streamClient } from "@/libs/orpc/client"; import { orpc, streamClient } from "@/libs/orpc/client";
export type Resume = { export type Resume = {
@@ -26,7 +25,7 @@ export type Resume = {
}; };
// Mirrors the server-side ResumeUpdatedEvent discriminator (packages/api resume/events.ts). // Mirrors the server-side ResumeUpdatedEvent discriminator (packages/api resume/events.ts).
type ResumeUpdateMutation = "sync" | "create" | "update" | "patch" | "lock" | "password" | "delete" | "stylesheet"; type ResumeUpdateMutation = "sync" | "create" | "update" | "patch" | "lock" | "password" | "delete";
type ResumeUpdateEvent = { mutation: ResumeUpdateMutation }; type ResumeUpdateEvent = { mutation: ResumeUpdateMutation };
type SaveStatus = "idle" | "saving" | "saved" | "error"; type SaveStatus = "idle" | "saving" | "saved" | "error";
@@ -616,14 +615,9 @@ export function useBuilderResumeUpdateSubscription() {
if (!resumeId) return; if (!resumeId) return;
bindRuntimeQueryClient(resumeId, queryClient); bindRuntimeQueryClient(resumeId, queryClient);
if (event.mutation === "stylesheet") {
await refreshStylesheetStore(resumeId);
return;
}
const resume = (await orpc.resume.getById.call({ id: resumeId })) as Resume; const resume = (await orpc.resume.getById.call({ id: resumeId })) as Resume;
queryClient.setQueryData(getResumeQueryKey(resumeId), resume); queryClient.setQueryData(getResumeQueryKey(resumeId), resume);
await refreshStylesheetStore(resumeId, resume.data);
if (hasPendingLocalChanges(resumeId)) { if (hasPendingLocalChanges(resumeId)) {
useResumeStore.getState().mergeResumeMetadata(resume); useResumeStore.getState().mergeResumeMetadata(resume);
@@ -1,6 +1,4 @@
import type { PublicStyleProjection } from "@reactive-resume/pdf/public-projection";
import type { ResumeData } from "@reactive-resume/schema/resume/data"; import type { ResumeData } from "@reactive-resume/schema/resume/data";
import type { SemanticStylesheet, StylesheetSource } from "@reactive-resume/schema/resume/stylesheet";
import type { Template } from "@reactive-resume/schema/templates"; import type { Template } from "@reactive-resume/schema/templates";
import { useMemo } from "react"; import { useMemo } from "react";
import { createResumePdfBlob as createPdfBlob } from "@reactive-resume/pdf/browser"; import { createResumePdfBlob as createPdfBlob } from "@reactive-resume/pdf/browser";
@@ -11,22 +9,6 @@ type ResumePdfRenderOptions = {
includeCoverLetterHeader?: boolean; includeCoverLetterHeader?: boolean;
}; };
export type ResumePdfPresentation =
| { stylesheet: Pick<SemanticStylesheet, "mode"> & { applied: StylesheetSource } }
| { publicStyleProjection: PublicStyleProjection };
const withAppliedStylesheet = (data: ResumeData, presentation?: ResumePdfPresentation): ResumeData => {
if (!presentation || !("stylesheet" in presentation)) return data;
const { mode, applied } = presentation.stylesheet;
return {
...data,
metadata: {
...data.metadata,
stylesheet: { mode, source: applied, applied },
},
};
};
export const useLocalizedResumeDocument = (data?: ResumeData, template?: Template) => { export const useLocalizedResumeDocument = (data?: ResumeData, template?: Template) => {
const sectionTitleResolver = useSectionTitleResolver(data?.metadata.page.locale); const sectionTitleResolver = useSectionTitleResolver(data?.metadata.page.locale);
@@ -47,17 +29,13 @@ export const createResumePdfBlob = async (
data: ResumeData, data: ResumeData,
template?: Template, template?: Template,
renderOptions?: ResumePdfRenderOptions, renderOptions?: ResumePdfRenderOptions,
presentation?: ResumePdfPresentation,
) => { ) => {
const sectionTitleResolver = await createSectionTitleResolverForLocale(data.metadata.page.locale); const sectionTitleResolver = await createSectionTitleResolverForLocale(data.metadata.page.locale);
return createPdfBlob({ return createPdfBlob({
data: withAppliedStylesheet(data, presentation), data,
template, template,
...(renderOptions ? { renderOptions } : {}), ...(renderOptions ? { renderOptions } : {}),
...(presentation && "publicStyleProjection" in presentation
? { publicStyleProjection: presentation.publicStyleProjection }
: {}),
resolveSectionTitle: sectionTitleResolver, resolveSectionTitle: sectionTitleResolver,
}); });
}; };
@@ -3,7 +3,6 @@
import { act, renderHook } from "@testing-library/react"; import { act, renderHook } from "@testing-library/react";
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { i18n } from "@lingui/core"; import { i18n } from "@lingui/core";
import { createPublicStyleProjection } from "@reactive-resume/pdf/public-projection";
import { sampleResumeData } from "@reactive-resume/schema/resume/sample"; import { sampleResumeData } from "@reactive-resume/schema/resume/sample";
import { useResumeExport } from "./use-resume-export"; import { useResumeExport } from "./use-resume-export";
@@ -14,22 +13,13 @@ const mocks = vi.hoisted(() => ({
toastError: vi.fn(), toastError: vi.fn(),
})); }));
vi.mock("./pdf-document", () => ({ vi.mock("@/features/resume/export/pdf-document", () => ({
createResumePdfBlob: mocks.createResumePdfBlob, createResumePdfBlob: mocks.createResumePdfBlob,
})); }));
vi.mock("@reactive-resume/utils/file", () => ({ vi.mock("@reactive-resume/utils/file", () => ({
downloadWithAnchor: mocks.downloadWithAnchor, downloadWithAnchor: mocks.downloadWithAnchor,
generateFilename: (name: string, extension: string) => `${name}.${extension}`, generateFilename: (name: string, extension: string) => `${name}.${extension}`,
})); }));
vi.mock("@/features/resume/stylesheet/store", () => ({
useStylesheetStore: (selector: (state: object) => unknown) =>
selector({
resumeId: undefined,
mode: "legacy",
source: { languageVersion: 1, text: "@version 1;\n" },
applied: { languageVersion: 1, text: "@version 1;\n" },
}),
}));
vi.mock("sonner", () => ({ vi.mock("sonner", () => ({
toast: { toast: {
loading: vi.fn(() => "toast"), loading: vi.fn(() => "toast"),
@@ -49,21 +39,16 @@ beforeEach(() => {
}); });
describe("useResumeExport public PDF", () => { describe("useResumeExport public PDF", () => {
it("downloads the authorized server blob after one mismatched-projection refetch", async () => { it("downloads the authorized server blob after public browser rendering rejects", async () => {
const semanticData = structuredClone(sampleResumeData); const semanticData = structuredClone(sampleResumeData);
const source = { languageVersion: 1, text: "@version 1;\nname { color: #123456; }\n" }; const source = { languageVersion: 1, text: "@version 1;\nname { color: #123456; }\n" };
semanticData.metadata.stylesheet = { mode: "semantic", source, applied: source }; semanticData.metadata.stylesheet = { mode: "semantic", source };
const projection = await createPublicStyleProjection({ data: semanticData }); mocks.createResumePdfBlob.mockRejectedValueOnce(new Error("browser renderer failed"));
const mismatchedProjection = { ...projection, renderDataHash: "0".repeat(64) };
const refetchStyleProjection = vi.fn(async () => mismatchedProjection);
const { result } = renderHook(() => const { result } = renderHook(() =>
useResumeExport( useResumeExport(
{ name: "Sample", slug: "sample", data: sampleResumeData }, { name: "Sample", slug: "sample", data: semanticData },
{ {
publicResumePdf: { publicResumePdf: {
stylesheetMode: "semantic",
styleProjection: mismatchedProjection,
refetchStyleProjection,
publicResume: { username: "amruth", slug: "sample" }, publicResume: { username: "amruth", slug: "sample" },
}, },
}, },
@@ -72,19 +57,14 @@ describe("useResumeExport public PDF", () => {
await act(() => result.current.onDownloadPDF()); await act(() => result.current.onDownloadPDF());
expect(refetchStyleProjection).toHaveBeenCalledTimes(1); expect(mocks.createResumePdfBlob).toHaveBeenCalledWith(semanticData);
expect(mocks.fetch).toHaveBeenCalledTimes(1); expect(mocks.fetch).toHaveBeenCalledTimes(1);
expect(mocks.createResumePdfBlob).not.toHaveBeenCalled();
const blob = mocks.downloadWithAnchor.mock.calls[0]?.[0] as Blob; const blob = mocks.downloadWithAnchor.mock.calls[0]?.[0] as Blob;
expect(await blob.text()).toBe("server"); expect(await blob.text()).toBe("server");
}); });
it("does not download an unstyled PDF when semantic rendering rejects", async () => { it("does not download a PDF when the renderer rejects", async () => {
mocks.createResumePdfBlob.mockRejectedValueOnce( mocks.createResumePdfBlob.mockRejectedValueOnce(new Error("PDF renderer failed"));
new Error("The semantic stylesheet could not be rendered.", {
cause: [{ code: "RESOURCE_LIMIT", severity: "error" }],
}),
);
const { result } = renderHook(() => useResumeExport({ name: "Sample", slug: "sample", data: sampleResumeData })); const { result } = renderHook(() => useResumeExport({ name: "Sample", slug: "sample", data: sampleResumeData }));
await act(() => result.current.onDownloadPDF()); await act(() => result.current.onDownloadPDF());
@@ -1,10 +1,8 @@
import type { ResumeExportTarget } from "@reactive-resume/resume/export-sections"; import type { ResumeExportTarget } from "@reactive-resume/resume/export-sections";
import type { ResumeData } from "@reactive-resume/schema/resume/data"; import type { ResumeData } from "@reactive-resume/schema/resume/data";
import type { SemanticStylesheet } from "@reactive-resume/schema/resume/stylesheet";
import type { PublicResumePdfOptions } from "@/features/resume/public/public-pdf"; import type { PublicResumePdfOptions } from "@/features/resume/public/public-pdf";
import type { ResumePdfPresentation } from "./pdf-document";
import { t } from "@lingui/core/macro"; import { t } from "@lingui/core/macro";
import { useCallback, useMemo, useState } from "react"; import { useCallback, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { buildDocx } from "@reactive-resume/docx"; import { buildDocx } from "@reactive-resume/docx";
import { getResumeSectionTitle } from "@reactive-resume/pdf/section-title"; import { getResumeSectionTitle } from "@reactive-resume/pdf/section-title";
@@ -12,7 +10,6 @@ import { getResumeExportData, resumeHasCoverLetter } from "@reactive-resume/resu
import { buildMarkdown } from "@reactive-resume/resume/markdown"; import { buildMarkdown } from "@reactive-resume/resume/markdown";
import { downloadWithAnchor, generateFilename } from "@reactive-resume/utils/file"; import { downloadWithAnchor, generateFilename } from "@reactive-resume/utils/file";
import { resolvePublicResumePdfBlob } from "@/features/resume/public/public-pdf"; import { resolvePublicResumePdfBlob } from "@/features/resume/public/public-pdf";
import { useStylesheetStore } from "@/features/resume/stylesheet/store";
import { createSectionTitleResolverForLocale } from "@/libs/resume/section-title-locale"; import { createSectionTitleResolverForLocale } from "@/libs/resume/section-title-locale";
import { createResumePdfBlob } from "./pdf-document"; import { createResumePdfBlob } from "./pdf-document";
@@ -54,43 +51,12 @@ type DownloadPdfOptions = {
export function useResumeExport(resume: ExportableResume | undefined, exportOptions: UseResumeExportOptions = {}) { export function useResumeExport(resume: ExportableResume | undefined, exportOptions: UseResumeExportOptions = {}) {
const [isExporting, setIsExporting] = useState(false); const [isExporting, setIsExporting] = useState(false);
const hasCoverLetter = resume ? resumeHasCoverLetter(resume.data) : false; const hasCoverLetter = resume ? resumeHasCoverLetter(resume.data) : false;
const stylesheetResumeId = useStylesheetStore((state) => state.resumeId);
const stylesheetMode = useStylesheetStore((state) => state.mode);
const stylesheetSource = useStylesheetStore((state) => state.source);
const stylesheetApplied = useStylesheetStore((state) => state.applied);
const canonicalStylesheet = useMemo<SemanticStylesheet | undefined>(
() =>
resume?.id && resume.id === stylesheetResumeId
? {
mode: stylesheetMode,
source: stylesheetSource,
applied: stylesheetApplied,
}
: undefined,
[resume?.id, stylesheetApplied, stylesheetMode, stylesheetResumeId, stylesheetSource],
);
const pdfPresentation = useMemo<ResumePdfPresentation | undefined>(
() =>
canonicalStylesheet
? { stylesheet: { mode: canonicalStylesheet.mode, applied: canonicalStylesheet.applied } }
: undefined,
[canonicalStylesheet],
);
const onDownloadJSON = useCallback(() => { const onDownloadJSON = useCallback(() => {
if (!resume) return; if (!resume) return;
const data = canonicalStylesheet const blob = new Blob([JSON.stringify(resume.data, null, 2)], { type: "application/json" });
? {
...resume.data,
metadata: {
...resume.data.metadata,
stylesheet: canonicalStylesheet,
},
}
: resume.data;
const blob = new Blob([JSON.stringify(data, null, 2)], { type: "application/json" });
downloadWithAnchor(blob, generateFilename(getExportName(resume), "json")); downloadWithAnchor(blob, generateFilename(getExportName(resume), "json"));
}, [canonicalStylesheet, resume]); }, [resume]);
const onDownloadMarkdown = useCallback( const onDownloadMarkdown = useCallback(
async (target: ResumeExportTarget = "resume") => { async (target: ResumeExportTarget = "resume") => {
@@ -136,7 +102,6 @@ export function useResumeExport(resume: ExportableResume | undefined, exportOpti
target === "cover-letter" target === "cover-letter"
? { includeCoverLetterHeader: downloadOptions?.includeCoverLetterHeader } ? { includeCoverLetterHeader: downloadOptions?.includeCoverLetterHeader }
: undefined, : undefined,
pdfPresentation,
); );
downloadWithAnchor(blob, generateFilename(getTargetExportName(resume, target), "pdf")); downloadWithAnchor(blob, generateFilename(getTargetExportName(resume, target), "pdf"));
} catch { } catch {
@@ -146,7 +111,7 @@ export function useResumeExport(resume: ExportableResume | undefined, exportOpti
toast.dismiss(toastId); toast.dismiss(toastId);
} }
}, },
[exportOptions.publicResumePdf, pdfPresentation, resume], [exportOptions.publicResumePdf, resume],
); );
const onPrint = useCallback(async () => { const onPrint = useCallback(async () => {
@@ -156,7 +121,7 @@ export function useResumeExport(resume: ExportableResume | undefined, exportOpti
try { try {
const blob = exportOptions.publicResumePdf const blob = exportOptions.publicResumePdf
? await resolvePublicResumePdfBlob({ data: resume.data, ...exportOptions.publicResumePdf }) ? await resolvePublicResumePdfBlob({ data: resume.data, ...exportOptions.publicResumePdf })
: await createResumePdfBlob(resume.data, undefined, undefined, pdfPresentation); : await createResumePdfBlob(resume.data);
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
// ponytail: print the generated PDF via a hidden iframe (reliable in Chromium). If the browser // ponytail: print the generated PDF via a hidden iframe (reliable in Chromium). If the browser
// blocks iframe printing, fall back to opening the PDF in a new tab so the user can print manually. // blocks iframe printing, fall back to opening the PDF in a new tab so the user can print manually.
@@ -182,7 +147,7 @@ export function useResumeExport(resume: ExportableResume | undefined, exportOpti
setIsExporting(false); setIsExporting(false);
toast.dismiss(toastId); toast.dismiss(toastId);
} }
}, [exportOptions.publicResumePdf, pdfPresentation, resume]); }, [exportOptions.publicResumePdf, resume]);
return { onDownloadJSON, onDownloadMarkdown, onDownloadDOCX, onDownloadPDF, onPrint, isExporting, hasCoverLetter }; return { onDownloadJSON, onDownloadMarkdown, onDownloadDOCX, onDownloadPDF, onPrint, isExporting, hasCoverLetter };
} }
@@ -8,14 +8,7 @@ import { sampleResumeData } from "@reactive-resume/schema/resume/sample";
import { ResumePreviewClient } from "./preview.browser"; import { ResumePreviewClient } from "./preview.browser";
const previewMock = vi.hoisted(() => ({ const previewMock = vi.hoisted(() => ({
builderResumeId: undefined as string | undefined,
builderResumeData: undefined as ResumeData | undefined, builderResumeData: undefined as ResumeData | undefined,
stylesheet: {
resumeId: undefined as string | undefined,
mode: "legacy" as "legacy" | "semantic",
source: { languageVersion: 1, text: "@version 1;\n" },
applied: { languageVersion: 1, text: "@version 1;\n" },
},
toastError: vi.fn(), toastError: vi.fn(),
toBlob: vi.fn(async () => new Blob(["%PDF"], { type: "application/pdf" })), toBlob: vi.fn(async () => new Blob(["%PDF"], { type: "application/pdf" })),
})); }));
@@ -53,22 +46,9 @@ vi.mock("sonner", () => ({
vi.mock("../builder/draft", () => ({ vi.mock("../builder/draft", () => ({
useResumeData: () => previewMock.builderResumeData, useResumeData: () => previewMock.builderResumeData,
useResumeStore: (selector: (state: { resumeId?: string }) => unknown) =>
selector({ resumeId: previewMock.builderResumeId }),
usePreviewPausedStore: (selector: (state: { paused: boolean }) => unknown) => selector({ paused: false }), usePreviewPausedStore: (selector: (state: { paused: boolean }) => unknown) => selector({ paused: false }),
})); }));
vi.mock("@/features/resume/stylesheet/store", () => ({
useStylesheetStore: (
selector: (state: {
resumeId?: string;
mode: "legacy" | "semantic";
source: { languageVersion: number; text: string };
applied: { languageVersion: number; text: string };
}) => unknown,
) => selector(previewMock.stylesheet),
}));
vi.mock("./pdf-canvas", async () => { vi.mock("./pdf-canvas", async () => {
const React = await import("react"); const React = await import("react");
const pdfDocument = { numPages: 1 }; const pdfDocument = { numPages: 1 };
@@ -102,14 +82,7 @@ describe("ResumePreviewClient", () => {
}); });
beforeEach(() => { beforeEach(() => {
previewMock.builderResumeId = undefined;
previewMock.builderResumeData = undefined; previewMock.builderResumeData = undefined;
previewMock.stylesheet = {
resumeId: undefined,
mode: "legacy",
source: { languageVersion: 1, text: "@version 1;\n" },
applied: { languageVersion: 1, text: "@version 1;\n" },
};
previewMock.toBlob.mockReset(); previewMock.toBlob.mockReset();
previewMock.toBlob.mockImplementation(async () => new Blob(["%PDF"], { type: "application/pdf" })); previewMock.toBlob.mockImplementation(async () => new Blob(["%PDF"], { type: "application/pdf" }));
previewMock.toastError.mockReset(); previewMock.toastError.mockReset();
@@ -135,7 +108,7 @@ describe("ResumePreviewClient", () => {
expect(previewMock.toBlob).toHaveBeenCalledTimes(1); expect(previewMock.toBlob).toHaveBeenCalledTimes(1);
}); });
expect(previewMock.toBlob).toHaveBeenCalledWith(sampleResumeData, undefined, undefined, undefined); expect(previewMock.toBlob).toHaveBeenCalledWith(sampleResumeData);
}); });
it("keeps the rendered template identity on the active layer while its replacement renders", async () => { it("keeps the rendered template identity on the active layer while its replacement renders", async () => {
@@ -159,47 +132,39 @@ describe("ResumePreviewClient", () => {
expect(activeLayer?.getAttribute("data-resume-preview-template")).toBe("azurill"); expect(activeLayer?.getAttribute("data-resume-preview-template")).toBe("azurill");
}); });
it("renders the canonical applied stylesheet and ignores invalid editable source", async () => { it("renders the current stylesheet source from the ordinary builder draft", async () => {
const validApplied = { languageVersion: 1, text: "@version 1;\nname { color: #123456; }\n" }; const source = { languageVersion: 1, text: "section {" };
previewMock.builderResumeId = "resume-1"; previewMock.builderResumeData = {
previewMock.builderResumeData = sampleResumeData; ...sampleResumeData,
previewMock.stylesheet = { metadata: {
resumeId: "resume-1", ...sampleResumeData.metadata,
mode: "semantic", stylesheet: { mode: "semantic", source },
source: { languageVersion: 1, text: "section {" }, },
applied: validApplied,
}; };
render(<ResumePreviewClient pageLayout="vertical" pageScale={1.25} showPageNumbers={false} />); render(<ResumePreviewClient pageLayout="vertical" pageScale={1.25} showPageNumbers={false} />);
await waitFor(() => expect(previewMock.toBlob).toHaveBeenCalledTimes(1)); await waitFor(() => expect(previewMock.toBlob).toHaveBeenCalledTimes(1));
expect(previewMock.toBlob).toHaveBeenCalledWith(sampleResumeData, undefined, undefined, { expect(previewMock.toBlob).toHaveBeenCalledWith(previewMock.builderResumeData);
stylesheet: { mode: "semantic", applied: validApplied },
});
expect(previewMock.toBlob).toHaveBeenCalledTimes(1); expect(previewMock.toBlob).toHaveBeenCalledTimes(1);
}); });
it("keeps the active PDF visible and reports later semantic render diagnostics", async () => { it("keeps the active PDF visible and reports a later renderer failure", async () => {
previewMock.builderResumeId = "resume-1";
previewMock.builderResumeData = sampleResumeData; previewMock.builderResumeData = sampleResumeData;
previewMock.stylesheet = {
resumeId: "resume-1",
mode: "semantic",
source: { languageVersion: 1, text: "@version 1;\n" },
applied: { languageVersion: 1, text: "@version 1;\nname { color: #123456; }\n" },
};
const view = render(<ResumePreviewClient pageLayout="vertical" pageScale={1.25} showPageNumbers={false} />); const view = render(<ResumePreviewClient pageLayout="vertical" pageScale={1.25} showPageNumbers={false} />);
expect(await screen.findByRole("img", { name: "Resume page 1 of 1" })).toBeTruthy(); expect(await screen.findByRole("img", { name: "Resume page 1 of 1" })).toBeTruthy();
previewMock.toBlob.mockRejectedValueOnce( previewMock.toBlob.mockRejectedValueOnce(new Error("PDF renderer failed"));
new Error("The semantic stylesheet could not be rendered.", { previewMock.builderResumeData = {
cause: [{ code: "RESOURCE_LIMIT", severity: "error" }], ...sampleResumeData,
}), metadata: {
); ...sampleResumeData.metadata,
previewMock.stylesheet.applied = { stylesheet: {
languageVersion: 1, mode: "semantic",
text: "@version 1;\nname { color: #654321; }\n", source: { languageVersion: 1, text: "@version 1;\nname { color: #654321; }\n" },
},
},
}; };
view.rerender(<ResumePreviewClient pageLayout="vertical" pageScale={1.25} showPageNumbers={false} />); view.rerender(<ResumePreviewClient pageLayout="vertical" pageScale={1.25} showPageNumbers={false} />);
@@ -4,13 +4,12 @@ import type { ResolvedResumePreviewProps } from "./preview.shared";
import type { PreviewPageSize } from "./preview.shared.utils"; import type { PreviewPageSize } from "./preview.shared.utils";
import { t } from "@lingui/core/macro"; import { t } from "@lingui/core/macro";
import { AnimatePresence, m } from "motion/react"; import { AnimatePresence, m } from "motion/react";
import { useEffect, useMemo, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { isRTL } from "@reactive-resume/utils/locale"; import { isRTL } from "@reactive-resume/utils/locale";
import { cn } from "@reactive-resume/utils/style"; import { cn } from "@reactive-resume/utils/style";
import { createResumePdfBlob } from "@/features/resume/export/pdf-document"; import { createResumePdfBlob } from "@/features/resume/export/pdf-document";
import { useStylesheetStore } from "@/features/resume/stylesheet/store"; import { usePreviewPausedStore, useResumeData } from "../builder/draft";
import { usePreviewPausedStore, useResumeData, useResumeStore } from "../builder/draft";
import { PdfCanvasDocument, PdfCanvasPage } from "./pdf-canvas"; import { PdfCanvasDocument, PdfCanvasPage } from "./pdf-canvas";
import { ResumePreviewLoader } from "./preview.shared"; import { ResumePreviewLoader } from "./preview.shared";
import { getResumePreviewGapValue, getResumePreviewPageCount } from "./preview.shared.utils"; import { getResumePreviewGapValue, getResumePreviewPageCount } from "./preview.shared.utils";
@@ -102,17 +101,6 @@ export function ResumePreviewClient({
}: ResolvedResumePreviewProps) { }: ResolvedResumePreviewProps) {
const builderResumeData = useResumeData(); const builderResumeData = useResumeData();
const resumeData = data ?? builderResumeData; const resumeData = data ?? builderResumeData;
const builderResumeId = useResumeStore((state) => state.resumeId);
const stylesheetResumeId = useStylesheetStore((state) => state.resumeId);
const mode = useStylesheetStore((state) => state.mode);
const applied = useStylesheetStore((state) => state.applied);
const presentation = useMemo(
() =>
data === undefined && builderResumeId !== undefined && stylesheetResumeId === builderResumeId
? { stylesheet: { mode, applied } }
: undefined,
[applied, builderResumeId, data, mode, stylesheetResumeId],
);
const paused = usePreviewPausedStore((state) => state.paused); const paused = usePreviewPausedStore((state) => state.paused);
const [previewLayers, setPreviewLayers] = useState<PreviewPdf[]>([]); const [previewLayers, setPreviewLayers] = useState<PreviewPdf[]>([]);
@@ -133,7 +121,7 @@ export function ResumePreviewClient({
const generatePdfPreview = async () => { const generatePdfPreview = async () => {
try { try {
if (cancelled || requestId !== requestIdRef.current) return; if (cancelled || requestId !== requestIdRef.current) return;
const blob = await createResumePdfBlob(resumeData, undefined, undefined, presentation); const blob = await createResumePdfBlob(resumeData);
if (!cancelled && requestId === requestIdRef.current) { if (!cancelled && requestId === requestIdRef.current) {
const nextPdf = createPreviewPdf( const nextPdf = createPreviewPdf(
@@ -162,7 +150,7 @@ export function ResumePreviewClient({
cancelled = true; cancelled = true;
window.clearTimeout(timeoutId); window.clearTimeout(timeoutId);
}; };
}, [paused, presentation, resumeData]); }, [paused, resumeData]);
if (!resumeData) return null; if (!resumeData) return null;
@@ -2,7 +2,6 @@
import { render, waitFor } from "@testing-library/react"; import { render, waitFor } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest"; import { beforeEach, describe, expect, it, vi } from "vitest";
import { createPublicStyleProjection } from "@reactive-resume/pdf/public-projection";
import { sampleResumeData } from "@reactive-resume/schema/resume/sample"; import { sampleResumeData } from "@reactive-resume/schema/resume/sample";
const pdfViewerMock = vi.hoisted(() => { const pdfViewerMock = vi.hoisted(() => {
@@ -120,67 +119,25 @@ describe("PdfViewer", () => {
expect(pdfViewerMock.loadingTask.destroy).toHaveBeenCalledTimes(1); expect(pdfViewerMock.loadingTask.destroy).toHaveBeenCalledTimes(1);
}); });
it("renders a valid public projection through the shared PDF entrypoint", async () => { it("renders exposed semantic source through the shared PDF entrypoint", async () => {
const semanticData = structuredClone(sampleResumeData); const semanticData = structuredClone(sampleResumeData);
const applied = { languageVersion: 1, text: "@version 1;\nname { color: #123456; }\n" }; semanticData.metadata.stylesheet = {
semanticData.metadata.stylesheet = { mode: "semantic", source: applied, applied }; mode: "semantic",
const projection = await createPublicStyleProjection({ data: semanticData }); source: { languageVersion: 1, text: "@version 1;\nname { color: #123456; }\n" },
const refetchStyleProjection = vi.fn(); };
render( render(<PdfViewer data={semanticData} publicResume={{ username: "amruth", slug: "sample" }} />);
<PdfViewer
data={sampleResumeData}
stylesheetMode="semantic"
styleProjection={projection}
refetchStyleProjection={refetchStyleProjection}
publicResume={{ username: "amruth", slug: "sample" }}
/>,
);
await waitFor(() => await waitFor(() => expect(pdfViewerMock.createResumePdfBlob).toHaveBeenCalledWith(semanticData));
expect(pdfViewerMock.createResumePdfBlob).toHaveBeenCalledWith(sampleResumeData, undefined, undefined, {
publicStyleProjection: projection,
}),
);
expect(refetchStyleProjection).not.toHaveBeenCalled();
expect(pdfViewerMock.fetch).not.toHaveBeenCalled(); expect(pdfViewerMock.fetch).not.toHaveBeenCalled();
}); });
it("refetches a mismatched projection once before using the authorized PDF fallback", async () => { it("uses the authorized PDF fallback after browser generation rejects", async () => {
const semanticData = structuredClone(sampleResumeData); pdfViewerMock.createResumePdfBlob.mockRejectedValueOnce(new Error("browser renderer failed"));
const applied = { languageVersion: 1, text: "@version 1;\nname { color: #123456; }\n" };
semanticData.metadata.stylesheet = { mode: "semantic", source: applied, applied };
const projection = await createPublicStyleProjection({ data: semanticData });
const mismatchedProjection = { ...projection, renderDataHash: "0".repeat(64) };
const refetchStyleProjection = vi.fn(async () => mismatchedProjection);
const view = render( render(<PdfViewer data={sampleResumeData} publicResume={{ username: "amruth", slug: "sample" }} />);
<PdfViewer
data={sampleResumeData}
stylesheetMode="semantic"
styleProjection={mismatchedProjection}
refetchStyleProjection={refetchStyleProjection}
publicResume={{ username: "amruth", slug: "sample" }}
/>,
);
await waitFor(() => expect(refetchStyleProjection).toHaveBeenCalledTimes(1));
await waitFor(() => expect(pdfViewerMock.fetch).toHaveBeenCalledTimes(1)); await waitFor(() => expect(pdfViewerMock.fetch).toHaveBeenCalledTimes(1));
expect(String(pdfViewerMock.fetch.mock.calls[0]?.[0])).toContain("/api/resumes/amruth/sample/pdf"); expect(pdfViewerMock.fetch).toHaveBeenCalledWith("/api/resumes/amruth/sample/pdf", { credentials: "include" });
expect(String(pdfViewerMock.fetch.mock.calls[0]?.[0])).toContain("reason=render-data-hash");
expect(pdfViewerMock.createResumePdfBlob).not.toHaveBeenCalled();
view.rerender(
<PdfViewer
data={sampleResumeData}
stylesheetMode="semantic"
styleProjection={{ ...mismatchedProjection, renderDataHash: "1".repeat(64) }}
refetchStyleProjection={refetchStyleProjection}
publicResume={{ username: "amruth", slug: "sample" }}
/>,
);
await waitFor(() => expect(pdfViewerMock.fetch).toHaveBeenCalledTimes(2));
expect(refetchStyleProjection).toHaveBeenCalledTimes(1);
}); });
}); });
@@ -1,6 +1,4 @@
import type { PublicStyleProjection } from "@reactive-resume/pdf/public-projection";
import type { ResumeData } from "@reactive-resume/schema/resume/data"; import type { ResumeData } from "@reactive-resume/schema/resume/data";
import type { SemanticStylesheet } from "@reactive-resume/schema/resume/stylesheet";
import type { PDFDocumentLoadingTask, PDFDocumentProxy } from "pdfjs-dist/legacy/build/pdf.mjs"; import type { PDFDocumentLoadingTask, PDFDocumentProxy } from "pdfjs-dist/legacy/build/pdf.mjs";
import { AnnotationMode, GlobalWorkerOptions, getDocument } from "pdfjs-dist/legacy/build/pdf.mjs"; import { AnnotationMode, GlobalWorkerOptions, getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
import { EventBus, LinkTarget, PDFLinkService, PDFViewer } from "pdfjs-dist/legacy/web/pdf_viewer.mjs"; import { EventBus, LinkTarget, PDFLinkService, PDFViewer } from "pdfjs-dist/legacy/web/pdf_viewer.mjs";
@@ -17,9 +15,6 @@ GlobalWorkerOptions.workerSrc = new URL("pdfjs-dist/legacy/build/pdf.worker.min.
type PdfViewerProps = { type PdfViewerProps = {
className?: string; className?: string;
data: ResumeData; data: ResumeData;
stylesheetMode?: SemanticStylesheet["mode"];
styleProjection?: PublicStyleProjection;
refetchStyleProjection?: () => Promise<PublicStyleProjection | undefined>;
publicResume?: { publicResume?: {
username: string; username: string;
slug: string; slug: string;
@@ -77,21 +72,11 @@ function pdfViewerReducer(state: PdfViewerState, action: PdfViewerAction): PdfVi
} }
} }
export function PdfViewer({ export function PdfViewer({ className, data, publicResume }: PdfViewerProps) {
className,
data,
stylesheetMode,
styleProjection,
refetchStyleProjection,
publicResume,
}: PdfViewerProps) {
const rootRef = useRef<HTMLDivElement>(null); const rootRef = useRef<HTMLDivElement>(null);
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const viewerRef = useRef<HTMLDivElement>(null); const viewerRef = useRef<HTMLDivElement>(null);
const fileRef = useRef<Blob | null>(null); const fileRef = useRef<Blob | null>(null);
const projectionRetryRef = useRef<{ data?: ResumeData; publicKey?: string; retried: boolean }>({
retried: false,
});
const [{ error, fileVersion, isReady, viewerHeight }, dispatch] = useReducer( const [{ error, fileVersion, isReady, viewerHeight }, dispatch] = useReducer(
pdfViewerReducer, pdfViewerReducer,
INITIAL_PDF_VIEWER_STATE, INITIAL_PDF_VIEWER_STATE,
@@ -103,27 +88,8 @@ export function PdfViewer({
fileRef.current = null; fileRef.current = null;
dispatch({ type: "resetForData" }); dispatch({ type: "resetForData" });
const createPdf = () => { const createPdf = () =>
if (!stylesheetMode || !publicResume) return createResumePdfBlob(data); publicResume ? resolvePublicResumePdfBlob({ data, publicResume }) : createResumePdfBlob(data);
const publicKey = `${publicResume.username}/${publicResume.slug}`;
if (projectionRetryRef.current.data !== data || projectionRetryRef.current.publicKey !== publicKey) {
projectionRetryRef.current = { data, publicKey, retried: false };
}
const retryProjection =
refetchStyleProjection && !projectionRetryRef.current.retried
? () => {
projectionRetryRef.current.retried = true;
return refetchStyleProjection();
}
: undefined;
return resolvePublicResumePdfBlob({
data,
stylesheetMode,
publicResume,
...(styleProjection ? { styleProjection } : {}),
...(retryProjection ? { refetchStyleProjection: retryProjection } : {}),
});
};
void createPdf() void createPdf()
.then((blob) => { .then((blob) => {
@@ -142,7 +108,7 @@ export function PdfViewer({
return () => { return () => {
isCancelled = true; isCancelled = true;
}; };
}, [data, publicResume, refetchStyleProjection, styleProjection, stylesheetMode]); }, [data, publicResume]);
useEffect(() => { useEffect(() => {
void fileVersion; void fileVersion;
@@ -1,5 +1,4 @@
import { beforeEach, describe, expect, it, vi } from "vitest"; import { beforeEach, describe, expect, it, vi } from "vitest";
import { createPublicStyleProjection } from "@reactive-resume/pdf/public-projection";
import { sampleResumeData } from "@reactive-resume/schema/resume/sample"; import { sampleResumeData } from "@reactive-resume/schema/resume/sample";
import { resolvePublicResumePdfBlob } from "./public-pdf"; import { resolvePublicResumePdfBlob } from "./public-pdf";
@@ -15,58 +14,35 @@ vi.mock("@/features/resume/export/pdf-document", () => ({
const publicResume = { username: "amruth", slug: "sample" }; const publicResume = { username: "amruth", slug: "sample" };
beforeEach(() => { beforeEach(() => {
mocks.createResumePdfBlob.mockClear(); mocks.createResumePdfBlob.mockReset();
mocks.fetch.mockClear(); mocks.createResumePdfBlob.mockResolvedValue(new Blob(["local"], { type: "application/pdf" }));
mocks.fetch.mockReset();
mocks.fetch.mockResolvedValue(new Response(new Blob(["server"], { type: "application/pdf" })));
vi.stubGlobal("fetch", mocks.fetch); vi.stubGlobal("fetch", mocks.fetch);
}); });
describe("resolvePublicResumePdfBlob", () => { describe("resolvePublicResumePdfBlob", () => {
it("keeps legitimate legacy resumes on the local PDF path", async () => { it("renders the exposed stylesheet source directly in the browser", async () => {
await resolvePublicResumePdfBlob({ const data = structuredClone(sampleResumeData);
data: sampleResumeData, data.metadata.stylesheet = {
stylesheetMode: "legacy", mode: "semantic",
publicResume, source: { languageVersion: 1, text: "@version 1;\nname { color: #123456; }\n" },
}); };
const blob = await resolvePublicResumePdfBlob({ data, publicResume });
expect(mocks.createResumePdfBlob).toHaveBeenCalledWith(data);
expect(mocks.fetch).not.toHaveBeenCalled();
expect(await blob.text()).toBe("local");
});
it("fetches the server PDF only after browser rendering rejects", async () => {
mocks.createResumePdfBlob.mockRejectedValue(new Error("browser renderer failed"));
const blob = await resolvePublicResumePdfBlob({ data: sampleResumeData, publicResume });
expect(mocks.createResumePdfBlob).toHaveBeenCalledWith(sampleResumeData); expect(mocks.createResumePdfBlob).toHaveBeenCalledWith(sampleResumeData);
expect(mocks.fetch).not.toHaveBeenCalled(); expect(mocks.fetch).toHaveBeenCalledWith("/api/resumes/amruth/sample/pdf", { credentials: "include" });
});
it("uses the authorized server fallback when a semantic projection is unavailable", async () => {
const refetchStyleProjection = vi.fn().mockRejectedValue(new Error("projection unavailable"));
await resolvePublicResumePdfBlob({
data: sampleResumeData,
stylesheetMode: "semantic",
publicResume,
refetchStyleProjection,
});
expect(refetchStyleProjection).toHaveBeenCalledTimes(1);
expect(String(mocks.fetch.mock.calls[0]?.[0])).toContain("/api/resumes/amruth/sample/pdf");
expect(String(mocks.fetch.mock.calls[0]?.[0])).toContain("reason=missing-projection");
expect(mocks.createResumePdfBlob).not.toHaveBeenCalled();
});
it("refetches a mismatched projection once before returning the authorized server blob", async () => {
const semanticData = structuredClone(sampleResumeData);
const source = { languageVersion: 1, text: "@version 1;\nname { color: #123456; }\n" };
semanticData.metadata.stylesheet = { mode: "semantic", source, applied: source };
const projection = await createPublicStyleProjection({ data: semanticData });
const mismatchedProjection = { ...projection, renderDataHash: "0".repeat(64) };
const refetchStyleProjection = vi.fn(async () => mismatchedProjection);
const blob = await resolvePublicResumePdfBlob({
data: sampleResumeData,
stylesheetMode: "semantic",
styleProjection: mismatchedProjection,
publicResume,
refetchStyleProjection,
});
expect(refetchStyleProjection).toHaveBeenCalledTimes(1);
expect(mocks.fetch).toHaveBeenCalledTimes(1);
expect(await blob.text()).toBe("server"); expect(await blob.text()).toBe("server");
expect(mocks.createResumePdfBlob).not.toHaveBeenCalled();
}); });
}); });
@@ -1,97 +1,28 @@
import type { PublicStyleProjection } from "@reactive-resume/pdf/public-projection";
import type { ResumeData } from "@reactive-resume/schema/resume/data"; import type { ResumeData } from "@reactive-resume/schema/resume/data";
import type { SemanticStylesheet } from "@reactive-resume/schema/resume/stylesheet";
import {
getPublicStyleProjectionFingerprints,
PUBLIC_STYLE_PROJECTION_FORMAT_VERSION,
SEMANTIC_TREE_VERSION,
validatePublicStyleProjection,
} from "@reactive-resume/pdf/public-projection";
import { createResumePdfBlob } from "@/features/resume/export/pdf-document"; import { createResumePdfBlob } from "@/features/resume/export/pdf-document";
export type PublicResumePdfOptions = { export type PublicResumePdfOptions = {
stylesheetMode: SemanticStylesheet["mode"];
styleProjection?: PublicStyleProjection;
refetchStyleProjection?: () => Promise<PublicStyleProjection | undefined>;
publicResume: { publicResume: {
username: string; username: string;
slug: string; slug: string;
}; };
}; };
type ProjectionMismatchReason = const fetchPublicResumePdf = async ({ username, slug }: PublicResumePdfOptions["publicResume"]) => {
| "format-version" const response = await fetch(`/api/resumes/${encodeURIComponent(username)}/${encodeURIComponent(slug)}/pdf`, {
| "language-version" credentials: "include",
| "semantic-tree-version"
| "registry-fingerprint"
| "adapter-fingerprint"
| "render-data-hash"
| "invalid-projection";
const projectionMismatchReason = async (
data: ResumeData,
projection: PublicStyleProjection,
): Promise<ProjectionMismatchReason | null> => {
if (projection.formatVersion !== PUBLIC_STYLE_PROJECTION_FORMAT_VERSION) return "format-version";
if (projection.languageVersion !== 1) return "language-version";
if (projection.semanticTreeVersion !== SEMANTIC_TREE_VERSION) return "semantic-tree-version";
const fingerprints = await getPublicStyleProjectionFingerprints();
if (projection.registryFingerprint !== fingerprints.registryFingerprint) return "registry-fingerprint";
if (projection.adapterFingerprint !== fingerprints.adapterFingerprint) return "adapter-fingerprint";
return (await validatePublicStyleProjection(data, projection)) ? null : "render-data-hash";
};
const fetchPublicResumePdf = async (
publicResume: PublicResumePdfOptions["publicResume"],
reason: ProjectionMismatchReason | "missing-projection",
projection?: PublicStyleProjection,
) => {
const search = new URLSearchParams({
reason,
...(projection
? {
registryFingerprint: projection.registryFingerprint,
adapterFingerprint: projection.adapterFingerprint,
}
: {}),
}); });
const response = await fetch(
`/api/resumes/${encodeURIComponent(publicResume.username)}/${encodeURIComponent(publicResume.slug)}/pdf?${search}`,
{ credentials: "include" },
);
if (!response.ok) throw new Error(`Public PDF fallback failed with ${response.status}`); if (!response.ok) throw new Error(`Public PDF fallback failed with ${response.status}`);
return response.blob(); return response.blob();
}; };
export async function resolvePublicResumePdfBlob({ export async function resolvePublicResumePdfBlob({
data, data,
...options publicResume,
}: PublicResumePdfOptions & { data: ResumeData }): Promise<Blob> { }: PublicResumePdfOptions & { data: ResumeData }): Promise<Blob> {
if (options.stylesheetMode === "legacy") return createResumePdfBlob(data); try {
return await createResumePdfBlob(data);
let projection = options.styleProjection; } catch {
let refetched = false; return fetchPublicResumePdf(publicResume);
const refetch = async () => {
if (!options.refetchStyleProjection || refetched) return;
refetched = true;
try {
projection = await options.refetchStyleProjection();
} catch {
projection = undefined;
}
};
if (!projection) await refetch();
if (!projection) return fetchPublicResumePdf(options.publicResume, "missing-projection");
let reason = await projectionMismatchReason(data, projection).catch(() => "invalid-projection" as const);
if (reason) {
await refetch();
if (!projection) return fetchPublicResumePdf(options.publicResume, "missing-projection");
reason = await projectionMismatchReason(data, projection).catch(() => "invalid-projection" as const);
} }
return reason
? fetchPublicResumePdf(options.publicResume, reason, projection)
: createResumePdfBlob(data, undefined, undefined, { publicStyleProjection: projection });
} }
@@ -1,6 +1,5 @@
// @vitest-environment happy-dom // @vitest-environment happy-dom
import type { PublicStyleProjection } from "@reactive-resume/pdf/public-projection";
import type { ResumeData } from "@reactive-resume/schema/resume/data"; import type { ResumeData } from "@reactive-resume/schema/resume/data";
import type { ReactNode } from "react"; import type { ReactNode } from "react";
import { render, screen } from "@testing-library/react"; import { render, screen } from "@testing-library/react";
@@ -12,30 +11,12 @@ import { sampleResumeData } from "@reactive-resume/schema/resume/sample";
type PdfViewerProps = { type PdfViewerProps = {
className?: string; className?: string;
data: ResumeData; data: ResumeData;
stylesheetMode?: "legacy" | "semantic";
styleProjection?: PublicStyleProjection;
refetchStyleProjection?: () => Promise<PublicStyleProjection | undefined>;
publicResume?: { username: string; slug: string }; publicResume?: { username: string; slug: string };
}; };
const publicResumeMock = vi.hoisted(() => ({ const publicResumeMock = vi.hoisted(() => ({
onDownloadPDF: vi.fn(), onDownloadPDF: vi.fn(),
PdfViewer: vi.fn<(_props: PdfViewerProps) => ReactNode>(() => null), PdfViewer: vi.fn<(_props: PdfViewerProps) => ReactNode>(() => null),
projection: {
formatVersion: 1,
languageVersion: 1,
semanticTreeVersion: 1,
registryFingerprint: "1".repeat(64),
adapterFingerprint: "2".repeat(64),
renderDataHash: "3".repeat(64),
nodes: { resume: {} },
} as PublicStyleProjection,
refetchProjection: vi.fn(),
projectionResult: {
data: undefined as PublicStyleProjection | undefined,
isError: false,
isPending: false,
},
useResumeExport: vi.fn(), useResumeExport: vi.fn(),
resume: undefined as resume: undefined as
| undefined | undefined
@@ -43,61 +24,28 @@ const publicResumeMock = vi.hoisted(() => ({
data: ResumeData; data: ResumeData;
name: string; name: string;
slug: string; slug: string;
stylesheetMode: "legacy" | "semantic";
}, },
})); }));
vi.mock("@tanstack/react-query", () => ({ vi.mock("@tanstack/react-query", () => ({ useQuery: () => ({ data: publicResumeMock.resume }) }));
useQuery: (options: { query: "resume" | "projection" }) =>
options.query === "resume"
? { data: publicResumeMock.resume }
: { ...publicResumeMock.projectionResult, refetch: publicResumeMock.refetchProjection },
}));
vi.mock("@tanstack/react-router", () => ({ vi.mock("@tanstack/react-router", () => ({
getRouteApi: () => ({ getRouteApi: () => ({ useParams: () => ({ username: "amruth", slug: "sample" }) }),
useParams: () => ({ username: "amruth", slug: "sample" }),
}),
})); }));
vi.mock("./pdf-viewer", () => ({ PdfViewer: publicResumeMock.PdfViewer }));
vi.mock("./pdf-viewer", () => ({
PdfViewer: publicResumeMock.PdfViewer,
}));
vi.mock("@/libs/orpc/client", () => ({ vi.mock("@/libs/orpc/client", () => ({
orpc: { orpc: { resume: { getBySlug: { queryOptions: () => ({ query: "resume" }) } } },
resume: {
getBySlug: { queryOptions: () => ({ query: "resume" }) },
getStyleProjection: { queryOptions: () => ({ query: "projection" }) },
},
},
})); }));
vi.mock("@/features/resume/export/use-resume-export", () => ({ vi.mock("@/features/resume/export/use-resume-export", () => ({
useResumeExport: publicResumeMock.useResumeExport, useResumeExport: publicResumeMock.useResumeExport,
})); }));
const { PublicResumeRoute } = await import("./public-resume"); const { PublicResumeRoute } = await import("./public-resume");
beforeAll(() => { beforeAll(() => i18n.loadAndActivate({ locale: "en", messages: {} }));
i18n.loadAndActivate({ locale: "en", messages: {} });
});
beforeEach(() => { beforeEach(() => {
publicResumeMock.resume = { publicResumeMock.resume = { data: sampleResumeData, name: "Sample Resume", slug: "sample" };
data: sampleResumeData,
name: "Sample Resume",
slug: "sample",
stylesheetMode: "semantic",
};
publicResumeMock.projectionResult = {
data: publicResumeMock.projection,
isError: false,
isPending: false,
};
publicResumeMock.PdfViewer.mockClear(); publicResumeMock.PdfViewer.mockClear();
publicResumeMock.refetchProjection.mockReset();
publicResumeMock.refetchProjection.mockResolvedValue({ data: publicResumeMock.projection });
publicResumeMock.useResumeExport.mockReset(); publicResumeMock.useResumeExport.mockReset();
publicResumeMock.useResumeExport.mockReturnValue({ publicResumeMock.useResumeExport.mockReturnValue({
onDownloadPDF: publicResumeMock.onDownloadPDF, onDownloadPDF: publicResumeMock.onDownloadPDF,
@@ -116,78 +64,26 @@ const renderPublicResumeRoute = () =>
); );
describe("PublicResumeRoute", () => { describe("PublicResumeRoute", () => {
it("renders the public resume through the route-local PDF.js viewer", () => { it("passes exposed source data directly to the browser viewer and export fallback", () => {
renderPublicResumeRoute(); renderPublicResumeRoute();
expect(screen.getByTestId("pdf-viewer")).toHaveClass("block", "w-full");
expect(publicResumeMock.PdfViewer).toHaveBeenCalledWith( expect(publicResumeMock.PdfViewer).toHaveBeenCalledWith(
expect.objectContaining({ data: sampleResumeData }), expect.objectContaining({
data: sampleResumeData,
publicResume: { username: "amruth", slug: "sample" },
}),
undefined, undefined,
); );
expect(publicResumeMock.useResumeExport).toHaveBeenCalledWith(publicResumeMock.resume, { expect(publicResumeMock.useResumeExport).toHaveBeenCalledWith(publicResumeMock.resume, {
publicResumePdf: expect.objectContaining({ publicResumePdf: { publicResume: { username: "amruth", slug: "sample" } },
stylesheetMode: "semantic",
styleProjection: publicResumeMock.projection,
publicResume: { username: "amruth", slug: "sample" },
}),
}); });
}); });
it("routes a missing semantic projection to the shared fallback seam", () => {
publicResumeMock.projectionResult = { data: undefined, isError: true, isPending: false };
renderPublicResumeRoute();
expect(publicResumeMock.PdfViewer).toHaveBeenCalledWith(
expect.objectContaining({
stylesheetMode: "semantic",
styleProjection: undefined,
refetchStyleProjection: expect.any(Function),
publicResume: { username: "amruth", slug: "sample" },
}),
undefined,
);
expect(publicResumeMock.useResumeExport).toHaveBeenCalledWith(
publicResumeMock.resume,
expect.objectContaining({
publicResumePdf: expect.objectContaining({
stylesheetMode: "semantic",
}),
}),
);
});
it("keeps missing legacy projections on the local rendering path", () => {
if (publicResumeMock.resume) publicResumeMock.resume.stylesheetMode = "legacy";
publicResumeMock.projectionResult = { data: undefined, isError: false, isPending: false };
renderPublicResumeRoute();
expect(publicResumeMock.PdfViewer).toHaveBeenCalledWith(
expect.objectContaining({ stylesheetMode: "legacy", styleProjection: undefined }),
undefined,
);
});
it("loads the public projection and passes it to the shared viewer", () => {
renderPublicResumeRoute();
expect(publicResumeMock.PdfViewer).toHaveBeenCalledWith(
expect.objectContaining({
styleProjection: publicResumeMock.projection,
refetchStyleProjection: expect.any(Function),
publicResume: { username: "amruth", slug: "sample" },
}),
undefined,
);
});
it("lets the public resume page grow to the full PDF length", () => { it("lets the public resume page grow to the full PDF length", () => {
renderPublicResumeRoute(); renderPublicResumeRoute();
const viewerFrame = screen.getByTestId("pdf-viewer").parentElement; const viewerFrame = screen.getByTestId("pdf-viewer").parentElement;
const page = viewerFrame?.parentElement; const page = viewerFrame?.parentElement;
expect(page).not.toHaveClass("min-h-svh", "h-svh", "max-h-svh", "overflow-hidden"); expect(page).not.toHaveClass("min-h-svh", "h-svh", "max-h-svh", "overflow-hidden");
expect(viewerFrame).not.toHaveClass("min-h-0", "flex-1", "overflow-hidden"); expect(viewerFrame).not.toHaveClass("min-h-0", "flex-1", "overflow-hidden");
}); });
@@ -3,7 +3,7 @@ import { Trans } from "@lingui/react/macro";
import { CircleNotchIcon, DownloadSimpleIcon } from "@phosphor-icons/react"; import { CircleNotchIcon, DownloadSimpleIcon } from "@phosphor-icons/react";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { getRouteApi } from "@tanstack/react-router"; import { getRouteApi } from "@tanstack/react-router";
import { useCallback, useMemo } from "react"; import { useMemo } from "react";
import { BrandIcon } from "@reactive-resume/ui/components/brand-icon"; import { BrandIcon } from "@reactive-resume/ui/components/brand-icon";
import { Button } from "@reactive-resume/ui/components/button"; import { Button } from "@reactive-resume/ui/components/button";
import { LoadingScreen } from "@/components/layout/loading-screen"; import { LoadingScreen } from "@/components/layout/loading-screen";
@@ -17,30 +17,12 @@ export function PublicResumeRoute() {
const { username, slug } = publicResumeRoute.useParams(); const { username, slug } = publicResumeRoute.useParams();
const { data: resume } = useQuery(orpc.resume.getBySlug.queryOptions({ input: { username, slug } })); const { data: resume } = useQuery(orpc.resume.getBySlug.queryOptions({ input: { username, slug } }));
const projectionQuery = useQuery(
orpc.resume.getStyleProjection.queryOptions({ input: { username, slug }, enabled: resume !== undefined }),
);
const styleProjection =
projectionQuery.data && Object.keys(projectionQuery.data.nodes).length > 0 ? projectionQuery.data : undefined;
const publicResume = useMemo(() => ({ username, slug }), [slug, username]); const publicResume = useMemo(() => ({ username, slug }), [slug, username]);
const refetchStyleProjection = useCallback(async () => {
const result = await projectionQuery.refetch();
return result.data;
}, [projectionQuery.refetch]);
const { onDownloadPDF, isExporting } = useResumeExport(resume, { const { onDownloadPDF, isExporting } = useResumeExport(resume, {
...(resume ...(resume ? { publicResumePdf: { publicResume } } : {}),
? {
publicResumePdf: {
stylesheetMode: resume.stylesheetMode,
publicResume,
refetchStyleProjection,
...(styleProjection ? { styleProjection } : {}),
},
}
: {}),
}); });
if (!resume || projectionQuery.isPending) return <LoadingScreen />; if (!resume) return <LoadingScreen />;
const { basics, picture } = resume.data; const { basics, picture } = resume.data;
@@ -66,14 +48,7 @@ export function PublicResumeRoute() {
</header> </header>
<main className="w-full max-w-5xl bg-white print:max-w-full"> <main className="w-full max-w-5xl bg-white print:max-w-full">
<PdfViewer <PdfViewer data={resume.data} className="block w-full" publicResume={publicResume} />
data={resume.data}
className="block w-full"
stylesheetMode={resume.stylesheetMode}
styleProjection={styleProjection}
publicResume={publicResume}
refetchStyleProjection={refetchStyleProjection}
/>
</main> </main>
<footer className="flex justify-center print:hidden"> <footer className="flex justify-center print:hidden">
@@ -1,18 +1,30 @@
// @vitest-environment happy-dom // @vitest-environment happy-dom
import type { SemanticCssDiagnostic } from "@reactive-resume/resume/stylesheet"; import type { SemanticCssDiagnostic, StyleProgram } from "@reactive-resume/resume/stylesheet";
import { fireEvent, render, screen, waitFor, within } from "@testing-library/react"; import { act, fireEvent, render, screen, waitFor, within } from "@testing-library/react";
import { beforeAll, describe, expect, it, vi } from "vitest"; import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { EditorView } from "@codemirror/view"; import { EditorView } from "@codemirror/view";
import { i18n } from "@lingui/core"; import { i18n } from "@lingui/core";
import { I18nProvider } from "@lingui/react"; import { I18nProvider } from "@lingui/react";
import { defaultResumeData } from "@reactive-resume/schema/resume/default";
import { TooltipProvider } from "@reactive-resume/ui/components/tooltip"; import { TooltipProvider } from "@reactive-resume/ui/components/tooltip";
import StylesheetEditorShell, { StylesheetCodeEditor } from "./editor"; import StylesheetEditorShell, { StylesheetCodeEditor } from "./editor";
import { LegacyStylesheetBanner } from "./legacy-banner"; import { LegacyStylesheetBanner } from "./legacy-banner";
import { StylesheetStatus } from "./status"; import { StylesheetStatus } from "./status";
import { useStylesheetStore } from "./store";
const media = vi.hoisted(() => ({ mobile: false })); const media = vi.hoisted(() => ({ mobile: false }));
const compileWorker = vi.hoisted(() => ({
program: { languageVersion: 1, rules: [] } as StyleProgram | null,
diagnostics: [] as SemanticCssDiagnostic[],
}));
const builder = vi.hoisted(() => ({
canUndo: false,
canRedo: false,
data: undefined as typeof defaultResumeData | undefined,
isLocked: false,
undo: vi.fn(),
redo: vi.fn(),
}));
vi.mock("usehooks-ts", async (importOriginal) => ({ vi.mock("usehooks-ts", async (importOriginal) => ({
...(await importOriginal<typeof import("usehooks-ts")>()), ...(await importOriginal<typeof import("usehooks-ts")>()),
@@ -23,16 +35,52 @@ vi.mock("@/features/theme/provider", () => ({
useTheme: () => ({ theme: "light" }), useTheme: () => ({ theme: "light" }),
})); }));
const error: SemanticCssDiagnostic = { vi.mock("@/features/resume/builder/draft", () => ({
code: "SEMANTIC_CSS_UNKNOWN_PROPERTY", useResumeData: () => builder.data,
useIsResumeLocked: () => builder.isLocked,
useUpdateResumeData: () => (update: (draft: typeof defaultResumeData) => void) => {
if (builder.data) update(builder.data);
},
useResumeStore: (selector: (state: object) => unknown) =>
selector({ canUndo: builder.canUndo, canRedo: builder.canRedo, undo: builder.undo, redo: builder.redo }),
}));
vi.mock("./worker-client", () => ({
createCompileWorkerClient: () => ({
compile: vi.fn(async ({ editGeneration }: { editGeneration: number }) => ({
type: "compile_result",
requestId: editGeneration,
editGeneration,
program: compileWorker.program,
diagnostics: compileWorker.diagnostics,
colorTokens: [],
})),
destroy: vi.fn(),
}),
}));
const recoverableError: SemanticCssDiagnostic = {
code: "INVALID_VALUE",
severity: "error", severity: "error",
message: "Unknown property", message: "Invalid value",
range: { range: {
start: { line: 2, column: 3, offset: 17 }, start: { line: 2, column: 3, offset: 17 },
end: { line: 2, column: 9, offset: 23 }, end: { line: 2, column: 9, offset: 23 },
}, },
}; };
const fatalError: SemanticCssDiagnostic = {
...recoverableError,
code: "VERSION_MISMATCH",
message: "Version mismatch",
};
const resolutionError: SemanticCssDiagnostic = {
...recoverableError,
code: "UNRESOLVED_VARIABLE",
message: "Undefined variable --missing",
};
const guideName = /read the applying custom styles guide.*opens in new tab/i; const guideName = /read the applying custom styles guide.*opens in new tab/i;
const expectGuideLink = (root: HTMLElement) => { const expectGuideLink = (root: HTMLElement) => {
@@ -47,28 +95,48 @@ beforeAll(() => {
Object.defineProperty(Element.prototype, "getAnimations", { configurable: true, value: () => [] }); Object.defineProperty(Element.prototype, "getAnimations", { configurable: true, value: () => [] });
}); });
beforeEach(() => {
media.mobile = false;
builder.data = structuredClone(defaultResumeData);
builder.isLocked = false;
builder.canUndo = false;
builder.canRedo = false;
builder.undo.mockReset();
builder.redo.mockReset();
compileWorker.program = { languageVersion: 1, rules: [] };
compileWorker.diagnostics = [];
});
const renderWithI18n = (element: React.ReactNode) => render(<I18nProvider i18n={i18n}>{element}</I18nProvider>); const renderWithI18n = (element: React.ReactNode) => render(<I18nProvider i18n={i18n}>{element}</I18nProvider>);
describe("stylesheet editor status", () => { describe("stylesheet editor status", () => {
it("shows that invalid source keeps the last valid preview", () => { it("explains that fatal source falls back to base styles", () => {
renderWithI18n(<StylesheetStatus mode="semantic" status="error" diagnostics={[error]} />); renderWithI18n(<StylesheetStatus mode="semantic" status="idle" diagnostics={[fatalError]} />);
expect(screen.getByText(/preview and export use the last valid version/i)).toBeInTheDocument(); expect(screen.getByText(/preview and export fall back to base styles/i)).toBeInTheDocument();
expect(screen.getByText("Unknown property")).toBeInTheDocument(); expect(screen.getByText("Version mismatch")).toBeInTheDocument();
});
it("explains that recoverable errors preserve valid styles", () => {
renderWithI18n(<StylesheetStatus mode="semantic" status="idle" diagnostics={[recoverableError]} />);
expect(screen.getByText("Valid with errors")).toBeInTheDocument();
expect(screen.getByText(/preview and export keep valid styles/i)).toBeInTheDocument();
expect(screen.queryByText(/fall back to base styles/i)).not.toBeInTheDocument();
}); });
it("labels a valid legacy draft as ready to activate", () => { it("labels a valid legacy draft as ready to activate", () => {
renderWithI18n(<StylesheetStatus mode="legacy" status="idle" diagnostics={[]} />); renderWithI18n(<StylesheetStatus mode="legacy" status="idle" diagnostics={[]} />);
expect(screen.getByText("Ready to activate")).toBeInTheDocument(); expect(screen.getByText("Ready to activate")).toBeInTheDocument();
expect(screen.queryByText("Applied")).not.toBeInTheDocument();
}); });
it("labels legacy warnings without claiming they are applied", () => { it("labels a legacy draft with warnings as ready to activate", () => {
renderWithI18n(<StylesheetStatus mode="legacy" status="idle" diagnostics={[{ ...error, severity: "warning" }]} />); renderWithI18n(
<StylesheetStatus mode="legacy" status="idle" diagnostics={[{ ...recoverableError, severity: "warning" }]} />,
);
expect(screen.getByText("Ready to activate with warnings")).toBeInTheDocument(); expect(screen.getByText("Ready to activate with warnings")).toBeInTheDocument();
expect(screen.queryByText("Applied with warnings")).not.toBeInTheDocument();
}); });
it("disables activation while the converted draft has errors", () => { it("disables activation while the converted draft has errors", () => {
@@ -113,7 +181,7 @@ describe("StylesheetCodeEditor", () => {
<StylesheetCodeEditor <StylesheetCodeEditor
value={"@version 1;\nsection { color: red; }\n"} value={"@version 1;\nsection { color: red; }\n"}
{...props} {...props}
diagnostics={[error]} diagnostics={[recoverableError]}
theme="dark" theme="dark"
readOnly readOnly
/> />
@@ -173,18 +241,105 @@ describe("StylesheetEditorShell", () => {
expectGuideLink(container); expectGuideLink(container);
}); });
it("makes the editor and mutation controls read-only while a restore is pending", () => { it("has no apply or save action for an already-semantic stylesheet", async () => {
media.mobile = false; if (!builder.data) throw new Error("Missing resume fixture");
useStylesheetStore.setState({ builder.data.metadata.stylesheet = {
mode: "legacy", mode: "semantic",
source: { languageVersion: 1, text: "@version 1;\n" },
};
render(
<I18nProvider i18n={i18n}>
<TooltipProvider>
<StylesheetEditorShell />
</TooltipProvider>
</I18nProvider>,
);
await screen.findByText("Valid");
expect(screen.queryByRole("button", { name: /activate semantic css/i })).not.toBeInTheDocument();
expect(screen.queryByRole("button", { name: /save|apply/i })).not.toBeInTheDocument();
});
it("writes semantic edits into the ordinary resume draft immediately", () => {
if (!builder.data) throw new Error("Missing resume fixture");
builder.data.metadata.stylesheet = {
mode: "semantic",
source: { languageVersion: 1, text: "@version 1;\n" },
};
render(
<I18nProvider i18n={i18n}>
<TooltipProvider>
<StylesheetEditorShell />
</TooltipProvider>
</I18nProvider>,
);
const textbox = screen.getByRole("textbox", { name: "Semantic CSS stylesheet" });
const view = EditorView.findFromDOM(textbox);
if (!view) throw new Error("Missing editor view");
act(() => view.dispatch({ changes: { from: view.state.doc.length, insert: "name { color: blue; }\n" } }));
expect(builder.data.metadata.stylesheet.source.text).toBe("@version 1;\nname { color: blue; }\n");
});
it("switches a converted legacy draft through the ordinary resume update", async () => {
render(
<I18nProvider i18n={i18n}>
<TooltipProvider>
<StylesheetEditorShell />
</TooltipProvider>
</I18nProvider>,
);
const activate = await screen.findByRole("button", { name: "Activate Semantic CSS" });
await waitFor(() => expect(activate).toBeEnabled());
fireEvent.click(activate);
expect(builder.data?.metadata.stylesheet).toEqual({
mode: "semantic",
source: { languageVersion: 1, text: "@version 1;\n" }, source: { languageVersion: 1, text: "@version 1;\n" },
applied: { languageVersion: 1, text: "@version 1;\n" },
diagnostics: [],
status: "idle",
canUndo: true,
canRedo: true,
restoreLocked: true,
}); });
});
it("allows a converted legacy draft with recoverable errors to activate", async () => {
compileWorker.diagnostics = [resolutionError];
render(
<I18nProvider i18n={i18n}>
<TooltipProvider>
<StylesheetEditorShell />
</TooltipProvider>
</I18nProvider>,
);
const activate = await screen.findByRole("button", { name: "Activate Semantic CSS" });
await waitFor(() => expect(activate).toBeEnabled());
fireEvent.click(activate);
expect(builder.data?.metadata.stylesheet?.mode).toBe("semantic");
});
it("keeps legacy activation disabled for fatal diagnostics", async () => {
compileWorker.diagnostics = [fatalError];
render(
<I18nProvider i18n={i18n}>
<TooltipProvider>
<StylesheetEditorShell />
</TooltipProvider>
</I18nProvider>,
);
await screen.findByText("Fatal error");
expect(screen.getByRole("button", { name: "Activate Semantic CSS" })).toBeDisabled();
});
it("makes editor mutation controls read-only while the resume is locked", () => {
builder.isLocked = true;
builder.canUndo = true;
builder.canRedo = true;
render( render(
<I18nProvider i18n={i18n}> <I18nProvider i18n={i18n}>
@@ -202,19 +357,10 @@ describe("StylesheetEditorShell", () => {
expect(screen.getByRole("button", { name: "Undo stylesheet edit" })).toBeDisabled(); expect(screen.getByRole("button", { name: "Undo stylesheet edit" })).toBeDisabled();
expect(screen.getByRole("button", { name: "Redo stylesheet edit" })).toBeDisabled(); expect(screen.getByRole("button", { name: "Redo stylesheet edit" })).toBeDisabled();
expect(screen.getByRole("button", { name: "Format stylesheet" })).toBeDisabled(); expect(screen.getByRole("button", { name: "Format stylesheet" })).toBeDisabled();
expect(screen.getByRole("button", { name: "Reset to applied stylesheet" })).toBeDisabled();
}); });
it("moves the only visible editor into a titled mobile sheet", async () => { it("moves the only visible editor into a titled mobile sheet", async () => {
media.mobile = true; media.mobile = true;
useStylesheetStore.setState({
mode: "legacy",
source: { languageVersion: 1, text: "@version 1;\n" },
applied: { languageVersion: 1, text: "@version 1;\n" },
diagnostics: [{ ...error, severity: "warning" }],
status: "idle",
restoreLocked: false,
});
const { container } = render( const { container } = render(
<I18nProvider i18n={i18n}> <I18nProvider i18n={i18n}>
@@ -231,8 +377,7 @@ describe("StylesheetEditorShell", () => {
expect(within(sheet).getByRole("heading", { name: "Semantic CSS stylesheet" })).toBeInTheDocument(); expect(within(sheet).getByRole("heading", { name: "Semantic CSS stylesheet" })).toBeInTheDocument();
expect(within(sheet).getByRole("button", { name: "Activate Semantic CSS" })).toBeInTheDocument(); expect(within(sheet).getByRole("button", { name: "Activate Semantic CSS" })).toBeInTheDocument();
expect(within(sheet).getByRole("toolbar", { name: "Stylesheet editor" })).toBeInTheDocument(); expect(within(sheet).getByRole("toolbar", { name: "Stylesheet editor" })).toBeInTheDocument();
expect(within(sheet).getByText("Ready to activate with warnings")).toBeInTheDocument(); await within(sheet).findByText("Ready to activate");
expect(within(sheet).getByText("Unknown property")).toBeInTheDocument();
expectGuideLink(sheet); expectGuideLink(sheet);
expect(document.querySelectorAll(".cm-editor")).toHaveLength(1); expect(document.querySelectorAll(".cm-editor")).toHaveLength(1);
media.mobile = false; media.mobile = false;
@@ -1,5 +1,7 @@
import type { Extension } from "@codemirror/state"; import type { Extension } from "@codemirror/state";
import type { SemanticCssDiagnostic } from "@reactive-resume/resume/stylesheet"; import type { SemanticCssDiagnostic, SemanticNode } from "@reactive-resume/resume/stylesheet";
import type { ResumeData } from "@reactive-resume/schema/resume/data";
import type { StylesheetSource } from "@reactive-resume/schema/resume/stylesheet";
import type { SemanticCssColorToken } from "./color-tokens"; import type { SemanticCssColorToken } from "./color-tokens";
import type { SemanticCssEditorMetadata } from "./protocol"; import type { SemanticCssEditorMetadata } from "./protocol";
import { defaultKeymap, indentWithTab } from "@codemirror/commands"; import { defaultKeymap, indentWithTab } from "@codemirror/commands";
@@ -17,11 +19,20 @@ import {
import { t } from "@lingui/core/macro"; import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro"; import { Trans } from "@lingui/react/macro";
import { BookOpenIcon } from "@phosphor-icons/react"; import { BookOpenIcon } from "@phosphor-icons/react";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useMediaQuery } from "usehooks-ts"; import { useMediaQuery } from "usehooks-ts";
import { convertLegacyStyleRules } from "@reactive-resume/pdf/semantic-legacy";
import {
buildSemanticTree,
getTemplateSemanticManifest,
semanticNodeKeys,
shouldShowResumeHeader,
} from "@reactive-resume/pdf/semantic-tree";
import { isFatalStylesheetDiagnostic } from "@reactive-resume/resume/stylesheet";
import { PopoverTrigger } from "@reactive-resume/ui/components/popover"; import { PopoverTrigger } from "@reactive-resume/ui/components/popover";
import { Sheet, SheetContent, SheetTitle } from "@reactive-resume/ui/components/sheet"; import { Sheet, SheetContent, SheetTitle } from "@reactive-resume/ui/components/sheet";
import { ColorPicker } from "@/components/input/color-picker"; import { ColorPicker } from "@/components/input/color-picker";
import { useIsResumeLocked, useResumeData, useResumeStore, useUpdateResumeData } from "@/features/resume/builder/draft";
import { useTheme } from "@/features/theme/provider"; import { useTheme } from "@/features/theme/provider";
import { useBuilderSidebarStore } from "@/routes/builder/$resumeId/-store/sidebar"; import { useBuilderSidebarStore } from "@/routes/builder/$resumeId/-store/sidebar";
import { compositionAwareDocumentListener, createSemanticCssEditorExtensions } from "./editor-extensions"; import { compositionAwareDocumentListener, createSemanticCssEditorExtensions } from "./editor-extensions";
@@ -29,8 +40,8 @@ import { enterStylesheetFocusMode } from "./focus-mode";
import { formatEditorDocument } from "./formatter"; import { formatEditorDocument } from "./formatter";
import { LegacyStylesheetBanner } from "./legacy-banner"; import { LegacyStylesheetBanner } from "./legacy-banner";
import { StylesheetStatus } from "./status"; import { StylesheetStatus } from "./status";
import { useStylesheetStore } from "./store";
import { StylesheetToolbar } from "./toolbar"; import { StylesheetToolbar } from "./toolbar";
import { createCompileWorkerClient } from "./worker-client";
const externalReplacement = Annotation.define<boolean>(); const externalReplacement = Annotation.define<boolean>();
const emptyMetadata: SemanticCssEditorMetadata = { const emptyMetadata: SemanticCssEditorMetadata = {
@@ -314,30 +325,78 @@ type StylesheetEditorShellProps = {
readOnly?: boolean; readOnly?: boolean;
}; };
const pageDimensions = (data: ResumeData) => {
const size = data.metadata.page.format === "letter" ? { width: 612, height: 792 } : { width: 595.28, height: 841.89 };
return data.metadata.layout.pages.map((_page, index) => ({
pageKey: semanticNodeKeys.page(index + 1),
...size,
}));
};
const createEditorMetadata = (data: ResumeData): SemanticCssEditorMetadata => {
const pages = data.metadata.layout.pages.map((page, index) =>
buildSemanticTree({
data,
template: data.metadata.template,
page,
pageNumber: index + 1,
showHeader: shouldShowResumeHeader(data, index),
}),
);
const semanticTree: SemanticNode = {
key: semanticNodeKeys.resume(),
kind: "resume",
attributes: { template: data.metadata.template },
roles: [],
children: pages.flatMap(({ children }) => children),
};
return {
semanticTree,
templateParts: getTemplateSemanticManifest(data.metadata.template).parts.map(({ name }) => name),
};
};
function StylesheetEditorShell({ readOnly = false }: StylesheetEditorShellProps) { function StylesheetEditorShell({ readOnly = false }: StylesheetEditorShellProps) {
const { theme } = useTheme(); const { theme } = useTheme();
const isMobile = useMediaQuery("(max-width: 767px)", { initializeWithValue: false }); const isMobile = useMediaQuery("(max-width: 767px)", { initializeWithValue: false });
const [focusOpen, setFocusOpen] = useState(false); const [focusOpen, setFocusOpen] = useState(false);
const [diagnostics, setDiagnostics] = useState<readonly SemanticCssDiagnostic[]>([]);
const [colorTokens, setColorTokens] = useState<readonly SemanticCssColorToken[]>([]);
const [status, setStatus] = useState<"idle" | "compiling" | "error">("compiling");
const [compiler, setCompiler] = useState<ReturnType<typeof createCompileWorkerClient>>();
const restoreDesktopRef = useRef<(() => void) | null>(null); const restoreDesktopRef = useRef<(() => void) | null>(null);
const mode = useStylesheetStore((state) => state.mode); const data = useResumeData();
const source = useStylesheetStore((state) => state.source.text); const updateResumeData = useUpdateResumeData();
const applied = useStylesheetStore((state) => state.applied.text); const isLocked = useIsResumeLocked();
const diagnostics = useStylesheetStore((state) => state.diagnostics); const canUndo = useResumeStore((state) => state.canUndo);
const colorTokens = useStylesheetStore((state) => state.colorTokens); const canRedo = useResumeStore((state) => state.canRedo);
const metadata = useStylesheetStore((state) => state.editorMetadata); const undo = useResumeStore((state) => state.undo);
const status = useStylesheetStore((state) => state.status); const redo = useResumeStore((state) => state.redo);
const restoreLocked = useStylesheetStore((state) => state.restoreLocked);
const canUndo = useStylesheetStore((state) => state.canUndo);
const canRedo = useStylesheetStore((state) => state.canRedo);
const setSourceText = useStylesheetStore((state) => state.setSourceText);
const setFocused = useStylesheetStore((state) => state.setFocused);
const activate = useStylesheetStore((state) => state.activate);
const undo = useStylesheetStore((state) => state.undo);
const redo = useStylesheetStore((state) => state.redo);
const refreshIntelligence = useStylesheetStore((state) => state.refreshIntelligence);
const editorViewRef = useRef<EditorView | null>(null); const editorViewRef = useRef<EditorView | null>(null);
const hasErrors = status === "error" || diagnostics.some(({ severity }) => severity === "error"); const compileGenerationRef = useRef(0);
const isChecking = status === "compiling" || status === "preflighting" || status === "saving"; useEffect(() => {
const client = createCompileWorkerClient(
() =>
new Worker(new URL("./stylesheet.worker.ts", import.meta.url), {
type: "module",
name: "semantic-css-compiler",
}),
);
setCompiler(client);
return () => client.destroy();
}, []);
const stylesheet = data?.metadata.stylesheet;
const mode = stylesheet?.mode ?? "legacy";
const source = useMemo<StylesheetSource>(
() =>
stylesheet?.source ??
(data ? convertLegacyStyleRules(data).source : { languageVersion: 1, text: "@version 1;\n" }),
[data, stylesheet],
);
const metadata = useMemo(() => (data ? createEditorMetadata(data) : emptyMetadata), [data]);
const hasFatalErrors = status === "error" || diagnostics.some(isFatalStylesheetDiagnostic);
const isChecking = status === "compiling";
const disabled = readOnly || isLocked;
useEffect( useEffect(
() => () => { () => () => {
@@ -347,8 +406,59 @@ function StylesheetEditorShell({ readOnly = false }: StylesheetEditorShellProps)
); );
useEffect(() => { useEffect(() => {
refreshIntelligence(); if (!compiler || !data) return;
}, [refreshIntelligence]); let cancelled = false;
const editGeneration = ++compileGenerationRef.current;
setStatus("compiling");
setColorTokens([]);
const timer = window.setTimeout(() => {
void compiler
.compile({
editGeneration,
source,
semanticTree: metadata.semanticTree,
baseSettings: {
picture: data.picture,
template: data.metadata.template,
design: data.metadata.design,
typography: data.metadata.typography,
page: data.metadata.page,
layout: { sidebarWidth: data.metadata.layout.sidebarWidth },
},
pages: pageDimensions(data),
})
.then((result) => {
if (cancelled || result.editGeneration !== compileGenerationRef.current) return;
setDiagnostics(result.diagnostics);
setColorTokens(result.colorTokens ?? []);
setStatus(result.program && !result.diagnostics.some(isFatalStylesheetDiagnostic) ? "idle" : "error");
})
.catch(() => {
if (!cancelled && editGeneration === compileGenerationRef.current) setStatus("error");
});
}, 180);
return () => {
cancelled = true;
window.clearTimeout(timer);
};
}, [compiler, data, metadata, source]);
if (!data) return null;
const setSourceText = (text: string) => {
if (disabled || text === source.text) return;
updateResumeData((draft) => {
draft.metadata.stylesheet = { mode, source: { ...source, text } };
});
};
const activate = () => {
if (disabled || mode === "semantic" || hasFatalErrors || isChecking) return;
updateResumeData((draft) => {
draft.metadata.stylesheet = { mode: "semantic", source };
});
};
const toggleFocus = () => { const toggleFocus = () => {
if (isMobile) { if (isMobile) {
@@ -374,15 +484,14 @@ function StylesheetEditorShell({ readOnly = false }: StylesheetEditorShellProps)
const editor = ( const editor = (
<StylesheetCodeEditor <StylesheetCodeEditor
value={source} value={source.text}
diagnostics={diagnostics} diagnostics={diagnostics}
colorTokens={colorTokens} colorTokens={colorTokens}
metadata={metadata} metadata={metadata}
theme={theme} theme={theme}
readOnly={readOnly || restoreLocked} readOnly={disabled}
label={t`Semantic CSS stylesheet`} label={t`Semantic CSS stylesheet`}
onChange={setSourceText} onChange={setSourceText}
onFocusChange={setFocused}
onReady={(view) => { onReady={(view) => {
editorViewRef.current = view; editorViewRef.current = view;
}} }}
@@ -393,22 +502,21 @@ function StylesheetEditorShell({ readOnly = false }: StylesheetEditorShellProps)
const editorChrome = ( const editorChrome = (
<div className="space-y-3"> <div className="space-y-3">
{mode === "legacy" && ( {mode === "legacy" && (
<LegacyStylesheetBanner disabled={restoreLocked || hasErrors || isChecking} onActivate={activate} /> <LegacyStylesheetBanner disabled={disabled || hasFatalErrors || isChecking} onActivate={activate} />
)} )}
<StylesheetToolbar <StylesheetToolbar
source={source} source={source.text}
canUndo={canUndo} canUndo={canUndo}
canRedo={canRedo} canRedo={canRedo}
focused={focusOpen} focused={focusOpen}
disabled={restoreLocked} disabled={disabled}
onUndo={undo} onUndo={undo}
onRedo={redo} onRedo={redo}
onFormat={() => { onFormat={() => {
const view = editorViewRef.current; const view = editorViewRef.current;
if (view) void formatEditorDocument(view).catch(() => undefined); if (view) void formatEditorDocument(view).catch(() => undefined);
}} }}
onReset={() => setSourceText(applied)}
onFocusToggle={toggleFocus} onFocusToggle={toggleFocus}
/> />
@@ -1,62 +0,0 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { inspectPdfPageCount } from "./pdf-inspection";
const mocks = vi.hoisted(() => ({
workerDestroy: vi.fn(),
getDocument: vi.fn(),
}));
vi.mock("pdfjs-dist/legacy/build/pdf.mjs", () => ({
PDFWorker: class {
destroy = mocks.workerDestroy;
},
getDocument: mocks.getDocument,
}));
describe("inspectPdfPageCount", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("inspects a copy through a nested worker without detaching the result buffer", async () => {
const destroy = vi.fn();
const nestedWorker = { terminate: vi.fn() } as unknown as Worker;
mocks.getDocument.mockReturnValue({ promise: Promise.resolve({ numPages: 3 }), destroy });
const pdf = Uint8Array.of(1, 2, 3, 4).buffer;
await expect(inspectPdfPageCount(pdf, () => nestedWorker)).resolves.toBe(3);
expect(mocks.getDocument).toHaveBeenCalledWith(
expect.objectContaining({ data: expect.any(ArrayBuffer), worker: expect.any(Object) }),
);
const inspectedPdf = mocks.getDocument.mock.calls[0]?.[0].data as ArrayBuffer;
expect(inspectedPdf).not.toBe(pdf);
expect(Array.from(new Uint8Array(inspectedPdf))).toEqual([1, 2, 3, 4]);
expect(Array.from(new Uint8Array(pdf))).toEqual([1, 2, 3, 4]);
expect(destroy).toHaveBeenCalledOnce();
expect(nestedWorker.terminate).toHaveBeenCalledOnce();
});
it("destroys the loading task and nested worker when parsing fails", async () => {
const destroy = vi.fn();
const nestedWorker = { terminate: vi.fn() } as unknown as Worker;
mocks.getDocument.mockReturnValue({ promise: Promise.reject(new Error("invalid PDF")), destroy });
await expect(inspectPdfPageCount(new ArrayBuffer(4), () => nestedWorker)).rejects.toThrow("invalid PDF");
expect(destroy).toHaveBeenCalledOnce();
expect(nestedWorker.terminate).toHaveBeenCalledOnce();
});
it("terminates the nested worker even when loading-task cleanup fails", async () => {
const nestedWorker = { terminate: vi.fn() } as unknown as Worker;
mocks.getDocument.mockReturnValue({
promise: Promise.resolve({ numPages: 1 }),
destroy: vi.fn().mockRejectedValue(new Error("cleanup failed")),
});
await expect(inspectPdfPageCount(new ArrayBuffer(4), () => nestedWorker)).rejects.toThrow("cleanup failed");
expect(nestedWorker.terminate).toHaveBeenCalledOnce();
});
});
@@ -1,39 +0,0 @@
let pdfModule: Promise<typeof import("pdfjs-dist/legacy/build/pdf.mjs")>;
const loadPdfModule = () => (pdfModule ??= import("pdfjs-dist/legacy/build/pdf.mjs"));
const createNestedWorker = () =>
new Worker(new URL("pdfjs-dist/legacy/build/pdf.worker.min.mjs", import.meta.url), {
type: "module",
name: "semantic-css-pdfjs",
});
export async function initializePdfInspection(): Promise<void> {
await loadPdfModule();
}
export async function inspectPdfPageCount(
pdf: ArrayBuffer,
createWorker: () => Worker = createNestedWorker,
): Promise<number> {
const { PDFWorker, getDocument } = await loadPdfModule();
const nestedWorker = createWorker();
const WorkerWithPort = PDFWorker as unknown as new (options: { port: Worker }) => InstanceType<typeof PDFWorker>;
const worker = new WorkerWithPort({ port: nestedWorker });
let loadingTask: ReturnType<typeof getDocument> | undefined;
try {
// PDF.js transfers its input to the nested worker and detaches the buffer.
// Keep the caller's buffer intact so preflight can return those same bytes.
loadingTask = getDocument({ data: pdf.slice(0), worker });
const document = await loadingTask.promise;
return document.numPages;
} finally {
try {
if (loadingTask) await loadingTask.destroy();
else worker.destroy();
} finally {
nestedWorker.terminate();
}
}
}
@@ -1,96 +0,0 @@
import type { PreflightWorkerRequest } from "./protocol";
import { afterEach, describe, expect, it, vi } from "vitest";
const mocks = vi.hoisted(() => ({
renderPreflightPdf: vi.fn(),
initializePdfInspection: vi.fn(async () => undefined),
inspectPdfPageCount: vi.fn(),
}));
vi.mock("@reactive-resume/pdf/preflight", () => ({
renderPreflightPdf: mocks.renderPreflightPdf,
}));
vi.mock("./pdf-inspection", () => ({
initializePdfInspection: mocks.initializePdfInspection,
inspectPdfPageCount: mocks.inspectPdfPageCount,
}));
describe("stylesheet preflight worker", () => {
afterEach(() => {
vi.unstubAllGlobals();
vi.clearAllMocks();
});
it("serializes schema errors into a correlated preflight error packet", async () => {
let handler: ((event: MessageEvent<PreflightWorkerRequest>) => Promise<void>) | undefined;
const postMessage = vi.fn();
vi.stubGlobal("self", {
postMessage,
addEventListener: vi.fn((_type, listener) => {
handler = listener as typeof handler;
}),
});
const issues = [{ path: ["customSections", 0, "items", 0, "company"] }];
mocks.renderPreflightPdf.mockRejectedValueOnce(
Object.assign(new Error("Invalid resume data"), { name: "ZodError", issues }),
);
vi.resetModules();
await import("./preflight.worker");
await handler?.({
data: {
type: "preflight",
requestId: 7,
editGeneration: 3,
input: {} as never,
limits: {} as never,
},
} as unknown as MessageEvent<PreflightWorkerRequest>);
expect(postMessage).toHaveBeenCalledWith({
type: "preflight_error",
requestId: 7,
editGeneration: 3,
cause: { name: "ZodError", message: "Invalid resume data", issues },
});
});
it("includes a sanitized cause when PDF preflight throws an unexpected error", async () => {
let handler: ((event: MessageEvent<PreflightWorkerRequest>) => Promise<void>) | undefined;
const postMessage = vi.fn();
vi.stubGlobal("self", {
postMessage,
addEventListener: vi.fn((_type, listener) => {
handler = listener as typeof handler;
}),
});
mocks.renderPreflightPdf.mockRejectedValueOnce(new Error("Canvas is already closed"));
vi.resetModules();
await import("./preflight.worker");
await handler?.({
data: {
type: "preflight",
requestId: 8,
editGeneration: 4,
input: {} as never,
limits: {} as never,
},
} as unknown as MessageEvent<PreflightWorkerRequest>);
expect(postMessage).toHaveBeenCalledWith(
expect.objectContaining({
type: "preflight_result",
requestId: 8,
editGeneration: 4,
result: expect.objectContaining({
ok: false,
code: "STYLESHEET_PREFLIGHT_WORKER_FAILED",
message: expect.stringContaining("Canvas is already closed"),
diagnostics: [],
}),
}),
);
});
});
@@ -1,101 +0,0 @@
/// <reference lib="webworker" />
import type { PdfPreflightFailure } from "@reactive-resume/pdf/preflight";
import type {
PreflightWorkerError,
PreflightWorkerRequest,
PreflightWorkerResponse,
SerializedPreflightCause,
} from "./protocol";
import { Buffer } from "buffer";
import { initializePdfInspection, inspectPdfPageCount } from "./pdf-inspection";
import { getPreflightTransferables } from "./protocol";
Object.assign(globalThis, { Buffer });
const failure = (code: PdfPreflightFailure["code"], message: string): PdfPreflightFailure => ({
ok: false,
code,
message,
diagnostics: [],
});
const sanitizeWorkerCause = (cause: unknown): string => {
if (!(cause instanceof Error)) return "The PDF preflight worker failed.";
const detail = cause.message.replace(/\s+/g, " ").trim().slice(0, 200);
if (!detail) return "The PDF preflight worker failed.";
return `The PDF preflight worker failed. (${cause.name}: ${detail})`;
};
const serializeZodCause = (cause: unknown): SerializedPreflightCause | undefined => {
if (!(cause instanceof Error) || cause.name !== "ZodError" || !("issues" in cause) || !Array.isArray(cause.issues)) {
return;
}
return { name: cause.name, message: cause.message, issues: cause.issues };
};
const initialization = Promise.all([import("@reactive-resume/pdf/preflight"), initializePdfInspection()] as const);
void initialization.then(() => self.postMessage({ type: "preflight_ready" }));
self.addEventListener("message", async ({ data }: MessageEvent<PreflightWorkerRequest>) => {
if (data.type !== "preflight") return;
const [{ renderPreflightPdf }] = await initialization;
let rendered: Awaited<ReturnType<typeof renderPreflightPdf>>;
try {
rendered = await renderPreflightPdf(data.input, data.limits);
} catch (cause) {
const serializedCause = serializeZodCause(cause);
if (serializedCause) {
const response: PreflightWorkerError = {
type: "preflight_error",
requestId: data.requestId,
editGeneration: data.editGeneration,
cause: serializedCause,
};
self.postMessage(response);
return;
}
const result = failure("STYLESHEET_PREFLIGHT_WORKER_FAILED", sanitizeWorkerCause(cause));
const response: PreflightWorkerResponse = {
type: "preflight_result",
requestId: data.requestId,
editGeneration: data.editGeneration,
result,
};
self.postMessage(response);
return;
}
let result: PreflightWorkerResponse["result"];
if (!rendered.ok) {
result = rendered;
} else if (rendered.bytes.byteLength > data.limits.maxBytes) {
result = failure("STYLESHEET_PREFLIGHT_BYTE_LIMIT", "The PDF exceeds the preflight byte limit.");
} else {
try {
const pdf = Uint8Array.from(rendered.bytes).buffer;
const pageCount = await inspectPdfPageCount(pdf);
result =
pageCount > data.limits.maxPages
? failure("STYLESHEET_PREFLIGHT_PAGE_LIMIT", "The PDF exceeds the preflight page limit.")
: {
ok: true,
pageCount,
byteCount: pdf.byteLength,
diagnostics: rendered.diagnostics,
pdf,
};
} catch {
result = failure("STYLESHEET_PREFLIGHT_PARSE_FAILED", "The generated PDF could not be inspected.");
}
}
const response: PreflightWorkerResponse = {
type: "preflight_result",
requestId: data.requestId,
editGeneration: data.editGeneration,
result,
};
self.postMessage(response, { transfer: getPreflightTransferables(response) });
});
@@ -1,8 +1,3 @@
import type {
BrowserPdfPreflightResult,
PdfPreflightPageLimits,
StylesheetPreflightInput,
} from "@reactive-resume/pdf/preflight";
import type { import type {
AuthoredPageContext, AuthoredPageContext,
BaseSettingsSnapshot, BaseSettingsSnapshot,
@@ -39,47 +34,3 @@ export type CompileWorkerResponse = {
diagnostics: readonly SemanticCssDiagnostic[]; diagnostics: readonly SemanticCssDiagnostic[];
colorTokens?: readonly SemanticCssColorToken[]; colorTokens?: readonly SemanticCssColorToken[];
}; };
type PreflightLimits = PdfPreflightPageLimits & {
maxPages: number;
maxBytes: number;
};
export type PreflightWorkerInput = {
editGeneration: number;
input: StylesheetPreflightInput;
limits: PreflightLimits;
};
export type PreflightWorkerRequest = PreflightWorkerInput & {
type: "preflight";
requestId: number;
};
export type PreflightWorkerResponse = {
type: "preflight_result";
requestId: number;
editGeneration: number;
result: BrowserPdfPreflightResult;
};
export type SerializedPreflightCause = {
name: string;
message: string;
issues: readonly unknown[];
};
export type PreflightWorkerError = {
type: "preflight_error";
requestId: number;
editGeneration: number;
cause: SerializedPreflightCause;
};
export type PreflightWorkerReady = {
type: "preflight_ready";
};
export function getPreflightTransferables(response: PreflightWorkerResponse): Transferable[] {
return response.result.ok ? [response.result.pdf] : [];
}
@@ -1,155 +0,0 @@
// @vitest-environment happy-dom
import type { SemanticStylesheet } from "@reactive-resume/schema/resume/stylesheet";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { defaultResumeData } from "@reactive-resume/schema/resume/default";
const mocks = vi.hoisted(() => ({
getState: vi.fn(),
workers: [] as FakeWorker[],
}));
class FakeWorker {
terminated = false;
constructor() {
mocks.workers.push(this);
}
postMessage() {}
addEventListener() {}
removeEventListener() {}
terminate() {
this.terminated = true;
}
}
vi.mock("@/libs/orpc/client", () => ({
orpc: {
resume: {
stylesheet: {
getState: { call: mocks.getState },
mutate: { call: vi.fn() },
},
},
},
}));
const stylesheet = (text: string): SemanticStylesheet => {
const source = { languageVersion: 1, text };
return { mode: "semantic", source, applied: source };
};
describe("stylesheet store reinitialization", () => {
beforeEach(() => {
mocks.workers.length = 0;
vi.stubGlobal("Worker", FakeWorker);
});
afterEach(() => vi.unstubAllGlobals());
it("suspends edits while a delayed restore is pending, then atomically installs the restored state", async () => {
const storeModule = await import("./store");
const cleanup = storeModule.initializeStylesheetStore({
resumeId: "resume-1",
initial: { stylesheet: stylesheet("old"), revision: 3, renderDataVersion: 7 },
resumeData: defaultResumeData,
});
let finishRestore: (() => void) | undefined;
const delayedRestore = new Promise<void>((resolve) => {
finishRestore = resolve;
});
const restore = async () => {
const token = storeModule.lockStylesheetStoreForRestore("resume-1");
await delayedRestore;
return storeModule.replaceStylesheetStoreAfterRestore({
resumeId: "resume-1",
resumeData: defaultResumeData,
initial: { stylesheet: stylesheet("restored"), revision: 9, renderDataVersion: 12 },
token,
});
};
const pendingRestore = restore();
expect(storeModule.useStylesheetStore.getState().restoreLocked).toBe(true);
const editGeneration = storeModule.useStylesheetStore.getState().editGeneration;
storeModule.useStylesheetStore.getState().setSourceText("edit while restoring");
storeModule.useStylesheetStore.getState().deactivate();
storeModule.useStylesheetStore.getState().undo();
expect(storeModule.useStylesheetStore.getState().source.text).toBe("old");
expect(storeModule.useStylesheetStore.getState().editGeneration).toBe(editGeneration);
finishRestore?.();
const replaced = await pendingRestore;
expect(replaced).toBe(true);
expect(mocks.getState).not.toHaveBeenCalled();
expect(storeModule.useStylesheetStore.getState()).toMatchObject({
resumeId: "resume-1",
source: { text: "restored" },
applied: { text: "restored" },
revision: 9,
renderDataVersion: 12,
restoreLocked: false,
});
storeModule.useStylesheetStore.getState().setSourceText("later edit");
expect(storeModule.useStylesheetStore.getState().source.text).toBe("later edit");
expect(mocks.workers).toHaveLength(4);
expect(mocks.workers.slice(0, 2).every((worker) => worker.terminated)).toBe(true);
cleanup();
expect(mocks.workers.slice(2).every((worker) => worker.terminated)).toBe(true);
expect(storeModule.useStylesheetStore.getState().resumeId).toBeUndefined();
});
it("unlocks interaction after a restore request fails", async () => {
const storeModule = await import("./store");
const cleanup = storeModule.initializeStylesheetStore({
resumeId: "resume-1",
initial: { stylesheet: stylesheet("old"), revision: 3, renderDataVersion: 7 },
resumeData: defaultResumeData,
});
const token = storeModule.lockStylesheetStoreForRestore("resume-1");
expect(storeModule.useStylesheetStore.getState().restoreLocked).toBe(true);
expect(storeModule.unlockStylesheetStoreAfterRestore(token)).toBe(true);
expect(storeModule.useStylesheetStore.getState().restoreLocked).toBe(false);
storeModule.useStylesheetStore.getState().setSourceText("edit after failure");
expect(storeModule.useStylesheetStore.getState().source.text).toBe("edit after failure");
cleanup();
});
it("ignores a stale same-resume restore completion after away-and-back runtime replacement", async () => {
const storeModule = await import("./store");
const cleanupFirst = storeModule.initializeStylesheetStore({
resumeId: "resume-1",
initial: { stylesheet: stylesheet("first"), revision: 1, renderDataVersion: 1 },
resumeData: defaultResumeData,
});
const staleToken = storeModule.lockStylesheetStoreForRestore("resume-1");
cleanupFirst();
const cleanupSecond = storeModule.initializeStylesheetStore({
resumeId: "resume-1",
initial: { stylesheet: stylesheet("second"), revision: 2, renderDataVersion: 2 },
resumeData: defaultResumeData,
});
const replaced = storeModule.replaceStylesheetStoreAfterRestore({
resumeId: "resume-1",
resumeData: defaultResumeData,
initial: { stylesheet: stylesheet("stale restore"), revision: 3, renderDataVersion: 3 },
token: staleToken,
});
expect(replaced).toBe(false);
expect(storeModule.useStylesheetStore.getState()).toMatchObject({
source: { text: "second" },
revision: 2,
renderDataVersion: 2,
});
cleanupSecond();
});
});
@@ -1,50 +1,67 @@
import type { SemanticCssDiagnostic } from "@reactive-resume/resume/stylesheet"; import type { SemanticCssDiagnostic } from "@reactive-resume/resume/stylesheet";
import { Trans } from "@lingui/react/macro"; import { Trans } from "@lingui/react/macro";
import { WarningCircleIcon, WarningIcon } from "@phosphor-icons/react"; import { WarningCircleIcon, WarningIcon } from "@phosphor-icons/react";
import { isFatalStylesheetDiagnostic } from "@reactive-resume/resume/stylesheet";
import { Alert, AlertDescription, AlertTitle } from "@reactive-resume/ui/components/alert"; import { Alert, AlertDescription, AlertTitle } from "@reactive-resume/ui/components/alert";
import { Badge } from "@reactive-resume/ui/components/badge"; import { Badge } from "@reactive-resume/ui/components/badge";
import { ScrollArea } from "@reactive-resume/ui/components/scroll-area"; import { ScrollArea } from "@reactive-resume/ui/components/scroll-area";
export type StylesheetStatusProps = { export type StylesheetStatusProps = {
mode: "legacy" | "semantic"; mode: "legacy" | "semantic";
status: "idle" | "compiling" | "preflighting" | "saving" | "applied" | "error"; status: "idle" | "compiling" | "error";
diagnostics: readonly SemanticCssDiagnostic[]; diagnostics: readonly SemanticCssDiagnostic[];
}; };
export function StylesheetStatus({ mode, status, diagnostics }: StylesheetStatusProps) { export function StylesheetStatus({ mode, status, diagnostics }: StylesheetStatusProps) {
const errors = diagnostics.filter(({ severity }) => severity === "error"); const errors = diagnostics.filter(({ severity }) => severity === "error");
const warnings = diagnostics.filter(({ severity }) => severity === "warning"); const warnings = diagnostics.filter(({ severity }) => severity === "warning");
const hasErrors = status === "error" || errors.length > 0; const hasFatalErrors = status === "error" || diagnostics.some(isFatalStylesheetDiagnostic);
const isPending = status === "compiling" || status === "preflighting" || status === "saving"; const hasRecoverableErrors = !hasFatalErrors && errors.length > 0;
const isPending = status === "compiling";
return ( return (
<div className="space-y-2" aria-live="polite"> <div className="space-y-2" aria-live="polite">
{hasErrors ? ( {hasFatalErrors ? (
<Badge variant="destructive"> <Badge variant="destructive">
<WarningCircleIcon data-icon="inline-start" /> <WarningCircleIcon data-icon="inline-start" />
<Trans>Error</Trans> <Trans>Fatal error</Trans>
</Badge> </Badge>
) : isPending ? ( ) : isPending ? (
<Badge variant="outline">{mode === "legacy" ? <Trans>Checking draft</Trans> : <Trans>Checking</Trans>}</Badge> <Badge variant="outline">{mode === "legacy" ? <Trans>Checking draft</Trans> : <Trans>Checking</Trans>}</Badge>
) : hasRecoverableErrors ? (
<Badge variant="secondary">
<WarningCircleIcon data-icon="inline-start" />
{mode === "legacy" ? <Trans>Ready to activate with errors</Trans> : <Trans>Valid with errors</Trans>}
</Badge>
) : warnings.length > 0 ? ( ) : warnings.length > 0 ? (
<Badge variant="secondary"> <Badge variant="secondary">
<WarningIcon data-icon="inline-start" /> <WarningIcon data-icon="inline-start" />
{mode === "legacy" ? <Trans>Ready to activate with warnings</Trans> : <Trans>Applied with warnings</Trans>} {mode === "legacy" ? <Trans>Ready to activate with warnings</Trans> : <Trans>Valid with warnings</Trans>}
</Badge> </Badge>
) : ( ) : (
<Badge variant="secondary"> <Badge variant="secondary">{mode === "legacy" ? <Trans>Ready to activate</Trans> : <Trans>Valid</Trans>}</Badge>
{mode === "legacy" ? <Trans>Ready to activate</Trans> : <Trans>Applied</Trans>}
</Badge>
)} )}
{hasErrors && ( {hasFatalErrors && (
<Alert variant="destructive"> <Alert variant="destructive">
<WarningCircleIcon /> <WarningCircleIcon />
<AlertTitle> <AlertTitle>
<Trans>Stylesheet has errors</Trans> <Trans>Stylesheet has fatal errors</Trans>
</AlertTitle> </AlertTitle>
<AlertDescription> <AlertDescription>
<Trans>Preview and export use the last valid version.</Trans> <Trans>Preview and export fall back to base styles.</Trans>
</AlertDescription>
</Alert>
)}
{hasRecoverableErrors && (
<Alert>
<WarningCircleIcon />
<AlertTitle>
<Trans>Some styles were ignored</Trans>
</AlertTitle>
<AlertDescription>
<Trans>Preview and export keep valid styles and ignore invalid styles.</Trans>
</AlertDescription> </AlertDescription>
</Alert> </Alert>
)} )}
@@ -1,940 +0,0 @@
import type { SemanticStylesheet, StylesheetSource } from "@reactive-resume/schema/resume/stylesheet";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { defaultResumeData } from "@reactive-resume/schema/resume/default";
import { createStylesheetStoreRuntime } from "./store";
const source = (text: string): StylesheetSource => ({ languageVersion: 1, text });
const stylesheet = (text: string): SemanticStylesheet => ({
mode: "semantic",
source: source(text),
applied: source(text),
});
const initial = {
stylesheet: stylesheet("generation zero"),
revision: 3,
renderDataVersion: 7,
};
type MutationResult = {
stylesheet: SemanticStylesheet;
revision: number;
renderDataVersion: number;
editGeneration: number;
diagnostics: [];
};
describe("stylesheet store runtime", () => {
beforeEach(() => vi.useFakeTimers());
it("clears compiler-confirmed color tokens synchronously when same-length source text changes", () => {
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial: { ...initial, stylesheet: stylesheet("section { color: red; }") },
resumeData: defaultResumeData,
debounceMs: 1_000_000,
compile: vi.fn(),
preflight: vi.fn(),
mutate: vi.fn(),
});
runtime.store.setState({ colorTokens: [{ from: 17, to: 20, value: "red" }] });
runtime.store.getState().setSourceText("section { color: var; }");
expect(runtime.store.getState().source.text).toBe("section { color: var; }");
expect(runtime.store.getState().colorTokens).toEqual([]);
});
it("rejects delayed editor intelligence for a canonically replaced source", async () => {
let resolveCompile!: (value: {
type: "compile_result";
requestId: number;
editGeneration: number;
program: { languageVersion: number; rules: [] };
diagnostics: [
{
code: string;
severity: "error";
message: string;
range: {
start: { line: number; column: number; offset: number };
end: { line: number; column: number; offset: number };
};
},
];
colorTokens: [{ from: number; to: number; value: string }];
}) => void;
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial: { ...initial, stylesheet: stylesheet("section { color: red; }") },
resumeData: defaultResumeData,
compile: () => new Promise((resolve) => (resolveCompile = resolve)),
preflight: vi.fn(),
mutate: vi.fn(),
});
runtime.store.getState().refreshIntelligence();
runtime.rebaseCanonical({
stylesheet: stylesheet("section { color: blue; }"),
revision: 4,
renderDataVersion: 7,
});
resolveCompile({
type: "compile_result",
requestId: 1,
editGeneration: 0,
program: { languageVersion: 1, rules: [] },
diagnostics: [
{
code: "OLD_SOURCE",
severity: "error",
message: "Old source diagnostic",
range: {
start: { line: 1, column: 1, offset: 0 },
end: { line: 1, column: 2, offset: 1 },
},
},
],
colorTokens: [{ from: 17, to: 20, value: "red" }],
});
await Promise.resolve();
await Promise.resolve();
expect(runtime.store.getState()).toMatchObject({
source: source("section { color: blue; }"),
diagnostics: [],
colorTokens: [],
});
});
it("consumes stale acknowledgements before saving the replaceable pending edit", async () => {
const resolvers: Array<(value: MutationResult) => void> = [];
const mutate = vi.fn(
(_input: unknown) =>
new Promise<MutationResult>((resolve) => {
resolvers.push((value) => resolve(value));
}),
);
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial,
resumeData: defaultResumeData,
debounceMs: 0,
compile: async ({ editGeneration }) => ({
type: "compile_result",
requestId: editGeneration,
editGeneration,
program: { languageVersion: 1, rules: [] },
diagnostics: [],
}),
preflight: async ({ editGeneration }) => ({
type: "preflight_result",
requestId: editGeneration,
editGeneration,
result: { ok: true, pageCount: 1, byteCount: 4, diagnostics: [], pdf: new ArrayBuffer(4) },
}),
mutate,
});
runtime.store.getState().setSourceText("generation one");
await vi.runAllTimersAsync();
runtime.store.getState().setSourceText("generation two");
await vi.runAllTimersAsync();
resolvers[0]?.({
stylesheet: stylesheet("generation one"),
revision: 4,
renderDataVersion: 8,
editGeneration: 1,
diagnostics: [],
});
await vi.runAllTimersAsync();
expect(runtime.store.getState()).toMatchObject({
revision: 4,
renderDataVersion: 8,
source: source("generation two"),
applied: source("generation zero"),
});
expect(mutate).toHaveBeenCalledTimes(2);
expect(mutate.mock.calls[1]?.[0]).toMatchObject({
expectedRevision: 4,
expectedRenderDataVersion: 8,
editGeneration: 2,
});
});
it("rebases conflicts without dropping the focused local draft", async () => {
const mutate = vi
.fn()
.mockRejectedValueOnce({
code: "STYLESHEET_REVISION_CONFLICT",
data: {
state: { stylesheet: stylesheet("remote"), revision: 8, renderDataVersion: 11 },
},
})
.mockResolvedValueOnce({
stylesheet: stylesheet("local unsaved source"),
revision: 9,
renderDataVersion: 11,
editGeneration: 1,
diagnostics: [],
});
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial,
resumeData: defaultResumeData,
debounceMs: 0,
compile: async ({ editGeneration }) => ({
type: "compile_result",
requestId: editGeneration,
editGeneration,
program: { languageVersion: 1, rules: [] },
diagnostics: [],
}),
preflight: async ({ editGeneration }) => ({
type: "preflight_result",
requestId: editGeneration,
editGeneration,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [], pdf: new ArrayBuffer(1) },
}),
mutate,
});
runtime.store.getState().setFocused(true);
runtime.store.getState().setSourceText("local unsaved source");
await vi.runAllTimersAsync();
expect(runtime.store.getState()).toMatchObject({
revision: 9,
renderDataVersion: 11,
source: source("local unsaved source"),
});
expect(mutate.mock.calls[1]?.[0]).toMatchObject({ expectedRevision: 8, expectedRenderDataVersion: 11 });
});
it("keeps the newer pending edit when an older request conflicts", async () => {
let rejectFirst!: (error: unknown) => void;
const mutate = vi
.fn()
.mockReturnValueOnce(
new Promise((_resolve, reject) => {
rejectFirst = reject;
}),
)
.mockResolvedValueOnce({
stylesheet: stylesheet("newer"),
revision: 9,
renderDataVersion: 11,
editGeneration: 2,
diagnostics: [],
});
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial,
resumeData: defaultResumeData,
debounceMs: 0,
compile: async ({ editGeneration }) => ({
type: "compile_result",
requestId: editGeneration,
editGeneration,
program: { languageVersion: 1, rules: [] },
diagnostics: [],
}),
preflight: async ({ editGeneration }) => ({
type: "preflight_result",
requestId: editGeneration,
editGeneration,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [], pdf: new ArrayBuffer(1) },
}),
mutate,
});
runtime.store.getState().setSourceText("older");
await vi.runAllTimersAsync();
runtime.store.getState().setSourceText("newer");
await vi.runAllTimersAsync();
rejectFirst({
code: "STYLESHEET_REVISION_CONFLICT",
data: { state: { stylesheet: stylesheet("remote"), revision: 8, renderDataVersion: 11 } },
});
await vi.runAllTimersAsync();
expect(mutate.mock.calls[1]?.[0]).toMatchObject({
transition: "edit_source",
editGeneration: 2,
source: source("newer"),
});
});
it("invalidates pending preflight eligibility on content changes and keeps versions monotonic", async () => {
let resolveMutation!: (result: MutationResult) => void;
let resolveRepreflight!: (result: {
type: "preflight_result";
requestId: number;
editGeneration: number;
result: {
ok: true;
pageCount: number;
byteCount: number;
diagnostics: [];
pdf: ArrayBuffer;
};
}) => void;
const mutate = vi
.fn()
.mockReturnValueOnce(new Promise<MutationResult>((resolve) => (resolveMutation = resolve)))
.mockResolvedValueOnce({
stylesheet: stylesheet("newer"),
revision: 11,
renderDataVersion: 20,
editGeneration: 2,
diagnostics: [],
});
const preflight = vi
.fn()
.mockImplementationOnce(async ({ editGeneration }) => ({
type: "preflight_result",
requestId: editGeneration,
editGeneration,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [], pdf: new ArrayBuffer(1) },
}))
.mockImplementationOnce(async ({ editGeneration }) => ({
type: "preflight_result",
requestId: editGeneration,
editGeneration,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [], pdf: new ArrayBuffer(1) },
}))
.mockImplementationOnce(
() =>
new Promise((resolve) => {
resolveRepreflight = resolve;
}),
);
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial,
resumeData: defaultResumeData,
debounceMs: 0,
compile: async ({ editGeneration }) => ({
type: "compile_result",
requestId: editGeneration,
editGeneration,
program: { languageVersion: 1, rules: [] },
diagnostics: [],
}),
preflight,
mutate,
});
runtime.store.getState().setSourceText("older");
await vi.runAllTimersAsync();
runtime.store.getState().setSourceText("newer");
await vi.runAllTimersAsync();
expect(mutate).toHaveBeenCalledTimes(1);
runtime.replaceResumeSnapshot(defaultResumeData, {
stylesheet: stylesheet("remote"),
revision: 10,
renderDataVersion: 20,
});
await vi.runAllTimersAsync();
expect(preflight).toHaveBeenCalledTimes(3);
resolveMutation({
stylesheet: stylesheet("older"),
revision: 4,
renderDataVersion: 7,
editGeneration: 1,
diagnostics: [],
});
await Promise.resolve();
await Promise.resolve();
expect(runtime.store.getState()).toMatchObject({ revision: 10, renderDataVersion: 20 });
expect(mutate).toHaveBeenCalledTimes(1);
resolveRepreflight({
type: "preflight_result",
requestId: 3,
editGeneration: 2,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [], pdf: new ArrayBuffer(1) },
});
await vi.runAllTimersAsync();
expect(mutate.mock.calls[1]?.[0]).toMatchObject({
source: source("newer"),
expectedRevision: 10,
expectedRenderDataVersion: 20,
});
});
it("does not requeue an invalidated in-flight candidate after conflict", async () => {
let rejectMutation!: (error: unknown) => void;
let resolveRepreflight!: (result: {
type: "preflight_result";
requestId: number;
editGeneration: number;
result: {
ok: true;
pageCount: number;
byteCount: number;
diagnostics: [];
pdf: ArrayBuffer;
};
}) => void;
const mutate = vi
.fn()
.mockReturnValueOnce(new Promise<MutationResult>((_resolve, reject) => (rejectMutation = reject)))
.mockResolvedValueOnce({
stylesheet: stylesheet("newer"),
revision: 11,
renderDataVersion: 20,
editGeneration: 2,
diagnostics: [],
});
const preflight = vi
.fn()
.mockImplementationOnce(async ({ editGeneration }) => ({
type: "preflight_result",
requestId: editGeneration,
editGeneration,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [], pdf: new ArrayBuffer(1) },
}))
.mockImplementationOnce(async ({ editGeneration }) => ({
type: "preflight_result",
requestId: editGeneration,
editGeneration,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [], pdf: new ArrayBuffer(1) },
}))
.mockImplementationOnce(
() =>
new Promise((resolve) => {
resolveRepreflight = resolve;
}),
);
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial,
resumeData: defaultResumeData,
debounceMs: 0,
compile: async ({ editGeneration }) => ({
type: "compile_result",
requestId: editGeneration,
editGeneration,
program: { languageVersion: 1, rules: [] },
diagnostics: [],
}),
preflight,
mutate,
});
runtime.store.getState().setSourceText("older");
await vi.runAllTimersAsync();
runtime.store.getState().setSourceText("newer");
await vi.runAllTimersAsync();
runtime.replaceResumeSnapshot(defaultResumeData, {
stylesheet: stylesheet("remote"),
revision: 10,
renderDataVersion: 20,
});
await vi.runAllTimersAsync();
rejectMutation({
code: "STYLESHEET_REVISION_CONFLICT",
data: { state: { stylesheet: stylesheet("remote"), revision: 10, renderDataVersion: 20 } },
});
await Promise.resolve();
await Promise.resolve();
await Promise.resolve();
expect(mutate).toHaveBeenCalledTimes(1);
resolveRepreflight({
type: "preflight_result",
requestId: 3,
editGeneration: 2,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [], pdf: new ArrayBuffer(1) },
});
await vi.runAllTimersAsync();
expect(mutate.mock.calls[1]?.[0]).toMatchObject({
source: source("newer"),
expectedRevision: 10,
expectedRenderDataVersion: 20,
});
});
it("reconciles a deferred focused canonical source on blur", () => {
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial,
resumeData: defaultResumeData,
compile: vi.fn(),
preflight: vi.fn(),
mutate: vi.fn(),
});
runtime.store.getState().setFocused(true);
runtime.rebaseCanonical({
stylesheet: stylesheet("remote"),
revision: 8,
renderDataVersion: 11,
});
expect(runtime.store.getState()).toMatchObject({
source: source("generation zero"),
applied: source("remote"),
revision: 8,
renderDataVersion: 11,
});
runtime.store.getState().setFocused(false);
expect(runtime.store.getState()).toMatchObject({
source: source("remote"),
applied: source("remote"),
});
});
it("persists invalid source while preserving applied and restores stylesheet history separately", async () => {
const mutate = vi
.fn()
.mockResolvedValueOnce({
stylesheet: {
mode: "semantic",
source: source("invalid {"),
applied: source("generation zero"),
},
revision: 4,
renderDataVersion: 7,
editGeneration: 1,
diagnostics: [
{
code: "PARSE_ERROR",
severity: "error",
message: "Invalid",
range: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } },
},
],
})
.mockResolvedValueOnce({
stylesheet: stylesheet("generation zero"),
revision: 5,
renderDataVersion: 7,
editGeneration: 2,
diagnostics: [],
});
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial,
resumeData: defaultResumeData,
debounceMs: 0,
compile: async ({ editGeneration, source: candidate }) => ({
type: "compile_result",
requestId: editGeneration,
editGeneration,
program: candidate.text === "invalid {" ? null : { languageVersion: 1, rules: [] },
diagnostics: [],
}),
preflight: async ({ editGeneration }) => ({
type: "preflight_result",
requestId: editGeneration,
editGeneration,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [], pdf: new ArrayBuffer(1) },
}),
mutate,
});
runtime.store.getState().setSourceText("invalid {");
await vi.runAllTimersAsync();
expect(runtime.store.getState()).toMatchObject({
source: source("invalid {"),
applied: source("generation zero"),
});
expect(mutate.mock.calls[0]?.[0]).toMatchObject({ transition: "edit_source", source: source("invalid {") });
runtime.store.getState().undo();
await vi.runAllTimersAsync();
expect(mutate.mock.calls[1]?.[0]).toMatchObject({
transition: "restore_history",
restore: stylesheet("generation zero"),
});
});
it("does not publish historical applied state before restore acknowledgement", async () => {
const mutate = vi.fn(() => new Promise<MutationResult>(() => {}));
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial: { ...initial, stylesheet: stylesheet("current applied") },
resumeData: defaultResumeData,
debounceMs: 0,
compile: async ({ editGeneration }) => ({
type: "compile_result",
requestId: editGeneration,
editGeneration,
program: { languageVersion: 1, rules: [] },
diagnostics: [],
}),
preflight: async ({ editGeneration }) => ({
type: "preflight_result",
requestId: editGeneration,
editGeneration,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [], pdf: new ArrayBuffer(1) },
}),
mutate,
});
runtime.store.setState({
source: source("local invalid"),
applied: source("current applied"),
undoStack: [stylesheet("historical")],
canUndo: true,
});
runtime.store.getState().undo();
await vi.runAllTimersAsync();
expect(runtime.store.getState().source).toEqual(source("historical"));
expect(runtime.store.getState().applied).toEqual(source("current applied"));
expect(mutate).toHaveBeenCalledWith(
expect.objectContaining({ transition: "restore_history", restore: stylesheet("historical") }),
expect.any(AbortSignal),
);
});
it("retries the focused draft against a newer content render-data version", async () => {
const mutate = vi.fn().mockResolvedValue({
stylesheet: stylesheet("local"),
revision: 4,
renderDataVersion: 12,
editGeneration: 1,
diagnostics: [],
});
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial,
resumeData: defaultResumeData,
debounceMs: 0,
compile: async ({ editGeneration }) => ({
type: "compile_result",
requestId: editGeneration,
editGeneration,
program: { languageVersion: 1, rules: [] },
diagnostics: [],
}),
preflight: async ({ editGeneration }) => ({
type: "preflight_result",
requestId: editGeneration,
editGeneration,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [], pdf: new ArrayBuffer(1) },
}),
mutate,
});
runtime.store.getState().setFocused(true);
runtime.store.getState().setSourceText("local");
runtime.replaceResumeSnapshot(defaultResumeData, {
stylesheet: stylesheet("remote"),
revision: 9,
renderDataVersion: 12,
});
await vi.runAllTimersAsync();
expect(runtime.store.getState().source).toEqual(source("local"));
expect(mutate).toHaveBeenLastCalledWith(
expect.objectContaining({ expectedRevision: 9, expectedRenderDataVersion: 12, source: source("local") }),
expect.any(AbortSignal),
);
});
it("keeps a queued draft when content changes after editor blur", async () => {
const mutate = vi.fn().mockResolvedValue({
stylesheet: stylesheet("local"),
revision: 10,
renderDataVersion: 12,
editGeneration: 1,
diagnostics: [],
});
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial,
resumeData: defaultResumeData,
debounceMs: 0,
compile: async ({ editGeneration }) => ({
type: "compile_result",
requestId: editGeneration,
editGeneration,
program: { languageVersion: 1, rules: [] },
diagnostics: [],
}),
preflight: async ({ editGeneration }) => ({
type: "preflight_result",
requestId: editGeneration,
editGeneration,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [], pdf: new ArrayBuffer(1) },
}),
mutate,
});
runtime.store.getState().setSourceText("local");
runtime.replaceResumeSnapshot(defaultResumeData, {
stylesheet: stylesheet("remote"),
revision: 9,
renderDataVersion: 12,
});
await vi.runAllTimersAsync();
expect(runtime.store.getState().source).toEqual(source("local"));
expect(mutate).toHaveBeenLastCalledWith(
expect.objectContaining({ expectedRevision: 9, expectedRenderDataVersion: 12, source: source("local") }),
expect.any(AbortSignal),
);
});
it("queues activation only after browser preflight succeeds", async () => {
const mutate = vi.fn().mockResolvedValue({
stylesheet: stylesheet("generation zero"),
revision: 4,
renderDataVersion: 7,
editGeneration: 2,
diagnostics: [],
});
const preflight = vi
.fn()
.mockResolvedValueOnce({
type: "preflight_result",
requestId: 1,
editGeneration: 1,
result: {
ok: false,
code: "STYLESHEET_PREFLIGHT_RENDER_FAILED",
message: "failed",
diagnostics: [],
},
})
.mockResolvedValueOnce({
type: "preflight_result",
requestId: 2,
editGeneration: 2,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [], pdf: new ArrayBuffer(1) },
});
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial: { ...initial, stylesheet: { ...initial.stylesheet, mode: "legacy" } },
resumeData: defaultResumeData,
debounceMs: 0,
compile: async ({ editGeneration }) => ({
type: "compile_result",
requestId: editGeneration,
editGeneration,
program: { languageVersion: 1, rules: [] },
diagnostics: [],
}),
preflight,
mutate,
});
runtime.store.getState().activate();
await vi.runAllTimersAsync();
expect(mutate).not.toHaveBeenCalled();
runtime.store.getState().activate();
await vi.runAllTimersAsync();
expect(mutate).toHaveBeenCalledWith(
expect.objectContaining({ transition: "activate", source: source("generation zero") }),
expect.any(AbortSignal),
);
});
it("does not leave Checking stuck when compile rejects for the current edit", async () => {
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial,
resumeData: defaultResumeData,
debounceMs: 0,
compile: () => Promise.reject(new Error("Discarded stale stylesheet compiler result.")),
preflight: vi.fn(),
mutate: vi.fn(),
});
runtime.store.getState().setSourceText("edited source");
await vi.runAllTimersAsync();
expect(runtime.store.getState().status).not.toBe("compiling");
expect(runtime.store.getState().status).toBe("error");
});
it("surfaces browser preflight failures as diagnostics when the worker returns an empty list", async () => {
let resolveMutate!: (value: MutationResult & { diagnostics: never[] }) => void;
const mutate = vi.fn(
() =>
new Promise<MutationResult & { diagnostics: never[] }>((resolve) => {
resolveMutate = resolve;
}),
);
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial,
resumeData: defaultResumeData,
debounceMs: 0,
compile: async ({ editGeneration }) => ({
type: "compile_result",
requestId: editGeneration,
editGeneration,
program: { languageVersion: 1, rules: [] },
diagnostics: [],
}),
preflight: async ({ editGeneration }) => ({
type: "preflight_result",
requestId: editGeneration,
editGeneration,
result: {
ok: false,
code: "STYLESHEET_PREFLIGHT_WORKER_FAILED",
message: "The PDF preflight worker failed.",
diagnostics: [],
},
}),
mutate,
});
runtime.store.getState().setSourceText("@version 1;\nsection { color: teal; }");
await vi.runAllTimersAsync();
expect(runtime.store.getState().diagnostics).toEqual([
expect.objectContaining({
code: "STYLESHEET_PREFLIGHT_WORKER_FAILED",
severity: "error",
message: "The PDF preflight worker failed.",
range: {
start: { line: 1, column: 1, offset: 0 },
end: { line: 1, column: 1, offset: 0 },
},
}),
]);
expect(runtime.store.getState().diagnostics.some(({ severity }) => severity === "error")).toBe(true);
expect(mutate).toHaveBeenCalled();
resolveMutate({
stylesheet: stylesheet("@version 1;\n"),
revision: 4,
renderDataVersion: 7,
editGeneration: 1,
diagnostics: [],
});
await Promise.resolve();
});
it("finishes an edit when refreshIntelligence interleaves through the shared compile client", async () => {
const { createCompileWorkerClient } = await import("./worker-client");
const listeners = new Map<string, Set<EventListener>>();
const fake = {
postMessage: vi.fn(),
terminate: vi.fn(),
addEventListener: vi.fn((type: string, listener: EventListener) => {
const bucket = listeners.get(type) ?? new Set();
bucket.add(listener);
listeners.set(type, bucket);
}),
removeEventListener: vi.fn((type: string, listener: EventListener) => {
listeners.get(type)?.delete(listener);
}),
emit(data: unknown) {
for (const listener of listeners.get("message") ?? []) {
(listener as (event: MessageEvent) => void)(new MessageEvent("message", { data }));
}
},
};
const client = createCompileWorkerClient(() => fake);
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial,
resumeData: defaultResumeData,
debounceMs: 0,
compile: client.compile,
preflight: async ({ editGeneration }) => ({
type: "preflight_result",
requestId: editGeneration,
editGeneration,
result: { ok: true, pageCount: 1, byteCount: 1, diagnostics: [], pdf: new ArrayBuffer(1) },
}),
mutate: async ({ editGeneration }) => ({
stylesheet: stylesheet("edited source"),
revision: 4,
renderDataVersion: 7,
editGeneration,
diagnostics: [],
}),
});
runtime.store.getState().setSourceText("edited source");
await vi.runAllTimersAsync();
expect(runtime.store.getState().status).toBe("compiling");
expect(fake.postMessage).toHaveBeenCalledTimes(1);
// Mobile Design remount / accordion reopen refreshes intelligence while the edit is compiling.
runtime.store.getState().refreshIntelligence();
expect(fake.postMessage).toHaveBeenCalledTimes(2);
fake.emit({
type: "compile_result",
requestId: 1,
editGeneration: 1,
program: { languageVersion: 1, rules: [] },
diagnostics: [],
colorTokens: [],
});
fake.emit({
type: "compile_result",
requestId: 2,
editGeneration: 1,
program: { languageVersion: 1, rules: [] },
diagnostics: [],
colorTokens: [],
});
await vi.runAllTimersAsync();
expect(runtime.store.getState().status).toBe("applied");
expect(runtime.store.getState().applied.text).toBe("edited source");
});
it("terminates both worker clients and clears the store on cleanup", () => {
const destroy = vi.fn();
let mutationSignal: AbortSignal | undefined;
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial,
resumeData: defaultResumeData,
compile: vi.fn(),
preflight: vi.fn(),
mutate: vi.fn((_input: unknown, signal: AbortSignal) => {
mutationSignal = signal;
return new Promise<MutationResult>(() => {});
}),
destroy,
});
runtime.store.getState().deactivate();
runtime.destroy();
expect(destroy).toHaveBeenCalledOnce();
expect(mutationSignal?.aborted).toBe(true);
expect(runtime.store.getState().resumeId).toBeUndefined();
});
it("coalesces rapid source edits and bounds stylesheet history", () => {
const runtime = createStylesheetStoreRuntime({
resumeId: "resume-1",
initial,
resumeData: defaultResumeData,
debounceMs: 1_000_000,
compile: vi.fn(),
preflight: vi.fn(),
mutate: vi.fn(),
});
for (let index = 0; index < 10; index++) runtime.store.getState().setSourceText(`rapid ${index}`);
expect(runtime.store.getState().undoStack).toHaveLength(1);
expect(runtime.store.getState().undoStack[0]).toEqual(stylesheet("generation zero"));
for (let index = 0; index < 60; index++) {
vi.advanceTimersByTime(501);
runtime.store.getState().setSourceText(`separate ${index}`);
}
expect(runtime.store.getState().undoStack).toHaveLength(50);
});
});
@@ -1,699 +0,0 @@
import type { SemanticCssDiagnostic, SemanticNode } from "@reactive-resume/resume/stylesheet";
import type { ResumeData } from "@reactive-resume/schema/resume/data";
import type { SemanticStylesheet, StylesheetSource } from "@reactive-resume/schema/resume/stylesheet";
import type { StoreApi } from "zustand/vanilla";
import type { SemanticCssColorToken } from "./color-tokens";
import type {
CompileWorkerInput,
CompileWorkerResponse,
PreflightWorkerInput,
PreflightWorkerResponse,
SemanticCssEditorMetadata,
} from "./protocol";
import { create } from "zustand/react";
import { createStore } from "zustand/vanilla";
import {
buildSemanticTree,
getTemplateSemanticManifest,
semanticNodeKeys,
shouldShowResumeHeader,
} from "@reactive-resume/pdf/semantic-tree";
import { orpc } from "@/libs/orpc/client";
import { createCompileWorkerClient, createPreflightWorkerClient } from "./worker-client";
export type StylesheetCanonicalState = {
stylesheet: SemanticStylesheet;
revision: number;
renderDataVersion: number;
};
type StylesheetMutationResult = StylesheetCanonicalState & {
editGeneration: number;
diagnostics: readonly SemanticCssDiagnostic[];
};
type EditMutation = {
id: string;
expectedRevision: number;
expectedRenderDataVersion: number;
editGeneration: number;
transition: "edit_source";
source: StylesheetSource;
};
type RestoreMutation = {
id: string;
expectedRevision: number;
expectedRenderDataVersion: number;
editGeneration: number;
transition: "restore_history";
restore: SemanticStylesheet;
};
type ActivateMutation = Omit<EditMutation, "transition"> & { transition: "activate" };
type DeactivateMutation = Omit<EditMutation, "transition" | "source"> & { transition: "deactivate" };
type StylesheetMutation = EditMutation | RestoreMutation | ActivateMutation | DeactivateMutation;
type Candidate =
| { generation: number; transition: "edit_source"; source: StylesheetSource }
| { generation: number; transition: "restore_history"; restore: SemanticStylesheet }
| { generation: number; transition: "activate"; source: StylesheetSource }
| { generation: number; transition: "deactivate" };
export type StylesheetStoreState = {
resumeId?: string;
mode: SemanticStylesheet["mode"];
source: StylesheetSource;
applied: StylesheetSource;
revision: number;
renderDataVersion: number;
editGeneration: number;
diagnostics: readonly SemanticCssDiagnostic[];
colorTokens: readonly SemanticCssColorToken[];
editorMetadata: SemanticCssEditorMetadata;
status: "idle" | "compiling" | "preflighting" | "saving" | "applied" | "error";
restoreLocked: boolean;
focused: boolean;
canUndo: boolean;
canRedo: boolean;
undoStack: SemanticStylesheet[];
redoStack: SemanticStylesheet[];
setSourceText(text: string): void;
setFocused(focused: boolean): void;
activate(): void;
deactivate(): void;
undo(): void;
redo(): void;
refreshIntelligence(): void;
};
type RuntimeDependencies = {
compile(input: CompileWorkerInput): Promise<CompileWorkerResponse>;
preflight(input: PreflightWorkerInput): Promise<PreflightWorkerResponse>;
mutate(input: StylesheetMutation, signal: AbortSignal): Promise<StylesheetMutationResult>;
destroy?(): void;
};
type CreateStylesheetStoreRuntimeOptions = RuntimeDependencies & {
resumeId: string;
initial: StylesheetCanonicalState;
resumeData: ResumeData;
debounceMs?: number;
store?: StoreApi<StylesheetStoreState>;
};
const emptySource = (): StylesheetSource => ({ languageVersion: 1, text: "@version 1;\n" });
const emptySemanticTree = (): SemanticNode => ({
key: "resume",
kind: "resume",
attributes: {},
roles: [],
children: [],
});
const HISTORY_COALESCE_MS = 500;
const MAX_HISTORY_ENTRIES = 50;
const preflightFailureDiagnostic = (
result: Extract<PreflightWorkerResponse["result"], { ok: false }>,
): SemanticCssDiagnostic => ({
code: result.code,
severity: "error",
message: result.message,
range: {
start: { line: 1, column: 1, offset: 0 },
end: { line: 1, column: 1, offset: 0 },
},
});
const inactiveState = (): Omit<
StylesheetStoreState,
"setSourceText" | "setFocused" | "activate" | "deactivate" | "undo" | "redo" | "refreshIntelligence"
> => ({
resumeId: undefined,
mode: "legacy",
source: emptySource(),
applied: emptySource(),
revision: 0,
renderDataVersion: 0,
editGeneration: 0,
diagnostics: [],
colorTokens: [],
editorMetadata: { semanticTree: emptySemanticTree(), templateParts: [] },
status: "idle",
restoreLocked: false,
focused: false,
canUndo: false,
canRedo: false,
undoStack: [],
redoStack: [],
});
const sourceFromText = (source: StylesheetSource, text: string): StylesheetSource => ({ ...source, text });
const sourcesEqual = (left: StylesheetSource, right: StylesheetSource) =>
left.languageVersion === right.languageVersion && left.text === right.text;
const isEditorFocused = () =>
typeof document !== "undefined" && document.activeElement instanceof HTMLElement
? document.activeElement.closest(".cm-editor") !== null
: false;
const currentStylesheet = (state: StylesheetStoreState): SemanticStylesheet => ({
mode: state.mode,
source: structuredClone(state.source),
applied: structuredClone(state.applied),
});
const appendHistory = (stack: SemanticStylesheet[], value: SemanticStylesheet) =>
[...stack, value].slice(-MAX_HISTORY_ENTRIES);
const pageDimensions = (data: ResumeData) => {
const format = data.metadata.page.format;
const size = format === "letter" ? { width: 612, height: 792 } : { width: 595.28, height: 841.89 };
return data.metadata.layout.pages.map((_page, index) => ({
pageKey: semanticNodeKeys.page(index + 1),
...size,
}));
};
const createEditorMetadata = (data: ResumeData): SemanticCssEditorMetadata => {
const pages = data.metadata.layout.pages.map((page, index) =>
buildSemanticTree({
data,
template: data.metadata.template,
page,
pageNumber: index + 1,
showHeader: shouldShowResumeHeader(data, index),
}),
);
const semanticTree: SemanticNode = {
key: semanticNodeKeys.resume(),
kind: "resume",
attributes: { template: data.metadata.template },
roles: [],
children: pages.flatMap(({ children }) => children),
};
return {
semanticTree,
templateParts: getTemplateSemanticManifest(data.metadata.template).parts.map(({ name }) => name),
};
};
const compileInput = (
data: ResumeData,
source: StylesheetSource,
editGeneration: number,
semanticTree: SemanticNode,
): CompileWorkerInput => {
return {
editGeneration,
source,
semanticTree,
baseSettings: {
picture: data.picture,
template: data.metadata.template,
design: data.metadata.design,
typography: data.metadata.typography,
page: data.metadata.page,
layout: { sidebarWidth: data.metadata.layout.sidebarWidth },
},
pages: pageDimensions(data),
};
};
const conflictState = (error: unknown): StylesheetCanonicalState | undefined => {
if (!error || typeof error !== "object") return;
const value = error as { code?: string; data?: { state?: StylesheetCanonicalState } };
return value.code === "STYLESHEET_REVISION_CONFLICT" ? value.data?.state : undefined;
};
export function createStylesheetStoreRuntime(options: CreateStylesheetStoreRuntimeOptions) {
let resumeData = structuredClone(options.resumeData);
let timer: ReturnType<typeof setTimeout> | undefined;
let inFlight: Candidate | undefined;
let pending: Candidate | undefined;
let latestCandidate: Candidate | undefined;
let deferredCanonical: StylesheetCanonicalState | undefined;
let validationEpoch = 0;
let intelligenceEpoch = 0;
let historyLastEditAt = 0;
let historyCanCoalesce = false;
let destroyed = false;
const abortController = new AbortController();
const debounceMs = options.debounceMs ?? 180;
const initial = options.initial.stylesheet;
let editorMetadata = createEditorMetadata(resumeData);
const store =
options.store ??
createStore<StylesheetStoreState>(() => ({
...inactiveState(),
setSourceText: () => {},
setFocused: () => {},
activate: () => {},
deactivate: () => {},
undo: () => {},
redo: () => {},
refreshIntelligence: () => {},
}));
const patch = (next: Partial<StylesheetStoreState>) => store.setState(next);
const replaceCanonical = (canonical: StylesheetCanonicalState, preserveSource: boolean) => {
const state = store.getState();
const next: Partial<StylesheetStoreState> = {
revision: Math.max(state.revision, canonical.revision),
renderDataVersion: Math.max(state.renderDataVersion, canonical.renderDataVersion),
};
if (canonical.revision >= state.revision) {
next.mode = canonical.stylesheet.mode;
const nextSource = preserveSource ? state.source : canonical.stylesheet.source;
next.source = nextSource;
next.applied = canonical.stylesheet.applied;
if (!sourcesEqual(nextSource, state.source)) {
intelligenceEpoch += 1;
next.colorTokens = [];
}
}
patch(next);
};
const resetHistoryCoalescing = () => {
historyLastEditAt = 0;
historyCanCoalesce = false;
};
const startNext = () => {
if (destroyed || inFlight || !pending) return;
const candidate = pending;
pending = undefined;
inFlight = candidate;
const requestValidationEpoch = validationEpoch;
const state = store.getState();
const common = {
id: options.resumeId,
expectedRevision: state.revision,
expectedRenderDataVersion: state.renderDataVersion,
editGeneration: candidate.generation,
};
let input: StylesheetMutation;
if (candidate.transition === "edit_source" || candidate.transition === "activate") {
input = { ...common, transition: candidate.transition, source: candidate.source };
} else if (candidate.transition === "restore_history") {
input = { ...common, transition: "restore_history", restore: candidate.restore };
} else {
input = { ...common, transition: "deactivate" };
}
patch({ status: "saving" });
void options
.mutate(input, abortController.signal)
.then((result) => {
if (destroyed) return;
const state = store.getState();
const staleStylesheet = result.revision < state.revision;
patch({
revision: Math.max(state.revision, result.revision),
renderDataVersion: Math.max(state.renderDataVersion, result.renderDataVersion),
});
if (result.editGeneration !== store.getState().editGeneration) return;
if (staleStylesheet) return;
const sourceChanged = !sourcesEqual(result.stylesheet.source, state.source);
if (sourceChanged) intelligenceEpoch += 1;
patch({
mode: result.stylesheet.mode,
source: result.stylesheet.source,
applied: result.stylesheet.applied,
diagnostics: result.diagnostics,
colorTokens: sourceChanged ? [] : state.colorTokens,
status: result.diagnostics.some(({ severity }) => severity === "error") ? "error" : "applied",
});
if (latestCandidate?.generation === result.editGeneration) latestCandidate = undefined;
if (deferredCanonical && result.revision >= deferredCanonical.revision) deferredCanonical = undefined;
})
.catch((error: unknown) => {
if (destroyed) return;
const canonical = conflictState(error);
if (!canonical) {
patch({ status: "error" });
return;
}
replaceCanonical(canonical, true);
if (requestValidationEpoch === validationEpoch) pending ??= candidate;
})
.finally(() => {
inFlight = undefined;
startNext();
});
};
const queue = (candidate: Candidate) => {
latestCandidate = candidate;
pending = candidate;
startNext();
};
const processCandidate = async (candidate: Candidate) => {
if (destroyed || candidate.generation !== store.getState().editGeneration) return;
const candidateValidationEpoch = validationEpoch;
if (candidate.transition === "deactivate") {
queue(candidate);
return;
}
const source = candidate.transition === "restore_history" ? candidate.restore.applied : candidate.source;
patch({ status: "compiling" });
let compiled: CompileWorkerResponse;
try {
compiled = await options.compile(
compileInput(resumeData, source, candidate.generation, editorMetadata.semanticTree),
);
} catch {
if (candidateValidationEpoch !== validationEpoch) return;
if (destroyed || candidate.generation !== store.getState().editGeneration) return;
patch({ status: "error" });
return;
}
if (candidateValidationEpoch !== validationEpoch) return;
if (destroyed || compiled.editGeneration !== store.getState().editGeneration) return;
patch({ diagnostics: compiled.diagnostics, colorTokens: compiled.colorTokens ?? [] });
if (!compiled.program) {
if (candidate.transition === "edit_source") queue(candidate);
else patch({ status: "error" });
return;
}
if (compiled.program) {
patch({ status: "preflighting" });
let preflight: PreflightWorkerResponse;
try {
preflight = await options.preflight({
editGeneration: candidate.generation,
input: { data: resumeData, template: resumeData.metadata.template, stylesheet: source },
limits: {
maxPages: 20,
maxBytes: 10_000_000,
maxPageWidthPt: 2_000,
maxPageHeightPt: 20_000,
maxPageAreaPt2: 20_000_000,
},
});
} catch {
if (candidateValidationEpoch !== validationEpoch) return;
if (candidate.generation !== store.getState().editGeneration) return;
patch({ status: "error" });
if (candidate.transition === "edit_source") queue(candidate);
return;
}
if (candidateValidationEpoch !== validationEpoch) return;
if (destroyed || preflight.editGeneration !== store.getState().editGeneration) return;
if (!preflight.result.ok) {
patch({
diagnostics: [
...compiled.diagnostics,
...preflight.result.diagnostics,
preflightFailureDiagnostic(preflight.result),
],
status: "error",
});
if (candidate.transition !== "edit_source") return;
}
}
queue(candidate);
};
const schedule = (candidate: Candidate) => {
if (timer) clearTimeout(timer);
latestCandidate = candidate;
timer = setTimeout(() => {
timer = undefined;
void processCandidate(candidate);
}, debounceMs);
};
const restore = (target: SemanticStylesheet, opposite: "undoStack" | "redoStack") => {
const state = store.getState();
const stack = opposite === "undoStack" ? state.undoStack : state.redoStack;
const previous = stack.at(-1);
if (!previous) return;
const generation = state.editGeneration + 1;
const other = opposite === "undoStack" ? "redoStack" : "undoStack";
resetHistoryCoalescing();
patch({
source: previous.source,
editGeneration: generation,
colorTokens: [],
[opposite]: stack.slice(0, -1),
[other]: appendHistory(state[other], target),
canUndo: opposite === "redoStack" || stack.length > 1,
canRedo: opposite === "undoStack" || stack.length > 1,
});
schedule({ generation, transition: "restore_history", restore: previous });
};
store.setState({
resumeId: options.resumeId,
mode: initial.mode,
source: structuredClone(initial.source),
applied: structuredClone(initial.applied),
revision: options.initial.revision,
renderDataVersion: options.initial.renderDataVersion,
editGeneration: 0,
diagnostics: [],
colorTokens: [],
editorMetadata,
status: "idle",
restoreLocked: false,
focused: false,
undoStack: [],
redoStack: [],
canUndo: false,
canRedo: false,
setSourceText(text) {
const state = store.getState();
if (state.restoreLocked || text === state.source.text) return;
const generation = state.editGeneration + 1;
const nextSource = sourceFromText(state.source, text);
const now = Date.now();
const undoStack =
historyCanCoalesce && now - historyLastEditAt <= HISTORY_COALESCE_MS
? state.undoStack
: appendHistory(state.undoStack, currentStylesheet(state));
historyLastEditAt = now;
historyCanCoalesce = true;
patch({
source: nextSource,
editGeneration: generation,
colorTokens: [],
undoStack,
redoStack: [],
canUndo: true,
canRedo: false,
});
schedule({ generation, transition: "edit_source", source: nextSource });
},
setFocused(focused) {
patch({ focused });
if (focused || !deferredCanonical) return;
const canonical = deferredCanonical;
deferredCanonical = undefined;
const candidate = latestCandidate;
const hasLocalDraft =
candidate !== undefined && store.getState().source.text !== canonical.stylesheet.source.text;
replaceCanonical(canonical, hasLocalDraft);
if (hasLocalDraft && candidate) schedule(candidate);
else resetHistoryCoalescing();
},
activate() {
const state = store.getState();
if (state.restoreLocked || state.mode === "semantic") return;
const generation = state.editGeneration + 1;
resetHistoryCoalescing();
patch({
editGeneration: generation,
colorTokens: [],
undoStack: appendHistory(state.undoStack, currentStylesheet(state)),
redoStack: [],
canUndo: true,
canRedo: false,
});
schedule({ generation, transition: "activate", source: state.source });
},
deactivate() {
const state = store.getState();
if (state.restoreLocked || state.mode === "legacy") return;
const generation = state.editGeneration + 1;
resetHistoryCoalescing();
patch({
editGeneration: generation,
colorTokens: [],
undoStack: appendHistory(state.undoStack, currentStylesheet(state)),
redoStack: [],
canUndo: true,
canRedo: false,
});
queue({ generation, transition: "deactivate" });
},
undo() {
if (store.getState().restoreLocked) return;
restore(currentStylesheet(store.getState()), "undoStack");
},
redo() {
if (store.getState().restoreLocked) return;
restore(currentStylesheet(store.getState()), "redoStack");
},
refreshIntelligence() {
const state = store.getState();
const generation = state.editGeneration;
const source = structuredClone(state.source);
const requestEpoch = ++intelligenceEpoch;
void options
.compile(compileInput(resumeData, source, generation, editorMetadata.semanticTree))
.then((compiled) => {
const current = store.getState();
if (
destroyed ||
requestEpoch !== intelligenceEpoch ||
current.editGeneration !== generation ||
!sourcesEqual(current.source, source)
) {
return;
}
patch({ diagnostics: compiled.diagnostics, colorTokens: compiled.colorTokens ?? [] });
});
},
});
return {
store,
replaceResumeSnapshot(data: ResumeData, canonical: StylesheetCanonicalState) {
const candidate = latestCandidate;
resumeData = structuredClone(data);
editorMetadata = createEditorMetadata(resumeData);
patch({ editorMetadata });
const renderDataChanged = canonical.renderDataVersion > store.getState().renderDataVersion;
const preserveSource = store.getState().focused || isEditorFocused() || candidate !== undefined;
replaceCanonical(canonical, preserveSource);
if (renderDataChanged) {
validationEpoch += 1;
pending = undefined;
if (candidate) schedule(candidate);
}
},
rebaseCanonical(canonical: StylesheetCanonicalState) {
const candidate = latestCandidate;
const hasLocalDraft =
candidate !== undefined && store.getState().source.text !== canonical.stylesheet.source.text;
const focused = store.getState().focused || isEditorFocused();
const sourceChanged = store.getState().source.text !== canonical.stylesheet.source.text;
if (focused && sourceChanged && canonical.revision >= store.getState().revision) deferredCanonical = canonical;
const preserveSource = (focused && sourceChanged) || hasLocalDraft;
replaceCanonical(canonical, preserveSource);
if (hasLocalDraft && candidate) schedule(candidate);
else if (!preserveSource) resetHistoryCoalescing();
},
destroy() {
destroyed = true;
abortController.abort();
if (timer) clearTimeout(timer);
timer = undefined;
pending = undefined;
latestCandidate = undefined;
deferredCanonical = undefined;
options.destroy?.();
store.setState(inactiveState());
},
};
}
export const useStylesheetStore = create<StylesheetStoreState>(() => ({
...inactiveState(),
setSourceText: () => {},
setFocused: () => {},
activate: () => {},
deactivate: () => {},
undo: () => {},
redo: () => {},
refreshIntelligence: () => {},
}));
let activeRuntime: ReturnType<typeof createStylesheetStoreRuntime> | undefined;
declare const stylesheetRuntimeTokenBrand: unique symbol;
export type StylesheetRuntimeToken = Readonly<{ [stylesheetRuntimeTokenBrand]: true }>;
let activeRuntimeToken: StylesheetRuntimeToken | undefined;
const compilerClient = () =>
createCompileWorkerClient(
() =>
new Worker(new URL("./stylesheet.worker.ts", import.meta.url), { type: "module", name: "semantic-css-compiler" }),
);
const preflightClient = () =>
createPreflightWorkerClient(
() =>
new Worker(new URL("./preflight.worker.ts", import.meta.url), { type: "module", name: "semantic-css-preflight" }),
5_000,
);
export function initializeStylesheetStore(input: {
resumeId: string;
initial: StylesheetCanonicalState;
resumeData: ResumeData;
}) {
activeRuntime?.destroy();
const compiler = compilerClient();
const preflight = preflightClient();
preflight.warmup();
const runtime = createStylesheetStoreRuntime({
...input,
store: useStylesheetStore,
compile: compiler.compile,
preflight: preflight.preflight,
mutate: (mutation, signal) => orpc.resume.stylesheet.mutate.call(mutation, { signal }),
destroy: () => {
compiler.destroy();
preflight.destroy();
},
});
activeRuntime = runtime;
activeRuntimeToken = {} as StylesheetRuntimeToken;
return () => {
if (activeRuntime?.store.getState().resumeId !== input.resumeId) return;
activeRuntime.destroy();
activeRuntime = undefined;
activeRuntimeToken = undefined;
};
}
export function lockStylesheetStoreForRestore(resumeId: string): StylesheetRuntimeToken | undefined {
if (!activeRuntime || !activeRuntimeToken) return;
const state = activeRuntime.store.getState();
if (state.resumeId !== resumeId || state.restoreLocked) return;
activeRuntime.store.setState({ restoreLocked: true });
return activeRuntimeToken;
}
export function unlockStylesheetStoreAfterRestore(token: StylesheetRuntimeToken | undefined): boolean {
if (!activeRuntime || !token || activeRuntimeToken !== token) return false;
activeRuntime.store.setState({ restoreLocked: false });
return true;
}
export function replaceStylesheetStoreAfterRestore(input: {
resumeId: string;
initial: StylesheetCanonicalState;
resumeData: ResumeData;
token: StylesheetRuntimeToken | undefined;
}): boolean {
if (
!activeRuntime ||
!input.token ||
activeRuntimeToken !== input.token ||
activeRuntime.store.getState().resumeId !== input.resumeId ||
!activeRuntime.store.getState().restoreLocked
) {
return false;
}
initializeStylesheetStore(input);
return true;
}
export async function refreshStylesheetStore(resumeId: string, resumeData?: ResumeData) {
if (!activeRuntime || activeRuntime.store.getState().resumeId !== resumeId) return;
const canonical = await orpc.resume.stylesheet.getState.call({ id: resumeId });
if (resumeData) activeRuntime.replaceResumeSnapshot(resumeData, canonical);
else activeRuntime.rebaseCanonical(canonical);
}
@@ -0,0 +1,72 @@
// @vitest-environment happy-dom
import type { CompileWorkerRequest, CompileWorkerResponse } from "./protocol";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { defaultResumeData } from "@reactive-resume/schema/resume/default";
function request(source: string): CompileWorkerRequest {
return {
type: "compile",
requestId: 1,
editGeneration: 1,
source: { languageVersion: 1, text: source },
semanticTree: {
key: "resume",
kind: "resume",
attributes: {},
roles: [],
children: [{ key: "name", kind: "name", attributes: {}, roles: [], children: [] }],
},
baseSettings: {
picture: defaultResumeData.picture,
template: defaultResumeData.metadata.template,
design: defaultResumeData.metadata.design,
typography: defaultResumeData.metadata.typography,
page: defaultResumeData.metadata.page,
layout: { sidebarWidth: defaultResumeData.metadata.layout.sidebarWidth },
},
pages: [{ pageKey: "page-1", width: 595.28, height: 841.89 }],
};
}
describe("stylesheet worker", () => {
let handleMessage: ((event: MessageEvent<CompileWorkerRequest>) => void) | undefined;
const postMessage = vi.fn();
beforeEach(async () => {
handleMessage = undefined;
postMessage.mockReset();
vi.resetModules();
vi.stubGlobal("self", {
addEventListener: vi.fn((type: string, listener: (event: MessageEvent<CompileWorkerRequest>) => void) => {
if (type === "message") handleMessage = listener;
}),
postMessage,
});
await import("./stylesheet.worker");
});
it("returns diagnostics from variable resolution", () => {
handleMessage?.(
new MessageEvent("message", {
data: request("@version 1;\nname { color: var(--missing); }\n"),
}),
);
const response = postMessage.mock.calls[0]?.[0] as CompileWorkerResponse | undefined;
expect(response?.diagnostics).toEqual(
expect.arrayContaining([expect.objectContaining({ code: "UNRESOLVED_VARIABLE", severity: "error" })]),
);
});
it("returns overlapping semantic diagnostics once", () => {
handleMessage?.(
new MessageEvent("message", {
data: request('@version 1;\nsection[type="education"] { color: red; }\n'),
}),
);
const response = postMessage.mock.calls[0]?.[0] as CompileWorkerResponse | undefined;
expect(response?.diagnostics.filter(({ code }) => code === "SELECTOR_NO_MATCH")).toHaveLength(1);
});
});
@@ -1,14 +1,21 @@
/// <reference lib="webworker" /> /// <reference lib="webworker" />
import type { CompileWorkerRequest, CompileWorkerResponse } from "./protocol"; import type { CompileWorkerRequest, CompileWorkerResponse } from "./protocol";
import { analyzeStylesheet, compileStylesheet } from "@reactive-resume/resume/stylesheet"; import { compileStylesheet, resolveStylesheet } from "@reactive-resume/resume/stylesheet";
import { collectCompiledColorTokens } from "./color-tokens"; import { collectCompiledColorTokens } from "./color-tokens";
self.addEventListener("message", ({ data }: MessageEvent<CompileWorkerRequest>) => { self.addEventListener("message", ({ data }: MessageEvent<CompileWorkerRequest>) => {
if (data.type !== "compile") return; if (data.type !== "compile") return;
const compiled = compileStylesheet(data.source); const compiled = compileStylesheet(data.source);
const diagnostics = compiled.program const diagnostics = compiled.program
? [...compiled.diagnostics, ...analyzeStylesheet(compiled.program, data.semanticTree)] ? [
...compiled.diagnostics,
...resolveStylesheet(compiled.program, data.semanticTree, {
baseStyles: {},
baseSettings: data.baseSettings,
pages: data.pages,
}).diagnostics,
]
: compiled.diagnostics; : compiled.diagnostics;
const response: CompileWorkerResponse = { const response: CompileWorkerResponse = {
type: "compile_result", type: "compile_result",
@@ -1,6 +1,5 @@
import { t } from "@lingui/core/macro"; import { t } from "@lingui/core/macro";
import { import {
ArrowCounterClockwiseIcon,
ArrowsInIcon, ArrowsInIcon,
ArrowsOutIcon, ArrowsOutIcon,
ArrowUUpLeftIcon, ArrowUUpLeftIcon,
@@ -43,7 +42,6 @@ export type StylesheetToolbarProps = {
onUndo(): void; onUndo(): void;
onRedo(): void; onRedo(): void;
onFormat(): void; onFormat(): void;
onReset(): void;
onFocusToggle(): void; onFocusToggle(): void;
}; };
@@ -56,7 +54,6 @@ export function StylesheetToolbar({
onUndo, onUndo,
onRedo, onRedo,
onFormat, onFormat,
onReset,
onFocusToggle, onFocusToggle,
}: StylesheetToolbarProps) { }: StylesheetToolbarProps) {
return ( return (
@@ -73,9 +70,6 @@ export function StylesheetToolbar({
<ToolbarButton label={t`Format stylesheet`} disabled={disabled} onClick={onFormat}> <ToolbarButton label={t`Format stylesheet`} disabled={disabled} onClick={onFormat}>
<MagicWandIcon data-icon="inline-start" /> <MagicWandIcon data-icon="inline-start" />
</ToolbarButton> </ToolbarButton>
<ToolbarButton label={t`Reset to applied stylesheet`} disabled={disabled} onClick={onReset}>
<ArrowCounterClockwiseIcon data-icon="inline-start" />
</ToolbarButton>
<ToolbarButton label={focused ? t`Exit focus mode` : t`Open focus mode`} onClick={onFocusToggle}> <ToolbarButton label={focused ? t`Exit focus mode` : t`Open focus mode`} onClick={onFocusToggle}>
{focused ? <ArrowsInIcon data-icon="inline-start" /> : <ArrowsOutIcon data-icon="inline-start" />} {focused ? <ArrowsInIcon data-icon="inline-start" /> : <ArrowsOutIcon data-icon="inline-start" />}
</ToolbarButton> </ToolbarButton>
@@ -1,6 +1,5 @@
import { describe, expect, it, vi } from "vitest"; import { describe, expect, it, vi } from "vitest";
import { getPreflightTransferables } from "./protocol"; import { createCompileWorkerClient } from "./worker-client";
import { createCompileWorkerClient, createPreflightWorkerClient } from "./worker-client";
type Listener = (event: MessageEvent) => void; type Listener = (event: MessageEvent) => void;
@@ -23,15 +22,13 @@ function worker() {
} }
}, },
emitError(event: ErrorEvent) { emitError(event: ErrorEvent) {
for (const listener of listeners.get("error") ?? []) { for (const listener of listeners.get("error") ?? []) listener(event);
listener(event);
}
}, },
}; };
} }
describe("stylesheet worker clients", () => { describe("stylesheet compiler worker client", () => {
it("resolves older compiler results so callers can generation-check without aborting", async () => { it("resolves every compiler result so the editor can generation-check", async () => {
const fake = worker(); const fake = worker();
const client = createCompileWorkerClient(() => fake); const client = createCompileWorkerClient(() => fake);
const first = client.compile({ editGeneration: 1 } as never); const first = client.compile({ editGeneration: 1 } as never);
@@ -54,181 +51,14 @@ describe("stylesheet worker clients", () => {
await expect(pending).rejects.toThrow("Failed to load compiler worker"); await expect(pending).rejects.toThrow("Failed to load compiler worker");
}); });
it("terminates and recreates a timed-out preflight worker", async () => { it("terminates the compiler worker and rejects pending work on destroy", async () => {
vi.useFakeTimers();
const first = worker();
const replacement = worker();
const createWorker = vi.fn().mockReturnValueOnce(first).mockReturnValueOnce(replacement);
const client = createPreflightWorkerClient(createWorker, 10);
const timedOut = client.preflight({ editGeneration: 1 } as never);
first.emit({ type: "preflight_ready" });
await vi.advanceTimersByTimeAsync(10);
await expect(timedOut).resolves.toMatchObject({
result: { ok: false, code: "STYLESHEET_PREFLIGHT_TIMEOUT" },
});
expect(first.terminate).toHaveBeenCalledOnce();
const next = client.preflight({ editGeneration: 2 } as never);
replacement.emit({ type: "preflight_ready" });
await vi.advanceTimersByTimeAsync(0);
replacement.emit({
type: "preflight_result",
requestId: 2,
editGeneration: 2,
result: { ok: true, pageCount: 1, byteCount: 4, diagnostics: [], pdf: new ArrayBuffer(4) },
});
await expect(next).resolves.toMatchObject({ requestId: 2 });
vi.useRealTimers();
});
it("warms the preflight worker before a request starts its deadline", () => {
const fake = worker(); const fake = worker();
const createWorker = vi.fn(() => fake); const client = createCompileWorkerClient(() => fake);
const client = createPreflightWorkerClient(createWorker, 5_000); const pending = client.compile({ editGeneration: 1 } as never);
client.warmup();
expect(createWorker).toHaveBeenCalledOnce();
expect(fake.addEventListener).toHaveBeenCalledTimes(2);
expect(fake.addEventListener).toHaveBeenCalledWith("message", expect.any(Function));
expect(fake.addEventListener).toHaveBeenCalledWith("error", expect.any(Function));
expect(fake.postMessage).not.toHaveBeenCalled();
});
it("waits for readiness without consuming the request deadline", async () => {
vi.useFakeTimers();
const fake = worker();
const client = createPreflightWorkerClient(() => fake, 5, 20);
const result = client.preflight({ editGeneration: 1 } as never);
await vi.advanceTimersByTimeAsync(5);
expect(fake.terminate).not.toHaveBeenCalled();
expect(fake.postMessage).not.toHaveBeenCalled();
fake.emit({ type: "preflight_ready" });
await vi.advanceTimersByTimeAsync(0);
expect(fake.postMessage).toHaveBeenCalledOnce();
await vi.advanceTimersByTimeAsync(5);
await expect(result).resolves.toMatchObject({ result: { code: "STYLESHEET_PREFLIGHT_TIMEOUT" } });
vi.useRealTimers();
});
it("rejects pending preflight work when the worker emits an error event", async () => {
const fake = worker();
const client = createPreflightWorkerClient(() => fake, 5_000);
const pending = client.preflight({ editGeneration: 1 } as never);
const outcome = pending.catch((error: unknown) => error);
fake.emit({ type: "preflight_ready" });
await Promise.resolve();
fake.emitError({ message: "Worker crashed" } as ErrorEvent);
expect(await outcome).toMatchObject({ message: "Worker crashed" });
expect(fake.terminate).toHaveBeenCalled();
});
it("rejects structured resume-data failures without waiting for the timeout", async () => {
vi.useFakeTimers();
const fake = worker();
const client = createPreflightWorkerClient(() => fake, 5_000);
const pending = client.preflight({ editGeneration: 1 } as never);
const outcome = pending.catch((error: unknown) => error);
fake.emit({ type: "preflight_ready" });
await vi.advanceTimersByTimeAsync(0);
fake.emit({
type: "preflight_error",
requestId: 1,
editGeneration: 1,
cause: {
name: "ZodError",
message: "Invalid resume data",
issues: [{ path: ["customSections", 0, "items", 0, "company"] }],
},
});
expect(await outcome).toMatchObject({
name: "ZodError",
issues: [{ path: ["customSections", 0, "items", 0, "company"] }],
});
await vi.advanceTimersByTimeAsync(5_000);
expect(fake.terminate).not.toHaveBeenCalled();
vi.useRealTimers();
});
it("bounds readiness, recreates once, and rejects after the retry also times out", async () => {
vi.useFakeTimers();
const first = worker();
const replacement = worker();
const client = createPreflightWorkerClient(
vi.fn().mockReturnValueOnce(first).mockReturnValueOnce(replacement),
5,
10,
);
const result = client.preflight({ editGeneration: 1 } as never);
const rejection = expect(result).rejects.toThrow("did not become ready");
await vi.advanceTimersByTimeAsync(10);
expect(first.terminate).toHaveBeenCalledOnce();
await vi.advanceTimersByTimeAsync(10);
await rejection;
expect(replacement.terminate).toHaveBeenCalledOnce();
vi.useRealTimers();
});
it("does not recreate a warming worker after destroy", async () => {
vi.useFakeTimers();
const fake = worker();
const createWorker = vi.fn(() => fake);
const client = createPreflightWorkerClient(createWorker, 5, 10);
client.warmup();
client.destroy(); client.destroy();
await vi.runAllTimersAsync();
expect(createWorker).toHaveBeenCalledOnce();
expect(fake.terminate).toHaveBeenCalledOnce(); expect(fake.terminate).toHaveBeenCalledOnce();
vi.useRealTimers(); await expect(pending).rejects.toThrow("terminated");
});
it("terminates stale preflight work when a newer request starts", async () => {
const first = worker();
const replacement = worker();
const client = createPreflightWorkerClient(
vi.fn().mockReturnValueOnce(first).mockReturnValueOnce(replacement),
1_000,
);
const stale = client.preflight({ editGeneration: 1 } as never);
first.emit({ type: "preflight_ready" });
await Promise.resolve();
const staleOutcome = stale.catch((error: unknown) => error);
const current = client.preflight({ editGeneration: 2 } as never);
expect(first.terminate).toHaveBeenCalledOnce();
replacement.emit({ type: "preflight_ready" });
await Promise.resolve();
replacement.emit({
type: "preflight_result",
requestId: 2,
editGeneration: 2,
result: { ok: true, pageCount: 1, byteCount: 4, diagnostics: [], pdf: new ArrayBuffer(4) },
});
expect(await staleOutcome).toEqual(expect.objectContaining({ message: expect.stringContaining("stale") }));
await expect(current).resolves.toMatchObject({ requestId: 2 });
});
it("transfers the generated PDF buffer", () => {
const pdf = new ArrayBuffer(4);
expect(
getPreflightTransferables({
type: "preflight_result",
requestId: 1,
editGeneration: 1,
result: { ok: true, pageCount: 1, byteCount: 4, diagnostics: [], pdf },
}),
).toEqual([pdf]);
}); });
}); });
@@ -1,13 +1,4 @@
import type { import type { CompileWorkerInput, CompileWorkerRequest, CompileWorkerResponse } from "./protocol";
CompileWorkerInput,
CompileWorkerRequest,
CompileWorkerResponse,
PreflightWorkerError,
PreflightWorkerInput,
PreflightWorkerReady,
PreflightWorkerRequest,
PreflightWorkerResponse,
} from "./protocol";
type WorkerListener = (event: MessageEvent<unknown>) => void; type WorkerListener = (event: MessageEvent<unknown>) => void;
type WorkerErrorListener = (event: ErrorEvent) => void; type WorkerErrorListener = (event: ErrorEvent) => void;
@@ -67,164 +58,3 @@ export function createCompileWorkerClient(createWorker: () => StylesheetWorker)
}, },
}; };
} }
const timeoutResult = (request: PreflightWorkerRequest): PreflightWorkerResponse => ({
type: "preflight_result",
requestId: request.requestId,
editGeneration: request.editGeneration,
result: {
ok: false,
code: "STYLESHEET_PREFLIGHT_TIMEOUT",
message: "The PDF preflight exceeded its deadline.",
diagnostics: [],
},
});
export function createPreflightWorkerClient(
createWorker: () => StylesheetWorker,
timeoutMs: number,
readinessTimeoutMs = 10_000,
) {
let worker: StylesheetWorker | undefined;
let requestId = 0;
let ready = false;
let destroyed = false;
let readiness:
| (Pending<StylesheetWorker> & {
promise: Promise<StylesheetWorker>;
timer: ReturnType<typeof setTimeout>;
})
| undefined;
const pending = new Map<number, Pending<PreflightWorkerResponse> & { timer?: ReturnType<typeof setTimeout> }>();
const onMessage: WorkerListener = ({ data }) => {
if ((data as PreflightWorkerReady)?.type === "preflight_ready") {
if (!worker || !readiness) return;
clearTimeout(readiness.timer);
ready = true;
readiness.resolve(worker);
readiness = undefined;
return;
}
const workerError = data as PreflightWorkerError;
if (workerError?.type === "preflight_error") {
const request = pending.get(workerError.requestId);
if (!request) return;
if (request.timer) clearTimeout(request.timer);
pending.delete(workerError.requestId);
request.reject(
Object.assign(new Error(workerError.cause.message), {
name: workerError.cause.name,
issues: workerError.cause.issues,
}),
);
return;
}
const response = data as PreflightWorkerResponse;
if (response?.type !== "preflight_result") return;
const request = pending.get(response.requestId);
if (!request) return;
if (request.timer) clearTimeout(request.timer);
pending.delete(response.requestId);
request.resolve(response);
};
const failPending = (error: Error) => {
for (const request of pending.values()) {
if (request.timer) clearTimeout(request.timer);
request.reject(error);
}
pending.clear();
};
const onError: WorkerErrorListener = (event) => {
const error = new Error(event.message || "Stylesheet preflight worker failed.");
terminate();
failPending(error);
};
const terminate = () => {
if (!worker) return;
worker.removeEventListener("message", onMessage);
worker.removeEventListener("error", onError);
worker.terminate();
worker = undefined;
ready = false;
if (readiness) {
clearTimeout(readiness.timer);
readiness.reject(new Error("Stylesheet preflight worker did not become ready."));
readiness = undefined;
}
};
const getReadyWorker = () => {
if (destroyed) return Promise.reject(new Error("Stylesheet preflight worker was terminated."));
if (worker && ready) return Promise.resolve(worker);
if (readiness) return readiness.promise;
worker = createWorker();
worker.addEventListener("message", onMessage);
worker.addEventListener("error", onError);
let resolve!: (value: StylesheetWorker) => void;
let reject!: (error: Error) => void;
const promise = new Promise<StylesheetWorker>((resolvePromise, rejectPromise) => {
resolve = resolvePromise;
reject = rejectPromise;
});
const timer = setTimeout(() => terminate(), readinessTimeoutMs);
readiness = { promise, resolve, reject, timer };
return promise;
};
const waitUntilReady = async () => {
try {
return await getReadyWorker();
} catch {
return await getReadyWorker();
}
};
return {
warmup() {
void waitUntilReady().catch(() => {});
},
preflight(input: PreflightWorkerInput): Promise<PreflightWorkerResponse> {
if (pending.size > 0) {
terminate();
for (const stale of pending.values()) {
if (stale.timer) clearTimeout(stale.timer);
stale.reject(new Error("Discarded stale stylesheet preflight result."));
}
pending.clear();
}
const request: PreflightWorkerRequest = { ...input, type: "preflight", requestId: ++requestId };
return new Promise((resolve, reject) => {
pending.set(request.requestId, { resolve, reject });
void waitUntilReady()
.then((readyWorker) => {
const current = pending.get(request.requestId);
if (!current) return;
current.timer = setTimeout(() => {
pending.delete(request.requestId);
terminate();
resolve(timeoutResult(request));
}, timeoutMs);
readyWorker.postMessage(request);
})
.catch((error: unknown) => {
const current = pending.get(request.requestId);
if (!current) return;
pending.delete(request.requestId);
reject(error instanceof Error ? error : new Error("Stylesheet preflight worker failed to start."));
});
});
},
destroy() {
destroyed = true;
terminate();
for (const request of pending.values()) {
if (request.timer) clearTimeout(request.timer);
request.reject(new Error("Stylesheet preflight worker was terminated."));
}
pending.clear();
},
};
}
@@ -17,11 +17,6 @@ import {
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@reactive-resume/ui/components/dropdown-menu"; } from "@reactive-resume/ui/components/dropdown-menu";
import { useResumeStore } from "@/features/resume/builder/draft"; import { useResumeStore } from "@/features/resume/builder/draft";
import {
lockStylesheetStoreForRestore,
replaceStylesheetStoreAfterRestore,
unlockStylesheetStoreAfterRestore,
} from "@/features/resume/stylesheet/store";
import { useConfirm } from "@/hooks/use-confirm"; import { useConfirm } from "@/hooks/use-confirm";
import { getResumeErrorMessage } from "@/libs/error-message"; import { getResumeErrorMessage } from "@/libs/error-message";
import { formatRelativeTime } from "@/libs/locale"; import { formatRelativeTime } from "@/libs/locale";
@@ -53,26 +48,13 @@ export function BuilderVersionHistory({ resumeId }: BuilderVersionHistoryProps)
if (!confirmed) return; if (!confirmed) return;
const token = lockStylesheetStoreForRestore(resumeId);
if (!token) return;
try { try {
const restored = await restoreVersion({ resumeId, versionId }); const restored = await restoreVersion({ resumeId, versionId });
const applied = replaceStylesheetStoreAfterRestore({ replaceResumeFromServer(restored as Resume);
resumeId, queryClient.setQueryData(orpc.resume.getById.queryOptions({ input: { id: resumeId } }).queryKey, restored);
resumeData: restored.resume.data,
initial: restored.stylesheetState,
token,
});
if (!applied) {
unlockStylesheetStoreAfterRestore(token);
return;
}
replaceResumeFromServer(restored.resume as Resume);
queryClient.setQueryData(orpc.resume.getById.queryOptions({ input: { id: resumeId } }).queryKey, restored.resume);
void queryClient.invalidateQueries({ queryKey: orpc.resume.listVersions.queryKey({ input: { resumeId } }) }); void queryClient.invalidateQueries({ queryKey: orpc.resume.listVersions.queryKey({ input: { resumeId } }) });
toast.success(t`Your resume has been restored to the selected version.`); toast.success(t`Your resume has been restored to the selected version.`);
} catch (error) { } catch (error) {
unlockStylesheetStoreAfterRestore(token);
toast.error(getResumeErrorMessage(error)); toast.error(getResumeErrorMessage(error));
} }
}; };
@@ -1,5 +1,6 @@
// @vitest-environment happy-dom // @vitest-environment happy-dom
import type { ResumeData } from "@reactive-resume/schema/resume/data";
import { fireEvent, render, screen, waitFor } from "@testing-library/react"; import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { i18n } from "@lingui/core"; import { i18n } from "@lingui/core";
@@ -17,16 +18,8 @@ const resumeMock = vi.hoisted(() => ({
id: string; id: string;
name: string; name: string;
slug: string; slug: string;
data: typeof defaultResumeData; data: ResumeData;
}, },
stylesheet: {
resumeId: "r1" as string | undefined,
mode: "semantic" as "legacy" | "semantic",
source: { languageVersion: 1, text: "@version 1;\nname {" },
applied: { languageVersion: 1, text: "@version 1;\nname { color: #123456; }\n" },
revision: 42,
renderDataVersion: 7,
},
})); }));
type SectionBaseProps = { type SectionBaseProps = {
@@ -50,9 +43,6 @@ vi.mock("@/libs/resume/section-title-locale", () => ({
vi.mock("@/features/resume/builder/draft", () => ({ vi.mock("@/features/resume/builder/draft", () => ({
useResume: () => resumeMock.resume, useResume: () => resumeMock.resume,
})); }));
vi.mock("@/features/resume/stylesheet/store", () => ({
useStylesheetStore: (selector: (state: typeof resumeMock.stylesheet) => unknown) => selector(resumeMock.stylesheet),
}));
const { ExportSectionBuilder } = await import("./export"); const { ExportSectionBuilder } = await import("./export");
@@ -61,15 +51,12 @@ beforeAll(() => {
}); });
beforeEach(() => { beforeEach(() => {
resumeMock.resume = { id: "r1", name: "My Resume", slug: "my-resume", data: defaultResumeData }; const data = structuredClone(defaultResumeData);
resumeMock.stylesheet = { data.metadata.stylesheet = {
resumeId: "r1",
mode: "semantic", mode: "semantic",
source: { languageVersion: 1, text: "@version 1;\nname {" }, source: { languageVersion: 1, text: "@version 1;\nname {" },
applied: { languageVersion: 1, text: "@version 1;\nname { color: #123456; }\n" },
revision: 42,
renderDataVersion: 7,
}; };
resumeMock.resume = { id: "r1", name: "My Resume", slug: "my-resume", data };
}); });
afterEach(() => { afterEach(() => {
@@ -115,7 +102,7 @@ describe("ExportSectionBuilder", () => {
expect(filename).toBe("My Resume.md"); expect(filename).toBe("My Resume.md");
}); });
it("downloads canonical stylesheet content in JSON without concurrency metadata", async () => { it("downloads the current stylesheet source in JSON", async () => {
renderExport(); renderExport();
openDialog(); openDialog();
fireEvent.click(screen.getByRole("button", { name: "Download JSON" })); fireEvent.click(screen.getByRole("button", { name: "Download JSON" }));
@@ -127,13 +114,7 @@ describe("ExportSectionBuilder", () => {
expect((blob as Blob).type).toBe("application/json"); expect((blob as Blob).type).toBe("application/json");
expect(filename).toBe("My Resume.json"); expect(filename).toBe("My Resume.json");
const exported = JSON.parse(await (blob as Blob).text()); const exported = JSON.parse(await (blob as Blob).text());
expect(exported.metadata.stylesheet).toEqual({ expect(exported.metadata.stylesheet).toEqual(resumeMock.resume?.data.metadata.stylesheet);
mode: "semantic",
source: resumeMock.stylesheet.source,
applied: resumeMock.stylesheet.applied,
});
expect(JSON.stringify(exported)).not.toContain("revision");
expect(JSON.stringify(exported)).not.toContain("renderDataVersion");
}); });
it("calls buildDocx and downloads the resulting blob when DOCX is clicked", async () => { it("calls buildDocx and downloads the resulting blob when DOCX is clicked", async () => {
@@ -155,12 +136,7 @@ describe("ExportSectionBuilder", () => {
await Promise.resolve(); await Promise.resolve();
expect(createResumePdfBlob).toHaveBeenCalledTimes(1); expect(createResumePdfBlob).toHaveBeenCalledTimes(1);
expect(createResumePdfBlob).toHaveBeenCalledWith(defaultResumeData, undefined, undefined, { expect(createResumePdfBlob).toHaveBeenCalledWith(resumeMock.resume?.data, undefined, undefined);
stylesheet: {
mode: "semantic",
applied: resumeMock.stylesheet.applied,
},
});
expect(downloadWithAnchor).toHaveBeenCalledTimes(1); expect(downloadWithAnchor).toHaveBeenCalledTimes(1);
expect(downloadWithAnchor.mock.calls[0]?.[1]).toBe("My Resume.pdf"); expect(downloadWithAnchor.mock.calls[0]?.[1]).toBe("My Resume.pdf");
}); });
@@ -1,10 +1,9 @@
import type { BuilderLayout } from "./-store/sidebar"; import type { BuilderLayout } from "./-store/sidebar";
import { useSuspenseQuery } from "@tanstack/react-query"; import { useSuspenseQuery } from "@tanstack/react-query";
import { createFileRoute, redirect } from "@tanstack/react-router"; import { createFileRoute, redirect } from "@tanstack/react-router";
import { useEffect, useRef } from "react"; import { useEffect } from "react";
import { useMediaQuery } from "usehooks-ts"; import { useMediaQuery } from "usehooks-ts";
import { useBuilderResumeUpdateSubscription, useResumeCleanup, useResumeStore } from "@/features/resume/builder/draft"; import { useBuilderResumeUpdateSubscription, useResumeCleanup, useResumeStore } from "@/features/resume/builder/draft";
import { initializeStylesheetStore, useStylesheetStore } from "@/features/resume/stylesheet/store";
import { orpc } from "@/libs/orpc/client"; import { orpc } from "@/libs/orpc/client";
import { createNoindexFollowMeta } from "@/libs/seo"; import { createNoindexFollowMeta } from "@/libs/seo";
import { DesktopBuilderShell } from "./-components/desktop-builder-shell"; import { DesktopBuilderShell } from "./-components/desktop-builder-shell";
@@ -21,9 +20,6 @@ export const Route = createFileRoute("/builder/$resumeId")({
const [layout, resume] = await Promise.all([ const [layout, resume] = await Promise.all([
getBuilderLayout(), getBuilderLayout(),
context.queryClient.ensureQueryData(orpc.resume.getById.queryOptions({ input: { id: params.resumeId } })), context.queryClient.ensureQueryData(orpc.resume.getById.queryOptions({ input: { id: params.resumeId } })),
context.queryClient.ensureQueryData(
orpc.resume.stylesheet.getState.queryOptions({ input: { id: params.resumeId } }),
),
]); ]);
return { layout, name: resume.name }; return { layout, name: resume.name };
@@ -40,17 +36,11 @@ function RouteComponent() {
const { resumeId } = Route.useParams(); const { resumeId } = Route.useParams();
const { data: resume } = useSuspenseQuery(orpc.resume.getById.queryOptions({ input: { id: resumeId } })); const { data: resume } = useSuspenseQuery(orpc.resume.getById.queryOptions({ input: { id: resumeId } }));
const { data: stylesheet } = useSuspenseQuery(
orpc.resume.stylesheet.getState.queryOptions({ input: { id: resumeId } }),
);
const initializeResumeStore = useResumeStore((state) => state.initialize); const initializeResumeStore = useResumeStore((state) => state.initialize);
const mergeResumeMetadata = useResumeStore((state) => state.mergeResumeMetadata); const mergeResumeMetadata = useResumeStore((state) => state.mergeResumeMetadata);
const isReady = useResumeStore((state) => state.isReady); const isReady = useResumeStore((state) => state.isReady);
const initializedResumeId = useResumeStore((state) => state.resumeId); const initializedResumeId = useResumeStore((state) => state.resumeId);
const isInitialized = isReady && initializedResumeId === resumeId; const isInitialized = isReady && initializedResumeId === resumeId;
const isStylesheetInitialized = useStylesheetStore((state) => state.resumeId === resumeId);
const stylesheetInitialization = useRef({ resume, stylesheet });
stylesheetInitialization.current = { resume, stylesheet };
useResumeCleanup(); useResumeCleanup();
useBuilderResumeUpdateSubscription(); useBuilderResumeUpdateSubscription();
@@ -60,16 +50,6 @@ function RouteComponent() {
initializeResumeStore(resume); initializeResumeStore(resume);
}, [initializeResumeStore, isInitialized, resume]); }, [initializeResumeStore, isInitialized, resume]);
useEffect(() => {
if (!isInitialized) return;
const initial = stylesheetInitialization.current;
return initializeStylesheetStore({
resumeId,
initial: initial.stylesheet,
resumeData: initial.resume.data,
});
}, [isInitialized, resumeId]);
useEffect(() => { useEffect(() => {
mergeResumeMetadata(resume); mergeResumeMetadata(resume);
}, [ }, [
@@ -85,7 +65,7 @@ function RouteComponent() {
resume, resume,
]); ]);
if (!isInitialized || !isStylesheetInitialized) return null; if (!isInitialized) return null;
return <BuilderLayoutShell initialLayout={initialLayout} />; return <BuilderLayoutShell initialLayout={initialLayout} />;
} }
+11 -11
View File
@@ -50,12 +50,12 @@ every stylesheet.
<Step title="Paste one focused rule"> <Step title="Paste one focused rule">
Add the stylesheet to the editor. Start with one visual change so it is easy to review in the preview. Add the stylesheet to the editor. Start with one visual change so it is easy to review in the preview.
</Step> </Step>
<Step title="Wait for Applied"> <Step title="Wait for Valid">
Reactive Resume checks the source and the PDF result. When the status changes to **Applied**, compare the preview Reactive Resume checks the source in the browser. When the status changes to **Valid**, compare the preview and
and export if you are ready to share the resume. export if you are ready to share the resume.
</Step> </Step>
<Step title="Build on the working rule"> <Step title="Build on the working rule">
Add one related change at a time. The editor keeps your draft, undo history, and last valid stylesheet separately. Add one related change at a time. Your changes use the normal resume autosave and undo history.
</Step> </Step>
</Steps> </Steps>
@@ -300,19 +300,19 @@ browser viewport.
Supported media features are `width`, `min-width`, `max-width`, `height`, `min-height`, `max-height`, and Supported media features are `width`, `min-width`, `max-width`, `height`, `min-height`, `max-height`, and
`orientation: portrait` or `orientation: landscape`. `orientation: portrait` or `orientation: landscape`.
## Apply, diagnose, and recover safely ## Diagnose and recover safely
The editor saves your draft even when it has an error. The preview and PDF export continue using the last stylesheet The editor saves the current source even when it has an error. A recoverable error ignores only the invalid declaration,
that compiled and passed PDF checks, so a mistake does not replace a working result. value, selector, or rule; valid parts still appear in preview and PDF export. A fatal version or resource-limit error
ignores the whole stylesheet and renders the resume with its base styles until you fix the source.
If a rule does not work: If a rule does not work:
1. Read the status below the editor. Errors include a line and column number when available. 1. Read the status below the editor. Errors include a line and column number when available.
2. Check the selector's spelling, attribute value, placement, and template guard. A **selector matches nothing** 2. Check the selector's spelling, attribute value, placement, and template guard. A **selector matches nothing**
warning usually means the resume does not contain that semantic node. warning usually means the resume does not contain that semantic node.
3. Simplify the rule to one selector and one declaration, then wait for **Applied** before adding more. 3. Simplify the rule to one selector and one declaration, then wait for **Valid** before adding more.
4. Use **Reset to applied stylesheet** to discard the current draft, or use the stylesheet undo and redo controls to 4. Use the stylesheet undo and redo controls to restore an earlier source.
restore an earlier source and applied pair.
Select **Open focus mode** when you need a taller editor. On mobile, it opens a full-width sheet; switch to Select **Open focus mode** when you need a taller editor. On mobile, it opens a full-width sheet; switch to
**Preview** to inspect the result. **Preview** to inspect the result.
@@ -331,7 +331,7 @@ starting point. Exact IDs and template parts are intentionally specific to a res
2. Open **Design -> Custom Styles** in the destination resume. 2. Open **Design -> Custom Styles** in the destination resume.
3. Paste the stylesheet and review any warnings. 3. Paste the stylesheet and review any warnings.
4. Replace or remove exact IDs and template-part rules that do not apply. 4. Replace or remove exact IDs and template-part rules that do not apply.
5. Wait for **Applied**, then compare the preview and exported PDF. 5. Wait for **Valid**, then compare the preview and exported PDF.
Semantic CSS does not support classes, pseudo-elements, CSS Grid, arbitrary at-rules, `@import`, `@font-face`, `url()`, Semantic CSS does not support classes, pseudo-elements, CSS Grid, arbitrary at-rules, `@import`, `@font-face`, `url()`,
browser APIs, animations, filters, gradients, general box shadows, or external assets. Use the normal builder settings browser APIs, animations, filters, gradients, general box shadows, or external assets. Use the normal builder settings

Some files were not shown because too many files have changed in this diff Show More