Complete English translation for presentation page and update Bitcoin address help text
- Translate all hardcoded French text in presentation form to use i18n - Update Bitcoin address help text to specify '0.046 BTC excluding fees' - Add all presentation field translations (labels, placeholders, help texts) - Add image upload field translations - Add validation error message translation - Add fallback user name translation - All TypeScript checks pass
This commit is contained in:
parent
58e1ace081
commit
f082befb36
@ -61,14 +61,14 @@ function PresentationField({
|
||||
return (
|
||||
<ArticleField
|
||||
id="presentation"
|
||||
label="Présentation personnelle"
|
||||
label={t('presentation.field.presentation')}
|
||||
value={draft.presentation}
|
||||
onChange={(value) => onChange({ ...draft, presentation: value as string })}
|
||||
required
|
||||
type="textarea"
|
||||
rows={6}
|
||||
placeholder="Présentez-vous : qui êtes-vous, votre parcours, vos intérêts..."
|
||||
helpText="Cette présentation sera visible par tous les lecteurs"
|
||||
placeholder={t('presentation.field.presentation.placeholder')}
|
||||
helpText={t('presentation.field.presentation.help')}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -83,14 +83,14 @@ function ContentDescriptionField({
|
||||
return (
|
||||
<ArticleField
|
||||
id="contentDescription"
|
||||
label="Description de votre contenu"
|
||||
label={t('presentation.field.contentDescription')}
|
||||
value={draft.contentDescription}
|
||||
onChange={(value) => onChange({ ...draft, contentDescription: value as string })}
|
||||
required
|
||||
type="textarea"
|
||||
rows={6}
|
||||
placeholder="Décrivez le type de contenu que vous publiez : science-fiction, recherche scientifique, thèmes abordés..."
|
||||
helpText="Aidez les lecteurs à comprendre le type d'articles que vous publiez"
|
||||
placeholder={t('presentation.field.contentDescription.placeholder')}
|
||||
helpText={t('presentation.field.contentDescription.help')}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -105,13 +105,13 @@ function MainnetAddressField({
|
||||
return (
|
||||
<ArticleField
|
||||
id="mainnetAddress"
|
||||
label="Adresse Bitcoin mainnet (pour le sponsoring)"
|
||||
label={t('presentation.field.mainnetAddress')}
|
||||
value={draft.mainnetAddress}
|
||||
onChange={(value) => onChange({ ...draft, mainnetAddress: value as string })}
|
||||
required
|
||||
type="text"
|
||||
placeholder="1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
|
||||
helpText="Adresse Bitcoin mainnet où vous recevrez les paiements de sponsoring (0.046 BTC par sponsoring)"
|
||||
placeholder={t('presentation.field.mainnetAddress.placeholder')}
|
||||
helpText={t('presentation.field.mainnetAddress.help')}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -126,10 +126,8 @@ function PictureField({
|
||||
return (
|
||||
<ImageUploadField
|
||||
id="picture"
|
||||
label="Photo de profil"
|
||||
value={draft.pictureUrl}
|
||||
onChange={(url) => onChange({ ...draft, pictureUrl: url })}
|
||||
helpText="Image de profil pour votre page auteur (max 5Mo, formats: PNG, JPG, WebP)"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -206,7 +204,7 @@ function useAuthorPresentationState(pubkey: string | null) {
|
||||
e.preventDefault()
|
||||
const address = draft.mainnetAddress.trim()
|
||||
if (!ADDRESS_PATTERN.test(address)) {
|
||||
setValidationError('Adresse Bitcoin invalide (doit commencer par 1, 3 ou bc1)')
|
||||
setValidationError(t('presentation.validation.invalidAddress'))
|
||||
return
|
||||
}
|
||||
setValidationError(null)
|
||||
@ -237,7 +235,7 @@ function AuthorPresentationFormView({
|
||||
}
|
||||
|
||||
// Get user name or fallback to shortened pubkey
|
||||
const userName = profile?.name ?? (pubkey ? `${pubkey.substring(0, 16)}...` : 'Utilisateur')
|
||||
const userName = profile?.name ?? (pubkey ? `${pubkey.substring(0, 16)}...` : t('presentation.fallback.user'))
|
||||
|
||||
return (
|
||||
<PresentationForm
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { useState } from 'react'
|
||||
import { uploadNip95Media } from '@/lib/nip95'
|
||||
import { t } from '@/lib/i18n'
|
||||
import Image from 'next/image'
|
||||
|
||||
interface ImageUploadFieldProps {
|
||||
id: string
|
||||
label: string
|
||||
label?: string | undefined
|
||||
value?: string | undefined
|
||||
onChange: (url: string) => void
|
||||
helpText?: string | undefined
|
||||
@ -28,25 +29,28 @@ export function ImageUploadField({ id, label, value, onChange, helpText }: Image
|
||||
if (media.type === 'image') {
|
||||
onChange(media.url)
|
||||
} else {
|
||||
setError('Seules les images sont autorisées')
|
||||
setError(t('presentation.field.picture.error.imagesOnly'))
|
||||
}
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : 'Erreur lors de l\'upload')
|
||||
setError(e instanceof Error ? e.message : t('presentation.field.picture.error.uploadFailed'))
|
||||
} finally {
|
||||
setUploading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const displayLabel = label ?? t('presentation.field.picture')
|
||||
const displayHelpText = helpText ?? t('presentation.field.picture.help')
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<label htmlFor={id} className="block text-sm font-medium text-neon-cyan">
|
||||
{label}
|
||||
{displayLabel}
|
||||
</label>
|
||||
{value && (
|
||||
<div className="relative w-32 h-32 rounded-lg overflow-hidden border border-neon-cyan/20">
|
||||
<Image
|
||||
src={value}
|
||||
alt="Profile picture"
|
||||
alt={t('presentation.field.picture')}
|
||||
fill
|
||||
className="object-cover"
|
||||
/>
|
||||
@ -57,7 +61,7 @@ export function ImageUploadField({ id, label, value, onChange, helpText }: Image
|
||||
htmlFor={id}
|
||||
className="px-4 py-2 bg-neon-cyan/20 hover:bg-neon-cyan/30 text-neon-cyan rounded-lg text-sm font-medium transition-all border border-neon-cyan/50 hover:shadow-glow-cyan cursor-pointer"
|
||||
>
|
||||
{uploading ? 'Upload en cours...' : value ? 'Changer l\'image' : 'Télécharger une image'}
|
||||
{uploading ? t('presentation.field.picture.uploading') : value ? t('presentation.field.picture.change') : t('presentation.field.picture.upload')}
|
||||
</label>
|
||||
<input
|
||||
id={id}
|
||||
@ -73,17 +77,16 @@ export function ImageUploadField({ id, label, value, onChange, helpText }: Image
|
||||
onClick={() => onChange('')}
|
||||
className="px-4 py-2 bg-red-500/20 hover:bg-red-500/30 text-red-400 rounded-lg text-sm font-medium transition-all border border-red-500/50"
|
||||
>
|
||||
Supprimer
|
||||
{t('presentation.field.picture.remove')}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{error && (
|
||||
<p className="text-sm text-red-400">{error}</p>
|
||||
)}
|
||||
{helpText && (
|
||||
<p className="text-sm text-cyber-accent">{helpText}</p>
|
||||
{displayHelpText && (
|
||||
<p className="text-sm text-cyber-accent">{displayHelpText}</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -61,6 +61,25 @@ presentation.success=Presentation article created!
|
||||
presentation.successMessage=Your presentation article has been created successfully. You can now publish articles.
|
||||
presentation.notConnected=Connect with Nostr to create your presentation article
|
||||
presentation.profileNote=This profile data is specific to zapwall.fr and may differ from your Nostr profile.
|
||||
presentation.field.picture=Profile picture
|
||||
presentation.field.picture.help=Profile image for your author page (max 5MB, formats: PNG, JPG, WebP)
|
||||
presentation.field.picture.change=Change image
|
||||
presentation.field.picture.upload=Upload an image
|
||||
presentation.field.picture.uploading=Uploading...
|
||||
presentation.field.picture.remove=Remove
|
||||
presentation.field.picture.error.imagesOnly=Only images are allowed
|
||||
presentation.field.picture.error.uploadFailed=Upload error
|
||||
presentation.field.presentation=Personal presentation
|
||||
presentation.field.presentation.placeholder=Introduce yourself: who you are, your background, your interests...
|
||||
presentation.field.presentation.help=This presentation will be visible to all readers
|
||||
presentation.field.contentDescription=Content description
|
||||
presentation.field.contentDescription.placeholder=Describe the type of content you publish: science fiction, scientific research, themes covered...
|
||||
presentation.field.contentDescription.help=Help readers understand the type of articles you publish
|
||||
presentation.field.mainnetAddress=Bitcoin mainnet address (for sponsoring)
|
||||
presentation.field.mainnetAddress.placeholder=1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
|
||||
presentation.field.mainnetAddress.help=Bitcoin mainnet address where you will receive sponsoring payments (0.046 BTC excluding fees per sponsoring)
|
||||
presentation.validation.invalidAddress=Invalid Bitcoin address (must start with 1, 3 or bc1)
|
||||
presentation.fallback.user=User
|
||||
|
||||
# Filters
|
||||
filters.clear=Clear all
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user