@belocal/react 0.5.1 → 0.5.2

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
@@ -48,11 +48,15 @@ var Translate = ({
48
48
  source_lang,
49
49
  context,
50
50
  user_context,
51
- fallback
51
+ fallback,
52
+ onSuccess,
53
+ onError,
54
+ dots
52
55
  }) => {
53
56
  const { engine, defaultLang } = useBelocal();
54
57
  const [translatedText, setTranslatedText] = react.useState(fallback || text);
55
58
  const [isLoading, setIsLoading] = react.useState(false);
59
+ const [dotCount, setDotCount] = react.useState(1);
56
60
  const targetLang = lang ?? defaultLang;
57
61
  const finalContext = react.useMemo(() => {
58
62
  const ctx = { ...context };
@@ -73,9 +77,11 @@ var Translate = ({
73
77
  setIsLoading(true);
74
78
  promise.then((translation) => {
75
79
  setTranslatedText(translation);
80
+ onSuccess?.(translation);
76
81
  }).catch((error) => {
77
82
  console.error("Translation error:", error);
78
83
  setTranslatedText(text);
84
+ onError?.(error instanceof Error ? error : new Error(String(error)));
79
85
  }).finally(() => {
80
86
  setIsLoading(false);
81
87
  });
@@ -106,6 +112,21 @@ var Translate = ({
106
112
  pendingRequests.set(cacheKey, translationPromise);
107
113
  attachHandlers(translationPromise);
108
114
  }, [text, targetLang, source_lang, finalContext, engine, cacheKey]);
115
+ react.useEffect(() => {
116
+ if (!isLoading || !dots) {
117
+ if (!isLoading) {
118
+ setDotCount(1);
119
+ }
120
+ return;
121
+ }
122
+ const interval = setInterval(() => {
123
+ setDotCount((prev) => prev >= 3 ? 1 : prev + 1);
124
+ }, 500);
125
+ return () => clearInterval(interval);
126
+ }, [isLoading, dots]);
127
+ if (isLoading && dots) {
128
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: ".".repeat(dotCount) });
129
+ }
109
130
  if (isLoading) {
110
131
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback || text });
111
132
  }
@@ -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\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"]}
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 onSuccess?: (translation: string) => void;\n onError?: (error: Error) => void;\n dots?: boolean;\n};\n\nexport const Translate: React.FC<TranslateProps> = ({\n text,\n lang,\n source_lang,\n context,\n user_context,\n fallback,\n onSuccess,\n onError,\n dots,\n}) => {\n const { engine, defaultLang } = useBelocal();\n const [translatedText, setTranslatedText] = useState<string>(fallback || text);\n const [isLoading, setIsLoading] = useState<boolean>(false);\n const [dotCount, setDotCount] = useState<number>(1);\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 onSuccess?.(translation);\n })\n .catch((error) => {\n console.error('Translation error:', error);\n setTranslatedText(text);\n onError?.(error instanceof Error ? error : new Error(String(error)));\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 useEffect(() => {\n if (!isLoading || !dots) {\n if (!isLoading) {\n setDotCount(1);\n }\n return;\n }\n\n const interval = setInterval(() => {\n setDotCount((prev) => (prev >= 3 ? 1 : prev + 1));\n }, 500);\n\n return () => clearInterval(interval);\n }, [isLoading, dots]);\n\n if (isLoading && dots) {\n return <>{'.'.repeat(dotCount)}</>;\n }\n\n if (isLoading) {\n return <>{fallback || text}</>;\n }\n\n return <>{translatedText}</>;\n};\n\n"]}
package/dist/index.d.cts CHANGED
@@ -23,6 +23,9 @@ type TranslateProps = {
23
23
  context?: Record<string, string>;
24
24
  user_context?: string;
25
25
  fallback?: string;
26
+ onSuccess?: (translation: string) => void;
27
+ onError?: (error: Error) => void;
28
+ dots?: boolean;
26
29
  };
27
30
  declare const Translate: React.FC<TranslateProps>;
28
31
 
package/dist/index.d.ts CHANGED
@@ -23,6 +23,9 @@ type TranslateProps = {
23
23
  context?: Record<string, string>;
24
24
  user_context?: string;
25
25
  fallback?: string;
26
+ onSuccess?: (translation: string) => void;
27
+ onError?: (error: Error) => void;
28
+ dots?: boolean;
26
29
  };
27
30
  declare const Translate: React.FC<TranslateProps>;
28
31
 
package/dist/index.js CHANGED
@@ -46,11 +46,15 @@ var Translate = ({
46
46
  source_lang,
47
47
  context,
48
48
  user_context,
49
- fallback
49
+ fallback,
50
+ onSuccess,
51
+ onError,
52
+ dots
50
53
  }) => {
51
54
  const { engine, defaultLang } = useBelocal();
52
55
  const [translatedText, setTranslatedText] = useState(fallback || text);
53
56
  const [isLoading, setIsLoading] = useState(false);
57
+ const [dotCount, setDotCount] = useState(1);
54
58
  const targetLang = lang ?? defaultLang;
55
59
  const finalContext = useMemo(() => {
56
60
  const ctx = { ...context };
@@ -71,9 +75,11 @@ var Translate = ({
71
75
  setIsLoading(true);
72
76
  promise.then((translation) => {
73
77
  setTranslatedText(translation);
78
+ onSuccess?.(translation);
74
79
  }).catch((error) => {
75
80
  console.error("Translation error:", error);
76
81
  setTranslatedText(text);
82
+ onError?.(error instanceof Error ? error : new Error(String(error)));
77
83
  }).finally(() => {
78
84
  setIsLoading(false);
79
85
  });
@@ -104,6 +110,21 @@ var Translate = ({
104
110
  pendingRequests.set(cacheKey, translationPromise);
105
111
  attachHandlers(translationPromise);
106
112
  }, [text, targetLang, source_lang, finalContext, engine, cacheKey]);
113
+ useEffect(() => {
114
+ if (!isLoading || !dots) {
115
+ if (!isLoading) {
116
+ setDotCount(1);
117
+ }
118
+ return;
119
+ }
120
+ const interval = setInterval(() => {
121
+ setDotCount((prev) => prev >= 3 ? 1 : prev + 1);
122
+ }, 500);
123
+ return () => clearInterval(interval);
124
+ }, [isLoading, dots]);
125
+ if (isLoading && dots) {
126
+ return /* @__PURE__ */ jsx(Fragment, { children: ".".repeat(dotCount) });
127
+ }
107
128
  if (isLoading) {
108
129
  return /* @__PURE__ */ jsx(Fragment, { children: fallback || text });
109
130
  }
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":"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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"]}
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;ACDA,IAAM,gBAAA,uBAAuB,GAAA,EAAoB;AACjD,IAAM,eAAA,uBAAsB,GAAA,EAA6B;AAclD,IAAM,YAAsC,CAAC;AAAA,EAClD,IAAA;AAAA,EACA,IAAA;AAAA,EACA,WAAA;AAAA,EACA,OAAA;AAAA,EACA,YAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;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;AACzD,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAiB,CAAC,CAAA;AAElD,EAAA,MAAM,aAAa,IAAA,IAAQ,WAAA;AAE3B,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,MAAM,QAAA,GAAWA,QAAQ,MAAM;AAC7B,IAAA,OAAO,KAAK,SAAA,CAAU;AAAA,MACpB,IAAA;AAAA,MACA,UAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH,GAAG,CAAC,IAAA,EAAM,UAAA,EAAY,WAAA,EAAa,YAAY,CAAC,CAAA;AAEhD,EAAA,MAAM,cAAA,GAAiB,CAAC,OAAA,KAA6B;AACnD,IAAA,YAAA,CAAa,IAAI,CAAA;AACjB,IAAA,OAAA,CACG,IAAA,CAAK,CAAC,WAAA,KAAgB;AACrB,MAAA,iBAAA,CAAkB,WAAW,CAAA;AAC7B,MAAA,SAAA,GAAY,WAAW,CAAA;AAAA,IACzB,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,KAAA,KAAU;AAChB,MAAA,OAAA,CAAQ,KAAA,CAAM,sBAAsB,KAAK,CAAA;AACzC,MAAA,iBAAA,CAAkB,IAAI,CAAA;AACtB,MAAA,OAAA,GAAU,KAAA,YAAiB,QAAQ,KAAA,GAAQ,IAAI,MAAM,MAAA,CAAO,KAAK,CAAC,CAAC,CAAA;AAAA,IACrE,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,YAAA,CAAa,KAAK,CAAA;AAAA,IACpB,CAAC,CAAA;AAAA,EACL,CAAA;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,UAAA,EAAY;AACf,MAAA,iBAAA,CAAkB,IAAI,CAAA;AACtB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,iBAAA,GAAoB,gBAAA,CAAiB,GAAA,CAAI,QAAQ,CAAA;AACvD,IAAA,IAAI,iBAAA,EAAmB;AACrB,MAAA,iBAAA,CAAkB,iBAAiB,CAAA;AACnC,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,cAAA,GAAiB,eAAA,CAAgB,GAAA,CAAI,QAAQ,CAAA;AACnD,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,cAAA,CAAe,cAAc,CAAA;AAC7B,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,kBAAA,GAAqB,MAAA,CACxB,SAAA,CAAU,IAAA,EAAM,UAAA,EAAY,aAAa,YAAY,CAAA,CACrD,IAAA,CAAK,CAAC,WAAA,KAAgB;AACrB,MAAA,gBAAA,CAAiB,GAAA,CAAI,UAAU,WAAW,CAAA;AAC1C,MAAA,eAAA,CAAgB,OAAO,QAAQ,CAAA;AAC/B,MAAA,OAAO,WAAA;AAAA,IACT,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,KAAA,KAAU;AAChB,MAAA,eAAA,CAAgB,OAAO,QAAQ,CAAA;AAC/B,MAAA,MAAM,KAAA;AAAA,IACR,CAAC,CAAA;AAEH,IAAA,eAAA,CAAgB,GAAA,CAAI,UAAU,kBAAkB,CAAA;AAEhD,IAAA,cAAA,CAAe,kBAAkB,CAAA;AAAA,EACnC,CAAA,EAAG,CAAC,IAAA,EAAM,UAAA,EAAY,aAAa,YAAA,EAAc,MAAA,EAAQ,QAAQ,CAAC,CAAA;AAElE,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,SAAA,IAAa,CAAC,IAAA,EAAM;AACvB,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,WAAA,CAAY,CAAC,CAAA;AAAA,MACf;AACA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,QAAA,GAAW,YAAY,MAAM;AACjC,MAAA,WAAA,CAAY,CAAC,IAAA,KAAU,IAAA,IAAQ,CAAA,GAAI,CAAA,GAAI,OAAO,CAAE,CAAA;AAAA,IAClD,GAAG,GAAG,CAAA;AAEN,IAAA,OAAO,MAAM,cAAc,QAAQ,CAAA;AAAA,EACrC,CAAA,EAAG,CAAC,SAAA,EAAW,IAAI,CAAC,CAAA;AAEpB,EAAA,IAAI,aAAa,IAAA,EAAM;AACrB,IAAA,uBAAOC,GAAAA,CAAA,QAAA,EAAA,EAAG,QAAA,EAAA,GAAA,CAAI,MAAA,CAAO,QAAQ,CAAA,EAAE,CAAA;AAAA,EACjC;AAEA,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,uBAAOA,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\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 onSuccess?: (translation: string) => void;\n onError?: (error: Error) => void;\n dots?: boolean;\n};\n\nexport const Translate: React.FC<TranslateProps> = ({\n text,\n lang,\n source_lang,\n context,\n user_context,\n fallback,\n onSuccess,\n onError,\n dots,\n}) => {\n const { engine, defaultLang } = useBelocal();\n const [translatedText, setTranslatedText] = useState<string>(fallback || text);\n const [isLoading, setIsLoading] = useState<boolean>(false);\n const [dotCount, setDotCount] = useState<number>(1);\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 onSuccess?.(translation);\n })\n .catch((error) => {\n console.error('Translation error:', error);\n setTranslatedText(text);\n onError?.(error instanceof Error ? error : new Error(String(error)));\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 useEffect(() => {\n if (!isLoading || !dots) {\n if (!isLoading) {\n setDotCount(1);\n }\n return;\n }\n\n const interval = setInterval(() => {\n setDotCount((prev) => (prev >= 3 ? 1 : prev + 1));\n }, 500);\n\n return () => clearInterval(interval);\n }, [isLoading, dots]);\n\n if (isLoading && dots) {\n return <>{'.'.repeat(dotCount)}</>;\n }\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.1",
3
+ "version": "0.5.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",