feat: i18n in widget

This commit is contained in:
Tristan Yang
2023-05-01 20:34:21 +08:00
parent f13616f176
commit a5deb17f76
10 changed files with 56 additions and 20 deletions
+3
View File
@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" stroke="#101828" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22 2L11 13M22 2L15 22L11 13M22 2L2 9L11 13" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 241 B

+4 -2
View File
@@ -8,6 +8,7 @@ import auth from "../public/locales/en/auth.json";
import member from "../public/locales/en/member.json";
import chat from "../public/locales/en/chat.json";
import fav from "../public/locales/en/fav.json";
import widget from "../public/locales/en/widget.json";
import welcome from "../public/locales/en/welcome.json";
import setting from "../public/locales/en/setting.json";
import file from "../public/locales/en/file.json";
@@ -26,7 +27,8 @@ export const resources = {
member,
welcome,
setting,
file
file,
widget
}
} as const;
i18n.on("languageChanged", (lng) => {
@@ -46,7 +48,7 @@ i18n
// init i18next
// for all options read: https://www.i18next.com/overview/configuration-options
.init<HttpBackendOptions>({
ns: ["common", "chat", "member", "setting", "fav", "file", "welcome", "auth"],
ns: ["common", "chat", "member", "setting", "fav", "file", "welcome", "auth", "widget"],
defaultNS,
load: "languageOnly",
// lng: "jp",
+3 -1
View File
@@ -6,7 +6,9 @@ type Props = {
const Index: FC<Props> = () => {
return (
<footer className="text-xs text-gray-300 text-center pb-2">Host your own <a href="https://voce.chat" target="_blank" rel="noopener noreferrer" className="text-gray-400">voce.chat</a></footer>
<footer className="text-xs text-gray-300 text-center pb-2">
Host your own <a href="https://voce.chat" target="_blank" rel="noopener noreferrer" className="text-gray-400">voce.chat</a>
</footer>
);
};
+1 -1
View File
@@ -11,7 +11,7 @@ const Index: FC<Props> = ({ handleClose }) => {
return (
<header className="relative flex justify-between items-center h-14 px-4 py-2" style={{ backgroundColor: color }}>
<div className="relative w-8 h-8">
<img src={logo} alt="logo" className="w-full h-full rounded-full" />
{logo && <img src={logo} alt="logo" className="w-full h-full rounded-full" />}
</div>
<div className="flex-1 px-4 pr-2 text-lg">
<span className="text-lg font-bold truncate text-gray-50" style={{ color: fgColor }}>{name}</span>
+7 -3
View File
@@ -14,10 +14,12 @@ import Input from '../../../common/component/styled/Input';
import useGithubAuthConfig from '../../../common/hook/useGithubAuthConfig';
import useGoogleAuthConfig from '../../../common/hook/useGoogleAuthConfig';
import { useWidget } from '../../WidgetContext';
import { useTranslation } from 'react-i18next';
// type Props = {}
const Login = () => {
const { t } = useTranslation("widget");
const dispatch = useDispatch();
const { color, fgColor, from } = useWidget();
const { clientId } = useGoogleAuthConfig();
@@ -72,10 +74,12 @@ const Login = () => {
return (
<div className="w-full max-w-[288px] flex flex-col gap-2 mt-4 animate-[fadeInUp_.5s_.8s_ease-in-out_both]">
<div className="bg-white dark:bg-gray-700 border dark:border-gray-500 rounded-lg">
<form className="px-4 py-3 flex flex-col gap-2" onSubmit={handleSubmit}>
<Input required placeholder="Name" name='username' />
<form className="px-4 py-3 flex flex-col gap-2" onSubmit={handleSubmit} >
<Input required placeholder="Name" type='text' name='username' />
{/* <Input required placeholder="Email" type="email" name='email' /> */}
<StyledButton disabled={isLoading} type="submit" className={clsx("small", `bg-[${color}] text-[${fgColor}]`)}>Start Chat</StyledButton>
<StyledButton disabled={isLoading} type="submit" className={clsx("small", `bg-[${color}] text-[${fgColor}]`)}>
{t("start_chat")}
</StyledButton>
{hasSocialLogins && <Divider content='OR' />}
{googleLogin && <GoogleLoginButton clientId={clientId} />}
{enableGithubLogin && <GithubLoginButton client_id={githubAuthConfig?.client_id} source="widget" />}
+4 -3
View File
@@ -33,9 +33,10 @@ const Index = (props: IWidgetMessage) => {
break;
}
return <div className={clsx('group flex mb-3', host ? 'relative justify-start items-start' : 'items-center justify-end px-3')}>
{host ? <><div className="w-9 h-9 absolute top-0 left-3">
<img src={logo} alt="avatar" className='rounded-full w-9 h-9' />
</div>
{host ? <>
<div className="w-9 h-9 absolute top-0 left-3">
<img src={logo} alt="avatar" className='rounded-full w-9 h-9' />
</div>
<div className="pl-14 flex items-center">
{contentContainer}
<Time time={create_time} />
+16 -7
View File
@@ -2,6 +2,8 @@ import { useRef, useState, memo } from 'react';
import clsx from 'clsx';
import useSendMessage from '../../common/hook/useSendMessage';
import { useWidget } from '../WidgetContext';
import IconSend from '../../assets/icons/send.svg';
import { useTranslation } from 'react-i18next';
@@ -11,6 +13,7 @@ type Props = {
}
let isComposing = false;
const MessageInput = (props: Props) => {
const { t } = useTranslation("widget");
const { color } = useWidget();
const { from, to } = props;
const { sendMessage } = useSendMessage({
@@ -27,16 +30,23 @@ const MessageInput = (props: Props) => {
`ring-1 ring-gray-200 dark:ring-gray-800 focus:ring-2 focus:ring-[${color}]`,
'focus:outline-none',
);
const handleSend = () => {
sendMessage({
type: "text",
content
});
setContent("");
};
return (
<div className="relative border-t border-gray-300 dark:border-gray-600 w-full">
<div className={'px-3 py-2 min-h-[48px]'}>
<div className={'px-3 py-2 min-h-[48px] flex items-center gap-2'}>
<textarea
// disabled={isSending}
ref={ref}
maxLength={4096}
className={textareaClassName}
value={content}
placeholder="Type and press enter"
placeholder={t("placeholder_send")}
onChange={e => setContent(e.target.value)}
onCompositionStart={() => {
isComposing = true;
@@ -56,14 +66,13 @@ const MessageInput = (props: Props) => {
// e.stopPropagation();
e.preventDefault();
if (content.trim().length === 0) return;
sendMessage({
type: "text",
content
});
setContent("");
handleSend();
}
}}
/>
<button onClick={handleSend} disabled={content.trim().length === 0} className='px-2 py-1 disabled:opacity-60'>
<IconSend className="dark:stroke-white w-4 h-4" />
</button>
</div>
</div>
);
+6 -3
View File
@@ -2,25 +2,28 @@
import { memo } from 'react';
import { useAppSelector } from '../../app/store';
import Login from './Login';
import { useTranslation } from 'react-i18next';
type Props = {
needLogin?: boolean
}
const Index = ({ needLogin = false }: Props) => {
const { logo } = useAppSelector(store => store.server);
const { t } = useTranslation("widget");
// console.log("logooo", logo);
return (
<>
<div className="group relative flex justify-start items-start mb-3">
<div className="w-9 h-9 absolute top-0 left-3">
<img src={logo} alt="logo" className="rounded-full bg-transparent w-9 h-9" />
{logo && <img src={logo} alt="logo" className="rounded-full bg-transparent w-9 h-9" />}
</div>
<div className="pl-14">
<div className="rounded-lg" style={{ maxWidth: 'min(((100vw - 56px) - 20px) - 64px, 360px)' }}>
<div className="text-md text-gray-900 dark:text-gray-100 px-3 py-1.5 bg-gray-100 dark:bg-gray-900 rounded-lg mb-1.5">
{needLogin ?
`👋 Hi there, Nice to meet you! Please login before we have a nice talk 👇`
t("welcome_not_login")
:
`👋 Hi there, Nice to meet you! `}
t("welcome")}
</div>
</div>
</div>