mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
fix(i18n): translate remaining German hardcoded strings in PhotoUpload
Replace 6 hardcoded German strings in PhotoUpload.tsx with t() calls:
- 'Tag verknüpfen' → t('photos.linkDay')
- 'Kein Tag' / 'Tag N' → t('photos.noDay') / t('photos.dayLabel')
- '{N} Foto(s) ausgewählt' → t('photos.photoSelected/photosSelected')
- 'bis zu 30 Fotos' hint → t('photos.fileTypeHint')
- 'Wird hochgeladen...' → t('common.uploading')
Add all 6 new keys to all 14 language files and update test
assertions from German strings to English equivalents.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -50,7 +50,7 @@ describe('PhotoUpload', () => {
|
||||
|
||||
it('FE-COMP-PHOTOUPLOAD-002: options section hidden before files are selected', () => {
|
||||
render(<PhotoUpload {...defaultProps} />)
|
||||
expect(screen.queryByText('Tag verknüpfen')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('Link Day')).not.toBeInTheDocument()
|
||||
expect(screen.queryByPlaceholderText('Optional caption...')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
@@ -65,27 +65,27 @@ describe('PhotoUpload', () => {
|
||||
render(<PhotoUpload {...defaultProps} />)
|
||||
await uploadFiles([makeFile()])
|
||||
expect(screen.getByAltText('photo.jpg')).toBeInTheDocument()
|
||||
expect(screen.getByText('Tag verknüpfen')).toBeInTheDocument()
|
||||
expect(screen.getByText('Link Day')).toBeInTheDocument()
|
||||
expect(screen.getByPlaceholderText('Optional caption...')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('FE-COMP-PHOTOUPLOAD-005: file count label updates correctly', async () => {
|
||||
render(<PhotoUpload {...defaultProps} />)
|
||||
await uploadFiles([makeFile('photo1.jpg'), makeFile('photo2.jpg')])
|
||||
expect(screen.getByText('2 Fotos ausgewählt')).toBeInTheDocument()
|
||||
expect(screen.getByText('2 Photos selected')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('FE-COMP-PHOTOUPLOAD-006: remove button removes a file from preview', async () => {
|
||||
render(<PhotoUpload {...defaultProps} />)
|
||||
await uploadFiles([makeFile('photo1.jpg'), makeFile('photo2.jpg')])
|
||||
expect(screen.getByText('2 Fotos ausgewählt')).toBeInTheDocument()
|
||||
expect(screen.getByText('2 Photos selected')).toBeInTheDocument()
|
||||
|
||||
// Remove buttons are inside `.relative.aspect-square` wrappers in the preview grid
|
||||
const removeButtons = document.querySelectorAll('.relative.aspect-square button')
|
||||
expect(removeButtons.length).toBe(2)
|
||||
await userEvent.click(removeButtons[0])
|
||||
|
||||
expect(screen.getByText('1 Foto ausgewählt')).toBeInTheDocument()
|
||||
expect(screen.getByText('1 Photo selected')).toBeInTheDocument()
|
||||
expect(screen.getAllByRole('img').length).toBe(1)
|
||||
})
|
||||
|
||||
@@ -146,7 +146,7 @@ describe('PhotoUpload', () => {
|
||||
await userEvent.click(getSubmitButton())
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/wird hochgeladen/i)).toBeInTheDocument()
|
||||
expect(screen.getAllByText(/uploading/i).length).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
expect(getSubmitButton()).toBeDisabled()
|
||||
|
||||
@@ -90,7 +90,7 @@ export function PhotoUpload({ tripId, days, places, onUpload, onClose }: PhotoUp
|
||||
<>
|
||||
<p className="text-gray-600 font-medium">{t('photos.dropHereActive')}</p>
|
||||
<p className="text-gray-400 text-sm mt-1">{t('photos.clickToSelect')}</p>
|
||||
<p className="text-gray-400 text-xs mt-2">JPG, PNG, WebP · max. 10 MB · bis zu 30 Fotos</p>
|
||||
<p className="text-gray-400 text-xs mt-2">{t('photos.fileTypeHint')}</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
@@ -98,7 +98,7 @@ export function PhotoUpload({ tripId, days, places, onUpload, onClose }: PhotoUp
|
||||
{/* Preview grid */}
|
||||
{files.length > 0 && (
|
||||
<div>
|
||||
<p className="text-sm font-medium text-gray-700 mb-2">{files.length} Foto{files.length !== 1 ? 's' : ''} ausgewählt</p>
|
||||
<p className="text-sm font-medium text-gray-700 mb-2">{files.length} {t(files.length !== 1 ? 'photos.photosSelected' : 'photos.photoSelected')}</p>
|
||||
<div className="grid grid-cols-4 sm:grid-cols-6 gap-2 max-h-48 overflow-y-auto">
|
||||
{files.map((file, idx) => (
|
||||
<div key={idx} className="relative aspect-square group">
|
||||
@@ -126,15 +126,15 @@ export function PhotoUpload({ tripId, days, places, onUpload, onClose }: PhotoUp
|
||||
{files.length > 0 && (
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-gray-700 mb-1">Tag verknüpfen</label>
|
||||
<label className="block text-xs font-medium text-gray-700 mb-1">{t('photos.linkDay')}</label>
|
||||
<select
|
||||
value={dayId}
|
||||
onChange={e => setDayId(e.target.value)}
|
||||
className="w-full border border-gray-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-slate-900"
|
||||
>
|
||||
<option value="">Kein Tag</option>
|
||||
<option value="">{t('photos.noDay')}</option>
|
||||
{(days || []).map(day => (
|
||||
<option key={day.id} value={day.id}>Tag {day.day_number}</option>
|
||||
<option key={day.id} value={day.id}>{t('photos.dayLabel', { number: day.day_number })}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
@@ -169,7 +169,7 @@ export function PhotoUpload({ tripId, days, places, onUpload, onClose }: PhotoUp
|
||||
<div className="bg-slate-50 rounded-lg p-3">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<div className="w-4 h-4 border-2 border-slate-900 border-t-transparent rounded-full animate-spin" />
|
||||
<span className="text-sm text-slate-900">Wird hochgeladen...</span>
|
||||
<span className="text-sm text-slate-900">{t('common.uploading')}</span>
|
||||
</div>
|
||||
<div className="w-full bg-slate-200 rounded-full h-1.5">
|
||||
<div
|
||||
|
||||
@@ -1357,6 +1357,12 @@ const ar: Record<string, string | { name: string; category: string }[]> = {
|
||||
'photos.linkPlace': 'ربط بمكان',
|
||||
'photos.noPlace': 'بلا مكان',
|
||||
'photos.uploadN': 'رفع {n} صورة',
|
||||
'photos.linkDay': 'ربط اليوم',
|
||||
'photos.noDay': 'لا يوم',
|
||||
'photos.dayLabel': 'اليوم {number}',
|
||||
'photos.photoSelected': 'صورة محددة',
|
||||
'photos.photosSelected': 'صور محددة',
|
||||
'photos.fileTypeHint': 'JPG, PNG, WebP · الحد الأقصى 10 ميغابايت · حتى 30 صورة',
|
||||
|
||||
// Backup restore modal
|
||||
'backup.restoreConfirmTitle': 'استعادة النسخة الاحتياطية؟',
|
||||
|
||||
@@ -1329,6 +1329,12 @@ const br: Record<string, string | { name: string; category: string }[]> = {
|
||||
'photos.linkPlace': 'Vincular lugar',
|
||||
'photos.noPlace': 'Sem lugar',
|
||||
'photos.uploadN': 'Enviar {n} foto(s)',
|
||||
'photos.linkDay': 'Vincular dia',
|
||||
'photos.noDay': 'Nenhum dia',
|
||||
'photos.dayLabel': 'Dia {number}',
|
||||
'photos.photoSelected': 'Foto selecionada',
|
||||
'photos.photosSelected': 'Fotos selecionadas',
|
||||
'photos.fileTypeHint': 'JPG, PNG, WebP · máx. 10 MB · até 30 fotos',
|
||||
|
||||
// Backup restore modal
|
||||
'backup.restoreConfirmTitle': 'Restaurar backup?',
|
||||
|
||||
@@ -1355,6 +1355,12 @@ const cs: Record<string, string | { name: string; category: string }[]> = {
|
||||
'photos.linkPlace': 'Propojit s místem',
|
||||
'photos.noPlace': 'Žádné místo',
|
||||
'photos.uploadN': 'Nahrát {n} fotek',
|
||||
'photos.linkDay': 'Propojit den',
|
||||
'photos.noDay': 'Žádný den',
|
||||
'photos.dayLabel': 'Den {number}',
|
||||
'photos.photoSelected': 'Fotografie vybrána',
|
||||
'photos.photosSelected': 'Fotografie vybrány',
|
||||
'photos.fileTypeHint': 'JPG, PNG, WebP · max. 10 MB · až 30 fotografií',
|
||||
|
||||
// Obnovení zálohy
|
||||
'backup.restoreConfirmTitle': 'Obnovit zálohu?',
|
||||
|
||||
@@ -1356,6 +1356,12 @@ const de: Record<string, string | { name: string; category: string }[]> = {
|
||||
'photos.linkPlace': 'Ort verknüpfen',
|
||||
'photos.noPlace': 'Kein Ort',
|
||||
'photos.uploadN': '{n} Foto(s) hochladen',
|
||||
'photos.linkDay': 'Tag verknüpfen',
|
||||
'photos.noDay': 'Kein Tag',
|
||||
'photos.dayLabel': 'Tag {number}',
|
||||
'photos.photoSelected': 'Foto ausgewählt',
|
||||
'photos.photosSelected': 'Fotos ausgewählt',
|
||||
'photos.fileTypeHint': 'JPG, PNG, WebP · max. 10 MB · bis zu 30 Fotos',
|
||||
|
||||
// Backup restore modal
|
||||
'backup.restoreConfirmTitle': 'Backup wiederherstellen?',
|
||||
|
||||
@@ -1378,6 +1378,12 @@ const en: Record<string, string | { name: string; category: string }[]> = {
|
||||
'photos.linkPlace': 'Link Place',
|
||||
'photos.noPlace': 'No Place',
|
||||
'photos.uploadN': '{n} photo(s) upload',
|
||||
'photos.linkDay': 'Link Day',
|
||||
'photos.noDay': 'No Day',
|
||||
'photos.dayLabel': 'Day {number}',
|
||||
'photos.photoSelected': 'Photo selected',
|
||||
'photos.photosSelected': 'Photos selected',
|
||||
'photos.fileTypeHint': 'JPG, PNG, WebP · max. 10 MB · up to 30 photos',
|
||||
|
||||
// Backup restore modal
|
||||
'backup.restoreConfirmTitle': 'Restore Backup?',
|
||||
|
||||
@@ -1294,6 +1294,12 @@ const es: Record<string, string> = {
|
||||
'photos.linkPlace': 'Vincular lugar',
|
||||
'photos.noPlace': 'Sin lugar',
|
||||
'photos.uploadN': 'Subida de {n} foto(s)',
|
||||
'photos.linkDay': 'Vincular día',
|
||||
'photos.noDay': 'Ningún día',
|
||||
'photos.dayLabel': 'Día {number}',
|
||||
'photos.photoSelected': 'Foto seleccionada',
|
||||
'photos.photosSelected': 'Fotos seleccionadas',
|
||||
'photos.fileTypeHint': 'JPG, PNG, WebP · máx. 10 MB · hasta 30 fotos',
|
||||
'admin.addons.catalog.memories.name': 'Fotos (Immich)',
|
||||
'admin.addons.catalog.memories.description': 'Comparte fotos de viaje a través de tu instancia de Immich',
|
||||
'admin.addons.catalog.mcp.name': 'MCP',
|
||||
|
||||
@@ -1356,6 +1356,12 @@ const fr: Record<string, string> = {
|
||||
'photos.linkPlace': 'Lier au lieu',
|
||||
'photos.noPlace': 'Aucun lieu',
|
||||
'photos.uploadN': '{n} photo(s) importée(s)',
|
||||
'photos.linkDay': 'Lier le jour',
|
||||
'photos.noDay': 'Aucun jour',
|
||||
'photos.dayLabel': 'Jour {number}',
|
||||
'photos.photoSelected': 'Photo sélectionnée',
|
||||
'photos.photosSelected': 'Photos sélectionnées',
|
||||
'photos.fileTypeHint': "JPG, PNG, WebP · max. 10 Mo · jusqu'à 30 photos",
|
||||
|
||||
// Backup restore modal
|
||||
'backup.restoreConfirmTitle': 'Restaurer la sauvegarde ?',
|
||||
|
||||
@@ -1354,6 +1354,12 @@ const hu: Record<string, string | { name: string; category: string }[]> = {
|
||||
'photos.linkPlace': 'Hely társítása',
|
||||
'photos.noPlace': 'Nincs hely',
|
||||
'photos.uploadN': '{n} fotó feltöltése',
|
||||
'photos.linkDay': 'Nap csatolása',
|
||||
'photos.noDay': 'Nincs nap',
|
||||
'photos.dayLabel': '{number}. nap',
|
||||
'photos.photoSelected': 'Fotó kiválasztva',
|
||||
'photos.photosSelected': 'Fotók kiválasztva',
|
||||
'photos.fileTypeHint': 'JPG, PNG, WebP · max. 10 MB · legfeljebb 30 fotó',
|
||||
|
||||
// Mentés visszaállítása modal
|
||||
'backup.restoreConfirmTitle': 'Mentés visszaállítása?',
|
||||
|
||||
@@ -1354,6 +1354,12 @@ const it: Record<string, string | { name: string; category: string }[]> = {
|
||||
'photos.linkPlace': 'Collega luogo',
|
||||
'photos.noPlace': 'Nessun luogo',
|
||||
'photos.uploadN': 'Caricamento di {n} foto',
|
||||
'photos.linkDay': 'Collega giorno',
|
||||
'photos.noDay': 'Nessun giorno',
|
||||
'photos.dayLabel': 'Giorno {number}',
|
||||
'photos.photoSelected': 'Foto selezionata',
|
||||
'photos.photosSelected': 'Foto selezionate',
|
||||
'photos.fileTypeHint': 'JPG, PNG, WebP · max. 10 MB · fino a 30 foto',
|
||||
|
||||
// Backup restore modal
|
||||
'backup.restoreConfirmTitle': 'Ripristinare il backup?',
|
||||
|
||||
@@ -1353,6 +1353,12 @@ const nl: Record<string, string> = {
|
||||
'photos.linkPlace': 'Koppel plaats',
|
||||
'photos.noPlace': 'Geen plaats',
|
||||
'photos.uploadN': '{n} foto(\'s) uploaden',
|
||||
'photos.linkDay': 'Dag koppelen',
|
||||
'photos.noDay': 'Geen dag',
|
||||
'photos.dayLabel': 'Dag {number}',
|
||||
'photos.photoSelected': 'Foto geselecteerd',
|
||||
'photos.photosSelected': "Foto's geselecteerd",
|
||||
'photos.fileTypeHint': "JPG, PNG, WebP · max. 10 MB · tot 30 foto's",
|
||||
|
||||
// Backup restore modal
|
||||
'backup.restoreConfirmTitle': 'Back-up herstellen?',
|
||||
|
||||
@@ -1314,6 +1314,12 @@ const pl: Record<string, string | { name: string; category: string }[]> = {
|
||||
'photos.linkPlace': 'Połącz z miejscem',
|
||||
'photos.noPlace': 'Brak miejsca',
|
||||
'photos.uploadN': 'Prześlij {n} zdjęć',
|
||||
'photos.linkDay': 'Połącz dzień',
|
||||
'photos.noDay': 'Brak dnia',
|
||||
'photos.dayLabel': 'Dzień {number}',
|
||||
'photos.photoSelected': 'Zdjęcie wybrane',
|
||||
'photos.photosSelected': 'Zdjęcia wybrane',
|
||||
'photos.fileTypeHint': 'JPG, PNG, WebP · maks. 10 MB · do 30 zdjęć',
|
||||
|
||||
// Backup restore modal
|
||||
'backup.restoreConfirmTitle': 'Przywrócić kopię zapasową?',
|
||||
|
||||
@@ -1353,6 +1353,12 @@ const ru: Record<string, string> = {
|
||||
'photos.linkPlace': 'Привязать место',
|
||||
'photos.noPlace': 'Без места',
|
||||
'photos.uploadN': '{n} фото загружено',
|
||||
'photos.linkDay': 'Связать день',
|
||||
'photos.noDay': 'Нет дня',
|
||||
'photos.dayLabel': 'День {number}',
|
||||
'photos.photoSelected': 'Фото выбрано',
|
||||
'photos.photosSelected': 'Фото выбраны',
|
||||
'photos.fileTypeHint': 'JPG, PNG, WebP · макс. 10 МБ · до 30 фото',
|
||||
|
||||
// Backup restore modal
|
||||
'backup.restoreConfirmTitle': 'Восстановить копию?',
|
||||
|
||||
@@ -1353,6 +1353,12 @@ const zh: Record<string, string> = {
|
||||
'photos.linkPlace': '关联地点',
|
||||
'photos.noPlace': '无地点',
|
||||
'photos.uploadN': '上传 {n} 张照片',
|
||||
'photos.linkDay': '关联天数',
|
||||
'photos.noDay': '无天数',
|
||||
'photos.dayLabel': '第 {number} 天',
|
||||
'photos.photoSelected': '张照片已选择',
|
||||
'photos.photosSelected': '张照片已选择',
|
||||
'photos.fileTypeHint': 'JPG, PNG, WebP · 最大 10 MB · 最多 30 张照片',
|
||||
|
||||
// Backup restore modal
|
||||
'backup.restoreConfirmTitle': '恢复备份?',
|
||||
|
||||
@@ -1379,6 +1379,12 @@ const zhTw: Record<string, string> = {
|
||||
'photos.linkPlace': '關聯地點',
|
||||
'photos.noPlace': '無地點',
|
||||
'photos.uploadN': '上傳 {n} 張照片',
|
||||
'photos.linkDay': '關聯天數',
|
||||
'photos.noDay': '無天數',
|
||||
'photos.dayLabel': '第 {number} 天',
|
||||
'photos.photoSelected': '張照片已選擇',
|
||||
'photos.photosSelected': '張照片已選擇',
|
||||
'photos.fileTypeHint': 'JPG, PNG, WebP · 最大 10 MB · 最多 30 張照片',
|
||||
|
||||
// Backup restore modal
|
||||
'backup.restoreConfirmTitle': '恢復備份?',
|
||||
|
||||
Reference in New Issue
Block a user