@belocal/react 0.6.0 → 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 +83 -26
- 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 +84 -27
- 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,48 +38,76 @@ var useBelocalContext = () => {
|
|
|
40
38
|
var useBelocal = () => {
|
|
41
39
|
return useBelocalContext();
|
|
42
40
|
};
|
|
43
|
-
var
|
|
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 = ({
|
|
44
56
|
text,
|
|
45
|
-
|
|
57
|
+
targetLang,
|
|
46
58
|
source_lang,
|
|
47
|
-
|
|
48
|
-
|
|
59
|
+
finalContext,
|
|
60
|
+
finalContextKey,
|
|
49
61
|
fallback,
|
|
50
62
|
onSuccess,
|
|
51
63
|
onError,
|
|
52
|
-
|
|
64
|
+
engine
|
|
53
65
|
}) => {
|
|
54
|
-
const { engine, defaultLang } = useBelocal();
|
|
55
66
|
const [translatedText, setTranslatedText] = react.useState(fallback || text);
|
|
56
67
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
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]);
|
|
63
77
|
react.useEffect(() => {
|
|
64
78
|
if (!targetLang) {
|
|
65
79
|
setTranslatedText(text);
|
|
66
80
|
return;
|
|
67
81
|
}
|
|
82
|
+
const currentRequestId = ++requestIdRef.current;
|
|
68
83
|
setIsLoading(true);
|
|
69
84
|
engine.translate(text, targetLang, source_lang, finalContext).then((translation) => {
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
if (currentRequestId === requestIdRef.current) {
|
|
86
|
+
setTranslatedText(translation);
|
|
87
|
+
onSuccessRef.current?.(translation);
|
|
88
|
+
}
|
|
72
89
|
}).catch((error) => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
+
}
|
|
76
95
|
}).finally(() => {
|
|
77
|
-
|
|
96
|
+
if (currentRequestId === requestIdRef.current) {
|
|
97
|
+
setIsLoading(false);
|
|
98
|
+
}
|
|
78
99
|
});
|
|
79
|
-
|
|
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);
|
|
80
108
|
react.useEffect(() => {
|
|
81
109
|
if (!isLoading || !dots) {
|
|
82
|
-
|
|
83
|
-
setDotCount(1);
|
|
84
|
-
}
|
|
110
|
+
setDotCount(1);
|
|
85
111
|
return;
|
|
86
112
|
}
|
|
87
113
|
const interval = setInterval(() => {
|
|
@@ -90,7 +116,38 @@ var Translate = ({
|
|
|
90
116
|
return () => clearInterval(interval);
|
|
91
117
|
}, [isLoading, dots]);
|
|
92
118
|
if (isLoading && dots) {
|
|
93
|
-
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 });
|
|
94
151
|
}
|
|
95
152
|
if (isLoading) {
|
|
96
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 } 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 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: Record<string, string> = { ...context };\n if (user_context) {\n finalContext.user_context = user_context;\n }\n\n useEffect(() => {\n if (!targetLang) {\n setTranslatedText(text);\n return;\n }\n\n setIsLoading(true);\n engine\n .translate(text, targetLang, source_lang, finalContext)\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 }, [text, targetLang, source_lang, finalContext, engine]);\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,48 +36,76 @@ var useBelocalContext = () => {
|
|
|
38
36
|
var useBelocal = () => {
|
|
39
37
|
return useBelocalContext();
|
|
40
38
|
};
|
|
41
|
-
var
|
|
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 = ({
|
|
42
54
|
text,
|
|
43
|
-
|
|
55
|
+
targetLang,
|
|
44
56
|
source_lang,
|
|
45
|
-
|
|
46
|
-
|
|
57
|
+
finalContext,
|
|
58
|
+
finalContextKey,
|
|
47
59
|
fallback,
|
|
48
60
|
onSuccess,
|
|
49
61
|
onError,
|
|
50
|
-
|
|
62
|
+
engine
|
|
51
63
|
}) => {
|
|
52
|
-
const { engine, defaultLang } = useBelocal();
|
|
53
64
|
const [translatedText, setTranslatedText] = useState(fallback || text);
|
|
54
65
|
const [isLoading, setIsLoading] = useState(false);
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
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]);
|
|
61
75
|
useEffect(() => {
|
|
62
76
|
if (!targetLang) {
|
|
63
77
|
setTranslatedText(text);
|
|
64
78
|
return;
|
|
65
79
|
}
|
|
80
|
+
const currentRequestId = ++requestIdRef.current;
|
|
66
81
|
setIsLoading(true);
|
|
67
82
|
engine.translate(text, targetLang, source_lang, finalContext).then((translation) => {
|
|
68
|
-
|
|
69
|
-
|
|
83
|
+
if (currentRequestId === requestIdRef.current) {
|
|
84
|
+
setTranslatedText(translation);
|
|
85
|
+
onSuccessRef.current?.(translation);
|
|
86
|
+
}
|
|
70
87
|
}).catch((error) => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
+
}
|
|
74
93
|
}).finally(() => {
|
|
75
|
-
|
|
94
|
+
if (currentRequestId === requestIdRef.current) {
|
|
95
|
+
setIsLoading(false);
|
|
96
|
+
}
|
|
76
97
|
});
|
|
77
|
-
|
|
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);
|
|
78
106
|
useEffect(() => {
|
|
79
107
|
if (!isLoading || !dots) {
|
|
80
|
-
|
|
81
|
-
setDotCount(1);
|
|
82
|
-
}
|
|
108
|
+
setDotCount(1);
|
|
83
109
|
return;
|
|
84
110
|
}
|
|
85
111
|
const interval = setInterval(() => {
|
|
@@ -88,7 +114,38 @@ var Translate = ({
|
|
|
88
114
|
return () => clearInterval(interval);
|
|
89
115
|
}, [isLoading, dots]);
|
|
90
116
|
if (isLoading && dots) {
|
|
91
|
-
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 });
|
|
92
149
|
}
|
|
93
150
|
if (isLoading) {
|
|
94
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":["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 } 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 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: Record<string, string> = { ...context };\n if (user_context) {\n finalContext.user_context = user_context;\n }\n\n useEffect(() => {\n if (!targetLang) {\n setTranslatedText(text);\n return;\n }\n\n setIsLoading(true);\n engine\n .translate(text, targetLang, source_lang, finalContext)\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 }, [text, targetLang, source_lang, finalContext, engine]);\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.6.
|
|
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.6.
|
|
31
|
+
"@belocal/js-sdk": "^0.6.1"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/react": "^18.0.0",
|