@justanarthur/payload-plugin-translator 1.3.6
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 +215 -0
- package/dist/client/api/index.d.ts +8 -0
- package/dist/client/api/index.d.ts.map +1 -0
- package/dist/client/components/CustomButton/CustomButtonWithTranslator.d.ts +5 -0
- package/dist/client/components/CustomButton/CustomButtonWithTranslator.d.ts.map +1 -0
- package/dist/client/components/CustomButton/index.d.ts +3 -0
- package/dist/client/components/CustomButton/index.d.ts.map +1 -0
- package/dist/client/components/CustomButton/styles.scss +5 -0
- package/dist/client/components/LocaleLabel/LocaleLabel.d.ts +5 -0
- package/dist/client/components/LocaleLabel/LocaleLabel.d.ts.map +1 -0
- package/dist/client/components/LocaleLabel/index.d.ts +2 -0
- package/dist/client/components/LocaleLabel/index.d.ts.map +1 -0
- package/dist/client/components/ResolverButton/ResolverButton.d.ts +5 -0
- package/dist/client/components/ResolverButton/ResolverButton.d.ts.map +1 -0
- package/dist/client/components/ResolverButton/index.d.ts +2 -0
- package/dist/client/components/ResolverButton/index.d.ts.map +1 -0
- package/dist/client/components/TranslatorModal/Content.d.ts +2 -0
- package/dist/client/components/TranslatorModal/Content.d.ts.map +1 -0
- package/dist/client/components/TranslatorModal/TranslatorModal.d.ts +3 -0
- package/dist/client/components/TranslatorModal/TranslatorModal.d.ts.map +1 -0
- package/dist/client/components/TranslatorModal/index.d.ts +2 -0
- package/dist/client/components/TranslatorModal/index.d.ts.map +1 -0
- package/dist/client/components/TranslatorModal/styles.scss +76 -0
- package/dist/client/providers/Translator/TranslatorProvider.d.ts +5 -0
- package/dist/client/providers/Translator/TranslatorProvider.d.ts.map +1 -0
- package/dist/client/providers/Translator/context.d.ts +21 -0
- package/dist/client/providers/Translator/context.d.ts.map +1 -0
- package/dist/exports/client.d.ts +2 -0
- package/dist/exports/client.d.ts.map +1 -0
- package/dist/i18n-translations.d.ts +87 -0
- package/dist/i18n-translations.d.ts.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/resolvers/copy.d.ts +3 -0
- package/dist/resolvers/copy.d.ts.map +1 -0
- package/dist/resolvers/google.d.ts +11 -0
- package/dist/resolvers/google.d.ts.map +1 -0
- package/dist/resolvers/libreTranslate.d.ts +16 -0
- package/dist/resolvers/libreTranslate.d.ts.map +1 -0
- package/dist/resolvers/openAI.d.ts +22 -0
- package/dist/resolvers/openAI.d.ts.map +1 -0
- package/dist/resolvers/types.d.ts +20 -0
- package/dist/resolvers/types.d.ts.map +1 -0
- package/dist/src/client/api/index.js +28 -0
- package/dist/src/client/api/index.js.map +1 -0
- package/dist/src/client/components/CustomButton/CustomButtonWithTranslator.js +28 -0
- package/dist/src/client/components/CustomButton/CustomButtonWithTranslator.js.map +1 -0
- package/dist/src/client/components/CustomButton/index.js +10 -0
- package/dist/src/client/components/CustomButton/index.js.map +1 -0
- package/dist/src/client/components/LocaleLabel/LocaleLabel.js +28 -0
- package/dist/src/client/components/LocaleLabel/LocaleLabel.js.map +1 -0
- package/dist/src/client/components/LocaleLabel/index.js +3 -0
- package/dist/src/client/components/LocaleLabel/index.js.map +1 -0
- package/dist/src/client/components/ResolverButton/ResolverButton.js +16 -0
- package/dist/src/client/components/ResolverButton/ResolverButton.js.map +1 -0
- package/dist/src/client/components/ResolverButton/index.js +3 -0
- package/dist/src/client/components/ResolverButton/index.js.map +1 -0
- package/dist/src/client/components/TranslatorModal/Content.js +60 -0
- package/dist/src/client/components/TranslatorModal/Content.js.map +1 -0
- package/dist/src/client/components/TranslatorModal/TranslatorModal.js +26 -0
- package/dist/src/client/components/TranslatorModal/TranslatorModal.js.map +1 -0
- package/dist/src/client/components/TranslatorModal/index.js +3 -0
- package/dist/src/client/components/TranslatorModal/index.js.map +1 -0
- package/dist/src/client/providers/Translator/TranslatorProvider.js +109 -0
- package/dist/src/client/providers/Translator/TranslatorProvider.js.map +1 -0
- package/dist/src/client/providers/Translator/context.js +9 -0
- package/dist/src/client/providers/Translator/context.js.map +1 -0
- package/dist/src/exports/client.js +3 -0
- package/dist/src/exports/client.js.map +1 -0
- package/dist/src/i18n-translations.js +88 -0
- package/dist/src/i18n-translations.js.map +1 -0
- package/dist/src/index.js +87 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/resolvers/copy.js +14 -0
- package/dist/src/resolvers/copy.js.map +1 -0
- package/dist/src/resolvers/google.js +47 -0
- package/dist/src/resolvers/google.js.map +1 -0
- package/dist/src/resolvers/libreTranslate.js +48 -0
- package/dist/src/resolvers/libreTranslate.js.map +1 -0
- package/dist/src/resolvers/openAI.js +100 -0
- package/dist/src/resolvers/openAI.js.map +1 -0
- package/dist/src/resolvers/types.js +3 -0
- package/dist/src/resolvers/types.js.map +1 -0
- package/dist/src/translate/endpoint.js +23 -0
- package/dist/src/translate/endpoint.js.map +1 -0
- package/dist/src/translate/findEntityWithConfig.js +34 -0
- package/dist/src/translate/findEntityWithConfig.js.map +1 -0
- package/dist/src/translate/operation.js +76 -0
- package/dist/src/translate/operation.js.map +1 -0
- package/dist/src/translate/traverseFields.js +190 -0
- package/dist/src/translate/traverseFields.js.map +1 -0
- package/dist/src/translate/traverseRichText.js +17 -0
- package/dist/src/translate/traverseRichText.js.map +1 -0
- package/dist/src/translate/types.js +3 -0
- package/dist/src/translate/types.js.map +1 -0
- package/dist/src/translate/updateEntity.js +26 -0
- package/dist/src/translate/updateEntity.js.map +1 -0
- package/dist/src/types.js +3 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/chunkArray.js +7 -0
- package/dist/src/utils/chunkArray.js.map +1 -0
- package/dist/src/utils/isEmpty.js +8 -0
- package/dist/src/utils/isEmpty.js.map +1 -0
- package/dist/translate/endpoint.d.ts +3 -0
- package/dist/translate/endpoint.d.ts.map +1 -0
- package/dist/translate/findEntityWithConfig.d.ts +15 -0
- package/dist/translate/findEntityWithConfig.d.ts.map +1 -0
- package/dist/translate/operation.d.ts +9 -0
- package/dist/translate/operation.d.ts.map +1 -0
- package/dist/translate/traverseFields.d.ts +13 -0
- package/dist/translate/traverseFields.d.ts.map +1 -0
- package/dist/translate/traverseRichText.d.ts +6 -0
- package/dist/translate/traverseRichText.d.ts.map +1 -0
- package/dist/translate/types.d.ts +25 -0
- package/dist/translate/types.d.ts.map +1 -0
- package/dist/translate/updateEntity.d.ts +14 -0
- package/dist/translate/updateEntity.d.ts.map +1 -0
- package/dist/types.d.ts +21 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/chunkArray.d.ts +2 -0
- package/dist/utils/chunkArray.d.ts.map +1 -0
- package/dist/utils/isEmpty.d.ts +2 -0
- package/dist/utils/isEmpty.d.ts.map +1 -0
- package/package.json +89 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { deepMerge } from 'payload/shared';
|
|
2
|
+
import { CustomButton } from './client/components/CustomButton';
|
|
3
|
+
import { translations } from './i18n-translations';
|
|
4
|
+
import { translateEndpoint } from './translate/endpoint';
|
|
5
|
+
import { translateOperation } from './translate/operation';
|
|
6
|
+
export { copyResolver } from './resolvers/copy';
|
|
7
|
+
export { googleResolver } from './resolvers/google';
|
|
8
|
+
export { libreResolver } from './resolvers/libreTranslate';
|
|
9
|
+
export { openAIResolver } from './resolvers/openAI';
|
|
10
|
+
export * from './resolvers/types';
|
|
11
|
+
export { translateOperation };
|
|
12
|
+
export const translator = (pluginConfig)=>{
|
|
13
|
+
return (config)=>{
|
|
14
|
+
if (pluginConfig.disabled || !config.localization || config.localization.locales.length < 2) return config;
|
|
15
|
+
const updatedConfig = {
|
|
16
|
+
...config,
|
|
17
|
+
admin: {
|
|
18
|
+
...config.admin ?? {},
|
|
19
|
+
custom: {
|
|
20
|
+
...config.admin?.custom ?? {},
|
|
21
|
+
translator: {
|
|
22
|
+
resolvers: pluginConfig.resolvers.map(({ key })=>({
|
|
23
|
+
key
|
|
24
|
+
}))
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
collections: config.collections?.map((collection)=>{
|
|
29
|
+
if (!pluginConfig.collections.includes(collection.slug)) return collection;
|
|
30
|
+
return {
|
|
31
|
+
...collection,
|
|
32
|
+
admin: {
|
|
33
|
+
...collection.admin ?? {},
|
|
34
|
+
components: {
|
|
35
|
+
...collection.admin?.components ?? {},
|
|
36
|
+
edit: {
|
|
37
|
+
...collection.admin?.components?.edit ?? {},
|
|
38
|
+
PublishButton: CustomButton('publish'),
|
|
39
|
+
SaveButton: CustomButton('save')
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}) ?? [],
|
|
45
|
+
custom: {
|
|
46
|
+
...config.custom ?? {},
|
|
47
|
+
translator: {
|
|
48
|
+
resolvers: pluginConfig.resolvers
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
endpoints: [
|
|
52
|
+
...config.endpoints ?? [],
|
|
53
|
+
{
|
|
54
|
+
handler: translateEndpoint,
|
|
55
|
+
method: 'post',
|
|
56
|
+
path: '/translator/translate'
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
globals: config.globals?.map((global)=>{
|
|
60
|
+
if (!pluginConfig.globals.includes(global.slug)) return global;
|
|
61
|
+
return {
|
|
62
|
+
...global,
|
|
63
|
+
admin: {
|
|
64
|
+
...global.admin ?? {},
|
|
65
|
+
components: {
|
|
66
|
+
...global.admin?.components ?? {},
|
|
67
|
+
elements: {
|
|
68
|
+
...global.admin?.components?.elements ?? {},
|
|
69
|
+
PublishButton: CustomButton('publish'),
|
|
70
|
+
SaveButton: CustomButton('save')
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}) ?? [],
|
|
76
|
+
i18n: {
|
|
77
|
+
...config.i18n,
|
|
78
|
+
translations: {
|
|
79
|
+
...deepMerge(config.i18n?.translations ?? {}, translations)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
return updatedConfig;
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import type { CollectionSlug, Config, GlobalSlug, Plugin } from 'payload'\nimport { deepMerge } from 'payload/shared'\n\nimport { CustomButton } from './client/components/CustomButton'\nimport { translations } from './i18n-translations'\nimport { translateEndpoint } from './translate/endpoint'\nimport { translateOperation } from './translate/operation'\nimport type { TranslatorConfig } from './types'\n\nexport { copyResolver } from './resolvers/copy'\n\nexport { googleResolver } from './resolvers/google'\n\nexport { libreResolver } from './resolvers/libreTranslate'\n\nexport { openAIResolver } from './resolvers/openAI'\nexport * from './resolvers/types'\n\nexport { translateOperation }\n\nexport const translator: (pluginConfig: TranslatorConfig) => Plugin = (pluginConfig) => {\n return (config) => {\n if (pluginConfig.disabled || !config.localization || config.localization.locales.length < 2)\n return config\n\n const updatedConfig: Config = {\n ...config,\n admin: {\n ...(config.admin ?? {}),\n custom: {\n ...(config.admin?.custom ?? {}),\n translator: {\n resolvers: pluginConfig.resolvers.map(({ key }) => ({ key })),\n },\n },\n },\n collections:\n config.collections?.map((collection) => {\n if (!pluginConfig.collections.includes(collection.slug as CollectionSlug))\n return collection\n\n return {\n ...collection,\n admin: {\n ...(collection.admin ?? {}),\n components: {\n ...(collection.admin?.components ?? {}),\n edit: {\n ...(collection.admin?.components?.edit ?? {}),\n PublishButton: CustomButton('publish'),\n SaveButton: CustomButton('save'),\n },\n },\n },\n }\n }) ?? [],\n custom: {\n ...(config.custom ?? {}),\n translator: {\n resolvers: pluginConfig.resolvers,\n },\n },\n endpoints: [\n ...(config.endpoints ?? []),\n {\n handler: translateEndpoint,\n method: 'post',\n path: '/translator/translate',\n },\n ],\n globals:\n config.globals?.map((global) => {\n if (!pluginConfig.globals.includes(global.slug as GlobalSlug)) return global\n\n return {\n ...global,\n admin: {\n ...(global.admin ?? {}),\n components: {\n ...(global.admin?.components ?? {}),\n elements: {\n ...(global.admin?.components?.elements ?? {}),\n PublishButton: CustomButton('publish'),\n SaveButton: CustomButton('save'),\n },\n },\n },\n }\n }) ?? [],\n i18n: {\n ...config.i18n,\n translations: {\n ...deepMerge(config.i18n?.translations ?? {}, translations),\n },\n },\n }\n\n return updatedConfig\n }\n}\n"],"names":["deepMerge","CustomButton","translations","translateEndpoint","translateOperation","copyResolver","googleResolver","libreResolver","openAIResolver","translator","pluginConfig","config","disabled","localization","locales","length","updatedConfig","admin","custom","resolvers","map","key","collections","collection","includes","slug","components","edit","PublishButton","SaveButton","endpoints","handler","method","path","globals","global","elements","i18n"],"mappings":"AACA,SAASA,SAAS,QAAQ,iBAAgB;AAE1C,SAASC,YAAY,QAAQ,mCAAkC;AAC/D,SAASC,YAAY,QAAQ,sBAAqB;AAClD,SAASC,iBAAiB,QAAQ,uBAAsB;AACxD,SAASC,kBAAkB,QAAQ,wBAAuB;AAG1D,SAASC,YAAY,QAAQ,mBAAkB;AAE/C,SAASC,cAAc,QAAQ,qBAAoB;AAEnD,SAASC,aAAa,QAAQ,6BAA4B;AAE1D,SAASC,cAAc,QAAQ,qBAAoB;AACnD,cAAc,oBAAmB;AAEjC,SAASJ,kBAAkB,GAAE;AAE7B,OAAO,MAAMK,aAAyD,CAACC;IACrE,OAAO,CAACC;QACN,IAAID,aAAaE,QAAQ,IAAI,CAACD,OAAOE,YAAY,IAAIF,OAAOE,YAAY,CAACC,OAAO,CAACC,MAAM,GAAG,GACxF,OAAOJ;QAET,MAAMK,gBAAwB;YAC5B,GAAGL,MAAM;YACTM,OAAO;gBACL,GAAIN,OAAOM,KAAK,IAAI,CAAC,CAAC;gBACtBC,QAAQ;oBACN,GAAIP,OAAOM,KAAK,EAAEC,UAAU,CAAC,CAAC;oBAC9BT,YAAY;wBACVU,WAAWT,aAAaS,SAAS,CAACC,GAAG,CAAC,CAAC,EAAEC,GAAG,EAAE,GAAM,CAAA;gCAAEA;4BAAI,CAAA;oBAC5D;gBACF;YACF;YACAC,aACEX,OAAOW,WAAW,EAAEF,IAAI,CAACG;gBACvB,IAAI,CAACb,aAAaY,WAAW,CAACE,QAAQ,CAACD,WAAWE,IAAI,GACpD,OAAOF;gBAET,OAAO;oBACL,GAAGA,UAAU;oBACbN,OAAO;wBACL,GAAIM,WAAWN,KAAK,IAAI,CAAC,CAAC;wBAC1BS,YAAY;4BACV,GAAIH,WAAWN,KAAK,EAAES,cAAc,CAAC,CAAC;4BACtCC,MAAM;gCACJ,GAAIJ,WAAWN,KAAK,EAAES,YAAYC,QAAQ,CAAC,CAAC;gCAC5CC,eAAe3B,aAAa;gCAC5B4B,YAAY5B,aAAa;4BAC3B;wBACF;oBACF;gBACF;YACF,MAAM,EAAE;YACViB,QAAQ;gBACN,GAAIP,OAAOO,MAAM,IAAI,CAAC,CAAC;gBACvBT,YAAY;oBACVU,WAAWT,aAAaS,SAAS;gBACnC;YACF;YACAW,WAAW;mBACLnB,OAAOmB,SAAS,IAAI,EAAE;gBAC1B;oBACEC,SAAS5B;oBACT6B,QAAQ;oBACRC,MAAM;gBACR;aACD;YACDC,SACEvB,OAAOuB,OAAO,EAAEd,IAAI,CAACe;gBACnB,IAAI,CAACzB,aAAawB,OAAO,CAACV,QAAQ,CAACW,OAAOV,IAAI,GAAiB,OAAOU;gBAEtE,OAAO;oBACL,GAAGA,MAAM;oBACTlB,OAAO;wBACL,GAAIkB,OAAOlB,KAAK,IAAI,CAAC,CAAC;wBACtBS,YAAY;4BACV,GAAIS,OAAOlB,KAAK,EAAES,cAAc,CAAC,CAAC;4BAClCU,UAAU;gCACR,GAAID,OAAOlB,KAAK,EAAES,YAAYU,YAAY,CAAC,CAAC;gCAC5CR,eAAe3B,aAAa;gCAC5B4B,YAAY5B,aAAa;4BAC3B;wBACF;oBACF;gBACF;YACF,MAAM,EAAE;YACVoC,MAAM;gBACJ,GAAG1B,OAAO0B,IAAI;gBACdnC,cAAc;oBACZ,GAAGF,UAAUW,OAAO0B,IAAI,EAAEnC,gBAAgB,CAAC,GAAGA,aAAa;gBAC7D;YACF;QACF;QAEA,OAAOc;IACT;AACF,EAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/resolvers/copy.ts"],"sourcesContent":["import type { TranslateResolver } from './types'\n\nexport const copyResolver = (): TranslateResolver => {\n return {\n key: 'copy',\n resolve: (args) => {\n const { texts } = args\n\n return {\n success: true,\n translatedTexts: texts,\n }\n },\n }\n}\n"],"names":["copyResolver","key","resolve","args","texts","success","translatedTexts"],"mappings":"AAEA,OAAO,MAAMA,eAAe;IAC1B,OAAO;QACLC,KAAK;QACLC,SAAS,CAACC;YACR,MAAM,EAAEC,KAAK,EAAE,GAAGD;YAElB,OAAO;gBACLE,SAAS;gBACTC,iBAAiBF;YACnB;QACF;IACF;AACF,EAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { chunkArray } from '../utils/chunkArray';
|
|
2
|
+
const localeToCountryCodeMapper = {
|
|
3
|
+
ua: 'uk'
|
|
4
|
+
};
|
|
5
|
+
const mapLocale = (incoming)=>incoming in localeToCountryCodeMapper ? localeToCountryCodeMapper[incoming] : incoming;
|
|
6
|
+
export const googleResolver = ({ apiKey, chunkLength = 100 })=>{
|
|
7
|
+
return {
|
|
8
|
+
key: 'google',
|
|
9
|
+
resolve: async (args)=>{
|
|
10
|
+
const { localeFrom, localeTo, req, texts } = args;
|
|
11
|
+
const apiUrl = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`;
|
|
12
|
+
const responses = await Promise.all(chunkArray(texts, chunkLength).map((q)=>fetch(apiUrl, {
|
|
13
|
+
body: JSON.stringify({
|
|
14
|
+
q,
|
|
15
|
+
source: mapLocale(localeFrom),
|
|
16
|
+
target: mapLocale(localeTo)
|
|
17
|
+
}),
|
|
18
|
+
headers: {
|
|
19
|
+
'Content-Type': 'application/json'
|
|
20
|
+
},
|
|
21
|
+
method: 'POST'
|
|
22
|
+
}).then(async (res)=>{
|
|
23
|
+
const data = await res.json();
|
|
24
|
+
if (!res.ok) req.payload.logger.info({
|
|
25
|
+
googleResponse: data,
|
|
26
|
+
message: 'An error occurred when trying to translate the data using Google API'
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
data,
|
|
30
|
+
success: res.ok
|
|
31
|
+
};
|
|
32
|
+
})));
|
|
33
|
+
if (responses.some((res)=>!res.success)) {
|
|
34
|
+
return {
|
|
35
|
+
success: false
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const translatedTexts = responses.flatMap((chunk)=>chunk.data.data.translations).map((translation)=>translation.translatedText);
|
|
39
|
+
return {
|
|
40
|
+
success: true,
|
|
41
|
+
translatedTexts
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=google.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/resolvers/google.ts"],"sourcesContent":["import { chunkArray } from '../utils/chunkArray'\nimport type { TranslateResolver } from './types'\n\ntype GoogleResponse = {\n data: {\n data: {\n translations: {\n detectedSourceLanguage: string\n model: string\n translatedText: string\n }[]\n }\n }\n success: boolean\n}\n\nconst localeToCountryCodeMapper = {\n ua: 'uk',\n}\n\nconst mapLocale = (incoming: string) =>\n incoming in localeToCountryCodeMapper\n ? localeToCountryCodeMapper[incoming as keyof typeof localeToCountryCodeMapper]\n : incoming\n\nexport type GoogleResolverConfig = {\n apiKey: string\n /**\n * How many texts to include into 1 request\n * @default 100\n */\n chunkLength?: number\n}\n\nexport const googleResolver = ({\n apiKey,\n chunkLength = 100,\n}: GoogleResolverConfig): TranslateResolver => {\n return {\n key: 'google',\n resolve: async (args) => {\n const { localeFrom, localeTo, req, texts } = args\n\n const apiUrl = `https://translation.googleapis.com/language/translate/v2?key=${apiKey}`\n\n const responses: GoogleResponse[] = await Promise.all(\n chunkArray(texts, chunkLength).map((q) =>\n fetch(apiUrl, {\n body: JSON.stringify({\n q,\n source: mapLocale(localeFrom),\n target: mapLocale(localeTo),\n }),\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n }).then(async (res) => {\n const data = await res.json()\n\n if (!res.ok)\n req.payload.logger.info({\n googleResponse: data,\n message: 'An error occurred when trying to translate the data using Google API',\n })\n\n return {\n data,\n success: res.ok,\n }\n }),\n ),\n )\n\n if (responses.some((res) => !res.success)) {\n return {\n success: false,\n }\n }\n\n const translatedTexts = responses\n .flatMap((chunk) => chunk.data.data.translations)\n .map((translation) => translation.translatedText)\n\n return {\n success: true,\n translatedTexts,\n }\n },\n }\n}\n"],"names":["chunkArray","localeToCountryCodeMapper","ua","mapLocale","incoming","googleResolver","apiKey","chunkLength","key","resolve","args","localeFrom","localeTo","req","texts","apiUrl","responses","Promise","all","map","q","fetch","body","JSON","stringify","source","target","headers","method","then","res","data","json","ok","payload","logger","info","googleResponse","message","success","some","translatedTexts","flatMap","chunk","translations","translation","translatedText"],"mappings":"AAAA,SAASA,UAAU,QAAQ,sBAAqB;AAgBhD,MAAMC,4BAA4B;IAChCC,IAAI;AACN;AAEA,MAAMC,YAAY,CAACC,WACjBA,YAAYH,4BACRA,yBAAyB,CAACG,SAAmD,GAC7EA;AAWN,OAAO,MAAMC,iBAAiB,CAAC,EAC7BC,MAAM,EACNC,cAAc,GAAG,EACI;IACrB,OAAO;QACLC,KAAK;QACLC,SAAS,OAAOC;YACd,MAAM,EAAEC,UAAU,EAAEC,QAAQ,EAAEC,GAAG,EAAEC,KAAK,EAAE,GAAGJ;YAE7C,MAAMK,SAAS,CAAC,6DAA6D,EAAET,QAAQ;YAEvF,MAAMU,YAA8B,MAAMC,QAAQC,GAAG,CACnDlB,WAAWc,OAAOP,aAAaY,GAAG,CAAC,CAACC,IAClCC,MAAMN,QAAQ;oBACZO,MAAMC,KAAKC,SAAS,CAAC;wBACnBJ;wBACAK,QAAQtB,UAAUQ;wBAClBe,QAAQvB,UAAUS;oBACpB;oBACAe,SAAS;wBACP,gBAAgB;oBAClB;oBACAC,QAAQ;gBACV,GAAGC,IAAI,CAAC,OAAOC;oBACb,MAAMC,OAAO,MAAMD,IAAIE,IAAI;oBAE3B,IAAI,CAACF,IAAIG,EAAE,EACTpB,IAAIqB,OAAO,CAACC,MAAM,CAACC,IAAI,CAAC;wBACtBC,gBAAgBN;wBAChBO,SAAS;oBACX;oBAEF,OAAO;wBACLP;wBACAQ,SAAST,IAAIG,EAAE;oBACjB;gBACF;YAIJ,IAAIjB,UAAUwB,IAAI,CAAC,CAACV,MAAQ,CAACA,IAAIS,OAAO,GAAG;gBACzC,OAAO;oBACLA,SAAS;gBACX;YACF;YAEA,MAAME,kBAAkBzB,UACrB0B,OAAO,CAAC,CAACC,QAAUA,MAAMZ,IAAI,CAACA,IAAI,CAACa,YAAY,EAC/CzB,GAAG,CAAC,CAAC0B,cAAgBA,YAAYC,cAAc;YAElD,OAAO;gBACLP,SAAS;gBACTE;YACF;QACF;IACF;AACF,EAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { chunkArray } from '../utils/chunkArray';
|
|
2
|
+
const localeToCountryCodeMapper = {
|
|
3
|
+
ua: 'uk'
|
|
4
|
+
};
|
|
5
|
+
const mapLocale = (incoming)=>incoming in localeToCountryCodeMapper ? localeToCountryCodeMapper[incoming] : incoming;
|
|
6
|
+
export const libreResolver = ({ apiKey, chunkLength = 100, url = 'https://libretranslate.com/translate' })=>{
|
|
7
|
+
return {
|
|
8
|
+
key: 'libre',
|
|
9
|
+
resolve: async (args)=>{
|
|
10
|
+
const { localeFrom, localeTo, req, texts } = args;
|
|
11
|
+
const apiUrl = url;
|
|
12
|
+
const responses = await Promise.all(chunkArray(texts, chunkLength).map((q)=>fetch(apiUrl, {
|
|
13
|
+
body: JSON.stringify({
|
|
14
|
+
api_key: apiKey,
|
|
15
|
+
q,
|
|
16
|
+
source: mapLocale(localeFrom),
|
|
17
|
+
target: mapLocale(localeTo)
|
|
18
|
+
}),
|
|
19
|
+
headers: {
|
|
20
|
+
'Content-Type': 'application/json'
|
|
21
|
+
},
|
|
22
|
+
method: 'POST'
|
|
23
|
+
}).then(async (res)=>{
|
|
24
|
+
const data = await res.json();
|
|
25
|
+
if (!res.ok) req.payload.logger.info({
|
|
26
|
+
libreResponse: data,
|
|
27
|
+
message: 'An error occurred when trying to translate the data using LibreTranslate API'
|
|
28
|
+
});
|
|
29
|
+
return {
|
|
30
|
+
data,
|
|
31
|
+
success: res.ok
|
|
32
|
+
};
|
|
33
|
+
})));
|
|
34
|
+
if (responses.some((res)=>!res.success)) {
|
|
35
|
+
return {
|
|
36
|
+
success: false
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const translatedTexts = responses.flatMap((chunk)=>chunk.data.translatedText);
|
|
40
|
+
return {
|
|
41
|
+
success: true,
|
|
42
|
+
translatedTexts
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=libreTranslate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/resolvers/libreTranslate.ts"],"sourcesContent":["import { chunkArray } from '../utils/chunkArray'\nimport type { TranslateResolver } from './types'\n\ntype LibreResponse = {\n data: {\n translatedText: string[]\n }\n success: boolean\n}\n\nconst localeToCountryCodeMapper = {\n ua: 'uk',\n}\n\nconst mapLocale = (incoming: string) =>\n incoming in localeToCountryCodeMapper\n ? localeToCountryCodeMapper[incoming as keyof typeof localeToCountryCodeMapper]\n : incoming\n\nexport type LibreResolverConfig = {\n apiKey: string\n /**\n * How many texts to include into 1 request\n * @default 100\n */\n chunkLength?: number\n /**\n * Custom url for the libre translate instance\n * @default \"https://libretranslate.com/translate\"\n */\n url?: string\n}\n\nexport const libreResolver = ({\n apiKey,\n chunkLength = 100,\n url = 'https://libretranslate.com/translate',\n}: LibreResolverConfig): TranslateResolver => {\n return {\n key: 'libre',\n resolve: async (args) => {\n const { localeFrom, localeTo, req, texts } = args\n\n const apiUrl = url\n\n const responses: LibreResponse[] = await Promise.all(\n chunkArray(texts, chunkLength).map((q) =>\n fetch(apiUrl, {\n body: JSON.stringify({\n api_key: apiKey,\n q,\n source: mapLocale(localeFrom),\n target: mapLocale(localeTo),\n }),\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n }).then(async (res) => {\n const data = await res.json()\n\n if (!res.ok)\n req.payload.logger.info({\n libreResponse: data,\n message:\n 'An error occurred when trying to translate the data using LibreTranslate API',\n })\n\n return {\n data,\n success: res.ok,\n }\n }),\n ),\n )\n\n if (responses.some((res) => !res.success)) {\n return {\n success: false,\n }\n }\n\n const translatedTexts = responses.flatMap((chunk) => chunk.data.translatedText)\n\n return {\n success: true,\n translatedTexts,\n }\n },\n }\n}\n"],"names":["chunkArray","localeToCountryCodeMapper","ua","mapLocale","incoming","libreResolver","apiKey","chunkLength","url","key","resolve","args","localeFrom","localeTo","req","texts","apiUrl","responses","Promise","all","map","q","fetch","body","JSON","stringify","api_key","source","target","headers","method","then","res","data","json","ok","payload","logger","info","libreResponse","message","success","some","translatedTexts","flatMap","chunk","translatedText"],"mappings":"AAAA,SAASA,UAAU,QAAQ,sBAAqB;AAUhD,MAAMC,4BAA4B;IAChCC,IAAI;AACN;AAEA,MAAMC,YAAY,CAACC,WACjBA,YAAYH,4BACRA,yBAAyB,CAACG,SAAmD,GAC7EA;AAgBN,OAAO,MAAMC,gBAAgB,CAAC,EAC5BC,MAAM,EACNC,cAAc,GAAG,EACjBC,MAAM,sCAAsC,EACxB;IACpB,OAAO;QACLC,KAAK;QACLC,SAAS,OAAOC;YACd,MAAM,EAAEC,UAAU,EAAEC,QAAQ,EAAEC,GAAG,EAAEC,KAAK,EAAE,GAAGJ;YAE7C,MAAMK,SAASR;YAEf,MAAMS,YAA6B,MAAMC,QAAQC,GAAG,CAClDnB,WAAWe,OAAOR,aAAaa,GAAG,CAAC,CAACC,IAClCC,MAAMN,QAAQ;oBACZO,MAAMC,KAAKC,SAAS,CAAC;wBACnBC,SAASpB;wBACTe;wBACAM,QAAQxB,UAAUS;wBAClBgB,QAAQzB,UAAUU;oBACpB;oBACAgB,SAAS;wBACP,gBAAgB;oBAClB;oBACAC,QAAQ;gBACV,GAAGC,IAAI,CAAC,OAAOC;oBACb,MAAMC,OAAO,MAAMD,IAAIE,IAAI;oBAE3B,IAAI,CAACF,IAAIG,EAAE,EACTrB,IAAIsB,OAAO,CAACC,MAAM,CAACC,IAAI,CAAC;wBACtBC,eAAeN;wBACfO,SACE;oBACJ;oBAEF,OAAO;wBACLP;wBACAQ,SAAST,IAAIG,EAAE;oBACjB;gBACF;YAIJ,IAAIlB,UAAUyB,IAAI,CAAC,CAACV,MAAQ,CAACA,IAAIS,OAAO,GAAG;gBACzC,OAAO;oBACLA,SAAS;gBACX;YACF;YAEA,MAAME,kBAAkB1B,UAAU2B,OAAO,CAAC,CAACC,QAAUA,MAAMZ,IAAI,CAACa,cAAc;YAE9E,OAAO;gBACLL,SAAS;gBACTE;YACF;QACF;IACF;AACF,EAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { chunkArray } from '../utils/chunkArray';
|
|
2
|
+
const defaultPrompt = ({ localeFrom, localeTo, texts })=>{
|
|
3
|
+
return `Translate me the following array: ${JSON.stringify(texts)} in locale=${localeFrom} to locale ${localeTo}, respond me with the same array structure`;
|
|
4
|
+
};
|
|
5
|
+
export const openAIResolver = ({ apiKey, baseUrl, chunkLength = 100, model = 'gpt-3.5-turbo', prompt = defaultPrompt })=>{
|
|
6
|
+
return {
|
|
7
|
+
key: 'openai',
|
|
8
|
+
resolve: async ({ localeFrom, localeTo, req, texts })=>{
|
|
9
|
+
const apiUrl = `${baseUrl || 'https://api.openai.com'}/v1/chat/completions`;
|
|
10
|
+
try {
|
|
11
|
+
const response = await Promise.all(chunkArray(texts, chunkLength).map((texts)=>{
|
|
12
|
+
return fetch(apiUrl, {
|
|
13
|
+
body: JSON.stringify({
|
|
14
|
+
messages: [
|
|
15
|
+
{
|
|
16
|
+
content: prompt({
|
|
17
|
+
localeFrom,
|
|
18
|
+
localeTo,
|
|
19
|
+
texts
|
|
20
|
+
}),
|
|
21
|
+
role: 'user'
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
model
|
|
25
|
+
}),
|
|
26
|
+
headers: {
|
|
27
|
+
Authorization: `Bearer ${apiKey}`,
|
|
28
|
+
'Content-Type': 'application/json'
|
|
29
|
+
},
|
|
30
|
+
method: 'post'
|
|
31
|
+
}).then(async (res)=>{
|
|
32
|
+
const data = await res.json();
|
|
33
|
+
if (!res.ok) req.payload.logger.info({
|
|
34
|
+
message: 'An error occurred when trying to translate the data using OpenAI API',
|
|
35
|
+
openAIresponse: data
|
|
36
|
+
});
|
|
37
|
+
return {
|
|
38
|
+
data,
|
|
39
|
+
success: res.ok
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}));
|
|
43
|
+
const translated = [];
|
|
44
|
+
for (const { data, success } of response){
|
|
45
|
+
if (!success) return {
|
|
46
|
+
success: false
|
|
47
|
+
};
|
|
48
|
+
const content = data?.choices?.[0]?.message?.content;
|
|
49
|
+
if (!content) {
|
|
50
|
+
req.payload.logger.error('An error occurred when trying to translate the data using OpenAI API - missing content in the response');
|
|
51
|
+
return {
|
|
52
|
+
success: false
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const translatedChunk = JSON.parse(content);
|
|
56
|
+
if (!Array.isArray(translatedChunk)) {
|
|
57
|
+
req.payload.logger.error({
|
|
58
|
+
data: translatedChunk,
|
|
59
|
+
fullContent: content,
|
|
60
|
+
message: 'An error occurred when trying to translate the data using OpenAI API - parsed content is not an array'
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
success: false
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
for (const text of translatedChunk){
|
|
67
|
+
if (text && typeof text !== 'string') {
|
|
68
|
+
req.payload.logger.error({
|
|
69
|
+
chunkData: translatedChunk,
|
|
70
|
+
data: text,
|
|
71
|
+
fullContent: content,
|
|
72
|
+
message: 'An error occurred when trying to translate the data using OpenAI API - parsed content is not a string'
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
success: false
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
translated.push(text);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
success: true,
|
|
83
|
+
translatedTexts: translated
|
|
84
|
+
};
|
|
85
|
+
} catch (e) {
|
|
86
|
+
if (e instanceof Error) {
|
|
87
|
+
req.payload.logger.info({
|
|
88
|
+
message: 'An error occurred when trying to translate the data using OpenAI API',
|
|
89
|
+
originalErr: e.message
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
success: false
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
//# sourceMappingURL=openAI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/resolvers/openAI.ts"],"sourcesContent":["import { chunkArray } from '../utils/chunkArray'\nimport type { TranslateResolver } from './types'\n\nexport type OpenAIPrompt = (args: {\n localeFrom: string\n localeTo: string\n texts: string[]\n}) => string\n\nexport type OpenAIResolverConfig = {\n apiKey: string\n baseUrl?: string\n /**\n * How many texts to include into 1 request\n * @default 100\n */\n chunkLength?: number\n /**\n * @default \"gpt-3.5-turbo\"\n */\n model?: string\n prompt?: OpenAIPrompt\n}\n\ntype OpenAIResponse = {\n choices: {\n message: {\n content: string\n }\n }[]\n}\n\nconst defaultPrompt: OpenAIPrompt = ({ localeFrom, localeTo, texts }) => {\n return `Translate me the following array: ${JSON.stringify(texts)} in locale=${localeFrom} to locale ${localeTo}, respond me with the same array structure`\n}\n\nexport const openAIResolver = ({\n apiKey,\n baseUrl,\n chunkLength = 100,\n model = 'gpt-3.5-turbo',\n prompt = defaultPrompt,\n}: OpenAIResolverConfig): TranslateResolver => {\n return {\n key: 'openai',\n resolve: async ({ localeFrom, localeTo, req, texts }) => {\n const apiUrl = `${baseUrl || 'https://api.openai.com'}/v1/chat/completions`\n\n try {\n const response: {\n data: OpenAIResponse\n success: boolean\n }[] = await Promise.all(\n chunkArray(texts, chunkLength).map((texts) => {\n return fetch(apiUrl, {\n body: JSON.stringify({\n messages: [\n {\n content: prompt({ localeFrom, localeTo, texts }),\n role: 'user',\n },\n ],\n model,\n }),\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n method: 'post',\n }).then(async (res) => {\n const data = await res.json()\n\n if (!res.ok)\n req.payload.logger.info({\n message: 'An error occurred when trying to translate the data using OpenAI API',\n openAIresponse: data,\n })\n\n return {\n data,\n success: res.ok,\n }\n })\n }),\n )\n\n const translated: string[] = []\n\n for (const { data, success } of response) {\n if (!success)\n return {\n success: false as const,\n }\n\n const content = data?.choices?.[0]?.message?.content\n\n if (!content) {\n req.payload.logger.error(\n 'An error occurred when trying to translate the data using OpenAI API - missing content in the response',\n )\n\n return {\n success: false as const,\n }\n }\n\n const translatedChunk: string[] = JSON.parse(content)\n\n if (!Array.isArray(translatedChunk)) {\n req.payload.logger.error({\n data: translatedChunk,\n fullContent: content,\n message:\n 'An error occurred when trying to translate the data using OpenAI API - parsed content is not an array',\n })\n\n return {\n success: false as const,\n }\n }\n\n for (const text of translatedChunk) {\n if (text && typeof text !== 'string') {\n req.payload.logger.error({\n chunkData: translatedChunk,\n data: text,\n fullContent: content,\n message:\n 'An error occurred when trying to translate the data using OpenAI API - parsed content is not a string',\n })\n\n return {\n success: false as const,\n }\n }\n\n translated.push(text)\n }\n }\n\n return {\n success: true as const,\n translatedTexts: translated,\n }\n } catch (e) {\n if (e instanceof Error) {\n req.payload.logger.info({\n message: 'An error occurred when trying to translate the data using OpenAI API',\n originalErr: e.message,\n })\n }\n\n return { success: false as const }\n }\n },\n }\n}\n"],"names":["chunkArray","defaultPrompt","localeFrom","localeTo","texts","JSON","stringify","openAIResolver","apiKey","baseUrl","chunkLength","model","prompt","key","resolve","req","apiUrl","response","Promise","all","map","fetch","body","messages","content","role","headers","Authorization","method","then","res","data","json","ok","payload","logger","info","message","openAIresponse","success","translated","choices","error","translatedChunk","parse","Array","isArray","fullContent","text","chunkData","push","translatedTexts","e","Error","originalErr"],"mappings":"AAAA,SAASA,UAAU,QAAQ,sBAAqB;AAgChD,MAAMC,gBAA8B,CAAC,EAAEC,UAAU,EAAEC,QAAQ,EAAEC,KAAK,EAAE;IAClE,OAAO,CAAC,kCAAkC,EAAEC,KAAKC,SAAS,CAACF,OAAO,WAAW,EAAEF,WAAW,WAAW,EAAEC,SAAS,0CAA0C,CAAC;AAC7J;AAEA,OAAO,MAAMI,iBAAiB,CAAC,EAC7BC,MAAM,EACNC,OAAO,EACPC,cAAc,GAAG,EACjBC,QAAQ,eAAe,EACvBC,SAASX,aAAa,EACD;IACrB,OAAO;QACLY,KAAK;QACLC,SAAS,OAAO,EAAEZ,UAAU,EAAEC,QAAQ,EAAEY,GAAG,EAAEX,KAAK,EAAE;YAClD,MAAMY,SAAS,GAAGP,WAAW,yBAAyB,oBAAoB,CAAC;YAE3E,IAAI;gBACF,MAAMQ,WAGA,MAAMC,QAAQC,GAAG,CACrBnB,WAAWI,OAAOM,aAAaU,GAAG,CAAC,CAAChB;oBAClC,OAAOiB,MAAML,QAAQ;wBACnBM,MAAMjB,KAAKC,SAAS,CAAC;4BACnBiB,UAAU;gCACR;oCACEC,SAASZ,OAAO;wCAAEV;wCAAYC;wCAAUC;oCAAM;oCAC9CqB,MAAM;gCACR;6BACD;4BACDd;wBACF;wBACAe,SAAS;4BACPC,eAAe,CAAC,OAAO,EAAEnB,QAAQ;4BACjC,gBAAgB;wBAClB;wBACAoB,QAAQ;oBACV,GAAGC,IAAI,CAAC,OAAOC;wBACb,MAAMC,OAAO,MAAMD,IAAIE,IAAI;wBAE3B,IAAI,CAACF,IAAIG,EAAE,EACTlB,IAAImB,OAAO,CAACC,MAAM,CAACC,IAAI,CAAC;4BACtBC,SAAS;4BACTC,gBAAgBP;wBAClB;wBAEF,OAAO;4BACLA;4BACAQ,SAAST,IAAIG,EAAE;wBACjB;oBACF;gBACF;gBAGF,MAAMO,aAAuB,EAAE;gBAE/B,KAAK,MAAM,EAAET,IAAI,EAAEQ,OAAO,EAAE,IAAItB,SAAU;oBACxC,IAAI,CAACsB,SACH,OAAO;wBACLA,SAAS;oBACX;oBAEF,MAAMf,UAAUO,MAAMU,SAAS,CAAC,EAAE,EAAEJ,SAASb;oBAE7C,IAAI,CAACA,SAAS;wBACZT,IAAImB,OAAO,CAACC,MAAM,CAACO,KAAK,CACtB;wBAGF,OAAO;4BACLH,SAAS;wBACX;oBACF;oBAEA,MAAMI,kBAA4BtC,KAAKuC,KAAK,CAACpB;oBAE7C,IAAI,CAACqB,MAAMC,OAAO,CAACH,kBAAkB;wBACnC5B,IAAImB,OAAO,CAACC,MAAM,CAACO,KAAK,CAAC;4BACvBX,MAAMY;4BACNI,aAAavB;4BACba,SACE;wBACJ;wBAEA,OAAO;4BACLE,SAAS;wBACX;oBACF;oBAEA,KAAK,MAAMS,QAAQL,gBAAiB;wBAClC,IAAIK,QAAQ,OAAOA,SAAS,UAAU;4BACpCjC,IAAImB,OAAO,CAACC,MAAM,CAACO,KAAK,CAAC;gCACvBO,WAAWN;gCACXZ,MAAMiB;gCACND,aAAavB;gCACba,SACE;4BACJ;4BAEA,OAAO;gCACLE,SAAS;4BACX;wBACF;wBAEAC,WAAWU,IAAI,CAACF;oBAClB;gBACF;gBAEA,OAAO;oBACLT,SAAS;oBACTY,iBAAiBX;gBACnB;YACF,EAAE,OAAOY,GAAG;gBACV,IAAIA,aAAaC,OAAO;oBACtBtC,IAAImB,OAAO,CAACC,MAAM,CAACC,IAAI,CAAC;wBACtBC,SAAS;wBACTiB,aAAaF,EAAEf,OAAO;oBACxB;gBACF;gBAEA,OAAO;oBAAEE,SAAS;gBAAe;YACnC;QACF;IACF;AACF,EAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/resolvers/types.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nexport type TranslateResolverArgs = {\n /** Locale to translate from */\n localeFrom: string\n /** Locale to translate to */\n localeTo: string\n req: PayloadRequest\n texts: string[]\n}\n\nexport type TranslateResolverResponse =\n | {\n success: false\n }\n | {\n success: true\n translatedTexts: string[]\n }\n\nexport type TranslateResolver = {\n key: string\n resolve: (\n args: TranslateResolverArgs,\n ) => Promise<TranslateResolverResponse> | TranslateResolverResponse\n}\n"],"names":[],"mappings":"AAoBA,WAKC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { APIError } from 'payload';
|
|
2
|
+
import { translateOperation } from './operation';
|
|
3
|
+
export const translateEndpoint = async (req)=>{
|
|
4
|
+
if (!req.json) throw new APIError('Content-Type should be json');
|
|
5
|
+
const args = await req.json();
|
|
6
|
+
const { collectionSlug, data, emptyOnly, globalSlug, id, locale, localeFrom, resolver } = args;
|
|
7
|
+
const result = await translateOperation({
|
|
8
|
+
collectionSlug,
|
|
9
|
+
data,
|
|
10
|
+
emptyOnly,
|
|
11
|
+
globalSlug,
|
|
12
|
+
id,
|
|
13
|
+
locale,
|
|
14
|
+
localeFrom,
|
|
15
|
+
overrideAccess: false,
|
|
16
|
+
req,
|
|
17
|
+
resolver,
|
|
18
|
+
update: false
|
|
19
|
+
});
|
|
20
|
+
return Response.json(result);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/translate/endpoint.ts"],"sourcesContent":["import type { PayloadHandler } from 'payload'\nimport { APIError } from 'payload'\n\nimport { translateOperation } from './operation'\nimport type { TranslateEndpointArgs } from './types'\n\nexport const translateEndpoint: PayloadHandler = async (req) => {\n if (!req.json) throw new APIError('Content-Type should be json')\n\n const args: TranslateEndpointArgs = await req.json()\n\n const { collectionSlug, data, emptyOnly, globalSlug, id, locale, localeFrom, resolver } = args\n\n const result = await translateOperation({\n collectionSlug,\n data,\n emptyOnly,\n globalSlug,\n id,\n locale,\n localeFrom,\n overrideAccess: false,\n req,\n resolver,\n update: false,\n })\n\n return Response.json(result)\n}\n"],"names":["APIError","translateOperation","translateEndpoint","req","json","args","collectionSlug","data","emptyOnly","globalSlug","id","locale","localeFrom","resolver","result","overrideAccess","update","Response"],"mappings":"AACA,SAASA,QAAQ,QAAQ,UAAS;AAElC,SAASC,kBAAkB,QAAQ,cAAa;AAGhD,OAAO,MAAMC,oBAAoC,OAAOC;IACtD,IAAI,CAACA,IAAIC,IAAI,EAAE,MAAM,IAAIJ,SAAS;IAElC,MAAMK,OAA8B,MAAMF,IAAIC,IAAI;IAElD,MAAM,EAAEE,cAAc,EAAEC,IAAI,EAAEC,SAAS,EAAEC,UAAU,EAAEC,EAAE,EAAEC,MAAM,EAAEC,UAAU,EAAEC,QAAQ,EAAE,GAAGR;IAE1F,MAAMS,SAAS,MAAMb,mBAAmB;QACtCK;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;QACAG,gBAAgB;QAChBZ;QACAU;QACAG,QAAQ;IACV;IAEA,OAAOC,SAASb,IAAI,CAACU;AACvB,EAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { APIError } from 'payload';
|
|
2
|
+
const findConfigBySlug = (slug, enities)=>enities.find((entity)=>entity.slug === slug);
|
|
3
|
+
export const findEntityWithConfig = async (args)=>{
|
|
4
|
+
const { collectionSlug, globalSlug, id, locale, overrideAccess, req } = args;
|
|
5
|
+
if (!collectionSlug && !globalSlug) throw new APIError('Bad Request', 400);
|
|
6
|
+
const { payload } = req;
|
|
7
|
+
const { config } = payload;
|
|
8
|
+
const isGlobal = !!globalSlug;
|
|
9
|
+
if (!isGlobal && !id) throw new APIError('Bad Request', 400);
|
|
10
|
+
const entityConfig = isGlobal ? findConfigBySlug(globalSlug, config.globals) : findConfigBySlug(collectionSlug, config.collections);
|
|
11
|
+
if (!entityConfig) throw new APIError('Bad Request', 400);
|
|
12
|
+
const docPromise = isGlobal ? payload.findGlobal({
|
|
13
|
+
depth: 0,
|
|
14
|
+
fallbackLocale: undefined,
|
|
15
|
+
locale: locale,
|
|
16
|
+
overrideAccess,
|
|
17
|
+
req,
|
|
18
|
+
slug: args.globalSlug
|
|
19
|
+
}) : payload.findByID({
|
|
20
|
+
collection: collectionSlug,
|
|
21
|
+
depth: 0,
|
|
22
|
+
fallbackLocale: undefined,
|
|
23
|
+
id: id,
|
|
24
|
+
locale: locale,
|
|
25
|
+
overrideAccess,
|
|
26
|
+
req
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
config: entityConfig,
|
|
30
|
+
doc: await docPromise
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=findEntityWithConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/translate/findEntityWithConfig.ts"],"sourcesContent":["import type {\n CollectionSlug,\n GlobalSlug,\n PayloadRequest,\n SanitizedCollectionConfig,\n SanitizedGlobalConfig,\n TypeWithID,\n} from 'payload'\nimport { APIError } from 'payload'\n\ntype Args = {\n collectionSlug?: string\n globalSlug?: string\n id?: number | string\n locale: string\n overrideAccess?: boolean\n req: PayloadRequest\n}\n\nconst findConfigBySlug = (\n slug: string,\n enities: SanitizedCollectionConfig[] | SanitizedGlobalConfig[],\n) => enities.find((entity) => entity.slug === slug)\n\nexport const findEntityWithConfig = async (\n args: Args,\n): Promise<{\n config: SanitizedCollectionConfig | SanitizedGlobalConfig\n doc: Record<string, unknown> & TypeWithID\n}> => {\n const { collectionSlug, globalSlug, id, locale, overrideAccess, req } = args\n\n if (!collectionSlug && !globalSlug) throw new APIError('Bad Request', 400)\n\n const { payload } = req\n\n const { config } = payload\n\n const isGlobal = !!globalSlug\n\n if (!isGlobal && !id) throw new APIError('Bad Request', 400)\n\n const entityConfig = isGlobal\n ? findConfigBySlug(globalSlug, config.globals)\n : findConfigBySlug(collectionSlug as string, config.collections)\n\n if (!entityConfig) throw new APIError('Bad Request', 400)\n\n const docPromise = isGlobal\n ? payload.findGlobal({\n depth: 0,\n fallbackLocale: undefined,\n locale: locale as any,\n overrideAccess,\n req,\n slug: args.globalSlug as GlobalSlug,\n })\n : payload.findByID({\n collection: collectionSlug as CollectionSlug,\n depth: 0,\n fallbackLocale: undefined,\n id: id as number | string,\n locale: locale as any,\n overrideAccess,\n req,\n })\n\n return {\n config: entityConfig,\n doc: (await docPromise) as any,\n }\n}\n"],"names":["APIError","findConfigBySlug","slug","enities","find","entity","findEntityWithConfig","args","collectionSlug","globalSlug","id","locale","overrideAccess","req","payload","config","isGlobal","entityConfig","globals","collections","docPromise","findGlobal","depth","fallbackLocale","undefined","findByID","collection","doc"],"mappings":"AAQA,SAASA,QAAQ,QAAQ,UAAS;AAWlC,MAAMC,mBAAmB,CACvBC,MACAC,UACGA,QAAQC,IAAI,CAAC,CAACC,SAAWA,OAAOH,IAAI,KAAKA;AAE9C,OAAO,MAAMI,uBAAuB,OAClCC;IAKA,MAAM,EAAEC,cAAc,EAAEC,UAAU,EAAEC,EAAE,EAAEC,MAAM,EAAEC,cAAc,EAAEC,GAAG,EAAE,GAAGN;IAExE,IAAI,CAACC,kBAAkB,CAACC,YAAY,MAAM,IAAIT,SAAS,eAAe;IAEtE,MAAM,EAAEc,OAAO,EAAE,GAAGD;IAEpB,MAAM,EAAEE,MAAM,EAAE,GAAGD;IAEnB,MAAME,WAAW,CAAC,CAACP;IAEnB,IAAI,CAACO,YAAY,CAACN,IAAI,MAAM,IAAIV,SAAS,eAAe;IAExD,MAAMiB,eAAeD,WACjBf,iBAAiBQ,YAAYM,OAAOG,OAAO,IAC3CjB,iBAAiBO,gBAA0BO,OAAOI,WAAW;IAEjE,IAAI,CAACF,cAAc,MAAM,IAAIjB,SAAS,eAAe;IAErD,MAAMoB,aAAaJ,WACfF,QAAQO,UAAU,CAAC;QACjBC,OAAO;QACPC,gBAAgBC;QAChBb,QAAQA;QACRC;QACAC;QACAX,MAAMK,KAAKE,UAAU;IACvB,KACAK,QAAQW,QAAQ,CAAC;QACfC,YAAYlB;QACZc,OAAO;QACPC,gBAAgBC;QAChBd,IAAIA;QACJC,QAAQA;QACRC;QACAC;IACF;IAEJ,OAAO;QACLE,QAAQE;QACRU,KAAM,MAAMP;IACd;AACF,EAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import he from 'he';
|
|
2
|
+
import { APIError } from 'payload';
|
|
3
|
+
import { findEntityWithConfig } from './findEntityWithConfig';
|
|
4
|
+
import { traverseFields } from './traverseFields';
|
|
5
|
+
import { updateEntity } from './updateEntity';
|
|
6
|
+
export const translateOperation = async (args)=>{
|
|
7
|
+
const req = 'req' in args ? args.req : {
|
|
8
|
+
payload: args.payload
|
|
9
|
+
};
|
|
10
|
+
const { collectionSlug, globalSlug, id, locale, localeFrom, overrideAccess } = args;
|
|
11
|
+
const { config, doc: dataFrom } = await findEntityWithConfig({
|
|
12
|
+
collectionSlug,
|
|
13
|
+
globalSlug,
|
|
14
|
+
id,
|
|
15
|
+
locale: localeFrom,
|
|
16
|
+
req
|
|
17
|
+
});
|
|
18
|
+
const resolver = (req.payload.config.custom?.translator?.resolvers ?? []).find((each)=>each.key === args.resolver);
|
|
19
|
+
if (!resolver) throw new APIError(`Resolver with the key ${args.resolver} was not found`);
|
|
20
|
+
const valuesToTranslate = [];
|
|
21
|
+
let translatedData = args.data;
|
|
22
|
+
if (!translatedData) {
|
|
23
|
+
const { doc } = await findEntityWithConfig({
|
|
24
|
+
collectionSlug,
|
|
25
|
+
globalSlug,
|
|
26
|
+
id,
|
|
27
|
+
locale,
|
|
28
|
+
overrideAccess,
|
|
29
|
+
req
|
|
30
|
+
});
|
|
31
|
+
translatedData = doc;
|
|
32
|
+
}
|
|
33
|
+
traverseFields({
|
|
34
|
+
dataFrom,
|
|
35
|
+
emptyOnly: args.emptyOnly,
|
|
36
|
+
fields: config.fields,
|
|
37
|
+
translatedData,
|
|
38
|
+
valuesToTranslate
|
|
39
|
+
});
|
|
40
|
+
const resolveResult = await resolver.resolve({
|
|
41
|
+
localeFrom: args.localeFrom,
|
|
42
|
+
localeTo: args.locale,
|
|
43
|
+
req,
|
|
44
|
+
texts: valuesToTranslate.map((each)=>each.value)
|
|
45
|
+
});
|
|
46
|
+
let result;
|
|
47
|
+
if (!resolveResult.success) {
|
|
48
|
+
result = {
|
|
49
|
+
success: false
|
|
50
|
+
};
|
|
51
|
+
} else {
|
|
52
|
+
resolveResult.translatedTexts.forEach((translated, index)=>{
|
|
53
|
+
const formattedValue = he.decode(translated);
|
|
54
|
+
valuesToTranslate[index].onTranslate(formattedValue);
|
|
55
|
+
});
|
|
56
|
+
if (args.update) {
|
|
57
|
+
await updateEntity({
|
|
58
|
+
collectionSlug,
|
|
59
|
+
data: translatedData,
|
|
60
|
+
depth: 0,
|
|
61
|
+
globalSlug,
|
|
62
|
+
id,
|
|
63
|
+
locale,
|
|
64
|
+
overrideAccess,
|
|
65
|
+
req
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
result = {
|
|
69
|
+
success: true,
|
|
70
|
+
translatedData
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
//# sourceMappingURL=operation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/translate/operation.ts"],"sourcesContent":["import he from 'he'\nimport { APIError, type Payload, type PayloadRequest } from 'payload'\n\nimport type { TranslateResolver } from '../resolvers/types'\nimport { findEntityWithConfig } from './findEntityWithConfig'\nimport { traverseFields } from './traverseFields'\nimport type { TranslateArgs, TranslateResult, ValueToTranslate } from './types'\nimport { updateEntity } from './updateEntity'\n\nexport type TranslateOperationArgs = (\n | {\n payload: Payload\n }\n | {\n req: PayloadRequest\n }\n) &\n TranslateArgs\n\nexport const translateOperation = async (args: TranslateOperationArgs) => {\n const req: PayloadRequest =\n 'req' in args\n ? args.req\n : ({\n payload: args.payload,\n } as PayloadRequest)\n\n const { collectionSlug, globalSlug, id, locale, localeFrom, overrideAccess } = args\n\n const { config, doc: dataFrom } = await findEntityWithConfig({\n collectionSlug,\n globalSlug,\n id,\n locale: localeFrom,\n req,\n })\n\n const resolver = (\n (req.payload.config.custom?.translator?.resolvers as TranslateResolver[]) ?? []\n ).find((each) => each.key === args.resolver)\n\n if (!resolver) throw new APIError(`Resolver with the key ${args.resolver} was not found`)\n\n const valuesToTranslate: ValueToTranslate[] = []\n\n let translatedData = args.data\n\n if (!translatedData) {\n const { doc } = await findEntityWithConfig({\n collectionSlug,\n globalSlug,\n id,\n locale,\n overrideAccess,\n req,\n })\n\n translatedData = doc\n }\n\n traverseFields({\n dataFrom,\n emptyOnly: args.emptyOnly,\n fields: config.fields,\n translatedData,\n valuesToTranslate,\n })\n\n const resolveResult = await resolver.resolve({\n localeFrom: args.localeFrom,\n localeTo: args.locale,\n req,\n texts: valuesToTranslate.map((each) => each.value),\n })\n\n let result: TranslateResult\n\n if (!resolveResult.success) {\n result = {\n success: false,\n }\n } else {\n resolveResult.translatedTexts.forEach((translated, index) => {\n const formattedValue = he.decode(translated)\n\n valuesToTranslate[index].onTranslate(formattedValue)\n })\n\n if (args.update) {\n await updateEntity({\n collectionSlug,\n data: translatedData,\n depth: 0,\n globalSlug,\n id,\n locale,\n overrideAccess,\n req,\n })\n }\n\n result = {\n success: true,\n translatedData,\n }\n }\n\n return result\n}\n"],"names":["he","APIError","findEntityWithConfig","traverseFields","updateEntity","translateOperation","args","req","payload","collectionSlug","globalSlug","id","locale","localeFrom","overrideAccess","config","doc","dataFrom","resolver","custom","translator","resolvers","find","each","key","valuesToTranslate","translatedData","data","emptyOnly","fields","resolveResult","resolve","localeTo","texts","map","value","result","success","translatedTexts","forEach","translated","index","formattedValue","decode","onTranslate","update","depth"],"mappings":"AAAA,OAAOA,QAAQ,KAAI;AACnB,SAASC,QAAQ,QAA2C,UAAS;AAGrE,SAASC,oBAAoB,QAAQ,yBAAwB;AAC7D,SAASC,cAAc,QAAQ,mBAAkB;AAEjD,SAASC,YAAY,QAAQ,iBAAgB;AAY7C,OAAO,MAAMC,qBAAqB,OAAOC;IACvC,MAAMC,MACJ,SAASD,OACLA,KAAKC,GAAG,GACP;QACCC,SAASF,KAAKE,OAAO;IACvB;IAEN,MAAM,EAAEC,cAAc,EAAEC,UAAU,EAAEC,EAAE,EAAEC,MAAM,EAAEC,UAAU,EAAEC,cAAc,EAAE,GAAGR;IAE/E,MAAM,EAAES,MAAM,EAAEC,KAAKC,QAAQ,EAAE,GAAG,MAAMf,qBAAqB;QAC3DO;QACAC;QACAC;QACAC,QAAQC;QACRN;IACF;IAEA,MAAMW,WAAW,AACf,CAAA,AAACX,IAAIC,OAAO,CAACO,MAAM,CAACI,MAAM,EAAEC,YAAYC,aAAqC,EAAE,AAAD,EAC9EC,IAAI,CAAC,CAACC,OAASA,KAAKC,GAAG,KAAKlB,KAAKY,QAAQ;IAE3C,IAAI,CAACA,UAAU,MAAM,IAAIjB,SAAS,CAAC,sBAAsB,EAAEK,KAAKY,QAAQ,CAAC,cAAc,CAAC;IAExF,MAAMO,oBAAwC,EAAE;IAEhD,IAAIC,iBAAiBpB,KAAKqB,IAAI;IAE9B,IAAI,CAACD,gBAAgB;QACnB,MAAM,EAAEV,GAAG,EAAE,GAAG,MAAMd,qBAAqB;YACzCO;YACAC;YACAC;YACAC;YACAE;YACAP;QACF;QAEAmB,iBAAiBV;IACnB;IAEAb,eAAe;QACbc;QACAW,WAAWtB,KAAKsB,SAAS;QACzBC,QAAQd,OAAOc,MAAM;QACrBH;QACAD;IACF;IAEA,MAAMK,gBAAgB,MAAMZ,SAASa,OAAO,CAAC;QAC3ClB,YAAYP,KAAKO,UAAU;QAC3BmB,UAAU1B,KAAKM,MAAM;QACrBL;QACA0B,OAAOR,kBAAkBS,GAAG,CAAC,CAACX,OAASA,KAAKY,KAAK;IACnD;IAEA,IAAIC;IAEJ,IAAI,CAACN,cAAcO,OAAO,EAAE;QAC1BD,SAAS;YACPC,SAAS;QACX;IACF,OAAO;QACLP,cAAcQ,eAAe,CAACC,OAAO,CAAC,CAACC,YAAYC;YACjD,MAAMC,iBAAiB1C,GAAG2C,MAAM,CAACH;YAEjCf,iBAAiB,CAACgB,MAAM,CAACG,WAAW,CAACF;QACvC;QAEA,IAAIpC,KAAKuC,MAAM,EAAE;YACf,MAAMzC,aAAa;gBACjBK;gBACAkB,MAAMD;gBACNoB,OAAO;gBACPpC;gBACAC;gBACAC;gBACAE;gBACAP;YACF;QACF;QAEA6B,SAAS;YACPC,SAAS;YACTX;QACF;IACF;IAEA,OAAOU;AACT,EAAC"}
|