diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1a9756650..8000187d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [1.9.20] - 2026-09-24
+### Added
+
+- Turkish (`tr`) interface language: full interface translation, Turkish as a native-language option at registration and in Settings, and Turkish verification, password reset, welcome, and account deletion emails. The dashboard announcement keeps its existing ten locales and falls back to English for Turkish users.
+
### Fixed
- Onboarding learning goals now name the selected language in all ten interface languages, with natural wording and a safe display fallback for unrecognized language codes.
diff --git a/backend/app/routers/lessons.py b/backend/app/routers/lessons.py
index b646d17db..d1a54e39c 100644
--- a/backend/app/routers/lessons.py
+++ b/backend/app/routers/lessons.py
@@ -119,6 +119,13 @@
"good_pronunciation": "Pronuntie buna!",
"target_phrase": "Fraza tinta a fost: {answer}",
},
+ "tr": {
+ "correct": "Doğru!",
+ "correct_answer": "Doğru cevap: {answer}",
+ "free_write_unavailable": "Yazılı cevap şu anda değerlendirilemedi.",
+ "good_pronunciation": "Telaffuzunuz iyi!",
+ "target_phrase": "Hedef ifade şuydu: {answer}",
+ },
}
diff --git a/backend/app/schemas/admin.py b/backend/app/schemas/admin.py
index 8852b78ca..22186699b 100644
--- a/backend/app/schemas/admin.py
+++ b/backend/app/schemas/admin.py
@@ -23,6 +23,7 @@
"nl",
"pl",
"ro",
+ "tr",
}
diff --git a/backend/app/schemas/auth.py b/backend/app/schemas/auth.py
index 53e9f0168..caba7eb03 100644
--- a/backend/app/schemas/auth.py
+++ b/backend/app/schemas/auth.py
@@ -29,6 +29,7 @@ def validate_password_strength(v: str) -> str:
"nl",
"pl",
"ro",
+ "tr",
}
SUPPORTED_TARGET_LANGUAGES: set[str] = {
@@ -65,6 +66,7 @@ def get_available_languages() -> list[str]:
"nl",
"ro",
"ru",
+ "tr",
}
VALID_LEARNING_GOALS: set[str] = {
diff --git a/backend/app/services/email_service.py b/backend/app/services/email_service.py
index 8c5802095..7bf6d731a 100644
--- a/backend/app/services/email_service.py
+++ b/backend/app/services/email_service.py
@@ -122,6 +122,14 @@ def _get_mail_config() -> ConnectionConfig:
"link_fallback": "\u0415\u0441\u043b\u0438 \u043a\u043d\u043e\u043f\u043a\u0430 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u0441\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u0438 \u0432\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u044d\u0442\u0443 \u0441\u0441\u044b\u043b\u043a\u0443 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440:",
"footer": "\u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u0438 \u044d\u0442\u043e\u0442 \u0430\u043a\u043a\u0430\u0443\u043d\u0442, \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u044d\u0442\u043e \u043f\u0438\u0441\u044c\u043c\u043e.",
},
+ "tr": {
+ "greeting": "Merhaba {name},",
+ "subject": "FreeLingo hesab\u0131n\u0131z\u0131 do\u011frulay\u0131n",
+ "body": "FreeLingo hesab\u0131n\u0131z\u0131 olu\u015fturdu\u011funuz i\u00e7in te\u015fekk\u00fcr ederiz.
L\u00fctfen a\u015fa\u011f\u0131daki d\u00fc\u011fmeye t\u0131klayarak e-posta adresinizi do\u011frulay\u0131n. Bu ba\u011flant\u0131 24 saat ge\u00e7erlidir.",
+ "button": "Hesab\u0131m\u0131 do\u011frula",
+ "link_fallback": "D\u00fc\u011fme \u00e7al\u0131\u015fmazsa bu ba\u011flant\u0131y\u0131 kopyalay\u0131p taray\u0131c\u0131n\u0131za yap\u0131\u015ft\u0131r\u0131n:",
+ "footer": "Bu hesab\u0131 siz olu\u015fturmad\u0131ysan\u0131z bu e-postay\u0131 yok sayabilirsiniz.",
+ },
}
_RESET_I18N: dict[str, dict[str, str]] = {
@@ -205,6 +213,14 @@ def _get_mail_config() -> ConnectionConfig:
"link_fallback": "\u0415\u0441\u043b\u0438 \u043a\u043d\u043e\u043f\u043a\u0430 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u0441\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u0438 \u0432\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u044d\u0442\u0443 \u0441\u0441\u044b\u043b\u043a\u0443 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440:",
"footer": "\u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u043b\u0438 \u0441\u0431\u0440\u043e\u0441, \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u044d\u0442\u043e \u043f\u0438\u0441\u044c\u043c\u043e.",
},
+ "tr": {
+ "greeting": "Merhaba {name},",
+ "subject": "FreeLingo parolan\u0131z\u0131 s\u0131f\u0131rlay\u0131n",
+ "body": "FreeLingo hesab\u0131n\u0131z\u0131n parolas\u0131n\u0131 s\u0131f\u0131rlama iste\u011fi ald\u0131k.
Yeni bir parola olu\u015fturmak i\u00e7in a\u015fa\u011f\u0131daki d\u00fc\u011fmeye t\u0131klay\u0131n. Bu ba\u011flant\u0131 1 saat ge\u00e7erlidir.",
+ "button": "Parolam\u0131 s\u0131f\u0131rla",
+ "link_fallback": "D\u00fc\u011fme \u00e7al\u0131\u015fmazsa bu ba\u011flant\u0131y\u0131 kopyalay\u0131p taray\u0131c\u0131n\u0131za yap\u0131\u015ft\u0131r\u0131n:",
+ "footer": "Parola s\u0131f\u0131rlama iste\u011finde bulunmad\u0131ysan\u0131z bu e-postay\u0131 g\u00fcvenle yok sayabilirsiniz.",
+ },
}
_WELCOME_I18N: dict[str, dict[str, str]] = {
@@ -308,6 +324,16 @@ def _get_mail_config() -> ConnectionConfig:
"button": "\u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f",
"footer": "\u0423\u0441\u043f\u0435\u0445\u043e\u0432 \u0432 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0438!",
},
+ "tr": {
+ "subject": "FreeLingo'ya ho\u015f geldiniz!",
+ "greeting": "Merhaba {name},",
+ "body": "Hesab\u0131n\u0131z haz\u0131r. Ba\u015flamak i\u00e7in \u015funlar\u0131 yapabilirsiniz:",
+ "step1": "Seviye Tespitine girin \u2014 mevcut seviyenizi (A1\u2013C2), g\u00fc\u00e7l\u00fc ve zay\u0131f y\u00f6nlerinizi belirler.",
+ "step2": "\u00c7al\u0131\u015fma Plan\u0131n\u0131z\u0131 olu\u015fturun \u2014 seviyenize ve hedeflerinize g\u00f6re haz\u0131rlanm\u0131\u015f haftal\u0131k bir program.",
+ "step3": "\u0130lk g\u00fcnl\u00fck dersinizi tamamlay\u0131n ve serinizi olu\u015fturmaya ba\u015flay\u0131n.",
+ "button": "Panoma git",
+ "footer": "\u0130yi \u00e7al\u0131\u015fmalar!",
+ },
}
@@ -372,6 +398,12 @@ def _get_mail_config() -> ConnectionConfig:
"body": "\u0412\u0430\u0448 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 FreeLingo \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0443\u0434\u0430\u043b\u0451\u043d. \u0412\u0441\u0435 \u0432\u0430\u0448\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u044b\u043b\u0438 \u043d\u0430\u0432\u0441\u0435\u0433\u0434\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u044b \u0441 \u043d\u0430\u0448\u0438\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432.",
"footer": "\u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u043b\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435, \u043d\u0435\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e \u0441\u0432\u044f\u0436\u0438\u0442\u0435\u0441\u044c \u0441 \u043d\u0430\u043c\u0438.",
},
+ "tr": {
+ "subject": "FreeLingo hesab\u0131n\u0131z silindi",
+ "greeting": "Merhaba {name},",
+ "body": "FreeLingo hesab\u0131n\u0131z ba\u015far\u0131yla silindi. T\u00fcm verileriniz sunucular\u0131m\u0131zdan kal\u0131c\u0131 olarak kald\u0131r\u0131ld\u0131.",
+ "footer": "Bu silme i\u015flemini siz istemediyseniz l\u00fctfen hemen bizimle ileti\u015fime ge\u00e7in.",
+ },
}
_CONTACT_I18N: dict[str, dict[str, str]] = {
@@ -465,6 +497,15 @@ def _get_mail_config() -> ConnectionConfig:
"message_label": "Сообщение",
"footer": "Отправлено через контактную форму FreeLingo",
},
+ "tr": {
+ "email_title": "İletişim formu mesajı",
+ "subject_prefix": "[FreeLingo İletişim]",
+ "logo": "FreeLingo: İletişim Formu",
+ "from_label": "Gönderen",
+ "subject_label": "Konu",
+ "message_label": "Mesaj",
+ "footer": "FreeLingo iletişim formu aracılığıyla gönderildi",
+ },
}
_FEEDBACK_I18N: dict[str, dict[str, str]] = {
@@ -598,6 +639,19 @@ def _get_mail_config() -> ConnectionConfig:
"cta": "Открыть в панели администратора",
"footer": "Доска отзывов FreeLingo",
},
+ "tr": {
+ "email_title": "Yeni geri bildirim gönderildi",
+ "logo": "FreeLingo: Yeni Geri Bildirim",
+ "feature_label": "Özellik isteği",
+ "bug_label": "Hata bildirimi",
+ "feature_subject_prefix": "[Özellik İsteği]",
+ "bug_subject_prefix": "[Hata Bildirimi]",
+ "author_label": "Gönderen",
+ "title_label": "Başlık",
+ "description_label": "Açıklama",
+ "cta": "Yönetim panelinde görüntüle",
+ "footer": "FreeLingo geri bildirim panosu",
+ },
}
_REVIEW_I18N: dict[str, dict[str, str]] = {
@@ -721,6 +775,18 @@ def _get_mail_config() -> ConnectionConfig:
"cta": "Открыть в панели администратора",
"footer": "Модерация отзывов FreeLingo",
},
+ "tr": {
+ "email_title": "Yeni yorum gönderildi",
+ "subject_prefix": "[Yeni Yorum]",
+ "logo": "FreeLingo: Yeni Yorum",
+ "author_label": "Gönderen",
+ "rating_label": "Puan",
+ "language_label": "Öğrenilen dil",
+ "comment_label": "Yorum",
+ "empty_comment": "Yorum yazılmadı.",
+ "cta": "Yönetim panelinde görüntüle",
+ "footer": "FreeLingo yorum moderasyonu",
+ },
}
diff --git a/backend/app/services/language_helpers.py b/backend/app/services/language_helpers.py
index 37094d13c..79e55c00d 100644
--- a/backend/app/services/language_helpers.py
+++ b/backend/app/services/language_helpers.py
@@ -135,6 +135,7 @@
"nl": "Spraaksessie",
"ro": "Sesiune vocală",
"ru": "Голосовая сессия",
+ "tr": "Sesli oturum",
}
_NATIVE_LANGUAGE_NAMES: dict[str, str] = {
@@ -148,6 +149,7 @@
"nl": "Dutch",
"ro": "Romanian",
"ru": "Russian",
+ "tr": "Turkish",
}
_MONTH_NAMES: dict[str, list[str]] = {
@@ -277,6 +279,20 @@
"ноября",
"декабря",
],
+ "tr": [
+ "Ocak",
+ "Şubat",
+ "Mart",
+ "Nisan",
+ "Mayıs",
+ "Haziran",
+ "Temmuz",
+ "Ağustos",
+ "Eylül",
+ "Ekim",
+ "Kasım",
+ "Aralık",
+ ],
}
diff --git a/backend/tests/test_conversation.py b/backend/tests/test_conversation.py
index 394c65f04..86867b385 100644
--- a/backend/tests/test_conversation.py
+++ b/backend/tests/test_conversation.py
@@ -577,11 +577,21 @@ def test_voice_session_title_russian() -> None:
assert " de " not in date_part
+def test_voice_session_title_turkish() -> None:
+ """Turkish uses its own label and plain 'D Month YYYY' format."""
+ from app.services.language_helpers import voice_session_title
+
+ title = voice_session_title("tr")
+ assert title.startswith("Sesli oturum — ")
+ date_part = title.split(" — ", 1)[1]
+ assert " de " not in date_part
+
+
def test_voice_session_title_all_supported_languages_produce_nonempty() -> None:
"""Every supported native language must produce a non-empty title."""
from app.services.language_helpers import voice_session_title
- supported = ["es", "fr", "pt", "de", "it", "pl", "nl", "ro", "ru"]
+ supported = ["es", "fr", "pt", "de", "it", "pl", "nl", "ro", "ru", "tr"]
for lang in supported:
title = voice_session_title(lang)
assert title.strip(), f"Empty title for language '{lang}'"
diff --git a/frontend/src/app/(app)/admin/users/page.tsx b/frontend/src/app/(app)/admin/users/page.tsx
index 7cb6e40f4..19d09c145 100644
--- a/frontend/src/app/(app)/admin/users/page.tsx
+++ b/frontend/src/app/(app)/admin/users/page.tsx
@@ -54,6 +54,7 @@ const LANGUAGES = [
'nl',
'ro',
'ru',
+ 'tr',
] as const
const PAGE_SIZE = 10
diff --git a/frontend/src/app/(auth)/register/page.tsx b/frontend/src/app/(auth)/register/page.tsx
index 82c9a178f..ec6236bd5 100644
--- a/frontend/src/app/(auth)/register/page.tsx
+++ b/frontend/src/app/(auth)/register/page.tsx
@@ -22,6 +22,7 @@ const LANGUAGES = [
'nl',
'ro',
'ru',
+ 'tr',
] as const
type SelectedPlan = 'monthly' | 'yearly'
diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx
index 5259bd1f1..c43d4928d 100644
--- a/frontend/src/app/layout.tsx
+++ b/frontend/src/app/layout.tsx
@@ -115,7 +115,7 @@ export default async function RootLayout({
{process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID && (
diff --git a/frontend/src/components/settings/ProfileSection.tsx b/frontend/src/components/settings/ProfileSection.tsx
index c3b850972..e7b926585 100644
--- a/frontend/src/components/settings/ProfileSection.tsx
+++ b/frontend/src/components/settings/ProfileSection.tsx
@@ -20,6 +20,7 @@ const LANGUAGES = [
'nl',
'ro',
'ru',
+ 'tr',
] as const
function resizeImage(file: File, maxPx: number): Promise {
diff --git a/frontend/src/lib/locales.ts b/frontend/src/lib/locales.ts
index d5822cb9c..0a8242367 100644
--- a/frontend/src/lib/locales.ts
+++ b/frontend/src/lib/locales.ts
@@ -13,6 +13,7 @@ export const SUPPORTED_LOCALES = [
'nl',
'ro',
'ru',
+ 'tr',
] as const
export type Locale = (typeof SUPPORTED_LOCALES)[number]
diff --git a/frontend/src/lib/target-languages.ts b/frontend/src/lib/target-languages.ts
index 038523a39..397952676 100644
--- a/frontend/src/lib/target-languages.ts
+++ b/frontend/src/lib/target-languages.ts
@@ -172,7 +172,7 @@ export function getTargetLanguageTextClass(code: string): string {
export const DEFAULT_TARGET_LANGUAGE = 'en-GB'
-const LOCALES_CAPITALIZE_LANGUAGE = new Set(['en', 'de', 'nl'])
+const LOCALES_CAPITALIZE_LANGUAGE = new Set(['en', 'de', 'nl', 'tr'])
export function formatLanguageName(name: string, locale: string): string {
const lang = locale.split('-')[0]
diff --git a/frontend/tests/app/onboarding-goals-subtitle.test.tsx b/frontend/tests/app/onboarding-goals-subtitle.test.tsx
index 1a25a1370..5c0f09b6a 100644
--- a/frontend/tests/app/onboarding-goals-subtitle.test.tsx
+++ b/frontend/tests/app/onboarding-goals-subtitle.test.tsx
@@ -16,6 +16,7 @@ import pl from '../../../messages/pl.json'
import pt from '../../../messages/pt.json'
import ro from '../../../messages/ro.json'
import ru from '../../../messages/ru.json'
+import tr from '../../../messages/tr.json'
const { searchParams, apiFetch } = vi.hoisted(() => ({
searchParams: new URLSearchParams(),
@@ -31,7 +32,7 @@ vi.mock('@/lib/api', () => ({ apiFetch }))
import OnboardingPage from '@/app/(auth)/onboarding/page'
-const catalogs = { de, en, es, fr, it: itMessages, nl, pl, pt, ro, ru }
+const catalogs = { de, en, es, fr, it: itMessages, nl, pl, pt, ro, ru, tr }
type Locale = keyof typeof catalogs
const spanishSubtitles: Record = {
@@ -45,6 +46,7 @@ const spanishSubtitles: Record = {
pt: 'Idioma: espanhol. Para que você quer usá-lo? Selecione todos os objetivos que se aplicam.',
ro: 'Limbă: spaniolă. Pentru ce vrei să o folosești? Selectează toate obiectivele care ți se potrivesc.',
ru: 'Язык: испанский. Для чего ты хочешь его использовать? Выбери все подходящие цели.',
+ tr: 'Dil: İspanyolca. Bu dili ne için kullanmak istiyorsunuz? Uygun olanların hepsini seçin.',
}
const onIntlError = vi.fn()
diff --git a/frontend/tests/components/ProfileSection.test.tsx b/frontend/tests/components/ProfileSection.test.tsx
index 6e1cf8e91..c996bfa60 100644
--- a/frontend/tests/components/ProfileSection.test.tsx
+++ b/frontend/tests/components/ProfileSection.test.tsx
@@ -804,6 +804,7 @@ describe('ProfileSection', () => {
expect(options).toContain('nl')
expect(options).toContain('ro')
expect(options).toContain('ru')
+ expect(options).toContain('tr')
})
it('renders all ui locale options', () => {
@@ -820,6 +821,7 @@ describe('ProfileSection', () => {
expect(options).toContain('nl')
expect(options).toContain('ro')
expect(options).toContain('ru')
+ expect(options).toContain('tr')
})
// ── Avatar upload buttons ───────────────────────────────────
diff --git a/frontend/tests/i18n/admin-messages.test.ts b/frontend/tests/i18n/admin-messages.test.ts
index 2ad663ed4..469cd0399 100644
--- a/frontend/tests/i18n/admin-messages.test.ts
+++ b/frontend/tests/i18n/admin-messages.test.ts
@@ -9,8 +9,9 @@ import pl from '../../../messages/pl.json'
import pt from '../../../messages/pt.json'
import ro from '../../../messages/ro.json'
import ru from '../../../messages/ru.json'
+import tr from '../../../messages/tr.json'
-const locales = { de, es, fr, it: itMessages, nl, pl, pt, ro, ru }
+const locales = { de, es, fr, it: itMessages, nl, pl, pt, ro, ru, tr }
describe('admin i18n messages', () => {
it('keeps admin namespace keys in sync across locales', () => {
diff --git a/messages/de.json b/messages/de.json
index aa2f62af4..b795bc5cf 100644
--- a/messages/de.json
+++ b/messages/de.json
@@ -1234,6 +1234,7 @@
"nl": "Niederländisch",
"ro": "Rumänisch",
"ru": "Russisch",
+ "tr": "Türkisch",
"myLanguages": "Meine Sprachen",
"addLanguage": "Sprache hinzufügen",
"selectLanguage": "Wähle die Sprache, die du lernen möchtest",
diff --git a/messages/en.json b/messages/en.json
index ce3eaf3d2..25e783bb5 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -1234,6 +1234,7 @@
"nl": "Dutch",
"ro": "Romanian",
"ru": "Russian",
+ "tr": "Turkish",
"myLanguages": "My Languages",
"addLanguage": "Add new language",
"selectLanguage": "Select the language you want to learn",
diff --git a/messages/es.json b/messages/es.json
index b27a12406..11782ced1 100644
--- a/messages/es.json
+++ b/messages/es.json
@@ -1234,6 +1234,7 @@
"nl": "Neerlandés",
"ro": "Rumano",
"ru": "Ruso",
+ "tr": "Turco",
"myLanguages": "Mis idiomas",
"addLanguage": "Añadir idioma",
"selectLanguage": "Selecciona el idioma que quieres aprender",
diff --git a/messages/fr.json b/messages/fr.json
index 1989d51ad..910cf6363 100644
--- a/messages/fr.json
+++ b/messages/fr.json
@@ -1234,6 +1234,7 @@
"nl": "Néerlandais",
"ro": "Roumain",
"ru": "Russe",
+ "tr": "Turc",
"myLanguages": "Mes langues",
"addLanguage": "Ajouter une langue",
"selectLanguage": "Choisissez la langue que vous voulez apprendre",
diff --git a/messages/it.json b/messages/it.json
index 572c1a756..d027be10a 100644
--- a/messages/it.json
+++ b/messages/it.json
@@ -1234,6 +1234,7 @@
"nl": "Olandese",
"ro": "Rumeno",
"ru": "Russo",
+ "tr": "Turco",
"myLanguages": "Le mie lingue",
"addLanguage": "Aggiungi lingua",
"selectLanguage": "Seleziona la lingua che vuoi imparare",
diff --git a/messages/nl.json b/messages/nl.json
index 84196e65a..ecbfc0d6a 100644
--- a/messages/nl.json
+++ b/messages/nl.json
@@ -1234,6 +1234,7 @@
"nl": "Nederlands",
"ro": "Roemeens",
"ru": "Russisch",
+ "tr": "Turks",
"myLanguages": "Mijn talen",
"addLanguage": "Taal toevoegen",
"selectLanguage": "Kies de taal die je wilt leren",
diff --git a/messages/pl.json b/messages/pl.json
index 11e10f47d..af379cbb7 100644
--- a/messages/pl.json
+++ b/messages/pl.json
@@ -1234,6 +1234,7 @@
"nl": "Niderlandzki",
"ro": "Rumuński",
"ru": "Rosyjski",
+ "tr": "Turecki",
"myLanguages": "Moje języki",
"addLanguage": "Dodaj język",
"selectLanguage": "Wybierz język, którego chcesz się uczyć",
diff --git a/messages/pt.json b/messages/pt.json
index b93d321c8..89b42cb85 100644
--- a/messages/pt.json
+++ b/messages/pt.json
@@ -1234,6 +1234,7 @@
"nl": "Neerlandês",
"ro": "Romeno",
"ru": "Russo",
+ "tr": "Turco",
"myLanguages": "Meus idiomas",
"addLanguage": "Adicionar idioma",
"selectLanguage": "Selecione o idioma que deseja aprender",
diff --git a/messages/ro.json b/messages/ro.json
index 3b66a1f66..d3b6af4ba 100644
--- a/messages/ro.json
+++ b/messages/ro.json
@@ -1234,6 +1234,7 @@
"nl": "Olandeză",
"ro": "Română",
"ru": "Rusă",
+ "tr": "Turcă",
"myLanguages": "Limbile mele",
"addLanguage": "Adaugă limbă",
"selectLanguage": "Alege limba pe care vrei să o înveți",
diff --git a/messages/ru.json b/messages/ru.json
index 07ca35a14..e83bd5c22 100644
--- a/messages/ru.json
+++ b/messages/ru.json
@@ -1234,6 +1234,7 @@
"nl": "Нидерландский",
"ro": "Румынский",
"ru": "Русский",
+ "tr": "Турецкий",
"myLanguages": "Мои языки",
"addLanguage": "Добавить язык",
"selectLanguage": "Выберите язык, который хотите изучать",
diff --git a/messages/tr.json b/messages/tr.json
new file mode 100644
index 000000000..c2518a007
--- /dev/null
+++ b/messages/tr.json
@@ -0,0 +1,1695 @@
+{
+ "landing": {
+ "microDemo": {
+ "title": "Lingu size şöyle yardımcı olur",
+ "exampleLabel": "İngilizce pratik örneği",
+ "questionLabel": "Lingu · Soru",
+ "answerLabel": "Siz · Cevap",
+ "correctionLabel": "Lingu · Düzeltme",
+ "explanation": "Dün hakkında konuşmak için 'go' fiilinin geçmiş zaman hâli olan 'went' kullanılır."
+ },
+ "hero": "Gerçek bir sesli konuşma partneriyle dil öğrenin",
+ "heroSub": "Konuşun. Dinleyin. Gelişin.",
+ "signIn": "Giriş yap",
+ "dashboard": "Devam et",
+ "feature1Title": "Öğrenme Planı",
+ "feature1Desc": "Seviye tespiti + A1'den C2'ye haftalık plan. Dersler sırayla, kendi hızınızda açılır.",
+ "feature2Title": "Yapay Zekâ Sohbet Eğitmeni",
+ "feature2Desc": "Eğitmeninizin rehberliğinde derslerle, alıştırmalarla ve bilgi kartlarıyla pratik yapın. Her adımda geri bildirim alın.",
+ "feature3Title": "Sesli Konuşma",
+ "feature3Desc": "Eğitmeninizle gerçek zamanlı konuşun. Sesle etkinleşir, anında yanıt verir, sıra beklemek yok.",
+ "feature4Title": "Dinleme ve Okuma",
+ "feature4Desc": "CEFR seviyenize uygun, yapay zekâ ile üretilmiş alıştırmalar. Bir metni dinleyin, 5 anlama sorusunu cevaplayın ve deşifreyi açın — ya da bir metni okuyup soruları doğrudan cevaplayın. İstediğiniz zaman yeni alıştırmalar.",
+ "feature5Title": "Bilgi Kartları",
+ "feature5Desc": "Aralıklı tekrarla kelime tekrarı. SM-2 algoritması, uzun süreli akılda kalıcılığı en üst düzeye çıkarmak için her kartı en uygun zamana planlar.",
+ "feature6Title": "İlerleme ve Seriler",
+ "feature6Desc": "XP, günlük seriler, beceri puanları ve ünite yeterlilikleri. Gelişiminizi hafta hafta takip edin ve her CEFR aşamasının sonunda seviyenizi test edin.",
+ "footer": "Açık kaynak · Ücretsiz olarak kendiniz barındırın veya barındırılan hizmete abone olun",
+ "navFeatures": "Özellikler",
+ "navReviews": "Yorumlar",
+ "navPricing": "Fiyatlandırma",
+ "navFAQ": "SSS",
+ "howItWorks": "Nasıl çalışır",
+ "faqTitle": "Sıkça Sorulan Sorular",
+ "terms": "Koşullar",
+ "privacy": "Gizlilik",
+ "contact": "İletişim",
+ "aboutMe": "Hakkımda",
+ "github": "GitHub",
+ "footerProduct": "Ürün",
+ "footerLegal": "Yasal",
+ "languageGreetings": {
+ "en-US": "Hello!",
+ "en-GB": "Hello!",
+ "de-DE": "Hallo!",
+ "es-ES": "¡Hola!",
+ "fr-FR": "Bonjour !",
+ "it-IT": "Ciao!",
+ "pt-PT": "Olá!",
+ "ja-JP": "こんにちは!",
+ "ko-KR": "안녕하세요!",
+ "zh-CN": "你好!"
+ }
+ },
+ "common": {
+ "loading": "Yükleniyor...",
+ "error": "Hata",
+ "save": "Değişiklikleri kaydet",
+ "saving": "Kaydediliyor...",
+ "cancel": "İptal",
+ "back": "Geri",
+ "done": "Tamam",
+ "next": "İleri",
+ "submit": "Gönder",
+ "start": "Başla",
+ "retry": "Tekrar dene",
+ "or": "veya",
+ "appName": "FreeLingo",
+ "days": "gün",
+ "logout": "Çıkış yap",
+ "logoutConfirmTitle": "Çıkış Yap",
+ "logoutConfirmMessage": "Çıkış yapmak istediğinizden emin misiniz?",
+ "initializing": "Başlatılıyor...",
+ "clearFilters": "Filtreleri temizle",
+ "all": "Tümü",
+ "score": "Puan",
+ "complete": "Tamamla",
+ "checking": "Kontrol ediliyor...",
+ "backToDashboard": "Panoya dön",
+ "tagline": "Yapay zekâ ile dil öğrenimi",
+ "close": "Kapat",
+ "verifyEmailBanner": "Hesap kurulumunuzu tamamlamak için lütfen e-posta adresinizi doğrulayın.",
+ "verifyEmailSent": "E-posta gönderildi. Gelen kutunuzu kontrol edin.",
+ "resendVerification": "Doğrulama e-postasını tekrar gönder",
+ "saveWord": "Kaydet",
+ "wordSaved": "Kaydedildi",
+ "wordAlreadySaved": "Zaten kaydedilmiş",
+ "wordSaveError": "Bir şeyler ters gitti",
+ "selectWordHint": "Kelime dağarcığınıza kaydetmek için bir kelime seçin",
+ "noActivePlan": "Etkin bir çalışma planı bulunamadı",
+ "memorySavedToast": "Lingu yeni bir anı kaydetti. Ayarlar'dan inceleyebilirsiniz.",
+ "removeLanguageConfirmTitle": "Dili kaldır",
+ "removeLanguageConfirmMessage": "Bu dile ait tüm veriler (çalışma planı, ilerleme, bilgi kartları ve konuşmalar) kalıcı olarak silinecek. Hesabınıza ait anılar korunacak. Bu işlem geri alınamaz.",
+ "removeLanguageConfirmLabel": "Kaldır",
+ "nativeHelpTitle": "{language} yardım",
+ "nativeHelpLoading": "{language} yardım hazırlanıyor...",
+ "nativeHelpShow": "{language} yardımı göster",
+ "nativeHelpKeyPoints": "Önemli noktalar",
+ "nativeHelpCommonTraps": "Sık yapılan hatalar",
+ "nativeHelpMiniGlossary": "Mini sözlük",
+ "nativeHelpUsageTips": "Kullanım ipuçları",
+ "nativeHelpRegisterNotes": "Üslup",
+ "nativeHelpPhraseNotes": "İfade notları",
+ "nativeHelpStudyTips": "Çalışma ipuçları",
+ "nativeHelpWordNotes": "Kelime notları",
+ "nativeHelpPractice": "Pratik"
+ },
+ "nav": {
+ "home": "Ana sayfa",
+ "myPlan": "Planım",
+ "progress": "İlerleme",
+ "flashcards": "Bilgi Kartları",
+ "tutor": "Eğitmenle sohbet",
+ "assessment": "Seviye Tespiti",
+ "resources": "Kaynaklar",
+ "grammar": "Dil Bilgisi",
+ "vocabulary": "Kelime Bilgisi",
+ "phrasebook": "Konuşma Kılavuzu",
+ "settings": "Ayarlar",
+ "faq": "SSS",
+ "admin": "Yönetim",
+ "conversation": "Konuşma",
+ "listening": "Dinleme",
+ "reading": "Okuma",
+ "contact": "İletişim",
+ "feedback": "Geri Bildirim",
+ "reviews": "Yorumlar",
+ "switchLanguage": "Dil değiştir"
+ },
+ "auth": {
+ "login": {
+ "title": "Giriş yap",
+ "subtitle": "Tekrar hoş geldiniz",
+ "email": "E-posta",
+ "password": "Parola",
+ "submit": "Giriş yap",
+ "noAccount": "Hesabınız yok mu?",
+ "register": "Kaydol",
+ "error": "Geçersiz e-posta veya parola",
+ "emailRequired": "Lütfen e-posta adresinizi girin",
+ "passwordRequired": "Lütfen parolanızı girin",
+ "loginFailed": "Giriş başarısız",
+ "signingIn": "Giriş yapılıyor...",
+ "showPassword": "Parolayı göster",
+ "hidePassword": "Parolayı gizle",
+ "accountCreated": "Hesap oluşturuldu. Artık giriş yapabilirsiniz",
+ "invalidEmail": "Lütfen geçerli bir e-posta adresi girin",
+ "forgotPassword": "Parolanızı mı unuttunuz?"
+ },
+ "register": {
+ "title": "Hesap oluştur",
+ "subtitle": "Öğrenmeye başlayın",
+ "username": "Kullanıcı adı",
+ "email": "E-posta",
+ "password": "Parola",
+ "displayName": "Görünen ad",
+ "nativeLanguage": "Ana dil",
+ "inviteToken": "Davet kodu",
+ "inviteTokenPlaceholder": "Davet kodunu girin",
+ "submit": "Hesap oluştur",
+ "hasAccount": "Zaten hesabınız var mı?",
+ "login": "Giriş yap",
+ "registrationClosed": "Kayıtlar kapalı. Bir davet koduna ihtiyacınız var.",
+ "error": "Kayıt başarısız",
+ "passwordMismatch": "Parolalar eşleşmiyor",
+ "confirmPassword": "Parolayı Onayla",
+ "showPassword": "Parolayı göster",
+ "hidePassword": "Parolayı gizle",
+ "displayNamePlaceholder": "Boş bırakılırsa kullanıcı adıyla aynı olur",
+ "inviteActive": "Davet etkin",
+ "creatingAccount": "Oluşturuluyor...",
+ "invalidEmail": "Lütfen geçerli bir e-posta adresi girin",
+ "usernameTaken": "Bu kullanıcı adı zaten alınmış",
+ "emailTaken": "Bu e-posta adresi zaten kayıtlı",
+ "invalidInvite": "Geçersiz veya süresi dolmuş davet kodu",
+ "termsAccept": "Okudum ve kabul ediyorum:",
+ "termsLink": "Hizmet Koşulları",
+ "andWord": "ve",
+ "privacyLink": "Gizlilik Politikası",
+ "termsRequired": "Devam etmek için koşulları kabul etmelisiniz",
+ "invalidPassword": "Parola 10-25 karakter olmalı ve en az bir büyük harf, bir rakam ve bir sembol içermelidir",
+ "invalidUsernameChars": "Kullanıcı adı yalnızca harf, rakam, kısa çizgi, alt çizgi ve nokta içerebilir"
+ },
+ "verifyEmail": {
+ "title": "E-posta doğrulama",
+ "loading": "Doğrulanıyor...",
+ "success": "E-posta adresiniz doğrulandı. Artık giriş yapabilirsiniz.",
+ "error": "Geçersiz veya süresi dolmuş doğrulama bağlantısı. Lütfen hesabınızdan yeni bir bağlantı isteyin.",
+ "goToLogin": "Girişe git"
+ },
+ "forgotPassword": {
+ "title": "Parolamı unuttum",
+ "description": "Hesabınızla ilişkili e-posta adresini girin, size bir sıfırlama bağlantısı gönderelim.",
+ "emailPlaceholder": "adiniz@eposta.com",
+ "submit": "Sıfırlama bağlantısı gönder",
+ "sending": "Gönderiliyor...",
+ "sent": "Bu e-posta adresi kayıtlıysa bir sıfırlama bağlantısı gönderildi. Gelen kutunuzu kontrol edin.",
+ "backToLogin": "Girişe dön",
+ "error": "Bir şeyler ters gitti. Lütfen tekrar deneyin."
+ },
+ "resetPassword": {
+ "title": "Parolayı sıfırla",
+ "newPassword": "Yeni parola",
+ "confirmPassword": "Yeni parolayı onayla",
+ "submit": "Yeni parolayı belirle",
+ "saving": "Kaydediliyor...",
+ "success": "Parola güncellendi. Giriş sayfasına yönlendiriliyorsunuz...",
+ "mismatch": "Parolalar eşleşmiyor",
+ "tooShort": "Parola en az 8 karakter olmalıdır",
+ "missingToken": "Geçersiz sıfırlama bağlantısı. Lütfen yeni bir parola sıfırlama isteyin.",
+ "error": "Geçersiz veya süresi dolmuş sıfırlama bağlantısı",
+ "backToLogin": "Girişe dön"
+ }
+ },
+ "settings": {
+ "title": "Ayarlar",
+ "sectionAccount": "Hesap",
+ "sectionProfile": "Profil",
+ "avatarChange": "Fotoğrafı değiştir",
+ "avatarRemove": "Kaldır",
+ "avatarUploading": "Yükleniyor...",
+ "avatarTypeError": "Yalnızca JPEG ve PNG görsellere izin verilir",
+ "avatarSizeError": "Görsel çok büyük (en fazla 2 MB)",
+ "displayName": "Görünen Ad",
+ "email": "E-posta",
+ "nativeLanguage": "Ana Dil",
+ "uiLocale": "Arayüz Dili",
+ "uiLocaleHint": "Menülerin ve düğmelerin dilini değiştirir. Sayfanın yeniden yüklenmesi gerekir.",
+ "newPassword": "Yeni Parola",
+ "newPasswordPlaceholder": "Değiştirmemek için boş bırakın",
+ "confirmPassword": "Parolayı Onayla",
+ "confirmPasswordPlaceholder": "Yeni parolayı tekrar girin",
+ "bio": "Hakkınızda (Yapay Zekâ Bağlamı)",
+ "bioPlaceholder": "ör. İş nedeniyle sık sık seyahat eden bir yazılım geliştiricisiyim...",
+ "bioHint": "Yapay zekâ eğitmeni, konuşmaları kişiselleştirmek için bu bilgiyi kullanır.",
+ "saveChanges": "Değişiklikleri Kaydet",
+ "saving": "Kaydediliyor...",
+ "saved": "Profil güncellendi.",
+ "passwordMismatch": "Parolalar eşleşmiyor",
+ "saveFailed": "Kaydedilemedi",
+ "logout": "Çıkış yap",
+ "sectionAppearance": "Görünüm",
+ "theme": "Tema",
+ "darkActive": "Koyu mod etkin",
+ "lightActive": "Açık mod etkin",
+ "systemActive": "Otomatik (sistem)",
+ "themeSystem": "Otomatik",
+ "themeDark": "Koyu",
+ "themeLight": "Açık",
+ "switchToLight": "Açık temaya geç",
+ "switchToDark": "Koyu temaya geç",
+ "sectionConversation": "Konuşma",
+ "conversationMaxDuration": "En Uzun Oturum Süresi",
+ "conversationInactivityTimeout": "Hareketsizlik Zaman Aşımı",
+ "conversationSpeechPause": "Sıra Sonu Duraklaması",
+ "conversationSpeechPauseHint": "Sıranız gönderilmeden önce cümle ortasında ne kadar duraklayabileceğiniz. Otomatik seçenek seviyenize göre ayarlanır.",
+ "speechPauseAuto": "Otomatik",
+ "speechPauseSec1": "1 saniye",
+ "speechPauseSec2": "2 saniye",
+ "speechPauseSec3": "3 saniye",
+ "min15": "15 dakika",
+ "min30": "30 dakika",
+ "min1": "1 dakika",
+ "min3": "3 dakika",
+ "min5": "5 dakika",
+ "saveConversation": "Kaydet",
+ "conversationSaved": "Konuşma ayarları kaydedildi.",
+ "sectionLegal": "Yasal",
+ "termsOfService": "Hizmet Koşulları",
+ "privacyPolicy": "Gizlilik Politikası",
+ "contactLink": "İletişim",
+ "deleteAccount": "Hesabı Sil",
+ "deleteAccountTitle": "Hesabı Sil",
+ "deleteAccountMessage": "Bu işlem hesabınızı ve tüm verilerinizi kalıcı olarak silecek. Bu işlem geri alınamaz.",
+ "deleteAccountConfirm": "Hesabı Sil",
+ "sectionUsageLimits": "Kullanım Sınırları",
+ "sectionVoice": "Ses",
+ "voiceHint": "Açılır listeden tercih ettiğiniz yapay zekâ sesini seçin, ardından dinlemek için oynat'a tıklayın.",
+ "voicePlay": "Oynat",
+ "voiceStop": "Durdur",
+ "quotaSessions": "Oturum / hafta",
+ "quotaMinutesDay": "Dakika / gün",
+ "quotaMinutesWeek": "Dakika / hafta",
+ "quotaTokens": "Token / ay",
+ "quotaUnlimited": "Sınırsız",
+ "quotaLoading": "Yükleniyor...",
+ "quotaHint": "Kullanım haftalık (oturumlar ve dakikalar) ve aylık (token'lar) olarak sıfırlanır.",
+ "sectionMemory": "Anılar",
+ "memoryEmpty": "Henüz kaydedilmiş anı yok. Yapay zekâ, konuşmalar sırasında sizinle ilgili önemli ayrıntıları hatırlayacak ve buraya kaydedecek.",
+ "memoryClearAll": "Tüm Anıları Temizle",
+ "memoryClearAllTitle": "Tüm Anıları Temizle",
+ "memoryClearAllMessage": "Bu işlem kaydedilmiş tüm anıları kalıcı olarak silecek. Bu işlem geri alınamaz.",
+ "memoryClearAllConfirm": "Tümünü Temizle",
+ "memoryManage": "Anıları yönet",
+ "memoryBreadcrumb": "Anı ayarları",
+ "memoryDescription": "Anılar, öğrendiğiniz tüm diller arasında paylaşılır. Lingu konuşmalar sırasında faydalı ayrıntıları kaydedebilir; siz de buradan anı ekleyip kaldırabilirsiniz.",
+ "memoryInputLabel": "Anı ekle",
+ "memoryInputPlaceholder": "Örneğin: Kısa ve öz açıklamaları tercih ederim.",
+ "memoryInputHint": "En fazla {max} karakter",
+ "memoryAdd": "Ekle",
+ "memoryAdding": "Ekleniyor...",
+ "memoryAddSuccess": "Anı eklendi.",
+ "memoryAddError": "Anı eklenemedi. Lütfen tekrar deneyin.",
+ "memoryDuplicateError": "Bu anı zaten mevcut.",
+ "memoryLoadError": "Anılar yüklenemedi.",
+ "memoryDeleteLabel": "Anıyı sil: {content}",
+ "memoryDeleteSuccess": "Anı silindi.",
+ "memoryDeleteError": "Anı silinemedi.",
+ "memoryClearing": "Temizleniyor...",
+ "memoryClearSuccess": "Tüm anılar silindi.",
+ "memoryClearError": "Anılar temizlenemedi.",
+ "memorySourceChat": "Sohbet",
+ "memorySourceVoice": "Sesli",
+ "memorySourceManual": "Elle",
+ "memorySourceUnknown": "Anı",
+ "sectionLanguages": "Diller",
+ "languagesManage": "Dillerim",
+ "cardProfileAccess": "Profil ve erişim",
+ "cardSessionSecurity": "Oturum ve güvenlik",
+ "cardTheme": "Tema",
+ "cardConversationTiming": "Konuşma zamanlaması",
+ "cardTutorVoice": "Eğitmen sesi",
+ "cardCurrentUsage": "Mevcut kullanım",
+ "cardProductReview": "Ürün yorumu",
+ "cardLegalDocuments": "Yasal belgeler",
+ "sectionReview": "Yorum",
+ "reviewDescription": "FreeLingo deneyiminizi paylaşın. Onaylanmış bir yorumu düzenlerseniz, herkese açık olarak görünmeden önce tekrar incelemeye gönderilir.",
+ "reviewPending": "Onay bekliyor",
+ "reviewUpdate": "Güncelle",
+ "reviewSaved": "Yorum kaydedildi.",
+ "reviewDelete": "Yorumu sil",
+ "reviewDeleteTitle": "Yorumu sil",
+ "reviewDeleteMessage": "Yorumunuzu silmek istiyor musunuz? Bu işlem geri alınamaz.",
+ "reviewDeleteConfirm": "Sil",
+ "reviewDeleted": "Yorum silindi.",
+ "reviewDeleteError": "Yorumunuz silinemedi. Lütfen tekrar deneyin."
+ },
+ "legal": {
+ "terms": {
+ "pageTitle": "Hizmet Koşulları",
+ "updated": "Son güncelleme: Ağustos 2026",
+ "s1Title": "1. FreeLingo Hakkında",
+ "s1Body": "FreeLingo, iki şekilde kullanılabilen, yapay zekâ destekli açık kaynaklı bir dil öğrenme platformudur: (1) kendi altyapınızda ücretsiz olarak çalıştırdığınız, kendi kendine barındırılan kurulum ve (2) FreeLingo ekibi tarafından işletilen, ücretsiz plan ve ücretli abonelikler sunan barındırılan hizmet. Bu hizmeti her iki şekilde de kullanarak bu Hizmet Koşulları'nı kabul etmiş olursunuz.",
+ "s2Title": "2. Kabul Edilebilir Kullanım",
+ "s2Intro": "FreeLingo'yu yalnızca kişisel dil öğrenimi amacıyla kullanabilirsiniz. Aşağıdakileri yapmamayı kabul edersiniz:",
+ "s2i1": "Sistemin herhangi bir bölümüne yetkisiz erişim sağlamaya çalışmak.",
+ "s2i2": "Kötü amaçlı içerik yüklemek veya hizmeti aksatmaya çalışmak.",
+ "s2i3": "Hesap bilgilerinizi üçüncü taraflarla paylaşmak.",
+ "s2i4": "Yapay zekâ eğitmenlik özelliklerini kötüye kullanmak için otomatik betikler veya botlar kullanmak.",
+ "s3Title": "3. Kullanıcı Hesapları",
+ "s3Body": "Hesap oluşturmak ve FreeLingo'yu kullanmak için en az 16 yaşında olmalısınız. Kaydolarak bu yaş şartını karşıladığınızı onaylarsınız. Bir hesabın 16 yaşından küçük birine ait olduğunu fark edersek, hesabı ve ilişkili tüm verileri bildirimde bulunmadan sileriz. Hesap bilgilerinizin gizliliğini korumaktan ve hesabınız altında gerçekleşen tüm etkinliklerden siz sorumlusunuz. Kurulumun işletmecisi — kendi kendine barındırılan kurulumlarda siz, barındırılan hizmette FreeLingo ekibi — bu koşulları ihlal eden hesapları askıya alabilir veya kapatabilir.",
+ "s4Title": "4. İçerik ve Yapay Zekâ Etkileşimleri",
+ "s4Body": "Yapay zekâ eğitmeniyle yaptığınız konuşmalar, öğrenmenin sürekliliği için veritabanında saklanır. Barındırılan hizmette yapay zekâ sohbet ve ses özellikleri OpenAI API'si üzerinden işlenir ve içeriğiniz OpenAI'nin kullanım politikalarına tabidir. Yapay zekâ hatalı yanıtlar üretebilir — her zaman kendi muhakemenizi kullanın. FreeLingo, altta yatan dil modellerinin ürettiği içerikten sorumlu değildir. Yapay zekâ eğitmeninin ürettiği içerik (alıştırmalar, düzeltmeler, açıklamalar ve diğer materyaller) kişisel kullanımınız için size aittir. FreeLingo, konuşmalarınız veya bunlardan üretilen içerik üzerinde mülkiyet iddia etmez.",
+ "s5Title": "5. Hizmet Şekilleri",
+ "s5Body": "Kendi kendine barındırılan kurulumlar ücretsizdir ve işletmeci, verileri ile altyapısı üzerinde tam denetime sahiptir. FreeLingo ekibinin işlettiği barındırılan hizmet, kullanım sınırları olan ücretsiz bir plan ile sınırsız erişim sağlayan, aylık veya yıllık olarak alınabilen ücretli abonelikler sunar. Ücretsiz plan, 7 günlük tam erişimli bir deneme süresi (ödeme yöntemi gerekmez) ve ardından dersler ile yapay zekâ sohbeti için sınırlı günlük kotaların yanı sıra dinleme alıştırmaları, okuma alıştırmaları ve sesli konuşmalar için haftalık kotalar içerir. Ücretli abonelikler bu özelliklerdeki tüm kullanım sınırlarını kaldırır. Barındırılan hizmette verileriniz FreeLingo ekibinin işlettiği sunucularda saklanır. Hesabınız için geçerli kullanım sınırlarını panonuzda görebilirsiniz.",
+ "s6Title": "6. Abonelik ve Faturalandırma",
+ "s6Body": "Ücretsiz plan, yeni kullanıcılar için 7 günlük tam erişimli bir deneme süresiyle (ödeme yöntemi gerekmez) yapay zekâ özelliklerine sınırlı erişim sağlar. Ücretli abonelikler aylık veya yıllık olarak sunulur ve önceden iptal edilmedikçe otomatik olarak yenilenir. Aboneliğinizi istediğiniz zaman Ayarlar'dan iptal edebilirsiniz; iptal, mevcut dönemin sonunda geçerli olur. İşletmeci de hizmetin değiştirilmesi veya kapatılması durumunda yenilemeleri veya abonelikleri iptal edebilir. Hizmet, ücreti ödenmiş bir dönem bitmeden sona ererse, tüketici mevzuatının gerektirdiği her türlü iade uygulanır. Cayma hakları ve geçerli fiyatlar, yürürlükteki mevzuata uygun olarak gösterilir ve işlenir.",
+ "s7Title": "7. Erişilebilirlik",
+ "s7Body": "Barındırılan hizmet, süreklilik veya erişilebilirlik garantisi olmaksızın sunulur. İşletmeci, teknik, mali veya başka herhangi bir nedenle hizmeti istediği zaman değiştirebilir, askıya alabilir veya kapatabilir. Makul ölçüde mümkün olduğunda, planlanan kapanışlar uygulama üzerinden veya e-postayla duyurulur. Duyurulan tarihten sonra hesaplar ve operasyonel veriler geri getirilemeyecek şekilde silinebilir. FreeLingo bir yedekleme hizmeti veya otomatik dışa aktarma aracı sunmaz.",
+ "s8Title": "8. Sorumluluğun Sınırlandırılması",
+ "s8Body": "FreeLingo ve katkıda bulunanları, bu hizmeti kullanmanızdan veya kullanamamanızdan doğan hiçbir doğrudan, dolaylı, arızi veya sonuç olarak ortaya çıkan zarardan sorumlu değildir. Yürürlükteki mevzuatın izin verdiği en geniş ölçüde, toplam sorumluluk, talepten önceki üç ay içinde ödediğiniz tutarı aşamaz. Hizmeti bu koşulları ihlal ederek kullanmanızdan doğan üçüncü taraf taleplerine, zararlara veya masraflara karşı FreeLingo'yu ve katkıda bulunanlarını tazmin etmeyi ve zarardan ari tutmayı kabul edersiniz.",
+ "s9Title": "9. Uygulanacak Hukuk",
+ "s9Body": "Bu koşullar İspanya kanunlarına tabidir. İkamet ettiğiniz ülkedeki emredici tüketici koruma mevzuatı aksini öngörmedikçe, bu koşullardan doğan uyuşmazlıklarda münhasıran İspanya mahkemeleri yetkilidir.",
+ "s10Title": "10. Bu Koşullardaki Değişiklikler",
+ "s10Body": "Bu koşullar herhangi bir zamanda güncellenebilir. Önemli değişiklikler, uygun olduğunda hizmet arayüzü üzerinden veya e-postayla bildirilir. Bir değişiklikten sonra hizmeti kullanmaya devam etmeniz, güncellenmiş koşulları kabul ettiğiniz anlamına gelir.",
+ "s11Title": "11. Bölünebilirlik",
+ "s11Body": "Bu koşulların herhangi bir hükmü yetkili bir mahkeme tarafından geçersiz veya uygulanamaz bulunursa, söz konusu hüküm gereken en az ölçüde sınırlandırılır veya kaldırılır ve diğer hükümler tüm geçerliliğiyle yürürlükte kalır.",
+ "linkPrivacy": "Gizlilik Politikası",
+ "linkBack": "Kayda Dön",
+ "linkBackSettings": "Ayarlara Dön",
+ "linkContact": "Bu koşullarla ilgili sorularınız için, erişilebilir olduğu sürece freelingo.app adresindeki iletişim formunu veya FreeLingo GitHub deposunda yayımlanan iletişim kanalını kullanın."
+ },
+ "privacy": {
+ "pageTitle": "Gizlilik Politikası",
+ "updated": "Son güncelleme: Ağustos 2026",
+ "s1Title": "1. Genel Bakış",
+ "s1Body": "FreeLingo, kendi kendine barındırılan bir uygulama ve barındırılan bir hizmet olarak kullanılabilir. Kendi kendine barındırılan kurulumlarda tüm veriler yalnızca işletmecinin sunucusunda saklanır ve FreeLingo proje yazarlarının bu verilere erişimi yoktur. Barındırılan hizmette veri sorumlusu FreeLingo ekibidir ve bu politika, kişisel verilerinizin nasıl toplandığını, kullanıldığını ve korunduğunu açıklar.",
+ "s2Title": "2. Topladığımız Veriler",
+ "s2Intro": "FreeLingo 16 yaşından küçük çocuklara yönelik değildir. 16 yaşından küçük kimseden bilerek kişisel veri toplamayız. 16 yaşından küçükseniz hesap oluşturmayın ve kişisel veri paylaşmayın. Bir hesap oluşturup FreeLingo'yu kullandığınızda aşağıdaki veriler saklanır:",
+ "s2i1": "Kullanıcı adı, görünen ad ve e-posta adresi.",
+ "s2i2": "Özetlenmiş (hash) parola (bcrypt — parolanız hiçbir zaman düz metin olarak saklanmaz).",
+ "s2i3": "Ana dil tercihi ve öğrenme ayarları.",
+ "s2i4": "İsteğe bağlı profil fotoğrafı.",
+ "s2i5": "Yapay zekâ eğitmeniyle yapılan sohbet ve konuşma geçmişi.",
+ "s2i6": "Bilgi kartı desteleri, çalışma ilerlemesi ve aralıklı tekrar verileri.",
+ "s2i7": "Seviye tespiti sonuçları ve müfredat ilerlemesi.",
+ "s2i8": "Abonelik durumu, plan türü ve Stripe müşteri kimliği (ücretli hizmet aboneleri için).",
+ "s2i9": "Yapay zekâ eğitmeninin konuşmalar sırasında öğrendiği veya öğrendiğiniz diller genelinde gelecekteki etkileşimleri kişiselleştirmek için sizin elle eklediğiniz genel hesap anıları ve tercihleri.",
+ "s2i10": "Geri bildirim panosu üzerinden gönderdiğiniz özellik istekleri, hata bildirimleri, yorumlar ve oylar. Herkese açık olarak yalnızca kullanıcı adınız gösterilir; yayımlanan öneri ve bildirimleri tüm kullanıcılar görebilir.",
+ "s3Title": "3. Verilerinizi Nasıl Kullanıyoruz",
+ "s3Intro": "Verileriniz yalnızca FreeLingo öğrenme deneyimini sunmak için kullanılır:",
+ "s3i1": "Kimliğinizi doğrulamak ve oturumunuzu sürdürmek.",
+ "s3i2": "Çalışma planınızı ve eğitmen etkileşimlerinizi kişiselleştirmek.",
+ "s3i3": "Öğrenme ilerlemenizi zaman içinde takip etmek.",
+ "s3i4": "Bağlama uygun yapay zekâ eğitmeni yanıtları üretmek.",
+ "s3i5": "Yapay zekâ eğitmeninin size daha kişiselleştirilmiş etkileşimler sunabilmesi için tercihlerinizi ve bağlamınızı hatırlamak.",
+ "s3i6": "Topluluğun özellik isteklerini ve hata bildirimlerini göstermek ve yönetmek.",
+ "s3Footer": "Verileriniz hiçbir zaman satılmaz, kiralanmaz veya üçüncü taraf pazarlama hizmetleriyle paylaşılmaz.",
+ "s4Title": "4. Harici Yapay Zekâ Hizmetleri",
+ "s4Body": "Barındırılan hizmette yapay zekâ sohbeti, ses sentezi (TTS) ve ses deşifresi (STT) OpenAI API'si üzerinden sağlanır. Konuşma içeriğiniz ve ses kayıtlarınız işlenmek üzere OpenAI'ye gönderilir ve OpenAI Gizlilik Politikası'na (openai.com/privacy) tabidir. Ödeme işlemleri Stripe, Inc. (ABD) tarafından yürütülür; Stripe ödeme verilerini doğrudan işler ve biz kart bilgilerini sunucularımızda saklamayız — işlem verileriniz Stripe Gizlilik Politikası'na (stripe.com/privacy) tabidir. Kendi kendine barındırılan kurulumlarda yapay zekâ sağlayıcısını işletmeci seçer; varsayılan olarak yerel bir Ollama kurulumu kullanılır ve hiçbir veri sunucudan çıkmaz.",
+ "s5Title": "5. Çerezler ve Oturum Anahtarları",
+ "s5Body": "FreeLingo, hizmetin çalışması için kesinlikle gerekli olan iki teknik çerez kullanır: oturum kimlik doğrulaması için kullanılan refresh_token (httpOnly, 30 gün geçerli) ve dil tercihinizi hatırlamak için NEXT_LOCALE (1 yıl geçerli). İzleme veya reklam çerezi kullanılmaz. Anonim trafik ölçümü için, çerez kullanmayan, kişisel veri toplamayan ve tüm verileri kendi sunucularımızda tutan, kendi kendine barındırılan açık kaynaklı bir analiz aracı olan Umami'yi kullanırız.",
+ "s6Title": "6. Haklarınız (GDPR)",
+ "s6Body": "Avrupa Ekonomik Alanı'ndaysanız GDPR kapsamında erişim, düzeltme, silme, itiraz ve veri taşınabilirliği haklarına sahipsiniz. Hesabınızı doğrudan Ayarlar'dan silebilirsiniz. Diğer talepler 8. bölümdeki iletişim kanalı üzerinden elle işlenir; FreeLingo otomatik bir dışa aktarma aracı sunmaz. Verileri hizmeti sunmak için işleriz (GDPR md. 6(1)(b)). OpenAI ve Stripe, uluslararası aktarımlar için geçerli güvenceler kapsamında verileri ABD'de işleyebilir. İspanya Veri Koruma Kurumu'na (aepd.es) veya bulunduğunuz yerdeki denetim makamına şikâyette bulunabilirsiniz.",
+ "s7Title": "7. Verilerin Saklanması ve Silinmesi",
+ "s7Body": "Operasyonel veriler, hesabınız var olduğu ve barındırılan hizmet faaliyette olduğu sürece saklanır. Anılarınızı, dillerinizi veya hesabınızın tamamını Ayarlar'dan silebilirsiniz. İşletmeci, hizmeti kapatırken mümkün olan makul bildirimi yaptıktan sonra tüm hesapları ve verilerini de silebilir. Silme işlemi geri alınamaz. İşletmecinin denetimindeki sistemler ve kopyalar silindikten sonra FreeLingo kişisel veri saklamaz. Stripe, ödeme ve işlem bilgilerini kendi politikası ve yasal yükümlülükleri çerçevesinde saklayabilir.",
+ "s8Title": "8. İletişim",
+ "s8Body": "Barındırılan hizmetle ilgili gizlilik sorularınız için, erişilebilir olduğu sürece freelingo.app adresindeki iletişim formunu kullanın. Hizmet kapandıktan sonra FreeLingo GitHub deposunda yayımlanan iletişim kanalını kullanın ve herkese açık issue'larda kişisel veri paylaşmayın. Kendi kendine barındırılan kurulumlar için ilgili kurulumun yöneticisiyle iletişime geçin.",
+ "s9Title": "9. Bölünebilirlik",
+ "s9Body": "Bu politikanın herhangi bir hükmü geçersiz veya uygulanamaz bulunursa, söz konusu hüküm gereken en az ölçüde sınırlandırılır ve diğer hükümler tüm geçerliliğiyle yürürlükte kalır.",
+ "linkTerms": "Hizmet Koşulları",
+ "linkBack": "Kayda Dön",
+ "linkBackSettings": "Ayarlara Dön"
+ }
+ },
+ "dashboard": {
+ "welcomeBack": "Tekrar hoş geldiniz",
+ "streak": "Seri",
+ "xp": "XP",
+ "level": "Seviye",
+ "skills": "Beceriler",
+ "today": "Bugün",
+ "noSkills": "Becerilerinizi takip etmek için seviye tespitini tamamlayın.",
+ "noLessons": "Bugün için planlanmış ders yok.",
+ "lessonDone": "tamamlandı",
+ "startLesson": "Başla",
+ "loadingProgress": "İlerleme yükleniyor...",
+ "noLevel": "Henüz bir seviye belirlenmedi.",
+ "completeAssessment": "Seviye tespitine gir",
+ "allCaughtUp": "Planınız, kendi hızınızda",
+ "levelTestReady": "Seviye testiniz hazır.",
+ "levelTestReadyDesc": "Planınızın sonuna ulaştınız. İlerlemenizi doğrulamak için seviye testine girin.",
+ "levelTestCompleted": "Seviye testi tamamlandı.",
+ "levelTestScoreLine": "Final puanı: {score}. Sonucunuz Planım bölümüne kaydedildi.",
+ "startWithAssessment": "Seviye tespitiyle başlayın.",
+ "takeAssessmentArrow": "Seviye Tespitine Gir →",
+ "goToMyPlan": "Planım →",
+ "quickActions": "Hızlı İşlemler",
+ "dayProgress": "Gün {current} / {total}",
+ "skipDay": "Bugünü atla",
+ "pendingLessons": "bekleyen ders",
+ "nextStep": "Sonraki adım",
+ "assessmentCreatesPlan": "Seviye tespiti, seviyenizi belirler ve etkin diliniz için size özel bir plan oluşturur.",
+ "lessonReady": "Sonraki adımınız, kendi hızınızda",
+ "pendingStillAvailable": "Planınızda bekleyen {count} önceki ders var.",
+ "noPendingToday": "Nasıl devam edeceğinizi görmek için planınıza göz atın.",
+ "planDayGoal": "Planınızın bu günü için hedef",
+ "lessonsCompleted": "Dersler",
+ "accuracy": "Doğruluk",
+ "exerciseStats": "{correct}/{total} alıştırma",
+ "noExercisesYet": "Henüz alıştırma yok",
+ "planProgress": "Plan ilerlemesi",
+ "currentDay": "Mevcut gün",
+ "daysRemaining": "Kalan gün",
+ "completedToday": "{completed}/{total} tamamlandı",
+ "vocabularyProgress": "Kelime bilgisi {level}",
+ "vocabularyWords": "{mastered}/{total} kelime",
+ "recentPerformance": "Son performans",
+ "recentPerformanceDescription": "En son cevaplarınıza ve tekrarlarınıza göre.",
+ "performanceNeedsPractice": "Pratik gerekiyor",
+ "performanceInProgress": "Gelişiyor",
+ "performanceStrong": "Güçlü",
+ "premiumBannerTitle": "Konuşma, dinleme ve okumanın kilidini açın",
+ "premiumBannerDesc": "Ücretsiz denemeyle başlayın ve seviyenize uyarlanmış yazılı sohbet, sesli konuşma ve alıştırmalarla Lingu ile pratik yapın.",
+ "premiumBannerDescTrialUsed": "Lingu ile yazılı sohbetin, sesli konuşmanın, okuma ve dinlemenin kilidini açmak için Premium'u etkinleştirin.",
+ "premiumBannerCta": "Ücretsiz deneme",
+ "premiumBannerCtaTrialUsed": "Planları görüntüle",
+ "premiumBannerPastDueTitle": "Ödeme bekleniyor",
+ "premiumBannerPastDueDesc": "Sohbet, sesli konuşma, okuma ve dinlemeye Premium erişiminizi geri kazanmak için ödeme yönteminizi güncelleyin.",
+ "premiumBannerPastDueCta": "Premium'u geri yükle",
+ "freemiumTrialTitle": "{days, plural, one {# günlük ücretsiz deneme} other {# günlük ücretsiz deneme}}",
+ "freemiumTrialDesc": "Sohbet, ses, dinleme ve okumaya sınırsız erişimin keyfini çıkarın. Premium'un tüm özelliklerini ücretsiz deneyin.",
+ "announcementDismiss": "Duyuruyu kapat",
+ "announcementDismissError": "Duyuru kapatılamadı. Tekrar deneyin."
+ },
+ "assessment": {
+ "title": "Seviye Tespiti",
+ "subtitle": "CEFR Seviye Belirleme",
+ "intro": "İngilizce seviyenizi belirlemek için size birkaç soru soracağız.",
+ "startWriting": "Yazma Değerlendirmesine Başla",
+ "startQuiz": "Teste Başla",
+ "writing": {
+ "title": "Yazı Örneği",
+ "submit": "Yazıyı Gönder",
+ "placeholder": "Cevabınızı buraya yazın...",
+ "evaluating": "Değerlendiriliyor..."
+ },
+ "quiz": {
+ "question": "Soru",
+ "of": "/",
+ "next": "İleri",
+ "submit": "Testi Gönder",
+ "submitting": "Gönderiliyor..."
+ },
+ "result": {
+ "title": "Seviyeniz",
+ "xpEarned": "Kazanılan XP",
+ "skillsTitle": "Beceriler",
+ "goToPlan": "Planımı Görüntüle",
+ "generatePlan": "Çalışma Planı Oluştur"
+ },
+ "currentLevel": "Mevcut Seviye",
+ "assessedOn": "Değerlendirme tarihi",
+ "alreadyHasPlan": "Zaten etkin bir çalışma planınız var. Seviye tespitini tekrarlamak yeni bir plan oluşturur.",
+ "retake": "Seviye Tespitini Tekrarla",
+ "evaluating": "Değerlendiriliyor...",
+ "resultStep": "Sonuç",
+ "cefrLevel": "CEFR Seviyesi",
+ "overrideLevel": "Başlangıç seviyesini değiştir",
+ "strengths": "Güçlü yönler",
+ "needsWork": "Geliştirilmesi gerekenler",
+ "createPlan": "Plan Oluştur →",
+ "creating": "Oluşturuluyor...",
+ "loading": "Yükleniyor...",
+ "levelTest": {
+ "title": "Seviye Tamamlama Testi",
+ "loading": "Sorular yükleniyor...",
+ "loadingTest": "Test yükleniyor...",
+ "submittingTest": "Cevaplar gönderiliyor...",
+ "quizTitle": "{level} Seviye Testi",
+ "resultsTitle": "{level} Seviye Testi — Sonuçlar",
+ "finalScore": "Final Puanı",
+ "correctCount": "{correct} / {total} doğru",
+ "correctAnswer": "✓ Doğru",
+ "incorrectAnswer": "✗ Yanlış — doğru cevap: {answer}",
+ "nextLevelFallback": "SONRAKİ SEVİYE",
+ "advanceLabel": "{level} İÇİN HAZIRSINIZ",
+ "advanceMessage": "{level} seviyesine sağlam bir şekilde hâkim olduğunuzu gösterdiniz. {next} planınızı oluşturmak için seviye tespitini tekrarlayın.",
+ "extendLabel": "4 HAFTALIK UZATMA",
+ "extendMessage": "Zayıf alanlar tespit edildi: {areas}. 4 hafta daha odaklı pratik yapmanızı öneriyoruz.",
+ "repeatLabel": "{level} TEKRARI",
+ "repeatMessage": "Puan %55'in altında. Birkaç temel {level} yeterliliğinin pekiştirilmesi gerekiyor.",
+ "reviewPlan": "Planımı İncele →",
+ "goToPlan": "Plana Git",
+ "invalidPlan": "Geçersiz plan kimliği. Seviye testine plan sayfanızdan erişin.",
+ "noQuestions": "Sunucudan soru alınamadı.",
+ "loadFailed": "Seviye testi yüklenemedi.",
+ "submitFailed": "Gönderim başarısız.",
+ "question": "Soru",
+ "of": "/",
+ "confirm": "Cevabı Onayla",
+ "nextQuestion": "Sonraki Soru",
+ "submit": "Testi Gönder",
+ "result": {
+ "title": "Test Tamamlandı",
+ "recommendation": "Öneri",
+ "advance": "Bir sonraki seviyeye geçmeye hazırsınız",
+ "extend": "Mevcut seviyenizde devam edin",
+ "repeat": "Mevcut seviyenin tekrarı öneriliyor",
+ "back": "Plana Dön"
+ }
+ },
+ "suggestedLevel": "Önerilen: {aiLevel}; plan {selectedLevel} seviyesini kullanacak",
+ "step1": "Adım 1 / 3: Seviyeniz",
+ "step2": "Adım 2 / 3: Soru {questionNumber} / {totalQuestions}",
+ "dontKnow": "Bilmiyorum",
+ "step3": "Adım 3 / 3: Programınız",
+ "studiedBefore": "Daha önce {language} çalıştınız mı?",
+ "studiedBeforeHint": "Bu, teste doğru seviyeden başlamamıza yardımcı olur.",
+ "beginnerOption": "Tamamen yeni başlıyorum",
+ "beginnerOptionHint": "A1'den başlayacağım, teste gerek yok.",
+ "hasExperienceOption": "Evet, biraz deneyimim var",
+ "hasExperienceOptionHint": "Kısa bir uyarlanabilir teste gireceğim (≈12 soru).",
+ "skills": {
+ "grammar": "Dil Bilgisi",
+ "vocabulary": "Kelime Bilgisi",
+ "reading": "Okuma"
+ },
+ "howManyWeeks": "{cefr_level} seviyesi için kaç hafta?",
+ "nWeeks": "{count} hafta",
+ "intensity": {
+ "intensive": "Yoğun",
+ "standard": "Standart",
+ "relaxed": "Rahat",
+ "veryRelaxed": "Çok rahat"
+ },
+ "approxLessons": "~{count} ders",
+ "daysPerWeek": "Haftada {count} gün",
+ "mainGoals": "Ana hedefler (uygun olanların hepsini seçin)",
+ "goals": {
+ "grammar": "Dil Bilgisi",
+ "vocabulary": "Kelime Bilgisi",
+ "reading": "Okuma",
+ "writing": "Yazma",
+ "conversation": "Konuşma",
+ "listening": "Dinleme"
+ },
+ "summaryLevel": "Seviye",
+ "summaryDuration": "Süre",
+ "summaryGoals": "Hedefler",
+ "noneSelected": "hiçbiri seçilmedi",
+ "buildingPlan": "Plan oluşturuluyor...",
+ "startWarningTitle": "Başlamadan önce",
+ "startWarningMessage": "Seviye tespitini bitirmeden ayrılırsanız ilerlemeniz kaybolur ve baştan başlamanız gerekir.",
+ "startWarningMessageLevelTest": "Seviye testini bitirmeden ayrılırsanız ilerlemeniz kaybolur ve testi yeniden yapmanız gerekir.",
+ "startWarningConfirm": "Başla",
+ "startMyPlan": "Planımı başlat",
+ "voiceTrialLabel": "Sesli deneme",
+ "voiceTrialTitle": "Hemen gerçek bir konuşma deneyin",
+ "voiceTrialDesc": "Lingu ile {minutes} dakika ücretsiz konuşun. Eğitmeniniz yeni açtığınız seviyeye uyum sağlayacak.",
+ "voiceTrialStart": "Ücretsiz konuşmayı başlat",
+ "voiceTrialSkip": "Şimdilik atla"
+ },
+ "plan": {
+ "unitLocked": "Ünite kilitli",
+ "unitAvailable": "Ünite kullanılabilir",
+ "lessonPending": "Bekleyen ders",
+ "title": "Planım",
+ "subtitle": "Çalışma Planı",
+ "noPlan": "Etkin bir çalışma planı bulunamadı.",
+ "startAssessment": "Önce seviye tespitine girin",
+ "week": "Hafta",
+ "currentLesson": "Mevcut Ders",
+ "currentUnit": "Mevcut ünite",
+ "startLesson": "Derse Başla",
+ "completed": "Tamamlandı",
+ "generating": "Ders oluşturuluyor...",
+ "generatingError": "Ders oluşturulamadı",
+ "loading": "Plan yükleniyor...",
+ "learningRoadmap": "Öğrenme Yol Haritası",
+ "level": "Seviye",
+ "duration": "Süre",
+ "durationDetail": "{weeks} hafta · haftada {days} gün",
+ "unitsLabel": "Üniteler",
+ "noUnitsForLevel": "{level} seviyesi için ünite yok",
+ "takeAssessmentArrow": "Seviye Tespitine Gir →",
+ "unitLabel": "Ünite",
+ "grammarCovered": "İşlenen dil bilgisi konuları",
+ "noLessons": "Bu ünite için henüz planlanmış ders yok.",
+ "weekDay": "Hafta {week}, Gün {day}",
+ "lessonTypes": {
+ "grammar": "Dil Bilgisi",
+ "vocabulary": "Kelime Bilgisi",
+ "reading": "Okuma",
+ "writing": "Yazma",
+ "listening": "Dinleme",
+ "conversation": "Konuşma",
+ "review": "Tekrar",
+ "level_test": "Seviye Testi"
+ },
+ "levelComplete": "{level} Seviyesi Tamamlandı. Seviye Testine Girin",
+ "levelCompleteDesc": "{level} seviyesi için planınızın sonuna ulaştınız. İlerlemenizi doğrulamak ve bir sonraki seviyenin kilidini açmak için seviye tamamlama testine girin.",
+ "levelCompleteHint": "Test yaklaşık 20 dakika sürer ve dil bilgisi, kelime bilgisi ve okumayı kapsar.",
+ "beginLevelTest": "Seviye Testine Başla",
+ "nLessons": "{count} ders",
+ "nGrammar": "{count} dil bilgisi",
+ "levelTestLabel": "Seviye Testi",
+ "unitAriaLabel": "Ünite {index}: {title}",
+ "noUnitsDesc": "Bu seviyenin içeriği hazırlanıyor. Yakında tekrar göz atın.",
+ "completionTestTitle": "{level} Seviyesi Tamamlama Testi",
+ "levelTestResult": "Seviye Testi Sonucu",
+ "testScore": "Puan:",
+ "pendingLessons": "Bekleyen dersler",
+ "pendingReassurance": "Bunlara size uygun olan herhangi bir zamanda devam edebilirsiniz.",
+ "resume": "Devam et",
+ "lessonsHeader": "Dersler · {count}",
+ "reviewLesson": "Tekrar et",
+ "noPlanLabel": "BAŞLAYIN",
+ "noPlanTitle": "Çalışma planınızı oluşturun",
+ "noPlanDesc": "Seviyenizi keşfetmek ve size özel bir öğrenme yolu edinmek için kısa bir seviye tespitine girin.",
+ "noPlanHint": "Yaklaşık 10 dakika sürer"
+ },
+ "lesson": {
+ "loading": "Ders yükleniyor...",
+ "notFound": "Ders bulunamadı",
+ "backToPlan": "Plana Dön",
+ "progress": "İlerleme",
+ "exercise": "Alıştırma",
+ "of": "/",
+ "checkAnswer": "Cevabı Kontrol Et",
+ "nextExercise": "Sonraki Alıştırma",
+ "submitWriting": "Yazıyı Gönder",
+ "yourAnswer": "Cevabınız...",
+ "correct": "Doğru",
+ "incorrect": "Yanlış",
+ "feedback": "Geri bildirim",
+ "corrections": "Düzeltmeler",
+ "completeLesson": "Dersi Tamamla",
+ "completing": "Tamamlanıyor...",
+ "relatedGrammar": "İlgili Dil Bilgisi",
+ "explanation": "Açıklama",
+ "exercises": "Alıştırmalar",
+ "vocabulary": "Kelime Bilgisi",
+ "label": "Ders",
+ "submitAnswer": "Cevabı Gönder",
+ "lessonDone": "Tebrikler. Ders tamamlandı.",
+ "exerciseSummary": "Değerlendirilen alıştırmalar: {completed} / {total}",
+ "score": "Puan",
+ "showNativeExplanation": "Şu dilde göster:",
+ "hint": "İpucu",
+ "showNativeHint": "İpucunu şu dilde göster:",
+ "regenerateExercise": "Alıştırmayı yeniden oluştur",
+ "regeneratingExercise": "Yeniden oluşturuluyor...",
+ "regenerateError": "Alıştırma yeniden oluşturulamadı. Tekrar deneyin.",
+ "regenerateNotNeeded": "Bu alıştırmanın yeniden oluşturulmasına gerek yok.",
+ "examples": "Örnekler",
+ "commonTraps": "Sık yapılan hatalar",
+ "miniGlossary": "Mini sözlük",
+ "pronunciationExercise": "Telaffuz",
+ "exerciseTypeMultipleChoice": "Çoktan Seçmeli",
+ "exerciseTypeFillBlank": "Boşluk Doldurma",
+ "exerciseTypeFreeWrite": "Serbest Yazma",
+ "exerciseTypePronunciation": "Telaffuz",
+ "tapToListen": "Dinlemek için dokunun",
+ "recordNow": "Cevabınızı kaydedin",
+ "exit": "Çık",
+ "exitConfirmTitle": "Dersten çıkılsın mı?",
+ "exitConfirmMessage": "Bu dersteki ilerlemeniz kaybolacak.",
+ "dayComplete": "Gün tamamlandı!",
+ "dayCompleteMsg": "Planınızın bu gününü tamamladınız. Size uygun olan herhangi bir zamanda devam edin."
+ },
+ "flashcards": {
+ "title": "Bilgi Kartları",
+ "due": "Tekrar zamanı gelen",
+ "total": "Toplam",
+ "noDue": "Tekrar zamanı gelen kart yok",
+ "allCaughtUp": "Hepsi tamam!",
+ "generate": "Bilgi Kartı Oluştur",
+ "generating": "Oluşturuluyor...",
+ "topic": "Konu",
+ "topicPlaceholder": "ör. seyahat kelimeleri",
+ "count": "Adet",
+ "level": "Seviye",
+ "submit": "Oluştur",
+ "again": "Tekrar",
+ "hard": "Zor",
+ "good": "İyi",
+ "easy": "Kolay",
+ "front": "Kelime",
+ "back": "Tanım",
+ "loading": "Bilgi kartları yükleniyor...",
+ "sectionGenerate": "Yeni Kart Oluştur",
+ "speakingMode": "Konuşma",
+ "standardMode": "Standart",
+ "sayWord": "Kelimeyi sesli söyleyin",
+ "refresh": "Yenile",
+ "generateBtn": "Oluştur",
+ "cards": "kart",
+ "myVocabularyBtn": "Kelimelerim",
+ "myVocabulary": "Kelimelerim",
+ "myVocabularyEmpty": "Henüz kaydedilmiş kelime yok. Okurken bir kelime seçerek buraya kaydedebilirsiniz.",
+ "myVocabularyNoResults": "Aramanızla eşleşen kayıtlı kelime yok.",
+ "vocabularySearch": "Kelime ara...",
+ "vocabularyPageInfo": "Sayfa {page} / {pages}",
+ "vocabularyPrev": "Önceki",
+ "vocabularyNext": "Sonraki",
+ "backToFlashcards": "Bilgi Kartları",
+ "noCardsHint": "Yapay zekâ ile ilk kartlarınızı oluşturmak için + Oluştur'u kullanın",
+ "tapToHide": "gizlemek için dokunun",
+ "tapToReveal": "görmek için dokunun",
+ "interval": "Aralık",
+ "repetitions": "Tekrar"
+ },
+ "chat": {
+ "title": "Yapay Zekâ Eğitmeni",
+ "subtitle": "{language} — İstediğinizi sorun",
+ "placeholder": "Bir mesaj yazın...",
+ "send": "Gönder",
+ "sending": "Gönderiliyor...",
+ "noConversation": "Bir konuşma seçin veya başlatın",
+ "newConversation": "Yeni",
+ "toggleSidebarShow": "Sohbetleri göster",
+ "toggleSidebarHide": "Sohbetleri gizle",
+ "conversations": "Konuşmalar",
+ "loading": "Yükleniyor...",
+ "thinking": "Düşünüyor...",
+ "takingLonger": "Beklenenden uzun sürüyor...",
+ "errorMessage": "Bir şeyler ters gitti. Lütfen tekrar deneyin.",
+ "deleteTitle": "Sohbeti Sil",
+ "deleteMessage": "Bu konuşma kalıcı olarak silinecek.",
+ "deleteConfirm": "Sil",
+ "enterToSend": "Göndermek için Enter",
+ "continueInVoice": "Sesli devam et",
+ "memoryUpdated": "Anı güncellendi"
+ },
+ "progress": {
+ "title": "İlerleme",
+ "subtitle": "Beceri Takibi",
+ "xp": "XP",
+ "streak": "Seri",
+ "lessons": "Dersler",
+ "accuracy": "Doğruluk",
+ "noPlan": "Etkin çalışma planı yok.",
+ "startPlan": "Seviye tespitine başla",
+ "competencies": "Ünite Yeterlilikleri",
+ "vocabularySection": "Kelime Bilgisi",
+ "skills": "Beceri Doğruluğu",
+ "mastered": "Öğrenildi",
+ "inProgress": "Devam Ediyor",
+ "notStarted": "Başlanmadı",
+ "loading": "İlerleme yükleniyor...",
+ "days": "gün",
+ "noData": "İlerlemenizi burada görmek için birkaç ders tamamlayın.",
+ "exploreVocab": "Kelime setlerini keşfedin",
+ "competenciesSection": "{level} Dil Bilgisi Yeterlilikleri",
+ "noCompetencies": "Yeterliliklerinizi takip etmeye başlamak için ders tamamlayın.",
+ "goToMyPlan": "→ Planıma Git",
+ "addToFlashcards": "Kelime bazında ilerlemenizi takip etmek için bir setteki kelimeleri bilgi kartı destenize ekleyin.",
+ "noActivePlanDesc": "Becerilerinizi takip etmeye başlamak için seviye tespitini tamamlayın.",
+ "vocabularyHeader": "{level} Kelime Bilgisi",
+ "currentLevelOnly": "Yalnızca mevcut seviye",
+ "allLevels": "Tüm seviyeler"
+ },
+ "grammar": {
+ "title": "Dil Bilgisi Başvuru Kaynağı",
+ "subtitle": "Başvuru",
+ "searchPlaceholder": "Dil bilgisi konularında ara...",
+ "allLevels": "Tüm Seviyeler",
+ "allCategories": "Tümü",
+ "noResults": "Konu bulunamadı.",
+ "structure": "Yapı",
+ "keyRules": "Temel Kurallar",
+ "examples": "Örnekler",
+ "commonMistakes": "Sık Yapılan Hatalar",
+ "relatedTopics": "İlgili Konular",
+ "backToGrammar": "Dil Bilgisi Başvuru Kaynağı",
+ "explanation": "Açıklama",
+ "backLink": "Dil Bilgisine Dön",
+ "notFound": "Konu bulunamadı.",
+ "topicsFound": "{count, plural, one {# konu bulundu} other {# konu bulundu}}"
+ },
+ "vocabulary": {
+ "title": "Kelime Merkezi",
+ "subtitle": "Kelime Bilgisi",
+ "all": "Tümü",
+ "searchPlaceholder": "Setlerde ara...",
+ "sets": "set",
+ "words": "kelime",
+ "addAll": "{count} Kelimenin Tümünü Bilgi Kartlarına Ekle",
+ "adding": "Ekleniyor...",
+ "added": "{count} bilgi kartı eklendi",
+ "addError": "Bilgi kartları eklenemedi",
+ "frequency": "sıklık",
+ "backToVocabulary": "Kelime Merkezi",
+ "notFound": "Set bulunamadı.",
+ "vocabularySet": "Kelime Seti",
+ "cardsAdded": "Bilgi kartı destenize {count} kart eklendi.",
+ "goToFlashcards": "Bilgi Kartlarına Git →",
+ "addFailed": "Bilgi kartları eklenemedi.",
+ "noResults": "Aramanızla eşleşen kelime seti yok"
+ },
+ "phrasebook": {
+ "title": "Konuşma Kılavuzu",
+ "subtitle": "İfadeler",
+ "all": "Tümü",
+ "allRegisters": "Tüm üsluplar",
+ "formal": "Resmî",
+ "neutral": "Nötr",
+ "informal": "Gündelik",
+ "copied": "Kopyalandı!",
+ "copy": "Kopyala",
+ "noResults": "Filtrelerinizle eşleşen ifade yok",
+ "level": "Seviye",
+ "register": "Üslup",
+ "statsLine": "{situationCount} durum · {phraseCount} ifade · {range}",
+ "situationsShown": "{count, plural, one {# durum gösteriliyor} other {# durum gösteriliyor}}",
+ "searchPlaceholder": "İfadelerde ara..."
+ },
+ "admin": {
+ "title": "Yönetim",
+ "overview": "Genel Bakış",
+ "users": "Kullanıcılar",
+ "feedback": "Geri Bildirim",
+ "reviews": "Yorumlar",
+ "system": "Sistem",
+ "invites": "Davet Bağlantıları",
+ "createUser": "Kullanıcı Oluştur",
+ "createInvite": "Davet Oluştur",
+ "deactivate": "Devre dışı bırak",
+ "activate": "Etkinleştir",
+ "loading": "Yükleniyor...",
+ "loadError": "Kullanıcı verileri yüklenemedi",
+ "userNotFound": "Kullanıcı bulunamadı",
+ "role": "Rol",
+ "status": "Durum",
+ "active": "Etkin",
+ "inactive": "Devre dışı",
+ "inviteCreated": "Davet bağlantısı oluşturuldu",
+ "copyLink": "Bağlantıyı kopyala",
+ "inviteCopied": "Davet bağlantısı kopyalandı",
+ "deleteUser": "Kullanıcıyı Sil",
+ "deleteUserMessage": "Bu kullanıcı silinsin mi? Bu işlem geri alınamaz.",
+ "deleteConfirm": "Sil",
+ "noUsers": "Kullanıcı bulunamadı",
+ "inviteLink": "Davet Bağlantısı (48 saat geçerli)",
+ "total": "toplam",
+ "delete": "Sil",
+ "inviteBtn": "Davet Bağlantısı",
+ "createUserBtn": "Kullanıcı Oluştur",
+ "prevPage": "← Önceki",
+ "nextPage": "Sonraki →",
+ "roleUser": "Kullanıcı",
+ "roleAdmin": "Yönetici",
+ "fieldUsername": "Kullanıcı adı",
+ "invalidUsernameChars": "Kullanıcı adı yalnızca harf, rakam, kısa çizgi, alt çizgi ve nokta içerebilir",
+ "fieldEmail": "E-posta",
+ "fieldPassword": "Parola",
+ "fieldDisplayName": "Görünen Ad",
+ "fieldNativeLanguage": "Ana Dil",
+ "fieldTargetLanguage": "Öğrenilecek dil",
+ "fieldRole": "Hesap türü",
+ "submitCreate": "Oluştur",
+ "searchPlaceholder": "Kullanıcı adı veya e-postayla ara...",
+ "statsTitle": "Kullanım istatistikleri",
+ "statsCefr": "Mevcut seviye",
+ "statsUnit": "Mevcut ünite",
+ "statsPlanWeeks": "Plan süresi",
+ "sectionXpProgress": "XP ve İlerleme",
+ "statsXp": "Toplam XP",
+ "statsStreak": "Seri",
+ "statsActiveDays": "Etkin günler",
+ "statsLessons": "Tamamlanan dersler",
+ "statsExercises": "Doğru alıştırmalar",
+ "statsMessages": "Gönderilen mesajlar",
+ "statsTokensTotal": "Harcanan token (toplam)",
+ "statsTokensChat": "Eğitmen token'ları",
+ "statsTokensConversation": "Ses token'ları",
+ "statsTokensNote": "Yalnızca yapay zekâ sağlayıcısı bu bilgiyi döndürdüğünde kullanılabilir",
+ "statsNoData": "İlerleme verisi yok",
+ "viewStats": "İstatistikleri görüntüle",
+ "weeks": "hafta",
+ "statsTestScore": "Final testi puanı",
+ "statsDays": "gün",
+ "sectionQuota": "Konuşma Kotaları",
+ "quotaWeeklySessions": "Haftalık oturum sınırı",
+ "quotaDailyMinutes": "Günlük dakika sınırı",
+ "quotaWeeklyMinutes": "Haftalık dakika sınırı",
+ "quotaMonthlyTokens": "Aylık token sınırı",
+ "quotaUnlimitedLabel": "Sınırsız (0)",
+ "quotaUsedSessions": "Bu hafta kullanılan",
+ "quotaUsedMinutes": "Bugün kullanılan",
+ "quotaUsedWeeklyMinutes": "Bu hafta kullanılan (dk)",
+ "quotaSave": "Kotaları kaydet",
+ "quotaSaved": "Kotalar kaydedildi.",
+ "emailVerified": "E-posta doğrulandı",
+ "emailNotVerified": "E-posta doğrulanmadı",
+ "verifyEmail": "E-postayı doğrula",
+ "unverifyEmail": "Doğrulanmamış olarak işaretle",
+ "emailVerifiedSuccess": "E-posta doğrulanmış olarak işaretlendi.",
+ "emailUnverifiedSuccess": "E-posta doğrulanmamış olarak işaretlendi.",
+ "fieldSubscription": "Abonelik",
+ "fieldEndsRenews": "Bitiş / Yenileme",
+ "fieldStripeCustomer": "Stripe Müşterisi",
+ "maintenanceTitle": "Bakım Modu",
+ "maintenanceOn": "AÇIK",
+ "maintenanceEnable": "Bakımı Etkinleştir",
+ "maintenanceDisable": "Bakımı Devre Dışı Bırak",
+ "maintenanceDesc": "Etkinleştirildiğinde, aboneliğe bağlı tüm özellikler (eğitmen sohbeti, sesli konuşmalar, dinleme ve okuma alıştırmaları) tüm kullanıcılar için kullanılamaz olur.",
+ "cannotDeactivateSelf": "Kendi hesabınızı devre dışı bırakamazsınız",
+ "cannotDeleteSelf": "Kendi hesabınızı silemezsiniz",
+ "sectionLanguages": "Diller",
+ "sectionActivity": "Etkinlik",
+ "statsActive": "Etkin",
+ "manageUsers": "Kullanıcıları yönet",
+ "manageUsersDesc": "Hesapları, abonelikleri, rolleri ve erişim durumunu inceleyin.",
+ "createUserDesc": "Başlangıç çalışma diliyle yönetilen bir kullanıcı hesabı oluşturun.",
+ "reviewFeedback": "Geri bildirimleri incele",
+ "reviewFeedbackDesc": "Öğrencilerden gelen özellik isteklerini ve hata bildirimlerini önceliklendirin.",
+ "reviewReviews": "Yorumları incele",
+ "reviewReviewsDesc": "Doğrulanmış öğrenci yorumlarını açılış sayfasında gösterilmek üzere onaylayın.",
+ "maintenanceOnDesc": "Aboneliğe bağlı öğrenme araçları için bakım modu etkin.",
+ "maintenanceOffDesc": "Bakım modu kapalı. Aboneliğe bağlı öğrenme araçları kullanılabilir.",
+ "openSystemControls": "Sistem denetimleri",
+ "adminRequired": "Yönetici erişimi gerekli",
+ "usersLoadError": "Kullanıcılar yüklenemedi",
+ "createUserError": "Kullanıcı oluşturulamadı",
+ "updateUserError": "Kullanıcı güncellenemedi",
+ "deleteUserError": "Kullanıcı silinemedi",
+ "inviteError": "Davet bağlantısı oluşturulamadı",
+ "copyInviteError": "Davet bağlantısı kopyalanamadı",
+ "maintenanceError": "Bakım modu güncellenemedi",
+ "maintenanceOff": "KAPALI",
+ "inviteExpiry": "Tek kullanımlık bağlantı. 48 saat sonra geçerliliğini yitirir.",
+ "searchAction": "Kullanıcı ara",
+ "roleFilter": "Role göre filtrele",
+ "statusFilter": "Duruma göre filtrele",
+ "subscriptionFilter": "Aboneliğe göre filtrele",
+ "allRoles": "Tüm roller",
+ "allStatuses": "Tüm durumlar",
+ "allSubscriptions": "Tüm abonelikler",
+ "clearFilters": "Temizle",
+ "userColumn": "Kullanıcı",
+ "actions": "İşlemler",
+ "createUserSheetDesc": "Hesap hemen oluşturulur. E-posta etkinse doğrulama e-postası gönderilir.",
+ "activateUser": "Kullanıcıyı etkinleştir",
+ "deactivateUser": "Kullanıcıyı devre dışı bırak",
+ "activateUserMessage": "Bu kullanıcı hesabı etkinleştirilsin mi?",
+ "deactivateUserMessage": "Bu kullanıcı hesabı devre dışı bırakılsın mı? Kullanıcı, hesabı yeniden etkinleştirilene kadar uygulamayı kullanamaz.",
+ "tabProfile": "Profil",
+ "tabLanguages": "Diller",
+ "tabActivity": "Etkinlik",
+ "tabQuota": "Kotalar",
+ "tabSubscription": "Abonelik",
+ "sectionCommunication": "İletişim",
+ "quotaCurrentUsage": "Mevcut kullanım",
+ "quotaConfiguredLimits": "Ayarlanan sınırlar",
+ "unitMinutes": "dk",
+ "unitSessions": "oturum",
+ "unitTokens": "token",
+ "quotaZeroMeansUnlimited": "Sınırsız erişim için sınırı 0 olarak ayarlayın.",
+ "quotaValidationError": "Tüm kota değerleri 0 veya daha büyük tam sayılar olmalıdır.",
+ "quotaSaveError": "Kota sınırları kaydedilemedi.",
+ "subscriptionOverride": "Elle abonelik değişikliği",
+ "subscriptionOverrideDesc": "Bu, kullanıcının erişim süresini doğrudan değiştirir ve Stripe tarafından yönetilen durumu geçersiz kılabilir.",
+ "subscriptionUpdateError": "Abonelik güncellenemedi.",
+ "saving": "Kaydediliyor...",
+ "verifyEmailConfirmMessage": "Bu e-posta adresi doğrulanmış olarak işaretlensin mi?",
+ "unverifyEmailConfirmMessage": "Bu e-posta adresi doğrulanmamış olarak işaretlensin mi?",
+ "subscriptionConfirmTitle": "Aboneliği değiştir",
+ "subscriptionConfirmMessage": "Abonelik planı uygulansın mı: {plan}?",
+ "subscriptionConfirm": "Uygula",
+ "feedbackStatusError": "Geri bildirim durumu güncellenemedi.",
+ "feedbackDeleteError": "Geri bildirim kaydı silinemedi.",
+ "allFeedback": "Tüm geri bildirimler",
+ "feedbackTotal": "Toplam geri bildirim",
+ "feedbackQueue": "Geri bildirim kuyruğu",
+ "feedbackSearchPlaceholder": "Başlık, açıklama veya yazara göre ara...",
+ "feedbackSearchAction": "Geri bildirimlerde ara",
+ "feedbackTypeFilter": "Geri bildirim türüne göre filtrele",
+ "noFilteredFeedback": "Mevcut filtrelerle eşleşen geri bildirim yok.",
+ "feedbackItem": "Kayıt",
+ "type": "Tür",
+ "signals": "Sinyaller",
+ "feedbackStatusAction": "Geri bildirim durumunu değiştir",
+ "adminStatsError": "Yönetim metrikleri yüklenemedi.",
+ "activeUsers": "Etkin kullanıcılar",
+ "paidAccess": "Etkin / deneme",
+ "pendingFeedback": "Bekleyen geri bildirimler",
+ "pendingReviews": "Onay bekleyen yorumlar",
+ "operationalAlerts": "Operasyonel uyarılar",
+ "pendingBugs": "Bekleyen hata bildirimleri",
+ "pendingBugsDesc": "Yönetici tarafından önceliklendirilmeyi bekleyen hata bildirimleri.",
+ "pastDueSubscriptions": "Ödemesi gecikmiş abonelikler",
+ "pastDueSubscriptionsDesc": "İncelenmesi gerekebilecek ödeme sorunu olan hesaplar.",
+ "dashboardBanner": {
+ "title": "Pano duyurusu",
+ "description": "Tüm öğrenci panoları için bir duyuru oluşturun, çevirin, inceleyin ve yayımlayın.",
+ "loading": "Duyuru yükleniyor...",
+ "loadError": "Pano duyurusu yüklenemedi.",
+ "sourceLocale": "Kaynak dil",
+ "activeLabel": "Duyuruyu yayımla",
+ "activeHint": "Etkin olmayan duyurular kaydedilir ancak öğrencilerden gizlenir.",
+ "fieldTitle": "Başlık",
+ "fieldSubtitle": "Alt başlık",
+ "fieldDescription": "Açıklama",
+ "translate": "Çevir",
+ "translateSuccess": "Çeviriler oluşturuldu. Kaydetmeden önce inceleyin.",
+ "translateError": "Çeviri başarısız oldu. Mevcut içeriğiniz korundu.",
+ "editTranslation": "Düzenlenecek çeviri",
+ "completion": "{complete}/{total} dil tamamlandı",
+ "save": "Duyuruyu kaydet",
+ "saveSuccess": "Pano duyurusu kaydedildi.",
+ "saveError": "Pano duyurusu kaydedilemedi.",
+ "revision": "Revizyon {revision}",
+ "updated": "Güncellendi: {date}",
+ "locales": {
+ "en": "İngilizce",
+ "es": "İspanyolca",
+ "fr": "Fransızca",
+ "pt": "Portekizce",
+ "de": "Almanca",
+ "it": "İtalyanca",
+ "ru": "Rusça",
+ "nl": "Felemenkçe",
+ "pl": "Lehçe",
+ "ro": "Rumence"
+ }
+ }
+ },
+ "faq": {
+ "title": "SSS",
+ "subtitle": "Sıkça Sorulan Sorular",
+ "q_start": "Nereden başlamalıyım?",
+ "a_start": "Seviye Tespiti ile başlayın. İngilizce seviyenizi (A1–C2), güçlü ve zayıf yönlerinizi belirler. Bu sonuçla, Pano'nuzu günlük derslerle dolduran size özel bir Çalışma Planı oluşturabilirsiniz. Seviye Tespiti yapılmadan Pano boş kalır.",
+ "q_workflow": "Adım adım süreç nasıl işliyor?",
+ "workflowStep1": "Kaydolun ve ana dilinizi seçin",
+ "workflowStep2": "Seviye Tespitine girin → CEFR seviyeniz belirlenir",
+ "workflowStep3": "Pano'dan Çalışma Planınızı oluşturun",
+ "workflowStep4": "Günlük derslerinizi tamamlayın (Pano'daki BAŞLA düğmesi)",
+ "workflowStep5": "Kelime bilginizi geliştirmek için paralel olarak Bilgi Kartlarını kullanın",
+ "workflowStep6": "Yapay Zekâ Eğitmeniyle serbest konuşma pratiği yapın",
+ "q_language": "Hangi dili öğreneceğim?",
+ "a_language": "FreeLingo şu anda birçok dili destekliyor (Amerikan İngilizcesi, İngiliz İngilizcesi, Fransızca, Almanca, İtalyanca, Japonca, Korece, Çince (Çin anakarası), Portekizce, İspanyolca) ve zamanla yenilerini eklemeye devam edeceğiz. Yeni bir dil kullanıma sunulduğunda onu Ayarlar → Dillerim bölümünde bulacaksınız — ekleyin ve hemen öğrenmeye başlayın.",
+ "q_assessment": "Seviye Tespiti nedir?",
+ "a_assessment": "Dil bilgisi, kelime bilgisi, okuduğunu anlama ve cümle dönüştürmeyi kapsayan, zorluğu A1'den C1'e kadar değişen, yapay zekâ ile üretilmiş 15 soruluk bir testtir. Bitirdiğinizde CEFR seviyenizi, bir puanı ve güçlü ve zayıf yönlerinizin analizini alırsınız. Bu sonuç, Çalışma Planına ve oluşturulan Bilgi Kartlarına temel oluşturur.",
+ "q_studyPlan": "Çalışma Planı nedir ve nasıl oluşturulur?",
+ "a_studyPlan": "Seviye Tespitinden sonra Pano'ya gidin ve Çalışma Planı Oluştur'a tıklayın. CEFR seviyenize ve hedeflerinize göre uyarlanmış, günlük derslerden oluşan haftalık bir plan otomatik olarak oluşturulur. Her derste yapay zekâ tarafından değerlendirilen çoktan seçmeli ve serbest yazma alıştırmaları bulunur.",
+ "q_resources": "Kaynaklar nedir?",
+ "a_resources": "Kaynaklar bölümü, Çalışma Planınızdan bağımsız başvuru materyallerini bir araya getirir: seviyeye göre dil bilgisi, kelime setleri ve faydalı ifadeler. Tekrar yapmak, açıklamalara bakmak veya günlük dersi beklemeden kelime bilginizi genişletmek için istediğiniz zaman kullanabilirsiniz.",
+ "q_flashcards": "Bilgi Kartları ne işe yarar?",
+ "a_flashcards": "SM-2 aralıklı tekrar algoritmasını kullanan bir kelime çalışma sistemidir. Herhangi bir konuda (ör. \"iş\", \"phrasal verb'ler\", \"yemek\") tanım, örnek cümle ve ana dilinize çeviri içeren kartlar oluşturun. Sistem, her kartı tam unutmak üzereyken tekrar göstermek için ne zaman göstereceğini hesaplar. Çalışma Planından tamamen bağımsızdır.",
+ "q_vocabulary": "Kelime dağarcığıma nasıl kelime eklerim?",
+ "a_vocabulary": "Kelimeleri iki şekilde kaydedebilirsiniz: (1) Bir ders, dinleme alıştırması okurken veya eğitmenle sohbet ederken herhangi bir kelimeyi farenizle seçin ve beliren ipucundaki Kaydet'e tıklayın — yapay zekâ bir tanım, örnek cümle ve ana dilinize çeviri oluşturur. (2) Kelime Bilgisi bölümüne gidin, seviyenize uygun bir kelime setini açın ve setin tamamını tek seferde eklemek için Tümünü Ekle'ye tıklayın. Kaydettiğiniz kelimeler Bilgi Kartları bölümündeki Kelimelerim altında görünür.",
+ "q_tutor": "Yapay Zekâ Eğitmeni nasıl çalışır?",
+ "a_tutor": "Akış hâlinde yanıt veren serbest bir sohbettir. Eğitmen, yanıtlarını size göre uyarlamak için CEFR seviyenizi ve zayıf noktalarınızı bilir. Dil bilgisi soruları sorun, açıklama isteyin, İngilizce yazma pratiği yapın ya da sadece sohbet edin. Konuşmalar kaydedilir ve oturumlar arasında kenar çubuğundan erişilebilir.",
+ "q_voice": "Sesli konuşma nasıl çalışır?",
+ "a_voice": "Sesli Konuşma modu, yapay zekâ eğitmeniyle gerçek zamanlı konuşmanızı sağlar. Başlamak için Başla'ya basın — uygulama ses etkinliği algılama (VAD) ile sesinizi otomatik olarak dinler ve eğitmen sentezlenmiş sesle yanıt verir. Eğitmenin sözünü istediğiniz an kesebilirsiniz. Oturum, süre sınırına ulaştığınızda veya Durdur'a bastığınızda sona erer. Tarayıcınızda mikrofon izninin açık olduğundan emin olun.",
+ "q_listening": "Dinleme alıştırmaları nasıl çalışır?",
+ "a_listening": "Dinleme bölümü, CEFR seviyenize uygun, yapay zekâ tarafından seslendirilen kısa ses parçaları oluşturur. Sesi dinleyin, ardından 5 anlama sorusunu cevaplayın. Gönderdikten sonra puanınızı (0–5), XP'nizi, doğru cevapları ve deşifrenin tamamını görürsünüz. İstediğiniz zaman yeni alıştırmalar oluşturabilirsiniz.",
+ "q_reading": "Okuma alıştırmaları nasıl çalışır?",
+ "a_reading": "Okuma bölümü, CEFR seviyenize uygun metinler oluşturur — duyurular, e-postalar, makaleler, blog yazıları ve daha fazlası. Metni okuyun ve 5 çoktan seçmeli soruyu cevaplayın. Gönderdikten sonra puanınızı (0–5) ve XP'nizi görürsünüz. İstediğiniz zaman yeni alıştırmalar oluşturulabilir.",
+ "q_providers": "FreeLingo hangi yapay zekâ sağlayıcılarını destekliyor?",
+ "a_providers_intro": ".env dosyasında LLM_PROVIDER ile ayarlanabilir:",
+ "provider_ollama": "Yerel, ücretsiz. Sunucuda çalışan bir Ollama gerektirir. Önerilen model: gemma4:e4b. GPU olmadan yavaş olabilir.",
+ "provider_openai": "OpenAI API (GPT-4o vb.). Hızlı ve güvenilir. OPENAI_API_KEY gerektirir.",
+ "provider_anthropic": "Anthropic Claude. ANTHROPIC_API_KEY gerektirir.",
+ "provider_deepseek": "DeepSeek API. DEEPSEEK_API_KEY gerektirir.",
+ "q_invite": "Başka kişileri davet edebilir miyim?",
+ "a_invite": "Evet. Yönetici, Yönetim → Kullanıcılar bölümünden doğrudan kullanıcı oluşturabilir veya 48 saat içinde geçerliliğini yitiren tek kullanımlık davet bağlantıları oluşturabilir. Herkese açık kayıt varsayılan olarak kapalıdır (ALLOW_REGISTRATION=false).",
+ "q_password": "Parolamı veya ana dilimi nasıl değiştiririm?",
+ "a_password": "Ayarlar'a gidin. Görünen adınızı, ana dilinizi ve parolanızı oradan güncelleyebilirsiniz.",
+ "q_uiLanguage": "Platformun dilini nasıl değiştiririm?",
+ "a_uiLanguage": "Ayarlar'a gidin ve Profil bölümündeki Arayüz Dili açılır listesini bulun. Tercih ettiğiniz dili seçtiğinizde tüm arayüz hemen değişir.",
+ "q_feedback": "Nasıl yeni bir özellik önerebilir veya hata bildirebilirim?",
+ "a_feedback": "Kenar çubuğundaki Geri Bildirim bölümünü kullanın. Yeni özellikler için öneri oluşturabilir veya hata bildirebilirsiniz. Diğer kullanıcıların fikirlerine oy verin, yorum bırakın ve her isteğin durumunu takip edin. Tüm gönderimler herkese açıktır ve yönetici tarafından incelenir."
+ },
+ "cookieBanner": {
+ "message": "Oturumunuzu açık tutmak için yalnızca kesinlikle gerekli çerezleri kullanıyoruz. İzleme veya reklam çerezi kullanılmaz.",
+ "learnMore": "Gizlilik politikası",
+ "accept": "Anladım"
+ },
+ "error": {
+ "label": "Beklenmeyen hata",
+ "title": "Bir şeyler ters gitti",
+ "body": "Beklenmeyen bir hata oluştu. Tekrar deneyebilir veya panoya dönebilirsiniz.",
+ "retry": "Tekrar dene",
+ "dashboard": "Panoya git",
+ "digest": "Hata referansı"
+ },
+ "notFound": {
+ "title": "Sayfa bulunamadı",
+ "body": "Aradığınız sayfa mevcut değil veya taşınmış.",
+ "dashboard": "Panoya git",
+ "home": "Ana sayfa"
+ },
+ "errors": {
+ "notFound": "Sayfa bulunamadı",
+ "serverError": "Bir şeyler ters gitti",
+ "unauthorized": "Lütfen giriş yapın",
+ "backHome": "Ana sayfaya dön"
+ },
+ "conversation": {
+ "title": "Konuşma",
+ "subtitle": "Sesli Pratik",
+ "start": "Oturumu Başlat",
+ "stop": "Durdur",
+ "startNew": "Yeni Oturum Başlat",
+ "statusLoading": "Ses modeli yükleniyor...",
+ "statusReady": "Hazır",
+ "statusWarming": "Modeller yükleniyor...",
+ "statusConnecting": "Bağlanıyor...",
+ "statusListening": "Dinleniyor...",
+ "statusDetecting": "Konuşma algılanıyor...",
+ "statusSpeaking": "Konuşuyor...",
+ "statusError": "Hata",
+ "errorServicesDisabled": "Bu sunucuda ses hizmetleri etkin değil.",
+ "errorConnection": "Bağlantı hatası. Lütfen tekrar deneyin.",
+ "errorUnauthorized": "Oturumun süresi doldu. Lütfen sayfayı yenileyin.",
+ "errorMic": "Mikrofon erişimi reddedildi.",
+ "errorVadInit": "Ses tanıma başlatılamadı. Tarayıcınızın WebAssembly desteklediğinden emin olun.",
+ "warningTimeout": "Oturum {seconds} sn içinde sona eriyor",
+ "sessionEnded": "Oturum sona erdi",
+ "tapToStart": "Hazır olduğunuzda konuşun",
+ "you": "Siz",
+ "assistant": "Lingu",
+ "quotaSessions": "Bu haftaki oturumlar",
+ "quotaMinutes": "Bugünkü dakikalar",
+ "quotaUnlimited": "Sınırsız",
+ "quotaExceededSessions": "Bu haftaki tüm oturumlarınızı kullandınız.",
+ "quotaExceededTime": "Günlük pratik sürenizin tamamını kullandınız.",
+ "quotaExceededTokens": "Aylık yapay zekâ token'larınızın tamamını kullandınız.",
+ "freemiumVoiceRemaining": "Ücretsiz sesli konuşma: bu hafta {remaining}/{limit} dk",
+ "quotaTokens": "Bu ayki token'lar",
+ "memoryUpdated": "Anı güncellendi",
+ "trialBanner": "Ücretsiz seviye tespiti konuşması · {minutes} dk",
+ "trialCtaLabel": "Konuşmaya devam edin",
+ "trialCtaTitle": "Lingu ile pratik yapmaya devam edin",
+ "trialCtaDesc": "Premium ile sesli konuşmaların, eğitmen sohbetinin, dinleme ve okuma pratiğinin tamamının kilidini açın.",
+ "startersHint": "Ya da bir konuyla başlayın",
+ "starters": [
+ "Sanat ve yaratıcılık",
+ "Kitaplar ve okuma",
+ "Çocukluk anıları",
+ "Şehir mi köy mü",
+ "Yemek pişirme ve tarifler",
+ "Hayaller ve hedefler",
+ "Aile ve ilişkiler",
+ "Moda ve stil",
+ "En sevilen filmler",
+ "Festivaller ve gelenekler",
+ "Dünya mutfakları",
+ "Sağlık ve iyi yaşam",
+ "Hobiler ve el işleri",
+ "Dil öğrenimi",
+ "Yeni beceriler öğrenmek",
+ "Para ve bütçe",
+ "Müzik ve konserler",
+ "Evcil hayvanlar ve hayvanlar",
+ "Toplu taşıma",
+ "Bilim ve uzay",
+ "Alışveriş alışkanlıkları",
+ "Sosyal medya",
+ "Spor ve fitness",
+ "Teknoloji ve cihazlar",
+ "Çevre",
+ "Seyahat rotaları",
+ "Diziler ve TV programları",
+ "Hafta sonu planları",
+ "İş ve kariyer hedefleri",
+ "Evden çalışma"
+ ]
+ },
+ "voiceRecorder": {
+ "record": "Kaydet",
+ "stop": "Durdur",
+ "processing": "İşleniyor",
+ "error": "Hata",
+ "ariaRecord": "Kaydı başlat",
+ "ariaStop": "Kaydı durdur"
+ },
+ "audioPlayer": {
+ "listen": "Dinle",
+ "stop": "Durdur",
+ "ariaListen": "Telaffuzu dinle",
+ "ariaStop": "Sesi durdur"
+ },
+ "languages": {
+ "en": "İngilizce",
+ "es": "İspanyolca",
+ "fr": "Fransızca",
+ "pt": "Portekizce",
+ "de": "Almanca",
+ "it": "İtalyanca",
+ "pl": "Lehçe",
+ "nl": "Felemenkçe",
+ "ro": "Rumence",
+ "ru": "Rusça",
+ "tr": "Türkçe",
+ "myLanguages": "Dillerim",
+ "addLanguage": "Yeni dil ekle",
+ "selectLanguage": "Öğrenmek istediğiniz dili seçin",
+ "activeLanguage": "Etkin",
+ "switchTo": "Bu dile geç",
+ "switching": "Geçiliyor: {language}...",
+ "switched": "Geçildi: {language} ({level})",
+ "removeLanguage": "Dili kaldır",
+ "removeConfirmTitle": "{language} kaldırılsın mı?",
+ "removeConfirmMessage": "Bu dile ait tüm ilerleme, dersler, bilgi kartları ve konuşmalar kalıcı olarak silinecek. Hesabınıza ait anılar korunacak. Bu işlem geri alınamaz.",
+ "removeConfirmButton": "Kaldır",
+ "deleteError": "{language} silinemedi. Lütfen tekrar deneyin.",
+ "noLanguages": "Ayarlanmış bir diliniz yok.",
+ "progressLabel": "İlerleme",
+ "levelLabel": "Seviye",
+ "xpLabel": "Toplam XP",
+ "streakLabel": "Seri",
+ "lessonsLabel": "Dersler",
+ "flashcardsLabel": "Bilgi Kartları",
+ "viewDetails": "Ayrıntıları görüntüle",
+ "supportedLanguages": "Kullanılabilir diller"
+ },
+ "targetLanguages": {
+ "en-US": "Amerikan İngilizcesi",
+ "en-GB": "İngiliz İngilizcesi",
+ "es-ES": "İspanyolca",
+ "it-IT": "İtalyanca",
+ "pt-PT": "Portekizce",
+ "fr-FR": "Fransızca",
+ "de-DE": "Almanca",
+ "ja-JP": "Japonca",
+ "ko-KR": "Korece",
+ "zh-CN": "Çince (Çin anakarası)",
+ "en": "İngilizce",
+ "es": "İspanyolca",
+ "it": "İtalyanca",
+ "pt": "Portekizce",
+ "fr": "Fransızca",
+ "de": "Almanca",
+ "ja": "Japonca",
+ "ko": "Korece",
+ "zh": "Çince",
+ "es-ES-description": "İspanya'da konuşulan İspanyolca.",
+ "it-IT-description": "İtalya'da konuşulan İtalyanca.",
+ "pt-PT-description": "Portekiz'de konuşulan Portekizce.",
+ "en-US-description": "Amerika Birleşik Devletleri'nde konuşulan İngilizce.",
+ "en-GB-description": "Birleşik Krallık'ta konuşulan İngilizce.",
+ "fr-FR-description": "Fransa'da konuşulan Fransızca.",
+ "de-DE-description": "Almanya'da konuşulan Almanca.",
+ "ja-JP-description": "Japonya'da konuşulan Japonca.",
+ "ko-KR-description": "Güney Kore'de konuşulan Korece.",
+ "zh-CN-description": "Çin anakarasında konuşulan, basitleştirilmiş karakterlerle yazılan Mandarin Çincesi."
+ },
+ "onboarding": {
+ "title": "Dilinizi seçin",
+ "subtitle": "Hangi dili öğrenmek istiyorsunuz?",
+ "chooseVariant": "Varyant seçin",
+ "continue": "Devam et",
+ "saveFailed": "Tercihler kaydedilemedi",
+ "goals": {
+ "title": "Öğrenme Hedefleriniz",
+ "subtitle": "Dil: {language}. Bu dili ne için kullanmak istiyorsunuz? Uygun olanların hepsini seçin.",
+ "skip": "Atla",
+ "travel": "Seyahat ve Turizm",
+ "work": "İş ve Meslek",
+ "academic": "Eğitim ve Akademik",
+ "daily": "Günlük Konuşma",
+ "media": "Filmler, Müzik ve Diziler",
+ "emigration": "Yurt Dışında Yaşam",
+ "exams": "Sınavlar ve Sertifikalar",
+ "social": "Sosyalleşme"
+ },
+ "trialHeadline": "Ücretsiz deneme",
+ "trialHeadlineTrialUsed": "Premium",
+ "trialTitle": "{days} gün ücretsiz başlayın",
+ "trialTitleTrialUsed": "FreeLingo Premium'u etkinleştirin",
+ "trialDesc": "İlk ödemenizden önce Lingu'ya, sesli pratiğe, dinleme ve okumaya tam erişim elde edin.",
+ "trialDescTrialUsed": "Lingu'nun, sesli pratiğin, dinleme ve okumanın kilidini açmak için bir plan seçin.",
+ "trialCtaMonthly": "Ücretsiz deneyin, ardından aylık €{price}",
+ "trialCtaMonthlyTrialUsed": "Esnek aylık · aylık €{price}",
+ "trialCtaYearly": "Ücretsiz deneyin, ardından yıllık €{price} · 2 ay ücretsiz",
+ "trialCtaYearlyTrialUsed": "En avantajlı · yıllık €{price} · 2 ay ücretsiz",
+ "trialSkip": "Ücretsiz özelliklerle devam et",
+ "trialNoCharge": "Bugün ücret alınmaz. Kart gereklidir, istediğiniz zaman iptal edebilirsiniz.",
+ "trialNoChargeTrialUsed": "Abone olmadan önce tutarı gözden geçirin. İstediğiniz zaman iptal edebilirsiniz.",
+ "trialError": "Ödeme başlatılamadı. Lütfen tekrar deneyin.",
+ "freemiumTrialTitle": "Ücretsiz denemeniz başladı",
+ "freemiumTrialDesc": "7 gün boyunca tüm özelliklere sınırsız erişimin keyfini çıkarın. Kart gerekmez. İstediğiniz zaman panodan Premium'a geçebilirsiniz.",
+ "freemiumChatLabel": "Yapay zekâ eğitmeni sohbeti",
+ "freemiumVoiceLabel": "Sesli konuşmalar",
+ "freemiumListeningLabel": "Dinleme alıştırmaları",
+ "freemiumReadingLabel": "Okuma alıştırmaları",
+ "goToDashboard": "Panoya git",
+ "newLanguageHeadline": "Hangi yeni dili öğrenmek istiyorsunuz?",
+ "newLanguageSubtitle": "Bu dil için yeni bir çalışma planı oluşturulacak."
+ },
+ "tour": {
+ "skip": "Atla",
+ "prev": "Geri",
+ "next": "İleri",
+ "done": "Başlayalım",
+ "step1": {
+ "label": "Hoş geldiniz",
+ "title": "FreeLingo'ya hoş geldiniz",
+ "desc": "FreeLingo, yapay zekâ destekli dil eğitmeninizdir. Konuşmalar, dersler ve akıllı bilgi kartlarıyla, istediğiniz zaman kendi hızınızda pratik yapın."
+ },
+ "step2": {
+ "label": "Yazılı sohbet",
+ "title": "Eğitmeninizle sohbet edin",
+ "desc": "Yapay zekâ eğitmeninizle yazılı konuşmalar yapın. Soru sorun, düzeltmeler alın ve dil bilgisi ile kelime bilginizi doğal bir şekilde geliştirin."
+ },
+ "step3": {
+ "label": "Ses",
+ "title": "Gerçek zamanlı konuşun",
+ "desc": "Gerçek zamanlı deşifre ve telaffuzunuz hakkında anında geri bildirimle konuşma becerinizi geliştirmek için sesli konuşma modunu kullanın."
+ },
+ "step4": {
+ "label": "Bilgi Kartları",
+ "title": "Hiçbir kelimeyi unutmayın",
+ "desc": "Bilgi kartları SM-2 aralıklı tekrar algoritmasını kullanır; böylece kelimeleri tam unutmak üzereyken tekrar edersiniz ve akılda kalıcılık en üst düzeye çıkar."
+ },
+ "step5": {
+ "label": "Çalışma planı",
+ "title": "Size özel planınız",
+ "desc": "FreeLingo, seviye tespitinize göre hedeflerinize ve ilerlemenize uyarlanmış günlük derslerden oluşan yapılandırılmış bir çalışma planı oluşturur."
+ },
+ "step6": {
+ "label": "Pratik",
+ "title": "Dinleme ve Okuma",
+ "desc": "Yapay zekâ ile üretilmiş alıştırmalarla anlama becerinizi sınayın. Bir metni dinleyip 5 soruyu cevaplayın ya da CEFR seviyenize uygun bir metin okuyun — her doğru cevap için XP kazanın."
+ },
+ "step7": {
+ "label": "Hazır",
+ "title": "Her şey hazır!",
+ "desc": "Bugünün dersiyle başlayın, bir sohbet açın, dinleme veya okuma pratiği yapın — FreeLingo sizin öğrenme tarzınıza uyum sağlar."
+ }
+ },
+ "billing": {
+ "paywallLabel": "Premium gerekli",
+ "paywallTitle": "FreeLingo Premium'un kilidini açın",
+ "paywallDesc": "{days} günlük ücretsiz denemenizi başlatın ve ilk ödemenizden önce tüm Premium pratik modlarının kilidini açın.",
+ "paywallDescTrialUsed": "Tüm Premium pratik modlarının kilidini açın ve onaylamadan önce tutarı gözden geçirin.",
+ "paywallChatTitle": "Lingu ile sınırsız pratik yapın",
+ "paywallChatDesc": "Yapay zekâ eğitmeninize soru sorun, düzeltmeler alın ve doğal yazılı konuşmalar yapın.",
+ "paywallLessonsTitle": "Sınırsız ders tamamlayın",
+ "paywallLessonsDesc": "Dil bilgisi, kelime bilgisi, okuma ve yazma — her gün istediğiniz kadar ders bitirin.",
+ "paywallConversationTitle": "Lingu ile gerçek zamanlı konuşun",
+ "paywallConversationDesc": "Akıcılık kazanmak için deşifre, hızlı yanıtlar ve geri bildirimle sözlü konuşma pratiği yapın.",
+ "paywallListeningTitle": "Seviyenize uygun dinleme çalışması yapın",
+ "paywallListeningDesc": "İlerlemenize uyarlanmış, yapay zekâ ile üretilmiş alıştırmaları dinleyin ve anladıklarınızı hemen kontrol edin.",
+ "paywallReadingTitle": "İlerlemenize uygun metinler okuyun",
+ "paywallReadingDesc": "Seviyenize uygun metinler, sorular ve anında geri bildirimle okuduğunu anlama becerinizi geliştirin.",
+ "paywallNoCharge": "Bugün ücret alınmaz · Kart gerekli · İstediğiniz zaman iptal edin",
+ "paywallNoChargeTrialUsed": "Güvenli ödeme · İstediğiniz zaman iptal edin",
+ "paywallSkip": "Şimdi değil",
+ "trialDays": "{days, plural, one {# günlük deneme} other {# günlük deneme}}",
+ "planMonthly": "Esnek aylık · aylık €{price} →",
+ "planYearly": "En avantajlı · yıllık €{price} · 2 ay ücretsiz →",
+ "checkoutError": "Ödeme başlatılamadı. Lütfen tekrar deneyin.",
+ "pricingTitle": "Basit ve şeffaf fiyatlandırma",
+ "pricingDesc": "{days} gün ücretsiz · Bugün ücret alınmaz · İstediğiniz zaman iptal edin",
+ "pricingDescTrialUsed": "Aylık veya yıllık seçin · İstediğiniz zaman iptal edin",
+ "planMonthlyName": "Aylık",
+ "planYearlyName": "Yıllık",
+ "bestValue": "En avantajlı",
+ "month": "ay",
+ "year": "yıl",
+ "planFeature": {
+ "feature1": "Sınırsız erişim — günlük veya haftalık sınır yok",
+ "feature2": "2 ay ücretsiz"
+ },
+ "planFreeName": "Ücretsiz",
+ "trialBadge": "Ücretsiz deneme",
+ "trialBadgeTrialUsed": "Premium",
+ "ctaRegister": "Ücretsiz denemeyi başlat",
+ "ctaRegisterTrialUsed": "Plan seç",
+ "freeFeature": {
+ "f1": "Seviye testi ve seviye tespiti",
+ "f2": "Dersler ve çalışma planı",
+ "f3": "Dil bilgisi ve kelime başvuru kaynakları",
+ "f4": "Pano ve ilerleme takibi",
+ "f5": "Bilgi kartları ve aralıklı tekrar",
+ "l1": "Yapay zekâ eğitmeni sohbeti",
+ "l2": "Sesli konuşmalar",
+ "l3": "Dinleme alıştırmaları",
+ "l4": "Okuma alıştırmaları",
+ "l5": "7 günlük tam erişimli deneme"
+ },
+ "successLabel": "Ödeme onaylandı",
+ "successTitle": "FreeLingo Premium'a hoş geldiniz!",
+ "successDesc": "Aboneliğiniz artık etkin. Tüm özelliklere sınırsız erişimin keyfini çıkarın.",
+ "successCheckingLabel": "Abonelik onaylanıyor",
+ "successCheckingTitle": "Aboneliğiniz kontrol ediliyor",
+ "successCheckingDesc": "Bu genellikle birkaç saniye sürer.",
+ "successPendingLabel": "Neredeyse hazır",
+ "successPendingTitle": "Aboneliğiniz onaylanıyor",
+ "successPendingDesc": "Premium erişiminiz kısa süre içinde kullanılabilir olacak. Olmazsa faturalandırma ayarlarınızı kontrol edin.",
+ "successErrorLabel": "Onay bekleniyor",
+ "successErrorTitle": "Aboneliğinizi henüz doğrulayamadık",
+ "successErrorDesc": "Panoya gidip birazdan sayfayı yenileyin veya faturalandırma ayarlarınızı kontrol edin.",
+ "successRedirect": "{seconds} sn içinde panoya yönlendiriliyorsunuz...",
+ "successCta": "Panoya git",
+ "canceledLabel": "Ödeme iptal edildi",
+ "canceledTitle": "Herhangi bir ücret alınmadı",
+ "canceledDesc": "Herhangi bir ücret alınmadı. İlerlemeniz güvende; daha sonra ayarlarınızdan bir plan seçebilirsiniz.",
+ "canceledCtaDashboard": "Panoya git",
+ "canceledCtaSettings": "Planları görüntüle",
+ "canceledNoCharge": "Bu oturumda herhangi bir ücret alınmadı · İstediğiniz zaman bir plan seçin",
+ "section": "Abonelik",
+ "status": "Durum",
+ "statusActive": "Etkin",
+ "statusCanceling": "İptal ediliyor",
+ "statusCanceled": "İptal edildi",
+ "statusTrialing": "Deneme",
+ "statusPastDue": "Ödemesi gecikmiş",
+ "statusUnpaid": "Ödenmedi",
+ "statusPaused": "Duraklatıldı",
+ "statusIncomplete": "Ödeme bekleniyor",
+ "statusIncompleteExpired": "Ödemenin süresi doldu",
+ "statusNone": "Abonelik yok",
+ "nextBilling": "Sonraki fatura",
+ "accessUntil": "Erişim bitiş tarihi",
+ "manage": "Aboneliği yönet",
+ "updatePayment": "Ödemeyi güncelle",
+ "pastDueTitle": "Ödeme bekleniyor",
+ "pastDueDesc": "Premium erişiminizi geri kazanmak için ödeme yönteminizi güncelleyin.",
+ "subscribe": "Abone ol",
+ "portalError": "Faturalandırma portalı açılamadı. Lütfen tekrar deneyin.",
+ "openSourceTitle": "Açık kaynak",
+ "openSourceDesc": "Kendi sunucunuzda ücretsiz olarak barındırın",
+ "openSourceCta": "GitHub'da görüntüle",
+ "planFreeBadge": "Sonsuza Dek Ücretsiz",
+ "priceAmount": "€{amount}",
+ "pricePerPeriod": "/ {period}",
+ "priceOriginal": "€{price} / {period}",
+ "planFreeDesc": "7 günlük tam deneme, ardından günlük ve haftalık sınırlarla ücretsiz",
+ "planFreeCta": "Başla",
+ "limitedLabel": "Sınırlı"
+ },
+ "freemium": {
+ "chatLabel": "Sohbet",
+ "lessonsLabel": "Dersler",
+ "listeningLabel": "Dinleme",
+ "readingLabel": "Okuma",
+ "voiceLabel": "Ses (dk)",
+ "freeLimit": "Premium'a geç",
+ "trialDaysLeft": "{days, plural, one {# günlük ücretsiz deneme} other {# günlük ücretsiz deneme}}",
+ "trialUnlimited": "Sınırsız erişim",
+ "requiresSubscription": "Yalnızca Premium"
+ },
+ "whatsNew": {
+ "title": "Yenilikler",
+ "version": "v1.9.15",
+ "cta": "Anladım",
+ "entry1": {
+ "label": "Daha dengeli çalışma planları",
+ "desc": "Yeni planlar dersleri tüm ünitelere daha eşit dağıtır ve daha kısa planlarda bile daha çeşitli etkinliklere yer açar."
+ },
+ "entry2": {
+ "label": "Planınızı tamamlayan bir test",
+ "desc": "Son güne ulaşıp bekleyen dersleri bitirdiğinizde, seviye sonu testine panodan veya Planım bölümünden girebilir ve ne kadar öğrendiğinizi görebilirsiniz."
+ },
+ "entry3": {
+ "label": "Daha net sonraki adımlar",
+ "desc": "Test sonuçları ve öneriler artık kendi dilinizde; bir sonraki adıma geçmek veya öğrendiklerinizi tekrar etmek için daha net yönlendirmeler içeriyor."
+ },
+ "entry4": {
+ "label": "Daha akıcı bir deneyim",
+ "desc": "FreeLingo ile günlük öğreniminizi daha keyifli hâle getirmek için küçük hataları da düzelttik ve bazı ayrıntıları iyileştirdik."
+ }
+ },
+ "contact": {
+ "title": "İletişim",
+ "labelEmail": "E-posta",
+ "placeholderEmail": "adiniz@eposta.com",
+ "labelSubject": "Konu",
+ "placeholderSubject": "Sorunuzun kısa açıklaması",
+ "labelDescription": "Mesaj",
+ "placeholderDescription": "Sorunuzu veya geri bildiriminizi açıklayın...",
+ "send": "Gönder",
+ "sending": "Gönderiliyor...",
+ "sent": "Mesaj gönderildi",
+ "errorGeneric": "Gönderilemedi. Lütfen tekrar deneyin."
+ },
+ "listening": {
+ "title": "Dinleme",
+ "topic": "Konu",
+ "listenLabel": "Dinle",
+ "questionsLabel": "Sorular",
+ "submit": "Cevapları gönder",
+ "generating": "Alıştırma oluşturuluyor...",
+ "generatingDesc": "Yapay zekâ yeni bir alıştırma oluşturuyor. Bu genellikle 30 saniye kadar sürer.",
+ "generatingLong": "Beklenenden uzun sürüyor...",
+ "noExercises": "Seviyeniz için alıştırma yok.",
+ "generate": "Alıştırma oluştur",
+ "audioError": "Ses yüklenemedi",
+ "alreadyAttempted": "Bu alıştırmayı zaten tamamladınız.",
+ "errorLoading": "Alıştırma yüklenemedi. Lütfen tekrar deneyin.",
+ "errorSubmit": "Cevaplar gönderilemedi. Lütfen tekrar deneyin.",
+ "resultsLabel": "Sonuçlar",
+ "transcript": "Deşifre",
+ "review": "Cevapların incelemesi",
+ "nextExercise": "Sonraki alıştırma",
+ "viewHistory": "Geçmiş",
+ "history": "Geçmiş",
+ "historyTitle": "Dinleme geçmişi",
+ "historyEmpty": "Henüz tamamlanmış alıştırma yok.",
+ "practiceMore": "Pratik",
+ "moreInHistory": "+{count} tane daha",
+ "practiceAgain": "Tekrar pratik yap",
+ "replayNoXp": "Tekrar oyna (XP yok)"
+ },
+ "reading": {
+ "title": "Okuma",
+ "topic": "Konu",
+ "textLabel": "Metin",
+ "questionsLabel": "Sorular",
+ "submit": "Cevapları gönder",
+ "generating": "Alıştırma oluşturuluyor...",
+ "generatingDesc": "Yapay zekâ yeni bir alıştırma oluşturuyor. Bu genellikle 30 saniye kadar sürer.",
+ "generatingLong": "Beklenenden uzun sürüyor...",
+ "noExercises": "Seviyeniz için alıştırma yok.",
+ "generate": "Alıştırma oluştur",
+ "alreadyAttempted": "Bu alıştırmayı zaten tamamladınız.",
+ "errorLoading": "Alıştırma yüklenemedi. Lütfen tekrar deneyin.",
+ "errorSubmit": "Cevaplar gönderilemedi. Lütfen tekrar deneyin.",
+ "resultsLabel": "Sonuçlar",
+ "review": "Cevapların incelemesi",
+ "nextExercise": "Sonraki alıştırma",
+ "viewHistory": "Geçmiş",
+ "history": "Geçmiş",
+ "historyTitle": "Okuma geçmişi",
+ "historyEmpty": "Henüz tamamlanmış alıştırma yok.",
+ "practiceMore": "Pratik",
+ "moreInHistory": "+{count} tane daha",
+ "practiceAgain": "Tekrar pratik yap",
+ "replayNoXp": "Tekrar yap (XP yok)",
+ "selectWordHint": "Kelime dağarcığınıza kaydetmek için bir kelime seçin"
+ },
+ "feedback": {
+ "title": "Geri Bildirim",
+ "subtitle": "Özellik istekleri ve hata bildirimleri",
+ "tabFeatures": "Öneriler",
+ "tabBugs": "Hata bildirimleri",
+ "newFeature": "+ Yeni öneri",
+ "newBug": "+ Hata bildir",
+ "sortBy": "Sırala",
+ "sortVotes": "En çok oy alan",
+ "sortDate": "En yeni",
+ "filterStatus": "Durum",
+ "filterAll": "Tümü",
+ "noEntries": "Burada henüz bir şey yok. İlk gönderen siz olun.",
+ "votes": "{count} oy",
+ "vote": "1 oy",
+ "comments": "{count} yorum",
+ "comment": "1 yorum",
+ "by": "Gönderen:",
+ "statusPending": "Beklemede",
+ "statusPlanned": "Planlandı",
+ "statusInProgress": "Devam ediyor",
+ "statusDone": "Tamamlandı",
+ "statusDeclined": "Reddedildi",
+ "unread": "Okunmadı",
+ "modalCreateTitleFeature": "Yeni öneri",
+ "modalCreateTitleBug": "Hata bildir",
+ "labelTitle": "Başlık",
+ "placeholderTitleFeature": "Önerinizi tek cümleyle açıklayın",
+ "placeholderTitleBug": "Hatanın kısa açıklaması",
+ "labelDescription": "Ayrıntılar",
+ "placeholderDescriptionFeature": "Özelliği ve neden faydalı olacağını açıklayın",
+ "placeholderDescriptionBug": "Hatayı yeniden oluşturma adımları, beklenen davranış, bunun yerine ne oldu",
+ "submit": "Gönder",
+ "submitting": "Gönderiliyor...",
+ "cancel": "İptal",
+ "deleteEntry": "Sil",
+ "deleteEntryConfirmTitle": "Kaydı sil",
+ "deleteEntryConfirmMessage": "Bu kaydı silmek istediğinizden emin misiniz? Bu işlem geri alınamaz.",
+ "deleteEntryConfirm": "Sil",
+ "addComment": "Yorum ekle",
+ "commentPlaceholder": "Bir yorum yazın...",
+ "postComment": "Paylaş",
+ "postingComment": "Paylaşılıyor...",
+ "deleteComment": "Sil",
+ "deleteCommentConfirmTitle": "Yorumu sil",
+ "deleteCommentConfirmMessage": "Bu yorum silinsin mi?",
+ "deleteCommentConfirm": "Sil",
+ "loading": "Yükleniyor...",
+ "backToList": "← Geri",
+ "errorLoad": "Yüklenemedi. Lütfen tekrar deneyin.",
+ "errorSubmit": "Gönderilemedi. Lütfen tekrar deneyin.",
+ "prevPage": "← Önceki",
+ "nextPage": "Sonraki →"
+ },
+ "reviewPrompt": {
+ "statusError": "Yorum durumunuz kontrol edilemedi. Lütfen daha sonra tekrar deneyin.",
+ "ratingRequiredError": "Göndermeden önce lütfen bir puan seçin.",
+ "saveError": "Yorumunuz kaydedilemedi. Lütfen tekrar deneyin.",
+ "eyebrow": "FreeLingo'yu değerlendirin",
+ "title": "Deneyiminiz nasıldı?",
+ "closeLabel": "Değerlendirme penceresini kapat",
+ "checking": "Yorum durumu kontrol ediliyor...",
+ "ratingLabel": "Puan zorunlu",
+ "ratingGroupLabel": "Puan",
+ "star": "yıldız",
+ "stars": "yıldız",
+ "commentLabel": "Yorum isteğe bağlı",
+ "commentPlaceholder": "Öğrenmenize neyin yardımcı olduğunu bize anlatın.",
+ "cancel": "İptal",
+ "submit": "Gönder"
+ },
+ "landingReviews": {
+ "eyebrow": "Öğrenci hikâyeleri",
+ "title": "Öğrenmek, kendiniz anlattığınızda daha gerçek hissettirir",
+ "subtitle": "FreeLingo'da Lingu ile pratik yapan öğrencilerden yorumlar.",
+ "averageLabel": "{average}/5 · {count, plural, one {toplam # yorum} other {toplam # yorum}}",
+ "learningLanguage": "Öğrendiği dil: {language}",
+ "starsLabel": "5 üzerinden {rating} yıldız",
+ "ratingOnly": "Doğrulanmış FreeLingo puanı."
+ },
+ "adminReviews": {
+ "title": "Yorumlar",
+ "eyebrow": "Yönetim",
+ "totalFiltered": "Filtrelenen toplam",
+ "approvedOnPage": "Sayfada onaylanan",
+ "pendingOnPage": "Sayfada bekleyen",
+ "filters": "Filtreler",
+ "approvalFilter": "Onay filtresi",
+ "allReviews": "Tüm yorumlar",
+ "pending": "Beklemede",
+ "approved": "Onaylandı",
+ "ratingFilter": "Puan filtresi",
+ "allRatings": "Tüm puanlar",
+ "starsOption": "{rating} yıldız",
+ "clear": "Temizle",
+ "loadError": "Yorumlar yüklenemedi.",
+ "updateError": "Yorum güncellenemedi.",
+ "deleteError": "Yorum silinemedi.",
+ "loading": "Yorumlar yükleniyor...",
+ "queue": "Yorum kuyruğu",
+ "total": "Toplam {total}",
+ "empty": "Yorum bulunamadı.",
+ "starsLabel": "{rating} yıldız",
+ "learningLanguage": "Öğrendiği dil: {language}",
+ "ratingOnly": "Yalnızca puan içeren yorum.",
+ "unapprove": "Onayı kaldır",
+ "approve": "Onayla",
+ "delete": "Sil",
+ "prev": "Önceki",
+ "next": "Sonraki",
+ "deleteTitle": "Yorumu sil",
+ "deleteMessage": "Bu yorum silinsin mi? Bu işlem geri alınamaz."
+ },
+ "maintenance": {
+ "label": "Bakım",
+ "title": "Bakımda",
+ "description": "Bakım çalışması yaptığımız için bu bölüm geçici olarak kullanılamıyor. Lütfen daha sonra tekrar kontrol edin."
+ }
+}
diff --git a/specs/api-endpoints.instructions.md b/specs/api-endpoints.instructions.md
index 66a1b6e7f..398a156e5 100644
--- a/specs/api-endpoints.instructions.md
+++ b/specs/api-endpoints.instructions.md
@@ -34,7 +34,7 @@ Most REST endpoints are prefixed under `/api`. The public health check is at `/h
- **POST `/refresh`** — Rate limit: 60/min. Rotates refresh token, returns new access_token
- **POST `/logout`** — Rate limit: 60/min. Deletes refresh token from Redis, clears cookie
- **GET `/me`** — Rate limit: 60/min. Returns authenticated user profile, including subscription fields (`subscription_status`, `subscription_ends_at`, `cancel_at_period_end`, `trial_used`, `assessment_voice_trial_used`), freemium fields (`freemium_trial_ends_at`, `freemium_trial_used`), and nullable `dismissed_dashboard_banner_revision`.
-- **PATCH `/me`** — Rate limit: 60/min. Updates display name, email, password, native language, target language, UI locale, bio, learning goals, and conversation settings (`conversation_max_duration` ∈ {900, 1800}, `conversation_inactivity_timeout` ∈ {60, 180, 300}, `conversation_speech_pause` ∈ {0, 1000, 2000, 3000} milliseconds, where `0` means automatic). `native_language` is validated against the same supported UI-language codes used at registration (`en`, `es`, `fr`, `pt`, `de`, `it`, `ru`, `nl`, `pl`, `ro`); unsupported codes return HTTP 422 even when the API is called outside the selector-based frontend.
+- **PATCH `/me`** — Rate limit: 60/min. Updates display name, email, password, native language, target language, UI locale, bio, learning goals, and conversation settings (`conversation_max_duration` ∈ {900, 1800}, `conversation_inactivity_timeout` ∈ {60, 180, 300}, `conversation_speech_pause` ∈ {0, 1000, 2000, 3000} milliseconds, where `0` means automatic). `native_language` is validated against the same supported UI-language codes used at registration (`en`, `es`, `fr`, `pt`, `de`, `it`, `ru`, `nl`, `pl`, `ro`, `tr`); unsupported codes return HTTP 422 even when the API is called outside the selector-based frontend.
- **POST `/me/avatar`** — Rate limit: 60/min. Uploads the authenticated user's profile avatar (JPEG/PNG, max 2 MB). Validates the declared content type, image signature, and minimal image structure, stores the image on disk under `/app/avatars` using a non-predictable UUID filename, and returns the user profile with `avatar` set to a cache-busted internal reference (`/api/avatars/{uuid}.{ext}?v={ms}`). The file reference is not publicly served.
- **GET `/me/avatar-file`** — Rate limit: 60/min. Authenticated current-user avatar retrieval endpoint. Returns only the authenticated user's own avatar file; this is the supported image retrieval path used by the frontend. Responses are marked `Cache-Control: private, no-store`; client-side avatar reuse is handled by the frontend blob cache keyed by the stored avatar reference.
- **DELETE `/me/avatar`** — Rate limit: 60/min. Removes profile avatar (sets to null)
diff --git a/specs/platform.instructions.md b/specs/platform.instructions.md
index 2085b0f2a..5aed70d11 100644
--- a/specs/platform.instructions.md
+++ b/specs/platform.instructions.md
@@ -188,7 +188,7 @@ translation context from the user profile. Reviewing always credits the card's s
The application distinguishes UI locale, native language, learned target language, active
`UserLanguage`, and resource-owning `StudyPlan.target_language`.
-The interface locales are `en`, `es`, `fr`, `pt`, `de`, `it`, `pl`, `nl`, `ro`, and `ru`. Locale
+The interface locales are `en`, `es`, `fr`, `pt`, `de`, `it`, `pl`, `nl`, `ro`, `ru`, and `tr`. Locale
resolution uses `NEXT_LOCALE`, then `Accept-Language`, then English. Middleware passes the selected
locale to server rendering; missing catalogs fall back to English. Settings updates profile locale
and locale cookies before reload.