diff --git a/packages/moderation/src/locales/ar-SA/index.json b/packages/moderation/src/locales/ar-SA/index.json
index 528f7704e7..6c099f406f 100644
--- a/packages/moderation/src/locales/ar-SA/index.json
+++ b/packages/moderation/src/locales/ar-SA/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "تحقق من إفصاحات المحتوى"
},
- "nags.description-too-short.description": {
- "defaultMessage": "وصفك هو {length, plural, one {# readable character} other {# readable characters}}. يُوصى بأن يكون على الأقل {minChars, plural, one {# character}other{#characters}} لإنشاء وصف واضح وغني بالمعلومات."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "قم بتوسيع الوصف"
- },
"nags.edit-description.title": {
"defaultMessage": "تعديل الوصف"
},
diff --git a/packages/moderation/src/locales/cs-CZ/index.json b/packages/moderation/src/locales/cs-CZ/index.json
index 802f26b754..0d11fe3dca 100644
--- a/packages/moderation/src/locales/cs-CZ/index.json
+++ b/packages/moderation/src/locales/cs-CZ/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "Zkontrolovat zveřejnění obsahu"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Váš popis má {length, plural, one {# čitelný znak} few {# čitelné znaky} other {# čitelných znaků}}. Pro vytvoření jasného a informativního popisu doporučujeme alespoň {minChars, plural, one {# znak} few {# znaky} other {# znaků}}."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Rozšiřte popis"
- },
"nags.edit-description.title": {
"defaultMessage": "Upravte popis"
},
diff --git a/packages/moderation/src/locales/da-DK/index.json b/packages/moderation/src/locales/da-DK/index.json
index 32b76cce2b..25f4c3e81a 100644
--- a/packages/moderation/src/locales/da-DK/index.json
+++ b/packages/moderation/src/locales/da-DK/index.json
@@ -35,12 +35,6 @@
"nags.all-tags-selected.title": {
"defaultMessage": "Vælg præcise tags"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Din beskrivelse er {length, plural, one {# læsligt bogstav} other {# læslige bogstaver}}. Som minimum er {minChars, plural, one {# bogstav} other {# bogstaver}} anbefalet for at lave en klar og informativ beskrivelse."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Forlæng beskrivelsen"
- },
"nags.edit-description.title": {
"defaultMessage": "Rediger beskrivelsen"
},
diff --git a/packages/moderation/src/locales/de-CH/index.json b/packages/moderation/src/locales/de-CH/index.json
index bf959d56db..7f48903a0b 100644
--- a/packages/moderation/src/locales/de-CH/index.json
+++ b/packages/moderation/src/locales/de-CH/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "Angaben zum Inhalt prüfen"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Deine Beschreibung ist {length, plural, one {# lesbares Zeichen} other {# lesbare Zeichen}} lang. Mindestens {minChars, plural, one {1 Zeichen ist} other {# Zeichen sind}} empfohlen, um eine klare und informative Beschreibung zu erstellen."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Beschreibung erweitern"
- },
"nags.edit-description.title": {
"defaultMessage": "Beschreibung bearbeiten"
},
diff --git a/packages/moderation/src/locales/de-DE/index.json b/packages/moderation/src/locales/de-DE/index.json
index fb251a8452..aa67132a4b 100644
--- a/packages/moderation/src/locales/de-DE/index.json
+++ b/packages/moderation/src/locales/de-DE/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "Angaben zum Inhalt prüfen"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Deine Beschreibung enthält {length, plural, one {# lesbares Zeichen} other {# lesbare Zeichen}}. Es wird empfohlen, mindestens {minChars, plural, one {# Zeichen} other {# Zeichen}} zu verwenden, um eine klare und informative Beschreibung zu erstellen."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Beschreibung erweitern"
- },
"nags.edit-description.title": {
"defaultMessage": "Beschreibung bearbeiten"
},
diff --git a/packages/moderation/src/locales/en-US/index.json b/packages/moderation/src/locales/en-US/index.json
index e6e054a804..50812e7341 100644
--- a/packages/moderation/src/locales/en-US/index.json
+++ b/packages/moderation/src/locales/en-US/index.json
@@ -60,7 +60,7 @@
"defaultMessage": "Check content disclosures"
},
"nags.description-too-short.description": {
- "defaultMessage": "Your description is {length, plural, one {# readable character} other {# readable characters}}. At least {minChars, plural, one {# character} other {# characters}} is recommended to create a clear and informative description."
+ "defaultMessage": "Your description is too brief. Add more to clearly describe the project's purpose and function."
},
"nags.description-too-short.title": {
"defaultMessage": "Expand the description"
@@ -245,6 +245,12 @@
"nags.project-description-slur.description": {
"defaultMessage": "Your project cannot contain any slurs. Detected: “{value}”."
},
+ "nags.project-description-spam.description": {
+ "defaultMessage": "Repeated characters, words, or phrases cannot be used to pad a project description."
+ },
+ "nags.project-description-spam.title": {
+ "defaultMessage": "Remove spam from the description"
+ },
"nags.project-name-non-standard-text.description": {
"defaultMessage": "Non-standard text characters, such as “₮ɆӾ₮”, are not allowed."
},
@@ -269,6 +275,12 @@
"nags.project-summary-slur.description": {
"defaultMessage": "Your project summary cannot contain any slurs. Detected: “{value}”."
},
+ "nags.project-summary-spam.description": {
+ "defaultMessage": "Repeated characters, words, or phrases cannot be used to pad a project summary."
+ },
+ "nags.project-summary-spam.title": {
+ "defaultMessage": "Remove spam from the summary"
+ },
"nags.review-permissions.description": {
"defaultMessage": "Make sure you have provided proof of your permission to distribute any external content in your Modpack."
},
@@ -390,7 +402,7 @@
"defaultMessage": "A project summary cannot be the same as it's title."
},
"project.text-validation.summary-too-short": {
- "defaultMessage": "Your summary is {length, plural, one {# character} other {# characters}}. At least {minChars, plural, one {# character} other {# characters}} is recommended to create an informative and enticing summary."
+ "defaultMessage": "Your summary is too short. Add a sentence or two which describes your project."
},
"project.text-validation.title-version-number": {
"defaultMessage": "Names are not allowed to include version numbers."
diff --git a/packages/moderation/src/locales/es-419/index.json b/packages/moderation/src/locales/es-419/index.json
index 8e29d695c8..587ccd7169 100644
--- a/packages/moderation/src/locales/es-419/index.json
+++ b/packages/moderation/src/locales/es-419/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "Comprobar el contenido de divulgación"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Tu descripción tiene {length, plural, one {# carácter legible} other {# caracteres legibles}}. Se recomienda al menos {minChars, plural, one {# carácter} other {# caracteres}} para crear una descripción clara e informativa."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Expandir la descripción"
- },
"nags.edit-description.title": {
"defaultMessage": "Editar descripción"
},
diff --git a/packages/moderation/src/locales/es-ES/index.json b/packages/moderation/src/locales/es-ES/index.json
index 0f6e64ddfa..e6444804d0 100644
--- a/packages/moderation/src/locales/es-ES/index.json
+++ b/packages/moderation/src/locales/es-ES/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "Comprobar divulgaciones de contenido"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Tu descripción tiene {length, plural, one {# carácter legible} other {# caracteres legibles}}. Se recomienda un mínimo de {minChars, plural, one {# carácter} other {# caracteres}} para crear una descripción clara e informativa."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Amplíe la descripción"
- },
"nags.edit-description.title": {
"defaultMessage": "Editar descripción"
},
diff --git a/packages/moderation/src/locales/fi-FI/index.json b/packages/moderation/src/locales/fi-FI/index.json
index a98f6b0f5f..c4ec9ab672 100644
--- a/packages/moderation/src/locales/fi-FI/index.json
+++ b/packages/moderation/src/locales/fi-FI/index.json
@@ -32,9 +32,6 @@
"nags.all-tags-selected.title": {
"defaultMessage": "Valitse sopivat tagit"
},
- "nags.description-too-short.title": {
- "defaultMessage": "Laajenna kuvausta"
- },
"nags.edit-description.title": {
"defaultMessage": "Muokkaa kuvausta"
},
diff --git a/packages/moderation/src/locales/fil-PH/index.json b/packages/moderation/src/locales/fil-PH/index.json
index 0da4fee097..27de44b87f 100644
--- a/packages/moderation/src/locales/fil-PH/index.json
+++ b/packages/moderation/src/locales/fil-PH/index.json
@@ -35,12 +35,6 @@
"nags.all-tags-selected.title": {
"defaultMessage": "Pumili ng mga pinaktumpak na tag"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Ang iyong paglalarawan ay may {length, plural, one {# mababasang titik} other {# na mababasang titik}}. Hindi kumulang sa {minChars, plural, one {# titik} other {# na titik}} ang inimumungkahi sa paglikha ng maliwanag at makabuluhang paglalarawan."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Palawakin ang paglalarawan"
- },
"nags.edit-description.title": {
"defaultMessage": "Baguhin ang paglalarawan"
},
diff --git a/packages/moderation/src/locales/fr-FR/index.json b/packages/moderation/src/locales/fr-FR/index.json
index d8cbb6e425..42a59fa96d 100644
--- a/packages/moderation/src/locales/fr-FR/index.json
+++ b/packages/moderation/src/locales/fr-FR/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "Regarder les avertissements sur le contenu"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Votre description contient {length, plural, one {# caractère lisible} other {# caractères lisibles}}. Il est recommandé d’en avoir au moins {minChars, plural, one {# caractère} other {# caractères}} pour obtenir une description claire et informative."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Étendre la description"
- },
"nags.edit-description.title": {
"defaultMessage": "Modifier la description"
},
diff --git a/packages/moderation/src/locales/he-IL/index.json b/packages/moderation/src/locales/he-IL/index.json
index da16c8c590..ff013cdd45 100644
--- a/packages/moderation/src/locales/he-IL/index.json
+++ b/packages/moderation/src/locales/he-IL/index.json
@@ -47,12 +47,6 @@
"nags.all-tags-selected.title": {
"defaultMessage": "בחר תגיות מדויקות"
},
- "nags.description-too-short.description": {
- "defaultMessage": "התיאור שלך הוא {length, plural, one {# דמות} other {# דמויות}}. מומלץ להשתמש לפחות ב-{minChars, plural, one {# דמות} other {# דמויות}} כדי ליצור תיאור ברור ואינפורמטיבי."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "הרחב את התיאור"
- },
"nags.edit-description.title": {
"defaultMessage": "ערוך תיאור"
},
diff --git a/packages/moderation/src/locales/hu-HU/index.json b/packages/moderation/src/locales/hu-HU/index.json
index a871e3581b..4c83f7832c 100644
--- a/packages/moderation/src/locales/hu-HU/index.json
+++ b/packages/moderation/src/locales/hu-HU/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "Ellenőrizd a tartalomnyilatkozatokat"
},
- "nags.description-too-short.description": {
- "defaultMessage": "A jelenlegi leírás {length} olvasható karakter hosszú. Egy világos és informatív leíráshoz legalább {minChars} karakter ajánlott."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Fejtsd ki a leírást"
- },
"nags.edit-description.title": {
"defaultMessage": "Leírás szerkesztése"
},
diff --git a/packages/moderation/src/locales/id-ID/index.json b/packages/moderation/src/locales/id-ID/index.json
index cf647cad08..75ab20af5a 100644
--- a/packages/moderation/src/locales/id-ID/index.json
+++ b/packages/moderation/src/locales/id-ID/index.json
@@ -47,12 +47,6 @@
"nags.all-tags-selected.title": {
"defaultMessage": "Pilih tag yang tepat"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Panjang keterangan Anda adalah {length, plural, other {# karakter yang dapat dibaca}}. Setidaknya {minChars, plural, other {# karakter}} disarankan untuk membuat keterangan yang jelas dan informatif."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Kembangkan keterangan"
- },
"nags.edit-description.title": {
"defaultMessage": "Sunting keterangan"
},
diff --git a/packages/moderation/src/locales/it-IT/index.json b/packages/moderation/src/locales/it-IT/index.json
index 277e097136..fea0ea2746 100644
--- a/packages/moderation/src/locales/it-IT/index.json
+++ b/packages/moderation/src/locales/it-IT/index.json
@@ -50,12 +50,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "Controlla le informative"
},
- "nags.description-too-short.description": {
- "defaultMessage": "La descrizione è di {length, plural, one {# carattere} other {# caratteri}}. Usane almeno {minChars} per tenerla chiara e informativa."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Espandi la descrizione"
- },
"nags.edit-description.title": {
"defaultMessage": "Modifica la descrizione"
},
diff --git a/packages/moderation/src/locales/ja-JP/index.json b/packages/moderation/src/locales/ja-JP/index.json
index a6dc110c39..87abf4168b 100644
--- a/packages/moderation/src/locales/ja-JP/index.json
+++ b/packages/moderation/src/locales/ja-JP/index.json
@@ -50,12 +50,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "コンテンツの開示を確認"
},
- "nags.description-too-short.description": {
- "defaultMessage": "説明文が{length, plural, other {#文字}}しかありません。より明確で分かりやすい説明文を作成するためには、少なくとも{minChars, plural, other {#文字}}以上であることが推奨されます。"
- },
- "nags.description-too-short.title": {
- "defaultMessage": "説明を展開する"
- },
"nags.edit-description.title": {
"defaultMessage": "説明を編集する"
},
diff --git a/packages/moderation/src/locales/ko-KR/index.json b/packages/moderation/src/locales/ko-KR/index.json
index df56e50dab..a9a98170ea 100644
--- a/packages/moderation/src/locales/ko-KR/index.json
+++ b/packages/moderation/src/locales/ko-KR/index.json
@@ -47,12 +47,6 @@
"nags.all-tags-selected.title": {
"defaultMessage": "올바른 태그를 선택해 주세요"
},
- "nags.description-too-short.description": {
- "defaultMessage": "작성한 설명이 {length, plural, one {#자} other {#자}}입니다. 명확하고 유익한 설명을 작성하려면 최소 {minChars, plural, one {#자} other {#자}}가 권장됩니다."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "설명을 덧붙여주세요"
- },
"nags.edit-description.title": {
"defaultMessage": "설명 수정하기"
},
diff --git a/packages/moderation/src/locales/ms-MY/index.json b/packages/moderation/src/locales/ms-MY/index.json
index cc4d5f1afe..0d38c824c7 100644
--- a/packages/moderation/src/locales/ms-MY/index.json
+++ b/packages/moderation/src/locales/ms-MY/index.json
@@ -35,12 +35,6 @@
"nags.all-tags-selected.title": {
"defaultMessage": "Pilih tag yang tepat"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Panjang keterangan anda ialah {length, plural, other {# aksara yang boleh dibaca}}. Sekurang-kurangnya {minChars, plural, other {# aksara}} disyorkan untuk membuat keterangan yang jelas dan bermaklumat."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Kembangkan keterangan"
- },
"nags.edit-description.title": {
"defaultMessage": "Sunting keterangan"
},
diff --git a/packages/moderation/src/locales/nl-NL/index.json b/packages/moderation/src/locales/nl-NL/index.json
index 6ff0e471a2..985e30c548 100644
--- a/packages/moderation/src/locales/nl-NL/index.json
+++ b/packages/moderation/src/locales/nl-NL/index.json
@@ -47,12 +47,6 @@
"nags.all-tags-selected.title": {
"defaultMessage": "Selecteer relevante tags"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Je beschrijving is {length, plural, one{# leesbare tekens}other {# leesbare tekens}}. Ten minste {minChars, plural, one {# teken}other {# tekens}} is aangeraden om een duidelijke en informatieve beschrijving te maken."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Verleng de beschrijving"
- },
"nags.edit-description.title": {
"defaultMessage": "Pas de beschrijving aan"
},
diff --git a/packages/moderation/src/locales/no-NO/index.json b/packages/moderation/src/locales/no-NO/index.json
index bbd485e843..31480ad171 100644
--- a/packages/moderation/src/locales/no-NO/index.json
+++ b/packages/moderation/src/locales/no-NO/index.json
@@ -41,12 +41,6 @@
"nags.all-tags-selected.title": {
"defaultMessage": "Velg aktuelle tagger"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Din beskrivelse inneholder {length, plural, one {# leselig tegn} other {# leselige tegn}}. Minst {minChars, plural, one {# tegn} other {# tegn}} er anbefalt for å lage en klar og informativ beskrivelse."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Utvid beskrivelsen"
- },
"nags.edit-description.title": {
"defaultMessage": "Rediger beskrivelse"
},
diff --git a/packages/moderation/src/locales/pl-PL/index.json b/packages/moderation/src/locales/pl-PL/index.json
index ca638c2dc4..77567f7507 100644
--- a/packages/moderation/src/locales/pl-PL/index.json
+++ b/packages/moderation/src/locales/pl-PL/index.json
@@ -47,12 +47,6 @@
"nags.all-tags-selected.title": {
"defaultMessage": "Wybierz odpowiednie tagi"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Twój opis składa się z {length, plural, one {# czytenego znaku} other {# czytelnych znaków}}. Zalecane jest użycie chociaż {minChars, plural, one {# znaku} other {# znaków}} by stworzyć przejrzysty i informatywny opis."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Rozwiń opis"
- },
"nags.edit-description.title": {
"defaultMessage": "Edytuj opis"
},
diff --git a/packages/moderation/src/locales/pt-BR/index.json b/packages/moderation/src/locales/pt-BR/index.json
index 3b9613a803..0a2cf05b12 100644
--- a/packages/moderation/src/locales/pt-BR/index.json
+++ b/packages/moderation/src/locales/pt-BR/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "Verificar divulgações de conteúdo"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Sua descrição possui {length, plural, one {apenas # caractere legível} other {apenas # caracteres legíveis}}. No mínimo, {minChars, plural, one {# caractere é recomendado} other {# characteres são recomendados}} para criar uma descrição concisa e informativa."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Expandir a descrição"
- },
"nags.edit-description.title": {
"defaultMessage": "Edite a descrição"
},
diff --git a/packages/moderation/src/locales/pt-PT/index.json b/packages/moderation/src/locales/pt-PT/index.json
index dd6f805ac8..b5272f7e8d 100644
--- a/packages/moderation/src/locales/pt-PT/index.json
+++ b/packages/moderation/src/locales/pt-PT/index.json
@@ -41,12 +41,6 @@
"nags.all-tags-selected.title": {
"defaultMessage": "Seleciona etiquetas adequadas"
},
- "nags.description-too-short.description": {
- "defaultMessage": "A tua descrição tem {length, plural, one {# caractere legível} other {# caracteres legíveis}}. Pelo menos {minChars, plural, one {# caractere} other {# caracteres}} são recomendados para criar uma descrição clara e informativa."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Expande a descrição"
- },
"nags.edit-description.title": {
"defaultMessage": "Edita a descrição"
},
diff --git a/packages/moderation/src/locales/ro-RO/index.json b/packages/moderation/src/locales/ro-RO/index.json
index 5ca9cb0b8b..7f2b0b6826 100644
--- a/packages/moderation/src/locales/ro-RO/index.json
+++ b/packages/moderation/src/locales/ro-RO/index.json
@@ -35,12 +35,6 @@
"nags.all-tags-selected.title": {
"defaultMessage": "Selectează etichete precise"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Descrierea dumneavoastră este {length, plural, one {# caracter lizibil} other {# caractere lizibile}}. Măcar {minChars, plural, one {# caracter este} other {# caractere sunt}} recomandate pentru a creea o descriere clară și informativă."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Extinde descrierea"
- },
"nags.edit-description.title": {
"defaultMessage": "Editează descrierea"
},
diff --git a/packages/moderation/src/locales/ru-RU/index.json b/packages/moderation/src/locales/ru-RU/index.json
index b8417214c7..4929d3aac8 100644
--- a/packages/moderation/src/locales/ru-RU/index.json
+++ b/packages/moderation/src/locales/ru-RU/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "Проверьте маркировку"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Описание содержит {length, plural, one {# читаемый символ} few {# читаемых символа} other {# читаемых символов}}. Для ясного и информативного описания рекомендуется не менее {minChars, plural, one {# символа} other {# символов}}."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Расширьте описание"
- },
"nags.edit-description.title": {
"defaultMessage": "Изменить описание"
},
diff --git a/packages/moderation/src/locales/sr-CS/index.json b/packages/moderation/src/locales/sr-CS/index.json
index 00dec21ad5..c031c927f8 100644
--- a/packages/moderation/src/locales/sr-CS/index.json
+++ b/packages/moderation/src/locales/sr-CS/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "Proverite obaveštenja o sadržaju"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Tvoj opis je {length, plural, one {# čitljiv karakter} few {# čitljiva karaktera} other {# čitljivih karaktera}}. Barem {minChars, plural, one {# karakter} other {# karaktera}} je preporučeno kreiranje jasnog i informativnog opisa."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Proširi opis"
- },
"nags.edit-description.title": {
"defaultMessage": "Promeni opis"
},
diff --git a/packages/moderation/src/locales/sv-SE/index.json b/packages/moderation/src/locales/sv-SE/index.json
index b39031e3d2..060b57c634 100644
--- a/packages/moderation/src/locales/sv-SE/index.json
+++ b/packages/moderation/src/locales/sv-SE/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "Läs innehållsinformation"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Din beskrivning är {length, plural, one {# tecken} other {# tecken}} lång. Minst {minChars, plural, one {# tecken} other {# tecken}} rekommenderas för en klar och informativ beskrivning."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Utöka beskrivningen"
- },
"nags.edit-description.title": {
"defaultMessage": "Redigera beskrivning"
},
diff --git a/packages/moderation/src/locales/th-TH/index.json b/packages/moderation/src/locales/th-TH/index.json
index 4a766df5ce..63848cf8c7 100644
--- a/packages/moderation/src/locales/th-TH/index.json
+++ b/packages/moderation/src/locales/th-TH/index.json
@@ -14,9 +14,6 @@
"nags.add-links.title": {
"defaultMessage": "เพิ่มลิงก์ภายนอก"
},
- "nags.description-too-short.title": {
- "defaultMessage": "เพิ่มคำอธิบาย"
- },
"nags.edit-description.title": {
"defaultMessage": "แก้ไขคำอธิบาย"
},
diff --git a/packages/moderation/src/locales/tr-TR/index.json b/packages/moderation/src/locales/tr-TR/index.json
index 90f9442231..a88b4ee263 100644
--- a/packages/moderation/src/locales/tr-TR/index.json
+++ b/packages/moderation/src/locales/tr-TR/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "İçerikle ilgili uyarıları kontrol edin"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Açıklamanız {length, plural, one {# okunabilir karakter} other {# okunabilir karakter}} uzunluğunda. Net ve bilgilendirici bir açıklama oluşturmak için en az {minChars, plural, one {# karakter} other {# karakter}} önerilir."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Açıklamayı genişlet"
- },
"nags.edit-description.title": {
"defaultMessage": "Açıklamayı düzenle"
},
diff --git a/packages/moderation/src/locales/uk-UA/index.json b/packages/moderation/src/locales/uk-UA/index.json
index c4e23d84f9..28a9a1498c 100644
--- a/packages/moderation/src/locales/uk-UA/index.json
+++ b/packages/moderation/src/locales/uk-UA/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "Перевірте маркування вмісту"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Ваш опис містить {length, plural, one {# видимий символ} few {# видимі символів} other {# видимих символів}}. Радимо щонайменше {minChars, plural, one {# символ} few {# символи} other {# символів}} для чіткого й змістовного опису."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Доповніть опис"
- },
"nags.edit-description.title": {
"defaultMessage": "Відредагуйте опис"
},
diff --git a/packages/moderation/src/locales/vi-VN/index.json b/packages/moderation/src/locales/vi-VN/index.json
index 93502bead0..042fb29fbc 100644
--- a/packages/moderation/src/locales/vi-VN/index.json
+++ b/packages/moderation/src/locales/vi-VN/index.json
@@ -47,12 +47,6 @@
"nags.all-tags-selected.title": {
"defaultMessage": "Chọn các thẻ chính xác"
},
- "nags.description-too-short.description": {
- "defaultMessage": "Mô tả của bạn hiện có {length, plural, one {# ký tự có thể đọc} other {# ký tự có thể đọc}}. Khuyến nghị nên có ít nhất {minChars, plural, one {# ký tự} other {# ký tự}} để tạo ra một mô tả rõ ràng và đầy đủ thông tin."
- },
- "nags.description-too-short.title": {
- "defaultMessage": "Mở rộng mô tả"
- },
"nags.edit-description.title": {
"defaultMessage": "Chỉnh sửa mô tả"
},
diff --git a/packages/moderation/src/locales/zh-CN/index.json b/packages/moderation/src/locales/zh-CN/index.json
index 79ad3ee7f0..6df7d43608 100644
--- a/packages/moderation/src/locales/zh-CN/index.json
+++ b/packages/moderation/src/locales/zh-CN/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "查看内容披露"
},
- "nags.description-too-short.description": {
- "defaultMessage": "你的描述包含 {length, plural, other {# 个可读字符}}。建议至少包含 {minChars, plural, other {# 个字符}},让描述详尽清晰。"
- },
- "nags.description-too-short.title": {
- "defaultMessage": "扩展描述"
- },
"nags.edit-description.title": {
"defaultMessage": "编辑描述"
},
diff --git a/packages/moderation/src/locales/zh-TW/index.json b/packages/moderation/src/locales/zh-TW/index.json
index b9e60abb92..f8a26f226a 100644
--- a/packages/moderation/src/locales/zh-TW/index.json
+++ b/packages/moderation/src/locales/zh-TW/index.json
@@ -53,12 +53,6 @@
"nags.check-disclosures.title": {
"defaultMessage": "檢查內容揭露資訊"
},
- "nags.description-too-short.description": {
- "defaultMessage": "你的描述目前長度為 {length, plural, other {# 個可閱讀字元}}。建議至少輸入 {minChars, plural, other {# 個字元}},以建立清晰且資訊完整的描述。"
- },
- "nags.description-too-short.title": {
- "defaultMessage": "擴展描述"
- },
"nags.edit-description.title": {
"defaultMessage": "編輯描述"
},
diff --git a/packages/moderation/src/validation-rules/rules/description.ts b/packages/moderation/src/validation-rules/rules/description.ts
index ee390c5179..d0f4ee5c79 100644
--- a/packages/moderation/src/validation-rules/rules/description.ts
+++ b/packages/moderation/src/validation-rules/rules/description.ts
@@ -9,6 +9,7 @@ import {
hostnameMatchesDomain,
isIpAddress,
} from '../../validators/links/syntax-checks.ts'
+import { validateSpam } from '../../validators/spam/index.ts'
import { evaluateRules } from '../evaluate-rules.ts'
import {
evaluateNonStandardText,
@@ -33,6 +34,10 @@ const messages = defineMessages({
id: 'nags.description-too-short.title',
defaultMessage: 'Expand the description',
},
+ removeSpam: {
+ id: 'nags.project-description-spam.title',
+ defaultMessage: 'Remove spam from the description',
+ },
shortenHeaders: {
id: 'nags.long-headers.title',
defaultMessage: 'Shorten headers',
@@ -69,7 +74,12 @@ const messages = defineMessages({
tooShort: {
id: 'nags.description-too-short.description',
defaultMessage:
- 'Your description is {length, plural, one {# readable character} other {# readable characters}}. At least {minChars, plural, one {# character} other {# characters}} is recommended to create a clear and informative description.',
+ "Your description is too brief. Add more to clearly describe the project's purpose and function.",
+ },
+ spam: {
+ id: 'nags.project-description-spam.description',
+ defaultMessage:
+ 'Repeated characters, words, or phrases cannot be used to pad a project description.',
},
longHeaders: {
id: 'nags.long-headers.description',
@@ -85,7 +95,7 @@ const messages = defineMessages({
export const DESCRIPTION_MAX_PROFANITY_COUNT = 2
export const DESCRIPTION_NON_STANDARD_TEXT_FAILURE_THRESHOLD = 0.05
-export const MIN_DESCRIPTION_CHARS = 200
+export const MIN_DESCRIPTION_CHARS = 125
export const MAX_HEADER_LENGTH = 80
export const BANNED_DESCRIPTION_LINK_DOMAINS = [...URL_SHORTENERS] as const
@@ -141,21 +151,29 @@ export function analyzeHeaderLength(markdown: string): {
return { hasLongHeaders: longHeaders.length > 0, longHeaders }
}
-export function countText(markdown: string): number {
- if (!markdown) return 0
+export function extractDescriptionText(markdown: string): string {
+ if (!markdown) return ''
const withoutCode = markdown.replace(/```[\s\S]*?```/g, '').replace(/`[^`]*`/g, '')
const withoutImagesAndLinks = withoutCode
- .replace(/!\[[^\]]*]\([^)]+\)/g, ' ')
+ .replace(/!\[([^\]]*)]\([^)]+\)/g, '$1')
.replace(/\[[^\]]*]\([^)]+\)/g, ' ')
- const withoutHtml = withoutImagesAndLinks.replace(/<[^>]+>/g, ' ')
+ const withHtmlImageAltText = withoutImagesAndLinks.replace(/
]*>/gi, (image) => {
+ const altMatch = image.match(/alt\s*=\s*(?:"([^"]*)"|'([^']*)')/i)
+ return altMatch?.[1] ?? altMatch?.[2] ?? ' '
+ })
+ const withoutHtml = withHtmlImageAltText.replace(/<[^>]+>/g, ' ')
const withoutMarkdownSyntax = withoutHtml
.replace(/^(?:>[ \t]?)+/gm, '')
.replace(/^#{1,6}\s+/gm, ' ')
.replace(/[*_~`>-]/g, ' ')
.replace(/\|/g, ' ')
- return withoutMarkdownSyntax.replace(/\s+/g, ' ').trim().length
+ return withoutMarkdownSyntax.replace(/\s+/g, ' ').trim()
+}
+
+export function countText(markdown: string): number {
+ return extractDescriptionText(markdown).length
}
export function analyzeImageContent(markdown: string): {
@@ -220,6 +238,32 @@ export const projectDescriptionValidationRules = {
nag: { title: messages.addDescription, ...commonNagPresentation },
},
},
+ 'description-too-short': {
+ severity: 'error',
+ evaluate: (description) => {
+ const normalized = normalizeProjectFieldText(description ?? '')
+ if (!normalized) return { valid: true }
+
+ const length = countText(normalized)
+ return length >= MIN_DESCRIPTION_CHARS
+ ? { valid: true }
+ : { valid: false, values: { length, minChars: MIN_DESCRIPTION_CHARS } }
+ },
+ presentation: {
+ message: messages.tooShort,
+ nag: { title: messages.expandDescription, ...commonNagPresentation },
+ },
+ },
+ 'project-description-spam': {
+ severity: 'error',
+ evaluate: (description) => ({
+ valid: validateSpam(extractDescriptionText(description ?? '')).valid,
+ }),
+ presentation: {
+ message: messages.spam,
+ nag: { title: messages.removeSpam, ...commonNagPresentation },
+ },
+ },
'project-description-banned-link': {
severity: 'error',
evaluate: (description) => {
@@ -235,23 +279,6 @@ export const projectDescriptionValidationRules = {
nag: { title: messages.fixDescription, ...commonNagPresentation },
},
},
- 'description-too-short': {
- severity: 'warning',
- evaluate: (description) => {
- const normalized = normalizeProjectFieldText(description ?? '')
- if (!normalized) return { valid: true }
- const length = countText(normalized)
- if (length < MIN_DESCRIPTION_CHARS) {
- return { valid: false, values: { length, minChars: MIN_DESCRIPTION_CHARS } }
- } else {
- return { valid: true }
- }
- },
- presentation: {
- message: messages.tooShort,
- nag: { title: messages.expandDescription, ...commonNagPresentation },
- },
- },
'long-headers': {
severity: 'warning',
evaluate: (description) => {
diff --git a/packages/moderation/src/validation-rules/rules/summary.ts b/packages/moderation/src/validation-rules/rules/summary.ts
index 67bd505bb0..d7d30b095b 100644
--- a/packages/moderation/src/validation-rules/rules/summary.ts
+++ b/packages/moderation/src/validation-rules/rules/summary.ts
@@ -3,6 +3,7 @@ import LinkifyIt from 'linkify-it'
import tlds from 'tlds' with { type: 'json' }
import type { Nag, ProjectValidationContext } from '../../types/nags.ts'
+import { validateSpam } from '../../validators/spam/index.ts'
import { evaluateRules } from '../evaluate-rules.ts'
import {
evaluateNonStandardText,
@@ -27,6 +28,10 @@ const messages = defineMessages({
id: 'nags.summary-too-short.title',
defaultMessage: 'Expand the summary',
},
+ removeSpam: {
+ id: 'nags.project-summary-spam.title',
+ defaultMessage: 'Remove spam from the summary',
+ },
cleanUpSummary: {
id: 'nags.summary-special-formatting.title',
defaultMessage: 'Clean up the summary',
@@ -54,7 +59,12 @@ const messages = defineMessages({
tooShort: {
id: 'project.text-validation.summary-too-short',
defaultMessage:
- 'Your summary is {length, plural, one {# character} other {# characters}}. At least {minChars, plural, one {# character} other {# characters}} is recommended to create an informative and enticing summary.',
+ 'Your summary is too short. Add a sentence or two which describes your project.',
+ },
+ spam: {
+ id: 'nags.project-summary-spam.description',
+ defaultMessage:
+ 'Repeated characters, words, or phrases cannot be used to pad a project summary.',
},
specialFormatting: {
id: 'nags.summary-special-formatting.description',
@@ -159,6 +169,16 @@ export const projectSummaryValidationRules = {
nag: { title: messages.expandSummary, ...commonNagPresentation },
},
},
+ 'project-summary-spam': {
+ severity: 'error',
+ evaluate: ({ summary }) => ({
+ valid: validateSpam(normalizeProjectFieldText(summary ?? '')).valid,
+ }),
+ presentation: {
+ message: messages.spam,
+ nag: { title: messages.removeSpam, ...commonNagPresentation },
+ },
+ },
'summary-special-formatting': {
severity: 'error',
evaluate: ({ summary }) => ({
diff --git a/packages/moderation/src/validation-rules/tests.ts b/packages/moderation/src/validation-rules/tests.ts
index e5048382d0..ae209e1161 100644
--- a/packages/moderation/src/validation-rules/tests.ts
+++ b/packages/moderation/src/validation-rules/tests.ts
@@ -81,14 +81,14 @@ test('collects every matching project name rule', () => {
)
assert.deepEqual(matches[0]?.values, { value: 'fuck' })
assert.equal(matches[1]?.rule.severity, 'error')
- assert.equal(matches[2]?.rule.severity, 'warning')
+ assert.equal(matches[2]?.rule.severity, 'error')
})
test('derives project name field presentation from the matching rule', () => {
assert.deepEqual(validateProjectNameField('Minecraft'), [
{
code: 'minecraft-title-clause',
- severity: 'warning',
+ severity: 'error',
message: {
id: 'nags.minecraft-title-clause.description',
defaultMessage:
@@ -103,7 +103,7 @@ test('derives project name nags from the same matching rule', () => {
const [nag] = toNags(evaluateRules('Minecraft', projectNameValidationRules))
assert.equal(nag?.id, 'minecraft-title-clause')
- assert.equal(nag?.status, 'warning')
+ assert.equal(nag?.status, 'required')
assert.equal(nag?.title.id, 'nags.minecraft-title-clause.title')
assert.equal(nag?.link?.path, 'settings')
assert.equal(nag?.link?.title.id, 'nags.edit-title.title')
@@ -116,7 +116,7 @@ test('validates summary content from one rule set', () => {
({ code, severity }) => ({ code, severity }),
),
[
- { code: 'summary-too-short', severity: 'warning' },
+ { code: 'summary-too-short', severity: 'error' },
{ code: 'summary-special-formatting', severity: 'error' },
],
)
@@ -129,6 +129,16 @@ test('validates summary content from one rule set', () => {
)
})
+test('rejects repeated summary padding', () => {
+ assert.deepEqual(
+ validateProjectSummary({
+ summary: 'Useful project! '.repeat(3),
+ name: 'Project title',
+ }).map(({ code }) => code),
+ ['project-summary-spam'],
+ )
+})
+
test('rejects every link and IP address in project summaries', () => {
for (const summary of [
'Visit https://example.dev for more information about this project',
@@ -178,7 +188,26 @@ test('validates description requirements and simultaneous recommendations', () =
const description = `${'# '.concat('A'.repeat(81))}\n\n\n\n`
assert.deepEqual(
validateProjectDescription(description).map(({ code }) => code),
- ['description-too-short', 'long-headers', 'missing-alt-text'],
+ ['description-too-short', 'project-description-spam', 'long-headers', 'missing-alt-text'],
+ )
+})
+
+test('requires 125 readable description characters', () => {
+ const description =
+ 'This project adds useful tools, flexible behavior, accessible documentation, polished gameplay, and support for every player.'
+
+ assert.equal(countText(description), MIN_DESCRIPTION_CHARS)
+ assert.deepEqual(
+ validateProjectDescription(description.slice(0, -1)).map(({ code }) => code),
+ ['description-too-short'],
+ )
+ assert.deepEqual(validateProjectDescription(description), [])
+})
+
+test('rejects repeated description padding', () => {
+ assert.deepEqual(
+ validateProjectDescription('Useful project! '.repeat(10)).map(({ code }) => code),
+ ['project-description-spam'],
)
})
@@ -190,10 +219,20 @@ test('requires alt text for description images', () => {
assert.deepEqual(analyzeImageContent('
'), { hasEmptyAltText: true })
})
+test('counts image alt text as readable description text', () => {
+ assert.equal(countText(''), 'Project screenshot'.length)
+ assert.equal(
+ countText('
'),
+ 'Project screenshot'.length,
+ )
+})
+
test('counts blockquote content as readable description text', () => {
assert.equal(countText('> Quoted text'), 'Quoted text'.length)
- const quotedDescription = `> ${'A'.repeat(MIN_DESCRIPTION_CHARS)}`
+ const quotedDescription =
+ '> This project adds useful tools, flexible behavior, accessible documentation, polished gameplay, and support for every player.'
+ assert.equal(countText(quotedDescription), MIN_DESCRIPTION_CHARS)
assert.equal(
validateProjectDescription(quotedDescription).some(
({ code }) => code === 'description-too-short',
diff --git a/packages/moderation/src/validators/spam/index.ts b/packages/moderation/src/validators/spam/index.ts
new file mode 100644
index 0000000000..ba8e7e18e5
--- /dev/null
+++ b/packages/moderation/src/validators/spam/index.ts
@@ -0,0 +1,113 @@
+export type SpamMatchKind = 'character' | 'word' | 'phrase'
+
+export interface SpamMatch {
+ kind: SpamMatchKind
+ value: string
+}
+
+export interface SpamResult {
+ valid: boolean
+ firstMatch?: SpamMatch
+}
+
+export const MIN_REPEATED_CHARACTER_COUNT = 8
+export const MIN_REPEATED_WORD_COUNT = 4
+export const MIN_REPEATED_PHRASE_COUNT = 3
+export const MAX_REPEATED_PHRASE_WORDS = 8
+
+const REPEATABLE_CHARACTER_PATTERN = /\S/u
+const WORD_PATTERN = /[\p{L}\p{M}\p{N}]+/gu
+
+function findRepeatedCharacter(text: string): SpamMatch | undefined {
+ let previousCharacter: string | undefined
+ let repeatedCount = 0
+
+ for (const character of text.normalize('NFC')) {
+ const normalizedCharacter = character.toLowerCase()
+ if (
+ REPEATABLE_CHARACTER_PATTERN.test(normalizedCharacter) &&
+ normalizedCharacter === previousCharacter
+ ) {
+ repeatedCount++
+ } else {
+ previousCharacter = normalizedCharacter
+ repeatedCount = REPEATABLE_CHARACTER_PATTERN.test(normalizedCharacter) ? 1 : 0
+ }
+
+ if (repeatedCount >= MIN_REPEATED_CHARACTER_COUNT) {
+ return { kind: 'character', value: character.repeat(repeatedCount) }
+ }
+ }
+
+ return undefined
+}
+
+function getWords(text: string): string[] {
+ return [...text.normalize('NFC').toLowerCase().matchAll(WORD_PATTERN)].map((match) => match[0])
+}
+
+function findRepeatedWord(words: readonly string[]): SpamMatch | undefined {
+ let repeatedCount = 1
+
+ for (let index = 1; index < words.length; index++) {
+ repeatedCount = words[index] === words[index - 1] ? repeatedCount + 1 : 1
+ if (repeatedCount >= MIN_REPEATED_WORD_COUNT) {
+ return { kind: 'word', value: words[index] }
+ }
+ }
+
+ return undefined
+}
+
+function phrasesMatch(
+ words: readonly string[],
+ firstStart: number,
+ secondStart: number,
+ size: number,
+) {
+ for (let offset = 0; offset < size; offset++) {
+ if (words[firstStart + offset] !== words[secondStart + offset]) return false
+ }
+
+ return true
+}
+
+function findRepeatedPhrase(words: readonly string[]): SpamMatch | undefined {
+ const maxPhraseWords = Math.min(
+ MAX_REPEATED_PHRASE_WORDS,
+ Math.floor(words.length / MIN_REPEATED_PHRASE_COUNT),
+ )
+
+ for (let phraseWords = maxPhraseWords; phraseWords >= 2; phraseWords--) {
+ const repeatedWords = phraseWords * MIN_REPEATED_PHRASE_COUNT
+ for (let start = 0; start + repeatedWords <= words.length; start++) {
+ let matches = true
+ for (let repetition = 1; repetition < MIN_REPEATED_PHRASE_COUNT; repetition++) {
+ if (!phrasesMatch(words, start, start + repetition * phraseWords, phraseWords)) {
+ matches = false
+ break
+ }
+ }
+
+ if (matches) {
+ return { kind: 'phrase', value: words.slice(start, start + phraseWords).join(' ') }
+ }
+ }
+ }
+
+ return undefined
+}
+
+/**
+ The spam validator checks normalized, readable description text in this order:
+ Characters: the same non-whitespace character repeated 8 times consecutively, e.g. aaaaaaaa.
+ Words: the same word repeated 4 times consecutively, case-insensitively, e.g. Great great GREAT great.
+ Phrases: a 2–8 word phrase repeated 3 times consecutively. Punctuation and capitalization are ignored, so best project, best project! BEST PROJECT is rejected.
+ */
+export function validateSpam(text: string): SpamResult {
+ const words = getWords(text)
+ const firstMatch =
+ findRepeatedCharacter(text) ?? findRepeatedWord(words) ?? findRepeatedPhrase(words)
+
+ return firstMatch ? { valid: false, firstMatch } : { valid: true }
+}
diff --git a/packages/moderation/src/validators/spam/tests.ts b/packages/moderation/src/validators/spam/tests.ts
new file mode 100644
index 0000000000..a17bef315e
--- /dev/null
+++ b/packages/moderation/src/validators/spam/tests.ts
@@ -0,0 +1,36 @@
+import assert from 'node:assert/strict'
+import test from 'node:test'
+
+import { validateSpam } from './index.ts'
+
+test('allows ordinary prose', () => {
+ assert.equal(
+ validateSpam('This project adds a configurable compass for exploring large worlds.').valid,
+ true,
+ )
+})
+
+test('detects repeated characters', () => {
+ assert.deepEqual(validateSpam('aaaaaaaa').firstMatch, {
+ kind: 'character',
+ value: 'aaaaaaaa',
+ })
+})
+
+test('detects repeated words case-insensitively', () => {
+ assert.deepEqual(validateSpam('Great great GREAT great').firstMatch, {
+ kind: 'word',
+ value: 'great',
+ })
+})
+
+test('detects repeated phrases across punctuation', () => {
+ assert.deepEqual(validateSpam('best project, best project! BEST PROJECT').firstMatch, {
+ kind: 'phrase',
+ value: 'best project',
+ })
+})
+
+test('allows repetition below the spam thresholds', () => {
+ assert.equal(validateSpam('so so so good good phrase here phrase here').valid, true)
+})