[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:
Vamsi Krishna 2025-01-03 14:16:26 +05:30 committed by GitHub
parent ade0aa1643
commit 873e4330bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
84 changed files with 2588 additions and 873 deletions

View file

@ -1,29 +1,16 @@
"use client";
import { useMemo } from "react";
import { observer } from "mobx-react";
import { Controller, useForm } from "react-hook-form";
// types
import { useTranslation } from "@plane/i18n";
import { IUserTheme } from "@plane/types";
// ui
import { Button, InputColorPicker, setPromiseToast } from "@plane/ui";
// hooks
import { useUserProfile } from "@/hooks/store";
const inputRules = {
minLength: {
value: 7,
message: "Enter a valid hex code of 6 characters",
},
maxLength: {
value: 7,
message: "Enter a valid hex code of 6 characters",
},
pattern: {
value: /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,
message: "Enter a valid hex code of 6 characters",
},
};
type TCustomThemeSelector = {
applyThemeChange: (theme: Partial<IUserTheme>) => void;
};
@ -32,7 +19,7 @@ export const CustomThemeSelector: React.FC<TCustomThemeSelector> = observer((pro
const { applyThemeChange } = props;
// hooks
const { data: userProfile, updateUserTheme } = useUserProfile();
const { t } = useTranslation();
const {
control,
formState: { errors, isSubmitting },
@ -51,6 +38,24 @@ export const CustomThemeSelector: React.FC<TCustomThemeSelector> = observer((pro
},
});
const inputRules = useMemo(
() => ({
minLength: {
value: 7,
message: t("enter_a_valid_hex_code_of_6_characters"),
},
maxLength: {
value: 7,
message: t("enter_a_valid_hex_code_of_6_characters"),
},
pattern: {
value: /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,
message: t("enter_a_valid_hex_code_of_6_characters"),
},
}),
[t] // Empty dependency array since these rules never change
);
const handleUpdateTheme = async (formData: Partial<IUserTheme>) => {
const payload: IUserTheme = {
background: formData.background,
@ -66,14 +71,14 @@ export const CustomThemeSelector: React.FC<TCustomThemeSelector> = observer((pro
const updateCurrentUserThemePromise = updateUserTheme(payload);
setPromiseToast(updateCurrentUserThemePromise, {
loading: "Updating theme...",
loading: t("updating_theme"),
success: {
title: "Success!",
message: () => "Theme updated successfully!",
title: t("success"),
message: () => t("theme_updated_successfully"),
},
error: {
title: "Error!",
message: () => "Failed to Update the theme",
title: t("error"),
message: () => t("failed_to_update_the_theme"),
},
});
@ -91,16 +96,16 @@ export const CustomThemeSelector: React.FC<TCustomThemeSelector> = observer((pro
return (
<form onSubmit={handleSubmit(handleUpdateTheme)}>
<div className="space-y-5">
<h3 className="text-lg font-semibold text-custom-text-100">Customize your theme</h3>
<h3 className="text-lg font-semibold text-custom-text-100">{t("customize_your_theme")}</h3>
<div className="space-y-4">
<div className="grid grid-cols-1 gap-x-8 gap-y-4 sm:grid-cols-2 md:grid-cols-3">
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-sm font-medium text-custom-text-200">Background color</h3>
<h3 className="text-left text-sm font-medium text-custom-text-200">{t("background_color")}</h3>
<div className="w-full">
<Controller
control={control}
name="background"
rules={{ ...inputRules, required: "Background color is required" }}
rules={{ ...inputRules, required: t("background_color_is_required") }}
render={({ field: { value, onChange } }) => (
<InputColorPicker
name="background"
@ -121,12 +126,12 @@ export const CustomThemeSelector: React.FC<TCustomThemeSelector> = observer((pro
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-sm font-medium text-custom-text-200">Text color</h3>
<h3 className="text-left text-sm font-medium text-custom-text-200">{t("text_color")}</h3>
<div className="w-full">
<Controller
control={control}
name="text"
rules={{ ...inputRules, required: "Text color is required" }}
rules={{ ...inputRules, required: t("text_color_is_required") }}
render={({ field: { value, onChange } }) => (
<InputColorPicker
name="text"
@ -147,12 +152,12 @@ export const CustomThemeSelector: React.FC<TCustomThemeSelector> = observer((pro
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-sm font-medium text-custom-text-200">Primary(Theme) color</h3>
<h3 className="text-left text-sm font-medium text-custom-text-200">{t("primary_color")}</h3>
<div className="w-full">
<Controller
control={control}
name="primary"
rules={{ ...inputRules, required: "Primary color is required" }}
rules={{ ...inputRules, required: t("primary_color_is_required") }}
render={({ field: { value, onChange } }) => (
<InputColorPicker
name="primary"
@ -173,12 +178,12 @@ export const CustomThemeSelector: React.FC<TCustomThemeSelector> = observer((pro
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-sm font-medium text-custom-text-200">Sidebar background color</h3>
<h3 className="text-left text-sm font-medium text-custom-text-200">{t("sidebar_background_color")}</h3>
<div className="w-full">
<Controller
control={control}
name="sidebarBackground"
rules={{ ...inputRules, required: "Sidebar background color is required" }}
rules={{ ...inputRules, required: t("sidebar_background_color_is_required") }}
render={({ field: { value, onChange } }) => (
<InputColorPicker
name="sidebarBackground"
@ -201,12 +206,12 @@ export const CustomThemeSelector: React.FC<TCustomThemeSelector> = observer((pro
</div>
<div className="flex flex-col items-start gap-2">
<h3 className="text-left text-sm font-medium text-custom-text-200">Sidebar text color</h3>
<h3 className="text-left text-sm font-medium text-custom-text-200">{t("sidebar_text_color")}</h3>
<div className="w-full">
<Controller
control={control}
name="sidebarText"
rules={{ ...inputRules, required: "Sidebar text color is required" }}
rules={{ ...inputRules, required: t("sidebar_text_color_is_required") }}
render={({ field: { value, onChange } }) => (
<InputColorPicker
name="sidebarText"
@ -230,7 +235,7 @@ export const CustomThemeSelector: React.FC<TCustomThemeSelector> = observer((pro
</div>
<div className="mt-5 flex justify-end gap-2">
<Button variant="primary" type="submit" loading={isSubmitting}>
{isSubmitting ? "Creating Theme..." : "Set Theme"}
{isSubmitting ? t("creating_theme") : t("set_theme")}
</Button>
</div>
</form>

View file

@ -1,6 +1,7 @@
"use client";
import { FC } from "react";
import { useTranslation } from "@plane/i18n";
// constants
import { CustomSelect } from "@plane/ui";
import { THEME_OPTIONS, I_THEME_OPTION } from "@/constants/themes";
@ -13,7 +14,7 @@ type Props = {
export const ThemeSwitch: FC<Props> = (props) => {
const { value, onChange } = props;
const { t } = useTranslation();
return (
<CustomSelect
value={value}
@ -40,10 +41,10 @@ export const ThemeSwitch: FC<Props> = (props) => {
}}
/>
</div>
{value.label}
{t(value.key)}
</div>
) : (
"Select your theme"
t("select_your_theme")
)
}
onChange={onChange}
@ -72,7 +73,7 @@ export const ThemeSwitch: FC<Props> = (props) => {
}}
/>
</div>
{themeOption.label}
{t(themeOption.key)}
</div>
</CustomSelect.Option>
))}