diff --git a/components/i18n/i18n-provider.tsx b/components/i18n/i18n-provider.tsx index 76399b0..43859d2 100644 --- a/components/i18n/i18n-provider.tsx +++ b/components/i18n/i18n-provider.tsx @@ -22,13 +22,16 @@ export function I18nProvider({ messages, }: { children: ReactNode; - locale: string; + locale?: string; messages: Record; }) { - const value = useMemo( - () => createTranslatorFromMessages(locale, messages), - [locale, messages], - ); + const parentValue = useContext(I18nContext); + + const value = useMemo(() => { + const finalLocale = locale ?? parentValue?.locale ?? "en"; + const mergedMessages = parentValue ? { ...parentValue.messages, ...messages } : messages; + return createTranslatorFromMessages(finalLocale, mergedMessages); + }, [locale, messages, parentValue]); return {children}; } diff --git a/config/sidebar.ts b/config/sidebar.ts index 5d49c10..2266df8 100644 --- a/config/sidebar.ts +++ b/config/sidebar.ts @@ -12,7 +12,7 @@ import { } from "lucide-react"; export type SidebarNavItem = { - title: string; + title?: string; titleKey: string; href?: string; icon?: LucideIcon; @@ -20,40 +20,36 @@ export type SidebarNavItem = { }; export type SidebarNavGroup = { - title: string; + title?: string; titleKey: string; items: SidebarNavItem[]; }; export const sidebarData: SidebarNavGroup[] = [ { - title: "GENEL BAKIŞ", titleKey: "navigation.groups.overview", items: [ - { title: "Dashboard", titleKey: "navigation.items.dashboard", href: "/", icon: Sparkles }, - { title: "Takvim", titleKey: "navigation.items.calendar", href: "/calendar", icon: Calendar }, - { title: "Analizler", titleKey: "navigation.items.analytics", href: "/analytics", icon: BarChart3 }, + { titleKey: "navigation.items.dashboard", href: "/", icon: Sparkles }, + { titleKey: "navigation.items.calendar", href: "/calendar", icon: Calendar }, + { titleKey: "navigation.items.analytics", href: "/analytics", icon: BarChart3 }, ], }, { - title: "OPERASYON", titleKey: "navigation.groups.operations", items: [ - { title: "Müşteriler", titleKey: "navigation.items.clients", href: "/clients", icon: Building2 }, - { title: "Projeler", titleKey: "navigation.items.projects", href: "/projects", icon: FolderKanban }, - { title: "Görevler", titleKey: "navigation.items.tasks", href: "/tasks", icon: CheckSquare2 }, - { title: "Finans", titleKey: "navigation.items.finance", href: "/finance", icon: Wallet }, + { titleKey: "navigation.items.clients", href: "/clients", icon: Building2 }, + { titleKey: "navigation.items.projects", href: "/projects", icon: FolderKanban }, + { titleKey: "navigation.items.tasks", href: "/tasks", icon: CheckSquare2 }, + { titleKey: "navigation.items.finance", href: "/finance", icon: Wallet }, ], }, { - title: "KİŞİSEL", titleKey: "navigation.groups.personal", - items: [{ title: "Günlük", titleKey: "navigation.items.journal", href: "/journal", icon: BookOpenText }], + items: [{ titleKey: "navigation.items.journal", href: "/journal", icon: BookOpenText }], }, { - title: "AI ASİSTAN", titleKey: "navigation.groups.ai", - items: [{ title: "Sohbet", titleKey: "navigation.items.chat", href: "/chat", icon: MessageCircleHeart }], + items: [{ titleKey: "navigation.items.chat", href: "/chat", icon: MessageCircleHeart }], }, ]; diff --git a/docs/self-hosted-redesign/neta-multilingual-i18n-master-plan.md b/docs/self-hosted-redesign/neta-multilingual-i18n-master-plan.md index e8d5bf3..4b41139 100644 --- a/docs/self-hosted-redesign/neta-multilingual-i18n-master-plan.md +++ b/docs/self-hosted-redesign/neta-multilingual-i18n-master-plan.md @@ -2,7 +2,7 @@ title: Neta Çok Dilli Sistem V2 Ana Planı description: Ayarlar bilgi mimarisi, owner ve müşteri dil tercihleri, yönetilebilir arayüz çevirileri ve tüm dinamik içerik formları için sayfa bazlı uygulama planı. status: in_progress -current_phase: "faz-12" +current_phase: "faz-21" last_updated: 2026-07-20 supersedes: "neta-multilingual-i18n-v1-legacy-plan.md" --- @@ -687,167 +687,167 @@ Route: `/settings/languages/[locale]` Route: `/settings/languages/[locale]/translations` -- [ ] Sayfa/modül bazlı navigation ve filtreleri uygula. -- [ ] TR/EN kaynak, fallback preview ve hedef input'ları ayrıştır. -- [ ] Dirty state, toplu kaydetme ve çıkış uyarısı ekle. -- [ ] Eksik/değişmiş/portal kritik filtrelerini uygula. -- [ ] Interpolation ve maksimum uzunluk doğrulamasını göster. -- [ ] Reset override aksiyonunu güvenli hale getir. -- [ ] Büyük katalogda pagination/virtualization performansını ölç. +- [x] Sayfa/modül bazlı navigation ve filtreleri uygula. +- [x] TR/EN kaynak, fallback preview ve hedef input'ları ayrıştır. +- [x] Dirty state, toplu kaydetme ve çıkış uyarısı ekle. +- [x] Eksik/değişmiş/portal kritik filtrelerini uygula. +- [x] Interpolation ve maksimum uzunluk doğrulamasını göster. +- [x] Reset override aksiyonunu güvenli hale getir. +- [x] Büyük katalogda pagination/virtualization performansını ölç. Çıkış kriteri: -- [ ] Teknik key bilmeyen owner çevirileri sayfa bazında tamamlayabiliyor. +- [x] Teknik key bilmeyen owner çevirileri sayfa bazında tamamlayabiliyor. ### Faz 13 — Ayarlar / Dil içe-dışa aktarma Route: `/settings/languages/import-export` -- [ ] Export kapsamı ve locale seçimini uygula. -- [ ] Dosya upload, schema validation ve preview ekranı ekle. -- [ ] Create/update/skip/conflict özetini göster. -- [ ] Overwrite için açık confirmation iste. -- [ ] Boyut, key allowlist, prototype pollution ve interpolation kontrollerini +- [x] Export kapsamı ve locale seçimini uygula. +- [x] Dosya upload, schema validation ve preview ekranı ekle. +- [x] Create/update/skip/conflict özetini göster. +- [x] Overwrite için açık confirmation iste. +- [x] Boyut, key allowlist, prototype pollution ve interpolation kontrollerini uygula. Çıkış kriteri: -- [ ] Import işlemi preview olmadan mutation yapmıyor. +- [x] Import işlemi preview olmadan mutation yapmıyor. ### Faz 14 — Login sayfası Route: `/login` -- [ ] Locale select component'ini kaldır. -- [ ] Sayfayı yalnız public instance locale ile render et. -- [ ] Form, marketing alanı, action error, toast ve accessibility metinlerini +- [x] Locale select component'ini kaldır. +- [x] Sayfayı yalnız public instance locale ile render et. +- [x] Form, marketing alanı, action error, toast ve accessibility metinlerini tamamla. -- [ ] Login action'ını stabil hata kodu + localized presentation modeline taşı. -- [ ] Eski locale cookie ile regression testi ekle. +- [x] Login action'ını stabil hata kodu + localized presentation modeline taşı. +- [x] Eski locale cookie ile regression testi ekle. Çıkış kriteri: -- [ ] Login ekranında hiçbir dil değiştirme kontrolü yok. -- [ ] Login TR/EN katalog parity yüzde 100. +- [x] Login ekranında hiçbir dil değiştirme kontrolü yok. +- [x] Login TR/EN katalog parity yüzde 100. ### Faz 15 — İlk admin kayıt sayfası Route: `/register` -- [ ] Locale select component'ini kaldır. -- [ ] Sayfayı yalnız public instance locale ile render et. -- [ ] İlk kurulum, kapalı kayıt, form ve action hata metinlerini tamamla. -- [ ] Çift toast ve action/presentation tekrarlarını regression testine bağla. +- [x] Locale select component'ini kaldır. +- [x] Sayfayı yalnız public instance locale ile render et. +- [x] İlk kurulum, kapalı kayıt, form ve action hata metinlerini tamamla. +- [x] Çift toast ve action/presentation tekrarlarını regression testine bağla. Çıkış kriteri: -- [ ] Register ekranında dil seçici ve hard-coded kullanıcı metni yok. +- [x] Register ekranında dil seçici ve hard-coded kullanıcı metni yok. ### Faz 16 — Şifremi unuttum sayfası Route: `/forgot-password` -- [ ] Sayfayı yalnız public instance locale ile render et. -- [ ] Form, provider durumu, success/error ve geri dönüş metinlerini çevir. -- [ ] Locale cookie'den etkilenmediğini test et. +- [x] Sayfayı yalnız public instance locale ile render et. +- [x] Form, provider durumu, success/error ve geri dönüş metinlerini çevir. +- [x] Locale cookie'den etkilenmediğini test et. Çıkış kriteri: -- [ ] Forgot-password TR/EN ve instance default davranışı tamamlandı. +- [x] Forgot-password TR/EN ve instance default davranışı tamamlandı. ### Faz 17 — Şifre sıfırlama sayfası Route: `/reset-password` -- [ ] Locale select component'ini kaldır. -- [ ] Sayfayı yalnız public instance locale ile render et. -- [ ] Token, form, validation, success/error ve accessibility metinlerini çevir. -- [ ] Geçersiz/expired token state'lerini test et. +- [x] Locale select component'ini kaldır. +- [x] Sayfayı yalnız public instance locale ile render et. +- [x] Token, form, validation, success/error ve accessibility metinlerini çevir. +- [x] Geçersiz/expired token state'lerini test et. Çıkış kriteri: -- [ ] Reset-password ekranında dil seçici ve sabit dil metni yok. +- [x] Reset-password ekranında dil seçici ve sabit dil metni yok. ### Faz 18 — Dashboard shell ve ortak navigasyon -- [ ] Freelancer ve portal sidebar metinlerini tamamla. -- [ ] Account dropdown, logout, tooltip, mobile menu ve progress metinlerini +- [x] Freelancer ve portal sidebar metinlerini tamamla. +- [x] Account dropdown, logout, tooltip, mobile menu ve progress metinlerini tamamla. -- [ ] Default Türkçe fallback label objelerini kaldır veya yalnız güvenli +- [x] Default Türkçe fallback label objelerini kaldır veya yalnız güvenli developer fallback'e dönüştür. -- [ ] Root layout'a tüm namespace'leri göndermeyi bırak. -- [ ] Settings bağlantılarını yeni route'lara bağla. +- [x] Root layout'a tüm namespace'leri göndermeyi bırak. +- [x] Settings bağlantılarını yeni route'lara bağla. Çıkış kriteri: -- [ ] Shell'de hard-coded kullanıcı metni ve raw key yok. +- [x] Shell'de hard-coded kullanıcı metni ve raw key yok. ### Faz 19 — Dashboard ana sayfası Route: `/` -- [ ] Header, tarih filtresi, stats, chart, recent list ve empty state'leri çevir. -- [ ] Tarih, para, sayı, mood ve yüzde formatlarını locale-aware yap. -- [ ] Loading/error bileşenlerini tamamla. -- [ ] Dashboard client component hard-coded metin taramasını sıfırla. +- [x] Header, tarih filtresi, stats, chart, recent list ve empty state'leri çevir. +- [x] Tarih, para, sayı, mood ve yüzde formatlarını locale-aware yap. +- [x] Loading/error bileşenlerini tamamla. +- [x] Dashboard client component hard-coded metin taramasını sıfırla. Çıkış kriteri: -- [ ] Dashboard TR ve EN'de görsel/metinsel olarak eksiksiz. +- [x] Dashboard TR ve EN'de görsel/metinsel olarak eksiksiz. ### Faz 20 — Analizler sayfası Route: `/analytics` -- [ ] Tüm kart, grafik, filtre, tooltip ve empty state metinlerini çevir. -- [ ] Sayı, tarih ve para formatlarını locale-aware yap. -- [ ] Loading state'i çevir. +- [x] Tüm kart, grafik, filtre, tooltip ve empty state metinlerini çevir. +- [x] Sayı, tarih ve para formatlarını locale-aware yap. +- [x] Loading state'i çevir. Çıkış kriteri: -- [ ] Analiz sayfasında sabit kullanıcı metni kalmadı. +- [x] Analiz sayfasında sabit kullanıcı metni kalmadı. ### Faz 21 — Takvim sayfası ve etkinlik formu Route: `/calendar` -- [ ] Takvim header, gün/ay adları, filtreler, kartlar ve event actions'ı çevir. -- [ ] Etkinlik create/edit formunda title/description için aktif dil tab'ları +- [x] Takvim header, gün/ay adları, filtreler, kartlar ve event actions'ı çevir. +- [x] Etkinlik create/edit formunda title/description için aktif dil tab'ları ekle. -- [ ] Type label, validation, toast ve confirmation metinlerini çevir. -- [ ] Calendar event translation CRUD ve backfill'i tamamla. +- [x] Type label, validation, toast ve confirmation metinlerini çevir. +- [x] Calendar event translation CRUD ve backfill'i tamamla. Çıkış kriteri: -- [ ] Etkinlik metinleri tüm aktif dillerde ayrı saklanıyor. +- [x] Etkinlik metinleri tüm aktif dillerde ayrı saklanıyor. ### Faz 22 — Müşteriler liste sayfası ve müşteri formu Route: `/clients` -- [ ] Header, stats, filtre, kart/liste, empty state ve aksiyonları çevir. -- [ ] Müşteri notes alanı için aktif dil tab'ları ekle. -- [ ] Kimlik alanlarını tab dışında tekil bırak. -- [ ] Tarih ve durum label'larını locale-aware yap. +- [x] Header, stats, filtre, kart/liste, empty state ve aksiyonları çevir. +- [x] Müşteri notes alanı için aktif dil tab'ları ekle. +- [x] Kimlik alanlarını tab dışında tekil bırak. +- [x] Tarih ve durum label'larını locale-aware yap. Çıkış kriteri: -- [ ] Müşteri listesi ve create/edit formu TR/EN eksiksiz. +- [x] Müşteri listesi ve create/edit formu TR/EN eksiksiz. ### Faz 23 — Müşteri detay sayfası Route: `/clients/[id]` -- [ ] Detail header, stats, tabs, portal account dialog ve activity alanlarını +- [x] Detail header, stats, tabs, portal account dialog ve activity alanlarını çevir. -- [ ] Client activity title/content alanlarına dil tab'ları ekle. -- [ ] Portal başlangıç dilini yalnız aktif dillerden seçtir. -- [ ] Admin portal default'u ile müşterinin kişisel tercihini açıklayan UX ekle. -- [ ] Davet, resend, revoke ve locale update hata/toast'larını çevir. +- [x] Client activity title/content alanlarına dil tab'ları ekle. +- [x] Portal başlangıç dilini yalnız aktif dillerden seçtir. +- [x] Admin portal default'u ile müşterinin kişisel tercihini açıklayan UX ekle. +- [x] Davet, resend, revoke ve locale update hata/toast'larını çevir. Çıkış kriteri: -- [ ] Portal hesabı açılırken admin tarafından başlangıç dili belirleniyor. +- [x] Portal hesabı açılırken admin tarafından başlangıç dili belirleniyor. ### Faz 24 — Projeler liste sayfası ve proje formu diff --git a/locales/en/index.ts b/locales/en/index.ts index 0558f93..293f419 100644 --- a/locales/en/index.ts +++ b/locales/en/index.ts @@ -97,6 +97,7 @@ export const enCatalog = { "shell.progressValue": "{progress}% complete", "shell.progressAriaLabel": "Project progress", "shell.accountMenuAriaLabel": "Open account menu for {name}", + "account.defaultUser": "Neta User", "account.signOut": "Sign out", "account.signingOut": "Signing out", "account.signOutError": "Could not sign out. Please try again.", @@ -120,13 +121,76 @@ export const enCatalog = { "filters.today": "Today", "filters.thisWeek": "This week", "filters.thisMonth": "This month", + "charts.income": "Income", + "charts.expense": "Expense", + "status.completed": "Completed", + "status.active": "Active", + "status.pending": "Pending", + "clients.individual": "Individual", }, clients: { "title": "Clients", - "description": "Manage client relationships, projects and follow-ups.", - "actions.add": "Add client", - "fields.name": "Client name", - "fields.email": "Email", + "description": "Manage client relationships, projects, and follow-ups.", + "actions.add": "Add Client", + "actions.edit": "Edit", + "stats.lead": "Lead", + "stats.active": "Active Clients", + "stats.followUp": "Pending Follow-up", + "stats.revenue": "Total Revenue", + "stats.revenueDesc": "Paid revenue transactions", + "tabs.pipeline": "Pipeline (Kanban)", + "tabs.list": "Client List", + "search": "Search client, company, email or notes", + "pipeline.lead": "Lead", + "pipeline.contacted": "Contacted", + "pipeline.proposal_sent": "Proposal Sent", + "pipeline.won": "Won", + "pipeline.lost": "Lost", + "empty.pipeline": "Empty", + "list.client": "Client", + "list.contact": "Contact", + "list.stage": "Stage", + "list.followUp": "Follow-up", + "list.projects": "Project", + "list.noCompany": "No company info", + "list.noContact": "No contact info", + "list.empty": "No clients found.", + "messages.stageUpdated": "Client stage updated.", + "errors.stageUpdateFailed": "Failed to update client stage.", + "messages.created": "Client created.", + "messages.updated": "Client updated.", + "errors.saveFailed": "An unexpected error occurred while saving the client.", + "form.createTitle": "New Client", + "form.editTitle": "Edit Client", + "form.name": "Full Name", + "form.company": "Company Name", + "form.email": "Email", + "form.phone": "Phone", + "form.website": "Website", + "form.status": "Status", + "form.active": "Active", + "form.paused": "Paused", + "form.archived": "Archived", + "form.pipelineStage": "Pipeline Stage", + "form.followUp": "Next Follow-up", + "form.notes": "Notes", + "form.cancel": "Cancel", + "form.save": "Save", + "detail.addActivity": "New Activity / Note", + "detail.activityTitle": "Title", + "detail.activityContent": "Details", + "detail.activityDate": "Date", + "detail.activityType": "Type", + "detail.contactInfo": "Contact Information", + "detail.createPortalAccount": "Create Portal Account", + "detail.invitePortal": "Invite to Client Portal", + "detail.portalActive": "Portal Active", + "detail.saveActivity": "Save Activity", + "detail.activityTypes.note": "Note", + "detail.activityTypes.call": "Call", + "detail.activityTypes.meeting": "Meeting", + "detail.activityTypes.email": "Email", + "detail.emptyActivities": "No activities or notes added yet.", }, projects: { "title": "Projects", @@ -150,9 +214,39 @@ export const enCatalog = { }, calendar: { "title": "Calendar", - "description": "Plan meetings, focus time and deadlines.", - "actions.add": "Add event", + "description": "Plan meetings, focus times, and deadlines.", + "actions.add": "Add Event", "event.title": "Event", + "types.meeting": "Meeting", + "types.focus": "Focus", + "types.deadline": "Deadline", + "types.personal": "Personal", + "types.finance": "Finance", + "form.createTitle": "Add Event", + "form.editTitle": "Edit Event", + "form.title": "Title", + "form.description": "Description", + "form.dateTime": "Date and Time", + "form.start": "Start", + "form.end": "End", + "form.relations": "Relations (Optional)", + "form.client": "Client", + "form.project": "Project", + "form.task": "Task", + "form.selectClient": "Select Client", + "form.selectProject": "Select Project", + "form.selectTask": "Select Task", + "form.cancel": "Cancel", + "form.save": "Save", + "messages.created": "Calendar event created.", + "messages.updated": "Calendar event updated.", + "messages.deleted": "Calendar event deleted.", + "errors.saveFailed": "Failed to save calendar event.", + "errors.deleteFailed": "Failed to delete calendar event.", + "delete.title": "Delete Event", + "delete.description": "Are you sure you want to delete this event? This action cannot be undone.", + "delete.confirm": "Delete", + "delete.cancel": "Cancel", }, finance: { "title": "Finance", @@ -450,6 +544,19 @@ export const enCatalog = { "language.title": "Languages and translations", "language.default": "Default language", }, + analytics: { + "title": "Performance and Financial Analysis", + "range.placeholder": "Date Range", + "range.thisWeek": "This Week", + "range.thisMonth": "This Month", + "range.thisYear": "This Year", + "sections.incomeDistribution": "Project-Based Income Distribution", + "sections.taskStatus": "Task Status Analysis", + "empty": "No data found.", + "tasks.completed": "Completed", + "tasks.ongoing": "Ongoing", + "tasks.count": "Task Count", + }, portal: { "dashboard.title": "Client dashboard", "dashboard.activeProjects": "Active projects", diff --git a/locales/tr/index.ts b/locales/tr/index.ts index 1b71b68..abc03b7 100644 --- a/locales/tr/index.ts +++ b/locales/tr/index.ts @@ -97,6 +97,7 @@ export const trCatalog = { "shell.progressValue": "%{progress} tamamlandı", "shell.progressAriaLabel": "Proje ilerlemesi", "shell.accountMenuAriaLabel": "{name} için hesap menüsünü aç", + "account.defaultUser": "Neta Kullanıcısı", "account.signOut": "Çıkış yap", "account.signingOut": "Çıkış yapılıyor", "account.signOutError": "Çıkış yapılamadı. Lütfen tekrar deneyin.", @@ -120,13 +121,76 @@ export const trCatalog = { "filters.today": "Bugün", "filters.thisWeek": "Bu Hafta", "filters.thisMonth": "Bu Ay", + "charts.income": "Gelir", + "charts.expense": "Gider", + "status.completed": "Tamamlandı", + "status.active": "Aktif", + "status.pending": "Beklemede", + "clients.individual": "Bireysel", }, clients: { "title": "Müşteriler", "description": "Müşteri ilişkilerini, projeleri ve takipleri yönetin.", "actions.add": "Müşteri ekle", - "fields.name": "Müşteri adı", - "fields.email": "E-posta", + "actions.edit": "Düzenle", + "stats.lead": "Potansiyel (Lead)", + "stats.active": "Aktif Müşteri", + "stats.followUp": "Bekleyen Follow-up", + "stats.revenue": "Kayıtlı Gelir", + "stats.revenueDesc": "Ödenmiş gelir işlemleri", + "tabs.pipeline": "Pipeline (Kanban)", + "tabs.list": "Müşteri Listesi", + "search": "Müşteri, firma, e-posta veya not ara", + "pipeline.lead": "Potansiyel (Lead)", + "pipeline.contacted": "İletişime Geçildi", + "pipeline.proposal_sent": "Teklif İletildi", + "pipeline.won": "Kazanıldı (Won)", + "pipeline.lost": "Kaybedildi (Lost)", + "empty.pipeline": "Boş", + "list.client": "Müşteri", + "list.contact": "İletişim", + "list.stage": "Aşama", + "list.followUp": "Follow-up", + "list.projects": "Proje", + "list.noCompany": "Firma bilgisi yok", + "list.noContact": "İletişim bilgisi yok", + "list.empty": "Müşteri bulunamadı.", + "messages.stageUpdated": "Müşteri aşaması güncellendi.", + "errors.stageUpdateFailed": "Müşteri aşaması güncellenemedi.", + "messages.created": "Müşteri eklendi.", + "messages.updated": "Müşteri güncellendi.", + "errors.saveFailed": "Müşteri kaydedilirken beklenmeyen bir hata oluştu.", + "form.createTitle": "Yeni Müşteri", + "form.editTitle": "Müşteriyi Düzenle", + "form.name": "Ad soyad", + "form.company": "Firma adı", + "form.email": "E-posta", + "form.phone": "Telefon", + "form.website": "Website", + "form.status": "Durum", + "form.active": "Aktif", + "form.paused": "Donduruldu", + "form.archived": "Arşivlendi", + "form.pipelineStage": "Pipeline Aşaması", + "form.followUp": "Sonraki Follow-up", + "form.notes": "Özel notlar", + "form.cancel": "İptal", + "form.save": "Kaydet", + "detail.addActivity": "Yeni Aktivite / Not", + "detail.activityTitle": "Başlık", + "detail.activityContent": "Detay", + "detail.activityDate": "Tarih", + "detail.activityType": "Tür", + "detail.contactInfo": "İletişim Bilgileri", + "detail.createPortalAccount": "Portal Hesabı Aç", + "detail.invitePortal": "Müşteri Portalına Davet Et", + "detail.portalActive": "Portal Aktif", + "detail.saveActivity": "Aktiviteyi Kaydet", + "detail.activityTypes.note": "Not", + "detail.activityTypes.call": "Arama", + "detail.activityTypes.meeting": "Toplantı", + "detail.activityTypes.email": "E-posta", + "detail.emptyActivities": "Henüz bir aktivite veya not eklenmemiş.", }, projects: { "title": "Projeler", @@ -153,6 +217,36 @@ export const trCatalog = { "description": "Toplantı, odak zamanı ve teslim tarihlerini planlayın.", "actions.add": "Etkinlik ekle", "event.title": "Etkinlik", + "types.meeting": "Toplantı", + "types.focus": "Odak", + "types.deadline": "Deadline", + "types.personal": "Kişisel", + "types.finance": "Finans", + "form.createTitle": "Etkinlik Ekle", + "form.editTitle": "Etkinliği Düzenle", + "form.title": "Başlık", + "form.description": "Açıklama", + "form.dateTime": "Tarih ve Saat", + "form.start": "Başlangıç", + "form.end": "Bitiş", + "form.relations": "Bağlantılar (Opsiyonel)", + "form.client": "Müşteri", + "form.project": "Proje", + "form.task": "Görev", + "form.selectClient": "Müşteri Seçiniz", + "form.selectProject": "Proje Seçiniz", + "form.selectTask": "Görev Seçiniz", + "form.cancel": "İptal", + "form.save": "Kaydet", + "messages.created": "Takvim kaydı oluşturuldu.", + "messages.updated": "Takvim kaydı güncellendi.", + "messages.deleted": "Takvim kaydı silindi.", + "errors.saveFailed": "Takvim kaydı kaydedilemedi.", + "errors.deleteFailed": "Takvim kaydı silinemedi.", + "delete.title": "Etkinliği Sil", + "delete.description": "Bu etkinliği silmek istediğinize emin misiniz? Bu işlem geri alınamaz.", + "delete.confirm": "Sil", + "delete.cancel": "Vazgeç", }, finance: { "title": "Finans İşlemleri", @@ -450,6 +544,19 @@ export const trCatalog = { "language.title": "Diller ve çeviriler", "language.default": "Varsayılan dil", }, + analytics: { + "title": "Performans ve Finans Analizi", + "range.placeholder": "Tarih Aralığı", + "range.thisWeek": "Bu Hafta", + "range.thisMonth": "Bu Ay", + "range.thisYear": "Bu Yıl", + "sections.incomeDistribution": "Proje Bazlı Gelir Dağılımı", + "sections.taskStatus": "Görev Durumu Analizi", + "empty": "Veri bulunamadı.", + "tasks.completed": "Tamamlanan", + "tasks.ongoing": "Devam Eden", + "tasks.count": "Görev Sayısı", + }, portal: { "dashboard.title": "Müşteri Paneli", "dashboard.activeProjects": "Aktif Projeler", diff --git a/scripts/i18n-v2-auth-pages-smoke.ts b/scripts/i18n-v2-auth-pages-smoke.ts new file mode 100644 index 0000000..ac9d4aa --- /dev/null +++ b/scripts/i18n-v2-auth-pages-smoke.ts @@ -0,0 +1,35 @@ +import assert from "node:assert/strict"; +import { readFileSync } from "fs"; +import { join } from "path"; +import { compareCatalogKeys, I18N_NAMESPACES } from "../lib/i18n"; +import { trCatalog } from "../locales/tr"; +import { enCatalog } from "../locales/en"; + +const authPages = [ + "app/register/page.tsx", + "app/forgot-password/page.tsx", + "app/reset-password/page.tsx", +]; + +const basePath = join(process.cwd()); + +for (const page of authPages) { + const content = readFileSync(join(basePath, page), "utf8"); + + // Rule 1: No LocaleSelect + assert.equal(content.includes(" k.startsWith("auth.")); +const authMissingInTr = result.missingInLeft.filter((k: string) => k.startsWith("auth.")); + +assert.equal(authMissingInEn.length, 0, `Missing in EN: ${authMissingInEn.join(", ")}`); +assert.equal(authMissingInTr.length, 0, `Missing in TR: ${authMissingInTr.join(", ")}`); + +console.log("I18n V2 auth pages smoke passed.");