Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
pontusab committed Jan 18, 2025
1 parent 4eb5c35 commit 05ce61b
Show file tree
Hide file tree
Showing 23 changed files with 1,492 additions and 529 deletions.
2 changes: 1 addition & 1 deletion apps/web/languine.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { defineConfig } from "languine";
export default defineConfig({
locale: {
source: "en",
targets: ["es"],
targets: ["es", "sv", "de", "fr"],
},
files: {
ts: {
Expand Down
67 changes: 47 additions & 20 deletions apps/web/src/jobs/translate/translate.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { validateJobPermissions } from "@/db/queries/permissions";
import { logger, metadata, schemaTask, wait } from "@trigger.dev/sdk/v3";
import { metadata, schemaTask } from "@trigger.dev/sdk/v3";
import { z } from "zod";
import { translate } from "../utils/translate";

const translationSchema = z.object({
projectId: z.string(),
Expand All @@ -21,36 +22,62 @@ export const translateTask = schemaTask({
schema: translationSchema,
maxDuration: 300,
queue: {
concurrencyLimit: 1,
concurrencyLimit: 10,
},
run: async (payload, { ctx }) => {
// Simulate translation progress with smaller steps
const totalSteps =
payload.targetLanguages.length * payload.content.length * 10; // 10 mini-steps per translation
let completedSteps = 0;
// Validate permissions
// await validateJobPermissions(payload.projectId, payload.apiKey);

const translations: Record<
string,
Array<{ key: string; translatedText: string }>
> = {};

for (const lang of payload.targetLanguages) {
translations[lang] = [];
const totalTranslations =
payload.targetLanguages.length * payload.content.length;
let completedTranslations = 0;

for (const item of payload.content) {
// Split the 1 second wait into 10 smaller steps
for (let i = 0; i < 10; i++) {
await wait.for({ seconds: 0.1 });
completedSteps++;
metadata.set("progress", completedSteps / totalSteps);
}
metadata.set("progress", 0);

// Run translations in parallel for each target language
await Promise.all(
payload.targetLanguages.map(async (targetLocale) => {
translations[targetLocale] = [];

// Update progress before starting each language
metadata.set(
"progress",
Math.round((completedTranslations * 100) / totalTranslations),
);

translations[lang].push({
key: item.key,
translatedText: `Translated: ${item.sourceText}`,
const translatedContent = await translate(payload.content, {
sourceLocale: payload.sourceLanguage,
targetLocale,
});
}
}

for (let i = 0; i < payload.content.length; i++) {
translations[targetLocale].push({
key: payload.content[i].key,
translatedText: translatedContent[i],
});

completedTranslations++;

// Update progress after each individual translation
const progress = Math.round(
(completedTranslations * 100) / totalTranslations,
);
metadata.set("progress", progress);

// Add micro-progress updates between translations
if (i < payload.content.length - 1) {
metadata.set("progress", progress + 0.5);
}
}
}),
);

metadata.set("progress", 100);

return {
translations,
Expand Down
66 changes: 66 additions & 0 deletions apps/web/src/jobs/utils/prompt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import type { projectSettings } from "@/db/schema";
import type { PromptOptions } from "./types";

const baseRequirements = `
Translation Requirements:
- Maintain exact file structure, indentation, and formatting
- Provide natural, culturally-adapted translations that sound native
- Keep all technical identifiers unchanged
- Keep consistent capitalization, spacing, and line breaks
- Respect existing whitespace and newline patterns
`;

export function createFinalPrompt(
text: string,
options: PromptOptions,
settings?: Partial<typeof projectSettings.$inferSelect>,
) {
const basePrompt = `You are a professional translator working with JSON files.
Task: Translate the content below from ${options.sourceLocale} to ${options.targetLocale}.
${baseRequirements}`;

const tuningInstructions = settings
? [
// Style and tone settings
settings.formality && `- Use ${settings.formality} language style`,
settings.toneOfVoice &&
`- Maintain a ${settings.toneOfVoice} tone of voice`,
settings.emotiveIntent &&
`- Convey a ${settings.emotiveIntent} emotional tone`,

// Brand-specific settings
settings.brandName &&
`- Use "${settings.brandName}" consistently for brand references`,
settings.brandVoice &&
`- Follow brand voice guidelines: ${settings.brandVoice}`,

// Technical settings
settings.lengthControl &&
`- Apply ${settings.lengthControl} length control`,
settings.domainExpertise &&
`- Use terminology appropriate for ${settings.domainExpertise} domain`,
settings.terminology &&
`- Follow specific terminology: ${settings.terminology}`,

// Feature flags
settings.translationMemory &&
"- Maintain consistency with previous translations",
settings.qualityChecks &&
"- Ensure high-quality output with proper grammar and spelling",
settings.contextDetection &&
"- Consider surrounding context for accurate translations",
settings.inclusiveLanguage &&
"- Use inclusive and non-discriminatory language",
settings.idioms && "- Adapt idioms appropriately for target culture",
]
.filter(Boolean)
.join("\n")
: "";

return `${basePrompt}${
tuningInstructions
? `\nAdditional Requirements:\n${tuningInstructions}`
: ""
}\n\n${text}`;
}
38 changes: 38 additions & 0 deletions apps/web/src/jobs/utils/translate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { openai } from "@ai-sdk/openai";
import { generateObject } from "ai";
import { z } from "zod";
import { createFinalPrompt } from "./prompt";
import type { PromptOptions } from "./types";

function getPrompt(
content: Array<{ key: string; sourceText: string }>,
options: PromptOptions,
) {
const codeblocks = content
.map(({ key, sourceText }) => {
return `\`\`\`json
${sourceText}
\`\`\``;
})
.join("\n\n");

return createFinalPrompt(codeblocks, options);
}

export async function translate(
content: Array<{ key: string; sourceText: string }>,
options: PromptOptions,
) {
const prompt = getPrompt(content, options);

const { object } = await generateObject({
model: openai("gpt-4o-mini"),
prompt,
mode: "json",
schema: z.object({
content: z.array(z.string()),
}),
});

return object.content;
}
7 changes: 7 additions & 0 deletions apps/web/src/jobs/utils/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { projectSettings } from "@/db/schema";

export type PromptOptions = {
sourceLocale: string;
targetLocale: string;
settings?: Partial<typeof projectSettings.$inferSelect>;
};
25 changes: 0 additions & 25 deletions apps/web/src/lib/translators/index.ts

This file was deleted.

38 changes: 0 additions & 38 deletions apps/web/src/lib/translators/js.ts

This file was deleted.

37 changes: 0 additions & 37 deletions apps/web/src/lib/translators/md.ts

This file was deleted.

5 changes: 0 additions & 5 deletions apps/web/src/lib/translators/model.ts

This file was deleted.

62 changes: 0 additions & 62 deletions apps/web/src/lib/translators/prompt.ts

This file was deleted.

10 changes: 0 additions & 10 deletions apps/web/src/lib/translators/types.ts

This file was deleted.

Loading

0 comments on commit 05ce61b

Please sign in to comment.