@belocal/react 0.1.0

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 ADDED
@@ -0,0 +1,190 @@
1
+ # @belocal/react
2
+
3
+ React SDK for Belocal translation service. Provides easy-to-use React components and hooks for translating your application content.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @belocal/react
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ### 1. Wrap your app with BelocalProvider
14
+
15
+ ```tsx
16
+ import { BelocalProvider } from '@belocal/react';
17
+
18
+ function App() {
19
+ return (
20
+ <BelocalProvider
21
+ apiKey="your-api-key"
22
+ defaultLang="en"
23
+ baseUrl="https://api.belocal.dev" // optional
24
+ >
25
+ <YourApp />
26
+ </BelocalProvider>
27
+ );
28
+ }
29
+ ```
30
+
31
+ ### 2. Use the Translate component
32
+
33
+ ```tsx
34
+ import { Translate } from '@belocal/react';
35
+
36
+ function Welcome() {
37
+ return (
38
+ <div>
39
+ <h1>
40
+ <Translate
41
+ text="Welcome to our app!"
42
+ fallback="Loading..."
43
+ />
44
+ </h1>
45
+
46
+ <p>
47
+ <Translate
48
+ text="Hello {name}!"
49
+ ctx={{ name: "John" }}
50
+ lang="es" // Override default language
51
+ />
52
+ </p>
53
+ </div>
54
+ );
55
+ }
56
+ ```
57
+
58
+ ### 3. Use the useBelocal hook
59
+
60
+ ```tsx
61
+ import { useBelocal } from '@belocal/react';
62
+
63
+ function CustomTranslation() {
64
+ const { engine, defaultLang } = useBelocal();
65
+ const [translation, setTranslation] = useState('');
66
+
67
+ useEffect(() => {
68
+ engine.t('Hello world!', defaultLang)
69
+ .then(setTranslation)
70
+ .catch(console.error);
71
+ }, [engine, defaultLang]);
72
+
73
+ return <span>{translation}</span>;
74
+ }
75
+ ```
76
+
77
+ ## API Reference
78
+
79
+ ### BelocalProvider
80
+
81
+ The root provider component that initializes the Belocal engine.
82
+
83
+ #### Props
84
+
85
+ | Prop | Type | Required | Description |
86
+ |------|------|----------|-------------|
87
+ | `apiKey` | `string` | ✅ | Your Belocal API key |
88
+ | `baseUrl` | `string` | ❌ | Custom API base URL |
89
+ | `defaultLang` | `string` | ❌ | Default language for translations |
90
+ | `children` | `React.ReactNode` | ✅ | Child components |
91
+
92
+ ### Translate
93
+
94
+ Component for displaying translated text.
95
+
96
+ #### Props
97
+
98
+ | Prop | Type | Required | Description |
99
+ |------|------|----------|-------------|
100
+ | `text` | `string` | ✅ | Text to translate |
101
+ | `lang` | `string` | ❌ | Target language (overrides defaultLang) |
102
+ | `ctx` | `Record<string, any>` | ❌ | Context variables for interpolation |
103
+ | `fallback` | `string` | ❌ | Text to show while loading |
104
+
105
+ #### Language Priority
106
+
107
+ The language selection follows this priority:
108
+ 1. `lang` prop (highest priority)
109
+ 2. `defaultLang` from BelocalProvider
110
+ 3. No translation if neither is provided
111
+
112
+ ### useBelocal
113
+
114
+ Hook for accessing the Belocal engine and configuration.
115
+
116
+ #### Returns
117
+
118
+ | Property | Type | Description |
119
+ |----------|------|-------------|
120
+ | `engine` | `BelocalEngine` | Belocal engine instance |
121
+ | `defaultLang` | `string \| undefined` | Default language from provider |
122
+
123
+ #### Throws
124
+
125
+ - Error if used outside of `BelocalProvider`
126
+
127
+ ## Error Handling
128
+
129
+ - **Network errors**: Component falls back to original text
130
+ - **Missing provider**: `useBelocal` throws an error
131
+ - **Invalid context**: Console error, falls back to original text
132
+
133
+ ## TypeScript Support
134
+
135
+ Full TypeScript support with exported types:
136
+
137
+ ```tsx
138
+ import type {
139
+ BelocalProviderProps,
140
+ TranslateProps
141
+ } from '@belocal/react';
142
+ ```
143
+
144
+ ## Examples
145
+
146
+ ### Conditional Translation
147
+
148
+ ```tsx
149
+ <Translate
150
+ text="Good morning!"
151
+ lang={userPreferredLanguage}
152
+ fallback="Loading translation..."
153
+ />
154
+ ```
155
+
156
+ ### Variable Interpolation
157
+
158
+ ```tsx
159
+ <Translate
160
+ text="You have {count} new messages"
161
+ ctx={{ count: unreadCount }}
162
+ />
163
+ ```
164
+
165
+ ### Manual Translation
166
+
167
+ ```tsx
168
+ function ManualTranslation() {
169
+ const { engine } = useBelocal();
170
+
171
+ const handleTranslate = async () => {
172
+ try {
173
+ const result = await engine.t('Custom text', 'fr');
174
+ console.log(result);
175
+ } catch (error) {
176
+ console.error('Translation failed:', error);
177
+ }
178
+ };
179
+
180
+ return <button onClick={handleTranslate}>Translate</button>;
181
+ }
182
+ ```
183
+
184
+ ## License
185
+
186
+ MIT
187
+
188
+ ## Support
189
+
190
+ For issues and questions, please visit [GitHub Issues](https://github.com/belocal/sdk/issues).
package/dist/index.cjs ADDED
@@ -0,0 +1,74 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsSdk = require('@belocal/js-sdk');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ // src/BelocalProvider.tsx
8
+ var BelocalContext = react.createContext(null);
9
+ var BelocalProvider = ({
10
+ apiKey,
11
+ baseUrl,
12
+ defaultLang,
13
+ children
14
+ }) => {
15
+ const contextValue = react.useMemo(() => {
16
+ const engine = new jsSdk.BelocalEngine({
17
+ apiKey,
18
+ baseUrl
19
+ });
20
+ return {
21
+ engine,
22
+ defaultLang
23
+ };
24
+ }, [apiKey, baseUrl, defaultLang]);
25
+ return /* @__PURE__ */ jsxRuntime.jsx(BelocalContext.Provider, { value: contextValue, children });
26
+ };
27
+ var useBelocalContext = () => {
28
+ const context = react.useContext(BelocalContext);
29
+ if (!context) {
30
+ throw new Error("useBelocalContext must be used within a BelocalProvider");
31
+ }
32
+ return context;
33
+ };
34
+
35
+ // src/useBelocal.ts
36
+ var useBelocal = () => {
37
+ return useBelocalContext();
38
+ };
39
+ var Translate = ({
40
+ text,
41
+ lang,
42
+ ctx,
43
+ fallback
44
+ }) => {
45
+ const { engine, defaultLang } = useBelocal();
46
+ const [translatedText, setTranslatedText] = react.useState(fallback || text);
47
+ const [isLoading, setIsLoading] = react.useState(false);
48
+ const targetLang = lang ?? defaultLang;
49
+ react.useEffect(() => {
50
+ if (!targetLang) {
51
+ setTranslatedText(text);
52
+ return;
53
+ }
54
+ setIsLoading(true);
55
+ engine.t(text, targetLang, ctx).then((translation) => {
56
+ setTranslatedText(translation);
57
+ }).catch((error) => {
58
+ console.error("Translation error:", error);
59
+ setTranslatedText(text);
60
+ }).finally(() => {
61
+ setIsLoading(false);
62
+ });
63
+ }, [text, targetLang, ctx, engine]);
64
+ if (isLoading) {
65
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback || text });
66
+ }
67
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: translatedText });
68
+ };
69
+
70
+ exports.BelocalProvider = BelocalProvider;
71
+ exports.Translate = Translate;
72
+ exports.useBelocal = useBelocal;
73
+ //# sourceMappingURL=index.cjs.map
74
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/BelocalProvider.tsx","../src/useBelocal.ts","../src/Translate.tsx"],"names":["createContext","useMemo","BelocalEngine","useContext","useState","useEffect","jsx","Fragment"],"mappings":";;;;;;;AAeA,IAAM,cAAA,GAAiBA,oBAAyC,IAAI,CAAA;AAE7D,IAAM,kBAAkD,CAAC;AAAA,EAC9D,MAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA,KAAM;AACJ,EAAA,MAAM,YAAA,GAAeC,cAAQ,MAAM;AACjC,IAAA,MAAM,MAAA,GAAS,IAAIC,mBAAA,CAAc;AAAA,MAC/B,MAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAA,OAAO;AAAA,MACL,MAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF,CAAA,EAAG,CAAC,MAAA,EAAQ,OAAA,EAAS,WAAW,CAAC,CAAA;AAEjC,EAAA,sCACG,cAAA,CAAe,QAAA,EAAf,EAAwB,KAAA,EAAO,cAC7B,QAAA,EACH,CAAA;AAEJ;AAEO,IAAM,oBAAoB,MAAM;AACrC,EAAA,MAAM,OAAA,GAAUC,iBAAW,cAAc,CAAA;AACzC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,yDAAyD,CAAA;AAAA,EAC3E;AACA,EAAA,OAAO,OAAA;AACT,CAAA;;;AC9CO,IAAM,aAAa,MAAM;AAC9B,EAAA,OAAO,iBAAA,EAAkB;AAC3B;ACMO,IAAM,YAAsC,CAAC;AAAA,EAClD,IAAA;AAAA,EACA,IAAA;AAAA,EACA,GAAA;AAAA,EACA;AACF,CAAA,KAAM;AACJ,EAAA,MAAM,EAAE,MAAA,EAAQ,WAAA,EAAY,GAAI,UAAA,EAAW;AAC3C,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAIC,cAAA,CAAiB,YAAY,IAAI,CAAA;AAC7E,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,eAAkB,KAAK,CAAA;AAGzD,EAAA,MAAM,aAAa,IAAA,IAAQ,WAAA;AAE3B,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,UAAA,EAAY;AAEf,MAAA,iBAAA,CAAkB,IAAI,CAAA;AACtB,MAAA;AAAA,IACF;AAEA,IAAA,YAAA,CAAa,IAAI,CAAA;AAEjB,IAAA,MAAA,CACG,EAAE,IAAA,EAAM,UAAA,EAAY,GAAG,CAAA,CACvB,IAAA,CAAK,CAAC,WAAA,KAAgB;AACrB,MAAA,iBAAA,CAAkB,WAAW,CAAA;AAAA,IAC/B,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,KAAA,KAAU;AAChB,MAAA,OAAA,CAAQ,KAAA,CAAM,sBAAsB,KAAK,CAAA;AAEzC,MAAA,iBAAA,CAAkB,IAAI,CAAA;AAAA,IACxB,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,YAAA,CAAa,KAAK,CAAA;AAAA,IACpB,CAAC,CAAA;AAAA,EACL,GAAG,CAAC,IAAA,EAAM,UAAA,EAAY,GAAA,EAAK,MAAM,CAAC,CAAA;AAGlC,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,uBAAOC,cAAAA,CAAAC,mBAAA,EAAA,EAAG,QAAA,EAAA,QAAA,IAAY,IAAA,EAAK,CAAA;AAAA,EAC7B;AAEA,EAAA,uBAAOD,cAAAA,CAAAC,mBAAA,EAAA,EAAG,QAAA,EAAA,cAAA,EAAe,CAAA;AAC3B","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 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 children,\n}) => {\n const contextValue = useMemo(() => {\n const engine = new BelocalEngine({\n apiKey,\n baseUrl,\n });\n\n return {\n engine,\n defaultLang,\n };\n }, [apiKey, baseUrl, defaultLang]);\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 ctx?: Record<string, any>;\n fallback?: string;\n};\n\nexport const Translate: React.FC<TranslateProps> = ({\n text,\n lang,\n ctx,\n fallback,\n}) => {\n const { engine, defaultLang } = useBelocal();\n const [translatedText, setTranslatedText] = useState<string>(fallback || text);\n const [isLoading, setIsLoading] = useState<boolean>(false);\n\n // Выбираем язык: props.lang имеет приоритет над defaultLang\n const targetLang = lang ?? defaultLang;\n\n useEffect(() => {\n if (!targetLang) {\n // Если язык не указан, просто возвращаем исходный текст\n setTranslatedText(text);\n return;\n }\n\n setIsLoading(true);\n \n engine\n .t(text, targetLang, ctx)\n .then((translation) => {\n setTranslatedText(translation);\n })\n .catch((error) => {\n console.error('Translation error:', error);\n // При ошибке возвращаем исходный текст\n setTranslatedText(text);\n })\n .finally(() => {\n setIsLoading(false);\n });\n }, [text, targetLang, ctx, engine]);\n\n // Пока идёт запрос — рендерим fallback или исходный text\n if (isLoading) {\n return <>{fallback || text}</>;\n }\n\n return <>{translatedText}</>;\n};\n\n"]}
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import * as _belocal_js_sdk from '@belocal/js-sdk';
3
+
4
+ type BelocalProviderProps = {
5
+ apiKey: string;
6
+ baseUrl?: string;
7
+ defaultLang?: string;
8
+ children: React.ReactNode;
9
+ };
10
+ declare const BelocalProvider: React.FC<BelocalProviderProps>;
11
+
12
+ declare const useBelocal: () => {
13
+ engine: _belocal_js_sdk.BelocalEngine;
14
+ defaultLang?: string;
15
+ };
16
+
17
+ type TranslateProps = {
18
+ text: string;
19
+ lang?: string;
20
+ ctx?: Record<string, any>;
21
+ fallback?: string;
22
+ };
23
+ declare const Translate: React.FC<TranslateProps>;
24
+
25
+ export { BelocalProvider, type BelocalProviderProps, Translate, type TranslateProps, useBelocal };
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import * as _belocal_js_sdk from '@belocal/js-sdk';
3
+
4
+ type BelocalProviderProps = {
5
+ apiKey: string;
6
+ baseUrl?: string;
7
+ defaultLang?: string;
8
+ children: React.ReactNode;
9
+ };
10
+ declare const BelocalProvider: React.FC<BelocalProviderProps>;
11
+
12
+ declare const useBelocal: () => {
13
+ engine: _belocal_js_sdk.BelocalEngine;
14
+ defaultLang?: string;
15
+ };
16
+
17
+ type TranslateProps = {
18
+ text: string;
19
+ lang?: string;
20
+ ctx?: Record<string, any>;
21
+ fallback?: string;
22
+ };
23
+ declare const Translate: React.FC<TranslateProps>;
24
+
25
+ export { BelocalProvider, type BelocalProviderProps, Translate, type TranslateProps, useBelocal };
package/dist/index.js ADDED
@@ -0,0 +1,70 @@
1
+ import { createContext, useMemo, useState, useEffect, useContext } from 'react';
2
+ import { BelocalEngine } from '@belocal/js-sdk';
3
+ import { jsx, Fragment } from 'react/jsx-runtime';
4
+
5
+ // src/BelocalProvider.tsx
6
+ var BelocalContext = createContext(null);
7
+ var BelocalProvider = ({
8
+ apiKey,
9
+ baseUrl,
10
+ defaultLang,
11
+ children
12
+ }) => {
13
+ const contextValue = useMemo(() => {
14
+ const engine = new BelocalEngine({
15
+ apiKey,
16
+ baseUrl
17
+ });
18
+ return {
19
+ engine,
20
+ defaultLang
21
+ };
22
+ }, [apiKey, baseUrl, defaultLang]);
23
+ return /* @__PURE__ */ jsx(BelocalContext.Provider, { value: contextValue, children });
24
+ };
25
+ var useBelocalContext = () => {
26
+ const context = useContext(BelocalContext);
27
+ if (!context) {
28
+ throw new Error("useBelocalContext must be used within a BelocalProvider");
29
+ }
30
+ return context;
31
+ };
32
+
33
+ // src/useBelocal.ts
34
+ var useBelocal = () => {
35
+ return useBelocalContext();
36
+ };
37
+ var Translate = ({
38
+ text,
39
+ lang,
40
+ ctx,
41
+ fallback
42
+ }) => {
43
+ const { engine, defaultLang } = useBelocal();
44
+ const [translatedText, setTranslatedText] = useState(fallback || text);
45
+ const [isLoading, setIsLoading] = useState(false);
46
+ const targetLang = lang ?? defaultLang;
47
+ useEffect(() => {
48
+ if (!targetLang) {
49
+ setTranslatedText(text);
50
+ return;
51
+ }
52
+ setIsLoading(true);
53
+ engine.t(text, targetLang, ctx).then((translation) => {
54
+ setTranslatedText(translation);
55
+ }).catch((error) => {
56
+ console.error("Translation error:", error);
57
+ setTranslatedText(text);
58
+ }).finally(() => {
59
+ setIsLoading(false);
60
+ });
61
+ }, [text, targetLang, ctx, engine]);
62
+ if (isLoading) {
63
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback || text });
64
+ }
65
+ return /* @__PURE__ */ jsx(Fragment, { children: translatedText });
66
+ };
67
+
68
+ export { BelocalProvider, Translate, useBelocal };
69
+ //# sourceMappingURL=index.js.map
70
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/BelocalProvider.tsx","../src/useBelocal.ts","../src/Translate.tsx"],"names":["jsx"],"mappings":";;;;;AAeA,IAAM,cAAA,GAAiB,cAAyC,IAAI,CAAA;AAE7D,IAAM,kBAAkD,CAAC;AAAA,EAC9D,MAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA;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;AAAA,KACD,CAAA;AAED,IAAA,OAAO;AAAA,MACL,MAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF,CAAA,EAAG,CAAC,MAAA,EAAQ,OAAA,EAAS,WAAW,CAAC,CAAA;AAEjC,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;;;AC9CO,IAAM,aAAa,MAAM;AAC9B,EAAA,OAAO,iBAAA,EAAkB;AAC3B;ACMO,IAAM,YAAsC,CAAC;AAAA,EAClD,IAAA;AAAA,EACA,IAAA;AAAA,EACA,GAAA;AAAA,EACA;AACF,CAAA,KAAM;AACJ,EAAA,MAAM,EAAE,MAAA,EAAQ,WAAA,EAAY,GAAI,UAAA,EAAW;AAC3C,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,QAAA,CAAiB,YAAY,IAAI,CAAA;AAC7E,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAkB,KAAK,CAAA;AAGzD,EAAA,MAAM,aAAa,IAAA,IAAQ,WAAA;AAE3B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,UAAA,EAAY;AAEf,MAAA,iBAAA,CAAkB,IAAI,CAAA;AACtB,MAAA;AAAA,IACF;AAEA,IAAA,YAAA,CAAa,IAAI,CAAA;AAEjB,IAAA,MAAA,CACG,EAAE,IAAA,EAAM,UAAA,EAAY,GAAG,CAAA,CACvB,IAAA,CAAK,CAAC,WAAA,KAAgB;AACrB,MAAA,iBAAA,CAAkB,WAAW,CAAA;AAAA,IAC/B,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,KAAA,KAAU;AAChB,MAAA,OAAA,CAAQ,KAAA,CAAM,sBAAsB,KAAK,CAAA;AAEzC,MAAA,iBAAA,CAAkB,IAAI,CAAA;AAAA,IACxB,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,YAAA,CAAa,KAAK,CAAA;AAAA,IACpB,CAAC,CAAA;AAAA,EACL,GAAG,CAAC,IAAA,EAAM,UAAA,EAAY,GAAA,EAAK,MAAM,CAAC,CAAA;AAGlC,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 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 children,\n}) => {\n const contextValue = useMemo(() => {\n const engine = new BelocalEngine({\n apiKey,\n baseUrl,\n });\n\n return {\n engine,\n defaultLang,\n };\n }, [apiKey, baseUrl, defaultLang]);\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 ctx?: Record<string, any>;\n fallback?: string;\n};\n\nexport const Translate: React.FC<TranslateProps> = ({\n text,\n lang,\n ctx,\n fallback,\n}) => {\n const { engine, defaultLang } = useBelocal();\n const [translatedText, setTranslatedText] = useState<string>(fallback || text);\n const [isLoading, setIsLoading] = useState<boolean>(false);\n\n // Выбираем язык: props.lang имеет приоритет над defaultLang\n const targetLang = lang ?? defaultLang;\n\n useEffect(() => {\n if (!targetLang) {\n // Если язык не указан, просто возвращаем исходный текст\n setTranslatedText(text);\n return;\n }\n\n setIsLoading(true);\n \n engine\n .t(text, targetLang, ctx)\n .then((translation) => {\n setTranslatedText(translation);\n })\n .catch((error) => {\n console.error('Translation error:', error);\n // При ошибке возвращаем исходный текст\n setTranslatedText(text);\n })\n .finally(() => {\n setIsLoading(false);\n });\n }, [text, targetLang, ctx, engine]);\n\n // Пока идёт запрос — рендерим fallback или исходный text\n if (isLoading) {\n return <>{fallback || text}</>;\n }\n\n return <>{translatedText}</>;\n};\n\n"]}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@belocal/react",
3
+ "version": "0.1.0",
4
+ "description": "React SDK for Belocal translation service",
5
+ "license": "MIT",
6
+ "author": "bobredobre <bobredobre@belocal.dev>",
7
+ "type": "module",
8
+ "main": "dist/index.cjs",
9
+ "module": "dist/index.mjs",
10
+ "types": "dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "import": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.mjs"
16
+ },
17
+ "require": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.cjs"
20
+ }
21
+ }
22
+ },
23
+ "sideEffects": false,
24
+ "files": [
25
+ "dist",
26
+ "README.md"
27
+ ],
28
+ "scripts": {
29
+ "build": "tsup",
30
+ "dev": "tsup --watch",
31
+ "test": "echo \"Error: no test specified\" && exit 1"
32
+ },
33
+ "peerDependencies": {
34
+ "react": ">=17.0.0",
35
+ "react-dom": ">=17.0.0"
36
+ },
37
+ "dependencies": {
38
+ "@belocal/js-sdk": "^0.1.12"
39
+ },
40
+ "devDependencies": {
41
+ "@types/react": "^18.0.0",
42
+ "@types/react-dom": "^18.0.0",
43
+ "react": "^18.0.0",
44
+ "react-dom": "^18.0.0",
45
+ "typescript": "^5.0.0",
46
+ "tsup": "^8.0.0"
47
+ },
48
+ "publishConfig": {
49
+ "access": "public"
50
+ }
51
+ }