feat: i18n
This commit is contained in:
@@ -4,6 +4,7 @@ import usePinMessage from "../../../common/hook/usePinMessage";
|
||||
import PreviewMessage from "../../../common/component/Message/PreviewMessage";
|
||||
import IconSurprise from "../../../assets/icons/emoji.surprise.svg";
|
||||
import IconClose from "../../../assets/icons/close.svg";
|
||||
import { useTranslation } from "react-i18next";
|
||||
const Styled = styled.div`
|
||||
padding: 16px;
|
||||
background: #f9fafb;
|
||||
@@ -86,6 +87,7 @@ type Props = {
|
||||
id: number;
|
||||
};
|
||||
const PinList: FC<Props> = ({ id }: Props) => {
|
||||
const { t } = useTranslation("chat");
|
||||
const { pins, unpinMessage, canPin } = usePinMessage(id);
|
||||
const handleUnpin = (evt: FormEvent<HTMLButtonElement>) => {
|
||||
const { mid } = evt.currentTarget.dataset;
|
||||
@@ -95,12 +97,12 @@ const PinList: FC<Props> = ({ id }: Props) => {
|
||||
const noPins = pins.length == 0;
|
||||
return (
|
||||
<Styled>
|
||||
<h4 className="head">Pinned Message({pins.length})</h4>
|
||||
<h4 className="head">{t("pinned_msg")}({pins.length})</h4>
|
||||
|
||||
{noPins ? (
|
||||
<div className="none">
|
||||
<IconSurprise />
|
||||
<div className="tip">This channel doesn’t have any pinned message yet.</div>
|
||||
<div className="tip">{t("pin_empty_tip")}</div>
|
||||
</div>
|
||||
) : (
|
||||
<ul className="list">
|
||||
|
||||
@@ -28,11 +28,13 @@ import InviteModal from "../../../common/component/InviteModal";
|
||||
import LoadMore from "../LoadMore";
|
||||
import { useAppSelector } from "../../../app/store";
|
||||
import { AgoraConfig } from "../../../types/server";
|
||||
import { useTranslation } from "react-i18next";
|
||||
type Props = {
|
||||
cid?: number;
|
||||
dropFiles?: File[];
|
||||
};
|
||||
function ChannelChat({ cid = 0, dropFiles = [] }: Props) {
|
||||
const { t } = useTranslation("chat");
|
||||
const { values: agoraConfig } = useConfig("agora");
|
||||
const {
|
||||
list: msgIds,
|
||||
@@ -105,7 +107,7 @@ function ChannelChat({ cid = 0, dropFiles = [] }: Props) {
|
||||
</Tooltip>
|
||||
</li>
|
||||
)}
|
||||
<Tooltip tip="Pin" placement="left">
|
||||
<Tooltip tip={t("pin")} placement="left">
|
||||
<Tippy
|
||||
placement="left-start"
|
||||
popperOptions={{ strategy: "fixed" }}
|
||||
@@ -119,7 +121,7 @@ function ChannelChat({ cid = 0, dropFiles = [] }: Props) {
|
||||
</li>
|
||||
</Tippy>
|
||||
</Tooltip>
|
||||
<Tooltip tip="Favorite" placement="left">
|
||||
<Tooltip tip={t("fav")} placement="left">
|
||||
<Tippy
|
||||
placement="left-start"
|
||||
popperOptions={{ strategy: "fixed" }}
|
||||
@@ -137,7 +139,7 @@ function ChannelChat({ cid = 0, dropFiles = [] }: Props) {
|
||||
className={`tool ${membersVisible ? "active" : ""}`}
|
||||
onClick={toggleMembersVisible}
|
||||
>
|
||||
<Tooltip tip="Channel Members" placement="left">
|
||||
<Tooltip tip={t("channel_members")} placement="left">
|
||||
<IconPeople />
|
||||
</Tooltip>
|
||||
</li>
|
||||
@@ -160,7 +162,7 @@ function ChannelChat({ cid = 0, dropFiles = [] }: Props) {
|
||||
{addVisible && (
|
||||
<div className="add" onClick={toggleAddVisible}>
|
||||
<img className="icon" src={addIcon} />
|
||||
<div className="txt">Add members</div>
|
||||
<div className="txt">{t("add_channel_members")}</div>
|
||||
</div>
|
||||
)}
|
||||
{memberIds.map((uid: number) => {
|
||||
@@ -186,12 +188,12 @@ function ChannelChat({ cid = 0, dropFiles = [] }: Props) {
|
||||
<LoadMore pullUp={pullUp} />
|
||||
) : (
|
||||
<div className="info">
|
||||
<h2 className="title">Welcome to #{name} !</h2>
|
||||
<p className="desc">This is the start of the #{name} channel. </p>
|
||||
<h2 className="title">{t("welcome_channel", { name })}</h2>
|
||||
<p className="desc">{t("welcome_desc", { name })} </p>
|
||||
{loginUser?.is_admin && (
|
||||
<NavLink to={`/setting/channel/${cid}?f=${pathname}`} className="edit">
|
||||
<EditIcon className="icon" />
|
||||
Edit Channel
|
||||
{t("edit_channel")}
|
||||
</NavLink>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -15,12 +15,14 @@ import StyledLink from "./styled";
|
||||
import ChannelIcon from "../../../common/component/ChannelIcon";
|
||||
import { getUnreadCount } from "../utils";
|
||||
import { useAppSelector } from "../../../app/store";
|
||||
import { useTranslation } from "react-i18next";
|
||||
interface IProps {
|
||||
id: number;
|
||||
setFiles: (files: File[]) => void;
|
||||
toggleRemoveConfirm: (id: number) => void;
|
||||
}
|
||||
const NavItem: FC<IProps> = ({ id, setFiles, toggleRemoveConfirm }) => {
|
||||
const { t } = useTranslation();
|
||||
const { pathname } = useLocation();
|
||||
const [inviteModalVisible, setInviteModalVisible] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
@@ -118,20 +120,20 @@ const NavItem: FC<IProps> = ({ id, setFiles, toggleRemoveConfirm }) => {
|
||||
hideMenu={hideContextMenu}
|
||||
items={[
|
||||
{
|
||||
title: "Mark As Read",
|
||||
title: t("action.mark_read"),
|
||||
underline: true,
|
||||
handler: handleReadAll
|
||||
},
|
||||
{
|
||||
title: muted ? "Unmute" : "Mute",
|
||||
title: muted ? t("action.unmute") : t("action.mute"),
|
||||
handler: handleMute
|
||||
},
|
||||
{
|
||||
title: "Invite People",
|
||||
title: t("action.invite_people"),
|
||||
handler: toggleInviteModalVisible
|
||||
},
|
||||
{
|
||||
title: "Delete Channel",
|
||||
title: t("channel.delete", { ns: "setting" }),
|
||||
danger: true,
|
||||
handler: toggleRemoveConfirm.bind(null, id)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ import User from "../../../common/component/User";
|
||||
import { ContentTypes } from "../../../app/config";
|
||||
import { useAppSelector } from "../../../app/store";
|
||||
import { ArchiveMessage } from "../../../types/resource";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface IProps {
|
||||
uid: number;
|
||||
mid?: number;
|
||||
@@ -24,6 +26,7 @@ interface IProps {
|
||||
setFiles: (files: File[]) => void;
|
||||
}
|
||||
const NavItem: FC<IProps> = ({ uid, mid = 0, unreads, setFiles }) => {
|
||||
const { t } = useTranslation();
|
||||
const [previewMsg, setPreviewMsg] = useState<ArchiveMessage>();
|
||||
const { messages: normalizedMessages, normalizeMessage } = useNormalizeMessage();
|
||||
const dispatch = useDispatch();
|
||||
@@ -93,11 +96,11 @@ const NavItem: FC<IProps> = ({ uid, mid = 0, unreads, setFiles }) => {
|
||||
hideMenu={hideContextMenu}
|
||||
items={[
|
||||
{
|
||||
title: "Mark As Read",
|
||||
title: t("action.mark_read"),
|
||||
handler: handleReadAll
|
||||
},
|
||||
{
|
||||
title: "Hide Session",
|
||||
title: t("action.hide_session"),
|
||||
danger: true,
|
||||
handler: handleRemoveSession
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import FavoredMessage from "../../common/component/Message/FavoredMessage";
|
||||
import IconSurprise from "../../assets/icons/emoji.surprise.svg";
|
||||
import IconRemove from "../../assets/icons/close.svg";
|
||||
import useFavMessage from "../../common/hook/useFavMessage";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const Styled = styled.div`
|
||||
padding: 16px;
|
||||
@@ -84,6 +85,7 @@ const Styled = styled.div`
|
||||
`;
|
||||
type Props = { cid?: number; uid?: number };
|
||||
const FavList: FC<Props> = ({ cid = null, uid = null }) => {
|
||||
const { t } = useTranslation("chat");
|
||||
const { favorites, removeFavorite } = useFavMessage({ cid, uid });
|
||||
const handleRemove = (evt: MouseEvent<HTMLButtonElement>) => {
|
||||
const { id = "" } = evt.currentTarget.dataset;
|
||||
@@ -93,11 +95,11 @@ const FavList: FC<Props> = ({ cid = null, uid = null }) => {
|
||||
const noFavs = favorites.length == 0;
|
||||
return (
|
||||
<Styled>
|
||||
<h4 className="head">Saved Message({favorites.length})</h4>
|
||||
<h4 className="head">{t('fav_msg')}({favorites.length})</h4>
|
||||
{noFavs ? (
|
||||
<div className="none">
|
||||
<IconSurprise />
|
||||
<div className="tip">This channel doesn’t have any saved message yet.</div>
|
||||
<div className="tip">{t("fav_empty_tip")}</div>
|
||||
</div>
|
||||
) : (
|
||||
<ul className="list">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import styled from "styled-components";
|
||||
@@ -32,6 +33,7 @@ const Styled = styled.div`
|
||||
// type Props = {};
|
||||
|
||||
const GuestBlankPlaceholder = () => {
|
||||
const { t } = useTranslation("auth");
|
||||
const dispatch = useDispatch();
|
||||
const { clearLocalData } = useLogout();
|
||||
const navigateTo = useNavigate();
|
||||
@@ -43,10 +45,10 @@ const GuestBlankPlaceholder = () => {
|
||||
};
|
||||
return (
|
||||
<Styled>
|
||||
<h2 className="title">Welcome to {serverName} server</h2>
|
||||
<h2 className="title">{t("welcome", { name: serverName })}</h2>
|
||||
<div className="details">
|
||||
<span className="desc">Please sign in to send a message</span>
|
||||
<Button onClick={handleSignIn} className="small">{`Sign In`}</Button>
|
||||
<span className="desc">{t("guest_login_tip")}</span>
|
||||
<Button onClick={handleSignIn} className="small">{t("sign_in")}</Button>
|
||||
</div>
|
||||
</Styled>
|
||||
);
|
||||
|
||||
@@ -11,6 +11,7 @@ import { useAppSelector } from "../../../app/store";
|
||||
import LoginTip from "./LoginTip";
|
||||
import useLicense from "../../../common/hook/useLicense";
|
||||
import LicenseUpgradeTip from "./LicenseOutdatedTip";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface Props {
|
||||
readonly?: boolean;
|
||||
@@ -33,6 +34,7 @@ const Layout: FC<Props> = ({
|
||||
context = "channel",
|
||||
to
|
||||
}) => {
|
||||
const { t } = useTranslation('chat');
|
||||
const { reachLimit } = useLicense();
|
||||
const { addStageFile } = useUploadFile({ context, id: to });
|
||||
const messagesContainer = useRef<HTMLDivElement>(null);
|
||||
@@ -129,7 +131,7 @@ const Layout: FC<Props> = ({
|
||||
>
|
||||
<div className={`box ${isActive ? "animate__animated animate__bounceIn" : ""}`}>
|
||||
<div className="inner">
|
||||
<h4 className="head">{`Send to ${ChatPrefixes[context]}${name}`}</h4>
|
||||
<h4 className="head">{`${t("send_to")} ${ChatPrefixes[context]}${name}`}</h4>
|
||||
<span className="intro">Photos accept jpg, png, max size limit to 10M.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,8 @@ import { removeUserSession } from "../../../app/slices/message.user";
|
||||
import ContextMenu, { Item } from "../../../common/component/ContextMenu";
|
||||
import useUserOperation from "../../../common/hook/useUserOperation";
|
||||
import { useAppSelector } from "../../../app/store";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { t } from "i18next";
|
||||
type Props = {
|
||||
context: "user" | "channel";
|
||||
id: number;
|
||||
@@ -28,6 +30,7 @@ const SessionContextMenu: FC<Props> = ({
|
||||
setInviteChannelId,
|
||||
children
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { canCopyEmail, copyEmail, canDeleteChannel } = useUserOperation({
|
||||
uid: context == "user" ? id : undefined,
|
||||
cid: context == "channel" ? id : undefined
|
||||
@@ -71,45 +74,45 @@ const SessionContextMenu: FC<Props> = ({
|
||||
const items =
|
||||
context == "user"
|
||||
? [
|
||||
{
|
||||
title: "Mark As Read",
|
||||
handler: handleReadAll
|
||||
},
|
||||
canCopyEmail && {
|
||||
title: "Copy Email",
|
||||
handler: copyEmail
|
||||
},
|
||||
{
|
||||
title: "Hide Session",
|
||||
danger: true,
|
||||
handler: handleRemoveSession
|
||||
}
|
||||
]
|
||||
{
|
||||
title: t("action.mark_read"),
|
||||
handler: handleReadAll
|
||||
},
|
||||
canCopyEmail && {
|
||||
title: t("action.copy_email"),
|
||||
handler: copyEmail
|
||||
},
|
||||
{
|
||||
title: t("action.hide_session"),
|
||||
danger: true,
|
||||
handler: handleRemoveSession
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
title: "Settings",
|
||||
underline: true,
|
||||
handler: handleChannelSetting
|
||||
},
|
||||
{
|
||||
title: "Mark As Read",
|
||||
// underline: true
|
||||
handler: handleReadAll
|
||||
},
|
||||
{
|
||||
title: channelMuted ? "Unmute" : "Mute",
|
||||
handler: handleChannelMute
|
||||
},
|
||||
{
|
||||
title: "Invite People",
|
||||
handler: setInviteChannelId.bind(null, id)
|
||||
},
|
||||
canDeleteChannel && {
|
||||
title: "Delete Channel",
|
||||
danger: true,
|
||||
handler: deleteChannel.bind(null, id)
|
||||
}
|
||||
];
|
||||
{
|
||||
title: t("setting"),
|
||||
underline: true,
|
||||
handler: handleChannelSetting
|
||||
},
|
||||
{
|
||||
title: t("action.mark_read"),
|
||||
// underline: true
|
||||
handler: handleReadAll
|
||||
},
|
||||
{
|
||||
title: channelMuted ? t("action.unmute") : t("action.mute"),
|
||||
handler: handleChannelMute
|
||||
},
|
||||
{
|
||||
title: t("action.invite_people"),
|
||||
handler: setInviteChannelId.bind(null, id)
|
||||
},
|
||||
canDeleteChannel && {
|
||||
title: t("action.delete_channel"),
|
||||
danger: true,
|
||||
handler: deleteChannel.bind(null, id)
|
||||
}
|
||||
];
|
||||
return (
|
||||
<Tippy
|
||||
interactive
|
||||
|
||||
Reference in New Issue
Block a user