From 8af730e9cf5e65508930a4e62b21bec288fdcc32 Mon Sep 17 00:00:00 2001 From: Ulas Date: Tue, 14 Apr 2026 10:28:17 +0200 Subject: [PATCH] feat: add Japanese, Arabic, Hindi, Portuguese locales + new currencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 4 new locale files (ja, ar, hi, pt) with 567 keys each - full coverage - Japanese (日本語): Hiragana/Kanji script - Arabic (العربية): RTL-ready text - Hindi (हिन्दी): Devanagari script - Portuguese (Português): Brazilian Portuguese - SUPPORTED_LOCALES updated in i18n.js (10 → 14 locales) - LOCALE_LABELS updated in oikos-locale-picker.js - New currencies: AED, BRL, INR, SAR added to budget settings - Service Worker v31: new locale files pre-cached in APP_SHELL - Docs: README, SPEC.md, BACKLOG.md, CHANGELOG.md updated --- BACKLOG.md | 2 + CHANGELOG.md | 10 + README.md | 2 +- docs/SPEC.md | 6 +- package.json | 2 +- public/components/oikos-locale-picker.js | 4 + public/i18n.js | 2 +- public/locales/ar.json | 599 +++++++++++++++++++++++ public/locales/hi.json | 599 +++++++++++++++++++++++ public/locales/ja.json | 599 +++++++++++++++++++++++ public/locales/pt.json | 599 +++++++++++++++++++++++ public/pages/settings.js | 2 +- public/sw.js | 6 +- 13 files changed, 2426 insertions(+), 6 deletions(-) create mode 100644 public/locales/ar.json create mode 100644 public/locales/hi.json create mode 100644 public/locales/ja.json create mode 100644 public/locales/pt.json diff --git a/BACKLOG.md b/BACKLOG.md index a69b7c6..46c3f37 100644 --- a/BACKLOG.md +++ b/BACKLOG.md @@ -51,3 +51,5 @@ New suggestion? → [Open an issue](https://github.com/ulsklyc/oikos/issues/new? | - | Budget: CNY (Chinese Yuan) added to currency list (#42) | v0.16.2 | | - | i18n: French (fr), Turkish (tr), Russian (ru), Greek (el), Chinese Simplified (zh) locales | v0.16.3 | | - | Budget: TRY (Turkish Lira) and RUB (Russian Ruble) added to currency list | v0.16.3 | +| - | i18n: Japanese (ja), Arabic (ar), Hindi (hi), Portuguese (pt) locales (567 keys each) | v0.19.0 | +| - | Budget: AED (UAE Dirham), BRL (Brazilian Real), INR (Indian Rupee), SAR (Saudi Riyal) added to currency list | v0.19.0 | diff --git a/CHANGELOG.md b/CHANGELOG.md index 0813b62..1a02432 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.19.0] - 2026-04-14 + +### Added +- i18n: Japanese (ja) locale - full translation with 567 keys; Hiragana/Katakana/Kanji script +- i18n: Arabic (ar) locale - full translation with 567 keys; RTL-ready text +- i18n: Hindi (hi) locale - full translation with 567 keys; Devanagari script +- i18n: Portuguese (pt) locale - full translation with 567 keys; Brazilian Portuguese +- Budget: AED (UAE Dirham), BRL (Brazilian Real), INR (Indian Rupee), SAR (Saudi Riyal) added to currency list +- Service Worker: new locale files pre-cached in APP_SHELL for offline support (sw v31) + ## [0.18.2] - 2026-04-14 ### Fixed diff --git a/README.md b/README.md index 7a59a8f..73d39da 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ **PWA Native Feel:** Installable on any device, works offline, dark mode, responsive from phone to desktop -**Multilingual:** German, English, Spanish, French, Italian, Swedish, Greek, Russian, Turkish, and Chinese UI with automatic locale detection +**Multilingual:** German, English, Spanish, French, Italian, Swedish, Greek, Russian, Turkish, Chinese, Japanese, Arabic, Hindi, and Portuguese UI with automatic locale detection ## Quick Start diff --git a/docs/SPEC.md b/docs/SPEC.md index 3484959..acdd100 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -368,7 +368,7 @@ All UI strings are managed via `public/i18n.js`. No hardcoded text in JS files o ### Architecture - **Module:** `public/i18n.js` - exports: `initI18n()`, `setLocale()`, `t(key, params?)`, `getLocale()`, `getSupportedLocales()`, `formatDate(date)`, `formatTime(date)` -- **Locale files:** `public/locales/de.json` (reference), `public/locales/en.json`, `public/locales/es.json`, `public/locales/fr.json`, `public/locales/it.json`, `public/locales/sv.json`, `public/locales/el.json`, `public/locales/ru.json`, `public/locales/tr.json`, `public/locales/zh.json` - structure: `{ "module.camelCaseKey": "Value" }` +- **Locale files:** `public/locales/de.json` (reference), `public/locales/en.json`, `public/locales/es.json`, `public/locales/fr.json`, `public/locales/it.json`, `public/locales/sv.json`, `public/locales/el.json`, `public/locales/ru.json`, `public/locales/tr.json`, `public/locales/zh.json`, `public/locales/ja.json`, `public/locales/ar.json`, `public/locales/hi.json`, `public/locales/pt.json` - structure: `{ "module.camelCaseKey": "Value" }` - **Variables:** `{{variable}}` syntax in translation strings, e.g. `t('tasks.assignedTo', { name: 'Anna' })` - **Fallback chain:** active locale → German (`de`) → key itself - **Date format:** `Intl.DateTimeFormat` with current locale - use `formatDate()` and `formatTime()` from `i18n.js` @@ -393,6 +393,10 @@ All UI strings are managed via `public/i18n.js`. No hardcoded text in JS files o | `ru` | Russian | Full translation (added v0.16.3) | | `tr` | Turkish | Full translation (added v0.16.3) | | `zh` | Chinese (Simplified) | Full translation (added v0.16.3) | +| `ja` | Japanese | Full translation (added v0.19.0) | +| `ar` | Arabic | Full translation (added v0.19.0) | +| `hi` | Hindi | Full translation (added v0.19.0) | +| `pt` | Portuguese | Full translation (added v0.19.0) | ### Adding a New Language diff --git a/package.json b/package.json index a8eeb2b..d2ca364 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oikos", - "version": "0.18.2", + "version": "0.19.0", "description": "Self-hosted family planner - calendar, tasks, shopping, meal planning, budget and more. Private, open-source, no subscription.", "main": "server/index.js", "type": "module", diff --git a/public/components/oikos-locale-picker.js b/public/components/oikos-locale-picker.js index e1a6de0..1a6ac20 100644 --- a/public/components/oikos-locale-picker.js +++ b/public/components/oikos-locale-picker.js @@ -18,6 +18,10 @@ const LOCALE_LABELS = { ru: 'Русский', tr: 'Türkçe', zh: '中文', + ja: '日本語', + ar: 'العربية', + hi: 'हिन्दी', + pt: 'Português', }; class OikosLocalePicker extends HTMLElement { diff --git a/public/i18n.js b/public/i18n.js index 218cc67..0f173a5 100644 --- a/public/i18n.js +++ b/public/i18n.js @@ -5,7 +5,7 @@ * Dependencies: none (vanilla JS, Fetch API, Intl API) */ -const SUPPORTED_LOCALES = ['de', 'en', 'es', 'fr', 'it', 'sv', 'el', 'ru', 'tr', 'zh']; +const SUPPORTED_LOCALES = ['de', 'en', 'es', 'fr', 'it', 'sv', 'el', 'ru', 'tr', 'zh', 'ja', 'ar', 'hi', 'pt']; const DEFAULT_LOCALE = 'de'; const STORAGE_KEY = 'oikos-locale'; diff --git a/public/locales/ar.json b/public/locales/ar.json new file mode 100644 index 0000000..854ffa2 --- /dev/null +++ b/public/locales/ar.json @@ -0,0 +1,599 @@ +{ + "common": { + "save": "حفظ", + "cancel": "إلغاء", + "delete": "حذف", + "edit": "تعديل", + "close": "إغلاق", + "create": "إنشاء", + "add": "إضافة", + "back": "رجوع", + "next": "التالي", + "loading": "جارٍ التحميل…", + "saving": "جارٍ الحفظ…", + "required": "هذا الحقل مطلوب.", + "error": "خطأ", + "allFieldsRequired": "يرجى ملء جميع الحقول.", + "today": "اليوم", + "tomorrow": "غداً", + "skipToContent": "الانتقال إلى المحتوى", + "reload": "إعادة التحميل", + "errorOccurred": "حدث خطأ ما.", + "unexpectedError": "حدث خطأ غير متوقع.", + "errorGeneric": "حدث خطأ.", + "updateAvailable": "يوجد تحديث - أعد تحميل الصفحة للحصول على أحدث إصدار.", + "titleRequired": "العنوان مطلوب", + "nameRequired": "الاسم مطلوب", + "contentRequired": "المحتوى مطلوب", + "all": "الكل", + "unknownError": "خطأ غير معروف", + "confirm": "تأكيد", + "undo": "تراجع" + }, + "nav": { + "dashboard": "لوحة التحكم", + "tasks": "المهام", + "calendar": "التقويم", + "meals": "الوجبات", + "shopping": "التسوق", + "notes": "الملاحظات", + "contacts": "جهات الاتصال", + "budget": "الميزانية", + "settings": "الإعدادات", + "main": "القائمة الرئيسية", + "navigation": "التنقل", + "quickActions": "الإجراءات السريعة" + }, + "dashboard": { + "title": "لوحة التحكم", + "greetingMorning": "صباح الخير، {{name}}", + "greetingDay": "مرحباً، {{name}}", + "greetingEvening": "مساء الخير، {{name}}", + "allDone": "تم الانتهاء من الكل", + "noEvents": "لا توجد أحداث", + "noPinnedNotes": "لا توجد ملاحظات مثبتة", + "todayMeals": "وجبات اليوم", + "allLink": "الكل", + "weekLink": "هذا الأسبوع", + "urgentTasksChip": "{{count}} مهمة عاجلة", + "urgentTasksChipPlural": "{{count}} مهام عاجلة", + "eventsChip": "{{count}} حدث اليوم", + "eventsChipPlural": "{{count}} أحداث اليوم", + "todayMealChip": "اليوم: {{title}}", + "loadError": "فشل تحميل لوحة التحكم.", + "weatherRefresh": "تحديث الطقس", + "weatherRefreshTitle": "تحديث", + "weatherUpdated": "تم تحديث الطقس", + "weatherFeelsLike": "الإحساس {{temp}}° · {{humidity}}% · الريح {{wind}} كم/س", + "fabTaskLabel": "إضافة مهمة", + "fabCalendarLabel": "إضافة حدث", + "fabShoppingLabel": "إضافة تسوق", + "fabNoteLabel": "إضافة ملاحظة", + "fabTask": "مهمة", + "fabCalendar": "حدث", + "fabShopping": "تسوق", + "fabNote": "ملاحظة", + "overdue": "متأخر", + "dueSoon": "يستحق اليوم", + "dueTomorrow": "يستحق غداً", + "allDay": "طوال اليوم", + "shoppingMore": "+{{count}} أخرى", + "weather": "الطقس", + "customize": "تخصيص", + "customizeTitle": "تخصيص الأدوات", + "customizeReset": "الافتراضي", + "customizeSaved": "تم حفظ لوحة التحكم", + "customizeMoveUp": "للأعلى", + "customizeMoveDown": "للأسفل" + }, + "tasks": { + "title": "المهام", + "newTask": "مهمة جديدة", + "editTask": "تعديل المهمة", + "emptyTitle": "لا توجد مهام - هل انتهيت من الكل؟", + "emptyDescription": "أنشئ مهام جديدة عبر زر +.", + "titleLabel": "العنوان *", + "titlePlaceholder": "ما الذي يجب إنجازه؟", + "descriptionLabel": "ملاحظة", + "descriptionPlaceholder": "تفاصيل اختيارية…", + "priorityLabel": "الأولوية", + "categoryLabel": "الفئة", + "dueDateLabel": "تاريخ الاستحقاق", + "dueTimeLabel": "الوقت", + "assignedLabel": "مسند إلى", + "assignedNobody": "- لا أحد -", + "statusLabel": "الحالة", + "priorityUrgent": "عاجل", + "priorityHigh": "عالية", + "priorityMedium": "متوسطة", + "priorityLow": "منخفضة", + "priorityNone": "لا شيء", + "statusOpen": "مفتوح", + "statusInProgress": "قيد التنفيذ", + "statusDone": "منجز", + "categoryHousehold": "المنزل", + "categorySchool": "المدرسة", + "categoryShopping": "التسوق", + "categoryRepair": "الإصلاح", + "categoryHealth": "الصحة", + "categoryFinance": "المالية", + "categoryLeisure": "الترفيه", + "categoryMisc": "متنوع", + "overdue": "متأخر", + "overdueDay": "متأخر {{count}} يوم", + "dueToday": "يستحق اليوم", + "dueTomorrow": "يستحق غداً", + "groupOverdue": "متأخر", + "groupToday": "اليوم", + "groupThisWeek": "هذا الأسبوع", + "groupNextWeek": "الأسبوع القادم", + "groupLater": "لاحقاً", + "groupNoDate": "بلا تاريخ", + "markDone": "وضع علامة منجز على {{title}}", + "editButton": "تعديل المهمة", + "swipeOpen": "فتح", + "swipeDone": "منجز", + "swipeEdit": "تعديل", + "subtaskAdd": "+ إضافة مهمة فرعية", + "subtaskToggle": "عرض المهام الفرعية", + "subtaskMarkDone": "وضع علامة منجز على {{title}}", + "deleteConfirm": "حذف المهمة وجميع المهام الفرعية؟", + "savedToast": "تم حفظ المهمة.", + "createdToast": "تم إنشاء المهمة.", + "deletedToast": "تم حذف المهمة.", + "loadError": "فشل تحميل المهمة.", + "subtaskPrompt": "المهمة الفرعية:", + "kanbanOpen": "مفتوح", + "kanbanInProgress": "قيد التنفيذ", + "kanbanDone": "منجز", + "kanbanMoveToInProgress": "نقل إلى قيد التنفيذ", + "kanbanMoveToDone": "وضع علامة منجز", + "kanbanMoveToOpen": "إعادة الفتح", + "recurring": "متكرر", + "listView": "عرض القائمة", + "kanbanView": "عرض كانبان" + }, + "shopping": { + "title": "التسوق", + "noLists": "لا توجد قوائم", + "noListsDescription": "أنشئ قائمة عبر زر +.", + "emptyList": "القائمة فارغة", + "emptyListDescription": "أضف عناصر عبر حقل الإدخال أعلاه.", + "newListPrompt": "اسم القائمة الجديدة:", + "newListButton": "إنشاء قائمة جديدة", + "renameListPrompt": "اسم القائمة الجديد:", + "deleteListConfirm": "حذف القائمة \"{{name}}\" وجميع العناصر؟", + "deletedListToast": "تم حذف القائمة.", + "itemDeletedToast": "تم إزالة \"{{name}}\".", + "itemsRemovedToast": "تم إزالة {{count}} عنصر.", + "clearChecked": "حذف المحددات ({{count}})", + "itemNamePlaceholder": "إضافة عنصر…", + "itemQtyPlaceholder": "الكمية", + "itemNameLabel": "اسم العنصر", + "itemQtyLabel": "الكمية", + "categoryLabel": "الفئة", + "addItemLabel": "إضافة عنصر", + "renameListLabel": "إعادة تسمية القائمة", + "deleteListLabel": "حذف القائمة", + "swipeBack": "رجوع", + "swipeCheck": "تحديد", + "swipeDelete": "حذف", + "markDoneLabel": "تحديد {{name}}", + "markUndoneLabel": "إلغاء تحديد {{name}}", + "deleteItemLabel": "حذف {{name}}", + "listsLoadError": "فشل تحميل القوائم.", + "itemsLoadError": "فشل تحميل العناصر.", + "catFruitVeg": "فواكه وخضروات", + "catBakery": "مخبوزات", + "catDairy": "منتجات الألبان", + "catMeatFish": "لحوم وأسماك", + "catFrozen": "مجمدات", + "catDrinks": "مشروبات", + "catHousehold": "مستلزمات المنزل", + "catDrugstore": "صيدلية", + "catMisc": "متنوع" + }, + "meals": { + "title": "خطة الوجبات", + "noMealPlanned": "لا توجد وجبة مخططة", + "addMeal": "إضافة {{type}}", + "editMeal": "تعديل الوجبة", + "addMealTitle": "إضافة وجبة", + "deleteMeal": "حذف الوجبة", + "transferToShoppingList": "نقل المكونات إلى قائمة التسوق", + "today": "اليوم", + "prevWeek": "الأسبوع السابق", + "nextWeek": "الأسبوع التالي", + "loadError": "فشل تحميل خطة الوجبات.", + "typeBreakfast": "الإفطار", + "typeLunch": "الغداء", + "typeDinner": "العشاء", + "typeSnack": "وجبة خفيفة", + "dayMo": "الإثنين", + "dayDi": "الثلاثاء", + "dayMi": "الأربعاء", + "dayDo": "الخميس", + "dayFr": "الجمعة", + "daySa": "السبت", + "daySo": "الأحد", + "dateLabel": "التاريخ", + "mealTypeLabel": "نوع الوجبة", + "titleLabel": "العنوان *", + "titlePlaceholder": "مثال: أرز بالدجاج", + "notesLabel": "ملاحظات", + "notesPlaceholder": "اختياري…", + "ingredientsLabel": "المكونات", + "addIngredient": "إضافة مكون", + "ingredientNamePlaceholder": "المكون", + "ingredientQtyPlaceholder": "الكمية", + "removeIngredient": "إزالة المكون", + "transferLabel": "نقل المكونات إلى قائمة التسوق", + "transferNow": "نقل الآن", + "noShoppingLists": "لا توجد قوائم تسوق", + "transferSuccess": "تم نقل {{count}} مكون", + "transferSuccessPlural": "تم نقل {{count}} مكونات", + "transferAlreadyDone": "تم نقل جميع المكونات بالفعل", + "ingredientCount": "{{count}} مكون", + "ingredientCountPlural": "{{count}} مكونات", + "titleRequired": "العنوان مطلوب", + "loadingIndicator": "جارٍ التحميل…", + "recipeUrlLabel": "رابط الوصفة (اختياري)", + "recipeUrlPlaceholder": "https://…", + "openRecipe": "فتح الوصفة" + }, + "calendar": { + "title": "التقويم", + "newEvent": "حدث جديد", + "editEvent": "تعديل الحدث", + "addEvent": "إضافة حدث", + "deleteEvent": "حذف الحدث", + "noEvents": "لا توجد أحداث في الفترة المحددة.", + "today": "اليوم", + "back": "رجوع", + "forward": "للأمام", + "viewMonth": "شهر", + "viewWeek": "أسبوع", + "viewDay": "يوم", + "viewAgenda": "جدول أعمال", + "allDay": "طوال اليوم", + "allDayShort": "اليوم كله", + "moreEvents": "+{{count}} أخرى", + "weekNumberLabel": "الأسبوع {{week}} · {{month}} {{year}}", + "agendaFrom": "من {{date}}", + "titleLabel": "العنوان *", + "titlePlaceholder": "مثال: طبيب الأسنان", + "allDayToggle": "طوال اليوم", + "startDateLabel": "تاريخ البداية", + "startTimeLabel": "وقت البداية", + "endDateLabel": "تاريخ النهاية", + "endTimeLabel": "وقت النهاية", + "fromLabel": "من", + "toLabel": "إلى", + "locationLabel": "الموقع", + "locationPlaceholder": "اختياري", + "assignedLabel": "مسند إلى", + "assignedNobody": "- لا أحد -", + "colorLabel": "اللون {{color}}", + "descriptionLabel": "الوصف", + "descriptionPlaceholder": "اختياري…", + "popupEdit": "تعديل", + "deleteConfirm": "هل تريد حذف \"{{title}}\"؟", + "createdToast": "تم إنشاء الحدث", + "savedToast": "تم حفظ الحدث", + "deletedToast": "تم حذف الحدث", + "loadError": "فشل تحميل الأحداث.", + "saveError": "فشل الحفظ", + "deleteError": "فشل الحذف", + "titleRequired": "العنوان مطلوب", + "monthJanuary": "يناير", + "monthFebruary": "فبراير", + "monthMarch": "مارس", + "monthApril": "أبريل", + "monthMay": "مايو", + "monthJune": "يونيو", + "monthJuly": "يوليو", + "monthAugust": "أغسطس", + "monthSeptember": "سبتمبر", + "monthOctober": "أكتوبر", + "monthNovember": "نوفمبر", + "monthDecember": "ديسمبر", + "dayShortSunday": "أح", + "dayShortMonday": "إث", + "dayShortTuesday": "ثل", + "dayShortWednesday": "أر", + "dayShortThursday": "خم", + "dayShortFriday": "جم", + "dayShortSaturday": "سب", + "dayLongSunday": "الأحد", + "dayLongMonday": "الإثنين", + "dayLongTuesday": "الثلاثاء", + "dayLongWednesday": "الأربعاء", + "dayLongThursday": "الخميس", + "dayLongFriday": "الجمعة", + "dayLongSaturday": "السبت", + "timeSuffix": "" + }, + "notes": { + "title": "لوحة الملاحظات", + "newNote": "ملاحظة جديدة", + "editNote": "تعديل الملاحظة", + "addNoteLabel": "ملاحظة جديدة", + "searchPlaceholder": "البحث في الملاحظات…", + "emptyTitle": "لا توجد ملاحظات بعد", + "emptyDescription": "أنشئ ملاحظة جديدة عبر زر +.", + "noResultsTitle": "لا توجد نتائج", + "noResultsDescription": "لا توجد ملاحظة تحتوي على \"{{query}}\".", + "titleLabel": "العنوان (اختياري)", + "titlePlaceholder": "بلا عنوان", + "contentLabel": "المحتوى", + "contentMarkdownHint": "(يدعم تنسيق Markdown)", + "contentPlaceholder": "أدخل ملاحظة…", + "colorLabel": "اللون", + "pinnedLabel": "تثبيت (يظهر على لوحة التحكم)", + "pinAction": "تثبيت", + "unpinAction": "إلغاء التثبيت", + "deleteLabel": "حذف الملاحظة", + "deleteConfirm": "هل تريد حذف الملاحظة؟", + "createdToast": "تم إنشاء الملاحظة", + "savedToast": "تم حفظ الملاحظة", + "deletedToast": "تم حذف الملاحظة", + "loadError": "فشل تحميل الملاحظات.", + "formatBold": "عريض (Ctrl+B)", + "formatItalic": "مائل (Ctrl+I)", + "formatUnderline": "تسطير (Ctrl+U)", + "formatStrikethrough": "يتوسطه خط", + "formatHeading": "عنوان", + "formatList": "قائمة", + "formatOrderedList": "قائمة مرقمة", + "formatChecklist": "قائمة مهام", + "formatLink": "رابط", + "formatCode": "كود", + "formatQuote": "اقتباس", + "formatDivider": "فاصل" + }, + "contacts": { + "title": "جهات الاتصال", + "newContact": "جهة اتصال جديدة", + "editContact": "تعديل جهة الاتصال", + "addButton": "جديد", + "newContactLabel": "جهة اتصال جديدة", + "searchPlaceholder": "البحث بالاسم أو الهاتف أو البريد الإلكتروني…", + "importButton": "استيراد", + "importLabel": "استيراد جهة اتصال من vCard", + "importTooltip": "استيراد vCard", + "emptyTitle": "لا توجد جهات اتصال بعد", + "emptyDescription": "أضف جهات اتصال جديدة عبر زر +.", + "filterAll": "الكل", + "nameLabel": "الاسم *", + "namePlaceholder": "الاسم الكامل", + "categoryLabel": "الفئة", + "phoneLabel": "الهاتف", + "phonePlaceholder": "+966 …", + "emailLabel": "البريد الإلكتروني", + "emailPlaceholder": "name@example.com", + "addressLabel": "العنوان", + "addressPlaceholder": "الشارع، المدينة", + "notesLabel": "ملاحظات", + "notesPlaceholder": "اختياري…", + "callLabel": "اتصال", + "emailActionLabel": "بريد إلكتروني", + "mapsLabel": "فتح في الخرائط", + "exportLabel": "تصدير كـ vCard", + "exportTooltip": "تصدير vCard", + "deleteLabel": "حذف جهة الاتصال", + "deleteConfirm": "هل تريد حذف جهة الاتصال؟", + "deletePersonConfirm": "هل تريد حذف \"{{name}}\"؟", + "savedToast": "تم حفظ جهة الاتصال", + "updatedToast": "تم تحديث جهة الاتصال", + "deletedToast": "تم حذف جهة الاتصال", + "importedToast": "تم استيراد {{name}}.", + "importError": "فشل الاستيراد: {{error}}", + "vcardNoName": "لا يحتوي vCard على اسم.", + "catDoctor": "طبيب", + "catSchool": "مدرسة/روضة", + "catAuthority": "جهة حكومية", + "catInsurance": "تأمين", + "catCraftsman": "حرفي", + "catEmergency": "طوارئ", + "catMisc": "متنوع", + "categoryDoctor": "طبيب", + "categorySchool": "مدرسة/روضة", + "categoryAuthority": "جهة حكومية", + "categoryInsurance": "تأمين", + "categoryCraftsman": "حرفي", + "categoryEmergency": "طوارئ", + "categoryOther": "متنوع" + }, + "budget": { + "title": "الميزانية", + "newEntry": "إدخال جديد", + "editEntry": "تعديل الإدخال", + "addEntryLabel": "إضافة إدخال", + "newEntryFabLabel": "إدخال جديد", + "currentMonth": "الشهر الحالي", + "prevMonth": "الشهر السابق", + "nextMonth": "الشهر التالي", + "income": "الدخل", + "expenses": "المصروفات", + "balance": "الرصيد", + "byCategory": "حسب الفئة", + "transactions": "المعاملات", + "emptyTitle": "لا توجد إدخالات هذا الشهر", + "emptyDescription": "أضف إدخالات الميزانية عبر زر +.", + "csvExport": "CSV", + "typeExpense": "مصروف", + "typeIncome": "دخل", + "titleLabel": "العنوان *", + "titlePlaceholder": "مثال: تسوق السوبرماركت", + "amountLabel": "المبلغ *", + "amountPlaceholder": "0.00", + "categoryLabel": "الفئة", + "dateLabel": "التاريخ *", + "recurringLabel": "متكرر", + "deleteLabel": "حذف الإدخال", + "deleteConfirm": "هل تريد حذف الإدخال؟", + "deletePersonConfirm": "هل تريد حذف \"{{title}}\"؟", + "addedToast": "تم إضافة الإدخال", + "savedToast": "تم حفظ الإدخال", + "deletedToast": "تم حذف الإدخال", + "loadError": "فشل تحميل الميزانية.", + "trendNeutral": "- مثل {{month}}", + "validAmountRequired": "أدخل مبلغاً صحيحاً", + "dateRequired": "التاريخ مطلوب", + "catFood": "الطعام", + "catRent": "الإيجار", + "catInsurance": "التأمين", + "catMobility": "التنقل", + "catLeisure": "الترفيه", + "catClothing": "الملابس", + "catHealth": "الصحة", + "catEducation": "التعليم", + "catMisc": "متنوع", + "loadingIndicator": "جارٍ التحميل…" + }, + "settings": { + "title": "الإعدادات", + "tabGeneral": "عام", + "tabMeals": "الوجبات", + "tabBudget": "الميزانية", + "tabShopping": "التسوق", + "tabCalendar": "التقويم", + "tabAccount": "الحساب", + "tabsAriaLabel": "أقسام الإعدادات", + "sectionDesign": "التصميم", + "sectionShopping": "التسوق", + "shoppingCategoriesLabel": "فئات التسوق", + "shoppingCategoriesHint": "إضافة الفئات أو إعادة تسميتها أو حذفها أو ترتيبها.", + "shoppingCategoryPlaceholder": "فئة جديدة…", + "shoppingCategoryRenameHint": "انقر لإعادة التسمية", + "shoppingCategoryRenamePrompt": "اسم الفئة الجديد:", + "shoppingCategoryMoveUp": "نقل الفئة للأعلى", + "shoppingCategoryMoveDown": "نقل الفئة للأسفل", + "shoppingCategoryDelete": "حذف الفئة", + "shoppingCategoryDeleteConfirm": "حذف الفئة \"{{name}}\"؟ سيتم تعيين العناصر الموجودة للفئة التالية.", + "shoppingCategoryAdded": "تم إضافة الفئة.", + "shoppingCategoryRenamed": "تم إعادة تسمية الفئة.", + "shoppingCategoryDeleted": "تم حذف الفئة.", + "sectionAccount": "حسابي", + "sectionCalendarSync": "مزامنة التقويم", + "sectionFamily": "أفراد العائلة", + "cardAppearance": "المظهر", + "themeSystem": "النظام", + "themeSysLabel": "استخدام إعداد النظام", + "themeLight": "فاتح", + "themeLightLabel": "المظهر الفاتح", + "themeDark": "داكن", + "themeDarkLabel": "المظهر الداكن", + "changePassword": "تغيير كلمة المرور", + "currentPasswordLabel": "كلمة المرور الحالية", + "newPasswordLabel": "كلمة المرور الجديدة", + "confirmPasswordLabel": "تأكيد كلمة المرور الجديدة", + "savePassword": "حفظ كلمة المرور", + "passwordMismatch": "كلمتا المرور غير متطابقتين.", + "passwordSavedToast": "تم تغيير كلمة المرور بنجاح.", + "googleCalendar": "تقويم Google", + "appleCalendar": "تقويم Apple (iCloud)", + "syncNow": "المزامنة الآن", + "disconnect": "قطع الاتصال", + "connectGoogle": "الاتصال بـ Google", + "connected": "متصل", + "connectedLastSync": "متصل · آخر مزامنة: {{date}}", + "notConnected": "غير متصل", + "notConfigured": "غير مهيأ (متغيرات .env مفقودة)", + "configured": "مهيأ (عبر .env)", + "configuredLastSync": "مهيأ (عبر .env) · آخر مزامنة: {{date}}", + "syncSuccess": "تمت مزامنة {{provider}}.", + "disconnectedToast": "تم قطع اتصال {{provider}}.", + "googleOnlyAdmin": "يمكن للمسؤول فقط الاتصال بتقويم Google.", + "appleOnlyAdmin": "يمكن للمسؤول فقط الاتصال بتقويم Apple.", + "caldavUrlLabel": "عنوان URL لخادم CalDAV", + "caldavUrlPlaceholder": "https://caldav.icloud.com", + "appleIdLabel": "Apple ID (البريد الإلكتروني)", + "applePasswordLabel": "كلمة مرور التطبيق", + "applePasswordHint": "أنشئ كلمة المرور في appleid.apple.com ← الأمان.", + "appleConnectBtn": "اتصال واختبار", + "appleConnecting": "جارٍ الاتصال…", + "appleConnectedToast": "تم الاتصال بتقويم Apple.", + "syncSuccessGoogle": "تمت مزامنة تقويم Google بنجاح.", + "syncSuccessApple": "تمت مزامنة تقويم Apple بنجاح.", + "syncErrorGoogle": "فشل الاتصال بـ Google. يرجى المحاولة مرة أخرى.", + "syncErrorApple": "فشل الاتصال بـ Apple. يرجى المحاولة مرة أخرى.", + "addMember": "+ إضافة عضو", + "newMemberTitle": "فرد عائلة جديد", + "usernameLabel": "اسم المستخدم", + "displayNameLabel": "الاسم المعروض", + "memberPasswordLabel": "كلمة المرور", + "colorLabel": "اللون", + "roleLabel": "الدور", + "roleMember": "عضو", + "roleAdmin": "مسؤول", + "createMember": "إنشاء", + "cancelAddMember": "إلغاء", + "memberAddedToast": "تم إضافة {{name}}.", + "deleteMemberConfirm": "هل تريد حذف {{name}}؟", + "memberDeletedToast": "تم حذف {{name}}.", + "deleteMemberLabel": "حذف", + "logout": "تسجيل الخروج", + "synchronizing": "جارٍ المزامنة…", + "googleDisconnectConfirm": "قطع اتصال تقويم Google؟", + "appleDisconnectConfirm": "قطع اتصال تقويم Apple؟", + "localeSystem": "النظام", + "localeLabel": "اللغة", + "languageTitle": "اللغة", + "sectionMeals": "خطة الوجبات", + "mealTypesLabel": "أنواع الوجبات المرئية", + "mealTypesHint": "تظهر في خطة الوجبات أنواع الوجبات المحددة فقط.", + "mealTypesSaved": "تم حفظ إعدادات خطة الوجبات.", + "mealTypesMinOne": "يجب أن يكون نوع وجبة واحد على الأقل نشطاً.", + "sectionBudget": "الميزانية", + "currencyLabel": "العملة", + "currencyHint": "تحدد العملة المستخدمة في منطقة الميزانية بأكملها.", + "currencySaved": "تم حفظ العملة." + }, + "login": { + "tagline": "تخطيط عائلي. آمن. يحترم الخصوصية. مفتوح المصدر.", + "usernameLabel": "اسم المستخدم", + "usernamePlaceholder": "اسم المستخدم", + "passwordLabel": "كلمة المرور", + "passwordPlaceholder": "••••••••", + "loginButton": "تسجيل الدخول", + "loggingIn": "جارٍ تسجيل الدخول…", + "tooManyAttempts": "محاولات كثيرة جداً. يرجى الانتظار قليلاً.", + "invalidCredentials": "بيانات اعتماد غير صالحة." + }, + "install": { + "title": "تثبيت Oikos", + "subtitle": "إضافة إلى التطبيقات", + "iosTip1": "اضغط على ", + "iosTip2": " ← \"إضافة إلى الشاشة الرئيسية\"", + "installButton": "تثبيت", + "dismissLabel": "إغلاق" + }, + "modal": { + "closeLabel": "إغلاق", + "overlayLabel": "خلفية مربع الحوار" + }, + "rrule": { + "freqNone": "بدون تكرار", + "freqDaily": "يومياً", + "freqWeekly": "أسبوعياً", + "freqMonthly": "شهرياً", + "dayMo": "إث", + "dayTu": "ثل", + "dayWe": "أر", + "dayTh": "خم", + "dayFr": "جم", + "daySa": "سب", + "daySu": "أح", + "labelRepeat": "التكرار", + "labelEvery": "كل", + "labelOnDays": "في هذه الأيام", + "labelUntil": "ينتهي في (اختياري)", + "unitDay": "يوم", + "unitDays": "أيام", + "unitWeek": "أسبوع", + "unitWeeks": "أسابيع", + "unitMonth": "شهر", + "unitMonths": "أشهر" + } +} diff --git a/public/locales/hi.json b/public/locales/hi.json new file mode 100644 index 0000000..860e6d3 --- /dev/null +++ b/public/locales/hi.json @@ -0,0 +1,599 @@ +{ + "common": { + "save": "सहेजें", + "cancel": "रद्द करें", + "delete": "हटाएं", + "edit": "संपादित करें", + "close": "बंद करें", + "create": "बनाएं", + "add": "जोड़ें", + "back": "वापस", + "next": "अगला", + "loading": "लोड हो रहा है…", + "saving": "सहेजा जा रहा है…", + "required": "यह फ़ील्ड आवश्यक है।", + "error": "त्रुटि", + "allFieldsRequired": "कृपया सभी फ़ील्ड भरें।", + "today": "आज", + "tomorrow": "कल", + "skipToContent": "सामग्री पर जाएं", + "reload": "फिर से लोड करें", + "errorOccurred": "कुछ गलत हो गया।", + "unexpectedError": "एक अप्रत्याशित त्रुटि हुई।", + "errorGeneric": "एक त्रुटि हुई।", + "updateAvailable": "अपडेट उपलब्ध है - नवीनतम संस्करण के लिए पृष्ठ पुनः लोड करें।", + "titleRequired": "शीर्षक आवश्यक है", + "nameRequired": "नाम आवश्यक है", + "contentRequired": "सामग्री आवश्यक है", + "all": "सभी", + "unknownError": "अज्ञात त्रुटि", + "confirm": "पुष्टि करें", + "undo": "पूर्ववत करें" + }, + "nav": { + "dashboard": "डैशबोर्ड", + "tasks": "कार्य", + "calendar": "कैलेंडर", + "meals": "भोजन", + "shopping": "खरीदारी", + "notes": "नोट्स", + "contacts": "संपर्क", + "budget": "बजट", + "settings": "सेटिंग्स", + "main": "मुख्य नेविगेशन", + "navigation": "नेविगेशन", + "quickActions": "त्वरित क्रियाएं" + }, + "dashboard": { + "title": "डैशबोर्ड", + "greetingMorning": "सुप्रभात, {{name}}", + "greetingDay": "नमस्ते, {{name}}", + "greetingEvening": "शुभ संध्या, {{name}}", + "allDone": "सब हो गया", + "noEvents": "कोई कार्यक्रम नहीं", + "noPinnedNotes": "कोई पिन किया हुआ नोट नहीं", + "todayMeals": "आज का भोजन", + "allLink": "सभी", + "weekLink": "इस सप्ताह", + "urgentTasksChip": "{{count}} अत्यावश्यक कार्य", + "urgentTasksChipPlural": "{{count}} अत्यावश्यक कार्य", + "eventsChip": "आज {{count}} कार्यक्रम", + "eventsChipPlural": "आज {{count}} कार्यक्रम", + "todayMealChip": "आज: {{title}}", + "loadError": "डैशबोर्ड लोड नहीं हो सका।", + "weatherRefresh": "मौसम अपडेट करें", + "weatherRefreshTitle": "अपडेट", + "weatherUpdated": "मौसम अपडेट हो गया", + "weatherFeelsLike": "महसूस होता है {{temp}}° · {{humidity}}% · हवा {{wind}} km/h", + "fabTaskLabel": "कार्य जोड़ें", + "fabCalendarLabel": "कार्यक्रम जोड़ें", + "fabShoppingLabel": "खरीदारी जोड़ें", + "fabNoteLabel": "नोट जोड़ें", + "fabTask": "कार्य", + "fabCalendar": "कार्यक्रम", + "fabShopping": "खरीदारी", + "fabNote": "नोट", + "overdue": "अतिदेय", + "dueSoon": "आज देय है", + "dueTomorrow": "कल देय है", + "allDay": "पूरे दिन", + "shoppingMore": "+{{count}} और", + "weather": "मौसम", + "customize": "अनुकूलित करें", + "customizeTitle": "विजेट अनुकूलित करें", + "customizeReset": "डिफ़ॉल्ट", + "customizeSaved": "डैशबोर्ड सहेजा गया", + "customizeMoveUp": "ऊपर ले जाएं", + "customizeMoveDown": "नीचे ले जाएं" + }, + "tasks": { + "title": "कार्य", + "newTask": "नया कार्य", + "editTask": "कार्य संपादित करें", + "emptyTitle": "कोई कार्य नहीं - सब हो गया?", + "emptyDescription": "+ बटन से नए कार्य बनाएं।", + "titleLabel": "शीर्षक *", + "titlePlaceholder": "क्या करना है?", + "descriptionLabel": "नोट", + "descriptionPlaceholder": "वैकल्पिक विवरण…", + "priorityLabel": "प्राथमिकता", + "categoryLabel": "श्रेणी", + "dueDateLabel": "नियत तारीख", + "dueTimeLabel": "समय", + "assignedLabel": "सौंपा गया", + "assignedNobody": "- कोई नहीं -", + "statusLabel": "स्थिति", + "priorityUrgent": "अत्यावश्यक", + "priorityHigh": "उच्च", + "priorityMedium": "मध्यम", + "priorityLow": "निम्न", + "priorityNone": "कोई नहीं", + "statusOpen": "खुला", + "statusInProgress": "प्रगति में", + "statusDone": "पूर्ण", + "categoryHousehold": "घर", + "categorySchool": "स्कूल", + "categoryShopping": "खरीदारी", + "categoryRepair": "मरम्मत", + "categoryHealth": "स्वास्थ्य", + "categoryFinance": "वित्त", + "categoryLeisure": "मनोरंजन", + "categoryMisc": "विविध", + "overdue": "अतिदेय", + "overdueDay": "{{count}} दिन अतिदेय", + "dueToday": "आज देय है", + "dueTomorrow": "कल देय है", + "groupOverdue": "अतिदेय", + "groupToday": "आज", + "groupThisWeek": "इस सप्ताह", + "groupNextWeek": "अगले सप्ताह", + "groupLater": "बाद में", + "groupNoDate": "कोई तारीख नहीं", + "markDone": "{{title}} को पूर्ण के रूप में चिह्नित करें", + "editButton": "कार्य संपादित करें", + "swipeOpen": "खोलें", + "swipeDone": "पूर्ण", + "swipeEdit": "संपादित करें", + "subtaskAdd": "+ उपकार्य जोड़ें", + "subtaskToggle": "उपकार्य दिखाएं", + "subtaskMarkDone": "{{title}} को पूर्ण के रूप में चिह्नित करें", + "deleteConfirm": "कार्य और सभी उपकार्य हटाएं?", + "savedToast": "कार्य सहेजा गया।", + "createdToast": "कार्य बनाया गया।", + "deletedToast": "कार्य हटाया गया।", + "loadError": "कार्य लोड नहीं हो सका।", + "subtaskPrompt": "उपकार्य:", + "kanbanOpen": "खुला", + "kanbanInProgress": "प्रगति में", + "kanbanDone": "पूर्ण", + "kanbanMoveToInProgress": "प्रगति में ले जाएं", + "kanbanMoveToDone": "पूर्ण के रूप में चिह्नित करें", + "kanbanMoveToOpen": "फिर से खोलें", + "recurring": "आवर्ती", + "listView": "सूची दृश्य", + "kanbanView": "कानबान दृश्य" + }, + "shopping": { + "title": "खरीदारी", + "noLists": "कोई सूची नहीं", + "noListsDescription": "+ बटन से सूची बनाएं।", + "emptyList": "सूची खाली है", + "emptyListDescription": "ऊपर के इनपुट से आइटम जोड़ें।", + "newListPrompt": "नई सूची का नाम:", + "newListButton": "नई सूची बनाएं", + "renameListPrompt": "नया सूची नाम:", + "deleteListConfirm": "सूची \"{{name}}\" और सभी आइटम हटाएं?", + "deletedListToast": "सूची हटा दी गई।", + "itemDeletedToast": "\"{{name}}\" हटाया गया।", + "itemsRemovedToast": "{{count}} आइटम हटाए गए।", + "clearChecked": "चेक किए हटाएं ({{count}})", + "itemNamePlaceholder": "आइटम जोड़ें…", + "itemQtyPlaceholder": "मात्रा", + "itemNameLabel": "आइटम नाम", + "itemQtyLabel": "मात्रा", + "categoryLabel": "श्रेणी", + "addItemLabel": "आइटम जोड़ें", + "renameListLabel": "सूची का नाम बदलें", + "deleteListLabel": "सूची हटाएं", + "swipeBack": "वापस", + "swipeCheck": "चेक करें", + "swipeDelete": "हटाएं", + "markDoneLabel": "{{name}} चेक करें", + "markUndoneLabel": "{{name}} अनचेक करें", + "deleteItemLabel": "{{name}} हटाएं", + "listsLoadError": "सूचियां लोड नहीं हो सकीं।", + "itemsLoadError": "आइटम लोड नहीं हो सके।", + "catFruitVeg": "फल और सब्जियां", + "catBakery": "बेकरी", + "catDairy": "डेयरी उत्पाद", + "catMeatFish": "मांस और मछली", + "catFrozen": "जमा हुआ खाना", + "catDrinks": "पेय", + "catHousehold": "घरेलू", + "catDrugstore": "दवाखाना", + "catMisc": "विविध" + }, + "meals": { + "title": "भोजन योजना", + "noMealPlanned": "कोई भोजन नियोजित नहीं", + "addMeal": "{{type}} जोड़ें", + "editMeal": "भोजन संपादित करें", + "addMealTitle": "भोजन जोड़ें", + "deleteMeal": "भोजन हटाएं", + "transferToShoppingList": "सामग्री खरीदारी सूची में भेजें", + "today": "आज", + "prevWeek": "पिछला सप्ताह", + "nextWeek": "अगला सप्ताह", + "loadError": "भोजन योजना लोड नहीं हो सकी।", + "typeBreakfast": "नाश्ता", + "typeLunch": "दोपहर का खाना", + "typeDinner": "रात का खाना", + "typeSnack": "नाश्ता", + "dayMo": "सो", + "dayDi": "मं", + "dayMi": "बु", + "dayDo": "गु", + "dayFr": "शु", + "daySa": "श", + "daySo": "र", + "dateLabel": "तारीख", + "mealTypeLabel": "भोजन प्रकार", + "titleLabel": "शीर्षक *", + "titlePlaceholder": "उदा.: दाल चावल", + "notesLabel": "नोट्स", + "notesPlaceholder": "वैकल्पिक…", + "ingredientsLabel": "सामग्री", + "addIngredient": "सामग्री जोड़ें", + "ingredientNamePlaceholder": "सामग्री", + "ingredientQtyPlaceholder": "मात्रा", + "removeIngredient": "सामग्री हटाएं", + "transferLabel": "सामग्री खरीदारी सूची में जोड़ें", + "transferNow": "अभी जोड़ें", + "noShoppingLists": "कोई खरीदारी सूची नहीं", + "transferSuccess": "{{count}} सामग्री जोड़ी गई", + "transferSuccessPlural": "{{count}} सामग्रियां जोड़ी गईं", + "transferAlreadyDone": "सभी सामग्रियां पहले से जोड़ी गई हैं", + "ingredientCount": "{{count}} सामग्री", + "ingredientCountPlural": "{{count}} सामग्रियां", + "titleRequired": "शीर्षक आवश्यक है", + "loadingIndicator": "लोड हो रहा है…", + "recipeUrlLabel": "रेसिपी लिंक (वैकल्पिक)", + "recipeUrlPlaceholder": "https://…", + "openRecipe": "रेसिपी खोलें" + }, + "calendar": { + "title": "कैलेंडर", + "newEvent": "नया कार्यक्रम", + "editEvent": "कार्यक्रम संपादित करें", + "addEvent": "कार्यक्रम जोड़ें", + "deleteEvent": "कार्यक्रम हटाएं", + "noEvents": "चुनी गई अवधि में कोई कार्यक्रम नहीं।", + "today": "आज", + "back": "वापस", + "forward": "आगे", + "viewMonth": "माह", + "viewWeek": "सप्ताह", + "viewDay": "दिन", + "viewAgenda": "एजेंडा", + "allDay": "पूरे दिन", + "allDayShort": "पूरा दिन", + "moreEvents": "+{{count}} और", + "weekNumberLabel": "सप्ताह {{week}} · {{month}} {{year}}", + "agendaFrom": "{{date}} से", + "titleLabel": "शीर्षक *", + "titlePlaceholder": "उदा.: डॉक्टर के पास", + "allDayToggle": "पूरे दिन", + "startDateLabel": "शुरुआती तारीख", + "startTimeLabel": "शुरुआती समय", + "endDateLabel": "अंतिम तारीख", + "endTimeLabel": "अंतिम समय", + "fromLabel": "से", + "toLabel": "तक", + "locationLabel": "स्थान", + "locationPlaceholder": "वैकल्पिक", + "assignedLabel": "सौंपा गया", + "assignedNobody": "- कोई नहीं -", + "colorLabel": "रंग {{color}}", + "descriptionLabel": "विवरण", + "descriptionPlaceholder": "वैकल्पिक…", + "popupEdit": "संपादित करें", + "deleteConfirm": "\"{{title}}\" हटाएं?", + "createdToast": "कार्यक्रम बनाया गया", + "savedToast": "कार्यक्रम सहेजा गया", + "deletedToast": "कार्यक्रम हटाया गया", + "loadError": "कार्यक्रम लोड नहीं हो सके।", + "saveError": "सहेजने में विफल", + "deleteError": "हटाने में विफल", + "titleRequired": "शीर्षक आवश्यक है", + "monthJanuary": "जनवरी", + "monthFebruary": "फरवरी", + "monthMarch": "मार्च", + "monthApril": "अप्रैल", + "monthMay": "मई", + "monthJune": "जून", + "monthJuly": "जुलाई", + "monthAugust": "अगस्त", + "monthSeptember": "सितंबर", + "monthOctober": "अक्टूबर", + "monthNovember": "नवंबर", + "monthDecember": "दिसंबर", + "dayShortSunday": "रवि", + "dayShortMonday": "सोम", + "dayShortTuesday": "मंगल", + "dayShortWednesday": "बुध", + "dayShortThursday": "गुरु", + "dayShortFriday": "शुक्र", + "dayShortSaturday": "शनि", + "dayLongSunday": "रविवार", + "dayLongMonday": "सोमवार", + "dayLongTuesday": "मंगलवार", + "dayLongWednesday": "बुधवार", + "dayLongThursday": "गुरुवार", + "dayLongFriday": "शुक्रवार", + "dayLongSaturday": "शनिवार", + "timeSuffix": "" + }, + "notes": { + "title": "नोट बोर्ड", + "newNote": "नया नोट", + "editNote": "नोट संपादित करें", + "addNoteLabel": "नया नोट", + "searchPlaceholder": "नोट खोजें…", + "emptyTitle": "अभी तक कोई नोट नहीं", + "emptyDescription": "+ बटन से नया नोट बनाएं।", + "noResultsTitle": "कोई परिणाम नहीं", + "noResultsDescription": "\"{{query}}\" वाला कोई नोट नहीं मिला।", + "titleLabel": "शीर्षक (वैकल्पिक)", + "titlePlaceholder": "कोई शीर्षक नहीं", + "contentLabel": "सामग्री", + "contentMarkdownHint": "(Markdown फ़ॉर्मेटिंग संभव)", + "contentPlaceholder": "नोट लिखें…", + "colorLabel": "रंग", + "pinnedLabel": "पिन करें (डैशबोर्ड पर दिखाई देगा)", + "pinAction": "पिन करें", + "unpinAction": "अनपिन करें", + "deleteLabel": "नोट हटाएं", + "deleteConfirm": "नोट हटाएं?", + "createdToast": "नोट बनाया गया", + "savedToast": "नोट सहेजा गया", + "deletedToast": "नोट हटाया गया", + "loadError": "नोट लोड नहीं हो सके।", + "formatBold": "बोल्ड (Ctrl+B)", + "formatItalic": "इटैलिक (Ctrl+I)", + "formatUnderline": "रेखांकित (Ctrl+U)", + "formatStrikethrough": "स्ट्राइकथ्रू", + "formatHeading": "शीर्षक", + "formatList": "सूची", + "formatOrderedList": "क्रमांकित सूची", + "formatChecklist": "चेकलिस्ट", + "formatLink": "लिंक", + "formatCode": "कोड", + "formatQuote": "उद्धरण", + "formatDivider": "विभाजक" + }, + "contacts": { + "title": "संपर्क", + "newContact": "नया संपर्क", + "editContact": "संपर्क संपादित करें", + "addButton": "नया", + "newContactLabel": "नया संपर्क", + "searchPlaceholder": "नाम, फ़ोन या ईमेल से खोजें…", + "importButton": "आयात", + "importLabel": "vCard से संपर्क आयात करें", + "importTooltip": "vCard आयात करें", + "emptyTitle": "अभी तक कोई संपर्क नहीं", + "emptyDescription": "+ बटन से नए संपर्क जोड़ें।", + "filterAll": "सभी", + "nameLabel": "नाम *", + "namePlaceholder": "पूरा नाम", + "categoryLabel": "श्रेणी", + "phoneLabel": "फ़ोन", + "phonePlaceholder": "+91 …", + "emailLabel": "ईमेल", + "emailPlaceholder": "name@example.com", + "addressLabel": "पता", + "addressPlaceholder": "सड़क, शहर", + "notesLabel": "नोट्स", + "notesPlaceholder": "वैकल्पिक…", + "callLabel": "कॉल करें", + "emailActionLabel": "ईमेल करें", + "mapsLabel": "मानचित्र में खोलें", + "exportLabel": "vCard के रूप में निर्यात करें", + "exportTooltip": "vCard निर्यात करें", + "deleteLabel": "संपर्क हटाएं", + "deleteConfirm": "संपर्क हटाएं?", + "deletePersonConfirm": "\"{{name}}\" हटाएं?", + "savedToast": "संपर्क सहेजा गया", + "updatedToast": "संपर्क अपडेट हुआ", + "deletedToast": "संपर्क हटाया गया", + "importedToast": "{{name}} आयात हुआ।", + "importError": "आयात विफल: {{error}}", + "vcardNoName": "vCard में कोई नाम नहीं।", + "catDoctor": "डॉक्टर", + "catSchool": "स्कूल/किंडरगार्टन", + "catAuthority": "सरकारी कार्यालय", + "catInsurance": "बीमा", + "catCraftsman": "कारीगर", + "catEmergency": "आपातकालीन", + "catMisc": "विविध", + "categoryDoctor": "डॉक्टर", + "categorySchool": "स्कूल/किंडरगार्टन", + "categoryAuthority": "सरकारी कार्यालय", + "categoryInsurance": "बीमा", + "categoryCraftsman": "कारीगर", + "categoryEmergency": "आपातकालीन", + "categoryOther": "विविध" + }, + "budget": { + "title": "बजट", + "newEntry": "नई प्रविष्टि", + "editEntry": "प्रविष्टि संपादित करें", + "addEntryLabel": "प्रविष्टि जोड़ें", + "newEntryFabLabel": "नई प्रविष्टि", + "currentMonth": "वर्तमान", + "prevMonth": "पिछला माह", + "nextMonth": "अगला माह", + "income": "आय", + "expenses": "व्यय", + "balance": "शेष", + "byCategory": "श्रेणी द्वारा", + "transactions": "लेनदेन", + "emptyTitle": "इस माह कोई प्रविष्टि नहीं", + "emptyDescription": "+ बटन से बजट प्रविष्टियां जोड़ें।", + "csvExport": "CSV", + "typeExpense": "व्यय", + "typeIncome": "आय", + "titleLabel": "शीर्षक *", + "titlePlaceholder": "उदा.: किराने की दुकान", + "amountLabel": "राशि *", + "amountPlaceholder": "0.00", + "categoryLabel": "श्रेणी", + "dateLabel": "तारीख *", + "recurringLabel": "आवर्ती", + "deleteLabel": "प्रविष्टि हटाएं", + "deleteConfirm": "प्रविष्टि हटाएं?", + "deletePersonConfirm": "\"{{title}}\" हटाएं?", + "addedToast": "प्रविष्टि जोड़ी गई", + "savedToast": "प्रविष्टि सहेजी गई", + "deletedToast": "प्रविष्टि हटाई गई", + "loadError": "बजट लोड नहीं हो सका।", + "trendNeutral": "- {{month}} जैसा", + "validAmountRequired": "वैध राशि दर्ज करें", + "dateRequired": "तारीख आवश्यक है", + "catFood": "भोजन", + "catRent": "किराया", + "catInsurance": "बीमा", + "catMobility": "परिवहन", + "catLeisure": "मनोरंजन", + "catClothing": "कपड़े", + "catHealth": "स्वास्थ्य", + "catEducation": "शिक्षा", + "catMisc": "विविध", + "loadingIndicator": "लोड हो रहा है…" + }, + "settings": { + "title": "सेटिंग्स", + "tabGeneral": "सामान्य", + "tabMeals": "भोजन", + "tabBudget": "बजट", + "tabShopping": "खरीदारी", + "tabCalendar": "कैलेंडर", + "tabAccount": "खाता", + "tabsAriaLabel": "सेटिंग्स अनुभाग", + "sectionDesign": "डिज़ाइन", + "sectionShopping": "खरीदारी", + "shoppingCategoriesLabel": "खरीदारी श्रेणियां", + "shoppingCategoriesHint": "श्रेणियां जोड़ें, नाम बदलें, हटाएं या क्रम बदलें।", + "shoppingCategoryPlaceholder": "नई श्रेणी…", + "shoppingCategoryRenameHint": "नाम बदलने के लिए क्लिक करें", + "shoppingCategoryRenamePrompt": "नई श्रेणी का नाम:", + "shoppingCategoryMoveUp": "श्रेणी ऊपर ले जाएं", + "shoppingCategoryMoveDown": "श्रेणी नीचे ले जाएं", + "shoppingCategoryDelete": "श्रेणी हटाएं", + "shoppingCategoryDeleteConfirm": "श्रेणी \"{{name}}\" हटाएं? मौजूदा आइटम अगली श्रेणी में जाएंगे।", + "shoppingCategoryAdded": "श्रेणी जोड़ी गई।", + "shoppingCategoryRenamed": "श्रेणी का नाम बदला गया।", + "shoppingCategoryDeleted": "श्रेणी हटाई गई।", + "sectionAccount": "मेरा खाता", + "sectionCalendarSync": "कैलेंडर सिंक", + "sectionFamily": "परिवार के सदस्य", + "cardAppearance": "दिखावट", + "themeSystem": "सिस्टम", + "themeSysLabel": "सिस्टम सेटिंग का उपयोग करें", + "themeLight": "हल्का", + "themeLightLabel": "हल्का थीम", + "themeDark": "गहरा", + "themeDarkLabel": "गहरा थीम", + "changePassword": "पासवर्ड बदलें", + "currentPasswordLabel": "वर्तमान पासवर्ड", + "newPasswordLabel": "नया पासवर्ड", + "confirmPasswordLabel": "नया पासवर्ड पुष्टि करें", + "savePassword": "पासवर्ड सहेजें", + "passwordMismatch": "पासवर्ड मेल नहीं खाते।", + "passwordSavedToast": "पासवर्ड सफलतापूर्वक बदला गया।", + "googleCalendar": "Google कैलेंडर", + "appleCalendar": "Apple कैलेंडर (iCloud)", + "syncNow": "अभी सिंक करें", + "disconnect": "कनेक्शन तोड़ें", + "connectGoogle": "Google से कनेक्ट करें", + "connected": "कनेक्ट है", + "connectedLastSync": "कनेक्ट है · अंतिम: {{date}}", + "notConnected": "कनेक्ट नहीं है", + "notConfigured": "कॉन्फ़िगर नहीं (.env चर गुम)", + "configured": "कॉन्फ़िगर किया गया (.env के माध्यम से)", + "configuredLastSync": "कॉन्फ़िगर किया गया (.env के माध्यम से) · अंतिम: {{date}}", + "syncSuccess": "{{provider}} सिंक हुआ।", + "disconnectedToast": "{{provider}} डिसकनेक्ट हुआ।", + "googleOnlyAdmin": "केवल एडमिन Google कैलेंडर कनेक्ट कर सकता है।", + "appleOnlyAdmin": "केवल एडमिन Apple कैलेंडर कनेक्ट कर सकता है।", + "caldavUrlLabel": "CalDAV सर्वर URL", + "caldavUrlPlaceholder": "https://caldav.icloud.com", + "appleIdLabel": "Apple ID (ईमेल)", + "applePasswordLabel": "ऐप-विशिष्ट पासवर्ड", + "applePasswordHint": "appleid.apple.com → सुरक्षा पर पासवर्ड बनाएं।", + "appleConnectBtn": "कनेक्ट और परीक्षण", + "appleConnecting": "कनेक्ट हो रहा है…", + "appleConnectedToast": "Apple कैलेंडर कनेक्ट हुआ।", + "syncSuccessGoogle": "Google कैलेंडर सिंक सफलतापूर्वक कनेक्ट हुआ।", + "syncSuccessApple": "Apple कैलेंडर सिंक सफलतापूर्वक कनेक्ट हुआ।", + "syncErrorGoogle": "Google से कनेक्ट विफल। कृपया पुनः प्रयास करें।", + "syncErrorApple": "Apple से कनेक्ट विफल। कृपया पुनः प्रयास करें।", + "addMember": "+ सदस्य जोड़ें", + "newMemberTitle": "नया परिवार सदस्य", + "usernameLabel": "उपयोगकर्ता नाम", + "displayNameLabel": "प्रदर्शन नाम", + "memberPasswordLabel": "पासवर्ड", + "colorLabel": "रंग", + "roleLabel": "भूमिका", + "roleMember": "सदस्य", + "roleAdmin": "एडमिन", + "createMember": "बनाएं", + "cancelAddMember": "रद्द करें", + "memberAddedToast": "{{name}} जोड़ा गया।", + "deleteMemberConfirm": "{{name}} हटाएं?", + "memberDeletedToast": "{{name}} हटाया गया।", + "deleteMemberLabel": "हटाएं", + "logout": "लॉग आउट", + "synchronizing": "सिंक हो रहा है…", + "googleDisconnectConfirm": "Google कैलेंडर कनेक्शन तोड़ें?", + "appleDisconnectConfirm": "Apple कैलेंडर कनेक्शन तोड़ें?", + "localeSystem": "सिस्टम", + "localeLabel": "भाषा", + "languageTitle": "भाषा", + "sectionMeals": "भोजन योजना", + "mealTypesLabel": "दृश्यमान भोजन प्रकार", + "mealTypesHint": "भोजन योजना में केवल चुने गए भोजन प्रकार दिखाई देंगे।", + "mealTypesSaved": "भोजन योजना सेटिंग्स सहेजी गईं।", + "mealTypesMinOne": "कम से कम एक भोजन प्रकार सक्रिय होना चाहिए।", + "sectionBudget": "बजट", + "currencyLabel": "मुद्रा", + "currencyHint": "पूरे बजट अनुभाग में उपयोग की जाने वाली मुद्रा सेट करता है।", + "currencySaved": "मुद्रा सहेजी गई।" + }, + "login": { + "tagline": "पारिवारिक योजना। सुरक्षित। गोपनीयता-अनुकूल। ओपन सोर्स।", + "usernameLabel": "उपयोगकर्ता नाम", + "usernamePlaceholder": "उपयोगकर्ता नाम", + "passwordLabel": "पासवर्ड", + "passwordPlaceholder": "••••••••", + "loginButton": "लॉग इन", + "loggingIn": "लॉग इन हो रहा है…", + "tooManyAttempts": "बहुत अधिक प्रयास। कृपया थोड़ा प्रतीक्षा करें।", + "invalidCredentials": "अमान्य क्रेडेंशियल।" + }, + "install": { + "title": "Oikos इंस्टॉल करें", + "subtitle": "ऐप में जोड़ें", + "iosTip1": " पर टैप करें", + "iosTip2": " → \"होम स्क्रीन में जोड़ें\"", + "installButton": "इंस्टॉल करें", + "dismissLabel": "बंद करें" + }, + "modal": { + "closeLabel": "बंद करें", + "overlayLabel": "मोडल डायलॉग पृष्ठभूमि" + }, + "rrule": { + "freqNone": "कोई दोहराव नहीं", + "freqDaily": "दैनिक", + "freqWeekly": "साप्ताहिक", + "freqMonthly": "मासिक", + "dayMo": "सो", + "dayTu": "मं", + "dayWe": "बु", + "dayTh": "गु", + "dayFr": "शु", + "daySa": "श", + "daySu": "र", + "labelRepeat": "दोहराव", + "labelEvery": "हर", + "labelOnDays": "इन दिनों", + "labelUntil": "समाप्त होता है (वैकल्पिक)", + "unitDay": "दिन", + "unitDays": "दिन", + "unitWeek": "सप्ताह", + "unitWeeks": "सप्ताह", + "unitMonth": "माह", + "unitMonths": "माह" + } +} diff --git a/public/locales/ja.json b/public/locales/ja.json new file mode 100644 index 0000000..f18defb --- /dev/null +++ b/public/locales/ja.json @@ -0,0 +1,599 @@ +{ + "common": { + "save": "保存", + "cancel": "キャンセル", + "delete": "削除", + "edit": "編集", + "close": "閉じる", + "create": "作成", + "add": "追加", + "back": "戻る", + "next": "次へ", + "loading": "読み込み中…", + "saving": "保存中…", + "required": "このフィールドは必須です。", + "error": "エラー", + "allFieldsRequired": "すべてのフィールドを入力してください。", + "today": "今日", + "tomorrow": "明日", + "skipToContent": "コンテンツへスキップ", + "reload": "再読み込み", + "errorOccurred": "問題が発生しました。", + "unexpectedError": "予期しないエラーが発生しました。", + "errorGeneric": "エラーが発生しました。", + "updateAvailable": "アップデートがあります - 最新版を使うためにページを再読み込みしてください。", + "titleRequired": "タイトルは必須です", + "nameRequired": "名前は必須です", + "contentRequired": "内容は必須です", + "all": "すべて", + "unknownError": "不明なエラー", + "confirm": "確認", + "undo": "元に戻す" + }, + "nav": { + "dashboard": "ダッシュボード", + "tasks": "タスク", + "calendar": "カレンダー", + "meals": "食事", + "shopping": "買い物", + "notes": "メモ", + "contacts": "連絡先", + "budget": "家計", + "settings": "設定", + "main": "メインナビゲーション", + "navigation": "ナビゲーション", + "quickActions": "クイックアクション" + }, + "dashboard": { + "title": "ダッシュボード", + "greetingMorning": "おはようございます、{{name}}", + "greetingDay": "こんにちは、{{name}}", + "greetingEvening": "こんばんは、{{name}}", + "allDone": "すべて完了", + "noEvents": "予定なし", + "noPinnedNotes": "固定メモなし", + "todayMeals": "今日の食事", + "allLink": "すべて", + "weekLink": "今週", + "urgentTasksChip": "緊急タスク {{count}} 件", + "urgentTasksChipPlural": "緊急タスク {{count}} 件", + "eventsChip": "今日の予定 {{count}} 件", + "eventsChipPlural": "今日の予定 {{count}} 件", + "todayMealChip": "今日:{{title}}", + "loadError": "ダッシュボードの読み込みに失敗しました。", + "weatherRefresh": "天気を更新", + "weatherRefreshTitle": "更新", + "weatherUpdated": "天気を更新しました", + "weatherFeelsLike": "体感 {{temp}}° · {{humidity}}% · 風速 {{wind}} km/h", + "fabTaskLabel": "タスクを追加", + "fabCalendarLabel": "予定を追加", + "fabShoppingLabel": "買い物を追加", + "fabNoteLabel": "メモを追加", + "fabTask": "タスク", + "fabCalendar": "予定", + "fabShopping": "買い物", + "fabNote": "メモ", + "overdue": "期限切れ", + "dueSoon": "今日が期限", + "dueTomorrow": "明日が期限", + "allDay": "終日", + "shoppingMore": "+{{count}} 件", + "weather": "天気", + "customize": "カスタマイズ", + "customizeTitle": "ウィジェットのカスタマイズ", + "customizeReset": "デフォルト", + "customizeSaved": "ダッシュボードを保存しました", + "customizeMoveUp": "上へ", + "customizeMoveDown": "下へ" + }, + "tasks": { + "title": "タスク", + "newTask": "新しいタスク", + "editTask": "タスクを編集", + "emptyTitle": "タスクなし - すべて完了?", + "emptyDescription": "+ ボタンで新しいタスクを作成できます。", + "titleLabel": "タイトル *", + "titlePlaceholder": "何をする必要がありますか?", + "descriptionLabel": "メモ", + "descriptionPlaceholder": "任意の詳細…", + "priorityLabel": "優先度", + "categoryLabel": "カテゴリー", + "dueDateLabel": "期限", + "dueTimeLabel": "時刻", + "assignedLabel": "担当者", + "assignedNobody": "- なし -", + "statusLabel": "ステータス", + "priorityUrgent": "緊急", + "priorityHigh": "高", + "priorityMedium": "中", + "priorityLow": "低", + "priorityNone": "なし", + "statusOpen": "未着手", + "statusInProgress": "進行中", + "statusDone": "完了", + "categoryHousehold": "家事", + "categorySchool": "学校", + "categoryShopping": "買い物", + "categoryRepair": "修理", + "categoryHealth": "健康", + "categoryFinance": "財務", + "categoryLeisure": "余暇", + "categoryMisc": "その他", + "overdue": "期限切れ", + "overdueDay": "{{count}} 日超過", + "dueToday": "今日が期限", + "dueTomorrow": "明日が期限", + "groupOverdue": "期限切れ", + "groupToday": "今日", + "groupThisWeek": "今週", + "groupNextWeek": "来週", + "groupLater": "後で", + "groupNoDate": "日付なし", + "markDone": "{{title}} を完了としてマーク", + "editButton": "タスクを編集", + "swipeOpen": "開く", + "swipeDone": "完了", + "swipeEdit": "編集", + "subtaskAdd": "+ サブタスクを追加", + "subtaskToggle": "サブタスクを表示", + "subtaskMarkDone": "{{title}} を完了としてマーク", + "deleteConfirm": "タスクとすべてのサブタスクを削除しますか?", + "savedToast": "タスクを保存しました。", + "createdToast": "タスクを作成しました。", + "deletedToast": "タスクを削除しました。", + "loadError": "タスクの読み込みに失敗しました。", + "subtaskPrompt": "サブタスク:", + "kanbanOpen": "未着手", + "kanbanInProgress": "進行中", + "kanbanDone": "完了", + "kanbanMoveToInProgress": "進行中に移動", + "kanbanMoveToDone": "完了としてマーク", + "kanbanMoveToOpen": "再度開く", + "recurring": "繰り返し", + "listView": "リスト表示", + "kanbanView": "かんばん表示" + }, + "shopping": { + "title": "買い物", + "noLists": "リストなし", + "noListsDescription": "+ ボタンでリストを作成できます。", + "emptyList": "リストは空です", + "emptyListDescription": "上の入力欄から商品を追加してください。", + "newListPrompt": "新しいリスト名:", + "newListButton": "新しいリストを作成", + "renameListPrompt": "新しいリスト名:", + "deleteListConfirm": "リスト「{{name}}」とすべての商品を削除しますか?", + "deletedListToast": "リストを削除しました。", + "itemDeletedToast": "「{{name}}」を削除しました。", + "itemsRemovedToast": "{{count}} 件の商品を削除しました。", + "clearChecked": "チェック済みを削除 ({{count}})", + "itemNamePlaceholder": "商品を追加…", + "itemQtyPlaceholder": "数量", + "itemNameLabel": "商品名", + "itemQtyLabel": "数量", + "categoryLabel": "カテゴリー", + "addItemLabel": "商品を追加", + "renameListLabel": "リストの名前を変更", + "deleteListLabel": "リストを削除", + "swipeBack": "戻る", + "swipeCheck": "チェック", + "swipeDelete": "削除", + "markDoneLabel": "{{name}} をチェック", + "markUndoneLabel": "{{name}} のチェックを外す", + "deleteItemLabel": "{{name}} を削除", + "listsLoadError": "リストの読み込みに失敗しました。", + "itemsLoadError": "商品の読み込みに失敗しました。", + "catFruitVeg": "野菜・果物", + "catBakery": "パン・焼き菓子", + "catDairy": "乳製品", + "catMeatFish": "肉・魚", + "catFrozen": "冷凍食品", + "catDrinks": "飲み物", + "catHousehold": "日用品", + "catDrugstore": "薬局", + "catMisc": "その他" + }, + "meals": { + "title": "食事計画", + "noMealPlanned": "食事の計画なし", + "addMeal": "{{type}} を追加", + "editMeal": "食事を編集", + "addMealTitle": "食事を追加", + "deleteMeal": "食事を削除", + "transferToShoppingList": "材料を買い物リストへ", + "today": "今日", + "prevWeek": "前の週", + "nextWeek": "次の週", + "loadError": "食事計画の読み込みに失敗しました。", + "typeBreakfast": "朝食", + "typeLunch": "昼食", + "typeDinner": "夕食", + "typeSnack": "間食", + "dayMo": "月", + "dayDi": "火", + "dayMi": "水", + "dayDo": "木", + "dayFr": "金", + "daySa": "土", + "daySo": "日", + "dateLabel": "日付", + "mealTypeLabel": "食事の種類", + "titleLabel": "タイトル *", + "titlePlaceholder": "例:カレーライス", + "notesLabel": "メモ", + "notesPlaceholder": "任意…", + "ingredientsLabel": "材料", + "addIngredient": "材料を追加", + "ingredientNamePlaceholder": "材料", + "ingredientQtyPlaceholder": "量", + "removeIngredient": "材料を削除", + "transferLabel": "材料を買い物リストに追加", + "transferNow": "今すぐ追加", + "noShoppingLists": "買い物リストがありません", + "transferSuccess": "{{count}} 種の材料を追加しました", + "transferSuccessPlural": "{{count}} 種の材料を追加しました", + "transferAlreadyDone": "すべての材料が追加済みです", + "ingredientCount": "材料 {{count}} 種", + "ingredientCountPlural": "材料 {{count}} 種", + "titleRequired": "タイトルは必須です", + "loadingIndicator": "読み込み中…", + "recipeUrlLabel": "レシピリンク(任意)", + "recipeUrlPlaceholder": "https://…", + "openRecipe": "レシピを開く" + }, + "calendar": { + "title": "カレンダー", + "newEvent": "新しい予定", + "editEvent": "予定を編集", + "addEvent": "予定を追加", + "deleteEvent": "予定を削除", + "noEvents": "選択した期間に予定はありません。", + "today": "今日", + "back": "戻る", + "forward": "次へ", + "viewMonth": "月", + "viewWeek": "週", + "viewDay": "日", + "viewAgenda": "一覧", + "allDay": "終日", + "allDayShort": "終日", + "moreEvents": "+{{count}} 件", + "weekNumberLabel": "第 {{week}} 週 · {{month}} {{year}}", + "agendaFrom": "{{date}} から", + "titleLabel": "タイトル *", + "titlePlaceholder": "例:歯医者", + "allDayToggle": "終日", + "startDateLabel": "開始日", + "startTimeLabel": "開始時刻", + "endDateLabel": "終了日", + "endTimeLabel": "終了時刻", + "fromLabel": "開始", + "toLabel": "終了", + "locationLabel": "場所", + "locationPlaceholder": "任意", + "assignedLabel": "担当者", + "assignedNobody": "- なし -", + "colorLabel": "色 {{color}}", + "descriptionLabel": "説明", + "descriptionPlaceholder": "任意…", + "popupEdit": "編集", + "deleteConfirm": "「{{title}}」を削除しますか?", + "createdToast": "予定を作成しました", + "savedToast": "予定を保存しました", + "deletedToast": "予定を削除しました", + "loadError": "予定の読み込みに失敗しました。", + "saveError": "保存に失敗しました", + "deleteError": "削除に失敗しました", + "titleRequired": "タイトルは必須です", + "monthJanuary": "1月", + "monthFebruary": "2月", + "monthMarch": "3月", + "monthApril": "4月", + "monthMay": "5月", + "monthJune": "6月", + "monthJuly": "7月", + "monthAugust": "8月", + "monthSeptember": "9月", + "monthOctober": "10月", + "monthNovember": "11月", + "monthDecember": "12月", + "dayShortSunday": "日", + "dayShortMonday": "月", + "dayShortTuesday": "火", + "dayShortWednesday": "水", + "dayShortThursday": "木", + "dayShortFriday": "金", + "dayShortSaturday": "土", + "dayLongSunday": "日曜日", + "dayLongMonday": "月曜日", + "dayLongTuesday": "火曜日", + "dayLongWednesday": "水曜日", + "dayLongThursday": "木曜日", + "dayLongFriday": "金曜日", + "dayLongSaturday": "土曜日", + "timeSuffix": "" + }, + "notes": { + "title": "メモボード", + "newNote": "新しいメモ", + "editNote": "メモを編集", + "addNoteLabel": "新しいメモ", + "searchPlaceholder": "メモを検索…", + "emptyTitle": "メモなし", + "emptyDescription": "+ ボタンで新しいメモを作成できます。", + "noResultsTitle": "結果なし", + "noResultsDescription": "「{{query}}」を含むメモはありません。", + "titleLabel": "タイトル(任意)", + "titlePlaceholder": "タイトルなし", + "contentLabel": "内容", + "contentMarkdownHint": "(Markdown 形式対応)", + "contentPlaceholder": "メモを入力…", + "colorLabel": "色", + "pinnedLabel": "固定(ダッシュボードに表示)", + "pinAction": "固定", + "unpinAction": "固定を解除", + "deleteLabel": "メモを削除", + "deleteConfirm": "メモを削除しますか?", + "createdToast": "メモを作成しました", + "savedToast": "メモを保存しました", + "deletedToast": "メモを削除しました", + "loadError": "メモの読み込みに失敗しました。", + "formatBold": "太字 (Ctrl+B)", + "formatItalic": "斜体 (Ctrl+I)", + "formatUnderline": "下線 (Ctrl+U)", + "formatStrikethrough": "取り消し線", + "formatHeading": "見出し", + "formatList": "リスト", + "formatOrderedList": "番号付きリスト", + "formatChecklist": "チェックリスト", + "formatLink": "リンク", + "formatCode": "コード", + "formatQuote": "引用", + "formatDivider": "区切り線" + }, + "contacts": { + "title": "連絡先", + "newContact": "新しい連絡先", + "editContact": "連絡先を編集", + "addButton": "新規", + "newContactLabel": "新しい連絡先", + "searchPlaceholder": "名前、電話番号またはメールで検索…", + "importButton": "インポート", + "importLabel": "vCard から連絡先をインポート", + "importTooltip": "vCard をインポート", + "emptyTitle": "連絡先なし", + "emptyDescription": "+ ボタンで新しい連絡先を追加できます。", + "filterAll": "すべて", + "nameLabel": "名前 *", + "namePlaceholder": "フルネーム", + "categoryLabel": "カテゴリー", + "phoneLabel": "電話番号", + "phonePlaceholder": "+81 …", + "emailLabel": "メール", + "emailPlaceholder": "name@example.com", + "addressLabel": "住所", + "addressPlaceholder": "町名、都市", + "notesLabel": "メモ", + "notesPlaceholder": "任意…", + "callLabel": "電話をかける", + "emailActionLabel": "メールを送る", + "mapsLabel": "地図で開く", + "exportLabel": "vCard としてエクスポート", + "exportTooltip": "vCard をエクスポート", + "deleteLabel": "連絡先を削除", + "deleteConfirm": "連絡先を削除しますか?", + "deletePersonConfirm": "「{{name}}」を削除しますか?", + "savedToast": "連絡先を保存しました", + "updatedToast": "連絡先を更新しました", + "deletedToast": "連絡先を削除しました", + "importedToast": "{{name}} をインポートしました。", + "importError": "インポートに失敗しました:{{error}}", + "vcardNoName": "vCard に名前が含まれていません。", + "catDoctor": "医師", + "catSchool": "学校・保育園", + "catAuthority": "官公庁", + "catInsurance": "保険", + "catCraftsman": "職人", + "catEmergency": "緊急連絡先", + "catMisc": "その他", + "categoryDoctor": "医師", + "categorySchool": "学校・保育園", + "categoryAuthority": "官公庁", + "categoryInsurance": "保険", + "categoryCraftsman": "職人", + "categoryEmergency": "緊急連絡先", + "categoryOther": "その他" + }, + "budget": { + "title": "家計", + "newEntry": "新しい項目", + "editEntry": "項目を編集", + "addEntryLabel": "項目を追加", + "newEntryFabLabel": "新しい項目", + "currentMonth": "今月", + "prevMonth": "先月", + "nextMonth": "来月", + "income": "収入", + "expenses": "支出", + "balance": "残高", + "byCategory": "カテゴリー別", + "transactions": "取引", + "emptyTitle": "今月の項目なし", + "emptyDescription": "+ ボタンで家計項目を追加できます。", + "csvExport": "CSV", + "typeExpense": "支出", + "typeIncome": "収入", + "titleLabel": "タイトル *", + "titlePlaceholder": "例:スーパーでの買い物", + "amountLabel": "金額 *", + "amountPlaceholder": "0", + "categoryLabel": "カテゴリー", + "dateLabel": "日付 *", + "recurringLabel": "繰り返し", + "deleteLabel": "項目を削除", + "deleteConfirm": "項目を削除しますか?", + "deletePersonConfirm": "「{{title}}」を削除しますか?", + "addedToast": "項目を追加しました", + "savedToast": "項目を保存しました", + "deletedToast": "項目を削除しました", + "loadError": "家計の読み込みに失敗しました。", + "trendNeutral": "- {{month}} と同じ", + "validAmountRequired": "有効な金額を入力してください", + "dateRequired": "日付は必須です", + "catFood": "食費", + "catRent": "家賃", + "catInsurance": "保険", + "catMobility": "交通費", + "catLeisure": "娯楽", + "catClothing": "衣服", + "catHealth": "医療", + "catEducation": "教育", + "catMisc": "その他", + "loadingIndicator": "読み込み中…" + }, + "settings": { + "title": "設定", + "tabGeneral": "一般", + "tabMeals": "食事", + "tabBudget": "家計", + "tabShopping": "買い物", + "tabCalendar": "カレンダー", + "tabAccount": "アカウント", + "tabsAriaLabel": "設定カテゴリー", + "sectionDesign": "デザイン", + "sectionShopping": "買い物", + "shoppingCategoriesLabel": "買い物カテゴリー", + "shoppingCategoriesHint": "カテゴリーの追加、名前変更、削除、並び替えができます。", + "shoppingCategoryPlaceholder": "新しいカテゴリー…", + "shoppingCategoryRenameHint": "クリックして名前を変更", + "shoppingCategoryRenamePrompt": "新しいカテゴリー名:", + "shoppingCategoryMoveUp": "カテゴリーを上へ", + "shoppingCategoryMoveDown": "カテゴリーを下へ", + "shoppingCategoryDelete": "カテゴリーを削除", + "shoppingCategoryDeleteConfirm": "カテゴリー「{{name}}」を削除しますか?既存の商品は次のカテゴリーに移動されます。", + "shoppingCategoryAdded": "カテゴリーを追加しました。", + "shoppingCategoryRenamed": "カテゴリー名を変更しました。", + "shoppingCategoryDeleted": "カテゴリーを削除しました。", + "sectionAccount": "マイアカウント", + "sectionCalendarSync": "カレンダー同期", + "sectionFamily": "家族メンバー", + "cardAppearance": "外観", + "themeSystem": "システム設定", + "themeSysLabel": "システム設定を使用", + "themeLight": "ライト", + "themeLightLabel": "ライトテーマ", + "themeDark": "ダーク", + "themeDarkLabel": "ダークテーマ", + "changePassword": "パスワードを変更", + "currentPasswordLabel": "現在のパスワード", + "newPasswordLabel": "新しいパスワード", + "confirmPasswordLabel": "新しいパスワードを確認", + "savePassword": "パスワードを保存", + "passwordMismatch": "パスワードが一致しません。", + "passwordSavedToast": "パスワードを変更しました。", + "googleCalendar": "Google カレンダー", + "appleCalendar": "Apple カレンダー (iCloud)", + "syncNow": "今すぐ同期", + "disconnect": "接続を切断", + "connectGoogle": "Google に接続", + "connected": "接続済み", + "connectedLastSync": "接続済み · 最終同期:{{date}}", + "notConnected": "未接続", + "notConfigured": "未設定(.env 変数が不足しています)", + "configured": "設定済み(.env 経由)", + "configuredLastSync": "設定済み(.env 経由) · 最終同期:{{date}}", + "syncSuccess": "{{provider}} を同期しました。", + "disconnectedToast": "{{provider}} を切断しました。", + "googleOnlyAdmin": "Google カレンダーに接続できるのは管理者のみです。", + "appleOnlyAdmin": "Apple カレンダーに接続できるのは管理者のみです。", + "caldavUrlLabel": "CalDAV サーバー URL", + "caldavUrlPlaceholder": "https://caldav.icloud.com", + "appleIdLabel": "Apple ID(メール)", + "applePasswordLabel": "アプリ専用パスワード", + "applePasswordHint": "appleid.apple.com → セキュリティ でパスワードを作成してください。", + "appleConnectBtn": "接続してテスト", + "appleConnecting": "接続中…", + "appleConnectedToast": "Apple カレンダーを接続しました。", + "syncSuccessGoogle": "Google カレンダーの同期接続に成功しました。", + "syncSuccessApple": "Apple カレンダーの同期接続に成功しました。", + "syncErrorGoogle": "Google への接続に失敗しました。もう一度お試しください。", + "syncErrorApple": "Apple への接続に失敗しました。もう一度お試しください。", + "addMember": "+ メンバーを追加", + "newMemberTitle": "新しい家族メンバー", + "usernameLabel": "ユーザー名", + "displayNameLabel": "表示名", + "memberPasswordLabel": "パスワード", + "colorLabel": "色", + "roleLabel": "役割", + "roleMember": "メンバー", + "roleAdmin": "管理者", + "createMember": "作成", + "cancelAddMember": "キャンセル", + "memberAddedToast": "{{name}} を追加しました。", + "deleteMemberConfirm": "{{name}} を削除しますか?", + "memberDeletedToast": "{{name}} を削除しました。", + "deleteMemberLabel": "削除", + "logout": "ログアウト", + "synchronizing": "同期中…", + "googleDisconnectConfirm": "Google カレンダーの接続を切断しますか?", + "appleDisconnectConfirm": "Apple カレンダーの接続を切断しますか?", + "localeSystem": "システム設定", + "localeLabel": "言語", + "languageTitle": "言語", + "sectionMeals": "食事計画", + "mealTypesLabel": "表示する食事の種類", + "mealTypesHint": "選択した食事の種類のみ食事計画に表示されます。", + "mealTypesSaved": "食事計画の設定を保存しました。", + "mealTypesMinOne": "少なくとも1つの食事の種類を有効にしてください。", + "sectionBudget": "家計", + "currencyLabel": "通貨", + "currencyHint": "家計全体で使用する通貨を設定します。", + "currencySaved": "通貨を保存しました。" + }, + "login": { + "tagline": "家族計画。安全。プライバシー重視。オープンソース。", + "usernameLabel": "ユーザー名", + "usernamePlaceholder": "ユーザー名", + "passwordLabel": "パスワード", + "passwordPlaceholder": "••••••••", + "loginButton": "ログイン", + "loggingIn": "ログイン中…", + "tooManyAttempts": "試行回数が多すぎます。しばらくお待ちください。", + "invalidCredentials": "ユーザー名またはパスワードが正しくありません。" + }, + "install": { + "title": "Oikos をインストール", + "subtitle": "アプリに追加", + "iosTip1": " をタップ", + "iosTip2": " → 「ホーム画面に追加」", + "installButton": "インストール", + "dismissLabel": "閉じる" + }, + "modal": { + "closeLabel": "閉じる", + "overlayLabel": "モーダルダイアログの背景" + }, + "rrule": { + "freqNone": "繰り返しなし", + "freqDaily": "毎日", + "freqWeekly": "毎週", + "freqMonthly": "毎月", + "dayMo": "月", + "dayTu": "火", + "dayWe": "水", + "dayTh": "木", + "dayFr": "金", + "daySa": "土", + "daySu": "日", + "labelRepeat": "繰り返し", + "labelEvery": "毎", + "labelOnDays": "曜日", + "labelUntil": "終了日(任意)", + "unitDay": "日", + "unitDays": "日", + "unitWeek": "週", + "unitWeeks": "週", + "unitMonth": "ヶ月", + "unitMonths": "ヶ月" + } +} diff --git a/public/locales/pt.json b/public/locales/pt.json new file mode 100644 index 0000000..449c5df --- /dev/null +++ b/public/locales/pt.json @@ -0,0 +1,599 @@ +{ + "common": { + "save": "Salvar", + "cancel": "Cancelar", + "delete": "Excluir", + "edit": "Editar", + "close": "Fechar", + "create": "Criar", + "add": "Adicionar", + "back": "Voltar", + "next": "Próximo", + "loading": "Carregando…", + "saving": "Salvando…", + "required": "Este campo é obrigatório.", + "error": "Erro", + "allFieldsRequired": "Por favor, preencha todos os campos.", + "today": "Hoje", + "tomorrow": "Amanhã", + "skipToContent": "Pular para o conteúdo", + "reload": "Recarregar", + "errorOccurred": "Algo deu errado.", + "unexpectedError": "Ocorreu um erro inesperado.", + "errorGeneric": "Ocorreu um erro.", + "updateAvailable": "Atualização disponível - recarregue a página para obter a versão mais recente.", + "titleRequired": "Título é obrigatório", + "nameRequired": "Nome é obrigatório", + "contentRequired": "Conteúdo é obrigatório", + "all": "Todos", + "unknownError": "Erro desconhecido", + "confirm": "Confirmar", + "undo": "Desfazer" + }, + "nav": { + "dashboard": "Painel", + "tasks": "Tarefas", + "calendar": "Calendário", + "meals": "Refeições", + "shopping": "Compras", + "notes": "Notas", + "contacts": "Contatos", + "budget": "Orçamento", + "settings": "Configurações", + "main": "Navegação principal", + "navigation": "Navegação", + "quickActions": "Ações rápidas" + }, + "dashboard": { + "title": "Painel", + "greetingMorning": "Bom dia, {{name}}", + "greetingDay": "Boa tarde, {{name}}", + "greetingEvening": "Boa noite, {{name}}", + "allDone": "Tudo concluído", + "noEvents": "Nenhum evento", + "noPinnedNotes": "Nenhuma nota fixada", + "todayMeals": "Refeições de hoje", + "allLink": "Todos", + "weekLink": "Semana", + "urgentTasksChip": "{{count}} tarefa urgente", + "urgentTasksChipPlural": "{{count}} tarefas urgentes", + "eventsChip": "{{count}} evento hoje", + "eventsChipPlural": "{{count}} eventos hoje", + "todayMealChip": "Hoje: {{title}}", + "loadError": "Falha ao carregar o painel.", + "weatherRefresh": "Atualizar clima", + "weatherRefreshTitle": "Atualizar", + "weatherUpdated": "Clima atualizado", + "weatherFeelsLike": "Sensação {{temp}}° · {{humidity}}% · Vento {{wind}} km/h", + "fabTaskLabel": "Adicionar tarefa", + "fabCalendarLabel": "Adicionar evento", + "fabShoppingLabel": "Adicionar compra", + "fabNoteLabel": "Adicionar nota", + "fabTask": "Tarefa", + "fabCalendar": "Evento", + "fabShopping": "Compras", + "fabNote": "Nota", + "overdue": "Atrasado", + "dueSoon": "Vence hoje", + "dueTomorrow": "Vence amanhã", + "allDay": "Dia inteiro", + "shoppingMore": "+{{count}} mais", + "weather": "Clima", + "customize": "Personalizar", + "customizeTitle": "Personalizar widgets", + "customizeReset": "Padrão", + "customizeSaved": "Painel salvo", + "customizeMoveUp": "Mover para cima", + "customizeMoveDown": "Mover para baixo" + }, + "tasks": { + "title": "Tarefas", + "newTask": "Nova tarefa", + "editTask": "Editar tarefa", + "emptyTitle": "Nenhuma tarefa - tudo concluído?", + "emptyDescription": "Crie novas tarefas com o botão +.", + "titleLabel": "Título *", + "titlePlaceholder": "O que precisa ser feito?", + "descriptionLabel": "Nota", + "descriptionPlaceholder": "Detalhes opcionais…", + "priorityLabel": "Prioridade", + "categoryLabel": "Categoria", + "dueDateLabel": "Vencimento", + "dueTimeLabel": "Horário", + "assignedLabel": "Atribuído a", + "assignedNobody": "- Ninguém -", + "statusLabel": "Status", + "priorityUrgent": "Urgente", + "priorityHigh": "Alta", + "priorityMedium": "Média", + "priorityLow": "Baixa", + "priorityNone": "Nenhuma", + "statusOpen": "Aberto", + "statusInProgress": "Em andamento", + "statusDone": "Concluído", + "categoryHousehold": "Casa", + "categorySchool": "Escola", + "categoryShopping": "Compras", + "categoryRepair": "Reparo", + "categoryHealth": "Saúde", + "categoryFinance": "Finanças", + "categoryLeisure": "Lazer", + "categoryMisc": "Outros", + "overdue": "Atrasado", + "overdueDay": "{{count}}d atrasado", + "dueToday": "Vence hoje", + "dueTomorrow": "Vence amanhã", + "groupOverdue": "Atrasado", + "groupToday": "Hoje", + "groupThisWeek": "Esta semana", + "groupNextWeek": "Próxima semana", + "groupLater": "Depois", + "groupNoDate": "Sem data", + "markDone": "Marcar {{title}} como concluído", + "editButton": "Editar tarefa", + "swipeOpen": "Abrir", + "swipeDone": "Concluído", + "swipeEdit": "Editar", + "subtaskAdd": "+ Adicionar subtarefa", + "subtaskToggle": "Mostrar subtarefas", + "subtaskMarkDone": "Marcar {{title}} como concluído", + "deleteConfirm": "Excluir tarefa e todas as subtarefas?", + "savedToast": "Tarefa salva.", + "createdToast": "Tarefa criada.", + "deletedToast": "Tarefa excluída.", + "loadError": "Falha ao carregar a tarefa.", + "subtaskPrompt": "Subtarefa:", + "kanbanOpen": "Aberto", + "kanbanInProgress": "Em andamento", + "kanbanDone": "Concluído", + "kanbanMoveToInProgress": "Mover para em andamento", + "kanbanMoveToDone": "Marcar como concluído", + "kanbanMoveToOpen": "Reabrir", + "recurring": "Recorrente", + "listView": "Visualização em lista", + "kanbanView": "Visualização Kanban" + }, + "shopping": { + "title": "Compras", + "noLists": "Nenhuma lista", + "noListsDescription": "Crie uma lista com o botão +.", + "emptyList": "A lista está vazia", + "emptyListDescription": "Adicione itens pelo campo de entrada acima.", + "newListPrompt": "Nome da nova lista:", + "newListButton": "Criar nova lista", + "renameListPrompt": "Novo nome da lista:", + "deleteListConfirm": "Excluir a lista \"{{name}}\" e todos os itens?", + "deletedListToast": "Lista excluída.", + "itemDeletedToast": "\"{{name}}\" removido.", + "itemsRemovedToast": "{{count}} itens removidos.", + "clearChecked": "Excluir marcados ({{count}})", + "itemNamePlaceholder": "Adicionar item…", + "itemQtyPlaceholder": "Qtd", + "itemNameLabel": "Nome do item", + "itemQtyLabel": "Quantidade", + "categoryLabel": "Categoria", + "addItemLabel": "Adicionar item", + "renameListLabel": "Renomear lista", + "deleteListLabel": "Excluir lista", + "swipeBack": "Voltar", + "swipeCheck": "Marcar", + "swipeDelete": "Excluir", + "markDoneLabel": "Marcar {{name}}", + "markUndoneLabel": "Desmarcar {{name}}", + "deleteItemLabel": "Excluir {{name}}", + "listsLoadError": "Falha ao carregar listas.", + "itemsLoadError": "Falha ao carregar itens.", + "catFruitVeg": "Frutas e Legumes", + "catBakery": "Padaria", + "catDairy": "Laticínios", + "catMeatFish": "Carnes e Peixes", + "catFrozen": "Congelados", + "catDrinks": "Bebidas", + "catHousehold": "Casa", + "catDrugstore": "Farmácia", + "catMisc": "Outros" + }, + "meals": { + "title": "Plano de refeições", + "noMealPlanned": "Nenhuma refeição planejada", + "addMeal": "Adicionar {{type}}", + "editMeal": "Editar refeição", + "addMealTitle": "Adicionar refeição", + "deleteMeal": "Excluir refeição", + "transferToShoppingList": "Ingredientes para lista de compras", + "today": "Hoje", + "prevWeek": "Semana anterior", + "nextWeek": "Próxima semana", + "loadError": "Falha ao carregar o plano de refeições.", + "typeBreakfast": "Café da manhã", + "typeLunch": "Almoço", + "typeDinner": "Jantar", + "typeSnack": "Lanche", + "dayMo": "Seg", + "dayDi": "Ter", + "dayMi": "Qua", + "dayDo": "Qui", + "dayFr": "Sex", + "daySa": "Sáb", + "daySo": "Dom", + "dateLabel": "Data", + "mealTypeLabel": "Tipo de refeição", + "titleLabel": "Título *", + "titlePlaceholder": "Ex.: Feijoada", + "notesLabel": "Notas", + "notesPlaceholder": "Opcional…", + "ingredientsLabel": "Ingredientes", + "addIngredient": "Adicionar ingrediente", + "ingredientNamePlaceholder": "Ingrediente", + "ingredientQtyPlaceholder": "Qtd", + "removeIngredient": "Remover ingrediente", + "transferLabel": "Transferir ingredientes para lista de compras", + "transferNow": "Transferir agora", + "noShoppingLists": "Nenhuma lista de compras disponível", + "transferSuccess": "{{count}} ingrediente transferido", + "transferSuccessPlural": "{{count}} ingredientes transferidos", + "transferAlreadyDone": "Todos os ingredientes já foram transferidos", + "ingredientCount": "{{count}} ingrediente", + "ingredientCountPlural": "{{count}} ingredientes", + "titleRequired": "Título é obrigatório", + "loadingIndicator": "Carregando…", + "recipeUrlLabel": "Link da receita (opcional)", + "recipeUrlPlaceholder": "https://…", + "openRecipe": "Abrir receita" + }, + "calendar": { + "title": "Calendário", + "newEvent": "Novo evento", + "editEvent": "Editar evento", + "addEvent": "Adicionar evento", + "deleteEvent": "Excluir evento", + "noEvents": "Nenhum evento no período selecionado.", + "today": "Hoje", + "back": "Voltar", + "forward": "Avançar", + "viewMonth": "Mês", + "viewWeek": "Semana", + "viewDay": "Dia", + "viewAgenda": "Agenda", + "allDay": "Dia inteiro", + "allDayShort": "dia int.", + "moreEvents": "+{{count}} mais", + "weekNumberLabel": "Sem {{week}} · {{month}} {{year}}", + "agendaFrom": "A partir de {{date}}", + "titleLabel": "Título *", + "titlePlaceholder": "Ex.: Dentista", + "allDayToggle": "Dia inteiro", + "startDateLabel": "Data de início", + "startTimeLabel": "Horário de início", + "endDateLabel": "Data de término", + "endTimeLabel": "Horário de término", + "fromLabel": "De", + "toLabel": "Até", + "locationLabel": "Local", + "locationPlaceholder": "Opcional", + "assignedLabel": "Atribuído a", + "assignedNobody": "- Ninguém -", + "colorLabel": "Cor {{color}}", + "descriptionLabel": "Descrição", + "descriptionPlaceholder": "Opcional…", + "popupEdit": "Editar", + "deleteConfirm": "Excluir \"{{title}}\"?", + "createdToast": "Evento criado", + "savedToast": "Evento salvo", + "deletedToast": "Evento excluído", + "loadError": "Falha ao carregar eventos.", + "saveError": "Erro ao salvar", + "deleteError": "Erro ao excluir", + "titleRequired": "Título é obrigatório", + "monthJanuary": "Janeiro", + "monthFebruary": "Fevereiro", + "monthMarch": "Março", + "monthApril": "Abril", + "monthMay": "Maio", + "monthJune": "Junho", + "monthJuly": "Julho", + "monthAugust": "Agosto", + "monthSeptember": "Setembro", + "monthOctober": "Outubro", + "monthNovember": "Novembro", + "monthDecember": "Dezembro", + "dayShortSunday": "Dom", + "dayShortMonday": "Seg", + "dayShortTuesday": "Ter", + "dayShortWednesday": "Qua", + "dayShortThursday": "Qui", + "dayShortFriday": "Sex", + "dayShortSaturday": "Sáb", + "dayLongSunday": "Domingo", + "dayLongMonday": "Segunda-feira", + "dayLongTuesday": "Terça-feira", + "dayLongWednesday": "Quarta-feira", + "dayLongThursday": "Quinta-feira", + "dayLongFriday": "Sexta-feira", + "dayLongSaturday": "Sábado", + "timeSuffix": "" + }, + "notes": { + "title": "Quadro de notas", + "newNote": "Nova nota", + "editNote": "Editar nota", + "addNoteLabel": "Nova nota", + "searchPlaceholder": "Pesquisar notas…", + "emptyTitle": "Nenhuma nota ainda", + "emptyDescription": "Crie uma nova nota com o botão +.", + "noResultsTitle": "Nenhum resultado", + "noResultsDescription": "Nenhuma nota contém \"{{query}}\".", + "titleLabel": "Título (opcional)", + "titlePlaceholder": "Sem título", + "contentLabel": "Conteúdo", + "contentMarkdownHint": "(Formatação Markdown disponível)", + "contentPlaceholder": "Escreva uma nota…", + "colorLabel": "Cor", + "pinnedLabel": "Fixar (aparece no painel)", + "pinAction": "Fixar", + "unpinAction": "Desafixar", + "deleteLabel": "Excluir nota", + "deleteConfirm": "Excluir nota?", + "createdToast": "Nota criada", + "savedToast": "Nota salva", + "deletedToast": "Nota excluída", + "loadError": "Falha ao carregar notas.", + "formatBold": "Negrito (Ctrl+B)", + "formatItalic": "Itálico (Ctrl+I)", + "formatUnderline": "Sublinhado (Ctrl+U)", + "formatStrikethrough": "Tachado", + "formatHeading": "Título", + "formatList": "Lista", + "formatOrderedList": "Lista numerada", + "formatChecklist": "Lista de verificação", + "formatLink": "Link", + "formatCode": "Código", + "formatQuote": "Citação", + "formatDivider": "Divisor" + }, + "contacts": { + "title": "Contatos", + "newContact": "Novo contato", + "editContact": "Editar contato", + "addButton": "Novo", + "newContactLabel": "Novo contato", + "searchPlaceholder": "Pesquisar por nome, telefone ou e-mail…", + "importButton": "Importar", + "importLabel": "Importar contato de vCard", + "importTooltip": "Importar vCard", + "emptyTitle": "Nenhum contato ainda", + "emptyDescription": "Adicione novos contatos com o botão +.", + "filterAll": "Todos", + "nameLabel": "Nome *", + "namePlaceholder": "Nome completo", + "categoryLabel": "Categoria", + "phoneLabel": "Telefone", + "phonePlaceholder": "+55 …", + "emailLabel": "E-mail", + "emailPlaceholder": "nome@exemplo.com", + "addressLabel": "Endereço", + "addressPlaceholder": "Rua, Cidade", + "notesLabel": "Notas", + "notesPlaceholder": "Opcional…", + "callLabel": "Ligar", + "emailActionLabel": "E-mail", + "mapsLabel": "Abrir no Maps", + "exportLabel": "Exportar como vCard", + "exportTooltip": "Exportar vCard", + "deleteLabel": "Excluir contato", + "deleteConfirm": "Excluir contato?", + "deletePersonConfirm": "Excluir \"{{name}}\"?", + "savedToast": "Contato salvo", + "updatedToast": "Contato atualizado", + "deletedToast": "Contato excluído", + "importedToast": "{{name}} importado.", + "importError": "Falha na importação: {{error}}", + "vcardNoName": "vCard não contém nome.", + "catDoctor": "Médico", + "catSchool": "Escola/Creche", + "catAuthority": "Órgão público", + "catInsurance": "Seguro", + "catCraftsman": "Artesão", + "catEmergency": "Emergência", + "catMisc": "Outros", + "categoryDoctor": "Médico", + "categorySchool": "Escola/Creche", + "categoryAuthority": "Órgão público", + "categoryInsurance": "Seguro", + "categoryCraftsman": "Artesão", + "categoryEmergency": "Emergência", + "categoryOther": "Outros" + }, + "budget": { + "title": "Orçamento", + "newEntry": "Nova entrada", + "editEntry": "Editar entrada", + "addEntryLabel": "Adicionar entrada", + "newEntryFabLabel": "Nova entrada", + "currentMonth": "Atual", + "prevMonth": "Mês anterior", + "nextMonth": "Próximo mês", + "income": "Receita", + "expenses": "Despesas", + "balance": "Saldo", + "byCategory": "Por categoria", + "transactions": "Transações", + "emptyTitle": "Nenhuma entrada este mês", + "emptyDescription": "Adicione entradas de orçamento com o botão +.", + "csvExport": "CSV", + "typeExpense": "Despesa", + "typeIncome": "Receita", + "titleLabel": "Título *", + "titlePlaceholder": "Ex.: Supermercado", + "amountLabel": "Valor *", + "amountPlaceholder": "0,00", + "categoryLabel": "Categoria", + "dateLabel": "Data *", + "recurringLabel": "Recorrente", + "deleteLabel": "Excluir entrada", + "deleteConfirm": "Excluir entrada?", + "deletePersonConfirm": "Excluir \"{{title}}\"?", + "addedToast": "Entrada adicionada", + "savedToast": "Entrada salva", + "deletedToast": "Entrada excluída", + "loadError": "Falha ao carregar orçamento.", + "trendNeutral": "- igual a {{month}}", + "validAmountRequired": "Insira um valor válido", + "dateRequired": "Data é obrigatória", + "catFood": "Alimentação", + "catRent": "Aluguel", + "catInsurance": "Seguro", + "catMobility": "Transporte", + "catLeisure": "Lazer", + "catClothing": "Roupas", + "catHealth": "Saúde", + "catEducation": "Educação", + "catMisc": "Outros", + "loadingIndicator": "Carregando…" + }, + "settings": { + "title": "Configurações", + "tabGeneral": "Geral", + "tabMeals": "Refeições", + "tabBudget": "Orçamento", + "tabShopping": "Compras", + "tabCalendar": "Calendário", + "tabAccount": "Conta", + "tabsAriaLabel": "Seções de configurações", + "sectionDesign": "Design", + "sectionShopping": "Compras", + "shoppingCategoriesLabel": "Categorias de compras", + "shoppingCategoriesHint": "Adicione, renomeie, exclua ou ordene categorias.", + "shoppingCategoryPlaceholder": "Nova categoria…", + "shoppingCategoryRenameHint": "Clique para renomear", + "shoppingCategoryRenamePrompt": "Novo nome da categoria:", + "shoppingCategoryMoveUp": "Mover categoria para cima", + "shoppingCategoryMoveDown": "Mover categoria para baixo", + "shoppingCategoryDelete": "Excluir categoria", + "shoppingCategoryDeleteConfirm": "Excluir categoria \"{{name}}\"? Os itens existentes serão atribuídos à próxima categoria.", + "shoppingCategoryAdded": "Categoria adicionada.", + "shoppingCategoryRenamed": "Categoria renomeada.", + "shoppingCategoryDeleted": "Categoria excluída.", + "sectionAccount": "Minha conta", + "sectionCalendarSync": "Sincronização de calendário", + "sectionFamily": "Membros da família", + "cardAppearance": "Aparência", + "themeSystem": "Sistema", + "themeSysLabel": "Usar configuração do sistema", + "themeLight": "Claro", + "themeLightLabel": "Tema claro", + "themeDark": "Escuro", + "themeDarkLabel": "Tema escuro", + "changePassword": "Alterar senha", + "currentPasswordLabel": "Senha atual", + "newPasswordLabel": "Nova senha", + "confirmPasswordLabel": "Confirmar nova senha", + "savePassword": "Salvar senha", + "passwordMismatch": "As senhas não coincidem.", + "passwordSavedToast": "Senha alterada com sucesso.", + "googleCalendar": "Google Agenda", + "appleCalendar": "Apple Calendar (iCloud)", + "syncNow": "Sincronizar agora", + "disconnect": "Desconectar", + "connectGoogle": "Conectar ao Google", + "connected": "Conectado", + "connectedLastSync": "Conectado · Última: {{date}}", + "notConnected": "Não conectado", + "notConfigured": "Não configurado (variáveis .env ausentes)", + "configured": "Configurado (via .env)", + "configuredLastSync": "Configurado (via .env) · Última: {{date}}", + "syncSuccess": "{{provider}} sincronizado.", + "disconnectedToast": "{{provider}} desconectado.", + "googleOnlyAdmin": "Apenas o administrador pode conectar o Google Agenda.", + "appleOnlyAdmin": "Apenas o administrador pode conectar o Apple Calendar.", + "caldavUrlLabel": "URL do servidor CalDAV", + "caldavUrlPlaceholder": "https://caldav.icloud.com", + "appleIdLabel": "Apple ID (e-mail)", + "applePasswordLabel": "Senha específica do app", + "applePasswordHint": "Crie a senha em appleid.apple.com → Segurança.", + "appleConnectBtn": "Conectar e testar", + "appleConnecting": "Conectando…", + "appleConnectedToast": "Apple Calendar conectado.", + "syncSuccessGoogle": "Sincronização com Google Agenda conectada com sucesso.", + "syncSuccessApple": "Sincronização com Apple Calendar conectada com sucesso.", + "syncErrorGoogle": "Falha ao conectar ao Google. Tente novamente.", + "syncErrorApple": "Falha ao conectar ao Apple. Tente novamente.", + "addMember": "+ Adicionar membro", + "newMemberTitle": "Novo membro da família", + "usernameLabel": "Nome de usuário", + "displayNameLabel": "Nome de exibição", + "memberPasswordLabel": "Senha", + "colorLabel": "Cor", + "roleLabel": "Função", + "roleMember": "Membro", + "roleAdmin": "Admin", + "createMember": "Criar", + "cancelAddMember": "Cancelar", + "memberAddedToast": "{{name}} adicionado.", + "deleteMemberConfirm": "Excluir {{name}}?", + "memberDeletedToast": "{{name}} excluído.", + "deleteMemberLabel": "Excluir", + "logout": "Sair", + "synchronizing": "Sincronizando…", + "googleDisconnectConfirm": "Desconectar Google Agenda?", + "appleDisconnectConfirm": "Desconectar Apple Calendar?", + "localeSystem": "Sistema", + "localeLabel": "Idioma", + "languageTitle": "Idioma", + "sectionMeals": "Plano de refeições", + "mealTypesLabel": "Tipos de refeições visíveis", + "mealTypesHint": "Apenas os tipos de refeições selecionados serão exibidos no plano.", + "mealTypesSaved": "Configurações do plano de refeições salvas.", + "mealTypesMinOne": "Pelo menos um tipo de refeição deve estar ativo.", + "sectionBudget": "Orçamento", + "currencyLabel": "Moeda", + "currencyHint": "Define a moeda usada em toda a área de orçamento.", + "currencySaved": "Moeda salva." + }, + "login": { + "tagline": "Planejamento familiar. Seguro. Privado. Código aberto.", + "usernameLabel": "Nome de usuário", + "usernamePlaceholder": "nome de usuário", + "passwordLabel": "Senha", + "passwordPlaceholder": "••••••••", + "loginButton": "Entrar", + "loggingIn": "Entrando…", + "tooManyAttempts": "Muitas tentativas. Por favor, aguarde.", + "invalidCredentials": "Credenciais inválidas." + }, + "install": { + "title": "Instalar Oikos", + "subtitle": "Adicionar ao app", + "iosTip1": "Toque em ", + "iosTip2": " → \"Adicionar à Tela de Início\"", + "installButton": "Instalar", + "dismissLabel": "Fechar" + }, + "modal": { + "closeLabel": "Fechar", + "overlayLabel": "Fundo do diálogo modal" + }, + "rrule": { + "freqNone": "Sem repetição", + "freqDaily": "Diariamente", + "freqWeekly": "Semanalmente", + "freqMonthly": "Mensalmente", + "dayMo": "Seg", + "dayTu": "Ter", + "dayWe": "Qua", + "dayTh": "Qui", + "dayFr": "Sex", + "daySa": "Sáb", + "daySu": "Dom", + "labelRepeat": "Repetição", + "labelEvery": "A cada", + "labelOnDays": "Nestes dias", + "labelUntil": "Termina em (opcional)", + "unitDay": "dia", + "unitDays": "dias", + "unitWeek": "semana", + "unitWeeks": "semanas", + "unitMonth": "mês", + "unitMonths": "meses" + } +} diff --git a/public/pages/settings.js b/public/pages/settings.js index 1fc65e5..7647621 100644 --- a/public/pages/settings.js +++ b/public/pages/settings.js @@ -10,7 +10,7 @@ import { t, formatDate, formatTime } from '/i18n.js'; import { esc } from '/utils/html.js'; import '/components/oikos-locale-picker.js'; -const SUPPORTED_CURRENCIES = ['AUD', 'CAD', 'CHF', 'CNY', 'CZK', 'DKK', 'EUR', 'GBP', 'HUF', 'JPY', 'NOK', 'PLN', 'RUB', 'SEK', 'TRY', 'USD']; +const SUPPORTED_CURRENCIES = ['AED', 'AUD', 'BRL', 'CAD', 'CHF', 'CNY', 'CZK', 'DKK', 'EUR', 'GBP', 'HUF', 'INR', 'JPY', 'NOK', 'PLN', 'RUB', 'SAR', 'SEK', 'TRY', 'USD']; const SETTINGS_TAB_KEY = 'oikos:settings:tab'; function buildCurrencyOptions(selected) { diff --git a/public/sw.js b/public/sw.js index 0bec896..648375b 100644 --- a/public/sw.js +++ b/public/sw.js @@ -12,7 +12,7 @@ * API: Immer Netzwerk (kein Caching von Nutzerdaten) */ -const SHELL_CACHE = 'oikos-shell-v30'; +const SHELL_CACHE = 'oikos-shell-v31'; const PAGES_CACHE = 'oikos-pages-v28'; const ASSETS_CACHE = 'oikos-assets-v27'; const ALL_CACHES = [SHELL_CACHE, PAGES_CACHE, ASSETS_CACHE]; @@ -27,6 +27,10 @@ const APP_SHELL = [ '/rrule-ui.js', '/locales/de.json', '/locales/en.json', + '/locales/ja.json', + '/locales/ar.json', + '/locales/hi.json', + '/locales/pt.json', '/sw-register.js', '/lucide.min.js', '/styles/tokens.css',