@belocal/react 0.5.3 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/dist/index.cjs +86 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +87 -65
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -84,7 +84,6 @@ The root provider component that initializes the Belocal engine.
|
|
|
84
84
|
| Prop | Type | Required | Description |
|
|
85
85
|
|------|------|----------|-------------|
|
|
86
86
|
| `apiKey` | `string` | ✅ | Your Belocal API key |
|
|
87
|
-
| `baseUrl` | `string` | ❌ | Custom API base URL |
|
|
88
87
|
| `defaultLang` | `string` | ❌ | Default language for translations |
|
|
89
88
|
| `children` | `React.ReactNode` | ✅ | Child components |
|
|
90
89
|
|
package/dist/index.cjs
CHANGED
|
@@ -8,7 +8,6 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
8
8
|
var BelocalContext = react.createContext(null);
|
|
9
9
|
var BelocalProvider = ({
|
|
10
10
|
apiKey,
|
|
11
|
-
baseUrl,
|
|
12
11
|
defaultLang,
|
|
13
12
|
batchWindowMs,
|
|
14
13
|
timeoutMs,
|
|
@@ -17,7 +16,6 @@ var BelocalProvider = ({
|
|
|
17
16
|
const contextValue = react.useMemo(() => {
|
|
18
17
|
const engine = new jsSdk.BelocalEngine({
|
|
19
18
|
apiKey,
|
|
20
|
-
baseUrl,
|
|
21
19
|
batchWindowMs,
|
|
22
20
|
timeoutMs
|
|
23
21
|
});
|
|
@@ -25,7 +23,7 @@ var BelocalProvider = ({
|
|
|
25
23
|
engine,
|
|
26
24
|
defaultLang
|
|
27
25
|
};
|
|
28
|
-
}, [apiKey,
|
|
26
|
+
}, [apiKey, batchWindowMs, timeoutMs]);
|
|
29
27
|
return /* @__PURE__ */ jsxRuntime.jsx(BelocalContext.Provider, { value: contextValue, children });
|
|
30
28
|
};
|
|
31
29
|
var useBelocalContext = () => {
|
|
@@ -40,83 +38,76 @@ var useBelocalContext = () => {
|
|
|
40
38
|
var useBelocal = () => {
|
|
41
39
|
return useBelocalContext();
|
|
42
40
|
};
|
|
43
|
-
var
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
var useTranslationContext = (context, user_context) => {
|
|
42
|
+
const finalContext = react.useMemo(() => {
|
|
43
|
+
const ctx = { ...context };
|
|
44
|
+
if (user_context) {
|
|
45
|
+
ctx.user_context = user_context;
|
|
46
|
+
}
|
|
47
|
+
return ctx;
|
|
48
|
+
}, [context, user_context]);
|
|
49
|
+
const finalContextKey = react.useMemo(() => {
|
|
50
|
+
const keys = Object.keys(finalContext).sort();
|
|
51
|
+
return keys.map((k) => `${k}:${finalContext[k]}`).join("|");
|
|
52
|
+
}, [finalContext]);
|
|
53
|
+
return { finalContext, finalContextKey };
|
|
54
|
+
};
|
|
55
|
+
var useTranslation = ({
|
|
46
56
|
text,
|
|
47
|
-
|
|
57
|
+
targetLang,
|
|
48
58
|
source_lang,
|
|
49
|
-
|
|
50
|
-
|
|
59
|
+
finalContext,
|
|
60
|
+
finalContextKey,
|
|
51
61
|
fallback,
|
|
52
62
|
onSuccess,
|
|
53
63
|
onError,
|
|
54
|
-
|
|
64
|
+
engine
|
|
55
65
|
}) => {
|
|
56
|
-
const { engine, defaultLang } = useBelocal();
|
|
57
66
|
const [translatedText, setTranslatedText] = react.useState(fallback || text);
|
|
58
67
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}, [
|
|
68
|
-
const cacheKey = react.useMemo(() => {
|
|
69
|
-
return JSON.stringify({
|
|
70
|
-
text,
|
|
71
|
-
targetLang,
|
|
72
|
-
source_lang,
|
|
73
|
-
finalContext
|
|
74
|
-
});
|
|
75
|
-
}, [text, targetLang, source_lang, finalContext]);
|
|
76
|
-
const attachHandlers = (promise) => {
|
|
77
|
-
setIsLoading(true);
|
|
78
|
-
promise.then((translation) => {
|
|
79
|
-
setTranslatedText(translation);
|
|
80
|
-
onSuccess?.(translation);
|
|
81
|
-
}).catch((error) => {
|
|
82
|
-
console.error("Translation error:", error);
|
|
83
|
-
setTranslatedText(text);
|
|
84
|
-
onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
85
|
-
}).finally(() => {
|
|
86
|
-
setIsLoading(false);
|
|
87
|
-
});
|
|
88
|
-
};
|
|
68
|
+
const requestIdRef = react.useRef(0);
|
|
69
|
+
const onSuccessRef = react.useRef(onSuccess);
|
|
70
|
+
const onErrorRef = react.useRef(onError);
|
|
71
|
+
react.useEffect(() => {
|
|
72
|
+
onSuccessRef.current = onSuccess;
|
|
73
|
+
}, [onSuccess]);
|
|
74
|
+
react.useEffect(() => {
|
|
75
|
+
onErrorRef.current = onError;
|
|
76
|
+
}, [onError]);
|
|
89
77
|
react.useEffect(() => {
|
|
90
78
|
if (!targetLang) {
|
|
91
79
|
setTranslatedText(text);
|
|
92
80
|
return;
|
|
93
81
|
}
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
attachHandlers(pendingRequest);
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
const translationPromise = engine.translate(text, targetLang, source_lang, finalContext).then((translation) => {
|
|
105
|
-
translationCache.set(cacheKey, translation);
|
|
106
|
-
pendingRequests.delete(cacheKey);
|
|
107
|
-
return translation;
|
|
82
|
+
const currentRequestId = ++requestIdRef.current;
|
|
83
|
+
setIsLoading(true);
|
|
84
|
+
engine.translate(text, targetLang, source_lang, finalContext).then((translation) => {
|
|
85
|
+
if (currentRequestId === requestIdRef.current) {
|
|
86
|
+
setTranslatedText(translation);
|
|
87
|
+
onSuccessRef.current?.(translation);
|
|
88
|
+
}
|
|
108
89
|
}).catch((error) => {
|
|
109
|
-
|
|
110
|
-
|
|
90
|
+
if (currentRequestId === requestIdRef.current) {
|
|
91
|
+
console.error("Translation error:", error);
|
|
92
|
+
setTranslatedText(text);
|
|
93
|
+
onErrorRef.current?.(error instanceof Error ? error : new Error(String(error)));
|
|
94
|
+
}
|
|
95
|
+
}).finally(() => {
|
|
96
|
+
if (currentRequestId === requestIdRef.current) {
|
|
97
|
+
setIsLoading(false);
|
|
98
|
+
}
|
|
111
99
|
});
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
100
|
+
return () => {
|
|
101
|
+
requestIdRef.current++;
|
|
102
|
+
};
|
|
103
|
+
}, [text, targetLang, source_lang, finalContextKey, engine]);
|
|
104
|
+
return { translatedText, isLoading };
|
|
105
|
+
};
|
|
106
|
+
var useLoadingDots = (isLoading, dots) => {
|
|
107
|
+
const [dotCount, setDotCount] = react.useState(1);
|
|
115
108
|
react.useEffect(() => {
|
|
116
109
|
if (!isLoading || !dots) {
|
|
117
|
-
|
|
118
|
-
setDotCount(1);
|
|
119
|
-
}
|
|
110
|
+
setDotCount(1);
|
|
120
111
|
return;
|
|
121
112
|
}
|
|
122
113
|
const interval = setInterval(() => {
|
|
@@ -125,7 +116,38 @@ var Translate = ({
|
|
|
125
116
|
return () => clearInterval(interval);
|
|
126
117
|
}, [isLoading, dots]);
|
|
127
118
|
if (isLoading && dots) {
|
|
128
|
-
return
|
|
119
|
+
return ".".repeat(dotCount);
|
|
120
|
+
}
|
|
121
|
+
return null;
|
|
122
|
+
};
|
|
123
|
+
var Translate = ({
|
|
124
|
+
text,
|
|
125
|
+
lang,
|
|
126
|
+
source_lang,
|
|
127
|
+
context,
|
|
128
|
+
user_context,
|
|
129
|
+
fallback,
|
|
130
|
+
onSuccess,
|
|
131
|
+
onError,
|
|
132
|
+
dots
|
|
133
|
+
}) => {
|
|
134
|
+
const { engine, defaultLang } = useBelocal();
|
|
135
|
+
const targetLang = lang ?? defaultLang;
|
|
136
|
+
const { finalContext, finalContextKey } = useTranslationContext(context, user_context);
|
|
137
|
+
const { translatedText, isLoading } = useTranslation({
|
|
138
|
+
text,
|
|
139
|
+
targetLang,
|
|
140
|
+
source_lang,
|
|
141
|
+
finalContext,
|
|
142
|
+
finalContextKey,
|
|
143
|
+
fallback,
|
|
144
|
+
onSuccess,
|
|
145
|
+
onError,
|
|
146
|
+
engine
|
|
147
|
+
});
|
|
148
|
+
const loadingDots = useLoadingDots(isLoading, dots);
|
|
149
|
+
if (loadingDots) {
|
|
150
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loadingDots });
|
|
129
151
|
}
|
|
130
152
|
if (isLoading) {
|
|
131
153
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback || text });
|
package/dist/index.cjs.map
CHANGED
|
@@ -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 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"]}
|
|
1
|
+
{"version":3,"sources":["../src/BelocalProvider.tsx","../src/useBelocal.ts","../src/hooks/useTranslationContext.ts","../src/hooks/useTranslation.ts","../src/hooks/useLoadingDots.ts","../src/Translate.tsx"],"names":["createContext","useMemo","BelocalEngine","useContext","useState","useRef","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 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 defaultLang,\n batchWindowMs,\n timeoutMs,\n children,\n}) => {\n const contextValue = useMemo(() => {\n const engine = new BelocalEngine({\n apiKey,\n batchWindowMs,\n timeoutMs,\n });\n\n return {\n engine,\n defaultLang,\n };\n }, [apiKey, 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 { useMemo } from 'react';\n\nexport const useTranslationContext = (\n context?: Record<string, string>,\n user_context?: string\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 finalContextKey = useMemo(() => {\n const keys = Object.keys(finalContext).sort();\n return keys.map((k) => `${k}:${finalContext[k]}`).join('|');\n }, [finalContext]);\n\n return { finalContext, finalContextKey };\n};\n\n","import { useState, useEffect, useRef } from 'react';\nimport { BelocalEngine } from '@belocal/js-sdk';\n\ntype UseTranslationParams = {\n text: string;\n targetLang?: string;\n source_lang?: string;\n finalContext: Record<string, string>;\n finalContextKey: string;\n fallback?: string;\n onSuccess?: (translation: string) => void;\n onError?: (error: Error) => void;\n engine: BelocalEngine;\n};\n\nexport const useTranslation = ({\n text,\n targetLang,\n source_lang,\n finalContext,\n finalContextKey,\n fallback,\n onSuccess,\n onError,\n engine,\n}: UseTranslationParams) => {\n const [translatedText, setTranslatedText] = useState<string>(fallback || text);\n const [isLoading, setIsLoading] = useState<boolean>(false);\n const requestIdRef = useRef(0);\n const onSuccessRef = useRef(onSuccess);\n const onErrorRef = useRef(onError);\n\n useEffect(() => {\n onSuccessRef.current = onSuccess;\n }, [onSuccess]);\n\n useEffect(() => {\n onErrorRef.current = onError;\n }, [onError]);\n\n useEffect(() => {\n if (!targetLang) {\n setTranslatedText(text);\n return;\n }\n\n const currentRequestId = ++requestIdRef.current;\n setIsLoading(true);\n\n engine\n .translate(text, targetLang, source_lang, finalContext)\n .then((translation) => {\n if (currentRequestId === requestIdRef.current) {\n setTranslatedText(translation);\n onSuccessRef.current?.(translation);\n }\n })\n .catch((error) => {\n if (currentRequestId === requestIdRef.current) {\n console.error('Translation error:', error);\n setTranslatedText(text);\n onErrorRef.current?.(error instanceof Error ? error : new Error(String(error)));\n }\n })\n .finally(() => {\n if (currentRequestId === requestIdRef.current) {\n setIsLoading(false);\n }\n });\n\n return () => {\n // При размонтировании или новом запросе увеличиваем ID, чтобы старые запросы игнорировались\n requestIdRef.current++;\n };\n }, [text, targetLang, source_lang, finalContextKey, engine]);\n\n return { translatedText, isLoading };\n};\n\n","import { useState, useEffect } from 'react';\n\nexport const useLoadingDots = (isLoading: boolean, dots?: boolean) => {\n const [dotCount, setDotCount] = useState<number>(1);\n\n useEffect(() => {\n if (!isLoading || !dots) {\n setDotCount(1);\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 return null;\n};\n\n","import React from 'react';\nimport { useBelocal } from './useBelocal';\nimport { useTranslationContext } from './hooks/useTranslationContext';\nimport { useTranslation } from './hooks/useTranslation';\nimport { useLoadingDots } from './hooks/useLoadingDots';\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 targetLang = lang ?? defaultLang;\n const { finalContext, finalContextKey } = useTranslationContext(context, user_context);\n \n const { translatedText, isLoading } = useTranslation({\n text,\n targetLang,\n source_lang,\n finalContext,\n finalContextKey,\n fallback,\n onSuccess,\n onError,\n engine,\n });\n\n const loadingDots = useLoadingDots(isLoading, dots);\n\n if (loadingDots) {\n return <>{loadingDots}</>;\n }\n\n if (isLoading) {\n return <>{fallback || text}</>;\n }\n\n return <>{translatedText}</>;\n};\n"]}
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createContext, useMemo, useState,
|
|
1
|
+
import { createContext, useMemo, useContext, useState, useRef, useEffect } from 'react';
|
|
2
2
|
import { BelocalEngine } from '@belocal/js-sdk';
|
|
3
3
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
|
|
@@ -6,7 +6,6 @@ import { jsx, Fragment } from 'react/jsx-runtime';
|
|
|
6
6
|
var BelocalContext = createContext(null);
|
|
7
7
|
var BelocalProvider = ({
|
|
8
8
|
apiKey,
|
|
9
|
-
baseUrl,
|
|
10
9
|
defaultLang,
|
|
11
10
|
batchWindowMs,
|
|
12
11
|
timeoutMs,
|
|
@@ -15,7 +14,6 @@ var BelocalProvider = ({
|
|
|
15
14
|
const contextValue = useMemo(() => {
|
|
16
15
|
const engine = new BelocalEngine({
|
|
17
16
|
apiKey,
|
|
18
|
-
baseUrl,
|
|
19
17
|
batchWindowMs,
|
|
20
18
|
timeoutMs
|
|
21
19
|
});
|
|
@@ -23,7 +21,7 @@ var BelocalProvider = ({
|
|
|
23
21
|
engine,
|
|
24
22
|
defaultLang
|
|
25
23
|
};
|
|
26
|
-
}, [apiKey,
|
|
24
|
+
}, [apiKey, batchWindowMs, timeoutMs]);
|
|
27
25
|
return /* @__PURE__ */ jsx(BelocalContext.Provider, { value: contextValue, children });
|
|
28
26
|
};
|
|
29
27
|
var useBelocalContext = () => {
|
|
@@ -38,83 +36,76 @@ var useBelocalContext = () => {
|
|
|
38
36
|
var useBelocal = () => {
|
|
39
37
|
return useBelocalContext();
|
|
40
38
|
};
|
|
41
|
-
var
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
var useTranslationContext = (context, user_context) => {
|
|
40
|
+
const finalContext = useMemo(() => {
|
|
41
|
+
const ctx = { ...context };
|
|
42
|
+
if (user_context) {
|
|
43
|
+
ctx.user_context = user_context;
|
|
44
|
+
}
|
|
45
|
+
return ctx;
|
|
46
|
+
}, [context, user_context]);
|
|
47
|
+
const finalContextKey = useMemo(() => {
|
|
48
|
+
const keys = Object.keys(finalContext).sort();
|
|
49
|
+
return keys.map((k) => `${k}:${finalContext[k]}`).join("|");
|
|
50
|
+
}, [finalContext]);
|
|
51
|
+
return { finalContext, finalContextKey };
|
|
52
|
+
};
|
|
53
|
+
var useTranslation = ({
|
|
44
54
|
text,
|
|
45
|
-
|
|
55
|
+
targetLang,
|
|
46
56
|
source_lang,
|
|
47
|
-
|
|
48
|
-
|
|
57
|
+
finalContext,
|
|
58
|
+
finalContextKey,
|
|
49
59
|
fallback,
|
|
50
60
|
onSuccess,
|
|
51
61
|
onError,
|
|
52
|
-
|
|
62
|
+
engine
|
|
53
63
|
}) => {
|
|
54
|
-
const { engine, defaultLang } = useBelocal();
|
|
55
64
|
const [translatedText, setTranslatedText] = useState(fallback || text);
|
|
56
65
|
const [isLoading, setIsLoading] = useState(false);
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}, [
|
|
66
|
-
const cacheKey = useMemo(() => {
|
|
67
|
-
return JSON.stringify({
|
|
68
|
-
text,
|
|
69
|
-
targetLang,
|
|
70
|
-
source_lang,
|
|
71
|
-
finalContext
|
|
72
|
-
});
|
|
73
|
-
}, [text, targetLang, source_lang, finalContext]);
|
|
74
|
-
const attachHandlers = (promise) => {
|
|
75
|
-
setIsLoading(true);
|
|
76
|
-
promise.then((translation) => {
|
|
77
|
-
setTranslatedText(translation);
|
|
78
|
-
onSuccess?.(translation);
|
|
79
|
-
}).catch((error) => {
|
|
80
|
-
console.error("Translation error:", error);
|
|
81
|
-
setTranslatedText(text);
|
|
82
|
-
onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
83
|
-
}).finally(() => {
|
|
84
|
-
setIsLoading(false);
|
|
85
|
-
});
|
|
86
|
-
};
|
|
66
|
+
const requestIdRef = useRef(0);
|
|
67
|
+
const onSuccessRef = useRef(onSuccess);
|
|
68
|
+
const onErrorRef = useRef(onError);
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
onSuccessRef.current = onSuccess;
|
|
71
|
+
}, [onSuccess]);
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
onErrorRef.current = onError;
|
|
74
|
+
}, [onError]);
|
|
87
75
|
useEffect(() => {
|
|
88
76
|
if (!targetLang) {
|
|
89
77
|
setTranslatedText(text);
|
|
90
78
|
return;
|
|
91
79
|
}
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
attachHandlers(pendingRequest);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
const translationPromise = engine.translate(text, targetLang, source_lang, finalContext).then((translation) => {
|
|
103
|
-
translationCache.set(cacheKey, translation);
|
|
104
|
-
pendingRequests.delete(cacheKey);
|
|
105
|
-
return translation;
|
|
80
|
+
const currentRequestId = ++requestIdRef.current;
|
|
81
|
+
setIsLoading(true);
|
|
82
|
+
engine.translate(text, targetLang, source_lang, finalContext).then((translation) => {
|
|
83
|
+
if (currentRequestId === requestIdRef.current) {
|
|
84
|
+
setTranslatedText(translation);
|
|
85
|
+
onSuccessRef.current?.(translation);
|
|
86
|
+
}
|
|
106
87
|
}).catch((error) => {
|
|
107
|
-
|
|
108
|
-
|
|
88
|
+
if (currentRequestId === requestIdRef.current) {
|
|
89
|
+
console.error("Translation error:", error);
|
|
90
|
+
setTranslatedText(text);
|
|
91
|
+
onErrorRef.current?.(error instanceof Error ? error : new Error(String(error)));
|
|
92
|
+
}
|
|
93
|
+
}).finally(() => {
|
|
94
|
+
if (currentRequestId === requestIdRef.current) {
|
|
95
|
+
setIsLoading(false);
|
|
96
|
+
}
|
|
109
97
|
});
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
98
|
+
return () => {
|
|
99
|
+
requestIdRef.current++;
|
|
100
|
+
};
|
|
101
|
+
}, [text, targetLang, source_lang, finalContextKey, engine]);
|
|
102
|
+
return { translatedText, isLoading };
|
|
103
|
+
};
|
|
104
|
+
var useLoadingDots = (isLoading, dots) => {
|
|
105
|
+
const [dotCount, setDotCount] = useState(1);
|
|
113
106
|
useEffect(() => {
|
|
114
107
|
if (!isLoading || !dots) {
|
|
115
|
-
|
|
116
|
-
setDotCount(1);
|
|
117
|
-
}
|
|
108
|
+
setDotCount(1);
|
|
118
109
|
return;
|
|
119
110
|
}
|
|
120
111
|
const interval = setInterval(() => {
|
|
@@ -123,7 +114,38 @@ var Translate = ({
|
|
|
123
114
|
return () => clearInterval(interval);
|
|
124
115
|
}, [isLoading, dots]);
|
|
125
116
|
if (isLoading && dots) {
|
|
126
|
-
return
|
|
117
|
+
return ".".repeat(dotCount);
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
};
|
|
121
|
+
var Translate = ({
|
|
122
|
+
text,
|
|
123
|
+
lang,
|
|
124
|
+
source_lang,
|
|
125
|
+
context,
|
|
126
|
+
user_context,
|
|
127
|
+
fallback,
|
|
128
|
+
onSuccess,
|
|
129
|
+
onError,
|
|
130
|
+
dots
|
|
131
|
+
}) => {
|
|
132
|
+
const { engine, defaultLang } = useBelocal();
|
|
133
|
+
const targetLang = lang ?? defaultLang;
|
|
134
|
+
const { finalContext, finalContextKey } = useTranslationContext(context, user_context);
|
|
135
|
+
const { translatedText, isLoading } = useTranslation({
|
|
136
|
+
text,
|
|
137
|
+
targetLang,
|
|
138
|
+
source_lang,
|
|
139
|
+
finalContext,
|
|
140
|
+
finalContextKey,
|
|
141
|
+
fallback,
|
|
142
|
+
onSuccess,
|
|
143
|
+
onError,
|
|
144
|
+
engine
|
|
145
|
+
});
|
|
146
|
+
const loadingDots = useLoadingDots(isLoading, dots);
|
|
147
|
+
if (loadingDots) {
|
|
148
|
+
return /* @__PURE__ */ jsx(Fragment, { children: loadingDots });
|
|
127
149
|
}
|
|
128
150
|
if (isLoading) {
|
|
129
151
|
return /* @__PURE__ */ jsx(Fragment, { children: fallback || text });
|
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 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"]}
|
|
1
|
+
{"version":3,"sources":["../src/BelocalProvider.tsx","../src/useBelocal.ts","../src/hooks/useTranslationContext.ts","../src/hooks/useTranslation.ts","../src/hooks/useLoadingDots.ts","../src/Translate.tsx"],"names":["useMemo","useState","useEffect","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 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 defaultLang,\n batchWindowMs,\n timeoutMs,\n children,\n}) => {\n const contextValue = useMemo(() => {\n const engine = new BelocalEngine({\n apiKey,\n batchWindowMs,\n timeoutMs,\n });\n\n return {\n engine,\n defaultLang,\n };\n }, [apiKey, 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 { useMemo } from 'react';\n\nexport const useTranslationContext = (\n context?: Record<string, string>,\n user_context?: string\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 finalContextKey = useMemo(() => {\n const keys = Object.keys(finalContext).sort();\n return keys.map((k) => `${k}:${finalContext[k]}`).join('|');\n }, [finalContext]);\n\n return { finalContext, finalContextKey };\n};\n\n","import { useState, useEffect, useRef } from 'react';\nimport { BelocalEngine } from '@belocal/js-sdk';\n\ntype UseTranslationParams = {\n text: string;\n targetLang?: string;\n source_lang?: string;\n finalContext: Record<string, string>;\n finalContextKey: string;\n fallback?: string;\n onSuccess?: (translation: string) => void;\n onError?: (error: Error) => void;\n engine: BelocalEngine;\n};\n\nexport const useTranslation = ({\n text,\n targetLang,\n source_lang,\n finalContext,\n finalContextKey,\n fallback,\n onSuccess,\n onError,\n engine,\n}: UseTranslationParams) => {\n const [translatedText, setTranslatedText] = useState<string>(fallback || text);\n const [isLoading, setIsLoading] = useState<boolean>(false);\n const requestIdRef = useRef(0);\n const onSuccessRef = useRef(onSuccess);\n const onErrorRef = useRef(onError);\n\n useEffect(() => {\n onSuccessRef.current = onSuccess;\n }, [onSuccess]);\n\n useEffect(() => {\n onErrorRef.current = onError;\n }, [onError]);\n\n useEffect(() => {\n if (!targetLang) {\n setTranslatedText(text);\n return;\n }\n\n const currentRequestId = ++requestIdRef.current;\n setIsLoading(true);\n\n engine\n .translate(text, targetLang, source_lang, finalContext)\n .then((translation) => {\n if (currentRequestId === requestIdRef.current) {\n setTranslatedText(translation);\n onSuccessRef.current?.(translation);\n }\n })\n .catch((error) => {\n if (currentRequestId === requestIdRef.current) {\n console.error('Translation error:', error);\n setTranslatedText(text);\n onErrorRef.current?.(error instanceof Error ? error : new Error(String(error)));\n }\n })\n .finally(() => {\n if (currentRequestId === requestIdRef.current) {\n setIsLoading(false);\n }\n });\n\n return () => {\n // При размонтировании или новом запросе увеличиваем ID, чтобы старые запросы игнорировались\n requestIdRef.current++;\n };\n }, [text, targetLang, source_lang, finalContextKey, engine]);\n\n return { translatedText, isLoading };\n};\n\n","import { useState, useEffect } from 'react';\n\nexport const useLoadingDots = (isLoading: boolean, dots?: boolean) => {\n const [dotCount, setDotCount] = useState<number>(1);\n\n useEffect(() => {\n if (!isLoading || !dots) {\n setDotCount(1);\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 return null;\n};\n\n","import React from 'react';\nimport { useBelocal } from './useBelocal';\nimport { useTranslationContext } from './hooks/useTranslationContext';\nimport { useTranslation } from './hooks/useTranslation';\nimport { useLoadingDots } from './hooks/useLoadingDots';\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 targetLang = lang ?? defaultLang;\n const { finalContext, finalContextKey } = useTranslationContext(context, user_context);\n \n const { translatedText, isLoading } = useTranslation({\n text,\n targetLang,\n source_lang,\n finalContext,\n finalContextKey,\n fallback,\n onSuccess,\n onError,\n engine,\n });\n\n const loadingDots = useLoadingDots(isLoading, dots);\n\n if (loadingDots) {\n return <>{loadingDots}</>;\n }\n\n if (isLoading) {\n return <>{fallback || text}</>;\n }\n\n return <>{translatedText}</>;\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@belocal/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"react-dom": ">=17.0.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@belocal/js-sdk": "^0.
|
|
31
|
+
"@belocal/js-sdk": "^0.6.1"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/react": "^18.0.0",
|