@focus-reactive/payload-plugin-translator 0.10.4 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +199 -11
- package/dist/client/widgets/bulk-translation-dashboard/ui/BulkTranslationDashboard.server.js +2 -2
- package/dist/client/widgets/translate-document/ui/TranslateDocument.server.js +2 -2
- package/dist/client/widgets/translate-field-control/ui/TranslateFieldControl.js +10 -7
- package/dist/core/translation-pipeline/stages/field-collector/FieldChunkCollector.js +0 -5
- package/dist/index.d.ts +8 -3
- package/dist/index.js +4 -3
- package/dist/server/features/translate-document/handler.d.ts +1 -0
- package/dist/server/features/translate-document/handler.js +55 -46
- package/dist/server/features/translate-document/targetLayer.d.ts +37 -0
- package/dist/server/features/translate-document/targetLayer.js +26 -0
- package/dist/server/features/translate-field/handler.js +4 -10
- package/dist/server/modules/auto-translate/AutoTranslateEnqueue.hook.js +2 -1
- package/dist/server/shared/guards/index.d.ts +0 -1
- package/dist/server/shared/guards/index.js +0 -1
- package/dist/server/shared/payload/sourceDocument.d.ts +2 -4
- package/dist/server/shared/payload/sourceDocument.js +10 -5
- package/dist/translation-providers/index.d.ts +1 -0
- package/dist/translation-providers/index.js +1 -7
- package/dist/translation-providers/openai/OpenAI.shapes.d.ts +52 -0
- package/dist/translation-providers/openai/OpenAI.shapes.js +13 -0
- package/dist/translation-providers/openai/OpenAITranslation.provider.d.ts +51 -112
- package/dist/translation-providers/openai/OpenAITranslation.provider.js +49 -137
- package/dist/translation-providers/openai/OpenAITranslationLegacy.provider.d.ts +11 -0
- package/dist/translation-providers/openai/OpenAITranslationLegacy.provider.js +15 -0
- package/dist/translation-providers/openai/index.d.ts +6 -1
- package/dist/translation-providers/openai/index.js +3 -3
- package/dist/translation-providers/openai/loadOpenAIClient.d.ts +24 -0
- package/dist/translation-providers/openai/loadOpenAIClient.js +79 -0
- package/dist/translation-providers/openai/openAIComplete.d.ts +39 -0
- package/dist/translation-providers/openai/openAIComplete.js +84 -0
- package/dist/translation-providers/shared/CompletionProvider.provider.d.ts +65 -0
- package/dist/translation-providers/shared/CompletionProvider.provider.js +93 -0
- package/dist/translation-providers/shared/buildResponseSchema.d.ts +13 -0
- package/dist/translation-providers/shared/buildResponseSchema.js +22 -0
- package/dist/translation-providers/shared/buildSystemPrompt.d.ts +28 -0
- package/dist/translation-providers/shared/buildSystemPrompt.js +25 -0
- package/dist/translation-providers/shared/errors/KeySetMismatchError.d.ts +15 -0
- package/dist/translation-providers/shared/errors/KeySetMismatchError.js +26 -0
- package/dist/translation-providers/shared/errors/NoContentError.d.ts +9 -0
- package/dist/translation-providers/shared/errors/NoContentError.js +10 -0
- package/dist/translation-providers/shared/errors/ProviderConfigurationError.d.ts +10 -0
- package/dist/translation-providers/shared/errors/ProviderConfigurationError.js +11 -0
- package/dist/translation-providers/shared/errors/TranslationProviderError.d.ts +18 -0
- package/dist/translation-providers/shared/errors/TranslationProviderError.js +21 -0
- package/dist/translation-providers/shared/errors/TransportError.d.ts +10 -0
- package/dist/translation-providers/shared/errors/TransportError.js +11 -0
- package/dist/translation-providers/shared/errors/UnparseableReplyError.d.ts +9 -0
- package/dist/translation-providers/shared/errors/UnparseableReplyError.js +10 -0
- package/dist/translation-providers/shared/errors/errorMessageLower.d.ts +1 -0
- package/dist/translation-providers/shared/errors/errorMessageLower.js +8 -0
- package/dist/translation-providers/shared/errors/index.d.ts +9 -0
- package/dist/translation-providers/shared/errors/index.js +10 -0
- package/dist/translation-providers/shared/errors/wrapTransportError.d.ts +7 -0
- package/dist/translation-providers/shared/errors/wrapTransportError.js +14 -0
- package/dist/translation-providers/shared/index.d.ts +8 -0
- package/dist/translation-providers/shared/index.js +5 -0
- package/dist/translation-providers/shared/parseAndValidateReply.d.ts +13 -0
- package/dist/translation-providers/shared/parseAndValidateReply.js +46 -0
- package/dist/translation-providers/shared/runDryRun.d.ts +20 -0
- package/dist/translation-providers/shared/runDryRun.js +17 -0
- package/package.json +1 -1
- package/dist/server/shared/guards/collection-guards.d.ts +0 -6
- package/dist/server/shared/guards/collection-guards.js +0 -16
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { TranslationProviderError } from "./TranslationProviderError";
|
|
2
|
+
export { NoContentError } from "./NoContentError";
|
|
3
|
+
export { UnparseableReplyError } from "./UnparseableReplyError";
|
|
4
|
+
export { KeySetMismatchError } from "./KeySetMismatchError";
|
|
5
|
+
export { TransportError } from "./TransportError";
|
|
6
|
+
export { ProviderConfigurationError } from "./ProviderConfigurationError";
|
|
7
|
+
export { wrapTransportError } from "./wrapTransportError";
|
|
8
|
+
export { errorMessageLower } from "./errorMessageLower";
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { TranslationProviderError } from "./TranslationProviderError";
|
|
2
|
+
/**
|
|
3
|
+
* Turns anything a transport threw into a {@link TransportError}, keeping the original on `cause`.
|
|
4
|
+
* A value that is already one of ours passes through: re-wrapping would bury a specific cause under
|
|
5
|
+
* a generic transport failure.
|
|
6
|
+
*/
|
|
7
|
+
export declare function wrapTransportError(cause: unknown): TranslationProviderError;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { TransportError } from "./TransportError";
|
|
2
|
+
import { TranslationProviderError } from "./TranslationProviderError";
|
|
3
|
+
/**
|
|
4
|
+
* Turns anything a transport threw into a {@link TransportError}, keeping the original on `cause`.
|
|
5
|
+
* A value that is already one of ours passes through: re-wrapping would bury a specific cause under
|
|
6
|
+
* a generic transport failure.
|
|
7
|
+
*/ export function wrapTransportError(cause) {
|
|
8
|
+
if (cause instanceof TranslationProviderError) return cause;
|
|
9
|
+
return new TransportError("The translation request failed before a reply could be read. The provider's own error is on this error's `cause` property.", {
|
|
10
|
+
cause
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=wrapTransportError.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { createTranslationProvider } from "./CompletionProvider.provider";
|
|
2
|
+
export type { CompletionFn, CompletionRequest, TranslationProviderConfig, } from "./CompletionProvider.provider";
|
|
3
|
+
export type { JsonSchemaObject } from "./buildResponseSchema";
|
|
4
|
+
export type { SystemPromptBuilder, SystemPromptContext } from "./buildSystemPrompt";
|
|
5
|
+
export type { DryRunConfig, DryRunTransformer } from "./runDryRun";
|
|
6
|
+
export { errorMessageLower } from "./errors";
|
|
7
|
+
export { TranslationProviderError, NoContentError, UnparseableReplyError, KeySetMismatchError, TransportError, ProviderConfigurationError, } from "./errors";
|
|
8
|
+
export type { TranslationFailureCode } from "./errors";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { createTranslationProvider } from "./CompletionProvider.provider";
|
|
2
|
+
export { errorMessageLower } from "./errors";
|
|
3
|
+
export { TranslationProviderError, NoContentError, UnparseableReplyError, KeySetMismatchError, TransportError, ProviderConfigurationError } from "./errors";
|
|
4
|
+
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { TranslationInput, TranslationOutput } from "../../core/domain/translation-providers";
|
|
2
|
+
export type ParsedReply = {
|
|
3
|
+
translations: TranslationOutput;
|
|
4
|
+
missingInputKeys: number[];
|
|
5
|
+
unrequestedReplyKeys: string[];
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Parses an untrusted reply into a {@link TranslationOutput} and reports the key-set gap.
|
|
9
|
+
*
|
|
10
|
+
* A partial answer is applied, not rejected — the gap is returned so the caller can report it. Only
|
|
11
|
+
* a reply that answers nothing is a failure ({@link KeySetMismatchError}).
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseAndValidateReply(input: TranslationInput, raw: string): ParsedReply;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { isObject } from "../../core/kernel/utils/isObject";
|
|
2
|
+
import { KeySetMismatchError, UnparseableReplyError } from "./errors";
|
|
3
|
+
/**
|
|
4
|
+
* Parses an untrusted reply into a {@link TranslationOutput} and reports the key-set gap.
|
|
5
|
+
*
|
|
6
|
+
* A partial answer is applied, not rejected — the gap is returned so the caller can report it. Only
|
|
7
|
+
* a reply that answers nothing is a failure ({@link KeySetMismatchError}).
|
|
8
|
+
*/ export function parseAndValidateReply(input, raw) {
|
|
9
|
+
let parsed;
|
|
10
|
+
try {
|
|
11
|
+
parsed = JSON.parse(raw);
|
|
12
|
+
} catch (cause) {
|
|
13
|
+
throw new UnparseableReplyError("The provider's reply was not valid JSON.", {
|
|
14
|
+
cause
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
// `isObject` admits arrays: `["a"]` has key "0", so a 0-based input would accept it by coincidence.
|
|
18
|
+
if (!isObject(parsed) || Array.isArray(parsed)) {
|
|
19
|
+
throw new UnparseableReplyError("The provider's reply was JSON, but not an object.");
|
|
20
|
+
}
|
|
21
|
+
const expectedKeys = new Set(Object.keys(input));
|
|
22
|
+
const translations = {};
|
|
23
|
+
const missingInputKeys = [];
|
|
24
|
+
for (const key of expectedKeys){
|
|
25
|
+
const value = parsed[key];
|
|
26
|
+
if (typeof value === "string") {
|
|
27
|
+
translations[Number(key)] = value;
|
|
28
|
+
} else {
|
|
29
|
+
missingInputKeys.push(Number(key));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const unrequestedReplyKeys = Object.keys(parsed).filter((key)=>!expectedKeys.has(key));
|
|
33
|
+
if (expectedKeys.size > 0 && Object.keys(translations).length === 0) {
|
|
34
|
+
const answeredAnyKey = [
|
|
35
|
+
...expectedKeys
|
|
36
|
+
].some((key)=>Object.hasOwn(parsed, key));
|
|
37
|
+
throw new KeySetMismatchError(answeredAnyKey ? `The provider's reply carried the requested keys, but none of the ${expectedKeys.size} values was a string.` : `The provider's reply answered none of the ${expectedKeys.size} requested keys.`, missingInputKeys, unrequestedReplyKeys);
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
translations,
|
|
41
|
+
missingInputKeys,
|
|
42
|
+
unrequestedReplyKeys
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=parseAndValidateReply.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { TranslationInput, TranslationOutput } from "../../core/domain/translation-providers";
|
|
2
|
+
export type DryRunTransformer = (text: string) => string | Promise<string>;
|
|
3
|
+
/**
|
|
4
|
+
* Dry-run configuration: a transformer, and optionally a delay that imitates network latency.
|
|
5
|
+
*
|
|
6
|
+
* @deprecated Supply your own fake `complete` instead. Remove in next major.
|
|
7
|
+
* See docs/DEPRECATIONS.md#provider-dry-run
|
|
8
|
+
*/
|
|
9
|
+
export type DryRunConfig = {
|
|
10
|
+
/** Applied to every non-blank value. */
|
|
11
|
+
transform: DryRunTransformer;
|
|
12
|
+
/** Milliseconds to wait before returning. */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Simulates a translation without calling anything. Blank values pass through untouched.
|
|
17
|
+
*
|
|
18
|
+
* Logs the field count and never field content: the log reaches shared infrastructure.
|
|
19
|
+
*/
|
|
20
|
+
export declare function runDryRun(input: TranslationInput, config: boolean | DryRunConfig): Promise<TranslationOutput>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const reverse = (text)=>text.split("").reverse().join("");
|
|
2
|
+
/**
|
|
3
|
+
* Simulates a translation without calling anything. Blank values pass through untouched.
|
|
4
|
+
*
|
|
5
|
+
* Logs the field count and never field content: the log reaches shared infrastructure.
|
|
6
|
+
*/ export async function runDryRun(input, config) {
|
|
7
|
+
console.info(`[payload-plugin-translator] Dry run: simulated ${Object.keys(input).length} field(s), no API call made.`);
|
|
8
|
+
const { transform = reverse, timeout = 0 } = typeof config === "object" ? config : {};
|
|
9
|
+
if (timeout > 0) await new Promise((resolve)=>setTimeout(resolve, timeout));
|
|
10
|
+
const output = {};
|
|
11
|
+
for (const [key, value] of Object.entries(input)){
|
|
12
|
+
output[Number(key)] = value.trim() ? await transform(value) : value;
|
|
13
|
+
}
|
|
14
|
+
return output;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=runDryRun.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@focus-reactive/payload-plugin-translator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Translation plugin for Payload CMS 3.x. Automatically translate your localized content using any translation provider.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { CollectionConfig, SanitizedCollectionConfig } from "payload";
|
|
2
|
-
/**
|
|
3
|
-
* Checks if a collection has drafts enabled.
|
|
4
|
-
* Handles both CollectionConfig and SanitizedCollectionConfig.
|
|
5
|
-
*/
|
|
6
|
-
export declare function collectionHasDrafts(collection: CollectionConfig | SanitizedCollectionConfig): boolean;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type guard: Checks if versions config is an object (not boolean).
|
|
3
|
-
*/ function isVersionsObject(versions) {
|
|
4
|
-
return typeof versions === "object" && versions !== null;
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Checks if a collection has drafts enabled.
|
|
8
|
-
* Handles both CollectionConfig and SanitizedCollectionConfig.
|
|
9
|
-
*/ export function collectionHasDrafts(collection) {
|
|
10
|
-
const { versions } = collection;
|
|
11
|
-
if (!versions) return false;
|
|
12
|
-
if (!isVersionsObject(versions)) return false;
|
|
13
|
-
return "drafts" in versions && Boolean(versions.drafts);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
//# sourceMappingURL=collection-guards.js.map
|