@focus-reactive/payload-plugin-translator 0.8.2 → 0.9.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 +37 -0
- package/dist/auto-translate-config.d.ts +40 -0
- package/dist/auto-translate-config.js +46 -0
- package/dist/client/entities/translation/index.d.ts +1 -0
- package/dist/client/entities/translation/index.js +1 -0
- package/dist/client/entities/translation/model/autoTranslateSummary.d.ts +15 -0
- package/dist/client/entities/translation/model/autoTranslateSummary.js +22 -0
- package/dist/client/entities/translation/ui/AutoTranslateMarker/AutoTranslateMarker.d.ts +14 -0
- package/dist/client/entities/translation/ui/AutoTranslateMarker/AutoTranslateMarker.js +34 -0
- package/dist/client/entities/translation/ui/AutoTranslateMarker/index.d.ts +1 -0
- package/dist/client/entities/translation/ui/AutoTranslateMarker/index.js +3 -0
- package/dist/client/entities/translation/ui/AutoTranslateMarker/styles.module.scss +30 -0
- package/dist/client/shared/lib/assets/icons/AutoTranslateIcon.d.ts +3 -0
- package/dist/client/shared/lib/assets/icons/AutoTranslateIcon.js +14 -0
- package/dist/client/widgets/bulk-translation-dashboard/ui/BulkTranslationDashboard.d.ts +3 -1
- package/dist/client/widgets/bulk-translation-dashboard/ui/BulkTranslationDashboard.js +14 -5
- package/dist/client/widgets/bulk-translation-dashboard/ui/BulkTranslationDashboard.server.js +4 -1
- package/dist/client/widgets/bulk-translation-dashboard/ui/styles.module.scss +9 -0
- package/dist/client/widgets/translate-document/ui/TranslateDocument.d.ts +3 -1
- package/dist/client/widgets/translate-document/ui/TranslateDocument.js +14 -5
- package/dist/client/widgets/translate-document/ui/TranslateDocument.server.js +4 -1
- package/dist/client/widgets/translate-document/ui/styles.module.scss +9 -0
- package/dist/core/domain/auto-translate/getAutoTranslateConfig.d.ts +14 -0
- package/dist/core/domain/auto-translate/getAutoTranslateConfig.js +29 -0
- package/dist/core/domain/auto-translate/hasSourceContentChanged.d.ts +21 -0
- package/dist/core/domain/auto-translate/hasSourceContentChanged.js +25 -0
- package/dist/core/domain/auto-translate/index.d.ts +4 -0
- package/dist/core/domain/auto-translate/index.js +5 -0
- package/dist/core/domain/auto-translate/types.d.ts +32 -0
- package/dist/core/domain/auto-translate/types.js +7 -0
- package/dist/core/{content-projection → domain/content-projection}/computeSourceFingerprint.d.ts +1 -1
- package/dist/core/{content-projection → domain/content-projection}/contentProjector.d.ts +1 -1
- package/dist/core/{content-projection → domain/content-projection}/contentProjector.js +2 -2
- package/dist/core/{content-projection → domain/content-projection}/translatableLeaf.d.ts +1 -1
- package/dist/core/{content-projection → domain/content-projection}/translatableLeaf.js +2 -2
- package/dist/core/index.d.ts +10 -10
- package/dist/core/index.js +5 -5
- package/dist/core/translation-pipeline/TranslationPipeline.d.ts +1 -1
- package/dist/core/translation-pipeline/stages/data-reconciler/DataReconciler.d.ts +1 -1
- package/dist/core/translation-pipeline/stages/data-reconciler/DataReconciler.js +3 -3
- package/dist/core/translation-pipeline/stages/field-collector/FieldChunkCollector.d.ts +1 -1
- package/dist/core/translation-pipeline/stages/field-collector/FieldChunkCollector.js +3 -3
- package/dist/core/translation-pipeline/stages/text-expander/RichTextExpander.js +1 -1
- package/dist/core/translation-pipeline/stages/translation/Translation.stage.d.ts +1 -1
- package/dist/core/translation-pipeline/strategies/Overwrite.strategy.js +1 -1
- package/dist/core/translation-pipeline/strategies/SkipExisting.strategy.js +3 -3
- package/dist/core/translation-pipeline/translateContent.d.ts +2 -2
- package/dist/core/translation-pipeline/types/FieldChunk.d.ts +1 -1
- package/dist/core/translation-pipeline/types/Pipeline.d.ts +1 -1
- package/dist/core/translation-pipeline/types/PipelineContext.d.ts +1 -1
- package/dist/core/translation-pipeline/types/TextChunk.d.ts +1 -1
- package/dist/field-config.d.ts +1 -1
- package/dist/field-config.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/plugin.d.ts +1 -1
- package/dist/plugin.js +5 -0
- package/dist/server/features/translate-document/handler.d.ts +1 -1
- package/dist/server/features/translate-document/handler.js +9 -1
- package/dist/server/features/translate-document/wireTranslateRunner.d.ts +1 -1
- package/dist/server/features/translate-field/model.d.ts +1 -1
- package/dist/server/features/translate-field/resolveFieldSubtree.js +1 -1
- package/dist/server/modules/auto-translate/AutoTranslate.policy.d.ts +79 -0
- package/dist/server/modules/auto-translate/AutoTranslate.policy.js +77 -0
- package/dist/server/modules/auto-translate/AutoTranslate.shapes.d.ts +22 -0
- package/dist/server/modules/auto-translate/AutoTranslate.shapes.js +3 -0
- package/dist/server/modules/auto-translate/AutoTranslate.wiring.d.ts +21 -0
- package/dist/server/modules/auto-translate/AutoTranslate.wiring.js +68 -0
- package/dist/server/modules/auto-translate/AutoTranslateEnqueue.hook.d.ts +39 -0
- package/dist/server/modules/auto-translate/AutoTranslateEnqueue.hook.js +94 -0
- package/dist/server/modules/auto-translate/index.d.ts +4 -0
- package/dist/server/modules/auto-translate/index.js +7 -0
- package/dist/server/modules/index.d.ts +1 -1
- package/dist/server/modules/index.js +1 -1
- package/dist/server/modules/provenance/Provenance.service.d.ts +1 -1
- package/dist/server/modules/provenance/Provenance.service.js +2 -2
- package/dist/server/modules/provenance/Provenance.store.d.ts +1 -1
- package/dist/server/modules/provenance/index.js +1 -1
- package/dist/server/modules/task-runner/payload-jobs-runner/PayloadJobsTaskRunner.js +4 -0
- package/dist/server/modules/task-runner/types.d.ts +7 -0
- package/dist/server/modules/translation-levels/PluginConfigBuilder.d.ts +1 -1
- package/dist/server/modules/translation-levels/types.d.ts +1 -1
- package/dist/server/shared/index.d.ts +5 -5
- package/dist/server/shared/index.js +3 -3
- package/dist/server/shared/utils/filterLocalizedFields.js +2 -2
- package/dist/server/shared/utils/getByPath.js +1 -1
- package/dist/server/shared/utils/index.d.ts +2 -2
- package/dist/server/shared/utils/index.js +2 -2
- package/dist/server/shared/utils/setByPath.js +1 -1
- package/dist/translation-providers/index.d.ts +1 -1
- package/dist/translation-providers/openai/OpenAITranslation.provider.d.ts +1 -1
- package/dist/translation-providers/openai/OpenAITranslation.provider.js +1 -1
- package/dist/types/AutoTranslateContext.d.ts +10 -0
- package/dist/types/AutoTranslateContext.js +11 -0
- package/package.json +1 -1
- /package/dist/core/{content-projection → domain/content-projection}/computeSourceFingerprint.js +0 -0
- /package/dist/core/{content-projection → domain/content-projection}/fingerprinter.d.ts +0 -0
- /package/dist/core/{content-projection → domain/content-projection}/fingerprinter.js +0 -0
- /package/dist/core/{content-projection → domain/content-projection}/idPath.d.ts +0 -0
- /package/dist/core/{content-projection → domain/content-projection}/idPath.js +0 -0
- /package/dist/core/{field-config → domain/field-config}/getFieldConfig.d.ts +0 -0
- /package/dist/core/{field-config → domain/field-config}/getFieldConfig.js +0 -0
- /package/dist/core/{field-config → domain/field-config}/index.d.ts +0 -0
- /package/dist/core/{field-config → domain/field-config}/index.js +0 -0
- /package/dist/core/{field-config → domain/field-config}/types.d.ts +0 -0
- /package/dist/core/{field-config → domain/field-config}/types.js +0 -0
- /package/dist/core/{provenance → domain/provenance}/ProvenanceStore.interface.d.ts +0 -0
- /package/dist/core/{provenance → domain/provenance}/ProvenanceStore.interface.js +0 -0
- /package/dist/core/{provenance → domain/provenance}/index.d.ts +0 -0
- /package/dist/core/{provenance → domain/provenance}/index.js +0 -0
- /package/dist/core/{provenance → domain/provenance}/staleness.d.ts +0 -0
- /package/dist/core/{provenance → domain/provenance}/staleness.js +0 -0
- /package/dist/core/{translation-providers → domain/translation-providers}/TranslationProvider.interface.d.ts +0 -0
- /package/dist/core/{translation-providers → domain/translation-providers}/TranslationProvider.interface.js +0 -0
- /package/dist/core/{translation-providers → domain/translation-providers}/index.d.ts +0 -0
- /package/dist/core/{translation-providers → domain/translation-providers}/index.js +0 -0
- /package/dist/core/{field-traversal → kernel/field-traversal}/findFieldByPath.d.ts +0 -0
- /package/dist/core/{field-traversal → kernel/field-traversal}/findFieldByPath.js +0 -0
- /package/dist/core/{field-traversal → kernel/field-traversal}/guards.d.ts +0 -0
- /package/dist/core/{field-traversal → kernel/field-traversal}/guards.js +0 -0
- /package/dist/core/{field-traversal → kernel/field-traversal}/index.d.ts +0 -0
- /package/dist/core/{field-traversal → kernel/field-traversal}/index.js +0 -0
- /package/dist/core/{field-traversal → kernel/field-traversal}/kernel.d.ts +0 -0
- /package/dist/core/{field-traversal → kernel/field-traversal}/kernel.js +0 -0
- /package/dist/core/{field-traversal → kernel/field-traversal}/predicates.d.ts +0 -0
- /package/dist/core/{field-traversal → kernel/field-traversal}/predicates.js +0 -0
- /package/dist/core/{field-traversal → kernel/field-traversal}/types.d.ts +0 -0
- /package/dist/core/{field-traversal → kernel/field-traversal}/types.js +0 -0
- /package/dist/core/{field-traversal → kernel/field-traversal}/walkFields.d.ts +0 -0
- /package/dist/core/{field-traversal → kernel/field-traversal}/walkFields.js +0 -0
- /package/dist/core/{lexical → kernel/lexical}/collectTextNodes.d.ts +0 -0
- /package/dist/core/{lexical → kernel/lexical}/collectTextNodes.js +0 -0
- /package/dist/core/{lexical → kernel/lexical}/guards.d.ts +0 -0
- /package/dist/core/{lexical → kernel/lexical}/guards.js +0 -0
- /package/dist/core/{lexical → kernel/lexical}/index.d.ts +0 -0
- /package/dist/core/{lexical → kernel/lexical}/index.js +0 -0
- /package/dist/core/{lexical → kernel/lexical}/isEmptyRichText.d.ts +0 -0
- /package/dist/core/{lexical → kernel/lexical}/isEmptyRichText.js +0 -0
- /package/dist/core/{lexical → kernel/lexical}/traverseLexicalTree.d.ts +0 -0
- /package/dist/core/{lexical → kernel/lexical}/traverseLexicalTree.js +0 -0
- /package/dist/core/{lexical → kernel/lexical}/types.d.ts +0 -0
- /package/dist/core/{lexical → kernel/lexical}/types.js +0 -0
- /package/dist/core/{utils → kernel/utils}/index.d.ts +0 -0
- /package/dist/core/{utils → kernel/utils}/index.js +0 -0
- /package/dist/core/{utils → kernel/utils}/isEmpty.d.ts +0 -0
- /package/dist/core/{utils → kernel/utils}/isEmpty.js +0 -0
- /package/dist/core/{utils → kernel/utils}/isObject.d.ts +0 -0
- /package/dist/core/{utils → kernel/utils}/isObject.js +0 -0
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* translation can never disagree on which content is translatable. Payload-free and read-only:
|
|
10
10
|
* it never mutates the document and never captures write handles.
|
|
11
11
|
*/
|
|
12
|
-
import type { FieldLike } from "
|
|
12
|
+
import type { FieldLike } from "../../kernel/field-traversal/types";
|
|
13
13
|
import type { IdPath } from "./idPath";
|
|
14
14
|
/** One translatable leaf of a document: WHERE it lives ({@link IdPath}) and WHAT text it holds. */
|
|
15
15
|
export interface ProjectionEntry {
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* {@link leafSourceText}) as the translation pipeline's `FieldChunkCollector`, so projection and
|
|
9
9
|
* translation can never disagree on which content is translatable. Payload-free and read-only:
|
|
10
10
|
* it never mutates the document and never captures write handles.
|
|
11
|
-
*/ import { resolveBlockFields, walkFields } from "
|
|
12
|
-
import { isObject } from "
|
|
11
|
+
*/ import { resolveBlockFields, walkFields } from "../../kernel/field-traversal";
|
|
12
|
+
import { isObject } from "../../kernel/utils/isObject";
|
|
13
13
|
import { elementSegment, makeIdPath } from "./idPath";
|
|
14
14
|
import { isTranslatableLeaf, leafSourceText } from "./translatableLeaf";
|
|
15
15
|
/**
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Payload-free (structural {@link FieldLike} + owned `Serialized*` views only) so it can move to
|
|
8
8
|
* `@repo/translator-core` unchanged.
|
|
9
9
|
*/
|
|
10
|
-
import type { FieldLike, LeafFieldLike } from "
|
|
10
|
+
import type { FieldLike, LeafFieldLike } from "../../kernel/field-traversal/types";
|
|
11
11
|
/**
|
|
12
12
|
* The leaf-SELECTION decision shared by projection and translation: a leaf is a translation target
|
|
13
13
|
* iff it is a translatable text type, localized, and not excluded via `custom.translateKit`.
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* Payload-free (structural {@link FieldLike} + owned `Serialized*` views only) so it can move to
|
|
8
8
|
* `@repo/translator-core` unchanged.
|
|
9
9
|
*/ import { isFieldExcludedFromTranslation } from "../field-config";
|
|
10
|
-
import { collectSerializedLexicalTextNodes } from "
|
|
11
|
-
import { isSerializedLexicalRoot } from "
|
|
10
|
+
import { collectSerializedLexicalTextNodes } from "../../kernel/lexical/collectTextNodes";
|
|
11
|
+
import { isSerializedLexicalRoot } from "../../kernel/lexical/guards";
|
|
12
12
|
/** The field types this package translates (mirrors `isTranslatableField`, payload-free). */ const isTranslatableFieldType = (field)=>field.type === "text" || field.type === "textarea" || field.type === "richText";
|
|
13
13
|
/** Mirrors `isLocalizedField` structurally. */ const isLocalizedFieldLike = (field)=>field.localized === true;
|
|
14
14
|
/**
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export type { TranslationProvider, TranslationInput, TranslationOutput, TranslationIndex, } from "./translation-providers";
|
|
1
|
+
export type { TranslationProvider, TranslationInput, TranslationOutput, TranslationIndex, } from "./domain/translation-providers";
|
|
2
2
|
export { TranslationPipeline, translateContent } from "./translation-pipeline";
|
|
3
3
|
export type { TranslateContentArgs, TranslationStrategy } from "./translation-pipeline";
|
|
4
|
-
export type { ProvenanceKey, ProvenanceStore, TranslationProvenanceRecord } from "./provenance";
|
|
5
|
-
export { projectTranslatableContent } from "./content-projection/contentProjector";
|
|
6
|
-
export type { ProjectionEntry } from "./content-projection/contentProjector";
|
|
7
|
-
export { fingerprint } from "./content-projection/fingerprinter";
|
|
8
|
-
export { computeSourceFingerprint } from "./content-projection/computeSourceFingerprint";
|
|
9
|
-
export { makeIdPath } from "./content-projection/idPath";
|
|
10
|
-
export type { IdPath, PathSegment } from "./content-projection/idPath";
|
|
11
|
-
export { classifyField, findFieldByPath, hasFields, isBlockItem, isTabsField, matchElementById, resolveBlockFields, tabScopes, walkFields, } from "./field-traversal";
|
|
12
|
-
export type { ArrayFieldLike, BlockLike, BlocksFieldLike, FieldLike, FieldStructure, FieldWalker, GroupFieldLike, LeafField, LeafFieldLike, TabLike, TabScope, TabsFieldLike, } from "./field-traversal";
|
|
4
|
+
export type { ProvenanceKey, ProvenanceStore, TranslationProvenanceRecord, } from "./domain/provenance";
|
|
5
|
+
export { projectTranslatableContent } from "./domain/content-projection/contentProjector";
|
|
6
|
+
export type { ProjectionEntry } from "./domain/content-projection/contentProjector";
|
|
7
|
+
export { fingerprint } from "./domain/content-projection/fingerprinter";
|
|
8
|
+
export { computeSourceFingerprint } from "./domain/content-projection/computeSourceFingerprint";
|
|
9
|
+
export { makeIdPath } from "./domain/content-projection/idPath";
|
|
10
|
+
export type { IdPath, PathSegment } from "./domain/content-projection/idPath";
|
|
11
|
+
export { classifyField, findFieldByPath, hasFields, isBlockItem, isTabsField, matchElementById, resolveBlockFields, tabScopes, walkFields, } from "./kernel/field-traversal";
|
|
12
|
+
export type { ArrayFieldLike, BlockLike, BlocksFieldLike, FieldLike, FieldStructure, FieldWalker, GroupFieldLike, LeafField, LeafFieldLike, TabLike, TabScope, TabsFieldLike, } from "./kernel/field-traversal";
|
package/dist/core/index.js
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
// Translation pipeline
|
|
6
6
|
export { TranslationPipeline, translateContent } from "./translation-pipeline";
|
|
7
7
|
// Content projection
|
|
8
|
-
export { projectTranslatableContent } from "./content-projection/contentProjector";
|
|
9
|
-
export { fingerprint } from "./content-projection/fingerprinter";
|
|
10
|
-
export { computeSourceFingerprint } from "./content-projection/computeSourceFingerprint";
|
|
11
|
-
export { makeIdPath } from "./content-projection/idPath";
|
|
8
|
+
export { projectTranslatableContent } from "./domain/content-projection/contentProjector";
|
|
9
|
+
export { fingerprint } from "./domain/content-projection/fingerprinter";
|
|
10
|
+
export { computeSourceFingerprint } from "./domain/content-projection/computeSourceFingerprint";
|
|
11
|
+
export { makeIdPath } from "./domain/content-projection/idPath";
|
|
12
12
|
// Field traversal
|
|
13
|
-
export { classifyField, findFieldByPath, hasFields, isBlockItem, isTabsField, matchElementById, resolveBlockFields, tabScopes, walkFields } from "./field-traversal";
|
|
13
|
+
export { classifyField, findFieldByPath, hasFields, isBlockItem, isTabsField, matchElementById, resolveBlockFields, tabScopes, walkFields } from "./kernel/field-traversal";
|
|
14
14
|
|
|
15
15
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TranslationProvider } from "../translation-providers";
|
|
1
|
+
import type { TranslationProvider } from "../domain/translation-providers";
|
|
2
2
|
import type { PipelineConfig, PipelineResult } from "./types";
|
|
3
3
|
import type { TranslationStrategy } from "./strategies";
|
|
4
4
|
import type { TextExpander } from "./stages";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FieldLike } from "../../../field-traversal";
|
|
1
|
+
import type { FieldLike } from "../../../kernel/field-traversal";
|
|
2
2
|
/**
|
|
3
3
|
* Deep-merges source and target data with target priority, producing the full document shape
|
|
4
4
|
* Payload validation needs. Built on the shared {@link walkFields} engine.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { isEmpty } from "../../../utils/isEmpty";
|
|
2
|
-
import { isObject } from "../../../utils/isObject";
|
|
3
|
-
import { matchElementById, resolveBlockFields, walkFields } from "../../../field-traversal";
|
|
1
|
+
import { isEmpty } from "../../../kernel/utils/isEmpty";
|
|
2
|
+
import { isObject } from "../../../kernel/utils/isObject";
|
|
3
|
+
import { matchElementById, resolveBlockFields, walkFields } from "../../../kernel/field-traversal";
|
|
4
4
|
const asObject = (value)=>isObject(value) ? value : {};
|
|
5
5
|
/**
|
|
6
6
|
* Reconcile walker: produces the full document shape from source + target, with target
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { isTranslatableLeaf } from "../../../content-projection/translatableLeaf";
|
|
2
|
-
import { matchElementById, resolveBlockFields, walkFields } from "../../../field-traversal";
|
|
3
|
-
import { isObject } from "../../../utils/isObject";
|
|
1
|
+
import { isTranslatableLeaf } from "../../../domain/content-projection/translatableLeaf";
|
|
2
|
+
import { matchElementById, resolveBlockFields, walkFields } from "../../../kernel/field-traversal";
|
|
3
|
+
import { isObject } from "../../../kernel/utils/isObject";
|
|
4
4
|
const asObject = (value)=>isObject(value) ? value : {};
|
|
5
5
|
/**
|
|
6
6
|
* Collects FieldChunks by walking schema + data with the shared {@link walkFields} engine.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isSerializedLexicalRoot, collectSerializedLexicalTextNodes } from "../../../lexical";
|
|
1
|
+
import { isSerializedLexicalRoot, collectSerializedLexicalTextNodes } from "../../../kernel/lexical";
|
|
2
2
|
/**
|
|
3
3
|
* Expands richText fields into multiple RichTextChunks (one per text node).
|
|
4
4
|
*/ export class RichTextExpander {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PipelineContext, PipelineStage } from "../../types";
|
|
2
|
-
import type { TranslationProvider } from "../../../translation-providers";
|
|
2
|
+
import type { TranslationProvider } from "../../../domain/translation-providers";
|
|
3
3
|
/**
|
|
4
4
|
* Calls translation provider to translate text.
|
|
5
5
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { isEmptyRichText } from "../../lexical/isEmptyRichText";
|
|
2
|
-
import { isSerializedLexicalRoot } from "../../lexical/guards";
|
|
3
|
-
import { isEmpty } from "../../utils/isEmpty";
|
|
1
|
+
import { isEmptyRichText } from "../../kernel/lexical/isEmptyRichText";
|
|
2
|
+
import { isSerializedLexicalRoot } from "../../kernel/lexical/guards";
|
|
3
|
+
import { isEmpty } from "../../kernel/utils/isEmpty";
|
|
4
4
|
/**
|
|
5
5
|
* Only translates fields that are empty or missing in the target locale.
|
|
6
6
|
* Existing translations are preserved.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { FieldLike } from "../field-traversal";
|
|
2
|
-
import type { TranslationProvider } from "../translation-providers";
|
|
1
|
+
import type { FieldLike } from "../kernel/field-traversal";
|
|
2
|
+
import type { TranslationProvider } from "../domain/translation-providers";
|
|
3
3
|
import type { TranslationStrategyName } from "./strategies";
|
|
4
4
|
export type TranslateContentArgs = {
|
|
5
5
|
/** Schema subtree to translate (e.g. `[declaredFieldConfig]`). */
|
package/dist/field-config.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Field, RichTextField, TextareaField, TextField } from "payload";
|
|
2
|
-
import type { FieldTranslationConfig } from "./core/field-config";
|
|
2
|
+
import type { FieldTranslationConfig } from "./core/domain/field-config";
|
|
3
3
|
export type { FieldTranslationConfig };
|
|
4
4
|
/**
|
|
5
5
|
* Field types eligible for the per-field translate control — the same text-bearing
|
package/dist/field-config.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TRANSLATE_KIT_CUSTOM_KEY } from "./core/field-config";
|
|
1
|
+
import { TRANSLATE_KIT_CUSTOM_KEY } from "./core/domain/field-config";
|
|
2
2
|
import { TranslateFieldControlExport } from "./client/widgets/translate-field-control/ui/TranslateFieldControl.export";
|
|
3
3
|
import { beforeInputPositioner } from "./field-actions";
|
|
4
4
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export { documentLevel, collectionLevel, fieldLevel } from "./composition/levels
|
|
|
12
12
|
export type { TranslationLevel } from "./server/modules/translation-levels";
|
|
13
13
|
export { withFieldTranslation } from "./field-config";
|
|
14
14
|
export type { FieldTranslationConfig } from "./field-config";
|
|
15
|
+
export { withAutoTranslate } from "./auto-translate-config";
|
|
16
|
+
export type { AutoTranslateConfig, AutoTranslateStrategy } from "./auto-translate-config";
|
|
15
17
|
export { createTranslatePlugin, TranslateCollectionPlugin } from "./plugin";
|
|
16
18
|
export type { TranslateCollectionPluginConfig } from "./plugin";
|
|
17
19
|
export { OpenAITranslationProvider } from "./translation-providers";
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,10 @@ export { createPayloadJobsRunner, createSyncRunner } from "./server/modules/task
|
|
|
8
8
|
export { documentLevel, collectionLevel, fieldLevel } from "./composition/levels";
|
|
9
9
|
// Field config
|
|
10
10
|
export { withFieldTranslation } from "./field-config";
|
|
11
|
+
// Auto-translate — opt-in, per-collection auto-translation on source-locale change (#51). Wrap a
|
|
12
|
+
// collection with `withAutoTranslate`; requires a working job runner/autorun to execute (see the
|
|
13
|
+
// JSDoc for the Vercel/serverless caveat). Since v0.9.0.
|
|
14
|
+
export { withAutoTranslate } from "./auto-translate-config";
|
|
11
15
|
// Deprecated exports (for backwards compatibility)
|
|
12
16
|
export { createTranslatePlugin, TranslateCollectionPlugin } from "./plugin";
|
|
13
17
|
export { OpenAITranslationProvider } from "./translation-providers";
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CollectionConfig, Config } from "payload";
|
|
2
2
|
import type { AccessGuard } from "./types/AccessGuard";
|
|
3
|
-
import type { TranslationProvider } from "./core/translation-providers";
|
|
3
|
+
import type { TranslationProvider } from "./core/domain/translation-providers";
|
|
4
4
|
import type { TaskRunnerProvider } from "./server/modules/task-runner";
|
|
5
5
|
import type { TranslationLifecycleCallbacks } from "./server/modules/lifecycle";
|
|
6
6
|
import type { TranslationLevel } from "./server/modules/translation-levels";
|
package/dist/plugin.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CacheProviderExport } from "./client/app/cache/CacheProvider.export";
|
|
2
|
+
import { configureAutoTranslate } from "./server/modules/auto-translate";
|
|
2
3
|
import { configureProvenance } from "./server/modules/provenance";
|
|
3
4
|
import { wireTranslateRunner } from "./server/features/translate-document";
|
|
4
5
|
import { documentLevel, collectionLevel } from "./composition/levels";
|
|
@@ -36,6 +37,9 @@ import { normalizePath } from "./server/shared";
|
|
|
36
37
|
lifecycle: lifecycle ?? {},
|
|
37
38
|
collections: Array.from(collectionSlugs)
|
|
38
39
|
});
|
|
40
|
+
// Auto-translate (#51) reads its opt-in from each collection's `custom` (via `withAutoTranslate`);
|
|
41
|
+
// needs the runner's factory, so it wires after `wireTranslateRunner`.
|
|
42
|
+
const autoTranslateModule = configureAutoTranslate(collections, schemaMap, taskRunnerFactory);
|
|
39
43
|
const activeLevels = levels ?? [
|
|
40
44
|
documentLevel(),
|
|
41
45
|
collectionLevel()
|
|
@@ -52,6 +56,7 @@ import { normalizePath } from "./server/shared";
|
|
|
52
56
|
for (const level of activeLevels)level.extend(builder);
|
|
53
57
|
builder.addConfigModifier(runnerConfigModifier);
|
|
54
58
|
builder.addConfigModifier(provenanceModule.configure(collectionSlugs));
|
|
59
|
+
builder.addConfigModifier(autoTranslateModule.configure(collectionSlugs));
|
|
55
60
|
builder.addAdminProvider(new CacheProviderExport(basePath));
|
|
56
61
|
// The single place the Payload config is mutated.
|
|
57
62
|
return builder.applyTo(config);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Payload } from "payload";
|
|
2
2
|
import type { Handler } from "../../shared";
|
|
3
|
-
import type { TranslationProvider } from "../../../core/translation-providers";
|
|
3
|
+
import type { TranslationProvider } from "../../../core/domain/translation-providers";
|
|
4
4
|
import type { ProvenanceServiceFactory } from "../../modules/provenance";
|
|
5
5
|
import type { CollectionSchemaMap } from "../../../types/CollectionSchemaMap";
|
|
6
6
|
import type { TranslateDocumentInput, TranslateDocumentOutput } from "./model";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { APIError } from "payload";
|
|
2
2
|
import { translateContent } from "../../../core/translation-pipeline";
|
|
3
3
|
import { fetchSourceDocument } from "../../shared/payload/sourceDocument";
|
|
4
|
+
import { AUTO_TRANSLATE_SKIP_CONTEXT_KEY } from "../../../types/AutoTranslateContext";
|
|
4
5
|
/**
|
|
5
6
|
* Translates a single document from source language to target language. Provenance is delegated to
|
|
6
7
|
* {@link ProvenanceService}: this handler only decides *when* to capture the source fingerprint
|
|
@@ -73,7 +74,14 @@ import { fetchSourceDocument } from "../../shared/payload/sourceDocument";
|
|
|
73
74
|
data: translatedData,
|
|
74
75
|
autosave: isAutosaveEnabled,
|
|
75
76
|
locale: targetLng,
|
|
76
|
-
fallbackLocale: sourceLng
|
|
77
|
+
fallbackLocale: sourceLng,
|
|
78
|
+
// Mark this as a translator-authored write so the auto-translate afterChange hook (#51) skips it
|
|
79
|
+
// — the loop guard's second barrier, alongside the source-locale check. This write always targets
|
|
80
|
+
// the TARGET locale, so it is already exempt by locale; the flag also covers any future write
|
|
81
|
+
// path that could touch the source locale.
|
|
82
|
+
context: {
|
|
83
|
+
[AUTO_TRANSLATE_SKIP_CONTEXT_KEY]: true
|
|
84
|
+
}
|
|
77
85
|
});
|
|
78
86
|
}
|
|
79
87
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CollectionSlug } from "payload";
|
|
2
|
-
import type { TranslationProvider } from "../../../core/translation-providers";
|
|
2
|
+
import type { TranslationProvider } from "../../../core/domain/translation-providers";
|
|
3
3
|
import type { CollectionSchemaMap } from "../../../types/CollectionSchemaMap";
|
|
4
4
|
import type { ConfigModifier } from "../../../types/ConfigModifier";
|
|
5
5
|
import type { ProvenanceServiceFactory } from "../../modules/provenance";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { CollectionSchemaMap } from "../../../types/CollectionSchemaMap";
|
|
3
|
-
import type { TranslationProvider } from "../../../core/translation-providers";
|
|
3
|
+
import type { TranslationProvider } from "../../../core/domain/translation-providers";
|
|
4
4
|
/**
|
|
5
5
|
* Max serialized size of the value the endpoint will translate — the value read from the
|
|
6
6
|
* source-locale document (the request body no longer carries one; this is from-locale only). The
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isTranslatableField } from "../../shared";
|
|
2
|
-
import { findFieldByPath } from "../../../core/field-traversal";
|
|
2
|
+
import { findFieldByPath } from "../../../core/kernel/field-traversal";
|
|
3
3
|
/**
|
|
4
4
|
* Map a declared `fieldPath` to the `{ schema, sourceData }` pair `translateContent` expects.
|
|
5
5
|
* Walks the schema via the shared {@link findFieldByPath}. Descends transparently through
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { CollectionSlug } from "payload";
|
|
2
|
+
import type { AutoTranslateConfig } from "../../../core/domain/auto-translate";
|
|
3
|
+
import type { TaskInput } from "../task-runner/types";
|
|
4
|
+
/** A collection's auto-translate rule with defaults resolved — the shape the hook consumes. */
|
|
5
|
+
export type NormalizedAutoTranslatePolicy = {
|
|
6
|
+
targets: string[];
|
|
7
|
+
strategy: "overwrite" | "skip_existing";
|
|
8
|
+
debounceMs: number;
|
|
9
|
+
sourceLocale?: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Resolve the effective auto-translate policy for a document, or `null` when off. The `doc` parameter
|
|
13
|
+
* is the reserved seam for the future document-level manager override (#51 D7): v1 resolves at the
|
|
14
|
+
* collection level and IGNORES `doc`; a later phase supplies a second implementation that consults the
|
|
15
|
+
* document, without changing the hook, drift-gate, debounce, or wiring.
|
|
16
|
+
*/
|
|
17
|
+
export type AutoTranslatePolicyResolver = (collectionSlug: string, doc: Record<string, unknown>) => NormalizedAutoTranslatePolicy | null;
|
|
18
|
+
/** Apply defaults to a raw config: strategy → "overwrite", debounce → 0. Duplicate target locales are
|
|
19
|
+
* de-duplicated so a misconfigured `targets: ["de","de"]` never enqueues two racing jobs for the same
|
|
20
|
+
* (document, locale) in one batch (the runner's supersession only dedupes against already-stored jobs). */
|
|
21
|
+
export declare function normalizeAutoTranslateConfig(config: AutoTranslateConfig): NormalizedAutoTranslatePolicy;
|
|
22
|
+
/**
|
|
23
|
+
* A minimal localization shape — the set of configured locale codes, in either form Payload accepts
|
|
24
|
+
* (`"en"` or `{ code: "en" }`). Payload's `Config["localization"]` is structurally assignable, so the
|
|
25
|
+
* caller passes it straight in with no adapter and tests pass a tiny literal.
|
|
26
|
+
*/
|
|
27
|
+
export type LocalizationLike = false | {
|
|
28
|
+
locales: Array<string | {
|
|
29
|
+
code: string;
|
|
30
|
+
}>;
|
|
31
|
+
};
|
|
32
|
+
/** Extract the configured locale codes, or `null` when localization is disabled/absent. */
|
|
33
|
+
export declare function extractLocaleCodes(localization: LocalizationLike | undefined): Set<string> | null;
|
|
34
|
+
/** Outcome of validating a policy's locales against the configured set — the filtered policy plus what
|
|
35
|
+
* was dropped, so the caller can warn precisely. */
|
|
36
|
+
export type PolicyLocaleFilter = {
|
|
37
|
+
policy: NormalizedAutoTranslatePolicy;
|
|
38
|
+
droppedTargets: string[];
|
|
39
|
+
droppedSourceLocale: string | null;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Drop targets (and a `sourceLocale` override) that are not configured locales, so a mistyped locale in
|
|
43
|
+
* `withAutoTranslate` never reaches the pipeline — where it would silently burn a provider call and
|
|
44
|
+
* either error at the DB (Postgres locale enum) or write orphaned, invisible data (Mongo/SQLite). Pure:
|
|
45
|
+
* returns a new policy and reports the drops; the caller (config-time wiring) emits the warning.
|
|
46
|
+
*/
|
|
47
|
+
export declare function filterPolicyToKnownLocales(policy: NormalizedAutoTranslatePolicy, knownLocales: Set<string>): PolicyLocaleFilter;
|
|
48
|
+
/**
|
|
49
|
+
* The v1 (collection-level) resolver. Ignores `doc` — see {@link AutoTranslatePolicyResolver}. This is
|
|
50
|
+
* the single seam a future document-level manager replaces.
|
|
51
|
+
*/
|
|
52
|
+
export declare function makeCollectionPolicyResolver(policies: Map<string, NormalizedAutoTranslatePolicy>): AutoTranslatePolicyResolver;
|
|
53
|
+
/**
|
|
54
|
+
* Publish-gate (#51 D8): a drafts-enabled collection auto-translates only on a **published** save;
|
|
55
|
+
* autosave/draft saves are ignored. A collection without drafts has no `_status`, so every save
|
|
56
|
+
* qualifies. Applies uniformly to create and update.
|
|
57
|
+
*/
|
|
58
|
+
export declare function passesPublishGate(doc: Record<string, unknown>, hasDrafts: boolean): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Mirror the source document's status onto the translation (#51 D9). Combined with the publish-gate,
|
|
61
|
+
* the source is published whenever we reach enqueue, so translations publish; a no-drafts collection
|
|
62
|
+
* publishes too. Deliberately identical to {@link passesPublishGate} today — kept as a SEPARATE
|
|
63
|
+
* function (not merged) because it diverges once a future document-level manager (R8) can bypass the
|
|
64
|
+
* gate and translate a still-draft source; do not collapse the two.
|
|
65
|
+
*/
|
|
66
|
+
export declare function resolvePublishOnTranslation(doc: Record<string, unknown>, hasDrafts: boolean): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Build one {@link TaskInput} per configured target locale (the source locale is always excluded).
|
|
69
|
+
* `waitUntil` encodes the debounce; `now` is injected so the timestamp is deterministic in tests.
|
|
70
|
+
*/
|
|
71
|
+
export declare function buildAutoTranslateTasks(args: {
|
|
72
|
+
policy: NormalizedAutoTranslatePolicy;
|
|
73
|
+
collectionSlug: CollectionSlug;
|
|
74
|
+
documentId: string;
|
|
75
|
+
sourceLocale: string;
|
|
76
|
+
doc: Record<string, unknown>;
|
|
77
|
+
hasDrafts: boolean;
|
|
78
|
+
now: number;
|
|
79
|
+
}): TaskInput[];
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/** Apply defaults to a raw config: strategy → "overwrite", debounce → 0. Duplicate target locales are
|
|
2
|
+
* de-duplicated so a misconfigured `targets: ["de","de"]` never enqueues two racing jobs for the same
|
|
3
|
+
* (document, locale) in one batch (the runner's supersession only dedupes against already-stored jobs). */ export function normalizeAutoTranslateConfig(config) {
|
|
4
|
+
return {
|
|
5
|
+
targets: [
|
|
6
|
+
...new Set(config.targets)
|
|
7
|
+
],
|
|
8
|
+
strategy: config.strategy ?? "overwrite",
|
|
9
|
+
debounceMs: config.debounceMs ?? 0,
|
|
10
|
+
sourceLocale: config.sourceLocale
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/** Extract the configured locale codes, or `null` when localization is disabled/absent. */ export function extractLocaleCodes(localization) {
|
|
14
|
+
if (!localization) return null;
|
|
15
|
+
return new Set(localization.locales.map((locale)=>typeof locale === "string" ? locale : locale.code));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Drop targets (and a `sourceLocale` override) that are not configured locales, so a mistyped locale in
|
|
19
|
+
* `withAutoTranslate` never reaches the pipeline — where it would silently burn a provider call and
|
|
20
|
+
* either error at the DB (Postgres locale enum) or write orphaned, invisible data (Mongo/SQLite). Pure:
|
|
21
|
+
* returns a new policy and reports the drops; the caller (config-time wiring) emits the warning.
|
|
22
|
+
*/ export function filterPolicyToKnownLocales(policy, knownLocales) {
|
|
23
|
+
const droppedTargets = policy.targets.filter((target)=>!knownLocales.has(target));
|
|
24
|
+
const sourceUnknown = policy.sourceLocale !== undefined && !knownLocales.has(policy.sourceLocale);
|
|
25
|
+
return {
|
|
26
|
+
policy: {
|
|
27
|
+
...policy,
|
|
28
|
+
targets: policy.targets.filter((target)=>knownLocales.has(target)),
|
|
29
|
+
sourceLocale: sourceUnknown ? undefined : policy.sourceLocale
|
|
30
|
+
},
|
|
31
|
+
droppedTargets,
|
|
32
|
+
droppedSourceLocale: sourceUnknown ? policy.sourceLocale ?? null : null
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The v1 (collection-level) resolver. Ignores `doc` — see {@link AutoTranslatePolicyResolver}. This is
|
|
37
|
+
* the single seam a future document-level manager replaces.
|
|
38
|
+
*/ export function makeCollectionPolicyResolver(policies) {
|
|
39
|
+
return (collectionSlug, _doc)=>policies.get(collectionSlug) ?? null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Publish-gate (#51 D8): a drafts-enabled collection auto-translates only on a **published** save;
|
|
43
|
+
* autosave/draft saves are ignored. A collection without drafts has no `_status`, so every save
|
|
44
|
+
* qualifies. Applies uniformly to create and update.
|
|
45
|
+
*/ export function passesPublishGate(doc, hasDrafts) {
|
|
46
|
+
if (!hasDrafts) return true;
|
|
47
|
+
return doc._status === "published";
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Mirror the source document's status onto the translation (#51 D9). Combined with the publish-gate,
|
|
51
|
+
* the source is published whenever we reach enqueue, so translations publish; a no-drafts collection
|
|
52
|
+
* publishes too. Deliberately identical to {@link passesPublishGate} today — kept as a SEPARATE
|
|
53
|
+
* function (not merged) because it diverges once a future document-level manager (R8) can bypass the
|
|
54
|
+
* gate and translate a still-draft source; do not collapse the two.
|
|
55
|
+
*/ export function resolvePublishOnTranslation(doc, hasDrafts) {
|
|
56
|
+
if (!hasDrafts) return true;
|
|
57
|
+
return doc._status === "published";
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Build one {@link TaskInput} per configured target locale (the source locale is always excluded).
|
|
61
|
+
* `waitUntil` encodes the debounce; `now` is injected so the timestamp is deterministic in tests.
|
|
62
|
+
*/ export function buildAutoTranslateTasks(args) {
|
|
63
|
+
const { policy, collectionSlug, documentId, sourceLocale, doc, hasDrafts, now } = args;
|
|
64
|
+
const publishOnTranslation = resolvePublishOnTranslation(doc, hasDrafts);
|
|
65
|
+
const waitUntil = policy.debounceMs > 0 ? new Date(now + policy.debounceMs) : undefined;
|
|
66
|
+
return policy.targets.filter((target)=>target !== sourceLocale).map((target)=>({
|
|
67
|
+
collectionSlug,
|
|
68
|
+
collectionId: documentId,
|
|
69
|
+
sourceLng: sourceLocale,
|
|
70
|
+
targetLng: target,
|
|
71
|
+
strategy: policy.strategy,
|
|
72
|
+
publishOnTranslation,
|
|
73
|
+
waitUntil
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
//# sourceMappingURL=AutoTranslate.policy.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CollectionAfterChangeHook } from "payload";
|
|
2
|
+
/**
|
|
3
|
+
* The minimal slice of a Payload collection the auto-translate wiring mutates: its `slug` and the
|
|
4
|
+
* `afterChange` hook slot. A real `CollectionConfig` is structurally assignable to this, so call sites
|
|
5
|
+
* pass the live collection with no adapter and tests pass a `{ slug: "posts" }` literal. Keeps
|
|
6
|
+
* `injectAutoTranslateHook` off the god-`CollectionConfig` type (own shape — provenance's is not reused,
|
|
7
|
+
* per the module-owns-its-shape convention). The only Payload type imported is the hook callback
|
|
8
|
+
* contract, which legitimately stays framework-typed.
|
|
9
|
+
*/
|
|
10
|
+
export type AutoTranslateManagedEntry = {
|
|
11
|
+
slug: string;
|
|
12
|
+
hooks?: {
|
|
13
|
+
afterChange?: CollectionAfterChangeHook[];
|
|
14
|
+
};
|
|
15
|
+
/** The `custom` bag — the opt-in is propagated here so the admin UI can read it back off the
|
|
16
|
+
* REGISTERED collection (which may be a different object than the one `withAutoTranslate` wrapped). */
|
|
17
|
+
custom?: Record<string, unknown>;
|
|
18
|
+
};
|
|
19
|
+
/** The minimal config host: a mutable `collections` array. A real Payload `Config` plugs straight in. */
|
|
20
|
+
export type AutoTranslateManagedConfig = {
|
|
21
|
+
collections?: AutoTranslateManagedEntry[];
|
|
22
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CollectionSchemaMap } from "../../../types/CollectionSchemaMap";
|
|
2
|
+
import type { ConfigModifier } from "../../../types/ConfigModifier";
|
|
3
|
+
import type { TaskRunnerFactory } from "../task-runner";
|
|
4
|
+
/** A collection as the plugin receives it — only `slug` + `custom` are read to resolve the opt-in. */
|
|
5
|
+
type ConfigurableCollection = {
|
|
6
|
+
slug: string;
|
|
7
|
+
custom?: Record<string, unknown>;
|
|
8
|
+
};
|
|
9
|
+
/** Everything the auto-translate module contributes at config time (mirrors `ProvenanceModule`). */
|
|
10
|
+
export type AutoTranslateModule = {
|
|
11
|
+
configure(managedSlugs: Set<string>): ConfigModifier;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Turn the opt-in `withAutoTranslate` config (read from each collection's `custom`) into a
|
|
15
|
+
* self-contained {@link AutoTranslateModule} — mirrors `configureProvenance`. Builds the per-collection
|
|
16
|
+
* policy map + resolver once, then returns a `configure(managedSlugs) → ConfigModifier` that injects a
|
|
17
|
+
* single best-effort `afterChange` hook onto every enabled + managed collection. When no collection
|
|
18
|
+
* opted in, `configure` is a no-op (no hook, no behaviour change).
|
|
19
|
+
*/
|
|
20
|
+
export declare function configureAutoTranslate(collections: ConfigurableCollection[], schemaMap: CollectionSchemaMap, taskRunnerFactory: TaskRunnerFactory): AutoTranslateModule;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { getAutoTranslateConfig } from "../../../core/domain/auto-translate";
|
|
2
|
+
import { extractLocaleCodes, filterPolicyToKnownLocales, makeCollectionPolicyResolver, normalizeAutoTranslateConfig } from "./AutoTranslate.policy";
|
|
3
|
+
import { injectAutoTranslateHook, makeAutoTranslateHook, propagateAutoTranslateCustom } from "./AutoTranslateEnqueue.hook";
|
|
4
|
+
const NOOP = (config)=>config;
|
|
5
|
+
/** Emit one clear config-time warning per collection whose auto-translate config named unknown locales. */ function warnDroppedLocales(slug, filtered, knownLocales) {
|
|
6
|
+
const known = [
|
|
7
|
+
...knownLocales
|
|
8
|
+
].join(", ");
|
|
9
|
+
if (filtered.droppedTargets.length > 0) {
|
|
10
|
+
console.warn(`[payload-plugin-translator] auto-translate on "${slug}": ignoring unknown target locale(s) ${filtered.droppedTargets.join(", ")} (configured locales: ${known}).`);
|
|
11
|
+
}
|
|
12
|
+
if (filtered.droppedSourceLocale) {
|
|
13
|
+
console.warn(`[payload-plugin-translator] auto-translate on "${slug}": unknown sourceLocale "${filtered.droppedSourceLocale}" ignored, falling back to the default locale (configured locales: ${known}).`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Turn the opt-in `withAutoTranslate` config (read from each collection's `custom`) into a
|
|
18
|
+
* self-contained {@link AutoTranslateModule} — mirrors `configureProvenance`. Builds the per-collection
|
|
19
|
+
* policy map + resolver once, then returns a `configure(managedSlugs) → ConfigModifier` that injects a
|
|
20
|
+
* single best-effort `afterChange` hook onto every enabled + managed collection. When no collection
|
|
21
|
+
* opted in, `configure` is a no-op (no hook, no behaviour change).
|
|
22
|
+
*/ export function configureAutoTranslate(collections, schemaMap, taskRunnerFactory) {
|
|
23
|
+
const policies = new Map();
|
|
24
|
+
for (const collection of collections){
|
|
25
|
+
const config = getAutoTranslateConfig(collection);
|
|
26
|
+
if (config) policies.set(collection.slug, normalizeAutoTranslateConfig(config));
|
|
27
|
+
}
|
|
28
|
+
if (policies.size === 0) return {
|
|
29
|
+
configure: ()=>NOOP
|
|
30
|
+
};
|
|
31
|
+
const enabledSlugs = new Set(policies.keys());
|
|
32
|
+
const resolvePolicy = makeCollectionPolicyResolver(policies);
|
|
33
|
+
const hook = makeAutoTranslateHook({
|
|
34
|
+
resolvePolicy,
|
|
35
|
+
schemaMap,
|
|
36
|
+
taskRunnerFactory
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
configure: (managedSlugs)=>(config)=>{
|
|
40
|
+
// Inject only onto collections that both opted in AND are plugin-managed.
|
|
41
|
+
const slugs = new Set([
|
|
42
|
+
...enabledSlugs
|
|
43
|
+
].filter((slug)=>managedSlugs.has(slug)));
|
|
44
|
+
// Drop targets / source-locale overrides that are not configured locales, fail-fast with a
|
|
45
|
+
// warning at init — else a mistyped locale silently burns provider calls and orphans data at
|
|
46
|
+
// runtime. Filter the shared `policies` map once here (config-time, before any hook fires), so
|
|
47
|
+
// the hook, the propagated `custom`, and the admin indicator all read the corrected policy.
|
|
48
|
+
const knownLocales = extractLocaleCodes(config.localization);
|
|
49
|
+
if (knownLocales) {
|
|
50
|
+
for (const slug of slugs){
|
|
51
|
+
const policy = policies.get(slug);
|
|
52
|
+
if (!policy) continue;
|
|
53
|
+
const filtered = filterPolicyToKnownLocales(policy, knownLocales);
|
|
54
|
+
warnDroppedLocales(slug, filtered, knownLocales);
|
|
55
|
+
policies.set(slug, filtered.policy);
|
|
56
|
+
}
|
|
57
|
+
} else if (slugs.size > 0) {
|
|
58
|
+
console.warn("[payload-plugin-translator] auto-translate is configured but localization is disabled; no translations will be enqueued.");
|
|
59
|
+
}
|
|
60
|
+
injectAutoTranslateHook(config, slugs, hook);
|
|
61
|
+
// Mirror the opt-in onto the registered collection's `custom` so the admin UI can read it back.
|
|
62
|
+
propagateAutoTranslateCustom(config, slugs, policies);
|
|
63
|
+
return config;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
//# sourceMappingURL=AutoTranslate.wiring.js.map
|