diff --git a/public/locales/ar.json b/public/locales/ar.json
index 61db283..5b522b4 100644
--- a/public/locales/ar.json
+++ b/public/locales/ar.json
@@ -730,7 +730,14 @@
"private": "خاص",
"shared": "مشترك"
}
- }
+ },
+ "memberPhoneLabel": "Phone number (optional)",
+ "memberEmailLabel": "Email (optional)",
+ "memberBirthDateLabel": "Birthday date (optional)",
+ "memberContactBirthdayHint": "This member is automatically synchronized with Contacts and Birthdays.",
+ "memberBirthDateInvalid": "Use a valid birthday date in the selected date format.",
+ "memberPhoneMeta": "Phone: {{value}}",
+ "memberBirthdayMeta": "Birthday: {{date}}"
},
"login": {
"tagline": "تخطيط عائلي. آمن. يحترم الخصوصية. مفتوح المصدر.",
diff --git a/public/locales/de.json b/public/locales/de.json
index 798a228..f45aa51 100644
--- a/public/locales/de.json
+++ b/public/locales/de.json
@@ -755,7 +755,14 @@
"addedToast": "Abonnement hinzugefügt.",
"syncedToast": "Abonnement synchronisiert.",
"deletedToast": "Abonnement gelöscht."
- }
+ },
+ "memberPhoneLabel": "Telefonnummer (optional)",
+ "memberEmailLabel": "E-Mail (optional)",
+ "memberBirthDateLabel": "Geburtstag (optional)",
+ "memberContactBirthdayHint": "Dieses Mitglied wird automatisch mit Kontakten und Geburtstagen synchronisiert.",
+ "memberBirthDateInvalid": "Bitte ein gültiges Geburtstagsdatum im ausgewählten Format verwenden.",
+ "memberPhoneMeta": "Telefon: {{value}}",
+ "memberBirthdayMeta": "Geburtstag: {{date}}"
},
"login": {
"tagline": "Familienplanung. Sicher. Datenschutzfreundlich. Open Source.",
diff --git a/public/locales/el.json b/public/locales/el.json
index 8fac0bb..60e1729 100644
--- a/public/locales/el.json
+++ b/public/locales/el.json
@@ -730,7 +730,14 @@
"private": "Ιδιωτικό",
"shared": "Κοινόχρηστο"
}
- }
+ },
+ "memberPhoneLabel": "Phone number (optional)",
+ "memberEmailLabel": "Email (optional)",
+ "memberBirthDateLabel": "Birthday date (optional)",
+ "memberContactBirthdayHint": "This member is automatically synchronized with Contacts and Birthdays.",
+ "memberBirthDateInvalid": "Use a valid birthday date in the selected date format.",
+ "memberPhoneMeta": "Phone: {{value}}",
+ "memberBirthdayMeta": "Birthday: {{date}}"
},
"login": {
"tagline": "Οικογενειακός προγραμματισμός. Ασφαλής. Φιλικός προς την ιδιωτικότητα. Ανοιχτός κώδικας.",
diff --git a/public/locales/en.json b/public/locales/en.json
index 99dbc67..6d0cbf4 100644
--- a/public/locales/en.json
+++ b/public/locales/en.json
@@ -730,7 +730,14 @@
"private": "Private",
"shared": "Shared"
}
- }
+ },
+ "memberPhoneLabel": "Phone number (optional)",
+ "memberEmailLabel": "Email (optional)",
+ "memberBirthDateLabel": "Birthday date (optional)",
+ "memberContactBirthdayHint": "This member is automatically synchronized with Contacts and Birthdays.",
+ "memberBirthDateInvalid": "Use a valid birthday date in the selected date format.",
+ "memberPhoneMeta": "Phone: {{value}}",
+ "memberBirthdayMeta": "Birthday: {{date}}"
},
"login": {
"tagline": "Family planning. Secure. Privacy-friendly. Open source.",
diff --git a/public/locales/es.json b/public/locales/es.json
index 68b3af8..e7ff8fb 100644
--- a/public/locales/es.json
+++ b/public/locales/es.json
@@ -730,7 +730,14 @@
"private": "Privado",
"shared": "Compartido"
}
- }
+ },
+ "memberPhoneLabel": "Phone number (optional)",
+ "memberEmailLabel": "Email (optional)",
+ "memberBirthDateLabel": "Birthday date (optional)",
+ "memberContactBirthdayHint": "This member is automatically synchronized with Contacts and Birthdays.",
+ "memberBirthDateInvalid": "Use a valid birthday date in the selected date format.",
+ "memberPhoneMeta": "Phone: {{value}}",
+ "memberBirthdayMeta": "Birthday: {{date}}"
},
"login": {
"tagline": "Planificación familiar. Segura. Privada. Código abierto.",
diff --git a/public/locales/fr.json b/public/locales/fr.json
index d5d408d..2b1f314 100644
--- a/public/locales/fr.json
+++ b/public/locales/fr.json
@@ -730,7 +730,14 @@
"private": "Privé",
"shared": "Partagé"
}
- }
+ },
+ "memberPhoneLabel": "Phone number (optional)",
+ "memberEmailLabel": "Email (optional)",
+ "memberBirthDateLabel": "Birthday date (optional)",
+ "memberContactBirthdayHint": "This member is automatically synchronized with Contacts and Birthdays.",
+ "memberBirthDateInvalid": "Use a valid birthday date in the selected date format.",
+ "memberPhoneMeta": "Phone: {{value}}",
+ "memberBirthdayMeta": "Birthday: {{date}}"
},
"login": {
"tagline": "Planification familiale. Sécurisée. Respectueuse de la vie privée. Open source.",
diff --git a/public/locales/hi.json b/public/locales/hi.json
index b12ef8f..d17219e 100644
--- a/public/locales/hi.json
+++ b/public/locales/hi.json
@@ -730,7 +730,14 @@
"private": "निजी",
"shared": "साझा"
}
- }
+ },
+ "memberPhoneLabel": "Phone number (optional)",
+ "memberEmailLabel": "Email (optional)",
+ "memberBirthDateLabel": "Birthday date (optional)",
+ "memberContactBirthdayHint": "This member is automatically synchronized with Contacts and Birthdays.",
+ "memberBirthDateInvalid": "Use a valid birthday date in the selected date format.",
+ "memberPhoneMeta": "Phone: {{value}}",
+ "memberBirthdayMeta": "Birthday: {{date}}"
},
"login": {
"tagline": "पारिवारिक योजना। सुरक्षित। गोपनीयता-अनुकूल। ओपन सोर्स।",
diff --git a/public/locales/it.json b/public/locales/it.json
index e09b1d9..46a4d8d 100644
--- a/public/locales/it.json
+++ b/public/locales/it.json
@@ -730,7 +730,14 @@
"private": "Privato",
"shared": "Condiviso"
}
- }
+ },
+ "memberPhoneLabel": "Phone number (optional)",
+ "memberEmailLabel": "Email (optional)",
+ "memberBirthDateLabel": "Birthday date (optional)",
+ "memberContactBirthdayHint": "This member is automatically synchronized with Contacts and Birthdays.",
+ "memberBirthDateInvalid": "Use a valid birthday date in the selected date format.",
+ "memberPhoneMeta": "Phone: {{value}}",
+ "memberBirthdayMeta": "Birthday: {{date}}"
},
"login": {
"tagline": "Pianificazione familiare. Sicura. Rispettosa della privacy. Open source.",
diff --git a/public/locales/ja.json b/public/locales/ja.json
index c1d2325..defa202 100644
--- a/public/locales/ja.json
+++ b/public/locales/ja.json
@@ -730,7 +730,14 @@
"private": "プライベート",
"shared": "共有"
}
- }
+ },
+ "memberPhoneLabel": "Phone number (optional)",
+ "memberEmailLabel": "Email (optional)",
+ "memberBirthDateLabel": "Birthday date (optional)",
+ "memberContactBirthdayHint": "This member is automatically synchronized with Contacts and Birthdays.",
+ "memberBirthDateInvalid": "Use a valid birthday date in the selected date format.",
+ "memberPhoneMeta": "Phone: {{value}}",
+ "memberBirthdayMeta": "Birthday: {{date}}"
},
"login": {
"tagline": "家族計画。安全。プライバシー重視。オープンソース。",
diff --git a/public/locales/pt.json b/public/locales/pt.json
index 3360f41..a6db098 100644
--- a/public/locales/pt.json
+++ b/public/locales/pt.json
@@ -730,7 +730,14 @@
"private": "Privado",
"shared": "Partilhado"
}
- }
+ },
+ "memberPhoneLabel": "Telefone (opcional)",
+ "memberEmailLabel": "E-mail (opcional)",
+ "memberBirthDateLabel": "Data de aniversário (opcional)",
+ "memberContactBirthdayHint": "Este membro é sincronizado automaticamente com Contatos e Aniversários.",
+ "memberBirthDateInvalid": "Use uma data de aniversário válida no formato selecionado.",
+ "memberPhoneMeta": "Telefone: {{value}}",
+ "memberBirthdayMeta": "Aniversário: {{date}}"
},
"login": {
"tagline": "Planejamento familiar. Seguro. Privado. Código aberto.",
diff --git a/public/locales/ru.json b/public/locales/ru.json
index 12d5ab0..5e127a9 100644
--- a/public/locales/ru.json
+++ b/public/locales/ru.json
@@ -730,7 +730,14 @@
"private": "Личное",
"shared": "Общее"
}
- }
+ },
+ "memberPhoneLabel": "Phone number (optional)",
+ "memberEmailLabel": "Email (optional)",
+ "memberBirthDateLabel": "Birthday date (optional)",
+ "memberContactBirthdayHint": "This member is automatically synchronized with Contacts and Birthdays.",
+ "memberBirthDateInvalid": "Use a valid birthday date in the selected date format.",
+ "memberPhoneMeta": "Phone: {{value}}",
+ "memberBirthdayMeta": "Birthday: {{date}}"
},
"login": {
"tagline": "Семейное планирование. Безопасно. С уважением к приватности. Открытый исходный код.",
diff --git a/public/locales/sv.json b/public/locales/sv.json
index 4638f78..10e8537 100644
--- a/public/locales/sv.json
+++ b/public/locales/sv.json
@@ -730,7 +730,14 @@
"private": "Privat",
"shared": "Delad"
}
- }
+ },
+ "memberPhoneLabel": "Phone number (optional)",
+ "memberEmailLabel": "Email (optional)",
+ "memberBirthDateLabel": "Birthday date (optional)",
+ "memberContactBirthdayHint": "This member is automatically synchronized with Contacts and Birthdays.",
+ "memberBirthDateInvalid": "Use a valid birthday date in the selected date format.",
+ "memberPhoneMeta": "Phone: {{value}}",
+ "memberBirthdayMeta": "Birthday: {{date}}"
},
"login": {
"tagline": "Familjeplanering. Säker. Sekretessvänlig. Öppen källkod.",
diff --git a/public/locales/tr.json b/public/locales/tr.json
index e8caafb..4636a3d 100644
--- a/public/locales/tr.json
+++ b/public/locales/tr.json
@@ -730,7 +730,14 @@
"private": "Özel",
"shared": "Paylaşımlı"
}
- }
+ },
+ "memberPhoneLabel": "Phone number (optional)",
+ "memberEmailLabel": "Email (optional)",
+ "memberBirthDateLabel": "Birthday date (optional)",
+ "memberContactBirthdayHint": "This member is automatically synchronized with Contacts and Birthdays.",
+ "memberBirthDateInvalid": "Use a valid birthday date in the selected date format.",
+ "memberPhoneMeta": "Phone: {{value}}",
+ "memberBirthdayMeta": "Birthday: {{date}}"
},
"login": {
"tagline": "Aile planlaması. Güvenli. Gizlilik dostu. Açık kaynak.",
diff --git a/public/locales/uk.json b/public/locales/uk.json
index 3074e65..1ad0be7 100644
--- a/public/locales/uk.json
+++ b/public/locales/uk.json
@@ -730,7 +730,14 @@
"private": "Приватне",
"shared": "Спільне"
}
- }
+ },
+ "memberPhoneLabel": "Phone number (optional)",
+ "memberEmailLabel": "Email (optional)",
+ "memberBirthDateLabel": "Birthday date (optional)",
+ "memberContactBirthdayHint": "This member is automatically synchronized with Contacts and Birthdays.",
+ "memberBirthDateInvalid": "Use a valid birthday date in the selected date format.",
+ "memberPhoneMeta": "Phone: {{value}}",
+ "memberBirthdayMeta": "Birthday: {{date}}"
},
"login": {
"tagline": "Планування для родини. Безпечно. Конфіденційно. Відкритий код.",
diff --git a/public/locales/zh.json b/public/locales/zh.json
index 4c85846..7c2a6e2 100644
--- a/public/locales/zh.json
+++ b/public/locales/zh.json
@@ -730,7 +730,14 @@
"private": "私人",
"shared": "共享"
}
- }
+ },
+ "memberPhoneLabel": "Phone number (optional)",
+ "memberEmailLabel": "Email (optional)",
+ "memberBirthDateLabel": "Birthday date (optional)",
+ "memberContactBirthdayHint": "This member is automatically synchronized with Contacts and Birthdays.",
+ "memberBirthDateInvalid": "Use a valid birthday date in the selected date format.",
+ "memberPhoneMeta": "Phone: {{value}}",
+ "memberBirthdayMeta": "Birthday: {{date}}"
},
"login": {
"tagline": "家庭规划。安全。注重隐私。开源。",
diff --git a/public/pages/settings.js b/public/pages/settings.js
index b1ba929..8ab5d68 100644
--- a/public/pages/settings.js
+++ b/public/pages/settings.js
@@ -6,7 +6,7 @@
import { api, auth } from '/api.js';
import { openModal, closeModal, confirmModal } from '/components/modal.js';
-import { t, formatDate, formatTime } from '/i18n.js';
+import { t, formatDate, formatTime, dateInputPlaceholder, formatDateInput, parseDateInput, isDateInputValid } from '/i18n.js';
import { esc } from '/utils/html.js';
import '/components/oikos-locale-picker.js';
@@ -56,6 +56,15 @@ function buildFamilyRoleOptions(selected = 'other') {
`).join('');
}
+function bindSettingsDateInputs(root) {
+ root.querySelectorAll('.js-date-input').forEach((input) => {
+ input.addEventListener('blur', () => {
+ const parsed = parseDateInput(input.value);
+ if (parsed) input.value = formatDateInput(parsed);
+ });
+ });
+}
+
function avatarHtml(user, className = 'settings-avatar') {
const safeName = esc(user?.display_name || '');
const fallback = esc(initials(user?.display_name || ''));
@@ -586,6 +595,21 @@ export async function render(container, { user }) {
${buildFamilyRoleOptions()}
+
+