feat(i18n): Implement multilingual support with Polish and English translations

- Added translation context and provider for managing language state.
- Integrated translation functionality into existing components (TaskStatusDropdown, Navigation).
- Created LanguageSwitcher component for language selection.
- Updated task statuses and navigation labels to use translations.
- Added Polish translations for various UI elements, including navigation, tasks, projects, and contracts.
- Refactored utility functions to return localized strings for deadlines and date formatting.
This commit is contained in:
Chop
2025-07-27 22:01:15 +02:00
parent 9b6307eabe
commit e828aa660b
16 changed files with 1166 additions and 234 deletions

View File

@@ -11,8 +11,10 @@ import PageHeader from "@/components/ui/PageHeader";
import SearchBar from "@/components/ui/SearchBar";
import { LoadingState } from "@/components/ui/States";
import { formatDate } from "@/lib/utils";
import { useTranslation } from "@/lib/i18n";
export default function ProjectListPage() {
const { t } = useTranslation();
const [projects, setProjects] = useState([]);
const [searchTerm, setSearchTerm] = useState("");
const [filteredProjects, setFilteredProjects] = useState([]);
@@ -45,7 +47,7 @@ export default function ProjectListPage() {
}, [searchTerm, projects]);
async function handleDelete(id) {
const confirmed = confirm("Are you sure you want to delete this project?");
const confirmed = confirm(t('projects.deleteConfirm'));
if (!confirmed) return;
const res = await fetch(`/api/projects/${id}`, {
@@ -61,7 +63,7 @@ export default function ProjectListPage() {
};
return (
<PageContainer>
<PageHeader title="Projects" description="Manage and track your projects">
<PageHeader title={t('projects.title')} description={t('projects.subtitle')}>
<div className="flex gap-2">
<Link href="/projects/map">
<Button variant="outline" size="lg">
@@ -78,7 +80,7 @@ export default function ProjectListPage() {
d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7"
/>
</svg>
Map View
Widok mapy
</Button>
</Link>
<Link href="/projects/new">
@@ -96,7 +98,7 @@ export default function ProjectListPage() {
d="M12 4v16m8-8H4"
/>
</svg>
Add Project
{t('projects.newProject')}
</Button>
</Link>
</div>
@@ -105,9 +107,9 @@ export default function ProjectListPage() {
<SearchBar
searchTerm={searchTerm}
onSearchChange={handleSearchChange}
placeholder="Search by project name, WP, plot, or investment number..."
placeholder={t('projects.searchPlaceholder')}
resultsCount={filteredProjects.length}
resultsText="projects"
resultsText="projektów"
/>
{filteredProjects.length === 0 && searchTerm ? (
<Card>
@@ -126,14 +128,13 @@ export default function ProjectListPage() {
</svg>
</div>
<h3 className="text-lg font-medium text-gray-900 mb-2">
No projects found
{t('common.noResults')}
</h3>
<p className="text-gray-500 mb-6">
No projects match your search criteria. Try adjusting your search
terms.
Brak projektów pasujących do kryteriów wyszukiwania. Spróbuj zmienić wyszukiwane frazy.
</p>
<Button variant="outline" onClick={() => setSearchTerm("")}>
Clear Search
Wyczyść wyszukiwanie
</Button>
</CardContent>
</Card>
@@ -154,13 +155,13 @@ export default function ProjectListPage() {
</svg>
</div>
<h3 className="text-lg font-medium text-gray-900 mb-2">
No projects yet
{t('projects.noProjects')}
</h3>
<p className="text-gray-500 mb-6">
Get started by creating your first project
{t('projects.noProjectsMessage')}
</p>
<Link href="/projects/new">
<Button variant="primary">Create First Project</Button>
<Button variant="primary">Utwórz pierwszy projekt</Button>
</Link>
</CardContent>
</Card>
@@ -170,34 +171,34 @@ export default function ProjectListPage() {
<thead>
<tr className="bg-gray-100 border-b">
<th className="text-left px-2 py-3 font-semibold text-xs text-gray-700 w-32">
No.
Nr.
</th>
<th className="text-left px-2 py-3 font-semibold text-xs text-gray-700">
Project Name
{t('projects.projectName')}
</th>
<th className="text-left px-2 py-3 font-semibold text-xs text-gray-700 w-40">
WP
</th>
<th className="text-left px-2 py-3 font-semibold text-xs text-gray-700 w-20">
City
{t('projects.city')}
</th>
<th className="text-left px-2 py-3 font-semibold text-xs text-gray-700 w-40">
Address
{t('projects.address')}
</th>
<th className="text-left px-2 py-3 font-semibold text-xs text-gray-700 w-20">
Plot
{t('projects.plot')}
</th>
<th className="text-left px-2 py-3 font-semibold text-xs text-gray-700 w-24">
Finish
{t('projects.finishDate')}
</th>
<th className="text-left px-2 py-3 font-semibold text-xs text-gray-700 w-12">
Type
Typ
</th>
<th className="text-left px-2 py-3 font-semibold text-xs text-gray-700 w-24">
Status
</th>
<th className="text-left px-2 py-3 font-semibold text-xs text-gray-700 w-20">
Actions
Akcje
</th>
</tr>
</thead>
@@ -282,7 +283,7 @@ export default function ProjectListPage() {
size="sm"
className="text-xs px-2 py-1"
>
View
Wyświetl
</Button>
</Link>
</td>