Compare commits
3 Commits
02b367fcaa
...
994bf5c7e0
| Author | SHA1 | Date | |
|---|---|---|---|
| 994bf5c7e0 | |||
| 61123f708d | |||
| 5a8a478386 |
@@ -60,3 +60,7 @@ pnpm-debug.log
|
||||
|
||||
# Cloud compose (separate deployment)
|
||||
cloud/
|
||||
|
||||
# Local temporary caches
|
||||
.pnpm-store
|
||||
v8-compile-cache-0
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -4,6 +4,9 @@
|
||||
node_modules
|
||||
.pnp
|
||||
.pnp.js
|
||||
.pnpm/
|
||||
.pnpm-store/
|
||||
v8-compile-cache-0/
|
||||
|
||||
# testing
|
||||
coverage
|
||||
@@ -58,4 +61,4 @@ i18n.cache
|
||||
# local scripts
|
||||
scripts/
|
||||
|
||||
.claude
|
||||
.claude
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"version": "1.10",
|
||||
"locale": {
|
||||
"source": "en",
|
||||
"targets": ["fr", "de", "es", "it", "nl", "ru", "pl", "pt-BR"]
|
||||
"targets": ["fr", "de", "es", "it", "nl", "ru", "pl", "pt-BR", "zh-CN"]
|
||||
},
|
||||
"buckets": {
|
||||
"json": {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { formatter } from "@lingui/format-json";
|
||||
|
||||
|
||||
export default defineConfig({
|
||||
locales: ["en", "fr", "de", "es", "it", "nl", "ru", "pl", "pt-BR"],
|
||||
locales: ["en", "fr", "de", "es", "it", "nl", "ru", "pl", "pt-BR", "zh-CN"],
|
||||
sourceLocale: "en",
|
||||
catalogs: [
|
||||
{
|
||||
|
||||
@@ -28,6 +28,7 @@ import ButtonComponent from "~/components/Button";
|
||||
import ReactiveButton from "~/components/ReactiveButton";
|
||||
import UserMenu from "~/components/UserMenu";
|
||||
import WorkspaceMenu from "~/components/WorkspaceMenu";
|
||||
import { useLinguiContext } from "~/providers/lingui";
|
||||
import { useWorkspace } from "~/providers/workspace";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
@@ -50,6 +51,7 @@ export default function SideNavigation({
|
||||
}: SideNavigationProps) {
|
||||
const router = useRouter();
|
||||
const { workspace } = useWorkspace();
|
||||
const { locale } = useLinguiContext();
|
||||
const [isCollapsed, setIsCollapsed] = useState(false);
|
||||
const [isInitialised, setIsInitialised] = useState(false);
|
||||
|
||||
@@ -143,7 +145,7 @@ export default function SideNavigation({
|
||||
},
|
||||
},
|
||||
],
|
||||
[isDarkMode],
|
||||
[isDarkMode, locale, router],
|
||||
);
|
||||
|
||||
const toggleCollapse = () => {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { HiCheck, HiMagnifyingGlass } from "react-icons/hi2";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { useKeyboardShortcut } from "~/providers/keyboard-shortcuts";
|
||||
import { useLinguiContext } from "~/providers/lingui";
|
||||
import { useModal } from "~/providers/modal";
|
||||
import { useWorkspace } from "~/providers/workspace";
|
||||
import { api } from "~/utils/api";
|
||||
@@ -20,6 +21,7 @@ export default function WorkspaceMenu({
|
||||
}) {
|
||||
const { workspace, isLoading, availableWorkspaces, switchWorkspace } =
|
||||
useWorkspace();
|
||||
const { locale } = useLinguiContext();
|
||||
const { openModal } = useModal();
|
||||
const { data: hasPartnerSlot } =
|
||||
api.workspace.hasAvailablePartnerSlot.useQuery();
|
||||
@@ -37,7 +39,7 @@ export default function WorkspaceMenu({
|
||||
description: t`Open command menu`,
|
||||
group: "GENERAL" as const,
|
||||
}),
|
||||
[],
|
||||
[locale],
|
||||
);
|
||||
|
||||
const { tooltipContent: commandPaletteShortcutTooltipContent } =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Locale as DateFnsLocale } from "date-fns";
|
||||
import { useLingui } from "@lingui/react";
|
||||
import { de, enGB, es, fr, it, nl, pl, ptBR, ru } from "date-fns/locale";
|
||||
import { de, enGB, es, fr, it, nl, pl, ptBR, ru, zhCN } from "date-fns/locale";
|
||||
|
||||
import type { Locale } from "~/locales";
|
||||
import { useLinguiContext } from "~/providers/lingui";
|
||||
@@ -20,6 +20,7 @@ export function useLocalisation() {
|
||||
ru,
|
||||
pl,
|
||||
ptbr: ptBR,
|
||||
"zh-CN": zhCN,
|
||||
};
|
||||
|
||||
const currentDateLocale = dateLocaleMap[locale] ?? enGB;
|
||||
|
||||
@@ -37,26 +37,21 @@
|
||||
62
|
||||
]
|
||||
],
|
||||
"translation": "{0}"
|
||||
"translation": "{0}",
|
||||
"obsolete": true
|
||||
},
|
||||
"JArWcF": {
|
||||
"message": "{0} | {1}",
|
||||
"placeholders": {
|
||||
"0": [
|
||||
"card?.title ?? t`Card`",
|
||||
"isTemplate ? \"Templates\" : \"Boards\""
|
||||
"card?.title ?? t`Card`"
|
||||
],
|
||||
"1": [
|
||||
"board?.name ?? t`Board`",
|
||||
"workspace.name ?? t`Workspace`"
|
||||
"board?.name ?? t`Board`"
|
||||
]
|
||||
},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/index.tsx",
|
||||
57
|
||||
],
|
||||
[
|
||||
"src/views/card/index.tsx",
|
||||
321
|
||||
@@ -126,7 +121,8 @@
|
||||
570
|
||||
]
|
||||
],
|
||||
"translation": "{0} not found"
|
||||
"translation": "{0} not found",
|
||||
"obsolete": true
|
||||
},
|
||||
"0xWkkH": {
|
||||
"message": "{boardCount, plural, one {Import board (1)} other {Import boards ({boardCount})}}",
|
||||
@@ -144,6 +140,25 @@
|
||||
],
|
||||
"translation": "{boardCount, plural, one {Import board (1)} other {Import boards ({boardCount})}}"
|
||||
},
|
||||
"xbAVoi": {
|
||||
"translation": "{boardLabel} | {0}",
|
||||
"message": "{boardLabel} | {0}",
|
||||
"placeholders": {
|
||||
"0": [
|
||||
"workspace.name ?? t`Workspace`"
|
||||
],
|
||||
"boardLabel": [
|
||||
"boardLabel"
|
||||
]
|
||||
},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/index.tsx",
|
||||
58
|
||||
]
|
||||
]
|
||||
},
|
||||
"yndBF+": {
|
||||
"message": "{projectCount, plural, one {Import project (1)} other {Import projects ({projectCount})}}",
|
||||
"placeholders": {
|
||||
@@ -335,7 +350,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/providers/keyboard-shortcuts.tsx",
|
||||
56
|
||||
57
|
||||
]
|
||||
],
|
||||
"translation": "Actions"
|
||||
@@ -371,7 +386,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/index.tsx",
|
||||
30
|
||||
37
|
||||
],
|
||||
[
|
||||
"src/views/settings/components/NewWebhookModal.tsx",
|
||||
@@ -1121,7 +1136,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/index.tsx",
|
||||
31
|
||||
38
|
||||
]
|
||||
],
|
||||
"translation": "Archived"
|
||||
@@ -1188,7 +1203,24 @@
|
||||
36
|
||||
]
|
||||
],
|
||||
"translation": "Are you sure you want to delete this {0}?"
|
||||
"translation": "Are you sure you want to delete this {0}?",
|
||||
"obsolete": true
|
||||
},
|
||||
"I/URsS": {
|
||||
"translation": "Are you sure you want to delete this {boardTypeLabel}?",
|
||||
"message": "Are you sure you want to delete this {boardTypeLabel}?",
|
||||
"placeholders": {
|
||||
"boardTypeLabel": [
|
||||
"boardTypeLabel"
|
||||
]
|
||||
},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/board/components/DeleteBoardConfirmation.tsx",
|
||||
37
|
||||
]
|
||||
]
|
||||
},
|
||||
"ZT4Khw": {
|
||||
"message": "Are you sure you want to delete this card?",
|
||||
@@ -1478,6 +1510,30 @@
|
||||
],
|
||||
"translation": "Blog Post"
|
||||
},
|
||||
"TwoUcd": {
|
||||
"translation": "board",
|
||||
"message": "board",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/board/components/DeleteBoardConfirmation.tsx",
|
||||
17
|
||||
],
|
||||
[
|
||||
"src/views/boards/components/BoardsList.tsx",
|
||||
17
|
||||
],
|
||||
[
|
||||
"src/views/boards/components/NewBoardForm.tsx",
|
||||
35
|
||||
],
|
||||
[
|
||||
"src/views/boards/index.tsx",
|
||||
35
|
||||
]
|
||||
]
|
||||
},
|
||||
"QD8opX": {
|
||||
"message": "Board",
|
||||
"placeholders": {},
|
||||
@@ -1563,6 +1619,10 @@
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/board/index.tsx",
|
||||
570
|
||||
],
|
||||
[
|
||||
"src/views/public/board/index.tsx",
|
||||
181
|
||||
@@ -1669,11 +1729,23 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/views/board/components/VisibilityButton.tsx",
|
||||
49
|
||||
50
|
||||
]
|
||||
],
|
||||
"translation": "Board visibility updated"
|
||||
},
|
||||
"DaBhdY": {
|
||||
"translation": "boards",
|
||||
"message": "boards",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/components/BoardsList.tsx",
|
||||
18
|
||||
]
|
||||
]
|
||||
},
|
||||
"8TveY+": {
|
||||
"message": "Boards",
|
||||
"placeholders": {},
|
||||
@@ -1681,7 +1753,11 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/components/SideNavigation.tsx",
|
||||
98
|
||||
100
|
||||
],
|
||||
[
|
||||
"src/views/boards/index.tsx",
|
||||
34
|
||||
],
|
||||
[
|
||||
"src/views/pricing/components/FeatureComparisonTable.tsx",
|
||||
@@ -1697,7 +1773,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/components/BoardsList.tsx",
|
||||
66
|
||||
68
|
||||
]
|
||||
],
|
||||
"translation": "Boards you archive will appear here."
|
||||
@@ -2141,7 +2217,7 @@
|
||||
],
|
||||
[
|
||||
"src/views/board/components/DeleteBoardConfirmation.tsx",
|
||||
44
|
||||
45
|
||||
],
|
||||
[
|
||||
"src/views/board/components/MoveBoardForm.tsx",
|
||||
@@ -3057,7 +3133,24 @@
|
||||
166
|
||||
]
|
||||
],
|
||||
"translation": "Create {0}"
|
||||
"translation": "Create {0}",
|
||||
"obsolete": true
|
||||
},
|
||||
"d+ACJK": {
|
||||
"translation": "Create {boardTypeLabel}",
|
||||
"message": "Create {boardTypeLabel}",
|
||||
"placeholders": {
|
||||
"boardTypeLabel": [
|
||||
"boardTypeLabel"
|
||||
]
|
||||
},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/components/NewBoardForm.tsx",
|
||||
167
|
||||
]
|
||||
]
|
||||
},
|
||||
"vgdzLf": {
|
||||
"message": "Create another",
|
||||
@@ -3169,7 +3262,28 @@
|
||||
45
|
||||
]
|
||||
],
|
||||
"translation": "Create new {0}"
|
||||
"translation": "Create new {0}",
|
||||
"obsolete": true
|
||||
},
|
||||
"O6v9mX": {
|
||||
"translation": "Create new {boardTypeLabel}",
|
||||
"message": "Create new {boardTypeLabel}",
|
||||
"placeholders": {
|
||||
"boardTypeLabel": [
|
||||
"boardTypeLabel"
|
||||
]
|
||||
},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/components/BoardsList.tsx",
|
||||
82
|
||||
],
|
||||
[
|
||||
"src/views/boards/index.tsx",
|
||||
46
|
||||
]
|
||||
]
|
||||
},
|
||||
"okpxfB": {
|
||||
"message": "Create new key",
|
||||
@@ -3250,7 +3364,7 @@
|
||||
],
|
||||
[
|
||||
"src/components/WorkspaceMenu.tsx",
|
||||
176
|
||||
178
|
||||
]
|
||||
],
|
||||
"translation": "Create workspace"
|
||||
@@ -3535,7 +3649,7 @@
|
||||
],
|
||||
[
|
||||
"src/views/board/components/DeleteBoardConfirmation.tsx",
|
||||
47
|
||||
48
|
||||
],
|
||||
[
|
||||
"src/views/card/components/DeleteCardConfirmation.tsx",
|
||||
@@ -4448,11 +4562,11 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/components/NewBoardForm.tsx",
|
||||
77
|
||||
78
|
||||
],
|
||||
[
|
||||
"src/views/boards/components/NewBoardForm.tsx",
|
||||
92
|
||||
93
|
||||
],
|
||||
[
|
||||
"src/views/members/components/InviteMemberForm.tsx",
|
||||
@@ -4781,11 +4895,11 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/components/NewBoardForm.tsx",
|
||||
78
|
||||
79
|
||||
],
|
||||
[
|
||||
"src/views/boards/components/NewBoardForm.tsx",
|
||||
93
|
||||
94
|
||||
]
|
||||
],
|
||||
"translation": "Failed to create board"
|
||||
@@ -5189,7 +5303,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/providers/keyboard-shortcuts.tsx",
|
||||
54
|
||||
55
|
||||
]
|
||||
],
|
||||
"translation": "General"
|
||||
@@ -5256,7 +5370,24 @@
|
||||
66
|
||||
]
|
||||
],
|
||||
"translation": "Get started by creating a new {0}"
|
||||
"translation": "Get started by creating a new {0}",
|
||||
"obsolete": true
|
||||
},
|
||||
"sllapH": {
|
||||
"translation": "Get started by creating a new {boardTypeLabel}",
|
||||
"message": "Get started by creating a new {boardTypeLabel}",
|
||||
"placeholders": {
|
||||
"boardTypeLabel": [
|
||||
"boardTypeLabel"
|
||||
]
|
||||
},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/components/BoardsList.tsx",
|
||||
68
|
||||
]
|
||||
]
|
||||
},
|
||||
"zC8Whw": {
|
||||
"message": "Get started by creating a new list",
|
||||
@@ -5393,7 +5524,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/components/SideNavigation.tsx",
|
||||
106
|
||||
108
|
||||
],
|
||||
[
|
||||
"src/pages/404.tsx",
|
||||
@@ -5421,7 +5552,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/components/SideNavigation.tsx",
|
||||
130
|
||||
132
|
||||
]
|
||||
],
|
||||
"translation": "Go to members"
|
||||
@@ -5433,7 +5564,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/components/SideNavigation.tsx",
|
||||
142
|
||||
144
|
||||
]
|
||||
],
|
||||
"translation": "Go to settings"
|
||||
@@ -5445,7 +5576,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/components/SideNavigation.tsx",
|
||||
118
|
||||
120
|
||||
]
|
||||
],
|
||||
"translation": "Go to templates"
|
||||
@@ -5693,7 +5824,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/index.tsx",
|
||||
82
|
||||
83
|
||||
]
|
||||
],
|
||||
"translation": "Import"
|
||||
@@ -6110,7 +6241,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/providers/keyboard-shortcuts.tsx",
|
||||
321
|
||||
323
|
||||
]
|
||||
],
|
||||
"translation": "Keyboard Shortcuts"
|
||||
@@ -6643,7 +6774,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/components/SideNavigation.tsx",
|
||||
122
|
||||
124
|
||||
],
|
||||
[
|
||||
"src/views/board/components/Filters.tsx",
|
||||
@@ -6858,7 +6989,7 @@
|
||||
],
|
||||
[
|
||||
"src/views/boards/components/NewBoardForm.tsx",
|
||||
134
|
||||
135
|
||||
],
|
||||
[
|
||||
"src/views/settings/components/NewWebhookModal.tsx",
|
||||
@@ -6878,7 +7009,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/providers/keyboard-shortcuts.tsx",
|
||||
55
|
||||
56
|
||||
]
|
||||
],
|
||||
"translation": "Navigation"
|
||||
@@ -6902,7 +7033,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/index.tsx",
|
||||
104
|
||||
105
|
||||
],
|
||||
[
|
||||
"src/views/home/components/Features.tsx",
|
||||
@@ -6925,7 +7056,24 @@
|
||||
120
|
||||
]
|
||||
],
|
||||
"translation": "New {0}"
|
||||
"translation": "New {0}",
|
||||
"obsolete": true
|
||||
},
|
||||
"DKeyWA": {
|
||||
"translation": "New {boardTypeLabel}",
|
||||
"message": "New {boardTypeLabel}",
|
||||
"placeholders": {
|
||||
"boardTypeLabel": [
|
||||
"boardTypeLabel"
|
||||
]
|
||||
},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/components/NewBoardForm.tsx",
|
||||
121
|
||||
]
|
||||
]
|
||||
},
|
||||
"TjREUS": {
|
||||
"message": "New API key",
|
||||
@@ -7113,7 +7261,24 @@
|
||||
63
|
||||
]
|
||||
],
|
||||
"translation": "No {0}"
|
||||
"translation": "No {0}",
|
||||
"obsolete": true
|
||||
},
|
||||
"NcHwr6": {
|
||||
"translation": "No {boardLabel}",
|
||||
"message": "No {boardLabel}",
|
||||
"placeholders": {
|
||||
"boardLabel": [
|
||||
"boardLabel"
|
||||
]
|
||||
},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/components/BoardsList.tsx",
|
||||
65
|
||||
]
|
||||
]
|
||||
},
|
||||
"tlhgDC": {
|
||||
"message": "No archived boards",
|
||||
@@ -7122,7 +7287,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/components/BoardsList.tsx",
|
||||
63
|
||||
65
|
||||
]
|
||||
],
|
||||
"translation": "No archived boards"
|
||||
@@ -7194,7 +7359,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/providers/keyboard-shortcuts.tsx",
|
||||
334
|
||||
336
|
||||
]
|
||||
],
|
||||
"translation": "No keyboard shortcuts registered."
|
||||
@@ -7366,7 +7531,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/components/WorkspaceMenu.tsx",
|
||||
37
|
||||
39
|
||||
]
|
||||
],
|
||||
"translation": "Open command menu"
|
||||
@@ -7378,7 +7543,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/providers/keyboard-shortcuts.tsx",
|
||||
172
|
||||
174
|
||||
]
|
||||
],
|
||||
"translation": "Open keyboard shortcuts"
|
||||
@@ -7938,7 +8103,7 @@
|
||||
],
|
||||
[
|
||||
"src/views/board/components/VisibilityButton.tsx",
|
||||
57
|
||||
58
|
||||
],
|
||||
[
|
||||
"src/views/board/index.tsx",
|
||||
@@ -8235,6 +8400,18 @@
|
||||
],
|
||||
"translation": "Privacy policy"
|
||||
},
|
||||
"3KKSM4": {
|
||||
"translation": "private",
|
||||
"message": "private",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/board/components/VisibilityButton.tsx",
|
||||
45
|
||||
]
|
||||
]
|
||||
},
|
||||
"zwBp5t": {
|
||||
"message": "Private",
|
||||
"placeholders": {},
|
||||
@@ -8242,7 +8419,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/views/board/components/VisibilityButton.tsx",
|
||||
84
|
||||
85
|
||||
]
|
||||
],
|
||||
"translation": "Private"
|
||||
@@ -8319,6 +8496,18 @@
|
||||
],
|
||||
"translation": "Profile picture"
|
||||
},
|
||||
"qvFa8r": {
|
||||
"translation": "public",
|
||||
"message": "public",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/board/components/VisibilityButton.tsx",
|
||||
45
|
||||
]
|
||||
]
|
||||
},
|
||||
"7d1a0d": {
|
||||
"message": "Public",
|
||||
"placeholders": {},
|
||||
@@ -8326,7 +8515,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/views/board/components/VisibilityButton.tsx",
|
||||
79
|
||||
80
|
||||
]
|
||||
],
|
||||
"translation": "Public"
|
||||
@@ -9153,7 +9342,7 @@
|
||||
],
|
||||
[
|
||||
"src/components/SideNavigation.tsx",
|
||||
134
|
||||
136
|
||||
]
|
||||
],
|
||||
"translation": "Settings"
|
||||
@@ -9541,15 +9730,15 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/components/SideNavigation.tsx",
|
||||
228
|
||||
230
|
||||
],
|
||||
[
|
||||
"src/components/SideNavigation.tsx",
|
||||
229
|
||||
231
|
||||
],
|
||||
[
|
||||
"src/components/SideNavigation.tsx",
|
||||
239
|
||||
241
|
||||
]
|
||||
],
|
||||
"translation": "Start free trial"
|
||||
@@ -9734,6 +9923,30 @@
|
||||
],
|
||||
"translation": "Teams"
|
||||
},
|
||||
"1ZwmkP": {
|
||||
"translation": "template",
|
||||
"message": "template",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/board/components/DeleteBoardConfirmation.tsx",
|
||||
17
|
||||
],
|
||||
[
|
||||
"src/views/boards/components/BoardsList.tsx",
|
||||
17
|
||||
],
|
||||
[
|
||||
"src/views/boards/components/NewBoardForm.tsx",
|
||||
35
|
||||
],
|
||||
[
|
||||
"src/views/boards/index.tsx",
|
||||
35
|
||||
]
|
||||
]
|
||||
},
|
||||
"/K2CvV": {
|
||||
"message": "Template",
|
||||
"placeholders": {},
|
||||
@@ -9798,6 +10011,30 @@
|
||||
],
|
||||
"translation": "Template name is required"
|
||||
},
|
||||
"p2sbyZ": {
|
||||
"translation": "Template not found",
|
||||
"message": "Template not found",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/board/index.tsx",
|
||||
570
|
||||
]
|
||||
]
|
||||
},
|
||||
"UZREi+": {
|
||||
"translation": "templates",
|
||||
"message": "templates",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/components/BoardsList.tsx",
|
||||
18
|
||||
]
|
||||
]
|
||||
},
|
||||
"iTylMl": {
|
||||
"message": "Templates",
|
||||
"placeholders": {},
|
||||
@@ -9805,7 +10042,11 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/components/SideNavigation.tsx",
|
||||
110
|
||||
112
|
||||
],
|
||||
[
|
||||
"src/views/boards/index.tsx",
|
||||
34
|
||||
],
|
||||
[
|
||||
"src/views/home/components/Features.tsx",
|
||||
@@ -9938,7 +10179,7 @@
|
||||
"message": "The board has been moved to {0}.",
|
||||
"placeholders": {
|
||||
"0": [
|
||||
"targetWorkspace?.name ?? \"the workspace\""
|
||||
"targetWorkspace?.name ?? t`the workspace`"
|
||||
]
|
||||
},
|
||||
"comments": [],
|
||||
@@ -10064,7 +10305,36 @@
|
||||
50
|
||||
]
|
||||
],
|
||||
"translation": "The visibility of your board has been set to {0}."
|
||||
"translation": "The visibility of your board has been set to {0}.",
|
||||
"obsolete": true
|
||||
},
|
||||
"7ENRJu": {
|
||||
"translation": "The visibility of your board has been set to {visibilityLabel}.",
|
||||
"message": "The visibility of your board has been set to {visibilityLabel}.",
|
||||
"placeholders": {
|
||||
"visibilityLabel": [
|
||||
"visibilityLabel"
|
||||
]
|
||||
},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/board/components/VisibilityButton.tsx",
|
||||
51
|
||||
]
|
||||
]
|
||||
},
|
||||
"VTpWX6": {
|
||||
"translation": "the workspace",
|
||||
"message": "the workspace",
|
||||
"placeholders": {},
|
||||
"comments": [],
|
||||
"origin": [
|
||||
[
|
||||
"src/views/board/components/MoveBoardForm.tsx",
|
||||
34
|
||||
]
|
||||
]
|
||||
},
|
||||
"FEr96N": {
|
||||
"message": "Theme",
|
||||
@@ -10101,7 +10371,7 @@
|
||||
],
|
||||
[
|
||||
"src/views/board/components/DeleteBoardConfirmation.tsx",
|
||||
39
|
||||
40
|
||||
],
|
||||
[
|
||||
"src/views/card/components/DeleteCardConfirmation.tsx",
|
||||
@@ -10821,7 +11091,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/views/board/components/VisibilityButton.tsx",
|
||||
56
|
||||
57
|
||||
]
|
||||
],
|
||||
"translation": "Unable to update board visibility"
|
||||
@@ -11486,7 +11756,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/views/boards/components/NewBoardForm.tsx",
|
||||
154
|
||||
155
|
||||
]
|
||||
],
|
||||
"translation": "Use template"
|
||||
@@ -11618,7 +11888,7 @@
|
||||
"origin": [
|
||||
[
|
||||
"src/views/board/components/VisibilityButton.tsx",
|
||||
103
|
||||
104
|
||||
]
|
||||
],
|
||||
"translation": "Visibility"
|
||||
@@ -11903,7 +12173,7 @@
|
||||
],
|
||||
[
|
||||
"src/views/boards/index.tsx",
|
||||
57
|
||||
58
|
||||
],
|
||||
[
|
||||
"src/views/members/index.tsx",
|
||||
@@ -12276,7 +12546,7 @@
|
||||
],
|
||||
[
|
||||
"src/views/board/components/VisibilityButton.tsx",
|
||||
72
|
||||
73
|
||||
],
|
||||
[
|
||||
"src/views/board/index.tsx",
|
||||
@@ -12288,15 +12558,15 @@
|
||||
],
|
||||
[
|
||||
"src/views/boards/components/BoardsList.tsx",
|
||||
71
|
||||
73
|
||||
],
|
||||
[
|
||||
"src/views/boards/index.tsx",
|
||||
68
|
||||
69
|
||||
],
|
||||
[
|
||||
"src/views/boards/index.tsx",
|
||||
89
|
||||
90
|
||||
]
|
||||
],
|
||||
"translation": "You don't have permission"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -7,12 +7,14 @@ export const locales = [
|
||||
"nl",
|
||||
"ru",
|
||||
"pl",
|
||||
"ptbr"
|
||||
"ptbr",
|
||||
"zh-CN",
|
||||
] as const;
|
||||
|
||||
export type Locale = (typeof locales)[number];
|
||||
|
||||
export const defaultLocale: Locale = "en";
|
||||
// 自托管实例默认使用简体中文,用户仍可在设置中切换其他语言。
|
||||
export const defaultLocale: Locale = "zh-CN";
|
||||
|
||||
export const localeNames: Record<Locale, string> = {
|
||||
en: "English",
|
||||
@@ -24,4 +26,5 @@ export const localeNames: Record<Locale, string> = {
|
||||
ru: "Русский",
|
||||
pl: "Polski",
|
||||
ptbr: "Português",
|
||||
"zh-CN": "简体中文",
|
||||
};
|
||||
|
||||
13005
apps/web/src/locales/zh-CN/messages.json
Normal file
13005
apps/web/src/locales/zh-CN/messages.json
Normal file
File diff suppressed because it is too large
Load Diff
1
apps/web/src/locales/zh-CN/messages.ts
Normal file
1
apps/web/src/locales/zh-CN/messages.ts
Normal file
File diff suppressed because one or more lines are too long
@@ -82,8 +82,8 @@ const MyApp: AppType = ({ Component, pageProps }: AppPropsWithLayout) => {
|
||||
)}
|
||||
<script src="/__ENV.js" />
|
||||
<main className="font-sans">
|
||||
<KeyboardShortcutProvider>
|
||||
<LinguiProviderWrapper>
|
||||
<LinguiProviderWrapper>
|
||||
<KeyboardShortcutProvider>
|
||||
<FontSizeProvider>
|
||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
||||
<ModalProvider>
|
||||
@@ -99,8 +99,8 @@ const MyApp: AppType = ({ Component, pageProps }: AppPropsWithLayout) => {
|
||||
</ModalProvider>
|
||||
</ThemeProvider>
|
||||
</FontSizeProvider>
|
||||
</LinguiProviderWrapper>
|
||||
</KeyboardShortcutProvider>
|
||||
</KeyboardShortcutProvider>
|
||||
</LinguiProviderWrapper>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -20,6 +20,7 @@ import { HiXMark } from "react-icons/hi2";
|
||||
|
||||
import { env } from "~/env";
|
||||
import { useEventListener } from "~/hooks/useEventListener";
|
||||
import { useLinguiContext } from "~/providers/lingui";
|
||||
|
||||
const ModifierKey = {
|
||||
CONTROL: "CONTROL",
|
||||
@@ -160,6 +161,7 @@ export function KeyboardShortcutProvider({
|
||||
const sequenceTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
const [isLegendOpen, setIsLegendOpen] = useState(false);
|
||||
const { locale } = useLinguiContext();
|
||||
|
||||
const openLegendShortcut: KeyboardShortcut = useMemo(
|
||||
() => ({
|
||||
@@ -172,7 +174,7 @@ export function KeyboardShortcutProvider({
|
||||
description: t`Open keyboard shortcuts`,
|
||||
group: ShortcutGroup.GENERAL,
|
||||
}),
|
||||
[setIsLegendOpen],
|
||||
[locale],
|
||||
);
|
||||
|
||||
const handleKeyDown = useCallback((event: KeyboardEvent) => {
|
||||
|
||||
@@ -35,10 +35,31 @@ function detectBrowserLocale(availableLocales: readonly string[]): Locale {
|
||||
const browserLanguages = navigator.languages || [navigator.language];
|
||||
|
||||
for (const browserLang of browserLanguages) {
|
||||
const langCode = browserLang.split("-")[0];
|
||||
const normalizedLocale = browserLang.toLowerCase();
|
||||
const exactLocale = availableLocales.find(
|
||||
(availableLocale) => availableLocale.toLowerCase() === normalizedLocale,
|
||||
);
|
||||
|
||||
if (langCode && availableLocales.includes(langCode.toLowerCase())) {
|
||||
return langCode.toLowerCase() as Locale;
|
||||
if (exactLocale) {
|
||||
return exactLocale as Locale;
|
||||
}
|
||||
|
||||
const languageCode = normalizedLocale.split("-")[0];
|
||||
|
||||
if (languageCode === "zh" && availableLocales.includes("zh-CN")) {
|
||||
return "zh-CN";
|
||||
}
|
||||
|
||||
if (languageCode === "pt" && availableLocales.includes("ptbr")) {
|
||||
return "ptbr";
|
||||
}
|
||||
|
||||
const baseLocale = availableLocales.find(
|
||||
(availableLocale) => availableLocale.toLowerCase() === languageCode,
|
||||
);
|
||||
|
||||
if (baseLocale) {
|
||||
return baseLocale as Locale;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +70,7 @@ export function LinguiProviderWrapper({
|
||||
children,
|
||||
initialLocale = defaultLocale,
|
||||
}: LinguiProviderProps) {
|
||||
const [locale, setLocale] = useState<Locale>(defaultLocale);
|
||||
const [locale, setLocale] = useState<Locale>(initialLocale);
|
||||
const [isHydrated, setIsHydrated] = useState(false);
|
||||
|
||||
initializeI18n();
|
||||
|
||||
@@ -3,6 +3,7 @@ import { i18n } from "@lingui/core";
|
||||
import type { Locale } from "~/locales";
|
||||
import { defaultLocale } from "~/locales";
|
||||
import { messages as enMessages } from "~/locales/en/messages";
|
||||
import { messages as zhCNMessages } from "~/locales/zh-CN/messages";
|
||||
|
||||
const loadMessages = async (locale: Locale) => {
|
||||
switch (locale) {
|
||||
@@ -24,6 +25,8 @@ const loadMessages = async (locale: Locale) => {
|
||||
return (await import("~/locales/pl/messages")).messages;
|
||||
case "ptbr":
|
||||
return (await import("~/locales/ptbr/messages")).messages;
|
||||
case "zh-CN":
|
||||
return (await import("~/locales/zh-CN/messages")).messages;
|
||||
default:
|
||||
return enMessages;
|
||||
}
|
||||
@@ -32,11 +35,15 @@ const loadMessages = async (locale: Locale) => {
|
||||
let isInitialized = false;
|
||||
const loadedLocales = new Set<string>();
|
||||
|
||||
export function initializeI18n(locale: Locale = defaultLocale) {
|
||||
export function initializeI18n() {
|
||||
if (!isInitialized) {
|
||||
i18n.load(defaultLocale, enMessages);
|
||||
// 首屏同步加载中英文,避免默认语言激活前出现中英混排。
|
||||
i18n.load("en", enMessages);
|
||||
i18n.load("zh-CN", zhCNMessages);
|
||||
i18n.activate(defaultLocale);
|
||||
loadedLocales.add(defaultLocale);
|
||||
loadedLocales.add("en");
|
||||
loadedLocales.add("zh-CN");
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ export function DeleteBoardConfirmation({
|
||||
}) {
|
||||
const router = useRouter();
|
||||
const { closeModal } = useModal();
|
||||
const boardTypeLabel = isTemplate ? t`template` : t`board`;
|
||||
|
||||
const deleteBoard = api.board.delete.useMutation({
|
||||
onSuccess: () => {
|
||||
@@ -33,7 +34,7 @@ export function DeleteBoardConfirmation({
|
||||
<div className="p-5">
|
||||
<div className="flex w-full flex-col justify-between pb-4">
|
||||
<h2 className="text-md pb-4 font-medium text-neutral-900 dark:text-dark-1000">
|
||||
{t`Are you sure you want to delete this ${isTemplate ? "template" : "board"}?`}
|
||||
{t`Are you sure you want to delete this ${boardTypeLabel}?`}
|
||||
</h2>
|
||||
<p className="text-sm font-medium text-light-900 dark:text-dark-900">
|
||||
{t`This action can't be undone.`}
|
||||
|
||||
@@ -31,7 +31,7 @@ export function MoveBoardForm({
|
||||
closeModal();
|
||||
showPopup({
|
||||
header: t`Board moved`,
|
||||
message: t`The board has been moved to ${targetWorkspace?.name ?? "the workspace"}.`,
|
||||
message: t`The board has been moved to ${targetWorkspace?.name ?? t`the workspace`}.`,
|
||||
icon: "success",
|
||||
});
|
||||
if (targetWorkspace) {
|
||||
|
||||
@@ -42,12 +42,13 @@ const VisibilityButton = ({
|
||||
}, [visibility]);
|
||||
|
||||
const isPublic = stateVisibility === "public";
|
||||
const visibilityLabel = isPublic ? t`public` : t`private`;
|
||||
|
||||
const updateBoardVisibility = api.board.update.useMutation({
|
||||
onSuccess: () => {
|
||||
showPopup({
|
||||
header: t`Board visibility updated`,
|
||||
message: t`The visibility of your board has been set to ${isPublic ? "public" : "private"}.`,
|
||||
message: t`The visibility of your board has been set to ${visibilityLabel}.`,
|
||||
icon: "success",
|
||||
});
|
||||
},
|
||||
|
||||
@@ -540,7 +540,7 @@ export default function BoardPage({ isTemplate }: { isTemplate?: boolean }) {
|
||||
return (
|
||||
<>
|
||||
<PageHead
|
||||
title={`${boardData?.name ?? (isTemplate ? t`Board` : t`Template`)} | ${workspace.name ?? t`Workspace`}`}
|
||||
title={`${boardData?.name ?? (isTemplate ? t`Template` : t`Board`)} | ${workspace.name ?? t`Workspace`}`}
|
||||
/>
|
||||
<div className="relative flex h-full flex-col">
|
||||
<PatternedBackground />
|
||||
@@ -567,7 +567,7 @@ export default function BoardPage({ isTemplate }: { isTemplate?: boolean }) {
|
||||
)}
|
||||
{!boardData && !isLoading && (
|
||||
<p className="order-2 block p-0 py-0 font-bold leading-[2.3rem] tracking-tight text-neutral-900 dark:text-dark-1000 sm:text-[1.2rem] md:order-1">
|
||||
{t`${isTemplate ? "Template" : "Board"} not found`}
|
||||
{isTemplate ? t`Template not found` : t`Board not found`}
|
||||
</p>
|
||||
)}
|
||||
<div className="order-1 mb-4 flex items-center justify-end space-x-2 md:order-2 md:mb-0">
|
||||
|
||||
@@ -14,6 +14,8 @@ export function BoardsList({ isTemplate, archived = false }: { isTemplate?: bool
|
||||
const { workspace } = useWorkspace();
|
||||
const { openModal } = useModal();
|
||||
const { canCreateBoard } = usePermissions();
|
||||
const boardTypeLabel = isTemplate ? t`template` : t`board`;
|
||||
const boardLabel = isTemplate ? t`templates` : t`boards`;
|
||||
|
||||
const utils = api.useUtils();
|
||||
const updateBoard = api.board.update.useMutation({
|
||||
@@ -60,10 +62,10 @@ export function BoardsList({ isTemplate, archived = false }: { isTemplate?: bool
|
||||
<div className="flex flex-col items-center">
|
||||
<HiOutlineRectangleStack className="h-10 w-10 text-light-800 dark:text-dark-800" />
|
||||
<p className="mb-2 mt-4 text-[14px] font-bold text-light-1000 dark:text-dark-950">
|
||||
{archived ? t`No archived boards` : t`No ${isTemplate ? "templates" : "boards"}`}
|
||||
{archived ? t`No archived boards` : t`No ${boardLabel}`}
|
||||
</p>
|
||||
<p className="text-[14px] text-light-900 dark:text-dark-900">
|
||||
{archived ? t`Boards you archive will appear here.` : t`Get started by creating a new ${isTemplate ? "template" : "board"}`}
|
||||
{archived ? t`Boards you archive will appear here.` : t`Get started by creating a new ${boardTypeLabel}`}
|
||||
</p>
|
||||
</div>
|
||||
<Tooltip
|
||||
@@ -77,7 +79,7 @@ export function BoardsList({ isTemplate, archived = false }: { isTemplate?: bool
|
||||
}}
|
||||
disabled={!canCreateBoard}
|
||||
>
|
||||
{t`Create new ${isTemplate ? "template" : "board"}`}
|
||||
{t`Create new ${boardTypeLabel}`}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
@@ -32,6 +32,7 @@ interface NewBoardInputWithTemplate {
|
||||
}
|
||||
|
||||
export function NewBoardForm({ isTemplate }: { isTemplate?: boolean }) {
|
||||
const boardTypeLabel = isTemplate ? t`template` : t`board`;
|
||||
const utils = api.useUtils();
|
||||
const { closeModal } = useModal();
|
||||
const router = useRouter();
|
||||
@@ -117,7 +118,7 @@ export function NewBoardForm({ isTemplate }: { isTemplate?: boolean }) {
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="px-5 pt-5">
|
||||
<div className="text-neutral-9000 flex w-full items-center justify-between pb-4 dark:text-dark-1000">
|
||||
<h2 className="text-sm font-bold">{t`New ${isTemplate ? "template" : "board"}`}</h2>
|
||||
<h2 className="text-sm font-bold">{t`New ${boardTypeLabel}`}</h2>
|
||||
<button
|
||||
type="button"
|
||||
className="hover:bg-li ght-300 rounded p-1 focus:outline-none dark:hover:bg-dark-300"
|
||||
@@ -163,7 +164,7 @@ export function NewBoardForm({ isTemplate }: { isTemplate?: boolean }) {
|
||||
)}
|
||||
<div>
|
||||
<Button type="submit" isLoading={createBoard.isPending}>
|
||||
{t`Create ${isTemplate ? "template" : "board"}`}
|
||||
{t`Create ${boardTypeLabel}`}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -26,26 +26,27 @@ import { BoardsList } from "./components/BoardsList";
|
||||
import { ImportBoardsForm } from "./components/ImportBoardsForm";
|
||||
import { NewBoardForm } from "./components/NewBoardForm";
|
||||
|
||||
const boardsTabs = [
|
||||
{ key: "boards" as const, label: t`Active` },
|
||||
{ key: "archived" as const, label: t`Archived` },
|
||||
];
|
||||
|
||||
export default function BoardsPage({ isTemplate }: { isTemplate?: boolean }) {
|
||||
const { openModal, modalContentType, isOpen } = useModal();
|
||||
const { workspace } = useWorkspace();
|
||||
const [activeTab, setActiveTab] = useState<"boards" | "archived">("boards");
|
||||
const { canCreateBoard } = usePermissions();
|
||||
const boardLabel = isTemplate ? t`Templates` : t`Boards`;
|
||||
const boardTypeLabel = isTemplate ? t`template` : t`board`;
|
||||
const boardsTabs = [
|
||||
{ key: "boards" as const, label: t`Active` },
|
||||
{ key: "archived" as const, label: t`Archived` },
|
||||
];
|
||||
|
||||
const createBoardShortcut = useMemo(
|
||||
() => ({
|
||||
type: "PRESS" as const,
|
||||
stroke: { key: "C" },
|
||||
action: () => canCreateBoard && openModal("NEW_BOARD"),
|
||||
description: t`Create new ${isTemplate ? "template" : "board"}`,
|
||||
description: t`Create new ${boardTypeLabel}`,
|
||||
group: "ACTIONS" as const,
|
||||
}),
|
||||
[canCreateBoard, isTemplate, openModal],
|
||||
[boardTypeLabel, canCreateBoard, isTemplate, openModal],
|
||||
);
|
||||
|
||||
const { tooltipContent: createModalShortcutTooltipContent } =
|
||||
@@ -54,12 +55,12 @@ export default function BoardsPage({ isTemplate }: { isTemplate?: boolean }) {
|
||||
return (
|
||||
<>
|
||||
<PageHead
|
||||
title={t`${isTemplate ? "Templates" : "Boards"} | ${workspace.name ?? t`Workspace`}`}
|
||||
title={t`${boardLabel} | ${workspace.name ?? t`Workspace`}`}
|
||||
/>
|
||||
<div className="m-auto h-full max-w-[1100px] p-8 px-5 md:px-28 md:py-12">
|
||||
<div className="relative z-10 mb-8 flex w-full items-center justify-between">
|
||||
<h1 className="font-bold tracking-tight text-neutral-900 dark:text-dark-1000 sm:text-[1.2rem]">
|
||||
{t`${isTemplate ? "Templates" : "Boards"}`}
|
||||
{boardLabel}
|
||||
</h1>
|
||||
<div className="flex gap-2">
|
||||
{!isTemplate && (
|
||||
|
||||
Reference in New Issue
Block a user