fbt-inline-translations 0.1.2 → 0.1.5
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 +8 -0
- package/lib/@types/Phrase.d.ts +48 -0
- package/lib/@types/Phrase.js +1 -0
- package/lib/@types/SwiftyperContextType.d.ts +5 -0
- package/lib/@types/SwiftyperContextType.js +1 -0
- package/lib/@types/Translation.d.ts +16 -0
- package/lib/@types/Translation.js +1 -0
- package/lib/App.d.ts +20 -0
- package/lib/App.js +55 -0
- package/lib/components/Candidate.d.ts +9 -0
- package/lib/components/Candidate.js +6 -0
- package/lib/components/Composer.d.ts +13 -0
- package/lib/components/Composer.js +8 -0
- package/lib/components/PhraseOverview.d.ts +7 -0
- package/lib/components/PhraseOverview.js +5 -0
- package/lib/components/TranslationCard.d.ts +7 -0
- package/lib/components/TranslationCard.js +57 -0
- package/lib/contexts/SwiftyperServiceContext.d.ts +8 -0
- package/lib/contexts/SwiftyperServiceContext.js +21 -0
- package/lib/index.d.ts +11 -0
- package/lib/index.js +18 -0
- package/lib/providers/swiftyper.d.ts +13 -0
- package/lib/providers/swiftyper.js +7 -0
- package/lib/services/SwiftyperService.d.ts +11 -0
- package/lib/services/SwiftyperService.js +33 -0
- package/package.json +68 -58
- package/.babelrc +0 -7
- package/.eslintrc.js +0 -25
- package/.prettierignore +0 -1
- package/.prettierrc.json +0 -6
- package/babel.config.js +0 -20
- package/dist/0d8bb5b3ee5f5dac9e44.woff2 +0 -0
- package/dist/176f8f5bd5f02b3abfcf.woff2 +0 -0
- package/dist/18d00f739ff1e1c52db1.woff +0 -0
- package/dist/2267169ee7270a22a963.woff +0 -0
- package/dist/37a7069dc30fc663c878.woff2 +0 -0
- package/dist/451d4e559d6f57cdf6a1.woff +0 -0
- package/dist/49ae34d4cc6b98c00c69.woff +0 -0
- package/dist/7d8125ff7f707231fd89.woff2 +0 -0
- package/dist/7f839a8652da29745ce4.woff2 +0 -0
- package/dist/865f928cbabcc9f8f2b5.woff +0 -0
- package/dist/870c8c1486f76054301a.woff2 +0 -0
- package/dist/9360531f9bb817f917f0.woff +0 -0
- package/dist/a45108d3b34af91f9113.woff +0 -0
- package/dist/b1d9d9904bfca8802a63.woff +0 -0
- package/dist/bac8362e7a6ea60b6983.woff +0 -0
- package/dist/bd5b7a13f2c52b531a2a.woff +0 -0
- package/dist/bundle.js +0 -2
- package/dist/bundle.js.LICENSE.txt +0 -67
- package/dist/c18ee39fb002ad58b6dc.woff2 +0 -0
- package/dist/c20d916c1a1b094c1cec.woff +0 -0
- package/dist/c2aa4ab115bf9c6057cb.woff2 +0 -0
- package/dist/c64e7e354c88e613c77c.woff2 +0 -0
- package/dist/cb5ad999740e9d8a8bd1.woff2 +0 -0
- package/dist/cea99d3e3e13a3a599a0.woff +0 -0
- package/dist/d022bc70dc1bf7b3425d.woff2 +0 -0
- package/dist/f5b74d7ffcdf85b9dd60.woff2 +0 -0
- package/dist/index.html +0 -30
- package/images/demo.gif +0 -0
- package/postcss.config.js +0 -6
- package/src/@types/Phrase.ts +0 -58
- package/src/@types/SwiftyperContextType.ts +0 -5
- package/src/@types/Translation.ts +0 -16
- package/src/App.css +0 -29
- package/src/App.tsx +0 -85
- package/src/components/Candidate.tsx +0 -32
- package/src/components/Composer.tsx +0 -65
- package/src/components/PhraseOverview.tsx +0 -21
- package/src/components/TranslationCard.tsx +0 -120
- package/src/contexts/SwiftyperServiceContext.tsx +0 -37
- package/src/index.tsx +0 -35
- package/src/providers/swiftyper.tsx +0 -21
- package/src/services/SwiftyperService.ts +0 -46
- package/tailwind.config.js +0 -10
- package/tsconfig.json +0 -20
- package/webpack.config.js +0 -43
package/README.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# 👽 Inline translations for FBT
|
|
2
2
|
|
|
3
|
+
The extension serves to effectively translate your application using inline translations so that you can view strings you are
|
|
4
|
+
translating in context.
|
|
5
|
+
If you right-click on the underlined string, the translation dialog appears and you will be able to vote for the available translations or submit a new one.
|
|
6
|
+
|
|
7
|
+
You can make translations available to your translators, users, or the entire community and make your product multilingual.
|
|
8
|
+
|
|
9
|
+
**Translations can also be approved by your trusted translator(s).**
|
|
10
|
+
|
|
3
11
|

