[WEB-2870]feat: language support (#6215)
* fix: adding language support package * fix: language support implementation using mobx * fix: adding more languages for support * fix: profile settings translations * feat: added language support for sidebar and user settings * feat: added language support for deactivation modal * fix: added project sync after transfer issues (#6200) * code refactor and improvement (#6203) * chore: package code refactoring * chore: component restructuring and refactor * chore: comment create improvement * refactor: enhance workspace and project wrapper modularity (#6207) * [WEB-2678]feat: added functionality to add labels directly from dropdown (#6211) * enhancement:added functionality to add features directly from dropdown * fix: fixed import order * fix: fixed lint errors * chore: added common component for project activity (#6212) * chore: added common component for project activity * fix: added enum * fix: added enum for initiatives * - Do not clear temp files that are locked. (#6214) - Handle edge cases in sync workspace * fix: labels empty state for drop down (#6216) * refactor: remove cn helper function from the editor package (#6217) * * feat: added language support to issue create modal in sidebar * fix: project activity type * * fix: added missing translations * fix: modified translation for plurals * fix: fixed spanish translation * dev: language type error in space user profile types * fix: type fixes * chore: added alpha tag --------- Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com> Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com> Co-authored-by: Akshita Goyal <36129505+gakshita@users.noreply.github.com> Co-authored-by: Satish Gandham <satish.iitg@gmail.com> Co-authored-by: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Co-authored-by: gurusinath <gurusainath007@gmail.com>
This commit is contained in:
parent
ade0aa1643
commit
873e4330bc
84 changed files with 2588 additions and 873 deletions
|
|
@ -1,7 +1,8 @@
|
|||
import { ChangeEvent } from "react";
|
||||
import { Controller, useFormContext, UseFormSetValue } from "react-hook-form";
|
||||
import { Info } from "lucide-react";
|
||||
// plane ui
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// ui
|
||||
import { Input, TextArea, Tooltip } from "@plane/ui";
|
||||
// plane utils
|
||||
import { cn } from "@plane/utils";
|
||||
|
|
@ -27,6 +28,7 @@ const ProjectCommonAttributes: React.FC<Props> = (props) => {
|
|||
} = useFormContext<TProject>();
|
||||
|
||||
const { getIndex } = getTabIndex(ETabIndices.PROJECT_CREATE, isMobile);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleNameChange = (onChange: (...event: any[]) => void) => (e: ChangeEvent<HTMLInputElement>) => {
|
||||
if (!isChangeInIdentifierRequired) {
|
||||
|
|
@ -51,10 +53,10 @@ const ProjectCommonAttributes: React.FC<Props> = (props) => {
|
|||
control={control}
|
||||
name="name"
|
||||
rules={{
|
||||
required: "Name is required",
|
||||
required: t("name_is_required"),
|
||||
maxLength: {
|
||||
value: 255,
|
||||
message: "Title should be less than 255 characters",
|
||||
message: t("title_should_be_less_than_255_characters"),
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
|
|
@ -65,7 +67,7 @@ const ProjectCommonAttributes: React.FC<Props> = (props) => {
|
|||
value={value}
|
||||
onChange={handleNameChange(onChange)}
|
||||
hasError={Boolean(errors.name)}
|
||||
placeholder="Project name"
|
||||
placeholder={t("project_name")}
|
||||
className="w-full focus:border-blue-400"
|
||||
tabIndex={getIndex("name")}
|
||||
/>
|
||||
|
|
@ -78,17 +80,17 @@ const ProjectCommonAttributes: React.FC<Props> = (props) => {
|
|||
control={control}
|
||||
name="identifier"
|
||||
rules={{
|
||||
required: "Project ID is required",
|
||||
required: t("project_id_is_required"),
|
||||
// allow only alphanumeric & non-latin characters
|
||||
validate: (value) =>
|
||||
/^[ÇŞĞIİÖÜA-Z0-9]+$/.test(value.toUpperCase()) || "Only Alphanumeric & Non-latin characters are allowed.",
|
||||
/^[ÇŞĞIİÖÜA-Z0-9]+$/.test(value.toUpperCase()) || t("only_alphanumeric_non_latin_characters_allowed"),
|
||||
minLength: {
|
||||
value: 1,
|
||||
message: "Project ID must at least be of 1 character",
|
||||
message: t("project_id_must_be_at_least_1_character"),
|
||||
},
|
||||
maxLength: {
|
||||
value: 5,
|
||||
message: "Project ID must at most be of 5 characters",
|
||||
message: t("project_id_must_be_at_most_5_characters"),
|
||||
},
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
|
|
@ -99,7 +101,7 @@ const ProjectCommonAttributes: React.FC<Props> = (props) => {
|
|||
value={value}
|
||||
onChange={handleIdentifierChange(onChange)}
|
||||
hasError={Boolean(errors.identifier)}
|
||||
placeholder="Project ID"
|
||||
placeholder={t("project_id")}
|
||||
className={cn("w-full text-xs focus:border-blue-400 pr-7", {
|
||||
uppercase: value,
|
||||
})}
|
||||
|
|
@ -109,7 +111,7 @@ const ProjectCommonAttributes: React.FC<Props> = (props) => {
|
|||
/>
|
||||
<Tooltip
|
||||
isMobile={isMobile}
|
||||
tooltipContent="Helps you identify issues in the project uniquely. Max 5 characters."
|
||||
tooltipContent={t("project_id_tooltip_content")}
|
||||
className="text-sm"
|
||||
position="right-top"
|
||||
>
|
||||
|
|
@ -126,7 +128,7 @@ const ProjectCommonAttributes: React.FC<Props> = (props) => {
|
|||
id="description"
|
||||
name="description"
|
||||
value={value}
|
||||
placeholder="Description..."
|
||||
placeholder={t("description")}
|
||||
onChange={onChange}
|
||||
className="!h-24 text-sm focus:border-blue-400"
|
||||
hasError={Boolean(errors?.description)}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import { X } from "lucide-react";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// plane types
|
||||
import { IProject } from "@plane/types";
|
||||
// plane ui
|
||||
|
|
@ -21,6 +22,7 @@ type Props = {
|
|||
const ProjectCreateHeader: React.FC<Props> = (props) => {
|
||||
const { handleClose, isMobile = false } = props;
|
||||
const { watch, control } = useFormContext<IProject>();
|
||||
const { t } = useTranslation();
|
||||
// derived values
|
||||
const coverImage = watch("cover_image_url");
|
||||
|
||||
|
|
@ -33,7 +35,7 @@ const ProjectCreateHeader: React.FC<Props> = (props) => {
|
|||
<img
|
||||
src={getFileURL(coverImage)}
|
||||
className="absolute left-0 top-0 h-full w-full rounded-lg object-cover"
|
||||
alt="Project cover image"
|
||||
alt={t("project_cover_image_alt")}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
@ -48,7 +50,7 @@ const ProjectCreateHeader: React.FC<Props> = (props) => {
|
|||
control={control}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<ImagePickerPopover
|
||||
label="Change Cover"
|
||||
label={t("change_cover")}
|
||||
onChange={onChange}
|
||||
control={control}
|
||||
value={value}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { IProject } from "@plane/types";
|
||||
// ui
|
||||
import { Button } from "@plane/ui";
|
||||
|
|
@ -13,6 +14,7 @@ type Props = {
|
|||
};
|
||||
|
||||
const ProjectCreateButtons: React.FC<Props> = (props) => {
|
||||
const { t } = useTranslation();
|
||||
const { handleClose, isMobile = false } = props;
|
||||
const {
|
||||
formState: { isSubmitting },
|
||||
|
|
@ -23,10 +25,10 @@ const ProjectCreateButtons: React.FC<Props> = (props) => {
|
|||
return (
|
||||
<div className="flex justify-end gap-2 py-4 border-t border-custom-border-100">
|
||||
<Button variant="neutral-primary" size="sm" onClick={handleClose} tabIndex={getIndex("cancel")}>
|
||||
Cancel
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
<Button variant="primary" type="submit" size="sm" loading={isSubmitting} tabIndex={getIndex("submit")}>
|
||||
{isSubmitting ? "Creating" : "Create project"}
|
||||
{isSubmitting ? t("creating") : t("create_project")}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { FC, useEffect, useState } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { Info, Lock } from "lucide-react";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// plane types
|
||||
import { IProject, IWorkspace } from "@plane/types";
|
||||
// plane ui
|
||||
|
|
@ -43,6 +44,7 @@ export interface IProjectDetailsForm {
|
|||
const projectService = new ProjectService();
|
||||
export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
|
||||
const { project, workspaceSlug, projectId, isAdmin } = props;
|
||||
const { t } = useTranslation();
|
||||
// states
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
|
@ -361,8 +363,8 @@ export const ProjectDetailsForm: FC<IProjectDetailsForm> = (props) => {
|
|||
<div className="flex items-start gap-2">
|
||||
<network.icon className="h-3.5 w-3.5" />
|
||||
<div className="-mt-1">
|
||||
<p>{network.label}</p>
|
||||
<p className="text-xs text-custom-text-400">{network.description}</p>
|
||||
<p>{t(network.label)}</p>
|
||||
<p className="text-xs text-custom-text-400">{t(network.description)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</CustomSelect.Option>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import React, { FC } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import Link from "next/link";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// ui
|
||||
import { Button, getButtonStyling, Row } from "@plane/ui";
|
||||
// components
|
||||
|
|
@ -20,6 +21,7 @@ type Props = {
|
|||
export const ProjectFeatureUpdate: FC<Props> = observer((props) => {
|
||||
const { workspaceSlug, projectId, onClose } = props;
|
||||
// store hooks
|
||||
const { t } = useTranslation();
|
||||
const { getProjectById } = useProject();
|
||||
|
||||
if (!workspaceSlug || !projectId) return null;
|
||||
|
|
@ -33,12 +35,12 @@ export const ProjectFeatureUpdate: FC<Props> = observer((props) => {
|
|||
</Row>
|
||||
<div className="flex items-center justify-between gap-2 mt-4 px-6 py-4 border-t border-custom-border-100">
|
||||
<div className="flex gap-1 text-sm text-custom-text-300 font-medium">
|
||||
Congrats! Project <Logo logo={currentProjectDetails.logo_props} />{" "}
|
||||
<p className="break-all">{currentProjectDetails.name}</p> created.
|
||||
{t("congrats")}! {t("project")} <Logo logo={currentProjectDetails.logo_props} />{" "}
|
||||
<p className="break-all">{currentProjectDetails.name}</p> {t("created").toLowerCase()}.
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="neutral-primary" size="sm" onClick={onClose} tabIndex={1}>
|
||||
Close
|
||||
{t("close")}
|
||||
</Button>
|
||||
<Link
|
||||
href={`/${workspaceSlug}/projects/${projectId}/issues`}
|
||||
|
|
@ -46,7 +48,7 @@ export const ProjectFeatureUpdate: FC<Props> = observer((props) => {
|
|||
className={getButtonStyling("primary", "sm")}
|
||||
tabIndex={2}
|
||||
>
|
||||
Open project
|
||||
{t("open_project")}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import { FC } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { IProject } from "@plane/types";
|
||||
import { ToggleSwitch, Tooltip, setPromiseToast } from "@plane/ui";
|
||||
// hooks
|
||||
|
|
@ -20,6 +21,7 @@ type Props = {
|
|||
export const ProjectFeaturesList: FC<Props> = observer((props) => {
|
||||
const { workspaceSlug, projectId, isAdmin } = props;
|
||||
// store hooks
|
||||
const { t } = useTranslation();
|
||||
const { captureEvent } = useEventTracker();
|
||||
const { data: currentUser } = useUser();
|
||||
const { getProjectById, updateProject } = useProject();
|
||||
|
|
@ -62,8 +64,8 @@ export const ProjectFeaturesList: FC<Props> = observer((props) => {
|
|||
return (
|
||||
<div key={featureSectionKey} className="">
|
||||
<div className="flex flex-col justify-center pb-2 border-b border-custom-border-100">
|
||||
<h3 className="text-xl font-medium">{feature.title}</h3>
|
||||
<h4 className="text-sm leading-5 text-custom-text-200">{feature.description}</h4>
|
||||
<h3 className="text-xl font-medium">{t(feature.key)}</h3>
|
||||
<h4 className="text-sm leading-5 text-custom-text-200">{t(`${feature.key}_description`)}</h4>
|
||||
</div>
|
||||
{Object.keys(feature.featureList).map((featureItemKey) => {
|
||||
const featureItem = feature.featureList[featureItemKey];
|
||||
|
|
@ -79,7 +81,7 @@ export const ProjectFeaturesList: FC<Props> = observer((props) => {
|
|||
</div>
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<h4 className="text-sm font-medium leading-5">{featureItem.title}</h4>
|
||||
<h4 className="text-sm font-medium leading-5">{t(featureItem.key)}</h4>
|
||||
{featureItem.isPro && (
|
||||
<Tooltip tooltipContent="Pro feature" position="top">
|
||||
<UpgradeBadge />
|
||||
|
|
@ -87,7 +89,7 @@ export const ProjectFeaturesList: FC<Props> = observer((props) => {
|
|||
)}
|
||||
</div>
|
||||
<p className="text-sm leading-5 tracking-tight text-custom-text-300">
|
||||
{featureItem.description}
|
||||
{t(`${featureItem.key}_description`)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue