@translatehub/react 1.0.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.
@@ -0,0 +1,77 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React, { ReactNode } from 'react';
3
+ import { TranslateHubConfig } from '@translatehub/core';
4
+
5
+ interface TranslationContextValue {
6
+ /** Текущий язык */
7
+ lang: string;
8
+ /** Сменить язык */
9
+ setLang: (lang: string) => void;
10
+ /** Получить перевод по ключу с опциональной интерполяцией */
11
+ t: (key: string, params?: Record<string, string | number>) => string;
12
+ /** true пока переводы грузятся */
13
+ loading: boolean;
14
+ /** Ошибка загрузки (если есть) */
15
+ error: Error | null;
16
+ }
17
+ interface TranslationProviderProps extends TranslateHubConfig {
18
+ /** Язык по умолчанию */
19
+ defaultLang: string;
20
+ /** Список доступных языков (для LanguageSwitcher) */
21
+ languages?: string[];
22
+ /** Показывать ключ вместо пустой строки при отсутствии перевода */
23
+ fallbackToKey?: boolean;
24
+ children: ReactNode;
25
+ }
26
+ declare function TranslationProvider({ children, defaultLang, fallbackToKey, ...clientConfig }: TranslationProviderProps): react_jsx_runtime.JSX.Element;
27
+ /**
28
+ * Основной хук для доступа к переводам.
29
+ *
30
+ * @example
31
+ * const { t, lang, setLang } = useTranslation();
32
+ * return <h1>{t('page.title')}</h1>;
33
+ */
34
+ declare function useTranslation(): TranslationContextValue;
35
+ interface TProps {
36
+ /** Ключ перевода */
37
+ k: string;
38
+ /** Параметры интерполяции: {name}, {count} и т.д. */
39
+ params?: Record<string, string | number>;
40
+ }
41
+ /**
42
+ * Декларативный компонент перевода.
43
+ *
44
+ * @example
45
+ * <T k="cart.empty.message" />
46
+ * <T k="greeting" params={{ name: 'Артём' }} />
47
+ */
48
+ declare function T({ k, params }: TProps): React.ReactElement;
49
+ interface LanguageSwitcherProps {
50
+ /** Список языков для отображения */
51
+ languages: string[];
52
+ /** CSS-класс обёртки */
53
+ className?: string;
54
+ }
55
+ /**
56
+ * Готовый переключатель языка — рендерит кнопки/ссылки для смены локали.
57
+ *
58
+ * @example
59
+ * <LanguageSwitcher languages={['ru', 'en', 'de']} />
60
+ */
61
+ declare function LanguageSwitcher({ languages, className }: LanguageSwitcherProps): react_jsx_runtime.JSX.Element;
62
+ /**
63
+ * HOC для class-компонентов (альтернатива хуку).
64
+ *
65
+ * @example
66
+ * class MyComponent extends React.Component<WithTranslationProps> {
67
+ * render() { return <div>{this.props.t('key')}</div>; }
68
+ * }
69
+ * export default withTranslation(MyComponent);
70
+ */
71
+ interface WithTranslationProps {
72
+ t: (key: string, params?: Record<string, string | number>) => string;
73
+ lang: string;
74
+ }
75
+ declare function withTranslation<P extends WithTranslationProps>(Component: React.ComponentType<P>): (props: Omit<P, keyof WithTranslationProps>) => react_jsx_runtime.JSX.Element;
76
+
77
+ export { LanguageSwitcher, type LanguageSwitcherProps, T, type TProps, TranslationProvider, type TranslationProviderProps, type WithTranslationProps, useTranslation, withTranslation };
@@ -0,0 +1,77 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React, { ReactNode } from 'react';
3
+ import { TranslateHubConfig } from '@translatehub/core';
4
+
5
+ interface TranslationContextValue {
6
+ /** Текущий язык */
7
+ lang: string;
8
+ /** Сменить язык */
9
+ setLang: (lang: string) => void;
10
+ /** Получить перевод по ключу с опциональной интерполяцией */
11
+ t: (key: string, params?: Record<string, string | number>) => string;
12
+ /** true пока переводы грузятся */
13
+ loading: boolean;
14
+ /** Ошибка загрузки (если есть) */
15
+ error: Error | null;
16
+ }
17
+ interface TranslationProviderProps extends TranslateHubConfig {
18
+ /** Язык по умолчанию */
19
+ defaultLang: string;
20
+ /** Список доступных языков (для LanguageSwitcher) */
21
+ languages?: string[];
22
+ /** Показывать ключ вместо пустой строки при отсутствии перевода */
23
+ fallbackToKey?: boolean;
24
+ children: ReactNode;
25
+ }
26
+ declare function TranslationProvider({ children, defaultLang, fallbackToKey, ...clientConfig }: TranslationProviderProps): react_jsx_runtime.JSX.Element;
27
+ /**
28
+ * Основной хук для доступа к переводам.
29
+ *
30
+ * @example
31
+ * const { t, lang, setLang } = useTranslation();
32
+ * return <h1>{t('page.title')}</h1>;
33
+ */
34
+ declare function useTranslation(): TranslationContextValue;
35
+ interface TProps {
36
+ /** Ключ перевода */
37
+ k: string;
38
+ /** Параметры интерполяции: {name}, {count} и т.д. */
39
+ params?: Record<string, string | number>;
40
+ }
41
+ /**
42
+ * Декларативный компонент перевода.
43
+ *
44
+ * @example
45
+ * <T k="cart.empty.message" />
46
+ * <T k="greeting" params={{ name: 'Артём' }} />
47
+ */
48
+ declare function T({ k, params }: TProps): React.ReactElement;
49
+ interface LanguageSwitcherProps {
50
+ /** Список языков для отображения */
51
+ languages: string[];
52
+ /** CSS-класс обёртки */
53
+ className?: string;
54
+ }
55
+ /**
56
+ * Готовый переключатель языка — рендерит кнопки/ссылки для смены локали.
57
+ *
58
+ * @example
59
+ * <LanguageSwitcher languages={['ru', 'en', 'de']} />
60
+ */
61
+ declare function LanguageSwitcher({ languages, className }: LanguageSwitcherProps): react_jsx_runtime.JSX.Element;
62
+ /**
63
+ * HOC для class-компонентов (альтернатива хуку).
64
+ *
65
+ * @example
66
+ * class MyComponent extends React.Component<WithTranslationProps> {
67
+ * render() { return <div>{this.props.t('key')}</div>; }
68
+ * }
69
+ * export default withTranslation(MyComponent);
70
+ */
71
+ interface WithTranslationProps {
72
+ t: (key: string, params?: Record<string, string | number>) => string;
73
+ lang: string;
74
+ }
75
+ declare function withTranslation<P extends WithTranslationProps>(Component: React.ComponentType<P>): (props: Omit<P, keyof WithTranslationProps>) => react_jsx_runtime.JSX.Element;
76
+
77
+ export { LanguageSwitcher, type LanguageSwitcherProps, T, type TProps, TranslationProvider, type TranslationProviderProps, type WithTranslationProps, useTranslation, withTranslation };
package/dist/index.js ADDED
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.tsx
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ LanguageSwitcher: () => LanguageSwitcher,
24
+ T: () => T,
25
+ TranslationProvider: () => TranslationProvider,
26
+ useTranslation: () => useTranslation,
27
+ withTranslation: () => withTranslation
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+ var import_react = require("react");
31
+ var import_core = require("@translatehub/core");
32
+ var import_jsx_runtime = require("react/jsx-runtime");
33
+ var TranslationContext = (0, import_react.createContext)(null);
34
+ function TranslationProvider({
35
+ children,
36
+ defaultLang,
37
+ fallbackToKey = true,
38
+ ...clientConfig
39
+ }) {
40
+ const [client] = (0, import_react.useState)(() => new import_core.TranslateHubClient(clientConfig));
41
+ const [lang, setLangState] = (0, import_react.useState)(defaultLang);
42
+ const [translations, setTranslations] = (0, import_react.useState)({});
43
+ const [loading, setLoading] = (0, import_react.useState)(true);
44
+ const [error, setError] = (0, import_react.useState)(null);
45
+ const loadLang = (0, import_react.useCallback)(
46
+ async (targetLang) => {
47
+ setLoading(true);
48
+ setError(null);
49
+ try {
50
+ const data = await client.getTranslations(targetLang);
51
+ setTranslations(data);
52
+ } catch (e) {
53
+ setError(e instanceof Error ? e : new Error(String(e)));
54
+ } finally {
55
+ setLoading(false);
56
+ }
57
+ },
58
+ [client]
59
+ );
60
+ (0, import_react.useEffect)(() => {
61
+ loadLang(lang);
62
+ }, [lang, loadLang]);
63
+ const setLang = (0, import_react.useCallback)(
64
+ (newLang) => {
65
+ setLangState(newLang);
66
+ },
67
+ []
68
+ );
69
+ const t = (0, import_react.useCallback)(
70
+ (key, params) => {
71
+ const value = translations[key];
72
+ if (value === void 0) return fallbackToKey ? key : "";
73
+ return params ? (0, import_core.interpolate)(value, params) : value;
74
+ },
75
+ [translations, fallbackToKey]
76
+ );
77
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TranslationContext.Provider, { value: { lang, setLang, t, loading, error }, children });
78
+ }
79
+ function useTranslation() {
80
+ const ctx = (0, import_react.useContext)(TranslationContext);
81
+ if (!ctx) {
82
+ throw new Error("useTranslation must be used inside <TranslationProvider>");
83
+ }
84
+ return ctx;
85
+ }
86
+ function T({ k, params }) {
87
+ const { t } = useTranslation();
88
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: t(k, params) });
89
+ }
90
+ var LANG_LABELS = {
91
+ ru: "\u0420\u0443\u0441\u0441\u043A\u0438\u0439",
92
+ en: "English",
93
+ de: "Deutsch",
94
+ fr: "Fran\xE7ais",
95
+ es: "Espa\xF1ol",
96
+ zh: "\u4E2D\u6587",
97
+ ja: "\u65E5\u672C\u8A9E",
98
+ ar: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629"
99
+ };
100
+ function LanguageSwitcher({ languages, className }) {
101
+ const { lang, setLang } = useTranslation();
102
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, style: { display: "flex", gap: "8px" }, children: languages.map((l) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
103
+ "button",
104
+ {
105
+ onClick: () => setLang(l),
106
+ disabled: l === lang,
107
+ style: {
108
+ padding: "4px 10px",
109
+ borderRadius: "6px",
110
+ border: "1px solid #DEE2E6",
111
+ background: l === lang ? "#2D6ADF" : "#fff",
112
+ color: l === lang ? "#fff" : "#212529",
113
+ cursor: l === lang ? "default" : "pointer",
114
+ fontWeight: l === lang ? 600 : 400
115
+ },
116
+ children: LANG_LABELS[l] ?? l.toUpperCase()
117
+ },
118
+ l
119
+ )) });
120
+ }
121
+ function withTranslation(Component) {
122
+ return function WrappedComponent(props) {
123
+ const { t, lang } = useTranslation();
124
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ...props, t, lang });
125
+ };
126
+ }
127
+ // Annotate the CommonJS export names for ESM import in node:
128
+ 0 && (module.exports = {
129
+ LanguageSwitcher,
130
+ T,
131
+ TranslationProvider,
132
+ useTranslation,
133
+ withTranslation
134
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,111 @@
1
+ // src/index.tsx
2
+ import {
3
+ createContext,
4
+ useCallback,
5
+ useContext,
6
+ useEffect,
7
+ useState
8
+ } from "react";
9
+ import { TranslateHubClient, interpolate } from "@translatehub/core";
10
+ import { Fragment, jsx } from "react/jsx-runtime";
11
+ var TranslationContext = createContext(null);
12
+ function TranslationProvider({
13
+ children,
14
+ defaultLang,
15
+ fallbackToKey = true,
16
+ ...clientConfig
17
+ }) {
18
+ const [client] = useState(() => new TranslateHubClient(clientConfig));
19
+ const [lang, setLangState] = useState(defaultLang);
20
+ const [translations, setTranslations] = useState({});
21
+ const [loading, setLoading] = useState(true);
22
+ const [error, setError] = useState(null);
23
+ const loadLang = useCallback(
24
+ async (targetLang) => {
25
+ setLoading(true);
26
+ setError(null);
27
+ try {
28
+ const data = await client.getTranslations(targetLang);
29
+ setTranslations(data);
30
+ } catch (e) {
31
+ setError(e instanceof Error ? e : new Error(String(e)));
32
+ } finally {
33
+ setLoading(false);
34
+ }
35
+ },
36
+ [client]
37
+ );
38
+ useEffect(() => {
39
+ loadLang(lang);
40
+ }, [lang, loadLang]);
41
+ const setLang = useCallback(
42
+ (newLang) => {
43
+ setLangState(newLang);
44
+ },
45
+ []
46
+ );
47
+ const t = useCallback(
48
+ (key, params) => {
49
+ const value = translations[key];
50
+ if (value === void 0) return fallbackToKey ? key : "";
51
+ return params ? interpolate(value, params) : value;
52
+ },
53
+ [translations, fallbackToKey]
54
+ );
55
+ return /* @__PURE__ */ jsx(TranslationContext.Provider, { value: { lang, setLang, t, loading, error }, children });
56
+ }
57
+ function useTranslation() {
58
+ const ctx = useContext(TranslationContext);
59
+ if (!ctx) {
60
+ throw new Error("useTranslation must be used inside <TranslationProvider>");
61
+ }
62
+ return ctx;
63
+ }
64
+ function T({ k, params }) {
65
+ const { t } = useTranslation();
66
+ return /* @__PURE__ */ jsx(Fragment, { children: t(k, params) });
67
+ }
68
+ var LANG_LABELS = {
69
+ ru: "\u0420\u0443\u0441\u0441\u043A\u0438\u0439",
70
+ en: "English",
71
+ de: "Deutsch",
72
+ fr: "Fran\xE7ais",
73
+ es: "Espa\xF1ol",
74
+ zh: "\u4E2D\u6587",
75
+ ja: "\u65E5\u672C\u8A9E",
76
+ ar: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629"
77
+ };
78
+ function LanguageSwitcher({ languages, className }) {
79
+ const { lang, setLang } = useTranslation();
80
+ return /* @__PURE__ */ jsx("div", { className, style: { display: "flex", gap: "8px" }, children: languages.map((l) => /* @__PURE__ */ jsx(
81
+ "button",
82
+ {
83
+ onClick: () => setLang(l),
84
+ disabled: l === lang,
85
+ style: {
86
+ padding: "4px 10px",
87
+ borderRadius: "6px",
88
+ border: "1px solid #DEE2E6",
89
+ background: l === lang ? "#2D6ADF" : "#fff",
90
+ color: l === lang ? "#fff" : "#212529",
91
+ cursor: l === lang ? "default" : "pointer",
92
+ fontWeight: l === lang ? 600 : 400
93
+ },
94
+ children: LANG_LABELS[l] ?? l.toUpperCase()
95
+ },
96
+ l
97
+ )) });
98
+ }
99
+ function withTranslation(Component) {
100
+ return function WrappedComponent(props) {
101
+ const { t, lang } = useTranslation();
102
+ return /* @__PURE__ */ jsx(Component, { ...props, t, lang });
103
+ };
104
+ }
105
+ export {
106
+ LanguageSwitcher,
107
+ T,
108
+ TranslationProvider,
109
+ useTranslation,
110
+ withTranslation
111
+ };
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@translatehub/react",
3
+ "version": "1.0.0",
4
+ "description": "React components and hooks for TranslateHub localization",
5
+ "main": "dist/index.cjs",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.cjs",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": ["dist"],
16
+ "scripts": {
17
+ "build": "tsup src/index.tsx --format esm,cjs --dts --external react",
18
+ "dev": "tsup src/index.tsx --format esm,cjs --dts --external react --watch"
19
+ },
20
+ "peerDependencies": {
21
+ "react": ">=17.0.0",
22
+ "react-dom": ">=17.0.0"
23
+ },
24
+ "dependencies": {
25
+ "@translatehub/core": "^1.0.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/react": "^18.2.66",
29
+ "@types/react-dom": "^18.2.22",
30
+ "tsup": "^8.0.2",
31
+ "typescript": "^5.4.2"
32
+ },
33
+ "keywords": ["react", "i18n", "localization", "translatehub"],
34
+ "license": "MIT",
35
+ "publishConfig": {
36
+ "access": "public",
37
+ "registry": "https://registry.npmjs.org/"
38
+ },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://gitlab.com/artemryskal/translate-hub.git",
42
+ "directory": "sdk/react"
43
+ },
44
+ "homepage": "https://translate-hub.ru"
45
+ }