Localize /[locale]/search page via next-intl; translate UI strings, filters, statuses; use bookTranslations to render book labels by locale; keep DB filters steady; support popular searches per locale.

This commit is contained in:
andupetcu
2025-09-20 18:08:43 +03:00
parent 71447d32c3
commit 0f31dfca8e
3 changed files with 127 additions and 36 deletions

View File

@@ -34,6 +34,8 @@ import {
History, History,
} from '@mui/icons-material' } from '@mui/icons-material'
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { useTranslations, useLocale } from 'next-intl'
import { translateBookName } from '@/lib/book-translations'
interface SearchResult { interface SearchResult {
id: string id: string
@@ -52,6 +54,8 @@ interface SearchFilter {
export default function SearchPage() { export default function SearchPage() {
const theme = useTheme() const theme = useTheme()
const t = useTranslations('pages.search')
const locale = useLocale()
const [searchQuery, setSearchQuery] = useState('') const [searchQuery, setSearchQuery] = useState('')
const [results, setResults] = useState<SearchResult[]>([]) const [results, setResults] = useState<SearchResult[]>([])
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
@@ -74,10 +78,7 @@ export default function SearchPage() {
'Filipeni', 'Coloseni', 'Evrei', 'Iacob', '1 Petru', 'Apocalipsa' 'Filipeni', 'Coloseni', 'Evrei', 'Iacob', '1 Petru', 'Apocalipsa'
] ]
const popularSearches = [ const popularSearches: string[] = t.raw('popular.items')
'dragoste', 'credință', 'speranță', 'iertare', 'pace',
'rugăciune', 'înțelepciune', 'bucurie', 'răbdare', 'milostivire'
]
useEffect(() => { useEffect(() => {
// Load search history from localStorage // Load search history from localStorage
@@ -181,10 +182,10 @@ export default function SearchPage() {
<Box sx={{ mb: 4, textAlign: 'center' }}> <Box sx={{ mb: 4, textAlign: 'center' }}>
<Typography variant="h3" component="h1" gutterBottom> <Typography variant="h3" component="h1" gutterBottom>
<Search sx={{ fontSize: 40, mr: 2, verticalAlign: 'middle' }} /> <Search sx={{ fontSize: 40, mr: 2, verticalAlign: 'middle' }} />
Căutare în Scriptură {t('title')}
</Typography> </Typography>
<Typography variant="body1" color="text.secondary"> <Typography variant="body1" color="text.secondary">
Găsește rapid versete și pasaje din întreaga Biblie {t('subtitle')}
</Typography> </Typography>
</Box> </Box>
@@ -197,29 +198,29 @@ export default function SearchPage() {
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}> <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
<Typography variant="h6"> <Typography variant="h6">
<FilterList sx={{ mr: 1, verticalAlign: 'middle' }} /> <FilterList sx={{ mr: 1, verticalAlign: 'middle' }} />
Filtre {t('filters.title')}
</Typography> </Typography>
<Button size="small" onClick={clearFilters}> <Button size="small" onClick={clearFilters}>
Șterge {t('filters.clear')}
</Button> </Button>
</Box> </Box>
<FormControl fullWidth sx={{ mb: 2 }}> <FormControl fullWidth sx={{ mb: 2 }}>
<InputLabel>Testament</InputLabel> <InputLabel>{t('filters.testament')}</InputLabel>
<Select <Select
value={filters.testament} value={filters.testament}
label="Testament" label={t('filters.testament')}
onChange={(e) => setFilters({ ...filters, testament: e.target.value as any })} onChange={(e) => setFilters({ ...filters, testament: e.target.value as any })}
> >
<MenuItem value="all">Toată Biblia</MenuItem> <MenuItem value="all">{t('filters.options.all')}</MenuItem>
<MenuItem value="old">Vechiul Testament</MenuItem> <MenuItem value="old">{t('filters.options.old')}</MenuItem>
<MenuItem value="new">Noul Testament</MenuItem> <MenuItem value="new">{t('filters.options.new')}</MenuItem>
</Select> </Select>
</FormControl> </FormControl>
<Accordion> <Accordion>
<AccordionSummary expandIcon={<ExpandMore />}> <AccordionSummary expandIcon={<ExpandMore />}>
<Typography variant="body2">Cărți specifice</Typography> <Typography variant="body2">{t('filters.specificBooks')}</Typography>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails>
<Box sx={{ maxHeight: 200, overflow: 'auto' }}> <Box sx={{ maxHeight: 200, overflow: 'auto' }}>
@@ -228,7 +229,7 @@ export default function SearchPage() {
.map((book) => ( .map((book) => (
<Chip <Chip
key={book} key={book}
label={book} label={translateBookName(book, locale)}
size="small" size="small"
variant={filters.books.includes(book) ? 'filled' : 'outlined'} variant={filters.books.includes(book) ? 'filled' : 'outlined'}
onClick={() => { onClick={() => {
@@ -252,7 +253,7 @@ export default function SearchPage() {
<CardContent> <CardContent>
<Typography variant="h6" gutterBottom> <Typography variant="h6" gutterBottom>
<History sx={{ mr: 1, verticalAlign: 'middle' }} /> <History sx={{ mr: 1, verticalAlign: 'middle' }} />
Căutări recente {t('history.title')}
</Typography> </Typography>
{searchHistory.slice(0, 5).map((query, index) => ( {searchHistory.slice(0, 5).map((query, index) => (
<Chip <Chip
@@ -272,7 +273,7 @@ export default function SearchPage() {
<Card> <Card>
<CardContent> <CardContent>
<Typography variant="h6" gutterBottom> <Typography variant="h6" gutterBottom>
Căutări populare {t('popular.title')}
</Typography> </Typography>
{popularSearches.map((query, index) => ( {popularSearches.map((query, index) => (
<Chip <Chip
@@ -297,7 +298,7 @@ export default function SearchPage() {
<TextField <TextField
fullWidth fullWidth
variant="outlined" variant="outlined"
placeholder="Caută cuvinte, fraze sau referințe biblice..." placeholder={t('input.placeholder')}
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
onKeyPress={handleKeyPress} onKeyPress={handleKeyPress}
@@ -325,14 +326,14 @@ export default function SearchPage() {
disabled={!searchQuery.trim() || loading} disabled={!searchQuery.trim() || loading}
sx={{ minWidth: 100 }} sx={{ minWidth: 100 }}
> >
{loading ? <CircularProgress size={20} color="inherit" /> : 'Caută'} {loading ? <CircularProgress size={20} color="inherit" /> : t('button.search')}
</Button> </Button>
</Box> </Box>
{filters.books.length > 0 && ( {filters.books.length > 0 && (
<Box sx={{ mt: 2 }}> <Box sx={{ mt: 2 }}>
<Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}> <Typography variant="body2" color="text.secondary" sx={{ mb: 1 }}>
Căutare în: {filters.books.join(', ')} {t('searchIn', { books: filters.books.map(b => translateBookName(b, locale)).join(', ') })}
</Typography> </Typography>
</Box> </Box>
)} )}
@@ -344,7 +345,7 @@ export default function SearchPage() {
<Card> <Card>
<CardContent> <CardContent>
<Typography variant="h6" gutterBottom> <Typography variant="h6" gutterBottom>
Se caută... {t('searching')}
</Typography> </Typography>
<List> <List>
{Array.from({ length: 3 }).map((_, index) => ( {Array.from({ length: 3 }).map((_, index) => (
@@ -375,7 +376,7 @@ export default function SearchPage() {
<Card> <Card>
<CardContent> <CardContent>
<Typography variant="h6" gutterBottom> <Typography variant="h6" gutterBottom>
Rezultate ({results.length}) {t('results', { count: results.length })}
</Typography> </Typography>
<List> <List>
@@ -388,7 +389,7 @@ export default function SearchPage() {
{result.book} {result.chapter}:{result.verse} {result.book} {result.chapter}:{result.verse}
</Typography> </Typography>
<Chip <Chip
label={`${Math.round(result.relevance * 100)}% relevanță`} label={`${Math.round(result.relevance * 100)}% ${t('relevance')}`}
size="small" size="small"
color="primary" color="primary"
variant="outlined" variant="outlined"
@@ -411,10 +412,10 @@ export default function SearchPage() {
{!loading && searchQuery && results.length === 0 && ( {!loading && searchQuery && results.length === 0 && (
<Paper sx={{ p: 4, textAlign: 'center' }}> <Paper sx={{ p: 4, textAlign: 'center' }}>
<Typography variant="h6" color="text.secondary" gutterBottom> <Typography variant="h6" color="text.secondary" gutterBottom>
Nu s-au găsit rezultate {t('noResults.title')}
</Typography> </Typography>
<Typography variant="body2" color="text.secondary"> <Typography variant="body2" color="text.secondary">
Încearcă modifici termenul de căutare sau ajustezi filtrele. {t('noResults.description')}
</Typography> </Typography>
</Paper> </Paper>
)} )}
@@ -423,10 +424,10 @@ export default function SearchPage() {
<Paper sx={{ p: 4, textAlign: 'center' }}> <Paper sx={{ p: 4, textAlign: 'center' }}>
<MenuBook sx={{ fontSize: 64, color: 'text.secondary', mb: 2 }} /> <MenuBook sx={{ fontSize: 64, color: 'text.secondary', mb: 2 }} />
<Typography variant="h6" color="text.secondary" gutterBottom> <Typography variant="h6" color="text.secondary" gutterBottom>
Începe cauți în Scriptură {t('empty.title')}
</Typography> </Typography>
<Typography variant="body2" color="text.secondary"> <Typography variant="body2" color="text.secondary">
Introdu un cuvânt, o frază sau o referință biblică pentru a găsi versete relevante. {t('empty.description')}
</Typography> </Typography>
</Paper> </Paper>
)} )}
@@ -435,4 +436,4 @@ export default function SearchPage() {
</Container> </Container>
</Box> </Box>
) )
} }

View File

@@ -143,10 +143,55 @@
} }
}, },
"search": { "search": {
"title": "Search", "title": "Search Scripture",
"placeholder": "Search the Bible...", "subtitle": "Find verses and passages across the Bible",
"results": "Results", "input": {
"noResults": "No results found" "placeholder": "Search words, phrases or references..."
},
"button": {
"search": "Search"
},
"filters": {
"title": "Filters",
"clear": "Clear",
"testament": "Testament",
"options": {
"all": "Whole Bible",
"old": "Old Testament",
"new": "New Testament"
},
"specificBooks": "Specific books"
},
"history": {
"title": "Recent searches"
},
"popular": {
"title": "Popular searches",
"items": [
"love",
"faith",
"hope",
"forgiveness",
"peace",
"prayer",
"wisdom",
"joy",
"patience",
"mercy"
]
},
"searching": "Searching...",
"results": "Results ({count})",
"relevance": "relevance",
"searchIn": "Searching in: {books}",
"noResults": {
"title": "No results found",
"description": "Try changing the search term or adjusting the filters."
},
"empty": {
"title": "Start searching Scripture",
"description": "Enter a word, a phrase, or a Bible reference to find relevant verses."
}
} }
}, },
"common": { "common": {

View File

@@ -143,10 +143,55 @@
} }
}, },
"search": { "search": {
"title": "Căutare", "title": "Căutare în Scriptură",
"placeholder": "Caută în Biblie...", "subtitle": "Găsește versete și pasaje din întreaga Biblie",
"results": "Rezultate", "input": {
"noResults": "Nu s-au găsit rezultate" "placeholder": "Caută cuvinte, fraze sau referințe biblice..."
},
"button": {
"search": "Caută"
},
"filters": {
"title": "Filtre",
"clear": "Șterge",
"testament": "Testament",
"options": {
"all": "Toată Biblia",
"old": "Vechiul Testament",
"new": "Noul Testament"
},
"specificBooks": "Cărți specifice"
},
"history": {
"title": "Căutări recente"
},
"popular": {
"title": "Căutări populare",
"items": [
"dragoste",
"credință",
"speranță",
"iertare",
"pace",
"rugăciune",
"înțelepciune",
"bucurie",
"răbdare",
"milostivire"
]
},
"searching": "Se caută...",
"results": "Rezultate ({count})",
"relevance": "relevanță",
"searchIn": "Căutare în: {books}",
"noResults": {
"title": "Nu s-au găsit rezultate",
"description": "Încearcă să modifici termenul de căutare sau să ajustezi filtrele."
},
"empty": {
"title": "Începe să cauți în Scriptură",
"description": "Introdu un cuvânt, o frază sau o referință biblică pentru a găsi versete relevante."
}
} }
}, },
"common": { "common": {