refactor: inline i18n
This commit is contained in:
@@ -1,116 +0,0 @@
|
||||
import { defineMessages } from '@vintl/vintl'
|
||||
|
||||
export default defineMessages({
|
||||
moderatorFeedbackTitle: {
|
||||
id: 'nags.moderator-feedback.title',
|
||||
defaultMessage: 'Review moderator feedback',
|
||||
},
|
||||
moderatorFeedbackDescription: {
|
||||
id: 'nags.moderator-feedback.description',
|
||||
defaultMessage:
|
||||
'Review any feedback from moderators regarding your project before resubmitting.',
|
||||
},
|
||||
moderationTitle: {
|
||||
id: 'nags.moderation.title',
|
||||
defaultMessage: 'Visit moderation thread',
|
||||
},
|
||||
uploadVersionTitle: {
|
||||
id: 'nags.upload-version.title',
|
||||
defaultMessage: 'Upload a version',
|
||||
},
|
||||
uploadVersionDescription: {
|
||||
id: 'nags.upload-version.description',
|
||||
defaultMessage: 'At least one version is required for a project to be submitted for review.',
|
||||
},
|
||||
versionsTitle: {
|
||||
id: 'nags.versions.title',
|
||||
defaultMessage: 'Visit versions page',
|
||||
},
|
||||
addDescriptionTitle: {
|
||||
id: 'nags.add-description.title',
|
||||
defaultMessage: 'Add a description',
|
||||
},
|
||||
addDescriptionDescription: {
|
||||
id: 'nags.add-description.description',
|
||||
defaultMessage:
|
||||
"A description that clearly describes the project's purpose and function is required.",
|
||||
},
|
||||
settingsDescriptionTitle: {
|
||||
id: 'nags.settings.description.title',
|
||||
defaultMessage: 'Visit description settings',
|
||||
},
|
||||
addIconTitle: {
|
||||
id: 'nags.add-icon.title',
|
||||
defaultMessage: 'Add an icon',
|
||||
},
|
||||
addIconDescription: {
|
||||
id: 'nags.add-icon.description',
|
||||
defaultMessage:
|
||||
'Your project should have a nice-looking icon to uniquely identify your project at a glance.',
|
||||
},
|
||||
settingsTitle: {
|
||||
id: 'nags.settings.title',
|
||||
defaultMessage: 'Visit general settings',
|
||||
},
|
||||
featureGalleryImageTitle: {
|
||||
id: 'nags.feature-gallery-image.title',
|
||||
defaultMessage: 'Feature a gallery image',
|
||||
},
|
||||
featureGalleryImageDescription: {
|
||||
id: 'nags.feature-gallery-image.description',
|
||||
defaultMessage: 'Featured gallery images may be the first impression of many users.',
|
||||
},
|
||||
galleryTitle: {
|
||||
id: 'nags.gallery.title',
|
||||
defaultMessage: 'Visit gallery page',
|
||||
},
|
||||
selectTagsTitle: {
|
||||
id: 'nags.select-tags.title',
|
||||
defaultMessage: 'Select tags',
|
||||
},
|
||||
selectTagsDescription: {
|
||||
id: 'nags.select-tags.description',
|
||||
defaultMessage: 'Select all tags that apply to your project.',
|
||||
},
|
||||
settingsTagsTitle: {
|
||||
id: 'nags.settings.tags.title',
|
||||
defaultMessage: 'Visit tag settings',
|
||||
},
|
||||
addLinksTitle: {
|
||||
id: 'nags.add-links.title',
|
||||
defaultMessage: 'Add external links',
|
||||
},
|
||||
addLinksDescription: {
|
||||
id: 'nags.add-links.description',
|
||||
defaultMessage:
|
||||
'Add any relevant links targeted outside of Modrinth, such as sources, issues, or a Discord invite.',
|
||||
},
|
||||
settingsLinksTitle: {
|
||||
id: 'nags.settings.links.title',
|
||||
defaultMessage: 'Visit links settings',
|
||||
},
|
||||
selectEnvironmentsTitle: {
|
||||
id: 'nags.select-environments.title',
|
||||
defaultMessage: 'Select supported environments',
|
||||
},
|
||||
selectEnvironmentsDescription: {
|
||||
id: 'nags.select-environments.description',
|
||||
defaultMessage: `Select if the {projectType} functions on the client-side and/or server-side.`,
|
||||
},
|
||||
settingsEnvironmentsTitle: {
|
||||
id: 'nags.settings.environments.title',
|
||||
defaultMessage: 'Visit general settings',
|
||||
},
|
||||
selectLicenseTitle: {
|
||||
id: 'nags.select-license.title',
|
||||
defaultMessage: 'Select license',
|
||||
},
|
||||
selectLicenseDescription: {
|
||||
id: 'nags.select-license.description',
|
||||
defaultMessage: 'Select the license your {projectType} is distributed under.',
|
||||
},
|
||||
settingsLicenseTitle: {
|
||||
id: 'nags.settings.license.title',
|
||||
defaultMessage: 'Visit license settings',
|
||||
},
|
||||
})
|
||||
@@ -1,64 +1,107 @@
|
||||
import type { Nag, NagContext } from '../../types/nags'
|
||||
import { formatProjectType } from '@modrinth/utils'
|
||||
import { useVIntl } from '@vintl/vintl'
|
||||
|
||||
import messages from './core.i18n'
|
||||
import { useVIntl, defineMessage } from '@vintl/vintl'
|
||||
|
||||
export const coreNags: Nag[] = [
|
||||
{
|
||||
id: 'moderator-feedback',
|
||||
title: messages.moderatorFeedbackTitle,
|
||||
description: messages.moderatorFeedbackDescription,
|
||||
title: defineMessage({
|
||||
id: 'nags.moderator-feedback.title',
|
||||
defaultMessage: 'Review moderator feedback',
|
||||
}),
|
||||
description: defineMessage({
|
||||
id: 'nags.moderator-feedback.description',
|
||||
defaultMessage:
|
||||
'Review any feedback from moderators regarding your project before resubmitting.',
|
||||
}),
|
||||
status: 'suggestion',
|
||||
shouldShow: (context: NagContext) =>
|
||||
context.tags.rejectedStatuses.includes(context.project.status),
|
||||
link: {
|
||||
path: 'moderation',
|
||||
title: messages.moderationTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.moderation.title',
|
||||
defaultMessage: 'Visit moderation thread',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-moderation',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'upload-version',
|
||||
title: messages.uploadVersionTitle,
|
||||
description: messages.uploadVersionDescription,
|
||||
title: defineMessage({
|
||||
id: 'nags.upload-version.title',
|
||||
defaultMessage: 'Upload a version',
|
||||
}),
|
||||
description: defineMessage({
|
||||
id: 'nags.upload-version.description',
|
||||
defaultMessage: 'At least one version is required for a project to be submitted for review.',
|
||||
}),
|
||||
status: 'required',
|
||||
shouldShow: (context: NagContext) => context.versions.length < 1,
|
||||
link: {
|
||||
path: 'versions',
|
||||
title: messages.versionsTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.versions.title',
|
||||
defaultMessage: 'Visit versions page',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-versions',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'add-description',
|
||||
title: messages.addDescriptionTitle,
|
||||
description: messages.addDescriptionDescription,
|
||||
title: defineMessage({
|
||||
id: 'nags.add-description.title',
|
||||
defaultMessage: 'Add a description',
|
||||
}),
|
||||
description: defineMessage({
|
||||
id: 'nags.add-description.description',
|
||||
defaultMessage:
|
||||
"A description that clearly describes the project's purpose and function is required.",
|
||||
}),
|
||||
status: 'required',
|
||||
shouldShow: (context: NagContext) =>
|
||||
context.project.body === '' || context.project.body.startsWith('# Placeholder description'),
|
||||
link: {
|
||||
path: 'settings/description',
|
||||
title: messages.settingsDescriptionTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.settings.description.title',
|
||||
defaultMessage: 'Visit description settings',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings-description',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'add-icon',
|
||||
title: messages.addIconTitle,
|
||||
description: messages.addIconDescription,
|
||||
title: defineMessage({
|
||||
id: 'nags.add-icon.title',
|
||||
defaultMessage: 'Add an icon',
|
||||
}),
|
||||
description: defineMessage({
|
||||
id: 'nags.add-icon.description',
|
||||
defaultMessage:
|
||||
'Your project should have a nice-looking icon to uniquely identify your project at a glance.',
|
||||
}),
|
||||
status: 'suggestion',
|
||||
shouldShow: (context: NagContext) => !context.project.icon_url,
|
||||
link: {
|
||||
path: 'settings',
|
||||
title: messages.settingsTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.settings.title',
|
||||
defaultMessage: 'Visit general settings',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'feature-gallery-image',
|
||||
title: messages.featureGalleryImageTitle,
|
||||
description: messages.featureGalleryImageDescription,
|
||||
title: defineMessage({
|
||||
id: 'nags.feature-gallery-image.title',
|
||||
defaultMessage: 'Feature a gallery image',
|
||||
}),
|
||||
description: defineMessage({
|
||||
id: 'nags.feature-gallery-image.description',
|
||||
defaultMessage: 'Featured gallery images may be the first impression of many users.',
|
||||
}),
|
||||
status: 'suggestion',
|
||||
shouldShow: (context: NagContext) => {
|
||||
const featuredGalleryImage = context.project.gallery?.find((img) => img.featured)
|
||||
@@ -66,27 +109,46 @@ export const coreNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'gallery',
|
||||
title: messages.galleryTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.gallery.title',
|
||||
defaultMessage: 'Visit gallery page',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-gallery',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'select-tags',
|
||||
title: messages.selectTagsTitle,
|
||||
description: messages.selectTagsDescription,
|
||||
title: defineMessage({
|
||||
id: 'nags.select-tags.title',
|
||||
defaultMessage: 'Select tags',
|
||||
}),
|
||||
description: defineMessage({
|
||||
id: 'nags.select-tags.description',
|
||||
defaultMessage: 'Select all tags that apply to your project.',
|
||||
}),
|
||||
status: 'suggestion',
|
||||
shouldShow: (context: NagContext) =>
|
||||
context.project.versions.length > 0 && context.project.categories.length < 1,
|
||||
link: {
|
||||
path: 'settings/tags',
|
||||
title: messages.settingsTagsTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.settings.tags.title',
|
||||
defaultMessage: 'Visit tag settings',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings-tags',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'add-links',
|
||||
title: messages.addLinksTitle,
|
||||
description: messages.addLinksDescription,
|
||||
title: defineMessage({
|
||||
id: 'nags.add-links.title',
|
||||
defaultMessage: 'Add external links',
|
||||
}),
|
||||
description: defineMessage({
|
||||
id: 'nags.add-links.description',
|
||||
defaultMessage:
|
||||
'Add any relevant links targeted outside of Modrinth, such as sources, issues, or a Discord invite.',
|
||||
}),
|
||||
status: 'suggestion',
|
||||
shouldShow: (context: NagContext) =>
|
||||
!(
|
||||
@@ -98,19 +160,31 @@ export const coreNags: Nag[] = [
|
||||
),
|
||||
link: {
|
||||
path: 'settings/links',
|
||||
title: messages.settingsLinksTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.settings.links.title',
|
||||
defaultMessage: 'Visit links settings',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings-links',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'select-environments',
|
||||
title: messages.selectEnvironmentsTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.select-environments.title',
|
||||
defaultMessage: 'Select supported environments',
|
||||
}),
|
||||
description: (context: NagContext) => {
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
return formatMessage(messages.selectEnvironmentsDescription, {
|
||||
projectType: formatProjectType(context.project.project_type).toLowerCase(),
|
||||
})
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'nags.select-environments.description',
|
||||
defaultMessage: `Select if the {projectType} functions on the client-side and/or server-side.`,
|
||||
}),
|
||||
{
|
||||
projectType: formatProjectType(context.project.project_type).toLowerCase(),
|
||||
},
|
||||
)
|
||||
},
|
||||
status: 'required',
|
||||
shouldShow: (context: NagContext) => {
|
||||
@@ -126,25 +200,40 @@ export const coreNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings',
|
||||
title: messages.settingsEnvironmentsTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.settings.environments.title',
|
||||
defaultMessage: 'Visit general settings',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'select-license',
|
||||
title: messages.selectLicenseTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.select-license.title',
|
||||
defaultMessage: 'Select license',
|
||||
}),
|
||||
description: (context: NagContext) => {
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
return formatMessage(messages.selectLicenseDescription, {
|
||||
projectType: formatProjectType(context.project.project_type).toLowerCase(),
|
||||
})
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'nags.select-license.description',
|
||||
defaultMessage: 'Select the license your {projectType} is distributed under.',
|
||||
}),
|
||||
{
|
||||
projectType: formatProjectType(context.project.project_type).toLowerCase(),
|
||||
},
|
||||
)
|
||||
},
|
||||
status: 'required',
|
||||
shouldShow: (context: NagContext) => context.project.license.id === 'LicenseRef-Unknown',
|
||||
link: {
|
||||
path: 'settings/license',
|
||||
title: messages.settingsLicenseTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.settings.license.title',
|
||||
defaultMessage: 'Visit license settings',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings-license',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
import { defineMessages } from '@vintl/vintl'
|
||||
|
||||
export default defineMessages({
|
||||
descriptionTooShortTitle: {
|
||||
id: 'nags.description-too-short.title',
|
||||
defaultMessage: 'Description may be insufficient',
|
||||
},
|
||||
descriptionTooShortDescription: {
|
||||
id: 'nags.description-too-short.description',
|
||||
defaultMessage:
|
||||
"Your description is {length} characters. It's recommended to have at least {minChars} characters to provide users with enough information about your project.",
|
||||
},
|
||||
longHeadersTitle: {
|
||||
id: 'nags.long-headers.title',
|
||||
defaultMessage: 'Headers are too long',
|
||||
},
|
||||
longHeadersDescription: {
|
||||
id: 'nags.long-headers.description',
|
||||
defaultMessage:
|
||||
'{count, plural, one {# header} other {# headers}} in your description {count, plural, one {is} other {are}} too long. Headers should be concise and act as section titles, not full sentences.',
|
||||
},
|
||||
summaryTooShortTitle: {
|
||||
id: 'nags.summary-too-short.title',
|
||||
defaultMessage: 'Summary may be insufficient',
|
||||
},
|
||||
summaryTooShortDescription: {
|
||||
id: 'nags.summary-too-short.description',
|
||||
defaultMessage:
|
||||
"Your summary is {length} characters. It's recommended to have at least {minChars} characters to provide users with enough information about your project.",
|
||||
},
|
||||
minecraftTitleClauseTitle: {
|
||||
id: 'nags.minecraft-title-clause.title',
|
||||
defaultMessage: 'Title contains "Minecraft"',
|
||||
},
|
||||
minecraftTitleClauseDescription: {
|
||||
id: 'nags.minecraft-title-clause.description',
|
||||
defaultMessage:
|
||||
'Please remove "Minecraft" from your title. You cannot use "Minecraft" in your title for legal reasons.',
|
||||
},
|
||||
titleContainsTechnicalInfoTitle: {
|
||||
id: 'nags.title-contains-technical-info.title',
|
||||
defaultMessage: 'Title contains loader or version info',
|
||||
},
|
||||
titleContainsTechnicalInfoDescription: {
|
||||
id: 'nags.title-contains-technical-info.description',
|
||||
defaultMessage:
|
||||
'Removing these helps keep titles clean and makes your project easier to find. Version and loader information is automatically displayed alongside your project.',
|
||||
},
|
||||
summarySameAsTitleTitle: {
|
||||
id: 'nags.summary-same-as-title.title',
|
||||
defaultMessage: 'Summary is project name',
|
||||
},
|
||||
summarySameAsTitleDescription: {
|
||||
id: 'nags.summary-same-as-title.description',
|
||||
defaultMessage:
|
||||
"Your summary is the same as your project name. Please change it. It's recommended to have a unique summary to provide more context about your project.",
|
||||
},
|
||||
imageHeavyDescriptionTitle: {
|
||||
id: 'nags.image-heavy-description.title',
|
||||
defaultMessage: 'Description is mostly images',
|
||||
},
|
||||
imageHeavyDescriptionDescription: {
|
||||
id: 'nags.image-heavy-description.description',
|
||||
defaultMessage:
|
||||
'Please add more descriptive text to help users understand your project, especially those using screen readers or with slow internet connections.',
|
||||
},
|
||||
missingAltTextTitle: {
|
||||
id: 'nags.missing-alt-text.title',
|
||||
defaultMessage: 'Images missing alt text',
|
||||
},
|
||||
missingAltTextDescription: {
|
||||
id: 'nags.missing-alt-text.description',
|
||||
defaultMessage:
|
||||
'Some of your images are missing alt text, which is important for accessibility, especially for visually impaired users.',
|
||||
},
|
||||
editDescriptionTitle: {
|
||||
id: 'nags.edit-description.title',
|
||||
defaultMessage: 'Edit description',
|
||||
},
|
||||
editSummaryTitle: {
|
||||
id: 'nags.edit-summary.title',
|
||||
defaultMessage: 'Edit summary',
|
||||
},
|
||||
editTitleTitle: {
|
||||
id: 'nags.edit-title.title',
|
||||
defaultMessage: 'Edit title',
|
||||
},
|
||||
})
|
||||
@@ -1,7 +1,5 @@
|
||||
import type { Nag, NagContext } from '../../types/nags'
|
||||
import { useVIntl } from '@vintl/vintl'
|
||||
|
||||
import messages from './description.i18n'
|
||||
import { useVIntl, defineMessage } from '@vintl/vintl'
|
||||
|
||||
export const MIN_DESCRIPTION_CHARS = 500
|
||||
export const MAX_HEADER_LENGTH = 100
|
||||
@@ -73,14 +71,24 @@ function analyzeImageContent(markdown: string): { imageHeavy: boolean; hasEmptyA
|
||||
export const descriptionNags: Nag[] = [
|
||||
{
|
||||
id: 'description-too-short',
|
||||
title: messages.descriptionTooShortTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.description-too-short.title',
|
||||
defaultMessage: 'Description may be insufficient',
|
||||
}),
|
||||
description: (context: NagContext) => {
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
return formatMessage(messages.descriptionTooShortDescription, {
|
||||
length: context.project.body?.length || 0,
|
||||
minChars: MIN_DESCRIPTION_CHARS,
|
||||
})
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'nags.description-too-short.description',
|
||||
defaultMessage:
|
||||
"Your description is {length} characters. It's recommended to have at least {minChars} characters to provide users with enough information about your project.",
|
||||
}),
|
||||
{
|
||||
length: context.project.body?.length || 0,
|
||||
minChars: MIN_DESCRIPTION_CHARS,
|
||||
},
|
||||
)
|
||||
},
|
||||
status: 'warning',
|
||||
shouldShow: (context: NagContext) => {
|
||||
@@ -89,21 +97,34 @@ export const descriptionNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings/description',
|
||||
title: messages.editDescriptionTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.edit-description.title',
|
||||
defaultMessage: 'Edit description',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings-description',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'long-headers',
|
||||
title: messages.longHeadersTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.long-headers.title',
|
||||
defaultMessage: 'Headers are too long',
|
||||
}),
|
||||
description: (context: NagContext) => {
|
||||
const { formatMessage } = useVIntl()
|
||||
const { longHeaders } = analyzeHeaderLength(context.project.body || '')
|
||||
const count = longHeaders.length
|
||||
|
||||
return formatMessage(messages.longHeadersDescription, {
|
||||
count,
|
||||
})
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'nags.long-headers.description',
|
||||
defaultMessage:
|
||||
'{count, plural, one {# header} other {# headers}} in your description {count, plural, one {is} other {are}} too long. Headers should be concise and act as section titles, not full sentences.',
|
||||
}),
|
||||
{
|
||||
count,
|
||||
},
|
||||
)
|
||||
},
|
||||
status: 'warning',
|
||||
shouldShow: (context: NagContext) => {
|
||||
@@ -112,20 +133,33 @@ export const descriptionNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings/description',
|
||||
title: messages.editDescriptionTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.edit-description.title',
|
||||
defaultMessage: 'Edit description',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings-description',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'summary-too-short',
|
||||
title: messages.summaryTooShortTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.summary-too-short.title',
|
||||
defaultMessage: 'Summary may be insufficient',
|
||||
}),
|
||||
description: (context: NagContext) => {
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
return formatMessage(messages.summaryTooShortDescription, {
|
||||
length: context.project.description?.length || 0,
|
||||
minChars: MIN_SUMMARY_CHARS,
|
||||
})
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'nags.summary-too-short.description',
|
||||
defaultMessage:
|
||||
"Your summary is {length} characters. It's recommended to have at least {minChars} characters to provide users with enough information about your project.",
|
||||
}),
|
||||
{
|
||||
length: context.project.description?.length || 0,
|
||||
minChars: MIN_SUMMARY_CHARS,
|
||||
},
|
||||
)
|
||||
},
|
||||
status: 'warning',
|
||||
shouldShow: (context: NagContext) => {
|
||||
@@ -134,14 +168,24 @@ export const descriptionNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings',
|
||||
title: messages.editSummaryTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.edit-summary.title',
|
||||
defaultMessage: 'Edit summary',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'minecraft-title-clause',
|
||||
title: messages.minecraftTitleClauseTitle,
|
||||
description: messages.minecraftTitleClauseDescription,
|
||||
title: defineMessage({
|
||||
id: 'nags.minecraft-title-clause.title',
|
||||
defaultMessage: 'Title contains "Minecraft"',
|
||||
}),
|
||||
description: defineMessage({
|
||||
id: 'nags.minecraft-title-clause.description',
|
||||
defaultMessage:
|
||||
'Please remove "Minecraft" from your title. You cannot use "Minecraft" in your title for legal reasons.',
|
||||
}),
|
||||
status: 'required',
|
||||
shouldShow: (context: NagContext) => {
|
||||
const title = context.project.title?.toLowerCase() || ''
|
||||
@@ -150,14 +194,24 @@ export const descriptionNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings',
|
||||
title: messages.editTitleTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.edit-title.title',
|
||||
defaultMessage: 'Edit title',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'title-contains-technical-info',
|
||||
title: messages.titleContainsTechnicalInfoTitle,
|
||||
description: messages.titleContainsTechnicalInfoDescription,
|
||||
title: defineMessage({
|
||||
id: 'nags.title-contains-technical-info.title',
|
||||
defaultMessage: 'Title contains loader or version info',
|
||||
}),
|
||||
description: defineMessage({
|
||||
id: 'nags.title-contains-technical-info.description',
|
||||
defaultMessage:
|
||||
'Removing these helps keep titles clean and makes your project easier to find. Version and loader information is automatically displayed alongside your project.',
|
||||
}),
|
||||
status: 'warning',
|
||||
shouldShow: (context: NagContext) => {
|
||||
const title = context.project.title?.toLowerCase() || ''
|
||||
@@ -173,14 +227,24 @@ export const descriptionNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings',
|
||||
title: messages.editTitleTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.edit-title.title',
|
||||
defaultMessage: 'Edit title',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'summary-same-as-title',
|
||||
title: messages.summarySameAsTitleTitle,
|
||||
description: messages.summarySameAsTitleDescription,
|
||||
title: defineMessage({
|
||||
id: 'nags.summary-same-as-title.title',
|
||||
defaultMessage: 'Summary is project name',
|
||||
}),
|
||||
description: defineMessage({
|
||||
id: 'nags.summary-same-as-title.description',
|
||||
defaultMessage:
|
||||
"Your summary is the same as your project name. Please change it. It's recommended to have a unique summary to provide more context about your project.",
|
||||
}),
|
||||
status: 'required',
|
||||
shouldShow: (context: NagContext) => {
|
||||
const title = context.project.title?.trim() || ''
|
||||
@@ -189,14 +253,24 @@ export const descriptionNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings',
|
||||
title: messages.editSummaryTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.edit-summary.title',
|
||||
defaultMessage: 'Edit summary',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'image-heavy-description',
|
||||
title: messages.imageHeavyDescriptionTitle,
|
||||
description: messages.imageHeavyDescriptionDescription,
|
||||
title: defineMessage({
|
||||
id: 'nags.image-heavy-description.title',
|
||||
defaultMessage: 'Description is mostly images',
|
||||
}),
|
||||
description: defineMessage({
|
||||
id: 'nags.image-heavy-description.description',
|
||||
defaultMessage:
|
||||
'Please add more descriptive text to help users understand your project, especially those using screen readers or with slow internet connections.',
|
||||
}),
|
||||
status: 'warning',
|
||||
shouldShow: (context: NagContext) => {
|
||||
const { imageHeavy } = analyzeImageContent(context.project.body || '')
|
||||
@@ -204,14 +278,24 @@ export const descriptionNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings/description',
|
||||
title: messages.editDescriptionTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.edit-description.title',
|
||||
defaultMessage: 'Edit description',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings-description',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'missing-alt-text',
|
||||
title: messages.missingAltTextTitle,
|
||||
description: messages.missingAltTextDescription,
|
||||
title: defineMessage({
|
||||
id: 'nags.missing-alt-text.title',
|
||||
defaultMessage: 'Images missing alt text',
|
||||
}),
|
||||
description: defineMessage({
|
||||
id: 'nags.missing-alt-text.description',
|
||||
defaultMessage:
|
||||
'Some of your images are missing alt text, which is important for accessibility, especially for visually impaired users.',
|
||||
}),
|
||||
status: 'warning',
|
||||
shouldShow: (context: NagContext) => {
|
||||
const { hasEmptyAltText } = analyzeImageContent(context.project.body || '')
|
||||
@@ -219,7 +303,10 @@ export const descriptionNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings/description',
|
||||
title: messages.editDescriptionTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.edit-description.title',
|
||||
defaultMessage: 'Edit description',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings-description',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import { defineMessages } from '@vintl/vintl'
|
||||
|
||||
export default defineMessages({
|
||||
verifyExternalLinksTitle: {
|
||||
id: 'nags.verify-external-links.title',
|
||||
defaultMessage: 'Verify external links',
|
||||
},
|
||||
verifyExternalLinksDescription: {
|
||||
id: 'nags.verify-external-links.description',
|
||||
defaultMessage:
|
||||
"Some of your external links may be using domains that aren't recognized as common for their link type.",
|
||||
},
|
||||
invalidLicenseUrlTitle: {
|
||||
id: 'nags.invalid-license-url.title',
|
||||
defaultMessage: 'Invalid license URL',
|
||||
},
|
||||
invalidLicenseUrlDescriptionDefault: {
|
||||
id: 'nags.invalid-license-url.description.default',
|
||||
defaultMessage: 'License URL is invalid.',
|
||||
},
|
||||
invalidLicenseUrlDescriptionDomain: {
|
||||
id: 'nags.invalid-license-url.description.domain',
|
||||
defaultMessage:
|
||||
'Your license URL points to {domain}, which is not appropriate for license information. License URLs should link to the actual license text or legal documentation, not social media, gaming platforms etc.',
|
||||
},
|
||||
invalidLicenseUrlDescriptionMalformed: {
|
||||
id: 'nags.invalid-license-url.description.malformed',
|
||||
defaultMessage:
|
||||
'Your license URL appears to be malformed. Please provide a valid URL to your license text.',
|
||||
},
|
||||
gplLicenseSourceRequiredTitle: {
|
||||
id: 'nags.gpl-license-source-required.title',
|
||||
defaultMessage: 'GPL license requires source',
|
||||
},
|
||||
gplLicenseSourceRequiredDescription: {
|
||||
id: 'nags.gpl-license-source-required.description',
|
||||
defaultMessage:
|
||||
'Your {projectType} uses a GPL license which requires source code to be available. Please provide a source code link or consider using a different license.',
|
||||
},
|
||||
visitLinksSettingsTitle: {
|
||||
id: 'nags.visit-links-settings.title',
|
||||
defaultMessage: 'Visit links settings',
|
||||
},
|
||||
editLicenseTitle: {
|
||||
id: 'nags.edit-license.title',
|
||||
defaultMessage: 'Edit license',
|
||||
},
|
||||
})
|
||||
@@ -1,8 +1,6 @@
|
||||
import type { Nag, NagContext } from '../../types/nags'
|
||||
import { formatProjectType } from '@modrinth/utils'
|
||||
import { useVIntl } from '@vintl/vintl'
|
||||
|
||||
import messages from './links.i18n'
|
||||
import { useVIntl, defineMessage } from '@vintl/vintl'
|
||||
|
||||
export const commonLinkDomains = {
|
||||
source: ['github.com', 'gitlab.com', 'bitbucket.org', 'codeberg.org', 'git.sr.ht'],
|
||||
@@ -52,8 +50,15 @@ export function isUncommonLicenseUrl(url: string | undefined, domains: string[])
|
||||
export const linksNags: Nag[] = [
|
||||
{
|
||||
id: 'verify-external-links',
|
||||
title: messages.verifyExternalLinksTitle,
|
||||
description: messages.verifyExternalLinksDescription,
|
||||
title: defineMessage({
|
||||
id: 'nags.verify-external-links.title',
|
||||
defaultMessage: 'Verify external links',
|
||||
}),
|
||||
description: defineMessage({
|
||||
id: 'nags.verify-external-links.description',
|
||||
defaultMessage:
|
||||
"Some of your external links may be using domains that aren't recognized as common for their link type.",
|
||||
}),
|
||||
status: 'warning',
|
||||
shouldShow: (context: NagContext) => {
|
||||
return (
|
||||
@@ -64,26 +69,50 @@ export const linksNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings/links',
|
||||
title: messages.visitLinksSettingsTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.visit-links-settings.title',
|
||||
defaultMessage: 'Visit links settings',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings-links',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'invalid-license-url',
|
||||
title: messages.invalidLicenseUrlTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.invalid-license-url.title',
|
||||
defaultMessage: 'Invalid license URL',
|
||||
}),
|
||||
description: (context: NagContext) => {
|
||||
const { formatMessage } = useVIntl()
|
||||
const licenseUrl = context.project.license.url
|
||||
|
||||
if (!licenseUrl) {
|
||||
return formatMessage(messages.invalidLicenseUrlDescriptionDefault)
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'nags.invalid-license-url.description.default',
|
||||
defaultMessage: 'License URL is invalid.',
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
const domain = new URL(licenseUrl).hostname.toLowerCase()
|
||||
return formatMessage(messages.invalidLicenseUrlDescriptionDomain, { domain })
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'nags.invalid-license-url.description.domain',
|
||||
defaultMessage:
|
||||
'Your license URL points to {domain}, which is not appropriate for license information. License URLs should link to the actual license text or legal documentation, not social media, gaming platforms etc.',
|
||||
}),
|
||||
{ domain },
|
||||
)
|
||||
} catch {
|
||||
return formatMessage(messages.invalidLicenseUrlDescriptionMalformed)
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'nags.invalid-license-url.description.malformed',
|
||||
defaultMessage:
|
||||
'Your license URL appears to be malformed. Please provide a valid URL to your license text.',
|
||||
}),
|
||||
)
|
||||
}
|
||||
},
|
||||
status: 'required',
|
||||
@@ -102,19 +131,32 @@ export const linksNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings',
|
||||
title: messages.editLicenseTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.edit-license.title',
|
||||
defaultMessage: 'Edit license',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'gpl-license-source-required',
|
||||
title: messages.gplLicenseSourceRequiredTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.gpl-license-source-required.title',
|
||||
defaultMessage: 'GPL license requires source',
|
||||
}),
|
||||
description: (context: NagContext) => {
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
return formatMessage(messages.gplLicenseSourceRequiredDescription, {
|
||||
projectType: formatProjectType(context.project.project_type).toLowerCase(),
|
||||
})
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'nags.gpl-license-source-required.description',
|
||||
defaultMessage:
|
||||
'Your {projectType} uses a GPL license which requires source code to be available. Please provide a source code link or consider using a different license.',
|
||||
}),
|
||||
{
|
||||
projectType: formatProjectType(context.project.project_type).toLowerCase(),
|
||||
},
|
||||
)
|
||||
},
|
||||
status: 'required',
|
||||
shouldShow: (context: NagContext) => {
|
||||
@@ -148,7 +190,10 @@ export const linksNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings/links',
|
||||
title: messages.visitLinksSettingsTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.visit-links-settings.title',
|
||||
defaultMessage: 'Visit links settings',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings-links',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { defineMessages } from '@vintl/vintl'
|
||||
|
||||
export default defineMessages({
|
||||
tooManyTagsTitle: {
|
||||
id: 'nags.too-many-tags.title',
|
||||
defaultMessage: 'Too many tags selected',
|
||||
},
|
||||
tooManyTagsDescription: {
|
||||
id: 'nags.too-many-tags.description',
|
||||
defaultMessage:
|
||||
"You've selected {tagCount} tags. Consider reducing to 5 or fewer to keep your project focused and easier to discover.",
|
||||
},
|
||||
multipleResolutionTagsTitle: {
|
||||
id: 'nags.multiple-resolution-tags.title',
|
||||
defaultMessage: 'Multiple resolution tags selected',
|
||||
},
|
||||
multipleResolutionTagsDescription: {
|
||||
id: 'nags.multiple-resolution-tags.description',
|
||||
defaultMessage:
|
||||
"You've selected {count} resolution tags ({tags}). Resource packs should typically only have one resolution tag that matches their primary resolution.",
|
||||
},
|
||||
allTagsSelectedTitle: {
|
||||
id: 'nags.all-tags-selected.title',
|
||||
defaultMessage: 'All tags selected',
|
||||
},
|
||||
allTagsSelectedDescription: {
|
||||
id: 'nags.all-tags-selected.description',
|
||||
defaultMessage:
|
||||
"You've selected all {totalAvailableTags} available tags. This defeats the purpose of tags, which are meant to help users find relevant projects. Please select only the tags that truly apply to your project.",
|
||||
},
|
||||
editTagsTitle: {
|
||||
id: 'nags.edit-tags.title',
|
||||
defaultMessage: 'Edit tags',
|
||||
},
|
||||
})
|
||||
@@ -1,8 +1,6 @@
|
||||
import type { Project } from '@modrinth/utils'
|
||||
import type { Nag, NagContext } from '../../types/nags'
|
||||
import { useVIntl } from '@vintl/vintl'
|
||||
|
||||
import messages from './tags.i18n'
|
||||
import { useVIntl, defineMessage } from '@vintl/vintl'
|
||||
|
||||
function getCategories(
|
||||
project: Project & { actualProjectType: string },
|
||||
@@ -22,15 +20,25 @@ function getCategories(
|
||||
export const tagsNags: Nag[] = [
|
||||
{
|
||||
id: 'too-many-tags',
|
||||
title: messages.tooManyTagsTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.too-many-tags.title',
|
||||
defaultMessage: 'Too many tags selected',
|
||||
}),
|
||||
description: (context: NagContext) => {
|
||||
const { formatMessage } = useVIntl()
|
||||
const tagCount =
|
||||
context.project.categories.length + (context.project.additional_categories?.length || 0)
|
||||
|
||||
return formatMessage(messages.tooManyTagsDescription, {
|
||||
tagCount,
|
||||
})
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'nags.too-many-tags.description',
|
||||
defaultMessage:
|
||||
"You've selected {tagCount} tags. Consider reducing to 5 or fewer to keep your project focused and easier to discover.",
|
||||
}),
|
||||
{
|
||||
tagCount,
|
||||
},
|
||||
)
|
||||
},
|
||||
status: 'warning',
|
||||
shouldShow: (context: NagContext) => {
|
||||
@@ -40,23 +48,36 @@ export const tagsNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings/tags',
|
||||
title: messages.editTagsTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.edit-tags.title',
|
||||
defaultMessage: 'Edit tags',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings-tags',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'multiple-resolution-tags',
|
||||
title: messages.multipleResolutionTagsTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.multiple-resolution-tags.title',
|
||||
defaultMessage: 'Multiple resolution tags selected',
|
||||
}),
|
||||
description: (context: NagContext) => {
|
||||
const { formatMessage } = useVIntl()
|
||||
const resolutionTags = context.project.categories.filter((tag: string) =>
|
||||
['16x', '32x', '48x', '64x', '128x', '256x', '512x', '1024x'].includes(tag),
|
||||
)
|
||||
|
||||
return formatMessage(messages.multipleResolutionTagsDescription, {
|
||||
count: resolutionTags.length,
|
||||
tags: resolutionTags.join(', '),
|
||||
})
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'nags.multiple-resolution-tags.description',
|
||||
defaultMessage:
|
||||
"You've selected {count} resolution tags ({tags}). Resource packs should typically only have one resolution tag that matches their primary resolution.",
|
||||
}),
|
||||
{
|
||||
count: resolutionTags.length,
|
||||
tags: resolutionTags.join(', '),
|
||||
},
|
||||
)
|
||||
},
|
||||
status: 'warning',
|
||||
shouldShow: (context: NagContext) => {
|
||||
@@ -69,13 +90,19 @@ export const tagsNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings/tags',
|
||||
title: messages.editTagsTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.edit-tags.title',
|
||||
defaultMessage: 'Edit tags',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings-tags',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'all-tags-selected',
|
||||
title: messages.allTagsSelectedTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.all-tags-selected.title',
|
||||
defaultMessage: 'All tags selected',
|
||||
}),
|
||||
description: (context: NagContext) => {
|
||||
const { formatMessage } = useVIntl()
|
||||
const categoriesForProjectType = getCategories(
|
||||
@@ -84,9 +111,16 @@ export const tagsNags: Nag[] = [
|
||||
)
|
||||
const totalAvailableTags = categoriesForProjectType.length
|
||||
|
||||
return formatMessage(messages.allTagsSelectedDescription, {
|
||||
totalAvailableTags,
|
||||
})
|
||||
return formatMessage(
|
||||
defineMessage({
|
||||
id: 'nags.all-tags-selected.description',
|
||||
defaultMessage:
|
||||
"You've selected all {totalAvailableTags} available tags. This defeats the purpose of tags, which are meant to help users find relevant projects. Please select only the tags that truly apply to your project.",
|
||||
}),
|
||||
{
|
||||
totalAvailableTags,
|
||||
},
|
||||
)
|
||||
},
|
||||
status: 'required',
|
||||
shouldShow: (context: NagContext) => {
|
||||
@@ -100,7 +134,10 @@ export const tagsNags: Nag[] = [
|
||||
},
|
||||
link: {
|
||||
path: 'settings/tags',
|
||||
title: messages.editTagsTitle,
|
||||
title: defineMessage({
|
||||
id: 'nags.edit-tags.title',
|
||||
defaultMessage: 'Edit tags',
|
||||
}),
|
||||
shouldShow: (context: NagContext) => context.currentRoute !== 'type-id-settings-tags',
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user