@belocal/react 0.5.0 → 0.5.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/dist/index.cjs CHANGED
@@ -40,6 +40,8 @@ var useBelocalContext = () => {
40
40
  var useBelocal = () => {
41
41
  return useBelocalContext();
42
42
  };
43
+ var translationCache = /* @__PURE__ */ new Map();
44
+ var pendingRequests = /* @__PURE__ */ new Map();
43
45
  var Translate = ({
44
46
  text,
45
47
  lang,
@@ -59,13 +61,17 @@ var Translate = ({
59
61
  }
60
62
  return ctx;
61
63
  }, [context, user_context]);
62
- react.useEffect(() => {
63
- if (!targetLang) {
64
- setTranslatedText(text);
65
- return;
66
- }
64
+ const cacheKey = react.useMemo(() => {
65
+ return JSON.stringify({
66
+ text,
67
+ targetLang,
68
+ source_lang,
69
+ finalContext
70
+ });
71
+ }, [text, targetLang, source_lang, finalContext]);
72
+ const attachHandlers = (promise) => {
67
73
  setIsLoading(true);
68
- engine.translate(text, targetLang, source_lang, finalContext).then((translation) => {
74
+ promise.then((translation) => {
69
75
  setTranslatedText(translation);
70
76
  }).catch((error) => {
71
77
  console.error("Translation error:", error);
@@ -73,7 +79,33 @@ var Translate = ({
73
79
  }).finally(() => {
74
80
  setIsLoading(false);
75
81
  });
76
- }, [text, targetLang, source_lang, finalContext, engine]);
82
+ };
83
+ react.useEffect(() => {
84
+ if (!targetLang) {
85
+ setTranslatedText(text);
86
+ return;
87
+ }
88
+ const cachedTranslation = translationCache.get(cacheKey);
89
+ if (cachedTranslation) {
90
+ setTranslatedText(cachedTranslation);
91
+ return;
92
+ }
93
+ const pendingRequest = pendingRequests.get(cacheKey);
94
+ if (pendingRequest) {
95
+ attachHandlers(pendingRequest);
96
+ return;
97
+ }
98
+ const translationPromise = engine.translate(text, targetLang, source_lang, finalContext).then((translation) => {
99
+ translationCache.set(cacheKey, translation);
100
+ pendingRequests.delete(cacheKey);
101
+ return translation;
102
+ }).catch((error) => {
103
+ pendingRequests.delete(cacheKey);
104
+ throw error;
105
+ });
106
+ pendingRequests.set(cacheKey, translationPromise);
107
+ attachHandlers(translationPromise);
108
+ }, [text, targetLang, source_lang, finalContext, engine, cacheKey]);
77
109
  if (isLoading) {
78
110
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback || text });
79
111
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/BelocalProvider.tsx","../src/useBelocal.ts","../src/Translate.tsx"],"names":["createContext","useMemo","BelocalEngine","useContext","useState","useEffect","jsx","Fragment"],"mappings":"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","file":"index.cjs","sourcesContent":["import React, { createContext, useContext, useMemo } from 'react';\nimport { BelocalEngine } from '@belocal/js-sdk';\n\nexport type BelocalProviderProps = {\n apiKey: string;\n baseUrl?: string;\n defaultLang?: string;\n batchWindowMs?: number;\n timeoutMs?: number;\n children: React.ReactNode;\n};\n\ntype BelocalContextType = {\n engine: BelocalEngine;\n defaultLang?: string;\n};\n\nconst BelocalContext = createContext<BelocalContextType | null>(null);\n\nexport const BelocalProvider: React.FC<BelocalProviderProps> = ({\n apiKey,\n baseUrl,\n defaultLang,\n batchWindowMs,\n timeoutMs,\n children,\n}) => {\n const contextValue = useMemo(() => {\n const engine = new BelocalEngine({\n apiKey,\n baseUrl,\n batchWindowMs,\n timeoutMs,\n });\n\n return {\n engine,\n defaultLang,\n };\n }, [apiKey, baseUrl, defaultLang, batchWindowMs, timeoutMs]);\n\n return (\n <BelocalContext.Provider value={contextValue}>\n {children}\n </BelocalContext.Provider>\n );\n};\n\nexport const useBelocalContext = () => {\n const context = useContext(BelocalContext);\n if (!context) {\n throw new Error('useBelocalContext must be used within a BelocalProvider');\n }\n return context;\n};\n\n","import { useBelocalContext } from './BelocalProvider';\n\nexport const useBelocal = () => {\n return useBelocalContext();\n};\n\n","import React, { useState, useEffect, useMemo } from 'react';\nimport { useBelocal } from './useBelocal';\n\nexport type TranslateProps = {\n text: string;\n lang?: string;\n source_lang?: string;\n context?: Record<string, string>;\n user_context?: string;\n fallback?: string;\n};\n\nexport const Translate: React.FC<TranslateProps> = ({\n text,\n lang,\n source_lang,\n context,\n user_context,\n fallback,\n}) => {\n const { engine, defaultLang } = useBelocal();\n const [translatedText, setTranslatedText] = useState<string>(fallback || text);\n const [isLoading, setIsLoading] = useState<boolean>(false);\n\n // Выбираем язык: props.lang имеет приоритет над defaultLang\n const targetLang = lang ?? defaultLang;\n\n // Формируем финальный контекст\n const finalContext = useMemo(() => {\n const ctx: Record<string, string> = { ...context };\n if (user_context) {\n ctx.user_context = user_context;\n }\n return ctx;\n }, [context, user_context]);\n\n useEffect(() => {\n if (!targetLang) {\n // Если язык не указан, просто возвращаем исходный текст\n setTranslatedText(text);\n return;\n }\n\n setIsLoading(true);\n \n engine\n .translate(text, targetLang, source_lang, finalContext)\n .then((translation) => {\n setTranslatedText(translation);\n })\n .catch((error) => {\n console.error('Translation error:', error);\n // При ошибке возвращаем исходный текст\n setTranslatedText(text);\n })\n .finally(() => {\n setIsLoading(false);\n });\n }, [text, targetLang, source_lang, finalContext, engine]);\n\n // Пока идёт запрос рендерим fallback или исходный text\n if (isLoading) {\n return <>{fallback || text}</>;\n }\n\n return <>{translatedText}</>;\n};\n\n"]}
1
+ {"version":3,"sources":["../src/BelocalProvider.tsx","../src/useBelocal.ts","../src/Translate.tsx"],"names":["createContext","useMemo","BelocalEngine","useContext","useState","useEffect","jsx","Fragment"],"mappings":"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","file":"index.cjs","sourcesContent":["import React, { createContext, useContext, useMemo } from 'react';\nimport { BelocalEngine } from '@belocal/js-sdk';\n\nexport type BelocalProviderProps = {\n apiKey: string;\n baseUrl?: string;\n defaultLang?: string;\n batchWindowMs?: number;\n timeoutMs?: number;\n children: React.ReactNode;\n};\n\ntype BelocalContextType = {\n engine: BelocalEngine;\n defaultLang?: string;\n};\n\nconst BelocalContext = createContext<BelocalContextType | null>(null);\n\nexport const BelocalProvider: React.FC<BelocalProviderProps> = ({\n apiKey,\n baseUrl,\n defaultLang,\n batchWindowMs,\n timeoutMs,\n children,\n}) => {\n const contextValue = useMemo(() => {\n const engine = new BelocalEngine({\n apiKey,\n baseUrl,\n batchWindowMs,\n timeoutMs,\n });\n\n return {\n engine,\n defaultLang,\n };\n }, [apiKey, baseUrl, defaultLang, batchWindowMs, timeoutMs]);\n\n return (\n <BelocalContext.Provider value={contextValue}>\n {children}\n </BelocalContext.Provider>\n );\n};\n\nexport const useBelocalContext = () => {\n const context = useContext(BelocalContext);\n if (!context) {\n throw new Error('useBelocalContext must be used within a BelocalProvider');\n }\n return context;\n};\n\n","import { useBelocalContext } from './BelocalProvider';\n\nexport const useBelocal = () => {\n return useBelocalContext();\n};\n\n","import React, { useState, useEffect, useMemo } from 'react';\nimport { useBelocal } from './useBelocal';\n\nconst translationCache = new Map<string, string>();\nconst pendingRequests = new Map<string, Promise<string>>();\n\nexport type TranslateProps = {\n text: string;\n lang?: string;\n source_lang?: string;\n context?: Record<string, string>;\n user_context?: string;\n fallback?: string;\n};\n\nexport const Translate: React.FC<TranslateProps> = ({\n text,\n lang,\n source_lang,\n context,\n user_context,\n fallback,\n}) => {\n const { engine, defaultLang } = useBelocal();\n const [translatedText, setTranslatedText] = useState<string>(fallback || text);\n const [isLoading, setIsLoading] = useState<boolean>(false);\n\n const targetLang = lang ?? defaultLang;\n\n const finalContext = useMemo(() => {\n const ctx: Record<string, string> = { ...context };\n if (user_context) {\n ctx.user_context = user_context;\n }\n return ctx;\n }, [context, user_context]);\n\n const cacheKey = useMemo(() => {\n return JSON.stringify({\n text,\n targetLang,\n source_lang,\n finalContext,\n });\n }, [text, targetLang, source_lang, finalContext]);\n\n const attachHandlers = (promise: Promise<string>) => {\n setIsLoading(true);\n promise\n .then((translation) => {\n setTranslatedText(translation);\n })\n .catch((error) => {\n console.error('Translation error:', error);\n setTranslatedText(text);\n })\n .finally(() => {\n setIsLoading(false);\n });\n };\n\n useEffect(() => {\n if (!targetLang) {\n setTranslatedText(text);\n return;\n }\n\n const cachedTranslation = translationCache.get(cacheKey);\n if (cachedTranslation) {\n setTranslatedText(cachedTranslation);\n return;\n }\n\n const pendingRequest = pendingRequests.get(cacheKey);\n if (pendingRequest) {\n attachHandlers(pendingRequest);\n return;\n }\n\n const translationPromise = engine\n .translate(text, targetLang, source_lang, finalContext)\n .then((translation) => {\n translationCache.set(cacheKey, translation);\n pendingRequests.delete(cacheKey);\n return translation;\n })\n .catch((error) => {\n pendingRequests.delete(cacheKey);\n throw error;\n });\n\n pendingRequests.set(cacheKey, translationPromise);\n \n attachHandlers(translationPromise);\n }, [text, targetLang, source_lang, finalContext, engine, cacheKey]);\n\n if (isLoading) {\n return <>{fallback || text}</>;\n }\n\n return <>{translatedText}</>;\n};\n\n"]}
package/dist/index.js CHANGED
@@ -38,6 +38,8 @@ var useBelocalContext = () => {
38
38
  var useBelocal = () => {
39
39
  return useBelocalContext();
40
40
  };
41
+ var translationCache = /* @__PURE__ */ new Map();
42
+ var pendingRequests = /* @__PURE__ */ new Map();
41
43
  var Translate = ({
42
44
  text,
43
45
  lang,
@@ -57,13 +59,17 @@ var Translate = ({
57
59
  }
58
60
  return ctx;
59
61
  }, [context, user_context]);
60
- useEffect(() => {
61
- if (!targetLang) {
62
- setTranslatedText(text);
63
- return;
64
- }
62
+ const cacheKey = useMemo(() => {
63
+ return JSON.stringify({
64
+ text,
65
+ targetLang,
66
+ source_lang,
67
+ finalContext
68
+ });
69
+ }, [text, targetLang, source_lang, finalContext]);
70
+ const attachHandlers = (promise) => {
65
71
  setIsLoading(true);
66
- engine.translate(text, targetLang, source_lang, finalContext).then((translation) => {
72
+ promise.then((translation) => {
67
73
  setTranslatedText(translation);
68
74
  }).catch((error) => {
69
75
  console.error("Translation error:", error);
@@ -71,7 +77,33 @@ var Translate = ({
71
77
  }).finally(() => {
72
78
  setIsLoading(false);
73
79
  });
74
- }, [text, targetLang, source_lang, finalContext, engine]);
80
+ };
81
+ useEffect(() => {
82
+ if (!targetLang) {
83
+ setTranslatedText(text);
84
+ return;
85
+ }
86
+ const cachedTranslation = translationCache.get(cacheKey);
87
+ if (cachedTranslation) {
88
+ setTranslatedText(cachedTranslation);
89
+ return;
90
+ }
91
+ const pendingRequest = pendingRequests.get(cacheKey);
92
+ if (pendingRequest) {
93
+ attachHandlers(pendingRequest);
94
+ return;
95
+ }
96
+ const translationPromise = engine.translate(text, targetLang, source_lang, finalContext).then((translation) => {
97
+ translationCache.set(cacheKey, translation);
98
+ pendingRequests.delete(cacheKey);
99
+ return translation;
100
+ }).catch((error) => {
101
+ pendingRequests.delete(cacheKey);
102
+ throw error;
103
+ });
104
+ pendingRequests.set(cacheKey, translationPromise);
105
+ attachHandlers(translationPromise);
106
+ }, [text, targetLang, source_lang, finalContext, engine, cacheKey]);
75
107
  if (isLoading) {
76
108
  return /* @__PURE__ */ jsx(Fragment, { children: fallback || text });
77
109
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/BelocalProvider.tsx","../src/useBelocal.ts","../src/Translate.tsx"],"names":["useMemo","jsx"],"mappings":";;;;;AAiBA,IAAM,cAAA,GAAiB,cAAyC,IAAI,CAAA;AAE7D,IAAM,kBAAkD,CAAC;AAAA,EAC9D,MAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,KAAM;AACJ,EAAA,MAAM,YAAA,GAAe,QAAQ,MAAM;AACjC,IAAA,MAAM,MAAA,GAAS,IAAI,aAAA,CAAc;AAAA,MAC/B,MAAA;AAAA,MACA,OAAA;AAAA,MACA,aAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAA,OAAO;AAAA,MACL,MAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF,GAAG,CAAC,MAAA,EAAQ,SAAS,WAAA,EAAa,aAAA,EAAe,SAAS,CAAC,CAAA;AAE3D,EAAA,2BACG,cAAA,CAAe,QAAA,EAAf,EAAwB,KAAA,EAAO,cAC7B,QAAA,EACH,CAAA;AAEJ;AAEO,IAAM,oBAAoB,MAAM;AACrC,EAAA,MAAM,OAAA,GAAU,WAAW,cAAc,CAAA;AACzC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,yDAAyD,CAAA;AAAA,EAC3E;AACA,EAAA,OAAO,OAAA;AACT,CAAA;;;ACpDO,IAAM,aAAa,MAAM;AAC9B,EAAA,OAAO,iBAAA,EAAkB;AAC3B;ACQO,IAAM,YAAsC,CAAC;AAAA,EAClD,IAAA;AAAA,EACA,IAAA;AAAA,EACA,WAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AAAA,EACA;AACF,CAAA,KAAM;AACJ,EAAA,MAAM,EAAE,MAAA,EAAQ,WAAA,EAAY,GAAI,UAAA,EAAW;AAC3C,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,QAAA,CAAiB,YAAY,IAAI,CAAA;AAC7E,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAkB,KAAK,CAAA;AAGzD,EAAA,MAAM,aAAa,IAAA,IAAQ,WAAA;AAG3B,EAAA,MAAM,YAAA,GAAeA,QAAQ,MAAM;AACjC,IAAA,MAAM,GAAA,GAA8B,EAAE,GAAG,OAAA,EAAQ;AACjD,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,GAAA,CAAI,YAAA,GAAe,YAAA;AAAA,IACrB;AACA,IAAA,OAAO,GAAA;AAAA,EACT,CAAA,EAAG,CAAC,OAAA,EAAS,YAAY,CAAC,CAAA;AAE1B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,UAAA,EAAY;AAEf,MAAA,iBAAA,CAAkB,IAAI,CAAA;AACtB,MAAA;AAAA,IACF;AAEA,IAAA,YAAA,CAAa,IAAI,CAAA;AAEjB,IAAA,MAAA,CACG,SAAA,CAAU,MAAM,UAAA,EAAY,WAAA,EAAa,YAAY,CAAA,CACrD,IAAA,CAAK,CAAC,WAAA,KAAgB;AACrB,MAAA,iBAAA,CAAkB,WAAW,CAAA;AAAA,IAC/B,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,KAAA,KAAU;AAChB,MAAA,OAAA,CAAQ,KAAA,CAAM,sBAAsB,KAAK,CAAA;AAEzC,MAAA,iBAAA,CAAkB,IAAI,CAAA;AAAA,IACxB,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,YAAA,CAAa,KAAK,CAAA;AAAA,IACpB,CAAC,CAAA;AAAA,EACL,GAAG,CAAC,IAAA,EAAM,YAAY,WAAA,EAAa,YAAA,EAAc,MAAM,CAAC,CAAA;AAGxD,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,uBAAOC,GAAAA,CAAA,QAAA,EAAA,EAAG,QAAA,EAAA,QAAA,IAAY,IAAA,EAAK,CAAA;AAAA,EAC7B;AAEA,EAAA,uBAAOA,GAAAA,CAAA,QAAA,EAAA,EAAG,QAAA,EAAA,cAAA,EAAe,CAAA;AAC3B","file":"index.js","sourcesContent":["import React, { createContext, useContext, useMemo } from 'react';\nimport { BelocalEngine } from '@belocal/js-sdk';\n\nexport type BelocalProviderProps = {\n apiKey: string;\n baseUrl?: string;\n defaultLang?: string;\n batchWindowMs?: number;\n timeoutMs?: number;\n children: React.ReactNode;\n};\n\ntype BelocalContextType = {\n engine: BelocalEngine;\n defaultLang?: string;\n};\n\nconst BelocalContext = createContext<BelocalContextType | null>(null);\n\nexport const BelocalProvider: React.FC<BelocalProviderProps> = ({\n apiKey,\n baseUrl,\n defaultLang,\n batchWindowMs,\n timeoutMs,\n children,\n}) => {\n const contextValue = useMemo(() => {\n const engine = new BelocalEngine({\n apiKey,\n baseUrl,\n batchWindowMs,\n timeoutMs,\n });\n\n return {\n engine,\n defaultLang,\n };\n }, [apiKey, baseUrl, defaultLang, batchWindowMs, timeoutMs]);\n\n return (\n <BelocalContext.Provider value={contextValue}>\n {children}\n </BelocalContext.Provider>\n );\n};\n\nexport const useBelocalContext = () => {\n const context = useContext(BelocalContext);\n if (!context) {\n throw new Error('useBelocalContext must be used within a BelocalProvider');\n }\n return context;\n};\n\n","import { useBelocalContext } from './BelocalProvider';\n\nexport const useBelocal = () => {\n return useBelocalContext();\n};\n\n","import React, { useState, useEffect, useMemo } from 'react';\nimport { useBelocal } from './useBelocal';\n\nexport type TranslateProps = {\n text: string;\n lang?: string;\n source_lang?: string;\n context?: Record<string, string>;\n user_context?: string;\n fallback?: string;\n};\n\nexport const Translate: React.FC<TranslateProps> = ({\n text,\n lang,\n source_lang,\n context,\n user_context,\n fallback,\n}) => {\n const { engine, defaultLang } = useBelocal();\n const [translatedText, setTranslatedText] = useState<string>(fallback || text);\n const [isLoading, setIsLoading] = useState<boolean>(false);\n\n // Выбираем язык: props.lang имеет приоритет над defaultLang\n const targetLang = lang ?? defaultLang;\n\n // Формируем финальный контекст\n const finalContext = useMemo(() => {\n const ctx: Record<string, string> = { ...context };\n if (user_context) {\n ctx.user_context = user_context;\n }\n return ctx;\n }, [context, user_context]);\n\n useEffect(() => {\n if (!targetLang) {\n // Если язык не указан, просто возвращаем исходный текст\n setTranslatedText(text);\n return;\n }\n\n setIsLoading(true);\n \n engine\n .translate(text, targetLang, source_lang, finalContext)\n .then((translation) => {\n setTranslatedText(translation);\n })\n .catch((error) => {\n console.error('Translation error:', error);\n // При ошибке возвращаем исходный текст\n setTranslatedText(text);\n })\n .finally(() => {\n setIsLoading(false);\n });\n }, [text, targetLang, source_lang, finalContext, engine]);\n\n // Пока идёт запрос рендерим fallback или исходный text\n if (isLoading) {\n return <>{fallback || text}</>;\n }\n\n return <>{translatedText}</>;\n};\n\n"]}
1
+ {"version":3,"sources":["../src/BelocalProvider.tsx","../src/useBelocal.ts","../src/Translate.tsx"],"names":["useMemo","jsx"],"mappings":"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","file":"index.js","sourcesContent":["import React, { createContext, useContext, useMemo } from 'react';\nimport { BelocalEngine } from '@belocal/js-sdk';\n\nexport type BelocalProviderProps = {\n apiKey: string;\n baseUrl?: string;\n defaultLang?: string;\n batchWindowMs?: number;\n timeoutMs?: number;\n children: React.ReactNode;\n};\n\ntype BelocalContextType = {\n engine: BelocalEngine;\n defaultLang?: string;\n};\n\nconst BelocalContext = createContext<BelocalContextType | null>(null);\n\nexport const BelocalProvider: React.FC<BelocalProviderProps> = ({\n apiKey,\n baseUrl,\n defaultLang,\n batchWindowMs,\n timeoutMs,\n children,\n}) => {\n const contextValue = useMemo(() => {\n const engine = new BelocalEngine({\n apiKey,\n baseUrl,\n batchWindowMs,\n timeoutMs,\n });\n\n return {\n engine,\n defaultLang,\n };\n }, [apiKey, baseUrl, defaultLang, batchWindowMs, timeoutMs]);\n\n return (\n <BelocalContext.Provider value={contextValue}>\n {children}\n </BelocalContext.Provider>\n );\n};\n\nexport const useBelocalContext = () => {\n const context = useContext(BelocalContext);\n if (!context) {\n throw new Error('useBelocalContext must be used within a BelocalProvider');\n }\n return context;\n};\n\n","import { useBelocalContext } from './BelocalProvider';\n\nexport const useBelocal = () => {\n return useBelocalContext();\n};\n\n","import React, { useState, useEffect, useMemo } from 'react';\nimport { useBelocal } from './useBelocal';\n\nconst translationCache = new Map<string, string>();\nconst pendingRequests = new Map<string, Promise<string>>();\n\nexport type TranslateProps = {\n text: string;\n lang?: string;\n source_lang?: string;\n context?: Record<string, string>;\n user_context?: string;\n fallback?: string;\n};\n\nexport const Translate: React.FC<TranslateProps> = ({\n text,\n lang,\n source_lang,\n context,\n user_context,\n fallback,\n}) => {\n const { engine, defaultLang } = useBelocal();\n const [translatedText, setTranslatedText] = useState<string>(fallback || text);\n const [isLoading, setIsLoading] = useState<boolean>(false);\n\n const targetLang = lang ?? defaultLang;\n\n const finalContext = useMemo(() => {\n const ctx: Record<string, string> = { ...context };\n if (user_context) {\n ctx.user_context = user_context;\n }\n return ctx;\n }, [context, user_context]);\n\n const cacheKey = useMemo(() => {\n return JSON.stringify({\n text,\n targetLang,\n source_lang,\n finalContext,\n });\n }, [text, targetLang, source_lang, finalContext]);\n\n const attachHandlers = (promise: Promise<string>) => {\n setIsLoading(true);\n promise\n .then((translation) => {\n setTranslatedText(translation);\n })\n .catch((error) => {\n console.error('Translation error:', error);\n setTranslatedText(text);\n })\n .finally(() => {\n setIsLoading(false);\n });\n };\n\n useEffect(() => {\n if (!targetLang) {\n setTranslatedText(text);\n return;\n }\n\n const cachedTranslation = translationCache.get(cacheKey);\n if (cachedTranslation) {\n setTranslatedText(cachedTranslation);\n return;\n }\n\n const pendingRequest = pendingRequests.get(cacheKey);\n if (pendingRequest) {\n attachHandlers(pendingRequest);\n return;\n }\n\n const translationPromise = engine\n .translate(text, targetLang, source_lang, finalContext)\n .then((translation) => {\n translationCache.set(cacheKey, translation);\n pendingRequests.delete(cacheKey);\n return translation;\n })\n .catch((error) => {\n pendingRequests.delete(cacheKey);\n throw error;\n });\n\n pendingRequests.set(cacheKey, translationPromise);\n \n attachHandlers(translationPromise);\n }, [text, targetLang, source_lang, finalContext, engine, cacheKey]);\n\n if (isLoading) {\n return <>{fallback || text}</>;\n }\n\n return <>{translatedText}</>;\n};\n\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@belocal/react",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",