Skip to content

Commit d40047c

Browse files
committed
feat: sourt out loggers again
1 parent d875cd2 commit d40047c

11 files changed

Lines changed: 115 additions & 146 deletions

File tree

cmp/compiler/src/plugin/next.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { NextConfig } from "next";
22

33
import { getConfigPath } from "../utils/path-helpers";
44
import { createLingoConfig } from "../utils/config-factory";
5-
import { logger, loggerRegistry } from "../utils/logger";
5+
import { logger } from "../utils/logger";
66
import type { PartialLingoConfig } from "../types";
77
import type { TurbopackOptions } from "next/dist/server/config-shared";
88

@@ -64,12 +64,6 @@ function buildLingoConfig(
6464
): NextConfig {
6565
const lingoConfig = createLingoConfig(lingoOptions);
6666

67-
loggerRegistry.create("plugin", {
68-
enableConsole: true,
69-
// TODO (AleksandrSl 04/12/2025): Make configurable
70-
enableDebug: true,
71-
});
72-
7367
// Prepare Turbopack loader configuration
7468
const loaderConfig = {
7569
loader: "@lingo.dev/_compiler/turbopack-loader",

cmp/compiler/src/utils/file-writer.ts renamed to cmp/compiler/src/translation-server/logger.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import { Logger, type LogLevel } from "../utils/logger";
2+
import { join } from "path";
3+
import type { TranslationMiddlewareConfig } from "../types";
4+
15
/**
26
* Such weird separation of file writer from logger
37
* is needed to avoid leaking node deps to the client build in next,
48
* but still keep the main logger logic in one place.
59
*/
610
import { appendFile } from "fs/promises";
7-
import { getLogger, type LogLevel } from "./logger";
811

912
/**
1013
* Create a file writer function for a specific log file
@@ -36,13 +39,20 @@ export function createFileWriter(
3639
};
3740
}
3841

39-
/**
40-
* Configure a logger with file output
41-
*/
42-
export function configureFileLogger(
43-
logger: ReturnType<typeof getLogger>,
44-
filePath: string,
45-
): void {
46-
const fileWriter = createFileWriter(filePath);
47-
logger.setFileWriter(fileWriter);
42+
let logger: Logger | undefined = undefined;
43+
44+
export function getLogger(config: TranslationMiddlewareConfig) {
45+
if (!logger) {
46+
const translationServerLogPath = join(
47+
config.sourceRoot,
48+
config.lingoDir,
49+
"translation-server.log",
50+
);
51+
logger = new Logger({
52+
enableConsole: false,
53+
enableDebug: true,
54+
writeToFile: createFileWriter(translationServerLogPath),
55+
});
56+
}
57+
return logger;
4858
}

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

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,13 @@
1414
import http from "http";
1515
import { URL } from "url";
1616
import type { MetadataSchema, TranslationMiddlewareConfig } from "../types";
17-
import { getLogger, loggerRegistry } from "../utils/logger";
17+
import { getLogger } from "./logger";
1818
import {
1919
createTranslator,
2020
LocalTranslationCache,
2121
TranslationService,
2222
} from "../translators";
2323
import { createEmptyMetadata, loadMetadata } from "../metadata/manager";
24-
import { join } from "path";
25-
import { configureFileLogger } from "../utils/file-writer";
2624

2725
export interface TranslationServerOptions {
2826
/**
@@ -63,20 +61,7 @@ export class TranslationServer {
6361
this.startPort = options.startPort || 60000;
6462
this.onReadyCallback = options.onReady;
6563
this.onErrorCallback = options.onError;
66-
const translationServerLogger = loggerRegistry.create(
67-
"translation-server",
68-
{
69-
enableConsole: false,
70-
enableDebug: true,
71-
},
72-
);
73-
const translationServerLogPath = join(
74-
this.config.sourceRoot,
75-
this.config.lingoDir,
76-
"translation-server.log",
77-
);
78-
configureFileLogger(translationServerLogger, translationServerLogPath);
79-
this.logger = getLogger("translation-server");
64+
this.logger = getLogger(this.config);
8065
}
8166

8267
/**
@@ -89,19 +74,27 @@ export class TranslationServer {
8974

9075
this.logger.info(`🔧 Initializing translator...`);
9176

92-
const translator = createTranslator(this.config);
77+
const translator = createTranslator(this.config, this.logger);
9378
const isPseudo = translator.constructor.name === "PseudoTranslator";
9479

95-
const cache = new LocalTranslationCache({
96-
cacheDir: this.config.lingoDir,
97-
sourceRoot: this.config.sourceRoot,
98-
});
80+
const cache = new LocalTranslationCache(
81+
{
82+
cacheDir: this.config.lingoDir,
83+
sourceRoot: this.config.sourceRoot,
84+
},
85+
this.logger,
86+
);
9987

100-
this.translationService = new TranslationService(translator, cache, {
101-
sourceLocale: this.config.sourceLocale,
102-
pluralization: this.config.pluralization,
103-
isPseudo,
104-
});
88+
this.translationService = new TranslationService(
89+
translator,
90+
cache,
91+
{
92+
sourceLocale: this.config.sourceLocale,
93+
pluralization: this.config.pluralization,
94+
isPseudo,
95+
},
96+
this.logger,
97+
);
10598

10699
const port = await this.findAvailablePort(this.startPort);
107100

cmp/compiler/src/translators/lcp/lcp-translator.test.ts

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,34 @@
1-
import { describe, it, expect } from "vitest";
1+
import { describe, expect, it } from "vitest";
22
import { LCPTranslator } from "./lcp-translator";
3+
import { logger } from "../../utils/logger";
34

45
describe("LCPTranslator", () => {
56
it("should create an instance with config", () => {
6-
const translator = new LCPTranslator({
7-
models: "lingo.dev",
8-
sourceLocale: "en",
9-
});
7+
const translator = new LCPTranslator(
8+
{
9+
models: "lingo.dev",
10+
sourceLocale: "en",
11+
},
12+
logger,
13+
);
1014

1115
expect(translator).toBeDefined();
1216
expect(translator.config.models).toBe("lingo.dev");
1317
expect(translator.config.sourceLocale).toBe("en");
1418
});
1519

1620
it("should create an instance with custom models", () => {
17-
const translator = new LCPTranslator({
18-
models: {
19-
"en:es": "google:gemini-2.0-flash",
20-
"*:*": "groq:llama3-8b-8192",
21+
const translator = new LCPTranslator(
22+
{
23+
models: {
24+
"en:es": "google:gemini-2.0-flash",
25+
"*:*": "groq:llama3-8b-8192",
26+
},
27+
sourceLocale: "en",
28+
prompt: "Translate professionally",
2129
},
22-
sourceLocale: "en",
23-
prompt: "Translate professionally",
24-
});
30+
logger,
31+
);
2532

2633
expect(translator).toBeDefined();
2734
expect(translator.config.models).toEqual({
@@ -32,10 +39,13 @@ describe("LCPTranslator", () => {
3239
});
3340

3441
it("should implement Translator interface methods", () => {
35-
const translator = new LCPTranslator({
36-
models: "lingo.dev",
37-
sourceLocale: "en",
38-
});
42+
const translator = new LCPTranslator(
43+
{
44+
models: "lingo.dev",
45+
sourceLocale: "en",
46+
},
47+
logger,
48+
);
3949

4050
expect(typeof translator.translate).toBe("function");
4151
});

cmp/compiler/src/translators/lcp/lcp-translator.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { obj2xml, xml2obj } from "./xml2obj";
66
import { shots } from "./shots";
77
import { getLingoDotDevKey } from "./api-keys";
88
import { createAiModel, getLocaleModel } from "./model-factory";
9-
import { getLogger } from "../../utils/logger";
9+
import { Logger } from "../../utils/logger";
1010
import { DEFAULT_TIMEOUTS, withTimeout } from "../../utils/timeout";
1111

1212
/**
@@ -22,8 +22,10 @@ export interface LCPTranslatorConfig {
2222
* LCP-based translator using AI models
2323
*/
2424
export class LCPTranslator implements Translator<LCPTranslatorConfig> {
25-
private logger = getLogger("translation-server");
26-
constructor(readonly config: LCPTranslatorConfig) {}
25+
constructor(
26+
readonly config: LCPTranslatorConfig,
27+
private logger: Logger,
28+
) {}
2729

2830
/**
2931
* Translate multiple entries

cmp/compiler/src/translators/lcp/prompt.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,16 @@
1-
import { getLogger } from "../../utils/logger";
2-
31
interface PromptArguments {
42
sourceLocale: string;
53
targetLocale: string;
64
prompt?: string;
75
}
86

9-
const logger = getLogger("translation-server");
10-
117
export function getSystemPrompt(args: PromptArguments): string {
128
// If user provided custom prompt, use it
139
if (args.prompt?.trim()) {
14-
const userPrompt = args.prompt
10+
return args.prompt
1511
.trim()
1612
.replace("{SOURCE_LOCALE}", args.sourceLocale)
1713
.replace("{TARGET_LOCALE}", args.targetLocale);
18-
logger.info("✨ Using user-defined translation prompt");
19-
return userPrompt;
2014
}
2115

2216
// Otherwise use built-in prompt

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
import * as fs from "fs/promises";
66
import * as path from "path";
7-
import type { TranslationCache, LocalCacheConfig } from "./cache";
8-
import { getLogger } from "../utils/logger";
7+
import type { LocalCacheConfig, TranslationCache } from "./cache";
98
import type { DictionarySchema } from "./api";
10-
import { withTimeout, DEFAULT_TIMEOUTS } from "../utils/timeout";
9+
import { DEFAULT_TIMEOUTS, withTimeout } from "../utils/timeout";
10+
import type { Logger } from "../utils/logger";
1111

1212
/**
1313
* Local file system cache for translations
@@ -16,7 +16,10 @@ import { withTimeout, DEFAULT_TIMEOUTS } from "../utils/timeout";
1616
export class LocalTranslationCache implements TranslationCache {
1717
private config: LocalCacheConfig;
1818

19-
constructor(config: LocalCacheConfig) {
19+
constructor(
20+
config: LocalCacheConfig,
21+
private logger: Logger,
22+
) {
2023
this.config = config;
2124
}
2225

@@ -77,8 +80,7 @@ export class LocalTranslationCache implements TranslationCache {
7780
`Write cache for ${locale}`,
7881
);
7982
} catch (error) {
80-
const logger = getLogger("translation-server");
81-
logger.error(`Failed to write cache for locale ${locale}:`, error);
83+
this.logger.error(`Failed to write cache for locale ${locale}:`, error);
8284
throw error;
8385
}
8486
}

cmp/compiler/src/translators/pseudotranslator/index.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
import type { TranslatableEntry, Translator } from "../api";
6-
import { getLogger } from "../../utils/logger";
6+
import { Logger } from "../../utils/logger";
77

88
export interface PseudoTranslatorConfig {
99
delayMedian?: number;
@@ -14,8 +14,10 @@ export interface PseudoTranslatorConfig {
1414
* Useful for testing i18n without actual translation APIs
1515
*/
1616
export class PseudoTranslator implements Translator<PseudoTranslatorConfig> {
17-
private readonly logger = getLogger("translation-server");
18-
constructor(readonly config: PseudoTranslatorConfig) {}
17+
constructor(
18+
readonly config: PseudoTranslatorConfig,
19+
private readonly logger: Logger,
20+
) {}
1921

2022
translate(locale: string, entries: Record<string, TranslatableEntry>) {
2123
this.logger.debug(

cmp/compiler/src/translators/translation-service.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@
1111
import type { TranslationCache } from "./cache";
1212
import type { TranslatableEntry, Translator } from "./api";
1313
import type { MetadataSchema } from "../types";
14-
import { getLogger } from "../utils/logger";
15-
import {
16-
processPluralization,
17-
type PluralizationConfig,
18-
} from "./pluralization";
14+
import { processPluralization } from "./pluralization";
15+
import type { Logger } from "../utils/logger";
16+
import type { PartialPluralizationConfig } from "./pluralization/types";
17+
import type { LocaleCode } from "lingo.dev/spec";
1918

2019
/**
2120
* Configuration for translation service
@@ -24,7 +23,8 @@ export interface TranslationServiceConfig {
2423
/**
2524
* Source locale (e.g., "en")
2625
*/
27-
sourceLocale: string;
26+
// TODO (AleksandrSl 05/12/2025): Sort out these fields, they should most likely pick from the global config
27+
sourceLocale: LocaleCode;
2828

2929
/**
3030
* Whether the translator is a pseudo translator
@@ -36,7 +36,7 @@ export interface TranslationServiceConfig {
3636
* Pluralization configuration
3737
* If provided, enables automatic pluralization of source messages
3838
*/
39-
pluralization?: PluralizationConfig;
39+
pluralization?: Omit<PartialPluralizationConfig, "sourceLocale">;
4040
}
4141

4242
/**
@@ -79,12 +79,12 @@ export interface TranslationError {
7979
export class TranslationService {
8080
private useCache = true;
8181
private pluralizationProcessed = false;
82-
private logger = getLogger("translation-server");
8382

8483
constructor(
8584
private translator: Translator<any>,
8685
private cache: TranslationCache,
8786
private config: TranslationServiceConfig,
87+
private logger: Logger,
8888
) {
8989
this.useCache = !this.config.isPseudo;
9090
}
@@ -116,7 +116,11 @@ export class TranslationService {
116116
);
117117
const pluralStats = await processPluralization(
118118
metadata,
119-
this.config.pluralization || { enabled: true },
119+
{
120+
...this.config.pluralization,
121+
sourceLocale: this.config.sourceLocale,
122+
},
123+
this.logger,
120124
);
121125
this.logger.info(
122126
`Pluralization stats: ${pluralStats.pluralized} pluralized, ${pluralStats.rejected} rejected, ${pluralStats.failed} failed`,

0 commit comments

Comments
 (0)