@smart-cloud/ai-kit-ui 1.4.6 → 1.4.8
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/dist/index.cjs +9 -9
- package/dist/index.js +9 -9
- package/package.json +2 -1
- package/src/ai-feature/AiFeature.tsx +322 -25
- package/src/i18n/ar.ts +13 -13
- package/src/i18n/de.ts +5 -5
- package/src/i18n/es.ts +5 -5
- package/src/i18n/fr.ts +14 -14
- package/src/i18n/he.ts +16 -16
- package/src/i18n/hi.ts +16 -16
- package/src/i18n/hu.ts +4 -4
- package/src/i18n/id.ts +10 -10
- package/src/i18n/it.ts +7 -7
- package/src/i18n/ja.ts +10 -10
- package/src/i18n/ko.ts +11 -11
- package/src/i18n/nb.ts +6 -6
- package/src/i18n/nl.ts +6 -6
- package/src/i18n/pl.ts +19 -19
- package/src/i18n/pt.ts +4 -4
- package/src/i18n/ru.ts +8 -8
- package/src/i18n/sv.ts +5 -5
- package/src/i18n/th.ts +3 -3
- package/src/i18n/tr.ts +37 -37
- package/src/i18n/ua.ts +4 -4
- package/src/i18n/zh.ts +11 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smart-cloud/ai-kit-ui",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"@smart-cloud/wpsuite-core": "^2.2.10",
|
|
25
25
|
"@tabler/icons-react": "^3.40.0",
|
|
26
26
|
"chroma-js": "^3.2.0",
|
|
27
|
+
"country-flag-icons": "^1.6.15",
|
|
27
28
|
"react-markdown": "^10.1.0",
|
|
28
29
|
"rehype-parse": "^9.0.1",
|
|
29
30
|
"rehype-raw": "^7.0.0",
|
|
@@ -41,7 +41,16 @@ import {
|
|
|
41
41
|
type WriteArgs,
|
|
42
42
|
} from "@smart-cloud/ai-kit-core";
|
|
43
43
|
import { I18n } from "aws-amplify/utils";
|
|
44
|
-
import
|
|
44
|
+
import * as CountryFlagIcons from "country-flag-icons/react/3x2";
|
|
45
|
+
import {
|
|
46
|
+
type ComponentProps,
|
|
47
|
+
FC,
|
|
48
|
+
useCallback,
|
|
49
|
+
useEffect,
|
|
50
|
+
useMemo,
|
|
51
|
+
useRef,
|
|
52
|
+
useState,
|
|
53
|
+
} from "react";
|
|
45
54
|
import ReactMarkdown from "react-markdown";
|
|
46
55
|
import remarkGfm from "remark-gfm";
|
|
47
56
|
|
|
@@ -80,8 +89,97 @@ type GeneratedPostMetadata = {
|
|
|
80
89
|
excerpt?: string;
|
|
81
90
|
};
|
|
82
91
|
|
|
92
|
+
type LanguageSelectorOption = {
|
|
93
|
+
value: AiKitLanguageCode;
|
|
94
|
+
label: string;
|
|
95
|
+
countryCode: string;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
type WriterTone = "neutral" | "formal" | "casual";
|
|
99
|
+
type RewriterTone = "as-is" | "more-formal" | "more-casual";
|
|
100
|
+
type WriterLength = "short" | "medium" | "long";
|
|
101
|
+
type RewriterLength = "as-is" | "shorter" | "longer";
|
|
102
|
+
type SummarizerLength = "short" | "medium" | "long";
|
|
103
|
+
type SummarizerType = "headline" | "key-points" | "teaser" | "tldr";
|
|
104
|
+
type ProofreadResult = {
|
|
105
|
+
corrections: ComponentProps<typeof ProofreadDiff>["corrections"];
|
|
106
|
+
correctedInput?: string;
|
|
107
|
+
};
|
|
108
|
+
|
|
83
109
|
const aiKit = getAiKitPlugin();
|
|
84
110
|
|
|
111
|
+
const LANGUAGE_TO_COUNTRY_CODE: Record<AiKitLanguageCode, string> = {
|
|
112
|
+
ar: "SA",
|
|
113
|
+
en: "US",
|
|
114
|
+
zh: "CN",
|
|
115
|
+
nl: "NL",
|
|
116
|
+
fr: "FR",
|
|
117
|
+
de: "DE",
|
|
118
|
+
he: "IL",
|
|
119
|
+
hi: "IN",
|
|
120
|
+
hu: "HU",
|
|
121
|
+
id: "ID",
|
|
122
|
+
it: "IT",
|
|
123
|
+
ja: "JP",
|
|
124
|
+
ko: "KR",
|
|
125
|
+
no: "NO",
|
|
126
|
+
pl: "PL",
|
|
127
|
+
pt: "PT",
|
|
128
|
+
ru: "RU",
|
|
129
|
+
es: "ES",
|
|
130
|
+
sv: "SE",
|
|
131
|
+
th: "TH",
|
|
132
|
+
tr: "TR",
|
|
133
|
+
uk: "UA",
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const RTL_LANGUAGES = new Set<AiKitLanguageCode>(["ar", "he"]);
|
|
137
|
+
|
|
138
|
+
function LanguageFlag(props: { countryCode?: string; size?: number }) {
|
|
139
|
+
const { countryCode, size = 18 } = props;
|
|
140
|
+
|
|
141
|
+
if (!countryCode) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const Flag = CountryFlagIcons[
|
|
146
|
+
countryCode as keyof typeof CountryFlagIcons
|
|
147
|
+
] as FC<ComponentProps<"svg">> | undefined;
|
|
148
|
+
|
|
149
|
+
if (!Flag) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<Flag
|
|
155
|
+
aria-hidden="true"
|
|
156
|
+
focusable="false"
|
|
157
|
+
style={{
|
|
158
|
+
display: "block",
|
|
159
|
+
flex: "none",
|
|
160
|
+
height: size,
|
|
161
|
+
width: Math.round(size * (4 / 3)),
|
|
162
|
+
}}
|
|
163
|
+
/>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function isRtlLanguage(code?: AiKitLanguageCode | "" | null): boolean {
|
|
168
|
+
return Boolean(code && RTL_LANGUAGES.has(code as AiKitLanguageCode));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function getSupportedLanguageOptions(): LanguageSelectorOption[] {
|
|
172
|
+
return LANGUAGE_OPTIONS.map((languageOption) => {
|
|
173
|
+
const countryCode = LANGUAGE_TO_COUNTRY_CODE[languageOption.value];
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
value: languageOption.value,
|
|
177
|
+
label: languageOption.label,
|
|
178
|
+
countryCode,
|
|
179
|
+
};
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
85
183
|
const postResponseConstraint = {
|
|
86
184
|
type: "object",
|
|
87
185
|
properties: {
|
|
@@ -314,9 +412,30 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
314
412
|
onAccept,
|
|
315
413
|
onOptionsChanged,
|
|
316
414
|
language,
|
|
415
|
+
direction,
|
|
317
416
|
rootElement,
|
|
318
417
|
} = props;
|
|
319
418
|
|
|
419
|
+
const [languageOverride, setLanguageOverride] = useState<
|
|
420
|
+
AiKitLanguageCode | undefined
|
|
421
|
+
>();
|
|
422
|
+
const [directionOverride, setDirectionOverride] = useState<
|
|
423
|
+
"ltr" | "rtl" | "auto" | undefined
|
|
424
|
+
>();
|
|
425
|
+
|
|
426
|
+
const effectiveUiLanguage = languageOverride ?? normalizeLang(language);
|
|
427
|
+
I18n.setLanguage(effectiveUiLanguage || "en");
|
|
428
|
+
const currentUiLanguage = effectiveUiLanguage || "en";
|
|
429
|
+
const effectiveDirection = useMemo(() => {
|
|
430
|
+
const activeDirection = languageOverride ? directionOverride : direction;
|
|
431
|
+
|
|
432
|
+
if (!activeDirection || activeDirection === "auto") {
|
|
433
|
+
return isRtlLanguage(effectiveUiLanguage) ? "rtl" : "ltr";
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return activeDirection;
|
|
437
|
+
}, [direction, directionOverride, effectiveUiLanguage, languageOverride]);
|
|
438
|
+
|
|
320
439
|
const allowOverride = {
|
|
321
440
|
text: allowOverrideDefaults?.text ?? true,
|
|
322
441
|
instructions: allowOverrideDefaults?.instructions ?? true,
|
|
@@ -341,7 +460,7 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
341
460
|
(mode === "summarize" && allowOverride?.type) ||
|
|
342
461
|
allowOverride?.outputLanguage,
|
|
343
462
|
);
|
|
344
|
-
}, [allowOverride]);
|
|
463
|
+
}, [allowOverride, mode]);
|
|
345
464
|
|
|
346
465
|
const [state, setState] = useState<string>();
|
|
347
466
|
const [featureOpen, setFeatureOpen] = useState<boolean>(!showOpenButton);
|
|
@@ -375,13 +494,17 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
375
494
|
defaults?.tone,
|
|
376
495
|
);
|
|
377
496
|
const [type, setType] = useState<SummarizerType | undefined>(defaults?.type);
|
|
497
|
+
const [generatedContentLanguage, setGeneratedContentLanguage] = useState<
|
|
498
|
+
AiKitLanguageCode | ""
|
|
499
|
+
>("");
|
|
378
500
|
|
|
379
501
|
const autoRunOnceRef = useRef(false);
|
|
502
|
+
const supportedLanguageOptions = useMemo(
|
|
503
|
+
() => getSupportedLanguageOptions(),
|
|
504
|
+
[],
|
|
505
|
+
);
|
|
380
506
|
|
|
381
507
|
const defaultTitle = useMemo(() => {
|
|
382
|
-
if (language) {
|
|
383
|
-
I18n.setLanguage(language || "en");
|
|
384
|
-
}
|
|
385
508
|
if (title) {
|
|
386
509
|
return title;
|
|
387
510
|
}
|
|
@@ -411,7 +534,7 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
411
534
|
break;
|
|
412
535
|
}
|
|
413
536
|
return t;
|
|
414
|
-
}, [title, mode,
|
|
537
|
+
}, [title, mode, effectiveUiLanguage]);
|
|
415
538
|
|
|
416
539
|
const formatAiKitStatus = useCallback(
|
|
417
540
|
(e: AiKitStatusEvent | null): string | null => {
|
|
@@ -464,7 +587,7 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
464
587
|
return msg || I18n.get("Working...");
|
|
465
588
|
}
|
|
466
589
|
},
|
|
467
|
-
[
|
|
590
|
+
[effectiveUiLanguage, mode],
|
|
468
591
|
);
|
|
469
592
|
|
|
470
593
|
const inputText = useMemo(() => {
|
|
@@ -520,6 +643,18 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
520
643
|
const statusText =
|
|
521
644
|
formatAiKitStatus(ai.statusEvent) ?? (state ? I18n.get(state) : null);
|
|
522
645
|
|
|
646
|
+
const setGeneratedResultLanguage = useCallback(
|
|
647
|
+
(nextLanguage?: AiKitLanguageCode | "auto" | "" | null) => {
|
|
648
|
+
if (nextLanguage && nextLanguage !== "auto") {
|
|
649
|
+
setGeneratedContentLanguage(nextLanguage);
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
setGeneratedContentLanguage(readDefaultOutputLanguage() || "");
|
|
654
|
+
},
|
|
655
|
+
[],
|
|
656
|
+
);
|
|
657
|
+
|
|
523
658
|
const runGenerate = useCallback(
|
|
524
659
|
async (modeOverride?: AiModePreference) => {
|
|
525
660
|
if (!canGenerate) {
|
|
@@ -538,11 +673,11 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
538
673
|
typeof input === "function" ? await Promise.resolve(input()) : input;
|
|
539
674
|
switch (mode) {
|
|
540
675
|
case "summarize": {
|
|
676
|
+
const outLang =
|
|
677
|
+
(outputLanguage && outputLanguage !== "auto"
|
|
678
|
+
? outputLanguage
|
|
679
|
+
: null) || readDefaultOutputLanguage();
|
|
541
680
|
const res = await ai.run(async ({ signal, onStatus }) => {
|
|
542
|
-
const outLang =
|
|
543
|
-
(outputLanguage && outputLanguage !== "auto"
|
|
544
|
-
? outputLanguage
|
|
545
|
-
: null) || readDefaultOutputLanguage();
|
|
546
681
|
const args: SummarizeArgs = {
|
|
547
682
|
text: text!.trim(),
|
|
548
683
|
format:
|
|
@@ -564,6 +699,7 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
564
699
|
const out = await summarize(args, featureOptions);
|
|
565
700
|
return out.result;
|
|
566
701
|
});
|
|
702
|
+
setGeneratedResultLanguage(outLang || "");
|
|
567
703
|
setGenerated((res as never) ?? "");
|
|
568
704
|
break;
|
|
569
705
|
}
|
|
@@ -606,6 +742,10 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
606
742
|
break;
|
|
607
743
|
}
|
|
608
744
|
case "translate": {
|
|
745
|
+
const outLang =
|
|
746
|
+
(outputLanguage && outputLanguage !== "auto"
|
|
747
|
+
? outputLanguage
|
|
748
|
+
: null) || readDefaultOutputLanguage();
|
|
609
749
|
const res = await ai.run(async ({ signal, onStatus }) => {
|
|
610
750
|
let inputLang = inputLanguage ?? "auto";
|
|
611
751
|
if (inputLang === "auto") {
|
|
@@ -621,10 +761,6 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
621
761
|
} else {
|
|
622
762
|
setDetectedLanguage(inputLang);
|
|
623
763
|
}
|
|
624
|
-
const outLang =
|
|
625
|
-
(outputLanguage && outputLanguage !== "auto"
|
|
626
|
-
? outputLanguage
|
|
627
|
-
: null) || readDefaultOutputLanguage();
|
|
628
764
|
if (outLang === inputLang) {
|
|
629
765
|
console.warn(
|
|
630
766
|
"AI Kit: input and output languages are the same",
|
|
@@ -658,10 +794,12 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
658
794
|
const out = await translate(args, featureOptions);
|
|
659
795
|
return out.result;
|
|
660
796
|
});
|
|
797
|
+
setGeneratedResultLanguage(outLang || "");
|
|
661
798
|
setGenerated((res as never) ?? "");
|
|
662
799
|
break;
|
|
663
800
|
}
|
|
664
801
|
case "rewrite": {
|
|
802
|
+
let generatedLanguage: AiKitLanguageCode | "" = "";
|
|
665
803
|
const res = await ai.run(async ({ signal, onStatus }) => {
|
|
666
804
|
let outLang =
|
|
667
805
|
(outputLanguage && outputLanguage !== "auto"
|
|
@@ -678,6 +816,7 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
678
816
|
});
|
|
679
817
|
setOutputLanguage(outLang);
|
|
680
818
|
}
|
|
819
|
+
generatedLanguage = outLang || "";
|
|
681
820
|
const args: RewriteArgs = {
|
|
682
821
|
text: text!.trim(),
|
|
683
822
|
context: instructions?.trim() || undefined,
|
|
@@ -700,6 +839,7 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
700
839
|
const out = await rewrite(args, featureOptions);
|
|
701
840
|
return out.result;
|
|
702
841
|
});
|
|
842
|
+
setGeneratedResultLanguage(generatedLanguage);
|
|
703
843
|
setGenerated((res as never) ?? "");
|
|
704
844
|
break;
|
|
705
845
|
}
|
|
@@ -763,6 +903,7 @@ const AiFeatureBase: FC<AiFeatureProps & AiKitShellInjectedProps> = (props) => {
|
|
|
763
903
|
});
|
|
764
904
|
return out.result;
|
|
765
905
|
});
|
|
906
|
+
setGeneratedResultLanguage(outLang || "");
|
|
766
907
|
setGenerated((res as never) ?? "");
|
|
767
908
|
break;
|
|
768
909
|
}
|
|
@@ -996,7 +1137,7 @@ Follow these additional instructions: ${instructions}`
|
|
|
996
1137
|
default:
|
|
997
1138
|
return ai.lastSource ? I18n.get("Regenerate") : I18n.get("Generate");
|
|
998
1139
|
}
|
|
999
|
-
}, [
|
|
1140
|
+
}, [effectiveUiLanguage, ai.lastSource, mode]);
|
|
1000
1141
|
|
|
1001
1142
|
const getRegenerateOnBackendTitle = useCallback(() => {
|
|
1002
1143
|
switch (mode) {
|
|
@@ -1011,7 +1152,7 @@ Follow these additional instructions: ${instructions}`
|
|
|
1011
1152
|
default:
|
|
1012
1153
|
return I18n.get("Regenerate on Backend");
|
|
1013
1154
|
}
|
|
1014
|
-
}, [
|
|
1155
|
+
}, [effectiveUiLanguage, mode]);
|
|
1015
1156
|
|
|
1016
1157
|
const close = useCallback(async () => {
|
|
1017
1158
|
setFeatureOpen(false);
|
|
@@ -1082,6 +1223,16 @@ Follow these additional instructions: ${instructions}`
|
|
|
1082
1223
|
};
|
|
1083
1224
|
}, []);
|
|
1084
1225
|
|
|
1226
|
+
useEffect(() => {
|
|
1227
|
+
if (!languageOverride) {
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
setDirectionOverride("auto");
|
|
1232
|
+
setOutputLanguage(languageOverride);
|
|
1233
|
+
setDetectedLanguage(undefined);
|
|
1234
|
+
}, [languageOverride]);
|
|
1235
|
+
|
|
1085
1236
|
const optionsSummary = useMemo(() => {
|
|
1086
1237
|
const parts: string[] = [];
|
|
1087
1238
|
|
|
@@ -1126,7 +1277,7 @@ Follow these additional instructions: ${instructions}`
|
|
|
1126
1277
|
|
|
1127
1278
|
return parts.length ? parts.join(" • ") : I18n.get("No overrides");
|
|
1128
1279
|
}, [
|
|
1129
|
-
|
|
1280
|
+
effectiveUiLanguage,
|
|
1130
1281
|
mode,
|
|
1131
1282
|
inputLanguage,
|
|
1132
1283
|
outputLanguage,
|
|
@@ -1151,6 +1302,111 @@ Follow these additional instructions: ${instructions}`
|
|
|
1151
1302
|
const CollapseComponent = optionsDisplay === "collapse" ? Collapse : Stack;
|
|
1152
1303
|
const OptionsComponent = optionsDisplay === "horizontal" ? Group : Stack;
|
|
1153
1304
|
|
|
1305
|
+
const selectedLanguageOption = useMemo(
|
|
1306
|
+
() =>
|
|
1307
|
+
supportedLanguageOptions.find(
|
|
1308
|
+
(option) => option.value === currentUiLanguage,
|
|
1309
|
+
) ?? supportedLanguageOptions[0],
|
|
1310
|
+
[currentUiLanguage, supportedLanguageOptions],
|
|
1311
|
+
);
|
|
1312
|
+
|
|
1313
|
+
const renderLanguageOverrideSelect = useCallback(
|
|
1314
|
+
(size: "xs" | "sm" = "sm") => (
|
|
1315
|
+
<Select
|
|
1316
|
+
allowDeselect={false}
|
|
1317
|
+
aria-label={I18n.get("Interface language")}
|
|
1318
|
+
checkIconPosition="right"
|
|
1319
|
+
className="ai-feature-language-selector"
|
|
1320
|
+
data={supportedLanguageOptions.map((option) => ({
|
|
1321
|
+
value: option.value,
|
|
1322
|
+
label: "",
|
|
1323
|
+
}))}
|
|
1324
|
+
disabled={ai.busy}
|
|
1325
|
+
leftSection={
|
|
1326
|
+
selectedLanguageOption?.countryCode ? (
|
|
1327
|
+
<LanguageFlag
|
|
1328
|
+
countryCode={selectedLanguageOption.countryCode}
|
|
1329
|
+
size={18}
|
|
1330
|
+
/>
|
|
1331
|
+
) : null
|
|
1332
|
+
}
|
|
1333
|
+
onChange={(value) => {
|
|
1334
|
+
const nextLanguage = normalizeLang(value);
|
|
1335
|
+
|
|
1336
|
+
if (!nextLanguage) {
|
|
1337
|
+
return;
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
setLanguageOverride(nextLanguage);
|
|
1341
|
+
}}
|
|
1342
|
+
renderOption={({ option }) => {
|
|
1343
|
+
const languageOption = supportedLanguageOptions.find(
|
|
1344
|
+
(item) => item.value === option.value,
|
|
1345
|
+
);
|
|
1346
|
+
|
|
1347
|
+
if (!languageOption) {
|
|
1348
|
+
return option.label;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
return (
|
|
1352
|
+
<Group gap="xs" wrap="nowrap">
|
|
1353
|
+
{languageOption.countryCode ? (
|
|
1354
|
+
<LanguageFlag
|
|
1355
|
+
countryCode={languageOption.countryCode}
|
|
1356
|
+
size={18}
|
|
1357
|
+
/>
|
|
1358
|
+
) : null}
|
|
1359
|
+
<span>{I18n.get(languageOption.label)}</span>
|
|
1360
|
+
</Group>
|
|
1361
|
+
);
|
|
1362
|
+
}}
|
|
1363
|
+
rightSection={null}
|
|
1364
|
+
searchable={false}
|
|
1365
|
+
size={size}
|
|
1366
|
+
styles={{
|
|
1367
|
+
dropdown: {
|
|
1368
|
+
minWidth: 220,
|
|
1369
|
+
},
|
|
1370
|
+
input: {
|
|
1371
|
+
backgroundColor: "transparent",
|
|
1372
|
+
border: 0,
|
|
1373
|
+
boxShadow: "none",
|
|
1374
|
+
color: "inherit",
|
|
1375
|
+
fontSize: 18,
|
|
1376
|
+
lineHeight: 1,
|
|
1377
|
+
minHeight: size === "sm" ? 36 : 28,
|
|
1378
|
+
paddingInlineStart: 0,
|
|
1379
|
+
paddingInlineEnd: 0,
|
|
1380
|
+
backgroundImage: "none",
|
|
1381
|
+
width: size === "sm" ? 44 : 36,
|
|
1382
|
+
},
|
|
1383
|
+
option: {
|
|
1384
|
+
color: "inherit",
|
|
1385
|
+
},
|
|
1386
|
+
section: {
|
|
1387
|
+
color: "inherit",
|
|
1388
|
+
alignItems: "center",
|
|
1389
|
+
display: "flex",
|
|
1390
|
+
height: "100%",
|
|
1391
|
+
insetInlineStart: 0,
|
|
1392
|
+
justifyContent: "center",
|
|
1393
|
+
pointerEvents: "none",
|
|
1394
|
+
width: "100%",
|
|
1395
|
+
},
|
|
1396
|
+
}}
|
|
1397
|
+
value={selectedLanguageOption?.value || null}
|
|
1398
|
+
w={size === "sm" ? 44 : 36}
|
|
1399
|
+
/>
|
|
1400
|
+
),
|
|
1401
|
+
[
|
|
1402
|
+
ai.busy,
|
|
1403
|
+
selectedLanguageOption?.countryCode,
|
|
1404
|
+
selectedLanguageOption?.value,
|
|
1405
|
+
setLanguageOverride,
|
|
1406
|
+
supportedLanguageOptions,
|
|
1407
|
+
],
|
|
1408
|
+
);
|
|
1409
|
+
|
|
1154
1410
|
useEffect(() => {
|
|
1155
1411
|
if (variation !== "modal" || !featureOpen) {
|
|
1156
1412
|
return;
|
|
@@ -1214,14 +1470,25 @@ Follow these additional instructions: ${instructions}`
|
|
|
1214
1470
|
{variation === "modal" && <Modal.Overlay />}
|
|
1215
1471
|
<ContentComponent
|
|
1216
1472
|
w="100%"
|
|
1473
|
+
dir={effectiveDirection}
|
|
1217
1474
|
style={{
|
|
1218
1475
|
left: 0,
|
|
1219
1476
|
}}
|
|
1220
1477
|
>
|
|
1221
1478
|
{variation === "modal" && (
|
|
1222
|
-
<Modal.Header style={{ zIndex: 1000 }}>
|
|
1479
|
+
<Modal.Header dir={effectiveDirection} style={{ zIndex: 1000 }}>
|
|
1223
1480
|
{getOpenButtonDefaultIcon("ai-feature-title-icon")}
|
|
1224
1481
|
<Modal.Title>{I18n.get(defaultTitle)}</Modal.Title>
|
|
1482
|
+
<div
|
|
1483
|
+
style={{
|
|
1484
|
+
display: "flex",
|
|
1485
|
+
flex: 1,
|
|
1486
|
+
justifyContent: "flex-start",
|
|
1487
|
+
marginRight: 8,
|
|
1488
|
+
}}
|
|
1489
|
+
>
|
|
1490
|
+
{renderLanguageOverrideSelect("xs")}
|
|
1491
|
+
</div>
|
|
1225
1492
|
<Modal.CloseButton />
|
|
1226
1493
|
</Modal.Header>
|
|
1227
1494
|
)}
|
|
@@ -1231,7 +1498,13 @@ Follow these additional instructions: ${instructions}`
|
|
|
1231
1498
|
working={ai.busy}
|
|
1232
1499
|
variation={variation}
|
|
1233
1500
|
>
|
|
1234
|
-
<Stack gap="sm" mb="sm" p="sm">
|
|
1501
|
+
<Stack gap="sm" mb="sm" p="sm" dir={effectiveDirection}>
|
|
1502
|
+
{variation !== "modal" && (
|
|
1503
|
+
<Group justify="flex-end">
|
|
1504
|
+
{renderLanguageOverrideSelect()}
|
|
1505
|
+
</Group>
|
|
1506
|
+
)}
|
|
1507
|
+
|
|
1235
1508
|
{/* ERROR */}
|
|
1236
1509
|
{error && <Alert color="red">{I18n.get(error)}</Alert>}
|
|
1237
1510
|
|
|
@@ -1877,6 +2150,7 @@ Follow these additional instructions: ${instructions}`
|
|
|
1877
2150
|
mode !== "generatePostMetadata" &&
|
|
1878
2151
|
typeof generated === "string" && (
|
|
1879
2152
|
<MarkdownResult
|
|
2153
|
+
contentLanguage={generatedContentLanguage}
|
|
1880
2154
|
value={generated}
|
|
1881
2155
|
editable={!!editable}
|
|
1882
2156
|
onChange={(v) => {
|
|
@@ -1887,7 +2161,11 @@ Follow these additional instructions: ${instructions}`
|
|
|
1887
2161
|
</Stack>
|
|
1888
2162
|
)}
|
|
1889
2163
|
{generated === "" && (
|
|
1890
|
-
<MarkdownResult
|
|
2164
|
+
<MarkdownResult
|
|
2165
|
+
contentLanguage={generatedContentLanguage}
|
|
2166
|
+
value={generated}
|
|
2167
|
+
editable={false}
|
|
2168
|
+
/>
|
|
1891
2169
|
)}
|
|
1892
2170
|
</Stack>
|
|
1893
2171
|
{/* ACTIONS */}
|
|
@@ -1974,15 +2252,23 @@ Follow these additional instructions: ${instructions}`
|
|
|
1974
2252
|
};
|
|
1975
2253
|
|
|
1976
2254
|
function MarkdownResult(props: {
|
|
2255
|
+
contentLanguage?: AiKitLanguageCode | "";
|
|
1977
2256
|
value: string;
|
|
1978
2257
|
editable: boolean;
|
|
1979
2258
|
onChange?: (v: string) => void;
|
|
1980
2259
|
}) {
|
|
1981
|
-
const { value, editable, onChange } = props;
|
|
2260
|
+
const { contentLanguage, value, editable, onChange } = props;
|
|
2261
|
+
const contentDirection = isRtlLanguage(contentLanguage) ? "rtl" : "ltr";
|
|
2262
|
+
const contentAlign = contentDirection === "rtl" ? "right" : "left";
|
|
1982
2263
|
|
|
1983
2264
|
if (editable) {
|
|
1984
2265
|
return (
|
|
1985
|
-
<Stack
|
|
2266
|
+
<Stack
|
|
2267
|
+
p={0}
|
|
2268
|
+
gap="sm"
|
|
2269
|
+
dir={contentDirection}
|
|
2270
|
+
style={{ textAlign: contentAlign }}
|
|
2271
|
+
>
|
|
1986
2272
|
<Input.Label>{I18n.get("Generated content")}</Input.Label>
|
|
1987
2273
|
<Textarea
|
|
1988
2274
|
value={value}
|
|
@@ -1992,10 +2278,17 @@ function MarkdownResult(props: {
|
|
|
1992
2278
|
maxRows={12}
|
|
1993
2279
|
p={0}
|
|
1994
2280
|
className="ai-feature-generated-content ai-feature-editor"
|
|
2281
|
+
styles={{
|
|
2282
|
+
input: { direction: contentDirection, textAlign: contentAlign },
|
|
2283
|
+
}}
|
|
1995
2284
|
/>
|
|
1996
2285
|
|
|
1997
2286
|
<Input.Label>{I18n.get("Preview")}</Input.Label>
|
|
1998
|
-
<Stack
|
|
2287
|
+
<Stack
|
|
2288
|
+
className="ai-feature-generated-content ai-feature-preview"
|
|
2289
|
+
dir={contentDirection}
|
|
2290
|
+
style={{ textAlign: contentAlign }}
|
|
2291
|
+
>
|
|
1999
2292
|
<ReactMarkdown remarkPlugins={[remarkGfm]}>{value}</ReactMarkdown>
|
|
2000
2293
|
</Stack>
|
|
2001
2294
|
</Stack>
|
|
@@ -2003,7 +2296,11 @@ function MarkdownResult(props: {
|
|
|
2003
2296
|
}
|
|
2004
2297
|
|
|
2005
2298
|
return (
|
|
2006
|
-
<Stack
|
|
2299
|
+
<Stack
|
|
2300
|
+
className="ai-feature-generated-content"
|
|
2301
|
+
dir={contentDirection}
|
|
2302
|
+
style={{ textAlign: contentAlign }}
|
|
2303
|
+
>
|
|
2007
2304
|
{value ? (
|
|
2008
2305
|
<ReactMarkdown remarkPlugins={[remarkGfm]}>{value}</ReactMarkdown>
|
|
2009
2306
|
) : (
|
package/src/i18n/ar.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const arDict: Record<string, string> = {
|
|
2
2
|
"--- Select ---": "--- اختر ---",
|
|
3
|
-
Accept: "
|
|
3
|
+
Accept: "قبول",
|
|
4
4
|
"Accept response": "قبول الرد",
|
|
5
5
|
Add: "إضافة",
|
|
6
6
|
"Add image": "إضافة صورة",
|
|
@@ -24,7 +24,7 @@ export const arDict: Record<string, string> = {
|
|
|
24
24
|
"Audio no longer available": "الرسالة الصوتية لم تعد متاحة",
|
|
25
25
|
"Audio recorded": "تم تسجيل الصوت",
|
|
26
26
|
auto: "آلي",
|
|
27
|
-
"Auto-detect": "
|
|
27
|
+
"Auto-detect": "اكتشاف تلقائي",
|
|
28
28
|
Cancel: "يلغي",
|
|
29
29
|
Caption: "التسمية التوضيحية",
|
|
30
30
|
Casual: "غير رسمي",
|
|
@@ -32,7 +32,7 @@ export const arDict: Record<string, string> = {
|
|
|
32
32
|
Categories: "الفئات",
|
|
33
33
|
"Checking capabilities…": "إمكانيات الفحص…",
|
|
34
34
|
Chinese: "الصينية",
|
|
35
|
-
Clear: "",
|
|
35
|
+
Clear: "مسح",
|
|
36
36
|
"Clear audio": "مسح الصوت",
|
|
37
37
|
"Click again to confirm": "انقر مرة أخرى للتأكيد",
|
|
38
38
|
Close: "يغلق",
|
|
@@ -63,7 +63,7 @@ export const arDict: Record<string, string> = {
|
|
|
63
63
|
Formal: "رَسمِيّ",
|
|
64
64
|
formal: "رَسمِيّ",
|
|
65
65
|
French: "فرنسي",
|
|
66
|
-
Generate: "
|
|
66
|
+
Generate: "إنشاء",
|
|
67
67
|
"Generate Image Metadata": "إنشاء بيانات وصفية للصورة",
|
|
68
68
|
"Generate Post Metadata": "إنشاء بيانات وصفية للمقال",
|
|
69
69
|
"Generated content": "المحتوى المُنشأ",
|
|
@@ -98,7 +98,7 @@ export const arDict: Record<string, string> = {
|
|
|
98
98
|
long: "طويل",
|
|
99
99
|
Longer: "أطول",
|
|
100
100
|
longer: "أطول",
|
|
101
|
-
Markdown: "
|
|
101
|
+
Markdown: "Markdown",
|
|
102
102
|
Maximize: "تكبير",
|
|
103
103
|
Medium: "واسطة",
|
|
104
104
|
medium: "واسطة",
|
|
@@ -127,14 +127,14 @@ export const arDict: Record<string, string> = {
|
|
|
127
127
|
Preview: "معاينة",
|
|
128
128
|
Proofread: "التدقيق اللغوي",
|
|
129
129
|
"Proofread again": "راجع النص مرة أخرى",
|
|
130
|
-
"Proofread on Backend": "
|
|
130
|
+
"Proofread on Backend": "تدقيق لغوي على الخادم",
|
|
131
131
|
Proofreading: "التدقيق اللغوي",
|
|
132
132
|
"Proofreading part {current}/{total}...":
|
|
133
133
|
"جارٍ تدقيق الجزء {current}/{total}...",
|
|
134
134
|
"Ready.": "جاهز.",
|
|
135
135
|
"Received backend response.": "تم استلام رد من الخادم الخلفي.",
|
|
136
136
|
"Receiving response...": "جارٍ استلام الرد...",
|
|
137
|
-
Record: "",
|
|
137
|
+
Record: "تسجيل",
|
|
138
138
|
"Record audio": "تسجيل الصوت",
|
|
139
139
|
"Recorded audio:": "صوت مسجّل:",
|
|
140
140
|
"Recording...": "جارٍ التسجيل...",
|
|
@@ -151,7 +151,7 @@ export const arDict: Record<string, string> = {
|
|
|
151
151
|
"Restore size": "استعادة الحجم",
|
|
152
152
|
Rewrite: "إعادة كتابة",
|
|
153
153
|
"Rewrite again": "أعد الكتابة مرة أخرى",
|
|
154
|
-
"Rewrite on Backend": "إعادة كتابة
|
|
154
|
+
"Rewrite on Backend": "إعادة كتابة على الخادم",
|
|
155
155
|
"Rewriting part {current}/{total}...":
|
|
156
156
|
"جارٍ إعادة كتابة الجزء {current}/{total}...",
|
|
157
157
|
"Rewriting text": "إعادة كتابة النص",
|
|
@@ -179,13 +179,13 @@ export const arDict: Record<string, string> = {
|
|
|
179
179
|
"Suggested change": "التغيير المقترح",
|
|
180
180
|
Summarize: "لخص",
|
|
181
181
|
"Summarize again": "أعد التلخيص",
|
|
182
|
-
"Summarize on Backend": "تلخيص على
|
|
182
|
+
"Summarize on Backend": "تلخيص على الخادم",
|
|
183
183
|
Summarizing: "ملخص",
|
|
184
184
|
"Summarizing part {current}/{total}...":
|
|
185
185
|
"جارٍ تلخيص الجزء {current}/{total}...",
|
|
186
186
|
Swedish: "السويدية",
|
|
187
187
|
Tags: "الوسوم",
|
|
188
|
-
Teaser: "
|
|
188
|
+
Teaser: "نص تمهيدي",
|
|
189
189
|
teaser: "إعلان تشويقي",
|
|
190
190
|
Thai: "تايلاندي",
|
|
191
191
|
"The alt text for the image.": "النص البديل للصورة.",
|
|
@@ -208,11 +208,11 @@ export const arDict: Record<string, string> = {
|
|
|
208
208
|
Title: "عنوان",
|
|
209
209
|
"TL;DR": "باختصار شديد",
|
|
210
210
|
tldr: "باختصار",
|
|
211
|
-
Tone: "
|
|
212
|
-
Topic: "
|
|
211
|
+
Tone: "الأسلوب",
|
|
212
|
+
Topic: "الموضوع",
|
|
213
213
|
Translate: "يترجم",
|
|
214
214
|
"Translate again": "ترجم مرة أخرى",
|
|
215
|
-
"Translate on Backend": "
|
|
215
|
+
"Translate on Backend": "ترجمة على الخادم",
|
|
216
216
|
Translating: "الترجمة",
|
|
217
217
|
"Translating part {current}/{total}...":
|
|
218
218
|
"جارٍ ترجمة الجزء {current}/{total}...",
|