|
|
4
12
|
|
|
5
13
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Translation } from './Translation';
|
|
2
|
+
export declare type TableJSFBTTreeLeaf = {
|
|
3
|
+
desc: string;
|
|
4
|
+
hash?: string;
|
|
5
|
+
text: string;
|
|
6
|
+
tokenAliases?: string;
|
|
7
|
+
outerTokenName?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare type TableJSFBTTreeBranch = {
|
|
10
|
+
[key: number]: TableJSFBTTree;
|
|
11
|
+
};
|
|
12
|
+
export declare type TableJSFBTTree = TableJSFBTTreeLeaf | TableJSFBTTreeBranch;
|
|
13
|
+
export declare type JSFBTMetaEntry = {
|
|
14
|
+
type: string;
|
|
15
|
+
singular?: boolean;
|
|
16
|
+
token?: string;
|
|
17
|
+
} | {
|
|
18
|
+
type: string;
|
|
19
|
+
token: string;
|
|
20
|
+
} | {
|
|
21
|
+
type: string;
|
|
22
|
+
} | {
|
|
23
|
+
range: string[];
|
|
24
|
+
};
|
|
25
|
+
export declare type TableJSFBT = {
|
|
26
|
+
t: TableJSFBTTree;
|
|
27
|
+
m: JSFBTMetaEntry[];
|
|
28
|
+
};
|
|
29
|
+
export declare type Phrase = {
|
|
30
|
+
id: number;
|
|
31
|
+
parent_id: number | null;
|
|
32
|
+
object: string;
|
|
33
|
+
source: {
|
|
34
|
+
desc: string;
|
|
35
|
+
type: string;
|
|
36
|
+
jsfbt: string | TableJSFBT;
|
|
37
|
+
};
|
|
38
|
+
hash: string;
|
|
39
|
+
text: string;
|
|
40
|
+
description: string;
|
|
41
|
+
author: string;
|
|
42
|
+
project: string;
|
|
43
|
+
created_at: string;
|
|
44
|
+
translations: Translation[];
|
|
45
|
+
locale: {
|
|
46
|
+
name: string;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare type Translation = {
|
|
2
|
+
id: number;
|
|
3
|
+
voted: boolean;
|
|
4
|
+
phrase_id: number;
|
|
5
|
+
object: string;
|
|
6
|
+
phrase_hash: string;
|
|
7
|
+
hash: string;
|
|
8
|
+
translation: string;
|
|
9
|
+
approval_status: string;
|
|
10
|
+
variations: [];
|
|
11
|
+
tokens: [];
|
|
12
|
+
types: [];
|
|
13
|
+
locale: string;
|
|
14
|
+
author: string;
|
|
15
|
+
created_at: string;
|
|
16
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/lib/App.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Translation } from './@types/Translation';
|
|
3
|
+
import 'rodal/lib/rodal.css';
|
|
4
|
+
import 'typeface-roboto';
|
|
5
|
+
import './App.css';
|
|
6
|
+
declare type Props = {};
|
|
7
|
+
declare type State = {
|
|
8
|
+
visible: boolean;
|
|
9
|
+
translation: Translation | null;
|
|
10
|
+
hash: string | null;
|
|
11
|
+
locale: string | null;
|
|
12
|
+
};
|
|
13
|
+
declare class App extends React.Component<Props, State> {
|
|
14
|
+
constructor(props: Props);
|
|
15
|
+
componentDidMount(): void;
|
|
16
|
+
openTranslationDialog(event: MouseEvent): void;
|
|
17
|
+
hide(): void;
|
|
18
|
+
render(): JSX.Element;
|
|
19
|
+
}
|
|
20
|
+
export default App;
|
package/lib/App.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
// eslint-disable-next-line
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
import Rodal from 'rodal';
|
|
6
|
+
import TranslationCard from './components/TranslationCard';
|
|
7
|
+
import 'rodal/lib/rodal.css';
|
|
8
|
+
import 'typeface-roboto';
|
|
9
|
+
import './App.css';
|
|
10
|
+
class App extends React.Component {
|
|
11
|
+
constructor(props) {
|
|
12
|
+
super(props);
|
|
13
|
+
this.state = {
|
|
14
|
+
visible: false,
|
|
15
|
+
translation: null,
|
|
16
|
+
hash: null,
|
|
17
|
+
locale: null,
|
|
18
|
+
};
|
|
19
|
+
this.hide = this.hide.bind(this);
|
|
20
|
+
}
|
|
21
|
+
componentDidMount() {
|
|
22
|
+
document.addEventListener('contextmenu', this.openTranslationDialog.bind(this));
|
|
23
|
+
}
|
|
24
|
+
openTranslationDialog(event) {
|
|
25
|
+
let parent = event.target;
|
|
26
|
+
while (parent) {
|
|
27
|
+
if (parent.classList.contains('intlInlineMode_normal') ||
|
|
28
|
+
parent.classList.contains('intlInlineMode_translatable') ||
|
|
29
|
+
parent.classList.contains('intlInlineMode_approvable') ||
|
|
30
|
+
parent.classList.contains('intlInlineMode_reportable')) {
|
|
31
|
+
const hash = parent.getAttribute('data-intl-hash');
|
|
32
|
+
const locale = parent.getAttribute('data-intl-locale');
|
|
33
|
+
this.setState({
|
|
34
|
+
visible: true,
|
|
35
|
+
hash,
|
|
36
|
+
locale,
|
|
37
|
+
});
|
|
38
|
+
event.preventDefault();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
parent = parent.parentElement;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
hide() {
|
|
45
|
+
this.setState({ visible: false });
|
|
46
|
+
}
|
|
47
|
+
render() {
|
|
48
|
+
const { hash } = this.state;
|
|
49
|
+
const { children } = this.props;
|
|
50
|
+
return (_jsxs(_Fragment, { children: [children, _jsx(Rodal, { customStyles: { height: 'auto', bottom: 'auto', top: 'auto' }, className: "tw-flex tw-items-center tw-overflow-auto", enterAnimation: " rodal-zoom-enter dark:tw-bg-gray-800 " // ugly hack
|
|
51
|
+
, leaveAnimation: " rodal-fade-leave dark:tw-bg-gray-800 " // ugly hack
|
|
52
|
+
, visible: this.state.visible, onClose: this.hide, children: _jsx(TranslationCard, { hash: hash, hide: this.hide }, hash) })] }));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export default App;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { Translation } from '../@types/Translation';
|
|
3
|
+
declare type Props = {
|
|
4
|
+
candidate: Translation;
|
|
5
|
+
onClick: (translation: string) => void;
|
|
6
|
+
onVote: (id: number) => void;
|
|
7
|
+
};
|
|
8
|
+
export default function Candidate({ candidate, onClick, onVote }: Props): JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { HiCheckCircle, HiOutlineCheckCircle } from 'react-icons/hi';
|
|
3
|
+
export default function Candidate({ candidate, onClick, onVote }) {
|
|
4
|
+
const { translation } = candidate;
|
|
5
|
+
return (_jsxs("div", { className: "tw-flex tw-gap-2 hover:tw-cursor-pointer tw-py-2 tw-text-md tw-items-center tw-relative tw-border-0 tw-break-words", children: [candidate.voted ? (_jsx(HiCheckCircle, { className: "tw-text-xl tw-text-blue-600 tw-min-w-[20px]", onClick: () => onVote(candidate.id) })) : (_jsx(HiOutlineCheckCircle, { className: "tw-text-xl tw-text-gray-500 tw-min-w-[20px]", onClick: () => onVote(candidate.id) })), _jsx("span", { title: "Copy", onClick: () => onClick(translation), children: translation })] }));
|
|
6
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
declare type Props = {
|
|
3
|
+
hash: string;
|
|
4
|
+
translation: string | undefined;
|
|
5
|
+
language: string;
|
|
6
|
+
error: string | null;
|
|
7
|
+
loading: boolean;
|
|
8
|
+
hide: () => void;
|
|
9
|
+
setTranslation: (translation: string) => void;
|
|
10
|
+
onSubmit: (translation: string, hash: string) => void;
|
|
11
|
+
};
|
|
12
|
+
export default function Composer({ hash, translation, language, error, loading, hide, setTranslation, onSubmit, }: Props): JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { HiExclamation } from 'react-icons/hi';
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
export default function Composer({ hash, translation, language, error, loading, hide, setTranslation, onSubmit, }) {
|
|
5
|
+
return (_jsxs("div", { children: [_jsx("textarea", { placeholder: `Type your translation in ` + language, value: translation, className: classNames('tw-max-w-lg tw-mt-3 tw-mb-1 tw-p-3 dark:tw-bg-gray-900 dark:tw-text-gray-300 dark:tw-border-gray-900 tw-resize-y tw-outline-none tw-box-border tw-shadow-sm tw-block tw-w-full focus:!tw-ring-blue-500 focus:!tw-border-blue-500 sm:tw-text-sm tw-border tw-border-gray-300 tw-rounded-md', {
|
|
6
|
+
'!tw-border-red-500': error,
|
|
7
|
+
}), onInput: (event) => setTranslation(event.currentTarget.value), disabled: loading }), error && (_jsxs("div", { className: "tw-flex tw-gap-1.5 tw-items-center tw-text-xs tw-text-red-600", children: [_jsx(HiExclamation, {}), " ", error] })), _jsx("div", { children: _jsxs("div", { className: "tw-flex tw-justify-end tw-mt-2", children: [_jsx("button", { type: "button", className: "hover:tw-cursor-pointer tw-inline-flex tw-justify-center tw-py-2 tw-px-4 tw-border tw-border-transparent tw-shadow-sm tw-text-sm tw-font-medium tw-rounded-md tw-text-dark tw-bg-transparent dark:tw-text-white focus:tw-outline-none focus:tw-ring-2 focus:tw-ring-offset-2 focus:tw-ring-blue-500", onClick: hide, children: "Close" }), _jsx("button", { className: "tw-ml-3 hover:tw-cursor-pointer tw-inline-flex tw-justify-center tw-py-2 tw-px-4 tw-border tw-border-transparent tw-shadow-sm tw-text-sm tw-font-medium tw-rounded-md tw-text-white tw-bg-blue-600 hover:tw-bg-blue-700 focus:tw-outline-none focus:tw-ring-2 focus:tw-ring-offset-2 focus:tw-ring-blue-500", disabled: loading, onClick: () => onSubmit(translation, hash), children: "Submit" })] }) })] }));
|
|
8
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export default function PhraseOverview({ phrase }) {
|
|
3
|
+
const { text, description } = phrase;
|
|
4
|
+
return (_jsxs("div", { children: [_jsx("div", { className: "tw-text-md tw-text-gray-900 dark:tw-text-white", children: text }), _jsx("div", { className: "tw-text-sm tw-text-gray-500 dark:tw-text-gray-400 tw-mt-1 tw-mb-3", children: description })] }));
|
|
5
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import PhraseOverview from './PhraseOverview';
|
|
4
|
+
import Candidate from './Candidate';
|
|
5
|
+
import Composer from './Composer';
|
|
6
|
+
import { useSwiftyperService } from '../contexts/SwiftyperServiceContext';
|
|
7
|
+
import { HiExclamation } from 'react-icons/hi';
|
|
8
|
+
export default function TranslationCard({ hash, hide }) {
|
|
9
|
+
const swiftyperService = useSwiftyperService();
|
|
10
|
+
const [phrase, setPhrase] = useState();
|
|
11
|
+
const [loading, setLoading] = useState(true);
|
|
12
|
+
const [error, setError] = useState(null);
|
|
13
|
+
const [reload, setReload] = useState(null);
|
|
14
|
+
const [composerLoading, setComposerLoading] = useState(false);
|
|
15
|
+
const [composerError, setComposerError] = useState(null);
|
|
16
|
+
const [currentTranslation, setCurrentTranslation] = useState();
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (hash && reload !== false) {
|
|
19
|
+
setReload(false);
|
|
20
|
+
setLoading(true);
|
|
21
|
+
setError(null);
|
|
22
|
+
swiftyperService
|
|
23
|
+
.get(hash)
|
|
24
|
+
.then(setPhrase)
|
|
25
|
+
.catch(({ message }) => setError(message))
|
|
26
|
+
.finally(() => setLoading(false));
|
|
27
|
+
}
|
|
28
|
+
}, [hash, reload]);
|
|
29
|
+
if (error) {
|
|
30
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "tw-mx-auto tw-flex tw-items-center tw-justify-center tw-h-12 tw-w-12 tw-rounded-full tw-bg-red-100", children: _jsx(HiExclamation, { className: "tw-h-6 tw-w-6 tw-text-red-600" }) }), _jsx("div", { className: "tw-mt-3 tw-text-center sm:tw-mt-5", children: _jsx("h3", { className: "tw-mb-0 tw-text-lg tw-leading-6 tw-font-medium tw-text-gray-900 dark:tw-text-white", children: error || 'Invalid request' }) })] }));
|
|
31
|
+
}
|
|
32
|
+
if (loading && !phrase) {
|
|
33
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "tw-mx-auto tw-flex tw-items-center tw-justify-center tw-h-12 tw-w-12 loader" }), _jsx("div", { className: "tw-mt-3 tw-text-center sm:tw-mt-5", children: _jsx("h3", { className: "tw-mb-0 tw-text-lg tw-leading-6 tw-font-medium tw-text-gray-900 dark:tw-text-white", children: "Loading..." }) })] }));
|
|
34
|
+
}
|
|
35
|
+
return (_jsxs(_Fragment, { children: [_jsx(PhraseOverview, { phrase: phrase }), _jsx("div", { className: "tw-m-0 tw-p-0 tw-divide-y tw-divide-solid tw-divide-gray-300 dark:tw-divide-gray-700 dark:tw-text-white", children: phrase.translations.map((translation, index) => (_jsx(Candidate, { candidate: translation, onClick: (translation) => setCurrentTranslation(translation), onVote: (id) => {
|
|
36
|
+
setComposerLoading(true);
|
|
37
|
+
setComposerError(null);
|
|
38
|
+
swiftyperService
|
|
39
|
+
.vote(id)
|
|
40
|
+
.then(() => setReload(true))
|
|
41
|
+
.catch(({ message }) => setComposerError(message))
|
|
42
|
+
.finally(() => setComposerLoading(false));
|
|
43
|
+
} }, `candidate-` + index))) }), _jsx(Composer, { hash: phrase.hash, translation: currentTranslation, language: phrase.locale.name, loading: composerLoading, error: composerError, hide: hide, setTranslation: setCurrentTranslation, onSubmit: (translation, hash) => {
|
|
44
|
+
setComposerLoading(true);
|
|
45
|
+
setComposerError(null);
|
|
46
|
+
swiftyperService
|
|
47
|
+
.translate(translation, hash, phrase)
|
|
48
|
+
.then(() => {
|
|
49
|
+
setReload(true);
|
|
50
|
+
setCurrentTranslation('');
|
|
51
|
+
})
|
|
52
|
+
.catch(({ message }) => {
|
|
53
|
+
setComposerError(message);
|
|
54
|
+
})
|
|
55
|
+
.finally(() => setComposerLoading(false));
|
|
56
|
+
} })] }));
|
|
57
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
import SwiftyperService from '../services/SwiftyperService';
|
|
3
|
+
export declare const useSwiftyperService: () => SwiftyperService | null;
|
|
4
|
+
declare type Props = {
|
|
5
|
+
children: ReactElement;
|
|
6
|
+
};
|
|
7
|
+
export declare const SwiftyperServiceProvider: (props: Props) => JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { useContext, useEffect } from 'react';
|
|
3
|
+
import { useSwiftyper } from '../providers/swiftyper';
|
|
4
|
+
// eslint-disable-next-line
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
import { Swiftyper } from 'swiftyper-node';
|
|
7
|
+
import SwiftyperService from '../services/SwiftyperService';
|
|
8
|
+
const UserServiceContext = React.createContext(null);
|
|
9
|
+
export const useSwiftyperService = () => useContext(UserServiceContext);
|
|
10
|
+
const client = new Swiftyper();
|
|
11
|
+
const swiftyperServiceInstance = new SwiftyperService(client);
|
|
12
|
+
export const SwiftyperServiceProvider = (props) => {
|
|
13
|
+
const swiftyper = useSwiftyper();
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
const { token, locale, contributor } = swiftyper;
|
|
16
|
+
client._setApiKey(token);
|
|
17
|
+
swiftyperServiceInstance.contributor = contributor;
|
|
18
|
+
swiftyperServiceInstance.locale = locale;
|
|
19
|
+
}, [swiftyper]);
|
|
20
|
+
return (_jsx(UserServiceContext.Provider, { value: swiftyperServiceInstance, ...props }));
|
|
21
|
+
};
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
declare type FbtInlineTranslationsProps = {
|
|
3
|
+
token: string;
|
|
4
|
+
locale: string;
|
|
5
|
+
contributor: string;
|
|
6
|
+
darkMode?: boolean;
|
|
7
|
+
children?: React.ReactNode | undefined;
|
|
8
|
+
};
|
|
9
|
+
export declare const FbtInlineTranslationsWrapper: (props: FbtInlineTranslationsProps) => JSX.Element;
|
|
10
|
+
declare const swiftyperInlineTranslations: (props: FbtInlineTranslationsProps) => void;
|
|
11
|
+
export default swiftyperInlineTranslations;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import ReactDOM from 'react-dom';
|
|
3
|
+
import App from './App';
|
|
4
|
+
import { SwiftyperProvider } from './providers/swiftyper';
|
|
5
|
+
import { SwiftyperServiceProvider } from './contexts/SwiftyperServiceContext';
|
|
6
|
+
export const FbtInlineTranslationsWrapper = (props) => {
|
|
7
|
+
return (_jsx(SwiftyperProvider, { ...props, children: _jsx(SwiftyperServiceProvider, { children: _jsx(App, { children: props.children }) }) }));
|
|
8
|
+
};
|
|
9
|
+
const swiftyperInlineTranslations = (props) => {
|
|
10
|
+
if (props.darkMode) {
|
|
11
|
+
document.documentElement.classList.add('tw-dark');
|
|
12
|
+
}
|
|
13
|
+
ReactDOM.render(_jsx(FbtInlineTranslationsWrapper, { ...props }), document.getElementById('inline-translator'));
|
|
14
|
+
};
|
|
15
|
+
// eslint-disable-next-line
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
window.swiftyperInlineTranslations = swiftyperInlineTranslations;
|
|
18
|
+
export default swiftyperInlineTranslations;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React, { ReactElement } from 'react';
|
|
2
|
+
import { SwiftyperContextType } from '../@types/SwiftyperContextType';
|
|
3
|
+
export declare const SwiftyperContext: React.Context<SwiftyperContextType | null>;
|
|
4
|
+
export declare const useSwiftyper: () => SwiftyperContextType | null;
|
|
5
|
+
declare type Props = {
|
|
6
|
+
children: ReactElement;
|
|
7
|
+
token: string;
|
|
8
|
+
locale: string;
|
|
9
|
+
contributor: string;
|
|
10
|
+
darkMode?: boolean;
|
|
11
|
+
};
|
|
12
|
+
export declare const SwiftyperProvider: ({ children, ...props }: Props) => JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext } from 'react';
|
|
3
|
+
export const SwiftyperContext = createContext(null);
|
|
4
|
+
export const useSwiftyper = () => useContext(SwiftyperContext);
|
|
5
|
+
export const SwiftyperProvider = ({ children, ...props }) => {
|
|
6
|
+
return (_jsx(SwiftyperContext.Provider, { value: props, children: children }));
|
|
7
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Phrase } from '../@types/Phrase';
|
|
2
|
+
import { Swiftyper } from 'swiftyper-node';
|
|
3
|
+
export default class SwiftyperService {
|
|
4
|
+
client: Swiftyper;
|
|
5
|
+
contributor: null | string;
|
|
6
|
+
locale: null | string;
|
|
7
|
+
constructor(client: Swiftyper);
|
|
8
|
+
get(hash: string): any;
|
|
9
|
+
vote(id: number): any;
|
|
10
|
+
translate(translation: string, hash: string, phrase: Phrase): any;
|
|
11
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export default class SwiftyperService {
|
|
2
|
+
constructor(client) {
|
|
3
|
+
this.contributor = null;
|
|
4
|
+
this.locale = null;
|
|
5
|
+
this.client = client;
|
|
6
|
+
}
|
|
7
|
+
get(hash) {
|
|
8
|
+
const { locale, contributor } = this;
|
|
9
|
+
return this.client.translations.query({
|
|
10
|
+
hash,
|
|
11
|
+
locale,
|
|
12
|
+
contributor,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
vote(id) {
|
|
16
|
+
const { contributor } = this;
|
|
17
|
+
return this.client.translations.vote({
|
|
18
|
+
trid: id,
|
|
19
|
+
contributor,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
translate(translation, hash, phrase) {
|
|
23
|
+
const { locale, contributor } = this;
|
|
24
|
+
const { hash: phash } = phrase;
|
|
25
|
+
return this.client.translations.translate({
|
|
26
|
+
translation,
|
|
27
|
+
hash,
|
|
28
|
+
phash,
|
|
29
|
+
locale,
|
|
30
|
+
contributor,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
package/package.json
CHANGED
|
@@ -1,58 +1,68 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "fbt-inline-translations",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Dialog interface for efficient application translation.",
|
|
5
|
-
"main": "./
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"babel
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "fbt-inline-translations",
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"description": "Dialog interface for efficient application translation.",
|
|
5
|
+
"main": "./lib/index.js",
|
|
6
|
+
"types": "./lib/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"start": "webpack serve --config ./webpack.config.js --mode development",
|
|
9
|
+
"build": "webpack --mode=production && webpack --mode=production --env minified && tsc",
|
|
10
|
+
"lint": "eslint . --ext .ts,.tsx",
|
|
11
|
+
"format": "prettier --write src"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"swiftyper",
|
|
15
|
+
"fbt",
|
|
16
|
+
"translations",
|
|
17
|
+
"i18n"
|
|
18
|
+
],
|
|
19
|
+
"directories": {
|
|
20
|
+
"src": "src"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"lib/**/*",
|
|
24
|
+
"README.md",
|
|
25
|
+
"package.json"
|
|
26
|
+
],
|
|
27
|
+
"author": "Swiftyper <support@swiftyper.sk> (https://swiftyper.sk/)",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@babel/core": "^7.17.2",
|
|
31
|
+
"@babel/preset-env": "^7.16.11",
|
|
32
|
+
"@babel/preset-react": "^7.16.7",
|
|
33
|
+
"@types/react": "^17.0.45",
|
|
34
|
+
"@types/react-dom": "^18.0.5",
|
|
35
|
+
"@types/webpack-env": "^1.17.0",
|
|
36
|
+
"@typescript-eslint/eslint-plugin": "^5.26.0",
|
|
37
|
+
"@typescript-eslint/parser": "^5.26.0",
|
|
38
|
+
"autoprefixer": "^10.4.7",
|
|
39
|
+
"babel-loader": "^8.2.3",
|
|
40
|
+
"eslint": "^8.16.0",
|
|
41
|
+
"eslint-config-prettier": "^8.5.0",
|
|
42
|
+
"eslint-plugin-prettier": "^4.0.0",
|
|
43
|
+
"postcss": "^8.4.14",
|
|
44
|
+
"postcss-loader": "^7.0.0",
|
|
45
|
+
"prettier": "2.6.2",
|
|
46
|
+
"react-hot-loader": "^4.13.0",
|
|
47
|
+
"tailwindcss": "^3.1.2",
|
|
48
|
+
"ts-loader": "^9.3.0",
|
|
49
|
+
"typescript": "^4.7.3",
|
|
50
|
+
"webpack": "^5.68.0",
|
|
51
|
+
"webpack-cli": "^4.9.2",
|
|
52
|
+
"webpack-dev-server": "^4.7.4"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@babel/preset-typescript": "^7.17.12",
|
|
56
|
+
"classnames": "^2.3.1",
|
|
57
|
+
"css-loader": "^6.7.1",
|
|
58
|
+
"node-polyfill-webpack-plugin": "^1.1.4",
|
|
59
|
+
"react": "^16.0.2",
|
|
60
|
+
"react-dom": "^16.0.2",
|
|
61
|
+
"react-icons": "^4.4.0",
|
|
62
|
+
"rodal": "^1.8.3",
|
|
63
|
+
"style-loader": "^3.3.1",
|
|
64
|
+
"swiftyper-node": "^1.0.6",
|
|
65
|
+
"typeface-roboto": "^1.1.13",
|
|
66
|
+
"typescript": "^3.7.5"
|
|
67
|
+
}
|
|
68
|
+
}
|
package/.babelrc
DELETED
package/.eslintrc.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
root: true,
|
|
3
|
-
parser: '@typescript-eslint/parser',
|
|
4
|
-
parserOptions: {
|
|
5
|
-
ecmaVersion: 2020,
|
|
6
|
-
sourceType: "module",
|
|
7
|
-
},
|
|
8
|
-
plugins: [
|
|
9
|
-
'@typescript-eslint',
|
|
10
|
-
'prettier'
|
|
11
|
-
],
|
|
12
|
-
extends: [
|
|
13
|
-
'eslint:recommended',
|
|
14
|
-
'plugin:@typescript-eslint/eslint-recommended',
|
|
15
|
-
'plugin:@typescript-eslint/recommended',
|
|
16
|
-
'plugin:prettier/recommended'
|
|
17
|
-
],
|
|
18
|
-
"rules": {
|
|
19
|
-
"prettier/prettier": "warn",
|
|
20
|
-
"@typescript-eslint/member-delimiter-style": "off",
|
|
21
|
-
"@typescript-eslint/explicit-function-return-type": "off",
|
|
22
|
-
"@typescript-eslint/no-use-before-define": "off",
|
|
23
|
-
"@typescript-eslint/no-non-null-assertion": "off",
|
|
24
|
-
}
|
|
25
|
-
};
|
package/.prettierignore
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
node_modules
|
package/.prettierrc.json
DELETED
package/babel.config.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
module.exports = function (api) {
|
|
2
|
-
api.cache(true)
|
|
3
|
-
|
|
4
|
-
const useESModules = process.env.BABEL_MODULE === 'es'
|
|
5
|
-
|
|
6
|
-
return {
|
|
7
|
-
presets: [
|
|
8
|
-
[
|
|
9
|
-
'@babel/preset-env',
|
|
10
|
-
{
|
|
11
|
-
loose: true,
|
|
12
|
-
modules: useESModules ? false : 'commonjs',
|
|
13
|
-
},
|
|
14
|
-
],
|
|
15
|
-
['@babel/preset-react', { runtime: 'automatic' }],
|
|
16
|
-
'@babel/preset-typescript',
|
|
17
|
-
],
|
|
18
|
-
plugins: ['@babel/plugin-proposal-class-properties'],
|
|
19
|
-
}
|
|
20
|
-
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|