feat(localization): update project list translations and add new keys
- Enhanced localization JSON files for multiple languages, including Albanian, German, English, Spanish, Portuguese, and Chinese. - Updated existing translation keys for consistency and clarity, particularly for task progress, archive confirmations, and filtering instructions. - Introduced new keys for improved user experience, such as "yes", "no", "list", "group", and "noPermission". - Ensured all translations align with the latest UI changes for better internationalization support.
This commit is contained in:
@@ -3,21 +3,32 @@
|
|||||||
"client": "Klienti",
|
"client": "Klienti",
|
||||||
"category": "Kategoria",
|
"category": "Kategoria",
|
||||||
"status": "Statusi",
|
"status": "Statusi",
|
||||||
"tasksProgress": "Progresi i Detyrave",
|
"tasksProgress": "Përparimi i Detyrave",
|
||||||
"updated_at": "Përditësuar Së Fundi",
|
"updated_at": "E Përditësuar së Fundi",
|
||||||
"members": "Anëtarët",
|
"members": "Anëtarët",
|
||||||
"setting": "Cilësimet",
|
"setting": "Cilësimet",
|
||||||
"projects": "Projektet",
|
"projects": "Projektet",
|
||||||
"refreshProjects": "Rifresko projektet",
|
"refreshProjects": "Rifresko projektet",
|
||||||
"all": "Të Gjitha",
|
"all": "Të gjitha",
|
||||||
"favorites": "Të Preferuarat",
|
"favorites": "Të preferuarit",
|
||||||
"archived": "Të Arkivuara",
|
"archived": "E arkivuar",
|
||||||
"placeholder": "Kërko sipas emrit",
|
"placeholder": "Kërko sipas emrit",
|
||||||
"archive": "Arkivo",
|
"archive": "Arkivo",
|
||||||
"unarchive": "Ç'arkivo",
|
"unarchive": "Çarkivo",
|
||||||
"archiveConfirm": "Jeni i sigurt që doni ta arkivoni këtë projekt?",
|
"archiveConfirm": "Jeni i sigurt që dëshironi të arkivoni këtë projekt?",
|
||||||
"unarchiveConfirm": "Jeni i sigurt që doni ta çarkivoni këtë projekt?",
|
"unarchiveConfirm": "Jeni i sigurt që dëshironi të çarkivoni këtë projekt?",
|
||||||
"clickToFilter": "Klikoni për të filtruar sipas",
|
"yes": "Po",
|
||||||
|
"no": "Jo",
|
||||||
|
"clickToFilter": "Kliko për të filtruar sipas",
|
||||||
"noProjects": "Nuk u gjetën projekte",
|
"noProjects": "Nuk u gjetën projekte",
|
||||||
"addToFavourites": "Shto në të preferuarat"
|
"addToFavourites": "Shto te të preferuarit",
|
||||||
|
"list": "Lista",
|
||||||
|
"group": "Grupi",
|
||||||
|
"listView": "Pamja e Listës",
|
||||||
|
"groupView": "Pamja e Grupit",
|
||||||
|
"groupBy": {
|
||||||
|
"category": "Kategoria",
|
||||||
|
"client": "Klienti"
|
||||||
|
},
|
||||||
|
"noPermission": "Nuk keni leje për të kryer këtë veprim"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,18 @@
|
|||||||
"unarchive": "Dearchivieren",
|
"unarchive": "Dearchivieren",
|
||||||
"archiveConfirm": "Sind Sie sicher, dass Sie dieses Projekt archivieren möchten?",
|
"archiveConfirm": "Sind Sie sicher, dass Sie dieses Projekt archivieren möchten?",
|
||||||
"unarchiveConfirm": "Sind Sie sicher, dass Sie dieses Projekt dearchivieren möchten?",
|
"unarchiveConfirm": "Sind Sie sicher, dass Sie dieses Projekt dearchivieren möchten?",
|
||||||
|
"yes": "Ja",
|
||||||
|
"no": "Nein",
|
||||||
"clickToFilter": "Zum Filtern klicken nach",
|
"clickToFilter": "Zum Filtern klicken nach",
|
||||||
"noProjects": "Keine Projekte gefunden",
|
"noProjects": "Keine Projekte gefunden",
|
||||||
"addToFavourites": "Zu Favoriten hinzufügen"
|
"addToFavourites": "Zu Favoriten hinzufügen",
|
||||||
|
"list": "Liste",
|
||||||
|
"group": "Gruppe",
|
||||||
|
"listView": "Listenansicht",
|
||||||
|
"groupView": "Gruppenansicht",
|
||||||
|
"groupBy": {
|
||||||
|
"category": "Kategorie",
|
||||||
|
"client": "Kunde"
|
||||||
|
},
|
||||||
|
"noPermission": "Sie haben keine Berechtigung, diese Aktion durchzuführen"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
"unarchive": "Unarchive",
|
"unarchive": "Unarchive",
|
||||||
"archiveConfirm": "Are you sure you want to archive this project?",
|
"archiveConfirm": "Are you sure you want to archive this project?",
|
||||||
"unarchiveConfirm": "Are you sure you want to unarchive this project?",
|
"unarchiveConfirm": "Are you sure you want to unarchive this project?",
|
||||||
|
"yes": "Yes",
|
||||||
|
"no": "No",
|
||||||
"clickToFilter": "Click to filter by",
|
"clickToFilter": "Click to filter by",
|
||||||
"noProjects": "No projects found",
|
"noProjects": "No projects found",
|
||||||
"addToFavourites": "Add to favourites",
|
"addToFavourites": "Add to favourites",
|
||||||
@@ -27,5 +29,6 @@
|
|||||||
"groupBy": {
|
"groupBy": {
|
||||||
"category": "Category",
|
"category": "Category",
|
||||||
"client": "Client"
|
"client": "Client"
|
||||||
}
|
},
|
||||||
|
"noPermission": "You don't have permission to perform this action"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,23 +3,25 @@
|
|||||||
"client": "Cliente",
|
"client": "Cliente",
|
||||||
"category": "Categoría",
|
"category": "Categoría",
|
||||||
"status": "Estado",
|
"status": "Estado",
|
||||||
"tasksProgress": "Progreso de tareas",
|
"tasksProgress": "Progreso de Tareas",
|
||||||
"updated_at": "Última actualización",
|
"updated_at": "Última Actualización",
|
||||||
"members": "Miembros",
|
"members": "Miembros",
|
||||||
"setting": "Configuración",
|
"setting": "Configuración",
|
||||||
"archive": "Archivar",
|
|
||||||
"projects": "Proyectos",
|
"projects": "Proyectos",
|
||||||
"refreshProjects": "Actualizar proyectos",
|
"refreshProjects": "Actualizar proyectos",
|
||||||
"all": "Todos",
|
"all": "Todos",
|
||||||
"favorites": "Favoritos",
|
"favorites": "Favoritos",
|
||||||
"archived": "Archivados",
|
"archived": "Archivados",
|
||||||
"placeholder": "Buscar por nombre",
|
"placeholder": "Buscar por nombre",
|
||||||
|
"archive": "Archivar",
|
||||||
"unarchive": "Desarchivar",
|
"unarchive": "Desarchivar",
|
||||||
"archiveConfirm": "¿Estás seguro de que deseas archivar este proyecto?",
|
"archiveConfirm": "¿Está seguro de que desea archivar este proyecto?",
|
||||||
"unarchiveConfirm": "¿Estás seguro de que deseas desarchivar este proyecto?",
|
"unarchiveConfirm": "¿Está seguro de que desea desarchivar este proyecto?",
|
||||||
"clickToFilter": "Clique para filtrar por",
|
"yes": "Sí",
|
||||||
|
"no": "No",
|
||||||
|
"clickToFilter": "Haga clic para filtrar por",
|
||||||
"noProjects": "No se encontraron proyectos",
|
"noProjects": "No se encontraron proyectos",
|
||||||
"addToFavourites": "Añadir a favoritos",
|
"addToFavourites": "Agregar a favoritos",
|
||||||
"list": "Lista",
|
"list": "Lista",
|
||||||
"group": "Grupo",
|
"group": "Grupo",
|
||||||
"listView": "Vista de Lista",
|
"listView": "Vista de Lista",
|
||||||
@@ -27,5 +29,6 @@
|
|||||||
"groupBy": {
|
"groupBy": {
|
||||||
"category": "Categoría",
|
"category": "Categoría",
|
||||||
"client": "Cliente"
|
"client": "Cliente"
|
||||||
}
|
},
|
||||||
|
"noPermission": "No tienes permiso para realizar esta acción"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,17 +6,19 @@
|
|||||||
"tasksProgress": "Progresso das Tarefas",
|
"tasksProgress": "Progresso das Tarefas",
|
||||||
"updated_at": "Última Atualização",
|
"updated_at": "Última Atualização",
|
||||||
"members": "Membros",
|
"members": "Membros",
|
||||||
"setting": "Configuração",
|
"setting": "Configurações",
|
||||||
"archive": "Arquivar",
|
|
||||||
"projects": "Projetos",
|
"projects": "Projetos",
|
||||||
"refreshProjects": "Atualizar projetos",
|
"refreshProjects": "Atualizar projetos",
|
||||||
"all": "Todos",
|
"all": "Todos",
|
||||||
"favorites": "Favoritos",
|
"favorites": "Favoritos",
|
||||||
"archived": "Arquivados",
|
"archived": "Arquivados",
|
||||||
"placeholder": "Pesquisar por nome",
|
"placeholder": "Pesquisar por nome",
|
||||||
"archiveConfirm": "Tem certeza de que deseja arquivar este projeto?",
|
"archive": "Arquivar",
|
||||||
"unarchive": "Desarquivar",
|
"unarchive": "Desarquivar",
|
||||||
|
"archiveConfirm": "Tem certeza de que deseja arquivar este projeto?",
|
||||||
"unarchiveConfirm": "Tem certeza de que deseja desarquivar este projeto?",
|
"unarchiveConfirm": "Tem certeza de que deseja desarquivar este projeto?",
|
||||||
|
"yes": "Sim",
|
||||||
|
"no": "Não",
|
||||||
"clickToFilter": "Clique para filtrar por",
|
"clickToFilter": "Clique para filtrar por",
|
||||||
"noProjects": "Nenhum projeto encontrado",
|
"noProjects": "Nenhum projeto encontrado",
|
||||||
"addToFavourites": "Adicionar aos favoritos",
|
"addToFavourites": "Adicionar aos favoritos",
|
||||||
@@ -27,5 +29,6 @@
|
|||||||
"groupBy": {
|
"groupBy": {
|
||||||
"category": "Categoria",
|
"category": "Categoria",
|
||||||
"client": "Cliente"
|
"client": "Cliente"
|
||||||
}
|
},
|
||||||
|
"noPermission": "Você não tem permissão para realizar esta ação"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,18 @@
|
|||||||
"unarchive": "取消归档",
|
"unarchive": "取消归档",
|
||||||
"archiveConfirm": "您确定要归档此项目吗?",
|
"archiveConfirm": "您确定要归档此项目吗?",
|
||||||
"unarchiveConfirm": "您确定要取消归档此项目吗?",
|
"unarchiveConfirm": "您确定要取消归档此项目吗?",
|
||||||
"clickToFilter": "点击以筛选",
|
"yes": "是",
|
||||||
|
"no": "否",
|
||||||
|
"clickToFilter": "点击筛选",
|
||||||
"noProjects": "未找到项目",
|
"noProjects": "未找到项目",
|
||||||
"addToFavourites": "添加到收藏"
|
"addToFavourites": "添加到收藏",
|
||||||
|
"list": "列表",
|
||||||
|
"group": "分组",
|
||||||
|
"listView": "列表视图",
|
||||||
|
"groupView": "分组视图",
|
||||||
|
"groupBy": {
|
||||||
|
"category": "类别",
|
||||||
|
"client": "客户"
|
||||||
|
},
|
||||||
|
"noPermission": "您没有权限执行此操作"
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { RouteObject } from 'react-router-dom';
|
import { RouteObject } from 'react-router-dom';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
import AdminCenterLayout from '@/layouts/admin-center-layout';
|
|
||||||
import { adminCenterItems } from '@/pages/admin-center/admin-center-constants';
|
import { adminCenterItems } from '@/pages/admin-center/admin-center-constants';
|
||||||
import { Navigate } from 'react-router-dom';
|
import { Navigate } from 'react-router-dom';
|
||||||
import { useAuthService } from '@/hooks/useAuth';
|
import { useAuthService } from '@/hooks/useAuth';
|
||||||
import { SuspenseFallback } from '@/components/suspense-fallback/suspense-fallback';
|
import { SuspenseFallback } from '@/components/suspense-fallback/suspense-fallback';
|
||||||
|
import AdminCenterLayout from '@/layouts/AdminCenterLayout';
|
||||||
|
|
||||||
const AdminCenterGuard = ({ children }: { children: React.ReactNode }) => {
|
const AdminCenterGuard = ({ children }: { children: React.ReactNode }) => {
|
||||||
const isOwnerOrAdmin = useAuthService().isOwnerOrAdmin();
|
const isOwnerOrAdmin = useAuthService().isOwnerOrAdmin();
|
||||||
|
|||||||
@@ -1,259 +0,0 @@
|
|||||||
# Service Worker Implementation
|
|
||||||
|
|
||||||
This directory contains the service worker implementation for Worklenz, providing offline functionality, caching, and performance improvements.
|
|
||||||
|
|
||||||
## Files Overview
|
|
||||||
|
|
||||||
- **`sw.js`** (in `/public/`) - The main service worker file
|
|
||||||
- **`serviceWorkerRegistration.ts`** - Registration and management utilities
|
|
||||||
- **`ServiceWorkerStatus.tsx`** (in `/components/`) - React component for SW status
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
### 🔄 Caching Strategies
|
|
||||||
|
|
||||||
1. **Cache First** - Static assets (JS, CSS, images)
|
|
||||||
- Serves from cache first, falls back to network
|
|
||||||
- Perfect for unchanging resources
|
|
||||||
|
|
||||||
2. **Network First** - API requests
|
|
||||||
- Tries network first, falls back to cache
|
|
||||||
- Ensures fresh data when online
|
|
||||||
|
|
||||||
3. **Stale While Revalidate** - HTML pages
|
|
||||||
- Serves cached version immediately
|
|
||||||
- Updates cache in background
|
|
||||||
|
|
||||||
### 📱 PWA Features
|
|
||||||
|
|
||||||
- **Offline Support** - App works without internet
|
|
||||||
- **Installable** - Can be installed on devices
|
|
||||||
- **Background Sync** - Sync data when online (framework ready)
|
|
||||||
- **Push Notifications** - Real-time notifications (framework ready)
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Basic Integration
|
|
||||||
|
|
||||||
The service worker is automatically registered in `App.tsx`:
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import { registerSW } from './utils/serviceWorkerRegistration';
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
registerSW({
|
|
||||||
onSuccess: (registration) => {
|
|
||||||
console.log('SW registered successfully');
|
|
||||||
},
|
|
||||||
onUpdate: (registration) => {
|
|
||||||
// Show update notification to user
|
|
||||||
},
|
|
||||||
onOfflineReady: () => {
|
|
||||||
console.log('App ready for offline use');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using the Hook
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import { useServiceWorker } from '../utils/serviceWorkerRegistration';
|
|
||||||
|
|
||||||
const MyComponent = () => {
|
|
||||||
const { isOffline, swManager, clearCache, forceUpdate } = useServiceWorker();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<p>Status: {isOffline ? 'Offline' : 'Online'}</p>
|
|
||||||
<button onClick={clearCache}>Clear Cache</button>
|
|
||||||
<button onClick={forceUpdate}>Update App</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Status Component
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import ServiceWorkerStatus from '../components/service-worker-status/ServiceWorkerStatus';
|
|
||||||
|
|
||||||
// Minimal offline indicator
|
|
||||||
<ServiceWorkerStatus minimal />
|
|
||||||
|
|
||||||
// Full status with controls
|
|
||||||
<ServiceWorkerStatus showControls />
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Cacheable Resources
|
|
||||||
|
|
||||||
Edit the patterns in `sw.js`:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// API endpoints that can be cached
|
|
||||||
const CACHEABLE_API_PATTERNS = [
|
|
||||||
/\/api\/project-categories/,
|
|
||||||
/\/api\/task-statuses/,
|
|
||||||
// Add more patterns...
|
|
||||||
];
|
|
||||||
|
|
||||||
// Resources that should never be cached
|
|
||||||
const NEVER_CACHE_PATTERNS = [
|
|
||||||
/\/api\/auth\/login/,
|
|
||||||
/\/socket\.io/,
|
|
||||||
// Add more patterns...
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
### Cache Names
|
|
||||||
|
|
||||||
Update version to force cache refresh:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
const CACHE_VERSION = 'v1.0.1'; // Increment when deploying
|
|
||||||
```
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
### Testing Offline
|
|
||||||
|
|
||||||
1. Open DevTools → Application → Service Workers
|
|
||||||
2. Check "Offline" to simulate offline mode
|
|
||||||
3. Verify app still functions
|
|
||||||
|
|
||||||
### Debugging
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Check service worker status
|
|
||||||
navigator.serviceWorker.ready.then(registration => {
|
|
||||||
console.log('SW ready:', registration);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check cache contents
|
|
||||||
caches.keys().then(names => {
|
|
||||||
console.log('Cache names:', names);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Cache Management
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Clear all caches
|
|
||||||
caches.keys().then(names =>
|
|
||||||
Promise.all(names.map(name => caches.delete(name)))
|
|
||||||
);
|
|
||||||
|
|
||||||
// Clear specific cache
|
|
||||||
caches.delete('worklenz-api-v1.0.0');
|
|
||||||
```
|
|
||||||
|
|
||||||
## Best Practices
|
|
||||||
|
|
||||||
### 1. Cache Strategy Selection
|
|
||||||
|
|
||||||
- **Static Assets**: Cache First (fast loading)
|
|
||||||
- **API Data**: Network First (fresh data)
|
|
||||||
- **User Content**: Network Only (always fresh)
|
|
||||||
- **App Shell**: Cache First (instant loading)
|
|
||||||
|
|
||||||
### 2. Cache Invalidation
|
|
||||||
|
|
||||||
- Increment `CACHE_VERSION` when deploying
|
|
||||||
- Use versioned URLs for assets
|
|
||||||
- Set appropriate cache headers
|
|
||||||
|
|
||||||
### 3. Offline UX
|
|
||||||
|
|
||||||
- Show offline indicators
|
|
||||||
- Queue actions for later sync
|
|
||||||
- Provide meaningful offline messages
|
|
||||||
- Cache critical user data
|
|
||||||
|
|
||||||
### 4. Performance
|
|
||||||
|
|
||||||
- Cache only necessary resources
|
|
||||||
- Set cache size limits
|
|
||||||
- Clean up old caches regularly
|
|
||||||
- Monitor cache usage
|
|
||||||
|
|
||||||
## Monitoring
|
|
||||||
|
|
||||||
### Storage Usage
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Check storage quota
|
|
||||||
navigator.storage.estimate().then(estimate => {
|
|
||||||
console.log('Used:', estimate.usage);
|
|
||||||
console.log('Quota:', estimate.quota);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Cache Hit Rate
|
|
||||||
|
|
||||||
Monitor in DevTools → Network:
|
|
||||||
- Look for "from ServiceWorker" requests
|
|
||||||
- Check cache effectiveness
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Common Issues
|
|
||||||
|
|
||||||
1. **SW not updating**
|
|
||||||
- Hard refresh (Ctrl+Shift+R)
|
|
||||||
- Clear browser cache
|
|
||||||
- Check CACHE_VERSION
|
|
||||||
|
|
||||||
2. **Resources not caching**
|
|
||||||
- Verify URL patterns
|
|
||||||
- Check NEVER_CACHE_PATTERNS
|
|
||||||
- Ensure HTTPS in production
|
|
||||||
|
|
||||||
3. **Offline features not working**
|
|
||||||
- Verify SW registration
|
|
||||||
- Check browser support
|
|
||||||
- Test cache strategies
|
|
||||||
|
|
||||||
### Reset Service Worker
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
// Unregister and reload
|
|
||||||
navigator.serviceWorker.getRegistrations().then(registrations => {
|
|
||||||
registrations.forEach(registration => registration.unregister());
|
|
||||||
window.location.reload();
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Browser Support
|
|
||||||
|
|
||||||
- ✅ Chrome 45+
|
|
||||||
- ✅ Firefox 44+
|
|
||||||
- ✅ Safari 11.1+
|
|
||||||
- ✅ Edge 17+
|
|
||||||
- ❌ Internet Explorer
|
|
||||||
|
|
||||||
## Future Enhancements
|
|
||||||
|
|
||||||
1. **Background Sync**
|
|
||||||
- Queue offline actions
|
|
||||||
- Sync when online
|
|
||||||
|
|
||||||
2. **Push Notifications**
|
|
||||||
- Task assignments
|
|
||||||
- Project updates
|
|
||||||
- Deadline reminders
|
|
||||||
|
|
||||||
3. **Advanced Caching**
|
|
||||||
- Intelligent prefetching
|
|
||||||
- ML-based cache eviction
|
|
||||||
- Compression
|
|
||||||
|
|
||||||
4. **Offline Analytics**
|
|
||||||
- Track offline usage
|
|
||||||
- Cache hit rates
|
|
||||||
- Performance metrics
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*Last updated: January 2025*
|
|
||||||
Reference in New Issue
Block a user