feat: i18n

This commit is contained in:
Tristan Yang
2022-11-23 19:38:45 +08:00
parent 9b3dc2f740
commit 48ffdcc1b5
97 changed files with 1470 additions and 652 deletions
+4 -2
View File
@@ -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 doesnt have any pinned message yet.</div>
<div className="tip">{t("pin_empty_tip")}</div>
</div>
) : (
<ul className="list">
+9 -7
View File
@@ -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>
+6 -4
View File
@@ -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)
}
+5 -2
View File
@@ -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 -2
View File
@@ -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 doesnt have any saved message yet.</div>
<div className="tip">{t("fav_empty_tip")}</div>
</div>
) : (
<ul className="list">
+5 -3
View File
@@ -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>
);
+3 -1
View File
@@ -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>
+41 -38
View File
@@ -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