Extend lang support

This commit is contained in:
Henry
2025-06-25 13:20:07 +01:00
parent 8a93951464
commit a2f7582999
48 changed files with 4937 additions and 390 deletions

View File

@@ -1,3 +1,4 @@
import { t } from "@lingui/core/macro";
import { HiEllipsisHorizontal, HiLink, HiOutlineTrash } from "react-icons/hi2";
import Dropdown from "~/components/Dropdown";
@@ -11,12 +12,12 @@ export default function BoardDropdown({ isLoading }: { isLoading: boolean }) {
disabled={isLoading}
items={[
{
label: "Edit board URL",
label: t`Edit board URL`,
action: () => openModal("UPDATE_BOARD_SLUG"),
icon: <HiLink className="h-[16px] w-[16px] text-dark-900" />,
},
{
label: "Delete board",
label: t`Delete board`,
action: () => openModal("DELETE_BOARD"),
icon: <HiOutlineTrash className="h-[16px] w-[16px] text-dark-900" />,
},

View File

@@ -1,4 +1,5 @@
import { useRouter } from "next/router";
import { t } from "@lingui/core/macro";
import {
HiMiniXMark,
HiOutlineTag,
@@ -89,7 +90,7 @@ const Filters = ({
? [
{
key: "members",
label: "Members",
label: t`Members`,
icon: <HiOutlineUserCircle size={16} />,
items: formattedMembers,
},
@@ -97,7 +98,7 @@ const Filters = ({
: []),
{
key: "labels",
label: "Labels",
label: t`Labels`,
icon: <HiOutlineTag size={16} />,
items: formattedLabels,
},
@@ -145,13 +146,13 @@ const Filters = ({
disabled={isLoading}
iconLeft={<IoFilterOutline />}
>
Filter
{t`Filter`}
</Button>
{numOfFilters > 0 && (
<button
type="button"
onClick={clearFilters}
aria-label="Clear filters"
aria-label={t`Clear filters`}
className="group absolute -right-[8px] -top-[8px] flex h-5 w-5 items-center justify-center rounded-full border-2 border-light-100 bg-light-1000 text-[8px] font-[700] text-light-600 dark:border-dark-50 dark:bg-dark-1000 dark:text-dark-600"
>
<span className="group-hover:hidden">{numOfFilters}</span>

View File

@@ -92,9 +92,14 @@ export function NewCardForm({
args.labelPublicIds.includes(label.publicId),
),
members:
oldBoard.workspace.members.filter((member) =>
args.memberPublicIds.includes(member.publicId),
) ?? [],
oldBoard.workspace.members
.filter((member) =>
args.memberPublicIds.includes(member.publicId),
)
.map((member) => ({
...member,
deletedAt: null,
})) ?? [],
_filteredLabels: labelPublicIds.map((id) => ({ publicId: id })),
_filteredMembers: memberPublicIds.map((id) => ({ publicId: id })),
index: position === "start" ? 0 : list.cards.length,
@@ -168,6 +173,7 @@ export function NewCardForm({
member.user?.name ?? null,
member.user?.email ?? member.email,
),
selected: memberPublicIds.includes(member.publicId),
leftIcon: (
<Avatar
size="xs"
@@ -281,7 +287,7 @@ export function NewCardForm({
>
<div className="flex h-full w-full items-center rounded-[5px] border-[1px] border-light-600 bg-light-200 px-2 py-1 text-left text-xs text-light-800 hover:bg-light-300 dark:border-dark-600 dark:bg-dark-400 dark:text-dark-1000 dark:hover:bg-dark-500">
{!memberPublicIds.length ? (
"Members"
t`Members`
) : (
<div className="flex -space-x-1 overflow-hidden">
{memberPublicIds.map((memberPublicId) => {
@@ -322,7 +328,7 @@ export function NewCardForm({
>
<div className="flex h-full w-full items-center rounded-[5px] border-[1px] border-light-600 bg-light-200 px-2 py-1 text-left text-xs text-light-800 hover:bg-light-300 dark:border-dark-600 dark:bg-dark-400 dark:text-dark-1000 dark:hover:bg-dark-500">
{!labelPublicIds.length ? (
"Labels"
t`Labels`
) : (
<>
<div

View File

@@ -1,3 +1,4 @@
import { t } from "@lingui/core/macro";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import { HiXMark } from "react-icons/hi2";
@@ -73,8 +74,8 @@ export function NewListForm({
onError: (_error, _newList, context) => {
utils.board.byId.setData(queryParams, context?.previousState);
showPopup({
header: "Unable to create list",
message: "Please try again later, or contact customer support.",
header: t`Unable to create list`,
message: t`Please try again later, or contact customer support.`,
icon: "error",
});
},
@@ -108,7 +109,7 @@ export function NewListForm({
<div className="px-5 pt-5">
<div className="flex w-full items-center justify-between pb-4">
<h2 className="text-sm font-bold text-neutral-900 dark:text-dark-1000">
New list
{t`New list`}
</h2>
<button
type="button"
@@ -124,7 +125,7 @@ export function NewListForm({
<Input
id="list-name"
placeholder="List name"
placeholder={t`List name`}
{...register("name")}
onKeyDown={async (e) => {
if (e.key === "Enter") {
@@ -136,7 +137,7 @@ export function NewListForm({
</div>
<div className="mt-12 flex items-center justify-end border-t border-light-600 px-5 pb-5 pt-5 dark:border-dark-600">
<Toggle
label="Create another"
label={t`Create another`}
isChecked={isCreateAnotherEnabled}
onChange={() =>
setValue("isCreateAnotherEnabled", !isCreateAnotherEnabled)
@@ -144,7 +145,7 @@ export function NewListForm({
/>
<div>
<Button type="submit">Create list</Button>
<Button type="submit">{t`Create list`}</Button>
</div>
</div>
</form>

View File

@@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/core/macro";
import { env } from "next-runtime-env";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
@@ -12,20 +13,6 @@ import { useModal } from "~/providers/modal";
import { usePopup } from "~/providers/popup";
import { api } from "~/utils/api";
const schema = z.object({
slug: z
.string()
.min(3, {
message: "Board URL must be at least 3 characters long",
})
.max(60, { message: "Board URL cannot exceed 60 characters" })
.regex(/^(?![-]+$)[a-zA-Z0-9-]+$/, {
message: "Board URL can only contain letters, numbers, and hyphens",
}),
});
type FormValues = z.infer<typeof schema>;
interface QueryParams {
boardPublicId: string;
members: string[];
@@ -47,6 +34,20 @@ export function UpdateBoardSlugForm({
const { showPopup } = usePopup();
const utils = api.useUtils();
const schema = z.object({
slug: z
.string()
.min(3, {
message: t`Board URL must be at least 3 characters long`,
})
.max(60, { message: t`Board URL cannot exceed 60 characters` })
.regex(/^(?![-]+$)[a-zA-Z0-9-]+$/, {
message: t`Board URL can only contain letters, numbers, and hyphens`,
}),
});
type FormValues = z.infer<typeof schema>;
const {
register,
handleSubmit,
@@ -67,8 +68,8 @@ export function UpdateBoardSlugForm({
const updateBoardSlug = api.board.update.useMutation({
onError: () => {
showPopup({
header: "Unable to update board URL",
message: "Please try again later, or contact customer support.",
header: t`Unable to update board URL`,
message: t`Please try again later, or contact customer support.`,
icon: "error",
});
},
@@ -78,17 +79,15 @@ export function UpdateBoardSlugForm({
},
});
const checkBoardSlugAvailability =
api.board.checkSlugAvailability.useQuery(
{
boardSlug: debouncedSlug,
boardPublicId,
},
{
enabled:
!!debouncedSlug && debouncedSlug !== boardSlug && !errors.slug,
},
);
const checkBoardSlugAvailability = api.board.checkSlugAvailability.useQuery(
{
boardSlug: debouncedSlug,
boardPublicId,
},
{
enabled: !!debouncedSlug && debouncedSlug !== boardSlug && !errors.slug,
},
);
const isBoardSlugAvailable = checkBoardSlugAvailability.data;
@@ -100,7 +99,7 @@ export function UpdateBoardSlugForm({
const onSubmit = (data: FormValues) => {
if (!isBoardSlugAvailable) return;
if (isBoardSlugAvailable?.isReserved) return;
if (isBoardSlugAvailable.isReserved) return;
updateBoardSlug.mutate({
slug: data.slug,
@@ -113,7 +112,7 @@ export function UpdateBoardSlugForm({
<div className="px-5 pt-5">
<div className="flex w-full items-center justify-between pb-4">
<h2 className="text-sm font-bold text-neutral-900 dark:text-dark-1000">
Edit board URL
{t`Edit board URL`}
</h2>
<button
type="button"
@@ -130,9 +129,12 @@ export function UpdateBoardSlugForm({
<Input
id="board-slug"
{...register("slug")}
errorMessage={errors.slug?.message || (isBoardSlugAvailable?.isReserved
? "This board URL has already been taken"
: undefined)}
errorMessage={
errors.slug?.message ||
(isBoardSlugAvailable?.isReserved
? t`This board URL has already been taken`
: undefined)
}
prefix={`${env("NEXT_PUBLIC_BASE_URL")}/${workspaceSlug}/`}
onKeyDown={async (e) => {
if (e.key === "Enter") {
@@ -161,7 +163,7 @@ export function UpdateBoardSlugForm({
isBoardSlugAvailable?.isReserved
}
>
Update
{t`Update`}
</Button>
</div>
</div>