Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ no string plumbing with the Go templates), and admin-authored content (event nam
descriptions, questions, custom email copy). Locale is resolved per request from
`Accept-Language` + a `?lang=` override + the operator's fallback setting
(`internal/handler/i18n.go`), and the booker's locale is stored on the booking so later
reminders match. Ships `en es fr fr-CA de it pt nl sv`. Full detail: ARCHITECTURE §23.
reminders match. Ships `en es fr fr-CA de el it nl pl pt sv`. Full detail: ARCHITECTURE §23.

**Adding a locale = adding `internal/i18n/locales/<code>.json`.** Nothing else. `init()`
globs the directory; the switcher, the fallback dropdown and the public API payload all read
Expand Down
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1229,7 +1229,7 @@ LLM summary) — the next build; consent-gated (§8.11/§15 of the PRD).

## 23. Languages (i18n)

Calnode ships **9 locales**: `en` (source) · `es` · `fr` · `fr-CA` · `de` · `it` · `pt` · `nl` · `sv`.
Calnode ships **11 locales**: `en` (source) · `es` · `fr` · `fr-CA` · `de` · `el` · `it` · `nl` · `pl` · `pt` · `sv`.

`fr-CA` is the first **regional** locale, and it is a separate file rather than a fallback
because the differences are real: `courriel` not `e-mail`, `reporter`/`report` not
Expand Down
171 changes: 171 additions & 0 deletions internal/i18n/locales/pl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
{
"book_by_chat": "Zarezerwuj przez czat",
"close": "Zamknij",
"assistant_greeting": "Cześć! Powiedz mi w przybliżeniu, kiedy chcesz się spotkać — np. „w czwartek po południu” lub „w przyszłym tygodniu” — a znajdę termin. W każdej chwili możesz też użyć kalendarza.",
"assistant_input_placeholder": "Wpisz, kiedy masz czas…",
"assistant_input_aria": "Napisz do asystenta rezerwacji",
"send": "Wyślij",
"show_more": "Pokaż więcej",
"show_less": "Pokaż mniej",
"date_picker_aria": "Wybór daty",
"timezone_aria": "Strefa czasowa",
"select_day_hint": "Wybierz dzień, aby zobaczyć dostępne godziny.",
"back": "Wstecz",
"name_label": "Imię i nazwisko",
"name_placeholder": "Twoje imię i nazwisko",
"email_label": "E-mail",
"email_placeholder": "ty@example.com",
"choose_option": "Wybierz opcję",
"confirm_booking": "Potwierdź rezerwację",
"confirming": "Potwierdzanie…",
"booking_confirmed": "Rezerwacja potwierdzona",
"confirmation_email_sent": "E-mail z potwierdzeniem został wysłany.",
"required_fields_error": "Wypełnij wszystkie wymagane pola.",
"slot_taken_error": "Ten termin właśnie został zajęty. Wybierz inną godzinę.",
"booking_failed_error": "Rezerwacja nie powiodła się. Spróbuj ponownie.",
"network_error": "Błąd sieci. Sprawdź swoje połączenie z internetem.",
"loading": "Ładowanie…",
"no_available_times": "Brak dostępnych terminów w dniu %s. Wybierz inną datę.",
"no_available_times_host": "%[1]s nie ma dostępnych terminów w dniu %[2]s. Wybierz inną datę.",
"slot_taken": "już zarezerwowane",
"all_times_taken": "Wszystkie terminy w tym dniu są zajęte.",
"min_notice_hint": "Rezerwacji należy dokonać z co najmniej %s wyprzedzeniem.",
"could_not_load_times": "Nie udało się załadować terminów. Spróbuj ponownie.",
"times_shown_in": "Godziny wyświetlane w strefie ",
"payment_received": "Płatność otrzymana",
"payment_confirmed_sub": "Twoja rezerwacja została potwierdzona — e-mail z potwierdzeniem jest już w drodze.",
"assistant_error": "Przepraszamy — coś poszło nie tak. Użyj poniższego kalendarza.",
"assistant_disclosure": "Rozmawiasz z automatycznym asystentem, a nie z człowiekiem.",
"other": "inny",
"others": "innych",
"list_separator": ", ",
"list_conjunction": " i ",
"language_switcher_aria": "Język",
"cookie_consent_aria": "Zgoda na pliki cookie",
"cookie_text": "Używamy analitycznych plików cookie, aby zrozumieć, jak używana jest ta strona rezerwacji — zapisujemy je tylko za Twoją zgodą.",
"privacy_policy": "Polityka prywatności",
"decline": "Odrzuć",
"accept": "Akceptuj",
"privacy": "Prywatność",
"terms": "Regulamin",
"cookie_settings": "Ustawienia plików cookie",
"prev_month_aria": "Poprzedni miesiąc",
"next_month_aria": "Następny miesiąc",
"demo_public_label": "Demo publiczne",
"demo_public_text": "dane widoczne w tym miejscu są publiczne i resetują się automatycznie. Nie wprowadzaj poufnych informacji.",
"demo_view_source": "Zobacz kod źródłowy",
"powered_by": "Obsługiwane przez",
"duration_min": "%d min",
"duration_hour_one": "1 godzina",
"duration_hours": "%d godz.",
"duration_hr_min": "%d godz. %d min",
"location_video_meeting": "Spotkanie wideo",
"location_phone": "Rozmowa telefoniczna",
"location_in_person": "Osobiście",
"location_video_call": "Połączenie wideo",
"manage_booking_title": "Zarządzaj rezerwacją",
"link_expired_title": "Link wygasł lub jest nieprawidłowy",
"link_expired_text": "Ten link do zarządzania wygasł lub nie jest już aktywny. Sprawdź e-mail z potwierdzeniem, aby znaleźć aktualny link, lub skontaktuj się z organizatorem.",
"booking_already_cancelled_title": "Rezerwacja została już anulowana",
"booking_already_cancelled_text": "Ta rezerwacja została anulowana. Aby zarezerwować nowy termin, przejdź do strony wydarzenia.",
"scheduled_for": "Zaplanowano na",
"reschedule": "Zmień termin",
"cancel_booking": "Anuluj rezerwację",
"select_a_date": "Wybierz datę",
"pick_day_hint": "Wybierz dzień z kalendarza.",
"confirm_reschedule_question": "Potwierdzić zmianę terminu?",
"was_label": "Było",
"now_label": "Teraz",
"confirm_reschedule": "Potwierdź zmianę terminu",
"rescheduling": "Zmienianie terminu…",
"cancel_this_booking_question": "Anulować tę rezerwację?",
"cancel_booking_notice": "Tej operacji nie można cofnąć. Wiadomość o anulowaniu zostanie wysłana do Ciebie oraz do organizatora.",
"reason_optional_label": "Powód (opcjonalnie)",
"reason_placeholder": "np. konflikt w kalendarzu",
"yes_cancel_booking": "Tak, anuluj rezerwację",
"cancelling": "Anulowanie…",
"booking_rescheduled_title": "Zmieniono termin rezerwacji",
"booking_rescheduled_prefix": "Twoja rezerwacja została przeniesiona na ",
"booking_cancelled_title": "Rezerwacja anulowana",
"booking_cancelled_text": "Twoja rezerwacja została anulowana.",
"slot_no_longer_available_error": "Ten termin nie jest już dostępny. Wybierz inną godzinę.",
"reschedule_failed_error": "Zmiana terminu nie powiodła się. Spróbuj ponownie.",
"already_cancelled_error": "Ta rezerwacja jest już anulowana.",
"cancellation_failed_error": "Anulowanie nie powiodło się. Spróbuj ponownie.",
"dow_short_sun": "niedz.",
"dow_short_mon": "pon.",
"dow_short_tue": "wt.",
"dow_short_wed": "śr.",
"dow_short_thu": "czw.",
"dow_short_fri": "pt.",
"dow_short_sat": "sob.",
"month_short_jan": "sty",
"month_short_feb": "lut",
"month_short_mar": "mar",
"month_short_apr": "kwi",
"month_short_may": "maj",
"month_short_jun": "cze",
"month_short_jul": "lip",
"month_short_aug": "sie",
"month_short_sep": "wrz",
"month_short_oct": "paź",
"month_short_nov": "lis",
"month_short_dec": "gru",
"clock_format": "24h",
"date_format": "%[1]s %[2]d %[3]s %[4]d",
"email_greeting": "Cześć %s,",
"email_confirmed_lead": "Twoja rezerwacja została potwierdzona.",
"email_cancelled_lead": "Twoja rezerwacja została anulowana.",
"email_rescheduled_lead": "Termin Twojej rezerwacji został zmieniony.",
"email_reminder_lead": "Przypomnienie: zbliża się termin Twojej rezerwacji.",
"email_label_event": "Wydarzenie",
"email_label_with": "Z kim",
"email_label_start": "Początek",
"email_label_end": "Koniec",
"email_label_when": "Kiedy",
"email_label_location": "Lokalizacja",
"email_label_reason": "Powód",
"email_label_was": "Poprzedni termin",
"email_label_now": "Nowy termin",
"email_add_to_calendar": "Dodaj do kalendarza:",
"email_add_to_calendar_updated": "Dodaj do kalendarza (zaktualizowany termin):",
"email_calendar_google": "Kalendarz Google",
"email_calendar_outlook": "Outlook",
"email_booking_reference": "Numer rezerwacji: %s",
"email_manage_link_intro": "Aby zmienić termin lub anulować rezerwację, przejdź do:",
"email_manage_link_intro_reschedule": "Aby ponownie zmienić termin lub anulować rezerwację, przejdź do:",
"email_cancel_link_intro": "Aby anulować, przejdź do:",
"email_rebook_intro": "Aby zarezerwować ponownie, przejdź do:",
"email_manage_button": "Zarządzaj rezerwacją",
"email_rebook_button": "Zarezerwuj ponownie",
"email_subject_confirmed": "Potwierdzenie rezerwacji: %s",
"email_subject_cancelled": "Anulowanie rezerwacji: %s",
"email_subject_rescheduled": "Zmiana terminu rezerwacji: %s",
"email_subject_reminder": "Przypomnienie: zbliża się %s",
"email_booking_with": "Rezerwacja z %s",
"email_manage_this_booking": "Zarządzaj tą rezerwacją:",
"calendar_event_summary": "%s – %s",
"calendar_event_booking_id": "Identyfikator rezerwacji: %s",
"err_booking_limit": "Masz już maksymalną liczbę nadchodzących rezerwacji dla tego wydarzenia. Anuluj istniejącą rezerwację lub poczekaj na jej zakończenie przed kolejną rezerwacją.",
"err_email_throttled": "Z tego adresu e-mail dokonywano ostatnio zbyt wielu rezerwacji. Spróbuj ponownie później.",
"err_required_field": "wymagane pole %q nie zostało wypełnione",
"err_required_checkbox": "pole %q musi zostać zaznaczone",
"err_invalid_option": "nieprawidłowa opcja dla %[1]q: %[2]q nie jest dozwolonym wyborem",
"assistant_unavailable": "Asystent rezerwacji jest w tej chwili niedostępny — wybierz termin z poniższego kalendarza.",
"assistant_trouble": "Przepraszamy — występują trudności techniczne. Wybierz termin z poniższego kalendarza.",
"assistant_iteration_cap": "Wybierzmy prostszą drogę — zaznacz termin z poniższego kalendarza.",
"assistant_status_slots": "Sprawdzanie dostępności…",
"assistant_status_book": "Rezerwowanie…",
"assistant_status_working": "Przetwarzanie…",
"time_period": "Pora dnia",
"time_morning": "Rano",
"time_afternoon": "Po południu",
"time_evening": "Wieczór",
"phone_call_number": "Numer telefonu (opcjonalnie, w przypadku rozmowy telefonicznej)",
"calendar_degraded_notice": "Nie udało się załadować części danych kalendarza, dlatego informacje o dostępności mogą być niepełne.",
"directory_book": "Zarezerwuj",
"directory_empty": "Brak dostępnych wydarzeń do zarezerwowania.",
"directory_members": "Członkowie zespołu",
"directory_person_subtitle": "Zarezerwuj spotkanie z użytkownikiem %s",
"directory_team_subtitle": "Zarezerwuj spotkanie z zespołem %s"
}
Loading