diff --git a/Parlance/ClientApp/public/resources/translations/cs-CZ/translation.json b/Parlance/ClientApp/public/resources/translations/cs-CZ/translation.json
index ae69e57b..48b22672 100644
--- a/Parlance/ClientApp/public/resources/translations/cs-CZ/translation.json
+++ b/Parlance/ClientApp/public/resources/translations/cs-CZ/translation.json
@@ -80,12 +80,17 @@
"CLOSE": "",
"COMMENTS": "",
"COMMENT_ADD": "",
+ "COMMENT_GO_TO_STRING": "",
+ "COMMENT_NOT_LOGGED_IN_PROMPT": "",
"COMMENT_OPEN_THREADS_few": "",
"COMMENT_OPEN_THREADS_one": "",
"COMMENT_OPEN_THREADS_other": "",
+ "COMMENT_ORIGINAL_TRANSLATION": "",
+ "COMMENT_ORIGINAL_TRANSLATION_NO_LONGER_EXISTS": "",
"COMMENT_POST": "",
"COMMENT_POSTING_AS_PROMPT": "",
"COMMENT_SEND_FAILURE_PROMPT": "",
+ "COMMENT_THREAD_PROFILE_PICTURE_ALT_TEXT": "",
"CONFIRM_PASSWORD": "",
"CONFIRM_PASSWORD_PROMPT": "",
"CONNECTED_GLOSSARIES": "",
@@ -177,6 +182,10 @@
"OK": "",
"OTHER_LANGUAGES": "",
"OVERVIEW": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS_DESCRIPTION": "",
+ "OVERVIEW_GO_TO_COMMENTS": "",
+ "OVERVIEW_STATS": "",
"PARLANCE_ADMINISTRATION": "",
"PARLANCE_ADMINISTRATION_DESCRIPTION": "",
"PARLANCE_ON_GIT": "",
diff --git a/Parlance/ClientApp/public/resources/translations/da/translation.json b/Parlance/ClientApp/public/resources/translations/da/translation.json
index 2924ca45..6958b662 100644
--- a/Parlance/ClientApp/public/resources/translations/da/translation.json
+++ b/Parlance/ClientApp/public/resources/translations/da/translation.json
@@ -81,10 +81,15 @@
"CLOSE": "Luk",
"COMMENTS": "",
"COMMENT_ADD": "",
+ "COMMENT_GO_TO_STRING": "",
+ "COMMENT_NOT_LOGGED_IN_PROMPT": "",
"COMMENT_OPEN_THREADS": "",
+ "COMMENT_ORIGINAL_TRANSLATION": "",
+ "COMMENT_ORIGINAL_TRANSLATION_NO_LONGER_EXISTS": "",
"COMMENT_POST": "",
"COMMENT_POSTING_AS_PROMPT": "",
"COMMENT_SEND_FAILURE_PROMPT": "",
+ "COMMENT_THREAD_PROFILE_PICTURE_ALT_TEXT": "",
"CONFIRM_PASSWORD": "Bekræft adgangskode",
"CONFIRM_PASSWORD_PROMPT": "Bekræft adgangskoden til din konto",
"CONNECTED_GLOSSARIES": "",
@@ -177,6 +182,10 @@
"OK": "",
"OTHER_LANGUAGES": "",
"OVERVIEW": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS_DESCRIPTION": "",
+ "OVERVIEW_GO_TO_COMMENTS": "",
+ "OVERVIEW_STATS": "",
"PARLANCE_ADMINISTRATION": "",
"PARLANCE_ADMINISTRATION_DESCRIPTION": "",
"PARLANCE_ON_GIT": "",
diff --git a/Parlance/ClientApp/public/resources/translations/de/translation.json b/Parlance/ClientApp/public/resources/translations/de/translation.json
index 034e62b3..2cb9367c 100644
--- a/Parlance/ClientApp/public/resources/translations/de/translation.json
+++ b/Parlance/ClientApp/public/resources/translations/de/translation.json
@@ -81,10 +81,15 @@
"CLOSE": "Schließen",
"COMMENTS": "",
"COMMENT_ADD": "",
+ "COMMENT_GO_TO_STRING": "",
+ "COMMENT_NOT_LOGGED_IN_PROMPT": "",
"COMMENT_OPEN_THREADS": "",
+ "COMMENT_ORIGINAL_TRANSLATION": "",
+ "COMMENT_ORIGINAL_TRANSLATION_NO_LONGER_EXISTS": "",
"COMMENT_POST": "",
"COMMENT_POSTING_AS_PROMPT": "",
"COMMENT_SEND_FAILURE_PROMPT": "",
+ "COMMENT_THREAD_PROFILE_PICTURE_ALT_TEXT": "",
"CONFIRM_PASSWORD": "Passwort bestätigen",
"CONFIRM_PASSWORD_PROMPT": "Bestätige das Passwort für deinen Account",
"CONNECTED_GLOSSARIES": "",
@@ -177,6 +182,10 @@
"OK": "Ok",
"OTHER_LANGUAGES": "",
"OVERVIEW": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS_DESCRIPTION": "",
+ "OVERVIEW_GO_TO_COMMENTS": "",
+ "OVERVIEW_STATS": "",
"PARLANCE_ADMINISTRATION": "Parlance Administration",
"PARLANCE_ADMINISTRATION_DESCRIPTION": "Konfiguriere den Parlance server",
"PARLANCE_ON_GIT": "",
diff --git a/Parlance/ClientApp/public/resources/translations/en/translation.json b/Parlance/ClientApp/public/resources/translations/en/translation.json
index 957e6f00..cc86b5f5 100644
--- a/Parlance/ClientApp/public/resources/translations/en/translation.json
+++ b/Parlance/ClientApp/public/resources/translations/en/translation.json
@@ -83,11 +83,16 @@
"CLOSE": "Close",
"COMMENTS": "Comments",
"COMMENT_ADD": "Add Comment",
+ "COMMENT_GO_TO_STRING": "Go to string",
+ "COMMENT_NOT_LOGGED_IN_PROMPT": "Log in to write a comment",
"COMMENT_OPEN_THREADS_one": "{{count}} open thread",
"COMMENT_OPEN_THREADS_other": "{{count}} open threads",
+ "COMMENT_ORIGINAL_TRANSLATION": "Original Translation",
+ "COMMENT_ORIGINAL_TRANSLATION_NO_LONGER_EXISTS": "The translation entry no longer exists",
"COMMENT_POST": "Post Comment",
"COMMENT_POSTING_AS_PROMPT": "Posting as {{user}}",
"COMMENT_SEND_FAILURE_PROMPT": "Unable to send the comment",
+ "COMMENT_THREAD_PROFILE_PICTURE_ALT_TEXT": "{{ user }}'s profile picture",
"CONFIRM_PASSWORD": "Confirm Password",
"CONFIRM_PASSWORD_PROMPT": "Confirm the password for your account",
"CONNECTED_GLOSSARIES": "Connected Glossaries",
@@ -180,6 +185,10 @@
"OK": "OK",
"OTHER_LANGUAGES": "Other Languages",
"OVERVIEW": "Overview",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS": "No open threads",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS_DESCRIPTION": "There are no open comment threads in this file right now",
+ "OVERVIEW_GO_TO_COMMENTS": "Go to comments",
+ "OVERVIEW_STATS": "Stats",
"PARLANCE_ADMINISTRATION": "Parlance Administration",
"PARLANCE_ADMINISTRATION_DESCRIPTION": "Configure the Parlance server",
"PARLANCE_ON_GIT": "Parlance on Git",
diff --git a/Parlance/ClientApp/public/resources/translations/es/translation.json b/Parlance/ClientApp/public/resources/translations/es/translation.json
index e6feca45..a276b961 100644
--- a/Parlance/ClientApp/public/resources/translations/es/translation.json
+++ b/Parlance/ClientApp/public/resources/translations/es/translation.json
@@ -81,10 +81,15 @@
"CLOSE": "",
"COMMENTS": "",
"COMMENT_ADD": "",
+ "COMMENT_GO_TO_STRING": "",
+ "COMMENT_NOT_LOGGED_IN_PROMPT": "",
"COMMENT_OPEN_THREADS": "",
+ "COMMENT_ORIGINAL_TRANSLATION": "",
+ "COMMENT_ORIGINAL_TRANSLATION_NO_LONGER_EXISTS": "",
"COMMENT_POST": "",
"COMMENT_POSTING_AS_PROMPT": "",
"COMMENT_SEND_FAILURE_PROMPT": "",
+ "COMMENT_THREAD_PROFILE_PICTURE_ALT_TEXT": "",
"CONFIRM_PASSWORD": "",
"CONFIRM_PASSWORD_PROMPT": "",
"CONNECTED_GLOSSARIES": "",
@@ -177,6 +182,10 @@
"OK": "",
"OTHER_LANGUAGES": "",
"OVERVIEW": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS_DESCRIPTION": "",
+ "OVERVIEW_GO_TO_COMMENTS": "",
+ "OVERVIEW_STATS": "",
"PARLANCE_ADMINISTRATION": "",
"PARLANCE_ADMINISTRATION_DESCRIPTION": "",
"PARLANCE_ON_GIT": "",
diff --git a/Parlance/ClientApp/public/resources/translations/fr-CA/translation.json b/Parlance/ClientApp/public/resources/translations/fr-CA/translation.json
index 5f1ed5f3..f55f776e 100644
--- a/Parlance/ClientApp/public/resources/translations/fr-CA/translation.json
+++ b/Parlance/ClientApp/public/resources/translations/fr-CA/translation.json
@@ -81,11 +81,16 @@
"CLOSE": "Fermer",
"COMMENTS": "",
"COMMENT_ADD": "",
+ "COMMENT_GO_TO_STRING": "",
+ "COMMENT_NOT_LOGGED_IN_PROMPT": "",
"COMMENT_OPEN_THREADS_one": "",
"COMMENT_OPEN_THREADS_other": "",
+ "COMMENT_ORIGINAL_TRANSLATION": "",
+ "COMMENT_ORIGINAL_TRANSLATION_NO_LONGER_EXISTS": "",
"COMMENT_POST": "",
"COMMENT_POSTING_AS_PROMPT": "",
"COMMENT_SEND_FAILURE_PROMPT": "",
+ "COMMENT_THREAD_PROFILE_PICTURE_ALT_TEXT": "",
"CONFIRM_PASSWORD": "",
"CONFIRM_PASSWORD_PROMPT": "",
"CONNECTED_GLOSSARIES": "",
@@ -178,6 +183,10 @@
"OK": "",
"OTHER_LANGUAGES": "",
"OVERVIEW": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS_DESCRIPTION": "",
+ "OVERVIEW_GO_TO_COMMENTS": "",
+ "OVERVIEW_STATS": "",
"PARLANCE_ADMINISTRATION": "",
"PARLANCE_ADMINISTRATION_DESCRIPTION": "",
"PARLANCE_ON_GIT": "",
diff --git a/Parlance/ClientApp/public/resources/translations/he-IL/translation.json b/Parlance/ClientApp/public/resources/translations/he-IL/translation.json
index 1e52bb5b..85639d14 100644
--- a/Parlance/ClientApp/public/resources/translations/he-IL/translation.json
+++ b/Parlance/ClientApp/public/resources/translations/he-IL/translation.json
@@ -31,16 +31,16 @@
"ACTIONS": "פעולות",
"ADD_ENTRY_TO_GLOSSARY": "הוסף ערך למילון",
"ADD_GLOSSARY": "הוסף מילון",
- "ADD_GLOSSARY_CONNECT_PROJECT_PROMPT": "חבר מילון לפרויקט על ידי ביקור בפרויקט ובחירה ב-\u0022ניהול מילונים\u0022",
+ "ADD_GLOSSARY_CONNECT_PROJECT_PROMPT": "חבר מילון לפרויקט על ידי ביקור בפרויקט ובחירה ב-\"ניהול מילונים\"",
"ADD_GLOSSARY_ERROR": "לא ניתן להוסיף מילון",
"ADD_GLOSSARY_PROJECTS_CONNECTED_one": "פרויקט {{count}} מחובר",
- "ADD_GLOSSARY_PROJECTS_CONNECTED_two": "{{count}} פרוייקטים מחוברים",
"ADD_GLOSSARY_PROJECTS_CONNECTED_other": "{{count}} פרויקטים מחוברים",
+ "ADD_GLOSSARY_PROJECTS_CONNECTED_two": "{{count}} פרוייקטים מחוברים",
"ADD_PROJECT": "הוסף פרויקט חדש",
"ADD_PROJECT_ERROR": "לא ניתן להוסיף פרויקט חדש",
"ADD_PROJECT_ERROR_PROMPT": "לא ניתן להוסיף את הפרויקט. נסה שוב במועד מאוחר יותר.",
"ADD_PROJECT_PROMPT_1": "הזן את הנתונים הדרושים כדי להוסיף פרויקט",
- "ADD_PROJECT_PROMPT_2": "ודא שהפרויקט מכיל קובץ \u003C1\u003E.parlance.json\u003C/1\u003E בשורש תיקיית הפרויקט.",
+ "ADD_PROJECT_PROMPT_2": "ודא שהפרויקט מכיל קובץ <1>.parlance.json1> בשורש תיקיית הפרויקט.",
"ADD_TO_GLOSSARY": "הוסף למילון",
"ADD_TO_GLOSSARY_CONFIRM": "הוסף ל-{{glossary}}",
"ADD_TO_GLOSSARY_ERROR_NO_TERM": "הזן את המונח להוספה למילון",
@@ -84,12 +84,17 @@
"CLOSE": "סגור",
"COMMENTS": "תגובות",
"COMMENT_ADD": "הוסף תגובה",
+ "COMMENT_GO_TO_STRING": "",
+ "COMMENT_NOT_LOGGED_IN_PROMPT": "",
"COMMENT_OPEN_THREADS_one": "פתוח שרשור תגובות {{count}}",
- "COMMENT_OPEN_THREADS_two": "פתוחים {{count}} שרשורי תגובות",
"COMMENT_OPEN_THREADS_other": "פתוחים {{count}} שרשורי תגובות",
+ "COMMENT_OPEN_THREADS_two": "פתוחים {{count}} שרשורי תגובות",
+ "COMMENT_ORIGINAL_TRANSLATION": "",
+ "COMMENT_ORIGINAL_TRANSLATION_NO_LONGER_EXISTS": "",
"COMMENT_POST": "פרסם תגובה",
"COMMENT_POSTING_AS_PROMPT": "מפרסם כ-{{user}}",
"COMMENT_SEND_FAILURE_PROMPT": "לא ניתן לפרסם תגובה",
+ "COMMENT_THREAD_PROFILE_PICTURE_ALT_TEXT": "",
"CONFIRM_PASSWORD": "אשר סיסמה",
"CONFIRM_PASSWORD_PROMPT": "אשר את הסיסמה לחשבון שלך",
"CONNECTED_GLOSSARIES": "מילונים קשורים",
@@ -129,7 +134,7 @@
"ERROR_TWO_FACTOR_IS_DISABLED": "אימות דו-גורמי מושבת.",
"ERROR_UNKNOWN_USER": "המשתמש הזה אינו קיים.",
"ERROR_USERNAME_ALREADY_EXISTS": "מצטערים, שם המשתמש הזה כבר תפוס.",
- "ET_CETERA": "וכו\u0027",
+ "ET_CETERA": "וכו'",
"FILTER_ALERT_STRINGS": "הצג מחרוזות עם התראות",
"FILTER_ALL_STRINGS": "הצג כל המחרוזות",
"FILTER_UNFINISHED_STRINGS": "הצג מחרוזות לא גמורות",
@@ -182,6 +187,10 @@
"OK": "אישור",
"OTHER_LANGUAGES": "שפות אחרות",
"OVERVIEW": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS_DESCRIPTION": "",
+ "OVERVIEW_GO_TO_COMMENTS": "",
+ "OVERVIEW_STATS": "",
"PARLANCE_ADMINISTRATION": "ניהול Parlance",
"PARLANCE_ADMINISTRATION_DESCRIPTION": "הגדר את שרת ה-Parlance",
"PARLANCE_ON_GIT": "Parlance ב-Git",
@@ -338,36 +347,36 @@
"USER_PERMISSIONS_TITLE": "הרשאות עבור {{user}}",
"VCS_COMMIT": "בצע קומיט",
"VCS_COMMIT_PROMPT_one": "בצע שינוי {{count}}?",
- "VCS_COMMIT_PROMPT_two": "בצע {{count}} שינויים?",
"VCS_COMMIT_PROMPT_other": "בצע {{count}} שינויים?",
+ "VCS_COMMIT_PROMPT_two": "בצע {{count}} שינויים?",
"VCS_CREATED_COMMIT": "נוצר קומיט",
"VCS_CREATED_COMMIT_PROMPT": "הקומיט נוצר",
"VCS_CREATE_COMMIT": "צור קומיט",
"VCS_DISCARD": "היפטר",
"VCS_DISCARD_UNCOMMITTED_CHANGES": "היפטר משינויים להם לא בוצע קומיט",
"VCS_DISCARD_UNCOMMITTED_CHANGES_PROMPT_one": "היפטר משינויים בהם לא בוצע קומיט בקובץ {{count}}?",
- "VCS_DISCARD_UNCOMMITTED_CHANGES_PROMPT_two": "היפטר משינויים בהם לא בוצע קומיט ב-{{count}} קבצים?",
"VCS_DISCARD_UNCOMMITTED_CHANGES_PROMPT_other": "היפטר משינויים בהם לא בוצע קומיט ב-{{count}} קבצים?",
+ "VCS_DISCARD_UNCOMMITTED_CHANGES_PROMPT_two": "היפטר משינויים בהם לא בוצע קומיט ב-{{count}} קבצים?",
"VCS_FETCH": "השג",
"VCS_GIT": "Git",
"VCS_INCOMING_COMMITS": "קומיטים נכנסים",
"VCS_INCOMING_COMMITS_PULL_one": "משוך קומיט {{count}}",
- "VCS_INCOMING_COMMITS_PULL_two": "משוך {{count}} קומיטים",
"VCS_INCOMING_COMMITS_PULL_other": "משוך {{count}} קומיטים",
+ "VCS_INCOMING_COMMITS_PULL_two": "משוך {{count}} קומיטים",
"VCS_LAST_LOCAL_COMMIT": "קומיט מקומי אחרון",
"VCS_LAST_REMOTE_COMMIT": "קומיט מכוון אחרון",
"VCS_NOTHING_TO_COMMIT": "אין למה לבצע קומיט",
"VCS_NOTHING_TO_COMMIT_PROMPT": "אין למה לבצע קומיט.",
"VCS_OUTGOING_COMMITS": "קומיטים יוצאים",
"VCS_OUTGOING_COMMITS_PUSH_one": "דחוף קומיט {{count}}",
- "VCS_OUTGOING_COMMITS_PUSH_two": "דחוף {{count}} קומיטים",
"VCS_OUTGOING_COMMITS_PUSH_other": "דחוף {{count}} קומיטים",
+ "VCS_OUTGOING_COMMITS_PUSH_two": "דחוף {{count}} קומיטים",
"VCS_PULL": "משיכה",
"VCS_PUSH": "דחיפה",
"VCS_UNCOMMITTED_CHANGES": "שינויים שלא התבצעו",
"VCS_UNCOMMITTED_CHANGES_COMMIT_one": "בצע קומיט לקובץ {{count}}",
- "VCS_UNCOMMITTED_CHANGES_COMMIT_two": "בצע קומיטים ל-{{count}} קבצים",
"VCS_UNCOMMITTED_CHANGES_COMMIT_other": "בצע קומיטים ל-{{count}} קבצים",
+ "VCS_UNCOMMITTED_CHANGES_COMMIT_two": "בצע קומיטים ל-{{count}} קבצים",
"VERIFICATION_EMAIL_RESEND_PROMPT": "בדוק את דואר האלקטרוני שלך בשביל קוד אימות. ייתכן שתצטרך לבדוק את תיקיית הספאם שלך.",
"VERIFY_EMAIL": "אמת דואר אלקטרוני",
"VERIFY_EMAIL_FAILED_1": "אימות דואר האלקטרוני נכשל",
diff --git a/Parlance/ClientApp/public/resources/translations/nl/translation.json b/Parlance/ClientApp/public/resources/translations/nl/translation.json
index b6fee163..f6281892 100644
--- a/Parlance/ClientApp/public/resources/translations/nl/translation.json
+++ b/Parlance/ClientApp/public/resources/translations/nl/translation.json
@@ -81,11 +81,16 @@
"CLOSE": "Sluiten",
"COMMENTS": "Reacties",
"COMMENT_ADD": "Reactie Toevoegen",
+ "COMMENT_GO_TO_STRING": "",
+ "COMMENT_NOT_LOGGED_IN_PROMPT": "",
"COMMENT_OPEN_THREADS_one": "{{count}} open thread",
"COMMENT_OPEN_THREADS_other": "",
+ "COMMENT_ORIGINAL_TRANSLATION": "",
+ "COMMENT_ORIGINAL_TRANSLATION_NO_LONGER_EXISTS": "",
"COMMENT_POST": "Reactie Plaatsen",
"COMMENT_POSTING_AS_PROMPT": "Reageren als {{user}}",
"COMMENT_SEND_FAILURE_PROMPT": "Kon de reactie niet verzenden",
+ "COMMENT_THREAD_PROFILE_PICTURE_ALT_TEXT": "",
"CONFIRM_PASSWORD": "Wachtwoord Bevestigen",
"CONFIRM_PASSWORD_PROMPT": "Bevestig het wachtwoord voor je account",
"CONNECTED_GLOSSARIES": "",
@@ -178,6 +183,10 @@
"OK": "Oké",
"OTHER_LANGUAGES": "Andere Talen",
"OVERVIEW": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS_DESCRIPTION": "",
+ "OVERVIEW_GO_TO_COMMENTS": "",
+ "OVERVIEW_STATS": "",
"PARLANCE_ADMINISTRATION": "Parlance-administratie",
"PARLANCE_ADMINISTRATION_DESCRIPTION": "Parlance-server configureren",
"PARLANCE_ON_GIT": "Parlance op Git",
diff --git a/Parlance/ClientApp/public/resources/translations/pt-BR/translation.json b/Parlance/ClientApp/public/resources/translations/pt-BR/translation.json
index 784b9384..b5c845a7 100644
--- a/Parlance/ClientApp/public/resources/translations/pt-BR/translation.json
+++ b/Parlance/ClientApp/public/resources/translations/pt-BR/translation.json
@@ -81,10 +81,15 @@
"CLOSE": "Fechar",
"COMMENTS": "",
"COMMENT_ADD": "",
+ "COMMENT_GO_TO_STRING": "",
+ "COMMENT_NOT_LOGGED_IN_PROMPT": "",
"COMMENT_OPEN_THREADS": "",
+ "COMMENT_ORIGINAL_TRANSLATION": "",
+ "COMMENT_ORIGINAL_TRANSLATION_NO_LONGER_EXISTS": "",
"COMMENT_POST": "",
"COMMENT_POSTING_AS_PROMPT": "",
"COMMENT_SEND_FAILURE_PROMPT": "",
+ "COMMENT_THREAD_PROFILE_PICTURE_ALT_TEXT": "",
"CONFIRM_PASSWORD": "Confirmar senha",
"CONFIRM_PASSWORD_PROMPT": "Confirme a senha para a sua conta",
"CONNECTED_GLOSSARIES": "",
@@ -177,6 +182,10 @@
"OK": "OK",
"OTHER_LANGUAGES": "Outras linguagens",
"OVERVIEW": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS_DESCRIPTION": "",
+ "OVERVIEW_GO_TO_COMMENTS": "",
+ "OVERVIEW_STATS": "",
"PARLANCE_ADMINISTRATION": "Administração de Parlance",
"PARLANCE_ADMINISTRATION_DESCRIPTION": "Configurar servidor de Parlance",
"PARLANCE_ON_GIT": "Parlance em Git",
diff --git a/Parlance/ClientApp/public/resources/translations/ro-RO/translation.json b/Parlance/ClientApp/public/resources/translations/ro-RO/translation.json
index fba46840..230e655b 100644
--- a/Parlance/ClientApp/public/resources/translations/ro-RO/translation.json
+++ b/Parlance/ClientApp/public/resources/translations/ro-RO/translation.json
@@ -37,7 +37,7 @@
"ADD_PROJECT_ERROR": "Nu am putut adăuga proiectul",
"ADD_PROJECT_ERROR_PROMPT": "Nu am putut adăuga proiectul. Încearcă mai târziu.",
"ADD_PROJECT_PROMPT_1": "Introdu datele necesare pentru a adăuga un proiect",
- "ADD_PROJECT_PROMPT_2": "Asigură-te că proiectul conține un fișier \u003C1\u003E.parlance.json\u003C/1\u003E la rădăcină.",
+ "ADD_PROJECT_PROMPT_2": "Asigură-te că proiectul conține un fișier <1>.parlance.json1> la rădăcină.",
"ADD_TO_GLOSSARY": "",
"ADD_TO_GLOSSARY_CONFIRM": "",
"ADD_TO_GLOSSARY_ERROR_NO_TERM": "",
@@ -81,12 +81,17 @@
"CLOSE": "Închide",
"COMMENTS": "Comentarii",
"COMMENT_ADD": "Adaugă un comentariu",
+ "COMMENT_GO_TO_STRING": "",
+ "COMMENT_NOT_LOGGED_IN_PROMPT": "",
"COMMENT_OPEN_THREADS_few": "{{count}} conversații deschise",
"COMMENT_OPEN_THREADS_one": "{{count}} conversație deschisă",
"COMMENT_OPEN_THREADS_other": "{{count}} de conversații deschise",
+ "COMMENT_ORIGINAL_TRANSLATION": "",
+ "COMMENT_ORIGINAL_TRANSLATION_NO_LONGER_EXISTS": "",
"COMMENT_POST": "Postează comentariul",
"COMMENT_POSTING_AS_PROMPT": "Postare ca {{user}}",
"COMMENT_SEND_FAILURE_PROMPT": "Nu am putut trimite comentariul",
+ "COMMENT_THREAD_PROFILE_PICTURE_ALT_TEXT": "",
"CONFIRM_PASSWORD": "Confirmă parola",
"CONFIRM_PASSWORD_PROMPT": "Confirmă parola pentru contul tău",
"CONNECTED_GLOSSARIES": "",
@@ -179,6 +184,10 @@
"OK": "OK",
"OTHER_LANGUAGES": "Alte limbi",
"OVERVIEW": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS_DESCRIPTION": "",
+ "OVERVIEW_GO_TO_COMMENTS": "",
+ "OVERVIEW_STATS": "",
"PARLANCE_ADMINISTRATION": "Administrație Parlance",
"PARLANCE_ADMINISTRATION_DESCRIPTION": "Configură serverul Parlance",
"PARLANCE_ON_GIT": "Parlance pe Git",
@@ -235,7 +244,7 @@
"SECURITY_KEY_ADD_NAME_PROMPT": "Numele cheii de securitate",
"SECURITY_KEY_ADD_PROMPT": "Urmărește instrucțiunile din browser pentru a adăuga o cheie de securitate.",
"SECURITY_KEY_ADVERTISEMENT": "Poți să te conectezi mai rapid cu o cheie de acces. Cheile de acces pot fi setate rapid, și sunt mai sigure ca parolele.",
- "SECURITY_KEY_ADVERTISEMENT_2": "Dacă nu vrei să setezi o cheie de acces chiar acum, poți mereu să vizitezi \u0022Setări chei de acces\u0022 în setările contului tău pentru a seta una.",
+ "SECURITY_KEY_ADVERTISEMENT_2": "Dacă nu vrei să setezi o cheie de acces chiar acum, poți mereu să vizitezi \"Setări chei de acces\" în setările contului tău pentru a seta una.",
"SECURITY_KEY_ADVERTISEMENT_FEATURE_1_CONTENT": "Setarea poate fi efectuată în 10 secunde.",
"SECURITY_KEY_ADVERTISEMENT_FEATURE_1_HEADING": "Setare rapidă",
"SECURITY_KEY_ADVERTISEMENT_FEATURE_2_CONTENT": "Nu poți să îți uiți cheia de acces pentru că nu există nimic de ținut minte!",
@@ -249,8 +258,8 @@
"SECURITY_KEY_ADVERTISEMENT_NEVER": "Nu pe acest dispozitiv",
"SECURITY_KEY_ADVERTISEMENT_OK": "Setează acum",
"SECURITY_KEY_ADVERTISEMENT_SETUP_SUCCESS": "Cheia de acces a fost înregistrată cu succes pe acest cont",
- "SECURITY_KEY_ADVERTISEMENT_SETUP_SUCCESS_2": "Data viitoare când te conectezi la Parlance, poți folosi această cheie de acces introducându-ți numele de utilizator și selectând \u0022Folosește o cheie de acces\u0022 când ți se cere parola.",
- "SECURITY_KEY_ADVERTISEMENT_SETUP_SUCCESS_3": "Pentru a-ți gestiona cheile de acces, poți să vizitezi setările contului tău și să selectezi \u0022Gestionare chei de acces\u0022.",
+ "SECURITY_KEY_ADVERTISEMENT_SETUP_SUCCESS_2": "Data viitoare când te conectezi la Parlance, poți folosi această cheie de acces introducându-ți numele de utilizator și selectând \"Folosește o cheie de acces\" când ți se cere parola.",
+ "SECURITY_KEY_ADVERTISEMENT_SETUP_SUCCESS_3": "Pentru a-ți gestiona cheile de acces, poți să vizitezi setările contului tău și să selectezi \"Gestionare chei de acces\".",
"SECURITY_KEY_ADVERTISEMENT_SETUP_SUCCESS_TITLE": "Cheie de acces setată cu succes",
"SECURITY_KEY_ADVERTISEMENT_TITLE": "Setare cheie de acces",
"SECURITY_KEY_DEREGISTER": "Anulează cheia de securitate",
diff --git a/Parlance/ClientApp/public/resources/translations/uk/translation.json b/Parlance/ClientApp/public/resources/translations/uk/translation.json
index 0bd48b94..5a584a1b 100644
--- a/Parlance/ClientApp/public/resources/translations/uk/translation.json
+++ b/Parlance/ClientApp/public/resources/translations/uk/translation.json
@@ -81,10 +81,15 @@
"CLOSE": "",
"COMMENTS": "",
"COMMENT_ADD": "",
+ "COMMENT_GO_TO_STRING": "",
+ "COMMENT_NOT_LOGGED_IN_PROMPT": "",
"COMMENT_OPEN_THREADS": "",
+ "COMMENT_ORIGINAL_TRANSLATION": "",
+ "COMMENT_ORIGINAL_TRANSLATION_NO_LONGER_EXISTS": "",
"COMMENT_POST": "",
"COMMENT_POSTING_AS_PROMPT": "",
"COMMENT_SEND_FAILURE_PROMPT": "",
+ "COMMENT_THREAD_PROFILE_PICTURE_ALT_TEXT": "",
"CONFIRM_PASSWORD": "",
"CONFIRM_PASSWORD_PROMPT": "",
"CONNECTED_GLOSSARIES": "",
@@ -177,6 +182,10 @@
"OK": "",
"OTHER_LANGUAGES": "",
"OVERVIEW": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS_DESCRIPTION": "",
+ "OVERVIEW_GO_TO_COMMENTS": "",
+ "OVERVIEW_STATS": "",
"PARLANCE_ADMINISTRATION": "",
"PARLANCE_ADMINISTRATION_DESCRIPTION": "",
"PARLANCE_ON_GIT": "",
diff --git a/Parlance/ClientApp/public/resources/translations/vi/translation.json b/Parlance/ClientApp/public/resources/translations/vi/translation.json
index 90e81ba2..4250413c 100644
--- a/Parlance/ClientApp/public/resources/translations/vi/translation.json
+++ b/Parlance/ClientApp/public/resources/translations/vi/translation.json
@@ -38,7 +38,7 @@
"ADD_PROJECT_ERROR": "Không thể thêm dự án",
"ADD_PROJECT_ERROR_PROMPT": "",
"ADD_PROJECT_PROMPT_1": "Điền vào dữ liệu để thêm dự án",
- "ADD_PROJECT_PROMPT_2": "Đảm bảo rằng dự án này có tệp \u003C1\u003E.parlance.json\u003C/1\u003E trong thư mục góc",
+ "ADD_PROJECT_PROMPT_2": "Đảm bảo rằng dự án này có tệp <1>.parlance.json1> trong thư mục góc",
"ADD_TO_GLOSSARY": "Thêm vào bảng chữ giải",
"ADD_TO_GLOSSARY_CONFIRM": "Thêm vào {{glossary}}",
"ADD_TO_GLOSSARY_ERROR_NO_TERM": "",
@@ -82,10 +82,15 @@
"CLOSE": "Đóng",
"COMMENTS": "",
"COMMENT_ADD": "",
+ "COMMENT_GO_TO_STRING": "",
+ "COMMENT_NOT_LOGGED_IN_PROMPT": "",
"COMMENT_OPEN_THREADS_other": "",
+ "COMMENT_ORIGINAL_TRANSLATION": "",
+ "COMMENT_ORIGINAL_TRANSLATION_NO_LONGER_EXISTS": "",
"COMMENT_POST": "",
"COMMENT_POSTING_AS_PROMPT": "",
"COMMENT_SEND_FAILURE_PROMPT": "",
+ "COMMENT_THREAD_PROFILE_PICTURE_ALT_TEXT": "",
"CONFIRM_PASSWORD": "Xác nhận mật khẩu",
"CONFIRM_PASSWORD_PROMPT": "Xác nhận mật khẩu cho tài khoản của bạn",
"CONNECTED_GLOSSARIES": "",
@@ -178,6 +183,10 @@
"OK": "OK",
"OTHER_LANGUAGES": "Ngôn ngữ khác",
"OVERVIEW": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS": "",
+ "OVERVIEW_COMMENTS_NO_OPEN_THREADS_DESCRIPTION": "",
+ "OVERVIEW_GO_TO_COMMENTS": "",
+ "OVERVIEW_STATS": "",
"PARLANCE_ADMINISTRATION": "Quản lý Parlance",
"PARLANCE_ADMINISTRATION_DESCRIPTION": "Cấu hình máy chủ Parlance",
"PARLANCE_ON_GIT": "Parlance trên Git",
diff --git a/Parlance/ClientApp/src/components/Button.js b/Parlance/ClientApp/src/components/Button.js
deleted file mode 100644
index ae24b8c8..00000000
--- a/Parlance/ClientApp/src/components/Button.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import Styles from "./Button.module.css";
-
-export default function (props) {
- return
- {props.children}
-
-}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/components/Button.tsx b/Parlance/ClientApp/src/components/Button.tsx
new file mode 100644
index 00000000..b4f8b81d
--- /dev/null
+++ b/Parlance/ClientApp/src/components/Button.tsx
@@ -0,0 +1,13 @@
+import Styles from "./Button.module.css";
+import {HTMLAttributes, ReactNode} from "react";
+
+interface ButtonProps extends HTMLAttributes {
+ disabled?: boolean
+ children: ReactNode
+}
+
+export default function (props: ButtonProps) {
+ return
+ {props.children}
+
+}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/components/ListPage.js b/Parlance/ClientApp/src/components/ListPage.js
deleted file mode 100644
index 808fbbd9..00000000
--- a/Parlance/ClientApp/src/components/ListPage.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import Styles from "./ListPage.module.css";
-import {Route, Routes, useLocation, useNavigate} from "react-router-dom";
-
-function toUrl(name) {
- return name.toLowerCase().replace(" ", "-")
-}
-
-function ListItem(props) {
- const navigate = useNavigate();
- const location = useLocation();
-
- const switchPage = () => {
- navigate(toUrl(props.name));
- };
-
- let styles = [Styles.listItem, Styles.listItemClickable]
- if (location.pathname.includes(toUrl(props.name))) {
- styles.push(Styles.selected);
- }
-
- return
- {props.name}
-
-}
-
-export default function ListPage({items}) {
- return
-
- {items.map((item, i) => {
- if (typeof (item) === "string") {
- return {item.toUpperCase()}
- } else {
- return
- }
- })}
-
-
-
- {items.filter(item => typeof (item) === "object").map((item, index) => {
- return
- })}
-
-
-
-}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/components/ListPage.module.css b/Parlance/ClientApp/src/components/ListPage.module.css
index 72a83129..4b4dcc34 100644
--- a/Parlance/ClientApp/src/components/ListPage.module.css
+++ b/Parlance/ClientApp/src/components/ListPage.module.css
@@ -7,7 +7,6 @@
.leftPane {
flex-basis: 300px;
- border-right: 1px solid var(--border-color);
flex-grow: 1;
display: flex;
@@ -15,6 +14,14 @@
align-items: flex-end;
}
+:global(.ltr) .leftPane {
+ border-right: 1px solid var(--border-color);
+}
+
+:global(.rtl) .leftPane {
+ border-left: 1px solid var(--border-color);
+}
+
.rightPane {
flex-basis: 600px;
flex-grow: 1;
@@ -35,4 +42,26 @@
.listItemClickable:active, .selected {
background-color: var(--active-color);
+}
+
+.mobileOnly {
+ display: none;
+}
+
+@media (max-width: 600px) {
+ .mobileOnly {
+ display: block;
+ }
+
+ .desktopOnly {
+ display: none;
+ }
+
+ .leftPane {
+ align-items: stretch;
+ }
+
+ .listItem {
+ width: initial;
+ }
}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/components/ListPage.tsx b/Parlance/ClientApp/src/components/ListPage.tsx
new file mode 100644
index 00000000..e1b86021
--- /dev/null
+++ b/Parlance/ClientApp/src/components/ListPage.tsx
@@ -0,0 +1,85 @@
+import Styles from "./ListPage.module.css";
+import {Outlet, Route, Routes, useLocation, useNavigate} from "react-router-dom";
+import {ReactNode} from "react";
+import BackButton from "./BackButton";
+import {useTranslation} from "react-i18next";
+
+interface ListPageItemObject {
+ name: string,
+ slug: string,
+ render: ReactNode
+ default?: boolean
+}
+
+type ListPageItem = ListPageItemObject | string;
+
+function ListItem(props: {
+ name: string
+ slug: string
+ default?: boolean
+}) {
+ const navigate = useNavigate();
+ const location = useLocation();
+
+ const switchPage = () => {
+ navigate(props.slug);
+ };
+
+ let styles = [Styles.listItem, Styles.listItemClickable]
+ if (location.pathname.includes(props.slug)) {
+ styles.push(Styles.selected);
+ }
+
+ return
+ {props.name}
+
+}
+
+function ListPageInner({items, isLeftPane}: {
+ items: ListPageItem[],
+ isLeftPane: boolean
+}) {
+ const navigate = useNavigate();
+ const {t} = useTranslation();
+
+ const goBack = () => {
+ navigate("..")
+ };
+
+ return
+
+ {items.map((item, i) => {
+ if (typeof (item) === "string") {
+ return {item.toUpperCase()}
+ } else {
+ return
+ }
+ })}
+
+
+
+}
+
+export default function ListPage({items}: {
+ items: ListPageItem[]
+}) {
+ return
+ } path={"/"}>
+ {(items.filter(item => typeof (item) === "object") as ListPageItemObject[])
+ .filter(item => item.default)
+ .map(item => )}
+
+ }>
+ {(items.filter(item => typeof (item) === "object") as ListPageItemObject[]).flatMap((item, index) => {
+ const routes = []
+ if (item.default) routes.push()
+ return routes;
+ })}
+
+
+}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/components/Modal.module.css b/Parlance/ClientApp/src/components/Modal.module.css
index 4de7fa4c..4cb061b0 100644
--- a/Parlance/ClientApp/src/components/Modal.module.css
+++ b/Parlance/ClientApp/src/components/Modal.module.css
@@ -26,18 +26,26 @@
border: 1px solid var(--border-color);
flex-basis: 600px;
+ max-height: 100vh;
}
.PopoverContainer {
border-top: none;
border-bottom: none;
- border-right: none;
display: grid;
grid-template-rows: max-content 1fr;
grid-template-areas: "heading" "body";
}
+:global(.ltr) .PopoverContainer {
+ border-right: none;
+}
+
+:global(.rtl) .PopoverContainer {
+ border-left: none;
+}
+
.ModalHeading {
margin: 0;
font-size: 20pt;
@@ -64,9 +72,16 @@
justify-content: center;
padding: 10px;
+}
+
+:global(.ltr) .BackButton {
border-right: 1px solid var(--border-color);
}
+:global(.rtl) .BackButton {
+ border-left: 1px solid var(--border-color);
+}
+
.BackButton:hover {
background-color: var(--hover-color);
}
diff --git a/Parlance/ClientApp/src/components/Modal.tsx b/Parlance/ClientApp/src/components/Modal.tsx
index 0458cc2d..1b3157b3 100644
--- a/Parlance/ClientApp/src/components/Modal.tsx
+++ b/Parlance/ClientApp/src/components/Modal.tsx
@@ -19,7 +19,7 @@ interface ModalExportProps {
buttons?: ModalButton[]
onButtonClick?: () => {}
children?: ReactNode | TFunctionResult
- onBackClicked?: () => {}
+ onBackClicked?: () => void
heading?: string
topComponent?: ReactNode
}
diff --git a/Parlance/ClientApp/src/components/PageHeading.module.css b/Parlance/ClientApp/src/components/PageHeading.module.css
index deed3954..9a1fcfa3 100644
--- a/Parlance/ClientApp/src/components/PageHeading.module.css
+++ b/Parlance/ClientApp/src/components/PageHeading.module.css
@@ -13,4 +13,11 @@
font-weight: bold;
text-transform: uppercase;
margin: 0;
+}
+
+.level4 {
+ font-size: 8pt;
+ font-weight: normal;
+ text-transform: uppercase;
+ margin: 0;
}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/components/PageHeading.tsx b/Parlance/ClientApp/src/components/PageHeading.tsx
index 7c700a7f..e71733bb 100644
--- a/Parlance/ClientApp/src/components/PageHeading.tsx
+++ b/Parlance/ClientApp/src/components/PageHeading.tsx
@@ -2,7 +2,7 @@ import Styles from "./PageHeading.module.css";
import {ReactElement, ReactNode} from "react";
interface PageHeadingProps {
- level?: 1 | 2 | 3;
+ level?: 1 | 2 | 3 | 4;
children: ReactNode;
className?: string;
}
@@ -13,6 +13,8 @@ export default function PageHeading(props: PageHeadingProps): ReactElement {
return {props.children}
case 3:
return {props.children}
+ case 4:
+ return {props.children}
default:
return {props.children}
}
diff --git a/Parlance/ClientApp/src/components/comments/ThreadItem.module.css b/Parlance/ClientApp/src/components/comments/ThreadItem.module.css
new file mode 100644
index 00000000..637b3e41
--- /dev/null
+++ b/Parlance/ClientApp/src/components/comments/ThreadItem.module.css
@@ -0,0 +1,61 @@
+.threadItem {
+ display: grid;
+ grid-template-columns: 1fr max-content;
+ grid-template-rows: max-content max-content max-content;
+ gap: 6px 0px;
+ grid-template-areas:
+ "threadTitle goButton"
+ "lastMessageDate goButton"
+ "lastMessage goButton";
+ align-items: center;
+
+ padding: 9px;
+ cursor: default;
+}
+
+.threadItem:hover {
+ background-color: var(--hover-color);
+}
+
+.threadItem:active {
+ background-color: var(--active-color);
+}
+
+.threadTitle {
+ grid-area: threadTitle;
+}
+
+.closed {
+ color: var(--foreground-disabled-color);
+}
+
+.goButton {
+ grid-area: goButton;
+}
+
+.lastMessage {
+ grid-area: lastMessage;
+}
+
+.lastMessageDate {
+ grid-area: lastMessageDate;
+ font-size: 10pt;
+ opacity: 50%;
+}
+
+.threadCreator {
+ font-size: 10pt;
+
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+}
+
+.noPadding {
+ padding: 0;
+}
+
+.threadCreatorImage {
+ height: 16px;
+ border-radius: 50%;
+}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/components/comments/ThreadItem.tsx b/Parlance/ClientApp/src/components/comments/ThreadItem.tsx
new file mode 100644
index 00000000..2122ff81
--- /dev/null
+++ b/Parlance/ClientApp/src/components/comments/ThreadItem.tsx
@@ -0,0 +1,29 @@
+import {Thread} from "../../interfaces/comments";
+import Styles from "./ThreadItem.module.css";
+import Icon from "../Icon";
+import {useTranslation} from "react-i18next";
+import moment from "moment";
+
+export function ThreadItem({item, onCurrentThreadChanged, noPadding}: {
+ item: Thread,
+ onCurrentThreadChanged: (thread: Thread) => void,
+ noPadding?: boolean
+}) {
+ const {t} = useTranslation();
+
+ return onCurrentThreadChanged(item)}>
+
{item.title}
+
+
+ {moment(item.headComment.date).fromNow(false)}
+
+
+
{item.headComment.text}
+ —
+
+
+ {item.headComment.author.username}
+
+
+
+}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/interfaces/comments.ts b/Parlance/ClientApp/src/interfaces/comments.ts
new file mode 100644
index 00000000..38ba3863
--- /dev/null
+++ b/Parlance/ClientApp/src/interfaces/comments.ts
@@ -0,0 +1,27 @@
+export interface Thread {
+ id: string
+ title: string
+ isClosed: boolean
+ isFlagged: boolean
+ headComment: HeadComment
+ project: string
+ subproject: string
+ language: string
+ key: string
+ sourceTranslation?: string
+}
+
+interface HeadComment {
+ text: string
+ date: number
+ author: Author
+}
+
+export interface Comment extends HeadComment {
+ event: string | null
+}
+
+interface Author {
+ username: string
+ picture: string
+}
diff --git a/Parlance/ClientApp/src/interfaces/projects.ts b/Parlance/ClientApp/src/interfaces/projects.ts
new file mode 100644
index 00000000..d77c05ce
--- /dev/null
+++ b/Parlance/ClientApp/src/interfaces/projects.ts
@@ -0,0 +1,20 @@
+import {Thread} from "./comments";
+
+export interface SubprojectLocaleMeta {
+ completionData: CompletionData
+ projectName: string,
+ subprojectName: string,
+ language: string,
+ canEdit: boolean,
+ openThreads: Thread[]
+}
+
+export interface CompletionData {
+ count: number,
+ complete: number,
+ warnings: number,
+ errors: number,
+ cumulativeWarnings: number,
+ passedChecks: number,
+ needsAttention: number
+}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/pages/Administration/index.js b/Parlance/ClientApp/src/pages/Administration/index.js
index 59cca03a..b6548035 100644
--- a/Parlance/ClientApp/src/pages/Administration/index.js
+++ b/Parlance/ClientApp/src/pages/Administration/index.js
@@ -16,24 +16,29 @@ export default function(props) {
t("PROJECTS"),
{
name: t("PROJECTS"),
+ slug: "projects",
render:
},
{
name: t("GLOSSARIES"),
+ slug: "glossaries",
render:
},
t("SSH"),
{
name: t("SSH_KEYS"),
+ slug: "ssh-keys",
render:
},
t("USERS_AND_PERMISSIONS"),
{
name: t("SUPERUSERS"),
+ slug: "superusers",
render:
},
{
name: t("LOCALES"),
+ slug: "locales",
render:
}
];
diff --git a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/CommentsDashboard.tsx b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/CommentsDashboard.tsx
new file mode 100644
index 00000000..35c360f3
--- /dev/null
+++ b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/CommentsDashboard.tsx
@@ -0,0 +1,52 @@
+import ListPageBlock from "../../../../../components/ListPageBlock";
+import {VerticalLayout} from "../../../../../components/Layouts";
+import PageHeading from "../../../../../components/PageHeading";
+import {useTranslation} from "react-i18next";
+import SelectableList from "../../../../../components/SelectableList";
+import {useEffect, useState} from "react";
+import {Thread} from "../../../../../interfaces/comments";
+import {useParams} from "react-router-dom";
+import Fetch from "../../../../../helpers/Fetch";
+import {ThreadItem} from "../../../../../components/comments/ThreadItem";
+import PreloadingBlock from "../../../../../components/PreloadingBlock";
+import SilentInformation from "../../../../../components/SilentInformation";
+import Modal from "../../../../../components/Modal";
+import {CommentsThreadModal} from "./TranslationEditor/Comments/CommentsModal";
+
+export function CommentsDashboard() {
+ const {project, subproject, language} = useParams();
+ const {t} = useTranslation();
+ const [comments, setComments] = useState();
+
+ const updateComments = async () => {
+ setComments(null);
+ setComments(await Fetch.get(`/api/comments/${project}/${subproject}/${language}`));
+ }
+
+ useEffect(() => {
+ void updateComments();
+ }, []);
+
+ const openThread = (thread: Thread) => {
+ Modal.mount()
+ }
+
+ return
+
+
+ {t("COMMENTS")}
+ {comments?.length === 0 ?
+
+
+
: <>
+ {comments ? {t("COMMENT_OPEN_THREADS", {count: comments.length})}
: {t("COMMENT_OPEN_THREADS", {count: 0})}}
+ ({
+ contents: {}} />,
+ onClick: () => openThread(thread)
+ })) : SelectableList.PreloadingText(3)}/>
+ >
+ }
+
+
+
+}
diff --git a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/Dashboard.js b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/Dashboard.tsx
similarity index 69%
rename from Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/Dashboard.js
rename to Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/Dashboard.tsx
index a993ba4b..aab38476 100644
--- a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/Dashboard.js
+++ b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/Dashboard.tsx
@@ -9,10 +9,12 @@ import Hero from "../../../../../components/Hero";
import BackButton from "../../../../../components/BackButton";
import Spinner from "../../../../../components/Spinner";
import GlossariesDashboard from "./GlossariesDashboard";
+import {SubprojectLocaleMeta} from "../../../../../interfaces/projects";
+import {CommentsDashboard} from "./CommentsDashboard";
-export default function Dashboard(props) {
+export default function Dashboard() {
const {project, subproject, language} = useParams();
- const [data, setData] = useState();
+ const [data, setData] = useState();
const navigate = useNavigate();
const {t} = useTranslation();
@@ -31,17 +33,25 @@ export default function Dashboard(props) {
t("DASHBOARD"),
{
name: t("OVERVIEW"),
- render:
+ slug: "overview",
+ render: ,
+ default: true
},
{
name: t("GLOSSARIES"),
- render:
+ slug: "glossaries",
+ render:
+ },
+ {
+ name: t("COMMENTS"),
+ slug: "comments",
+ render:
}
];
return
navigate("../..")}/>
- navigate("translate")
@@ -49,4 +59,4 @@ export default function Dashboard(props) {
]}/>
-}
\ No newline at end of file
+}
diff --git a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/Overview.js b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/Overview.js
deleted file mode 100644
index c654a096..00000000
--- a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/Overview.js
+++ /dev/null
@@ -1,5 +0,0 @@
-export default function Overview({data}) {
- return
-
-
-}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/Overview.module.css b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/Overview.module.css
new file mode 100644
index 00000000..e69de29b
diff --git a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/Overview.tsx b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/Overview.tsx
new file mode 100644
index 00000000..6bbc4778
--- /dev/null
+++ b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/Overview.tsx
@@ -0,0 +1,38 @@
+import {SubprojectLocaleMeta} from "../../../../../interfaces/projects";
+import {VerticalLayout} from "../../../../../components/Layouts";
+import ListPageBlock from "../../../../../components/ListPageBlock";
+import PageHeading from "../../../../../components/PageHeading";
+import {useTranslation} from "react-i18next";
+import SelectableList from "../../../../../components/SelectableList";
+import {useNavigate} from "react-router-dom";
+
+export default function Overview({data}: {
+ data: SubprojectLocaleMeta
+}) {
+ const {t} = useTranslation();
+ const navigate = useNavigate();
+
+ const goToComments = () => {
+ navigate("../comments");
+ }
+
+ return
+
+
+ {t("OVERVIEW_STATS")}
+
+ {data.completionData.complete}/{data.completionData.count} strings translated
+
+ {data.completionData.warnings} warnings
+ {data.completionData.errors} errors
+
+
+
+
+ {t("COMMENTS")}
+ {t("COMMENT_OPEN_THREADS", { count: data.openThreads.length })}
+ {t("OVERVIEW_GO_TO_COMMENTS")}
+
+
+
+}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/CommentsModal.js b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/CommentsModal.js
deleted file mode 100644
index 2cdab6ac..00000000
--- a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/CommentsModal.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import {useTranslation} from "react-i18next";
-import Modal from "../../../../../../../components/Modal";
-import {useState} from "react";
-import {VerticalLayout} from "../../../../../../../components/Layouts";
-import PageHeading from "../../../../../../../components/PageHeading";
-
-import Styles from "./CommentsModal.module.css";
-import Icon from "../../../../../../../components/Icon";
-import ThreadView from "./ThreadView";
-import ThreadReplyArea from "./ThreadReplyArea";
-
-function ThreadItem({item, onCurrentThreadChanged}) {
- return onCurrentThreadChanged(item)}>
-
{item.title}
-
- {item.headCommentBody}
- {item.author.username}
-
-}
-
-export default function CommentsModal({project, subproject, language, tkey, threads, onUpdateThreads}) {
- const [currentThread, setCurrentThread] = useState();
- const {t} = useTranslation();
-
- const goBack = () => {
- if (currentThread) {
- setCurrentThread(null);
- } else {
- Modal.unmount();
- }
- };
-
- return
- {currentThread ? :
- <>
-
-
- {threads.map((x, i) => ) || t("THREADS_NO_THREADS")}
-
-
-
-
{t("THREADS_NEW_THREAD")}
-
-
-
- >}
-
-}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/CommentsModal.module.css b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/CommentsModal.module.css
index 0c7aa5ca..3c84799c 100644
--- a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/CommentsModal.module.css
+++ b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/CommentsModal.module.css
@@ -6,41 +6,6 @@
border-bottom: 1px solid var(--border-color);
}
-.threadItem {
- display: grid;
- grid-template-columns: 1fr max-content;
- grid-template-rows: 1fr 1fr 1fr;
- gap: 0px 0px;
- grid-template-areas:
- "threadTitle goButton"
- "lastMessage goButton"
- "threadCreator goButton";
- align-items: center;
-
- padding: 9px;
- cursor: default;
-}
-
-.threadItem:hover {
- background-color: var(--hover-color);
-}
-
-.threadItem:active {
- background-color: var(--active-color);
-}
-
-.threadTitle {
- grid-area: threadTitle;
-}
-
-.lastMessage {
- grid-area: lastMessage;
-}
-
-.threadCreator {
- grid-area: threadCreator;
-}
-
-.goButton {
- grid-area: goButton;
+.noThreads {
+ padding: 6px;
}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/CommentsModal.tsx b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/CommentsModal.tsx
new file mode 100644
index 00000000..8010e1ee
--- /dev/null
+++ b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/CommentsModal.tsx
@@ -0,0 +1,69 @@
+import {useTranslation} from "react-i18next";
+import Modal from "../../../../../../../components/Modal";
+import {useState} from "react";
+import {VerticalLayout} from "../../../../../../../components/Layouts";
+import PageHeading from "../../../../../../../components/PageHeading";
+
+import Styles from "./CommentsModal.module.css";
+import Icon from "../../../../../../../components/Icon";
+import ThreadView from "./ThreadView";
+import ThreadReplyArea from "./ThreadReplyArea";
+import {Thread} from "../../../../../../../interfaces/comments";
+import {ThreadItem} from "../../../../../../../components/comments/ThreadItem";
+import UserManager from "../../../../../../../helpers/UserManager";
+
+
+export function CommentsModal({project, subproject, language, tkey, threads, onUpdateThreads}: {
+ project: string,
+ subproject: string,
+ language: string,
+ tkey: string,
+ threads: Thread[],
+ onUpdateThreads: () => void,
+}) {
+ const [currentThread, setCurrentThread] = useState();
+ const {t} = useTranslation();
+
+ const goBack = () => {
+ if (currentThread) {
+ setCurrentThread(null);
+ } else {
+ Modal.unmount();
+ }
+ };
+
+ return
+ {currentThread ? :
+ <>
+
+
+ {threads.length ? threads.map((x, i) => ) :
+ {t("THREADS_NO_THREADS")}
+
}
+
+ {UserManager.currentUser && <>
+
+
+
{t("THREADS_NEW_THREAD")}
+
+
+
+ >}
+ >}
+
+}
+
+export function CommentsThreadModal({thread, onUpdateThreads, showHeader}: {
+ thread: Thread
+ onUpdateThreads: () => void,
+ showHeader?: boolean
+}) {
+ return Modal.unmount()}>
+ {}} onReloadThreads={onUpdateThreads} showHeader={showHeader} />
+
+}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/ThreadReplyArea.module.css b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/ThreadReplyArea.module.css
index 65b15e92..eaa35d8d 100644
--- a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/ThreadReplyArea.module.css
+++ b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/ThreadReplyArea.module.css
@@ -41,13 +41,21 @@ input.titleBox {
flex-direction: row;
}
-.buttonContainerInner div {
+:global(.ltr) .buttonContainerInner div {
border-left: 1px solid var(--border-color);
}
+:global(.rtl) .buttonContainerInner div {
+ border-right: 1px solid var(--border-color);
+}
+
.postingPrompt {
display: flex;
align-items: center;
padding: 9px;
gap: 6px;
+}
+
+.loggedOutMessage {
+ padding: 9px;
}
\ No newline at end of file
diff --git a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/ThreadReplyArea.js b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/ThreadReplyArea.tsx
similarity index 54%
rename from Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/ThreadReplyArea.js
rename to Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/ThreadReplyArea.tsx
index 783f381a..aa1b9efd 100644
--- a/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/ThreadReplyArea.js
+++ b/Parlance/ClientApp/src/pages/Projects/Subprojects/Languages/Translation/TranslationEditor/Comments/ThreadReplyArea.tsx
@@ -5,6 +5,12 @@ import Button from "../../../../../../../components/Button";
import UserManager from "../../../../../../../helpers/UserManager";
import Fetch from "../../../../../../../helpers/Fetch";
import {useState} from "react";
+import {Comment, Thread} from "../../../../../../../interfaces/comments";
+
+interface CloseResponse {
+ comments: Comment[],
+ thread: Thread
+}
export default function ThreadReplyArea({
project,
@@ -14,7 +20,16 @@ export default function ThreadReplyArea({
thread,
onReloadThreads,
onCurrentThreadChanged, onThreadDataChanged
- }) {
+ }: {
+ project?: string,
+ subproject?: string,
+ language?: string,
+ tkey?: string,
+ thread?: Thread,
+ onReloadThreads: () => void,
+ onCurrentThreadChanged: (thread: Thread | null) => void,
+ onThreadDataChanged?: (threadData: Comment[]) => void
+}) {
const [title, setTitle] = useState("");
const [body, setBody] = useState("");
const [error, setError] = useState("");
@@ -26,7 +41,7 @@ export default function ThreadReplyArea({
setError("");
if (threadId) {
try {
- onThreadDataChanged(await Fetch.post(`/api/comments/${thread.id}`, {
+ onThreadDataChanged!(await Fetch.post(`/api/comments/${thread.id}`, {
body: body
}));
} catch {
@@ -34,7 +49,7 @@ export default function ThreadReplyArea({
return;
}
} else {
- let thread;
+ let thread: Thread | null;
try {
thread = await Fetch.post(`/api/comments/${project}/${subproject}/${language}/${tkey}`, {
title: title,
@@ -53,46 +68,53 @@ export default function ThreadReplyArea({
};
const toggleClosed = async () => {
+ if (!thread) return;
+
let comments, newThread;
if (thread.isClosed) {
try {
- ({comments, thread: newThread} = await Fetch.delete(`/api/comments/${thread.id}/close`));
+ ({comments, thread: newThread} = await Fetch.delete(`/api/comments/${thread.id}/close`));
} catch {
setError(t("THREAD_REOPEN_FAILURE_PROMPT"))
return;
}
} else {
try {
- ({comments, thread: newThread} = await Fetch.post(`/api/comments/${thread.id}/close`));
+ ({comments, thread: newThread} = await Fetch.post(`/api/comments/${thread.id}/close`, null));
} catch {
setError(t("THREAD_CLOSE_FAILURE_PROMPT"))
return;
}
}
- onThreadDataChanged(comments);
+ onThreadDataChanged!(comments);
onReloadThreads();
onCurrentThreadChanged(newThread);
}
return