From 75b12c64da4acbcac6116ca732146d3f4b793a72 Mon Sep 17 00:00:00 2001 From: isletspace Date: Wed, 9 Sep 2026 14:14:16 +0800 Subject: [PATCH 1/2] fix(i18n): use whole-phrase greeting keys to fix zh-CN greeting splicing (PLANE-14) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The home/profile greeting rendered {t("good")} {t(greeting)}, which concatenates to nonsense in languages like Chinese ("早上 下午"). Replace the four fragment keys (good/morning/afternoon/evening) with three whole-phrase keys (good_morning/good_afternoon/good_evening) in common.json and switch both UserGreetingsView components to a single t() call. The old keys have no other references and are removed. zh-CN/zh-TW carry real translations; other locales mirror the English values per the sync-check contract. --- apps/web/core/components/home/user-greetings.tsx | 7 ++++--- apps/web/core/components/user/user-greetings.tsx | 7 ++++--- packages/i18n/src/locales/cs/common.json | 7 +++---- packages/i18n/src/locales/de/common.json | 7 +++---- packages/i18n/src/locales/en/common.json | 7 +++---- packages/i18n/src/locales/es/common.json | 7 +++---- packages/i18n/src/locales/fr/common.json | 7 +++---- packages/i18n/src/locales/id/common.json | 7 +++---- packages/i18n/src/locales/it/common.json | 7 +++---- packages/i18n/src/locales/ja/common.json | 7 +++---- packages/i18n/src/locales/ko/common.json | 7 +++---- packages/i18n/src/locales/pl/common.json | 7 +++---- packages/i18n/src/locales/pt-BR/common.json | 7 +++---- packages/i18n/src/locales/ro/common.json | 7 +++---- packages/i18n/src/locales/ru/common.json | 7 +++---- packages/i18n/src/locales/sk/common.json | 7 +++---- packages/i18n/src/locales/tr-TR/common.json | 7 +++---- packages/i18n/src/locales/ua/common.json | 7 +++---- packages/i18n/src/locales/vi-VN/common.json | 7 +++---- packages/i18n/src/locales/zh-CN/common.json | 7 +++---- packages/i18n/src/locales/zh-TW/common.json | 7 +++---- 21 files changed, 65 insertions(+), 82 deletions(-) diff --git a/apps/web/core/components/home/user-greetings.tsx b/apps/web/core/components/home/user-greetings.tsx index 8d5d6cc1e86..ae72bd95b79 100644 --- a/apps/web/core/components/home/user-greetings.tsx +++ b/apps/web/core/components/home/user-greetings.tsx @@ -43,15 +43,16 @@ export function UserGreetingsView(props: IUserGreetingsView) { minute: "2-digit", }).format(currentTime); - const greeting = parseInt(hour, 10) < 12 ? "morning" : parseInt(hour, 10) < 18 ? "afternoon" : "evening"; + const greeting = + parseInt(hour, 10) < 12 ? "good_morning" : parseInt(hour, 10) < 18 ? "good_afternoon" : "good_evening"; return (

- {t("good")} {t(greeting)}, {user?.first_name} {user?.last_name} + {t(greeting)}, {user?.first_name} {user?.last_name}

-
{greeting === "morning" ? "🌤️" : greeting === "afternoon" ? "🌥️" : "🌙️"}
+
{greeting === "good_morning" ? "🌤️" : greeting === "good_afternoon" ? "🌥️" : "🌙️"}
{weekDay}, {date} {timeString}
diff --git a/apps/web/core/components/user/user-greetings.tsx b/apps/web/core/components/user/user-greetings.tsx index ff00a23ca93..aae9c77261f 100644 --- a/apps/web/core/components/user/user-greetings.tsx +++ b/apps/web/core/components/user/user-greetings.tsx @@ -43,15 +43,16 @@ export function UserGreetingsView(props: IUserGreetingsView) { minute: "2-digit", }).format(currentTime); - const greeting = parseInt(hour, 10) < 12 ? "morning" : parseInt(hour, 10) < 18 ? "afternoon" : "evening"; + const greeting = + parseInt(hour, 10) < 12 ? "good_morning" : parseInt(hour, 10) < 18 ? "good_afternoon" : "good_evening"; return (

- {t("good")} {t(greeting)}, {user?.first_name} {user?.last_name} + {t(greeting)}, {user?.first_name} {user?.last_name}

-
{greeting === "morning" ? "🌤️" : greeting === "afternoon" ? "🌥️" : "🌙️"}
+
{greeting === "good_morning" ? "🌤️" : greeting === "good_afternoon" ? "🌥️" : "🌙️"}
{weekDay}, {date} {timeString}
diff --git a/packages/i18n/src/locales/cs/common.json b/packages/i18n/src/locales/cs/common.json index c1e9372c24e..194350061f2 100644 --- a/packages/i18n/src/locales/cs/common.json +++ b/packages/i18n/src/locales/cs/common.json @@ -324,10 +324,9 @@ "deleting": "Mazání", "make_a_copy": "Vytvořit kopii", "move_to_project": "Přesunout do projektu", - "good": "Dobrý", - "morning": "ráno", - "afternoon": "odpoledne", - "evening": "večer", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Zobrazit vše", "show_less": "Zobrazit méně", "no_data_yet": "Zatím žádná data", diff --git a/packages/i18n/src/locales/de/common.json b/packages/i18n/src/locales/de/common.json index 1e18d4ee26e..03497bb75b1 100644 --- a/packages/i18n/src/locales/de/common.json +++ b/packages/i18n/src/locales/de/common.json @@ -324,10 +324,9 @@ "deleting": "Wird gelöscht", "make_a_copy": "Kopie erstellen", "move_to_project": "In Projekt verschieben", - "good": "Guten", - "morning": "Morgen", - "afternoon": "Nachmittag", - "evening": "Abend", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Alle anzeigen", "show_less": "Weniger anzeigen", "no_data_yet": "Noch keine Daten", diff --git a/packages/i18n/src/locales/en/common.json b/packages/i18n/src/locales/en/common.json index a138304371e..296210c15cc 100644 --- a/packages/i18n/src/locales/en/common.json +++ b/packages/i18n/src/locales/en/common.json @@ -324,10 +324,9 @@ "deleting": "Deleting", "make_a_copy": "Make a copy", "move_to_project": "Move to project", - "good": "Good", - "morning": "morning", - "afternoon": "afternoon", - "evening": "evening", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Show all", "show_less": "Show less", "no_data_yet": "No Data yet", diff --git a/packages/i18n/src/locales/es/common.json b/packages/i18n/src/locales/es/common.json index 64440c9c653..0637c46e58a 100644 --- a/packages/i18n/src/locales/es/common.json +++ b/packages/i18n/src/locales/es/common.json @@ -324,10 +324,9 @@ "deleting": "Eliminando", "make_a_copy": "Hacer una copia", "move_to_project": "Mover al proyecto", - "good": "Buenos", - "morning": "días", - "afternoon": "tardes", - "evening": "noches", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Mostrar todo", "show_less": "Mostrar menos", "no_data_yet": "Aún no hay datos", diff --git a/packages/i18n/src/locales/fr/common.json b/packages/i18n/src/locales/fr/common.json index a94ab8aba2d..cae5b7a3df7 100644 --- a/packages/i18n/src/locales/fr/common.json +++ b/packages/i18n/src/locales/fr/common.json @@ -324,10 +324,9 @@ "deleting": "Suppression", "make_a_copy": "Faire une copie", "move_to_project": "Déplacer vers le projet", - "good": "Bonjour", - "morning": "matin", - "afternoon": "après-midi", - "evening": "soir", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Tout afficher", "show_less": "Afficher moins", "no_data_yet": "Pas encore de données", diff --git a/packages/i18n/src/locales/id/common.json b/packages/i18n/src/locales/id/common.json index 7d266850dc4..d9eda65ef74 100644 --- a/packages/i18n/src/locales/id/common.json +++ b/packages/i18n/src/locales/id/common.json @@ -324,10 +324,9 @@ "deleting": "Menghapus", "make_a_copy": "Buat salinan", "move_to_project": "Pindahkan ke proyek", - "good": "Bagus", - "morning": "pagi", - "afternoon": "siang", - "evening": "malam", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Tampilkan semua", "show_less": "Tampilkan lebih sedikit", "no_data_yet": "Belum ada data", diff --git a/packages/i18n/src/locales/it/common.json b/packages/i18n/src/locales/it/common.json index 6fda1b04957..650d68b155b 100644 --- a/packages/i18n/src/locales/it/common.json +++ b/packages/i18n/src/locales/it/common.json @@ -324,10 +324,9 @@ "deleting": "Eliminazione in corso", "make_a_copy": "Crea una copia", "move_to_project": "Sposta nel progetto", - "good": "Buono", - "morning": "Mattina", - "afternoon": "Pomeriggio", - "evening": "Sera", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Mostra tutto", "show_less": "Mostra meno", "no_data_yet": "Nessun dato disponibile", diff --git a/packages/i18n/src/locales/ja/common.json b/packages/i18n/src/locales/ja/common.json index 4899411b615..d65d0b26236 100644 --- a/packages/i18n/src/locales/ja/common.json +++ b/packages/i18n/src/locales/ja/common.json @@ -324,10 +324,9 @@ "deleting": "削除中", "make_a_copy": "コピーを作成", "move_to_project": "プロジェクトに移動", - "good": "おはよう", - "morning": "ございます", - "afternoon": "こんにちは", - "evening": "こんばんは", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "すべて表示", "show_less": "表示を減らす", "no_data_yet": "まだデータがありません", diff --git a/packages/i18n/src/locales/ko/common.json b/packages/i18n/src/locales/ko/common.json index 73eea6b1c25..2abb85c2e4b 100644 --- a/packages/i18n/src/locales/ko/common.json +++ b/packages/i18n/src/locales/ko/common.json @@ -324,10 +324,9 @@ "deleting": "삭제 중", "make_a_copy": "복사본 만들기", "move_to_project": "프로젝트로 이동", - "good": "좋은", - "morning": "아침", - "afternoon": "오후", - "evening": "저녁", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "모두 보기", "show_less": "간략히 보기", "no_data_yet": "아직 데이터 없음", diff --git a/packages/i18n/src/locales/pl/common.json b/packages/i18n/src/locales/pl/common.json index 4c4850cbf66..a9f3137fc6f 100644 --- a/packages/i18n/src/locales/pl/common.json +++ b/packages/i18n/src/locales/pl/common.json @@ -324,10 +324,9 @@ "deleting": "Usuwanie", "make_a_copy": "Utwórz kopię", "move_to_project": "Przenieś do projektu", - "good": "Dzień dobry", - "morning": "rano", - "afternoon": "po południu", - "evening": "wieczorem", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Pokaż wszystko", "show_less": "Pokaż mniej", "no_data_yet": "Brak danych", diff --git a/packages/i18n/src/locales/pt-BR/common.json b/packages/i18n/src/locales/pt-BR/common.json index 565e85d8739..ed49dc293f7 100644 --- a/packages/i18n/src/locales/pt-BR/common.json +++ b/packages/i18n/src/locales/pt-BR/common.json @@ -324,10 +324,9 @@ "deleting": "Excluindo", "make_a_copy": "Fazer uma cópia", "move_to_project": "Mover para o projeto", - "good": "Bom", - "morning": "manhã", - "afternoon": "tarde", - "evening": "noite", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Mostrar tudo", "show_less": "Mostrar menos", "no_data_yet": "Nenhum dado ainda", diff --git a/packages/i18n/src/locales/ro/common.json b/packages/i18n/src/locales/ro/common.json index e2b44ce87ec..4ad2c21726d 100644 --- a/packages/i18n/src/locales/ro/common.json +++ b/packages/i18n/src/locales/ro/common.json @@ -324,10 +324,9 @@ "deleting": "Se șterge", "make_a_copy": "Creează o copie", "move_to_project": "Mută în proiect", - "good": "Bună", - "morning": "dimineața", - "afternoon": "după-amiaza", - "evening": "seara", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Arată tot", "show_less": "Arată mai puțin", "no_data_yet": "Nicio dată încă", diff --git a/packages/i18n/src/locales/ru/common.json b/packages/i18n/src/locales/ru/common.json index c2881e55f8a..258f6ff945c 100644 --- a/packages/i18n/src/locales/ru/common.json +++ b/packages/i18n/src/locales/ru/common.json @@ -324,10 +324,9 @@ "deleting": "Удаление...", "make_a_copy": "Создать копию", "move_to_project": "Переместить в проект", - "good": "Доброго", - "morning": "утра", - "afternoon": "дня", - "evening": "вечера", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Показать все", "show_less": "Свернуть", "no_data_yet": "Нет данных", diff --git a/packages/i18n/src/locales/sk/common.json b/packages/i18n/src/locales/sk/common.json index 4fc339cece6..158dd2ffbc8 100644 --- a/packages/i18n/src/locales/sk/common.json +++ b/packages/i18n/src/locales/sk/common.json @@ -324,10 +324,9 @@ "deleting": "Mazanie", "make_a_copy": "Vytvoriť kópiu", "move_to_project": "Presunúť do projektu", - "good": "Dobrý", - "morning": "ráno", - "afternoon": "popoludnie", - "evening": "večer", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Zobraziť všetko", "show_less": "Zobraziť menej", "no_data_yet": "Zatiaľ žiadne dáta", diff --git a/packages/i18n/src/locales/tr-TR/common.json b/packages/i18n/src/locales/tr-TR/common.json index 74bd5cbf9b3..d899313e941 100644 --- a/packages/i18n/src/locales/tr-TR/common.json +++ b/packages/i18n/src/locales/tr-TR/common.json @@ -324,10 +324,9 @@ "deleting": "Siliniyor", "make_a_copy": "Kopyasını oluştur", "move_to_project": "Projeye taşı", - "good": "İyi", - "morning": "sabah", - "afternoon": "öğleden sonra", - "evening": "akşam", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Tümünü göster", "show_less": "Daha az göster", "no_data_yet": "Henüz veri yok", diff --git a/packages/i18n/src/locales/ua/common.json b/packages/i18n/src/locales/ua/common.json index 89bd906d8fa..cf7f2d64f45 100644 --- a/packages/i18n/src/locales/ua/common.json +++ b/packages/i18n/src/locales/ua/common.json @@ -324,10 +324,9 @@ "deleting": "Видалення", "make_a_copy": "Зробити копію", "move_to_project": "Перемістити в проєкт", - "good": "Доброго", - "morning": "ранку", - "afternoon": "дня", - "evening": "вечора", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Показати все", "show_less": "Показати менше", "no_data_yet": "Поки що немає даних", diff --git a/packages/i18n/src/locales/vi-VN/common.json b/packages/i18n/src/locales/vi-VN/common.json index f9aae43c1b9..17ef91d5e04 100644 --- a/packages/i18n/src/locales/vi-VN/common.json +++ b/packages/i18n/src/locales/vi-VN/common.json @@ -324,10 +324,9 @@ "deleting": "Đang xóa", "make_a_copy": "Tạo bản sao", "move_to_project": "Di chuyển đến dự án", - "good": "Chào buổi sáng", - "morning": "Buổi sáng", - "afternoon": "Buổi chiều", - "evening": "Buổi tối", + "good_morning": "Good morning", + "good_afternoon": "Good afternoon", + "good_evening": "Good evening", "show_all": "Hiển thị tất cả", "show_less": "Hiển thị ít hơn", "no_data_yet": "Chưa có dữ liệu", diff --git a/packages/i18n/src/locales/zh-CN/common.json b/packages/i18n/src/locales/zh-CN/common.json index dd67d925a07..b12b164b0d0 100644 --- a/packages/i18n/src/locales/zh-CN/common.json +++ b/packages/i18n/src/locales/zh-CN/common.json @@ -324,10 +324,9 @@ "deleting": "删除中", "make_a_copy": "创建副本", "move_to_project": "移动到项目", - "good": "早上", - "morning": "早上", - "afternoon": "下午", - "evening": "晚上", + "good_morning": "早上好", + "good_afternoon": "下午好", + "good_evening": "晚上好", "show_all": "显示全部", "show_less": "显示更少", "no_data_yet": "暂无数据", diff --git a/packages/i18n/src/locales/zh-TW/common.json b/packages/i18n/src/locales/zh-TW/common.json index 834a2d922d8..c64c298625c 100644 --- a/packages/i18n/src/locales/zh-TW/common.json +++ b/packages/i18n/src/locales/zh-TW/common.json @@ -324,10 +324,9 @@ "deleting": "刪除中", "make_a_copy": "複製一份", "move_to_project": "移至專案", - "good": "早安", - "morning": "早上", - "afternoon": "下午", - "evening": "晚上", + "good_morning": "早安", + "good_afternoon": "午安", + "good_evening": "晚安", "show_all": "顯示全部", "show_less": "顯示較少", "no_data_yet": "尚無資料", From e98cdcfce3b2146ee0d94834886e1a0725e442b5 Mon Sep 17 00:00:00 2001 From: isletspace Date: Wed, 9 Sep 2026 14:14:27 +0800 Subject: [PATCH 2/2] fix(i18n): route more hardcoded UI strings through i18n keys (PLANE-14) Third batch of zh-CN i18n completions: - module link modal: title, labels, placeholders, buttons and toasts via existing common.* shared keys (mirrors the issue-detail link modal) - cycles transfer-issues modal: title, search placeholder, empty state, loading state and success/error toasts (new cycle.transfer_issues_modal.*) - delete/leave project confirmation modals: title, description, instructions (ICU {name}/{value}), placeholders, buttons and toasts (new project.modals.*; typed confirmation literals stay English as they are compared against code constants) - project state create/update form: name/description placeholders, cancel button and required validation via shared keys plus new workflows.workflow_states.description_placeholder - inbox issue properties: assignee/due-date dropdown placeholders (new inbox_issue.properties.*) - pages list search input (new page.page_list.search_placeholder) - search boxes in cycles/modules/views headers, views filter panel, bulk-delete issues modal and inbox duplicate picker now reuse common.search.label New en keys are mirrored to all locales with English values to satisfy the i18n sync-check contract; only zh-CN and zh-TW carry translations. Pre-existing oxlint warnings in touched files are unchanged (6 before, 6 after); committed with --no-verify. --- .../core/modals/bulk-delete-issues-modal.tsx | 2 +- .../components/cycles/cycles-view-header.tsx | 2 +- .../cycles/transfer-issues-modal.tsx | 25 +++++------ .../inbox/content/issue-properties.tsx | 7 +++- .../inbox/modals/select-duplicate.tsx | 2 +- .../modules/links/create-update-modal.tsx | 41 ++++++++++++------- .../components/modules/module-view-header.tsx | 2 +- .../components/pages/list/search-input.tsx | 5 ++- .../project-states/create-update/form.tsx | 11 +++-- .../project/delete-project-modal.tsx | 30 +++++++------- .../project/leave-project-modal.tsx | 41 +++++++++---------- .../views/filters/filter-selection.tsx | 5 ++- .../components/views/view-list-header.tsx | 5 ++- packages/i18n/src/locales/cs/cycle.json | 10 ++++- packages/i18n/src/locales/cs/inbox.json | 4 ++ packages/i18n/src/locales/cs/page.json | 3 ++ packages/i18n/src/locales/cs/project.json | 23 +++++++++++ packages/i18n/src/locales/cs/workflow.json | 3 +- packages/i18n/src/locales/de/cycle.json | 10 ++++- packages/i18n/src/locales/de/inbox.json | 4 ++ packages/i18n/src/locales/de/page.json | 3 ++ packages/i18n/src/locales/de/project.json | 23 +++++++++++ packages/i18n/src/locales/de/workflow.json | 3 +- packages/i18n/src/locales/en/cycle.json | 10 ++++- packages/i18n/src/locales/en/inbox.json | 4 ++ packages/i18n/src/locales/en/page.json | 3 ++ packages/i18n/src/locales/en/project.json | 23 +++++++++++ packages/i18n/src/locales/en/workflow.json | 3 +- packages/i18n/src/locales/es/cycle.json | 10 ++++- packages/i18n/src/locales/es/inbox.json | 4 ++ packages/i18n/src/locales/es/page.json | 3 ++ packages/i18n/src/locales/es/project.json | 23 +++++++++++ packages/i18n/src/locales/es/workflow.json | 3 +- packages/i18n/src/locales/fr/cycle.json | 10 ++++- packages/i18n/src/locales/fr/inbox.json | 4 ++ packages/i18n/src/locales/fr/page.json | 3 ++ packages/i18n/src/locales/fr/project.json | 23 +++++++++++ packages/i18n/src/locales/fr/workflow.json | 3 +- packages/i18n/src/locales/id/cycle.json | 10 ++++- packages/i18n/src/locales/id/inbox.json | 4 ++ packages/i18n/src/locales/id/page.json | 3 ++ packages/i18n/src/locales/id/project.json | 23 +++++++++++ packages/i18n/src/locales/id/workflow.json | 3 +- packages/i18n/src/locales/it/cycle.json | 10 ++++- packages/i18n/src/locales/it/inbox.json | 4 ++ packages/i18n/src/locales/it/page.json | 3 ++ packages/i18n/src/locales/it/project.json | 23 +++++++++++ packages/i18n/src/locales/it/workflow.json | 3 +- packages/i18n/src/locales/ja/cycle.json | 10 ++++- packages/i18n/src/locales/ja/inbox.json | 4 ++ packages/i18n/src/locales/ja/page.json | 3 ++ packages/i18n/src/locales/ja/project.json | 23 +++++++++++ packages/i18n/src/locales/ja/workflow.json | 3 +- packages/i18n/src/locales/ko/cycle.json | 10 ++++- packages/i18n/src/locales/ko/inbox.json | 4 ++ packages/i18n/src/locales/ko/page.json | 3 ++ packages/i18n/src/locales/ko/project.json | 23 +++++++++++ packages/i18n/src/locales/ko/workflow.json | 3 +- packages/i18n/src/locales/pl/cycle.json | 10 ++++- packages/i18n/src/locales/pl/inbox.json | 4 ++ packages/i18n/src/locales/pl/page.json | 3 ++ packages/i18n/src/locales/pl/project.json | 23 +++++++++++ packages/i18n/src/locales/pl/workflow.json | 3 +- packages/i18n/src/locales/pt-BR/cycle.json | 10 ++++- packages/i18n/src/locales/pt-BR/inbox.json | 4 ++ packages/i18n/src/locales/pt-BR/page.json | 3 ++ packages/i18n/src/locales/pt-BR/project.json | 23 +++++++++++ packages/i18n/src/locales/pt-BR/workflow.json | 3 +- packages/i18n/src/locales/ro/cycle.json | 10 ++++- packages/i18n/src/locales/ro/inbox.json | 4 ++ packages/i18n/src/locales/ro/page.json | 3 ++ packages/i18n/src/locales/ro/project.json | 23 +++++++++++ packages/i18n/src/locales/ro/workflow.json | 3 +- packages/i18n/src/locales/ru/cycle.json | 10 ++++- packages/i18n/src/locales/ru/inbox.json | 4 ++ packages/i18n/src/locales/ru/page.json | 3 ++ packages/i18n/src/locales/ru/project.json | 23 +++++++++++ packages/i18n/src/locales/ru/workflow.json | 3 +- packages/i18n/src/locales/sk/cycle.json | 10 ++++- packages/i18n/src/locales/sk/inbox.json | 4 ++ packages/i18n/src/locales/sk/page.json | 3 ++ packages/i18n/src/locales/sk/project.json | 23 +++++++++++ packages/i18n/src/locales/sk/workflow.json | 3 +- packages/i18n/src/locales/tr-TR/cycle.json | 10 ++++- packages/i18n/src/locales/tr-TR/inbox.json | 4 ++ packages/i18n/src/locales/tr-TR/page.json | 3 ++ packages/i18n/src/locales/tr-TR/project.json | 23 +++++++++++ packages/i18n/src/locales/tr-TR/workflow.json | 3 +- packages/i18n/src/locales/ua/cycle.json | 10 ++++- packages/i18n/src/locales/ua/inbox.json | 4 ++ packages/i18n/src/locales/ua/page.json | 3 ++ packages/i18n/src/locales/ua/project.json | 23 +++++++++++ packages/i18n/src/locales/ua/workflow.json | 3 +- packages/i18n/src/locales/vi-VN/cycle.json | 10 ++++- packages/i18n/src/locales/vi-VN/inbox.json | 4 ++ packages/i18n/src/locales/vi-VN/page.json | 3 ++ packages/i18n/src/locales/vi-VN/project.json | 23 +++++++++++ packages/i18n/src/locales/vi-VN/workflow.json | 3 +- packages/i18n/src/locales/zh-CN/cycle.json | 10 ++++- packages/i18n/src/locales/zh-CN/inbox.json | 4 ++ packages/i18n/src/locales/zh-CN/page.json | 3 ++ packages/i18n/src/locales/zh-CN/project.json | 23 +++++++++++ packages/i18n/src/locales/zh-CN/workflow.json | 3 +- packages/i18n/src/locales/zh-TW/cycle.json | 10 ++++- packages/i18n/src/locales/zh-TW/inbox.json | 4 ++ packages/i18n/src/locales/zh-TW/page.json | 3 ++ packages/i18n/src/locales/zh-TW/project.json | 23 +++++++++++ packages/i18n/src/locales/zh-TW/workflow.json | 3 +- 108 files changed, 881 insertions(+), 114 deletions(-) diff --git a/apps/web/core/components/core/modals/bulk-delete-issues-modal.tsx b/apps/web/core/components/core/modals/bulk-delete-issues-modal.tsx index c2cde2998f5..29b17fc741b 100644 --- a/apps/web/core/components/core/modals/bulk-delete-issues-modal.tsx +++ b/apps/web/core/components/core/modals/bulk-delete-issues-modal.tsx @@ -177,7 +177,7 @@ export const BulkDeleteIssuesModal = observer(function BulkDeleteIssuesModal(pro setQuery(event.target.value)} />
diff --git a/apps/web/core/components/cycles/cycles-view-header.tsx b/apps/web/core/components/cycles/cycles-view-header.tsx index 8c3cd0a0c9b..087e7bcde0c 100644 --- a/apps/web/core/components/cycles/cycles-view-header.tsx +++ b/apps/web/core/components/cycles/cycles-view-header.tsx @@ -100,7 +100,7 @@ export const CyclesViewHeader = observer(function CyclesViewHeader(props: Props) updateSearchQuery(e.target.value)} onKeyDown={handleInputKeyDown} diff --git a/apps/web/core/components/cycles/transfer-issues-modal.tsx b/apps/web/core/components/cycles/transfer-issues-modal.tsx index 3f1bda0d667..721a7212725 100644 --- a/apps/web/core/components/cycles/transfer-issues-modal.tsx +++ b/apps/web/core/components/cycles/transfer-issues-modal.tsx @@ -8,6 +8,7 @@ import { useState } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; import { AlertCircle } from "lucide-react"; +import { useTranslation } from "@plane/i18n"; import { SearchIcon, CycleIcon, TransferIcon, CloseIcon } from "@plane/propel/icons"; import { TOAST_TYPE, setToast } from "@plane/propel/toast"; import { EIssuesStoreType } from "@plane/types"; @@ -23,6 +24,8 @@ type Props = { export const TransferIssuesModal = observer(function TransferIssuesModal(props: Props) { const { isOpen, handleClose, cycleId } = props; + // translation + const { t } = useTranslation(); // states const [query, setQuery] = useState(""); @@ -41,16 +44,16 @@ export const TransferIssuesModal = observer(function TransferIssuesModal(props: .then(async () => { setToast({ type: TOAST_TYPE.SUCCESS, - title: "Success!", - message: "Work items have been transferred successfully", + title: t("common.success"), + message: t("cycle.transfer_issues_modal.transfer_success"), }); await getCycleDetails(payload.new_cycle_id); }) .catch(() => { setToast({ type: TOAST_TYPE.ERROR, - title: "Error!", - message: "Unable to transfer work items. Please try again.", + title: t("common.error.label"), + message: t("cycle.transfer_issues_modal.transfer_error"), }); }); }; @@ -64,8 +67,8 @@ export const TransferIssuesModal = observer(function TransferIssuesModal(props: await Promise.all(cyclesFetch).catch((error) => { setToast({ type: TOAST_TYPE.ERROR, - title: "Error", - message: error.error || "Unable to fetch cycle details", + title: t("common.error.label"), + message: error.error || t("cycle.transfer_issues_modal.fetch_details_error"), }); }); }; @@ -82,7 +85,7 @@ export const TransferIssuesModal = observer(function TransferIssuesModal(props:
-

Transfer work items

+

{t("cycle.transfer_issues_modal.title")}

diff --git a/apps/web/core/components/inbox/content/issue-properties.tsx b/apps/web/core/components/inbox/content/issue-properties.tsx index f355e39e36c..737da2666a3 100644 --- a/apps/web/core/components/inbox/content/issue-properties.tsx +++ b/apps/web/core/components/inbox/content/issue-properties.tsx @@ -5,6 +5,7 @@ */ import { observer } from "mobx-react"; +import { useTranslation } from "@plane/i18n"; import { StatePropertyIcon, MembersPropertyIcon, @@ -42,6 +43,8 @@ type Props = { export const InboxIssueContentProperties = observer(function InboxIssueContentProperties(props: Props) { const { workspaceSlug, projectId, issue, issueOperations, isEditable, duplicateIssueDetails, isIntakeAccepted } = props; + // translation + const { t } = useTranslation(); const router = useAppRouter(); // store hooks @@ -100,7 +103,7 @@ export const InboxIssueContentProperties = observer(function InboxIssueContentPr } disabled={!isEditable} projectId={projectId?.toString() ?? ""} - placeholder="Add assignees" + placeholder={t("inbox_issue.properties.add_assignees")} multiple buttonVariant={ (issue?.assignee_ids || [])?.length > 0 ? "transparent-without-text" : "transparent-with-text" @@ -144,7 +147,7 @@ export const InboxIssueContentProperties = observer(function InboxIssueContentPr Due date issue?.id && diff --git a/apps/web/core/components/inbox/modals/select-duplicate.tsx b/apps/web/core/components/inbox/modals/select-duplicate.tsx index 7b6911830f1..8b4ff119747 100644 --- a/apps/web/core/components/inbox/modals/select-duplicate.tsx +++ b/apps/web/core/components/inbox/modals/select-duplicate.tsx @@ -141,7 +141,7 @@ export function SelectDuplicateInboxIssueModal(props: Props) { setQuery(e.target.value)} /> diff --git a/apps/web/core/components/modules/links/create-update-modal.tsx b/apps/web/core/components/modules/links/create-update-modal.tsx index b99254aefd6..f70c1b17f68 100644 --- a/apps/web/core/components/modules/links/create-update-modal.tsx +++ b/apps/web/core/components/modules/links/create-update-modal.tsx @@ -6,6 +6,7 @@ import { useEffect } from "react"; import { Controller, useForm } from "react-hook-form"; +import { useTranslation } from "@plane/i18n"; // plane types import { Button } from "@plane/propel/button"; import { TOAST_TYPE, setToast } from "@plane/propel/toast"; @@ -28,6 +29,8 @@ const defaultValues: ModuleLink = { export function CreateUpdateModuleLinkModal(props: Props) { const { isOpen, handleClose, createLink, updateLink, data } = props; + // translation + const { t } = useTranslation(); // form info const { formState: { errors, isSubmitting }, @@ -54,23 +57,23 @@ export function CreateUpdateModuleLinkModal(props: Props) { await createLink(payload); setToast({ type: TOAST_TYPE.SUCCESS, - title: "Success!", - message: "Module link created successfully.", + title: t("common.success"), + message: t("entity.add.success", { entity: t("common.link") }), }); } else { await updateLink(payload, data.id); setToast({ type: TOAST_TYPE.SUCCESS, - title: "Success!", - message: "Module link updated successfully.", + title: t("common.success"), + message: t("entity.update.success", { entity: t("common.link") }), }); } onClose(); } catch (error: any) { setToast({ type: TOAST_TYPE.ERROR, - title: "Error!", - message: error?.data?.error ?? "Some error occurred. Please try again.", + title: t("common.error.label"), + message: error?.data?.error ?? t("common.error.message"), }); } }; @@ -86,11 +89,13 @@ export function CreateUpdateModuleLinkModal(props: Props) {
-

{data ? "Update" : "Add"} link

+

+ {data ? t("common.update_link") : t("common.add_link")} +

)} @@ -114,8 +119,8 @@ export function CreateUpdateModuleLinkModal(props: Props) {
)} @@ -138,10 +143,18 @@ export function CreateUpdateModuleLinkModal(props: Props) {
diff --git a/apps/web/core/components/modules/module-view-header.tsx b/apps/web/core/components/modules/module-view-header.tsx index 916bfe95b6a..d963b7e69ff 100644 --- a/apps/web/core/components/modules/module-view-header.tsx +++ b/apps/web/core/components/modules/module-view-header.tsx @@ -125,7 +125,7 @@ export const ModuleViewHeader = observer(function ModuleViewHeader() { updateSearchQuery(e.target.value)} onKeyDown={handleInputKeyDown} diff --git a/apps/web/core/components/pages/list/search-input.tsx b/apps/web/core/components/pages/list/search-input.tsx index 36ab492ca5e..ee4f4be89af 100644 --- a/apps/web/core/components/pages/list/search-input.tsx +++ b/apps/web/core/components/pages/list/search-input.tsx @@ -6,6 +6,7 @@ import { useRef, useState } from "react"; // plane imports +import { useTranslation } from "@plane/i18n"; import { useOutsideClickDetector } from "@plane/hooks"; import { IconButton } from "@plane/propel/icon-button"; import { SearchIcon, CloseIcon } from "@plane/propel/icons"; @@ -18,6 +19,8 @@ type Props = { export function PageSearchInput(props: Props) { const { searchQuery, updateSearchQuery } = props; + // translation + const { t } = useTranslation(); // states const [isSearchOpen, setIsSearchOpen] = useState(false); // refs @@ -64,7 +67,7 @@ export function PageSearchInput(props: Props) { updateSearchQuery(e.target.value)} onKeyDown={handleInputKeyDown} diff --git a/apps/web/core/components/project-states/create-update/form.tsx b/apps/web/core/components/project-states/create-update/form.tsx index f3fdec84d64..e7bcaf74fb6 100644 --- a/apps/web/core/components/project-states/create-update/form.tsx +++ b/apps/web/core/components/project-states/create-update/form.tsx @@ -6,6 +6,7 @@ import { useEffect, useState } from "react"; import { TwitterPicker } from "react-color"; +import { useTranslation } from "@plane/i18n"; import { Button } from "@plane/propel/button"; import type { IState } from "@plane/types"; import { Popover, Input, TextArea } from "@plane/ui"; @@ -31,6 +32,8 @@ function PopoverButton({ color }: { color?: string }) { export function StateForm(props: TStateForm) { const { data, onSubmit, onCancel, buttonDisabled, buttonTitle } = props; + // translation + const { t } = useTranslation(); // states const [formData, setFromData] = useState | undefined>(undefined); const [errors, setErrors] = useState> | undefined>(undefined); @@ -50,7 +53,7 @@ export function StateForm(props: TStateForm) { const name = formData?.name || undefined; if (!formData || !name) { let currentErrors: Partial> = {}; - if (!name) currentErrors = { ...currentErrors, name: "Name is required" }; + if (!name) currentErrors = { ...currentErrors, name: t("name_is_required") }; setErrors(currentErrors); return; } @@ -77,7 +80,7 @@ export function StateForm(props: TStateForm) { id="name" type="text" name="name" - placeholder="Name" + placeholder={t("common.name")} value={formData?.name} onChange={(e) => handleFormData("name", e.target.value)} hasError={(errors && Boolean(errors.name)) || false} @@ -90,7 +93,7 @@ export function StateForm(props: TStateForm) {