feat(i18n): update locales, sidebar, and master plan for multilingual support

This commit is contained in:
poyrazavsever
2026-07-20 11:08:21 +03:00
parent a2c7f8cdf4
commit e5d609426d
6 changed files with 343 additions and 95 deletions
+8 -5
View File
@@ -22,13 +22,16 @@ export function I18nProvider({
messages,
}: {
children: ReactNode;
locale: string;
locale?: string;
messages: Record<string, string>;
}) {
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 <I18nContext.Provider value={value}>{children}</I18nContext.Provider>;
}
+11 -15
View File
@@ -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 }],
},
];
@@ -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
+113 -6
View File
@@ -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",
+109 -2
View File
@@ -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",
+35
View File
@@ -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("<LocaleSelect"), false, `${page} contains LocaleSelect`);
assert.equal(content.includes("locale-select-form"), false, `${page} contains locale-select-form`);
// Rule 2: Must use resolvePublicLocale
assert.equal(content.includes("resolvePublicLocale"), true, `${page} missing resolvePublicLocale`);
}
const result = compareCatalogKeys(trCatalog as any, enCatalog as any, ["auth"]);
const authMissingInEn = result.missingInRight.filter((k: string) => 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.");