Skip to content

Commit 9d9ab43

Browse files
committed
WIp
1 parent 60232b1 commit 9d9ab43

8 files changed

Lines changed: 60 additions & 187 deletions

File tree

cmp/compiler/src/plugin/build-translator.ts

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ import fs from "fs/promises";
1111
import path from "path";
1212
import type { LingoConfig, MetadataSchema } from "../types";
1313
import { logger } from "../utils/logger";
14-
import { getCachePath } from "../utils/path-helpers";
1514
import {
1615
startTranslationServer,
1716
type TranslationServer,
1817
} from "../translation-server";
1918
import { loadMetadata } from "../metadata/manager";
19+
import { LocalTranslationCache, type TranslationCache } from "../translators";
2020

2121
export interface BuildTranslationOptions {
2222
config: LingoConfig;
@@ -82,14 +82,19 @@ export async function processBuildTranslations(
8282
const totalEntries = Object.keys(metadata.entries).length;
8383
logger.info(`📊 Found ${totalEntries} translatable entries`);
8484

85+
const cache = new LocalTranslationCache(
86+
{ cacheDir: config.lingoDir },
87+
logger,
88+
);
89+
8590
// Handle cache-only mode
8691
if (buildMode === "cache-only") {
8792
logger.info("🔍 Validating translation cache...");
88-
await validateCache(config, metadata);
93+
await validateCache(config, metadata, cache);
8994
logger.info("✅ Cache validation passed");
9095

9196
if (publicOutputPath) {
92-
await copyStaticFiles(config, publicOutputPath, metadata);
97+
await copyStaticFiles(config, publicOutputPath, metadata, cache);
9398
}
9499

95100
return {
@@ -161,7 +166,7 @@ export async function processBuildTranslations(
161166

162167
// Copy cache to public directory if requested
163168
if (publicOutputPath) {
164-
await copyStaticFiles(config, publicOutputPath, metadata);
169+
await copyStaticFiles(config, publicOutputPath, metadata, cache);
165170
}
166171

167172
logger.info("✅ Translation generation completed successfully");
@@ -188,6 +193,7 @@ export async function processBuildTranslations(
188193
async function validateCache(
189194
config: LingoConfig,
190195
metadata: MetadataSchema,
196+
cache: TranslationCache,
191197
): Promise<void> {
192198
const allHashes = Object.keys(metadata.entries);
193199
const missingLocales: string[] = [];
@@ -204,13 +210,16 @@ async function validateCache(
204210
: config.targetLocales;
205211

206212
for (const locale of allLocales) {
207-
const cacheFilePath = getCachePath(config, locale);
208-
209213
try {
210-
const cacheContent = await fs.readFile(cacheFilePath, "utf-8");
211-
const cache = JSON.parse(cacheContent).entries as Record<string, string>;
214+
const entries = await cache.get(locale);
212215

213-
const missingHashes = allHashes.filter((hash) => !cache[hash]);
216+
if (Object.keys(entries).length === 0) {
217+
missingLocales.push(locale);
218+
logger.debug(`Cache file not found or empty for ${locale}`);
219+
continue;
220+
}
221+
222+
const missingHashes = allHashes.filter((hash) => !entries[hash]);
214223

215224
if (missingHashes.length > 0) {
216225
incompleteLocales.push({
@@ -228,7 +237,7 @@ async function validateCache(
228237
}
229238
} catch (error) {
230239
missingLocales.push(locale);
231-
logger.debug(`Cache file not found for ${locale}: ${cacheFilePath}`);
240+
logger.debug(`Failed to read cache for ${locale}:`, error);
232241
}
233242
}
234243

@@ -270,6 +279,7 @@ async function copyStaticFiles(
270279
config: LingoConfig,
271280
publicOutputPath: string,
272281
metadata: MetadataSchema,
282+
cache: TranslationCache,
273283
): Promise<void> {
274284
logger.info(`📦 Generating static translation files in ${publicOutputPath}`);
275285

@@ -285,20 +295,24 @@ async function copyStaticFiles(
285295
: config.targetLocales;
286296

287297
for (const locale of allLocales) {
288-
const cacheFilePath = getCachePath(config, locale);
289298
const publicFilePath = path.join(publicOutputPath, `${locale}.json`);
290299

291300
try {
292-
const cacheContent = await fs.readFile(cacheFilePath, "utf-8");
293-
const cache = JSON.parse(cacheContent);
301+
// Use getDictionary if available (for LocalTranslationCache), otherwise use get
302+
const dictionary = cache.getDictionary
303+
? await cache.getDictionary(locale)
304+
: null;
305+
306+
if (!dictionary) {
307+
logger.error(`❌ Failed to read cache for ${locale}`);
308+
process.exit(1);
309+
}
294310

295311
const filteredEntries: Record<string, string> = {};
296312
let includedCount = 0;
297313
let skippedCount = 0;
298314

299-
for (const [hash, translation] of Object.entries(
300-
cache.entries as Record<string, string>,
301-
)) {
315+
for (const [hash, translation] of Object.entries(dictionary.entries)) {
302316
if (usedHashes.has(hash)) {
303317
filteredEntries[hash] = translation;
304318
includedCount++;
@@ -311,7 +325,7 @@ async function copyStaticFiles(
311325
const outputData = {
312326
locale,
313327
entries: filteredEntries,
314-
version: cache.version,
328+
version: dictionary.version,
315329
};
316330

317331
await fs.writeFile(

cmp/compiler/src/translation-server/translation-server.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,7 @@ export class TranslationServer {
9595
const isPseudo = translator.constructor.name === "PseudoTranslator";
9696

9797
const cache = new LocalTranslationCache(
98-
{
99-
cacheDir: this.config.lingoDir,
100-
sourceRoot: this.config.sourceRoot,
101-
},
98+
{ cacheDir: this.config.lingoDir },
10299
this.logger,
103100
);
104101

cmp/compiler/src/translators/cache.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,29 @@ export interface TranslationCache {
4242
* Clear all cached translations
4343
*/
4444
clearAll(): Promise<void>;
45+
46+
/**
47+
* Get full dictionary schema for a locale (includes version, metadata)
48+
* Used for build-time operations that need the complete schema
49+
* Returns null if cache doesn't exist
50+
*/
51+
getDictionary?(
52+
locale: string,
53+
): Promise<import("./api").DictionarySchema | null>;
54+
55+
/**
56+
* Write full dictionary schema for a locale
57+
* Used for build-time operations that need to preserve schema metadata
58+
*/
59+
setDictionary?(
60+
locale: string,
61+
dictionary: import("./api").DictionarySchema,
62+
): Promise<void>;
4563
}
4664

4765
/**
4866
* Configuration for local disk cache
4967
*/
5068
export interface LocalCacheConfig {
51-
/**
52-
* Directory to store cache files (e.g., ".lingo")
53-
*/
5469
cacheDir: string;
55-
56-
/**
57-
* Optional source root path
58-
*/
59-
sourceRoot?: string;
6070
}

cmp/compiler/src/translators/local-cache.ts

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,15 @@ export class LocalTranslationCache implements TranslationCache {
2323
this.config = config;
2424
}
2525

26-
/**
27-
* Get cache file path for a locale
28-
*/
2926
private getCachePath(locale: string): string {
30-
const baseDir = this.config.sourceRoot
31-
? path.join(process.cwd(), this.config.sourceRoot, this.config.cacheDir)
32-
: path.join(process.cwd(), this.config.cacheDir);
33-
34-
return path.join(baseDir, "cache", `${locale}.json`);
27+
return path.join(this.config.cacheDir, `${locale}.json`);
3528
}
3629

3730
/**
3831
* Read dictionary file from disk
3932
* Times out after 10 seconds to prevent indefinite hangs
4033
*/
41-
private async readDictionary(
42-
locale: string,
43-
): Promise<DictionarySchema | null> {
34+
async getDictionary(locale: string): Promise<DictionarySchema | null> {
4435
try {
4536
const cachePath = this.getCachePath(locale);
4637
const content = await withTimeout(
@@ -58,7 +49,7 @@ export class LocalTranslationCache implements TranslationCache {
5849
* Write dictionary file to disk
5950
* Times out after 10 seconds to prevent indefinite hangs
6051
*/
61-
private async writeDictionary(
52+
async setDictionary(
6253
locale: string,
6354
dictionary: DictionarySchema,
6455
): Promise<void> {
@@ -89,7 +80,7 @@ export class LocalTranslationCache implements TranslationCache {
8980
* Get cached translations for a locale
9081
*/
9182
async get(locale: string): Promise<Record<string, string>> {
92-
const dictionary = await this.readDictionary(locale);
83+
const dictionary = await this.getDictionary(locale);
9384
if (!dictionary) {
9485
return {};
9586
}
@@ -126,7 +117,7 @@ export class LocalTranslationCache implements TranslationCache {
126117
entries: translations,
127118
};
128119

129-
await this.writeDictionary(locale, dictionary);
120+
await this.setDictionary(locale, dictionary);
130121
}
131122

132123
/**
@@ -159,17 +150,12 @@ export class LocalTranslationCache implements TranslationCache {
159150
*/
160151
async clearAll(): Promise<void> {
161152
try {
162-
const baseDir = this.config.sourceRoot
163-
? path.join(process.cwd(), this.config.sourceRoot, this.config.cacheDir)
164-
: path.join(process.cwd(), this.config.cacheDir);
165-
166-
const cacheDir = path.join(baseDir, "cache");
167-
const files = await fs.readdir(cacheDir);
153+
const files = await fs.readdir(this.config.cacheDir);
168154

169155
await Promise.all(
170156
files
171157
.filter((file) => file.endsWith(".json"))
172-
.map((file) => fs.unlink(path.join(cacheDir, file))),
158+
.map((file) => fs.unlink(path.join(this.config.cacheDir, file))),
173159
);
174160
} catch {
175161
// Ignore errors if directory doesn't exist

cmp/compiler/src/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ export interface PluralizationConfig {
6565
model?: string;
6666
}
6767

68+
export type LingoEnvironment = "development" | "production";
69+
6870
/**
6971
* Lingo config with all the defaults applied
7072
*/
@@ -85,7 +87,7 @@ export type LingoConfig = {
8587
*
8688
* @default "production"
8789
*/
88-
environment: "development" | "production";
90+
environment: LingoEnvironment;
8991

9092
/**
9193
* The locale to translate from.

cmp/compiler/src/utils/dictionary.ts

Lines changed: 0 additions & 101 deletions
This file was deleted.

0 commit comments

Comments
 (0)