diff --git a/app/internal/hebrew_date_view.py b/app/internal/hebrew_date_view.py new file mode 100644 index 00000000..8d4713b2 --- /dev/null +++ b/app/internal/hebrew_date_view.py @@ -0,0 +1,75 @@ +from datetime import date + +from hebrew_numbers import int_to_gematria +from pyluach import dates, hebrewcal +from pyluach.dates import HebrewDate + +HEBREW_LANGUAGE_ID = 2 +_HEB_MONTH_NAMES = { + 'Tishrei': _("Tishrei"), + 'Cheshvan': _("Cheshvan"), + 'Kislev': _("Kislev"), + 'Teves': _("Teves"), + 'Shvat': _("Shvat"), + 'Adar': _("Adar"), + 'Adar Rishon': _("Adar Rishon"), + 'Adar Sheni': _("Adar Sheni"), + 'Nissan': _("Nissan"), + 'Iyar': _("Iyar"), + 'Sivan': _("Sivan"), + 'Tamuz': _("Tamuz"), + 'Av': _("Av"), + 'Elul': _("Elul"), +} + + +def get_hebrew_date_in_words(calendar_date: date, language_id: int) -> str: + """Returns the Hebrew date for the specific day. + + Args: + calendar_date: The requested date. + language_id: The user's language. + + Returns: + A Hebrew date string. + """ + hebrew_date_object = from_gregorian_to_hebrew_date(calendar_date) + day = hebrew_date_object.day + month = get_month_name_by_num(hebrew_date_object) + year = hebrew_date_object.year + if language_id == HEBREW_LANGUAGE_ID: + day = int_to_gematria(day) + year = int_to_gematria(year % 1000) + return ' '.join((str(day), str(month), str(year))) + + +def get_month_name_by_num(calendar_date: HebrewDate) -> str: + """Returns the Hebrew name date for the specific day. + + Args: + calendar_date: The requested date. + + Returns: + A Hebrew name date. + Using "_" sign for function for using gettext translate . + """ + for month in hebrewcal.Year(calendar_date.year).itermonths(): + if calendar_date.month == month.month: + return _(month.name) + + +def from_gregorian_to_hebrew_date(calendar_date: date) -> HebrewDate: + """Returns the Hebrew date for the specific gregorian date. + + Args: + calendar_date: The requested date. + + Returns: + A HebrewDate object. + """ + gregorian_date = dates.GregorianDate( + calendar_date.year, + calendar_date.month, + calendar_date.day, + ) + return gregorian_date.to_heb() diff --git a/app/locales/en/LC_MESSAGES/base.mo b/app/locales/en/LC_MESSAGES/base.mo index a2af11c0..7b05f93d 100644 Binary files a/app/locales/en/LC_MESSAGES/base.mo and b/app/locales/en/LC_MESSAGES/base.mo differ diff --git a/app/locales/en/LC_MESSAGES/base.po b/app/locales/en/LC_MESSAGES/base.po index 948c8761..969eddcb 100644 --- a/app/locales/en/LC_MESSAGES/base.po +++ b/app/locales/en/LC_MESSAGES/base.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-02-07 21:31+0000\n" +"POT-Creation-Date: 2021-03-01 02:13+0200\n" "PO-Revision-Date: 2021-01-26 21:31+0200\n" "Last-Translator: FULL NAME \n" "Language: en\n" @@ -18,81 +18,161 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.9.0\n" -#: app/routers/profile.py:20 +#: app/internal/astronomy.py:11 +msgid "No response from server." +msgstr "" + +#: app/internal/hebrew_date_view.py:10 +msgid "Tishrei" +msgstr "" + +#: app/internal/hebrew_date_view.py:11 +msgid "Cheshvan" +msgstr "" + +#: app/internal/hebrew_date_view.py:12 +msgid "Kislev" +msgstr "" + +#: app/internal/hebrew_date_view.py:13 +msgid "Teves" +msgstr "" + +#: app/internal/hebrew_date_view.py:14 +msgid "Shvat" +msgstr "" + +#: app/internal/hebrew_date_view.py:15 +msgid "Adar" +msgstr "" + +#: app/internal/hebrew_date_view.py:16 +msgid "Adar Rishon" +msgstr "" + +#: app/internal/hebrew_date_view.py:17 +msgid "Adar Sheni" +msgstr "" + +#: app/internal/hebrew_date_view.py:18 +msgid "Nissan" +msgstr "" + +#: app/internal/hebrew_date_view.py:19 +msgid "Iyar" +msgstr "" + +#: app/internal/hebrew_date_view.py:20 +msgid "Sivan" +msgstr "" + +#: app/internal/hebrew_date_view.py:21 +msgid "Tamuz" +msgstr "" + +#: app/internal/hebrew_date_view.py:22 +msgid "Av" +msgstr "" + +#: app/internal/hebrew_date_view.py:23 +msgid "Elul" +msgstr "" + +#: app/routers/export.py:18 msgid "Not found" msgstr "" -#: app/templates/agenda.html:11 +#: app/routers/search.py:53 +msgid "Invalid request." +msgstr "" + +#: app/routers/search.py:58 +msgid "No matching results for '{keywords}'." +msgstr "" + +#: app/templates/agenda.html:14 +#: app/templates/partials/user_profile/sidebar_left/features_card/export_calendar.html:9 msgid "From" msgstr "" -#: app/templates/agenda.html:13 -msgid "to" +#: app/templates/agenda.html:18 +#: app/templates/partials/user_profile/sidebar_left/features_card/export_calendar.html:11 +msgid "To" msgstr "" -#: app/templates/agenda.html:15 +#: app/templates/agenda.html:22 msgid "Get Agenda" msgstr "" -#: app/templates/agenda.html:20 +#: app/templates/agenda.html:39 msgid "Today" msgstr "" -#: app/templates/agenda.html:23 -msgid "Next week" +#: app/templates/agenda.html:42 +msgid "Next 7 days" msgstr "" -#: app/templates/agenda.html:26 -msgid "Next month" +#: app/templates/agenda.html:45 +msgid "Next 30 days" msgstr "" -#: app/templates/agenda.html:33 +#: app/templates/agenda.html:49 +msgid "Week graph" +msgstr "" + +#: app/templates/agenda.html:61 msgid "Start date is greater than end date" msgstr "" -#: app/templates/agenda.html:35 +#: app/templates/agenda.html:63 msgid "No events found..." msgstr "" -#: app/templates/profile.html:50 -msgid "Update name" +#: app/templates/base.html:41 +msgid "Sign Out" msgstr "" -#: app/templates/profile.html:57 app/templates/profile.html:77 -#: app/templates/profile.html:97 app/templates/profile.html:120 -#: app/templates/profile.html:140 -msgid "Save changes" +#: app/templates/base.html:68 app/templates/partials/index/navigation.html:36 +msgid "About Us" msgstr "" -#: app/templates/profile.html:70 -msgid "Update email" +#: app/templates/partials/calendar/event/view_event_details_tab.html:61 +msgid "Choose user" +msgstr "" + +#: app/templates/partials/user_profile/sidebar_left/features_card/export_calendar.html:13 +msgid "Export" msgstr "" -#: app/templates/profile.html:90 +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/description_modal.html:6 msgid "Update description" msgstr "" -#: app/templates/profile.html:111 -msgid "Update photo" +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/description_modal.html:14 +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/email_modal.html:14 +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/name_modal.html:14 +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/telegram_modal.html:15 +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/upload_photo_modal.html:15 +msgid "Save changes" msgstr "" -#: app/templates/profile.html:220 -msgid "Upcoming event on (date)" +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/email_modal.html:6 +msgid "Update email" msgstr "" -#: app/templates/profile.html:246 -msgid "The Event (event)" +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/name_modal.html:6 +msgid "Update name" msgstr "" -#: app/templates/profile.html:249 -msgid "Last updated (time) ago" +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/upload_photo_modal.html:6 +msgid "Update photo" msgstr "" -#: app/templates/profile.html:285 +#: app/templates/partials/user_profile/sidebar_right/meetups.html:4 msgid "Explore MeetUps near you" msgstr "" -#: app/templates/profile.html:293 +#: app/templates/partials/user_profile/sidebar_right/new_card.html:4 msgid "Your Card" msgstr "" @@ -130,3 +210,22 @@ msgstr "" #~ msgid "Agenda" #~ msgstr "" + +#~ msgid "to" +#~ msgstr "" + +#~ msgid "Next week" +#~ msgstr "" + +#~ msgid "Next month" +#~ msgstr "" + +#~ msgid "Upcoming event on (date)" +#~ msgstr "" + +#~ msgid "The Event (event)" +#~ msgstr "" + +#~ msgid "Last updated (time) ago" +#~ msgstr "" + diff --git a/app/locales/he/LC_MESSAGES/base.mo b/app/locales/he/LC_MESSAGES/base.mo index 2233662f..528f1583 100644 Binary files a/app/locales/he/LC_MESSAGES/base.mo and b/app/locales/he/LC_MESSAGES/base.mo differ diff --git a/app/locales/he/LC_MESSAGES/base.po b/app/locales/he/LC_MESSAGES/base.po index 959b1f6d..911fd5a5 100644 --- a/app/locales/he/LC_MESSAGES/base.po +++ b/app/locales/he/LC_MESSAGES/base.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-02-07 21:31+0000\n" +"POT-Creation-Date: 2021-03-01 02:13+0200\n" "PO-Revision-Date: 2021-01-26 21:31+0200\n" "Last-Translator: FULL NAME \n" "Language: he\n" @@ -18,81 +18,161 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.9.0\n" -#: app/routers/profile.py:20 +#: app/internal/astronomy.py:11 +msgid "No response from server." +msgstr "" + +#: app/internal/hebrew_date_view.py:10 +msgid "Tishrei" +msgstr "" + +#: app/internal/hebrew_date_view.py:11 +msgid "Cheshvan" +msgstr "" + +#: app/internal/hebrew_date_view.py:12 +msgid "Kislev" +msgstr "" + +#: app/internal/hebrew_date_view.py:13 +msgid "Teves" +msgstr "טבת" + +#: app/internal/hebrew_date_view.py:14 +msgid "Shvat" +msgstr "" + +#: app/internal/hebrew_date_view.py:15 +msgid "Adar" +msgstr "" + +#: app/internal/hebrew_date_view.py:16 +msgid "Adar Rishon" +msgstr "" + +#: app/internal/hebrew_date_view.py:17 +msgid "Adar Sheni" +msgstr "" + +#: app/internal/hebrew_date_view.py:18 +msgid "Nissan" +msgstr "" + +#: app/internal/hebrew_date_view.py:19 +msgid "Iyar" +msgstr "" + +#: app/internal/hebrew_date_view.py:20 +msgid "Sivan" +msgstr "" + +#: app/internal/hebrew_date_view.py:21 +msgid "Tamuz" +msgstr "" + +#: app/internal/hebrew_date_view.py:22 +msgid "Av" +msgstr "" + +#: app/internal/hebrew_date_view.py:23 +msgid "Elul" +msgstr "" + +#: app/routers/export.py:18 msgid "Not found" msgstr "" -#: app/templates/agenda.html:11 +#: app/routers/search.py:53 +msgid "Invalid request." +msgstr "" + +#: app/routers/search.py:58 +msgid "No matching results for '{keywords}'." +msgstr "" + +#: app/templates/agenda.html:14 +#: app/templates/partials/user_profile/sidebar_left/features_card/export_calendar.html:9 msgid "From" msgstr "" -#: app/templates/agenda.html:13 -msgid "to" +#: app/templates/agenda.html:18 +#: app/templates/partials/user_profile/sidebar_left/features_card/export_calendar.html:11 +msgid "To" msgstr "" -#: app/templates/agenda.html:15 +#: app/templates/agenda.html:22 msgid "Get Agenda" msgstr "" -#: app/templates/agenda.html:20 +#: app/templates/agenda.html:39 msgid "Today" msgstr "" -#: app/templates/agenda.html:23 -msgid "Next week" +#: app/templates/agenda.html:42 +msgid "Next 7 days" msgstr "" -#: app/templates/agenda.html:26 -msgid "Next month" +#: app/templates/agenda.html:45 +msgid "Next 30 days" msgstr "" -#: app/templates/agenda.html:33 +#: app/templates/agenda.html:49 +msgid "Week graph" +msgstr "" + +#: app/templates/agenda.html:61 msgid "Start date is greater than end date" msgstr "" -#: app/templates/agenda.html:35 +#: app/templates/agenda.html:63 msgid "No events found..." msgstr "" -#: app/templates/profile.html:50 -msgid "Update name" +#: app/templates/base.html:41 +msgid "Sign Out" msgstr "" -#: app/templates/profile.html:57 app/templates/profile.html:77 -#: app/templates/profile.html:97 app/templates/profile.html:120 -#: app/templates/profile.html:140 -msgid "Save changes" +#: app/templates/base.html:68 app/templates/partials/index/navigation.html:36 +msgid "About Us" msgstr "" -#: app/templates/profile.html:70 -msgid "Update email" +#: app/templates/partials/calendar/event/view_event_details_tab.html:61 +msgid "Choose user" +msgstr "" + +#: app/templates/partials/user_profile/sidebar_left/features_card/export_calendar.html:13 +msgid "Export" msgstr "" -#: app/templates/profile.html:90 +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/description_modal.html:6 msgid "Update description" msgstr "" -#: app/templates/profile.html:111 -msgid "Update photo" +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/description_modal.html:14 +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/email_modal.html:14 +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/name_modal.html:14 +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/telegram_modal.html:15 +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/upload_photo_modal.html:15 +msgid "Save changes" msgstr "" -#: app/templates/profile.html:220 -msgid "Upcoming event on (date)" +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/email_modal.html:6 +msgid "Update email" msgstr "" -#: app/templates/profile.html:246 -msgid "The Event (event)" +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/name_modal.html:6 +msgid "Update name" msgstr "" -#: app/templates/profile.html:249 -msgid "Last updated (time) ago" +#: app/templates/partials/user_profile/sidebar_left/profile_card/modals/upload_photo_modal.html:6 +msgid "Update photo" msgstr "" -#: app/templates/profile.html:285 +#: app/templates/partials/user_profile/sidebar_right/meetups.html:4 msgid "Explore MeetUps near you" msgstr "" -#: app/templates/profile.html:293 +#: app/templates/partials/user_profile/sidebar_right/new_card.html:4 msgid "Your Card" msgstr "" @@ -130,3 +210,22 @@ msgstr "בדיקת תרגום בפייתון" #~ msgid "Agenda" #~ msgstr "" + +#~ msgid "to" +#~ msgstr "" + +#~ msgid "Next week" +#~ msgstr "" + +#~ msgid "Next month" +#~ msgstr "" + +#~ msgid "Upcoming event on (date)" +#~ msgstr "" + +#~ msgid "The Event (event)" +#~ msgstr "" + +#~ msgid "Last updated (time) ago" +#~ msgstr "" + diff --git a/app/routers/audio.py b/app/routers/audio.py index c53ed9ca..3da3d9e7 100644 --- a/app/routers/audio.py +++ b/app/routers/audio.py @@ -23,6 +23,7 @@ ) from app.internal.security.dependencies import current_user + router = APIRouter( prefix="/audio", tags=["audio"], diff --git a/app/routers/calendar.py b/app/routers/calendar.py index dc1aeefa..9876a97f 100644 --- a/app/routers/calendar.py +++ b/app/routers/calendar.py @@ -1,11 +1,12 @@ from http import HTTPStatus -from fastapi import APIRouter, Request +from fastapi import APIRouter, Request, Depends from fastapi.responses import HTMLResponse from starlette.responses import Response -from app.dependencies import templates -from app.routers import calendar_grid as cg +from app.dependencies import get_db, templates +from app.routers import calendar_grid + router = APIRouter( prefix="/calendar/month", @@ -16,16 +17,16 @@ @router.get("/") -async def calendar(request: Request) -> Response: - user_local_time = cg.Day.get_user_local_time() - day = cg.create_day(user_local_time) +async def calendar(request: Request, db_session=Depends(get_db)) -> Response: + user_local_time = calendar_grid.Day.get_user_local_time() + day = calendar_grid.create_day(user_local_time) return templates.TemplateResponse( "calendar_monthly_view.html", { "request": request, "day": day, - "week_days": cg.Week.DAYS_OF_THE_WEEK, - "weeks_block": cg.get_month_block(day) + "week_days": calendar_grid.Week.DAYS_OF_THE_WEEK, + "weeks_block": calendar_grid.get_month_block(day), } ) @@ -34,8 +35,10 @@ async def calendar(request: Request) -> Response: async def update_calendar( request: Request, date: str, days: int ) -> HTMLResponse: - last_day = cg.Day.convert_str_to_date(date) - next_weeks = cg.create_weeks(cg.get_n_days(last_day, days)) + last_day = calendar_grid.Day.convert_str_to_date(date) + next_weeks = calendar_grid.create_weeks( + calendar_grid.get_n_days(last_day, days) + ) template = templates.get_template( 'partials/calendar/monthly_view/add_week.html') content = template.render(weeks_block=next_weeks) diff --git a/app/routers/dayview.py b/app/routers/dayview.py index 2894eaa2..626600ec 100644 --- a/app/routers/dayview.py +++ b/app/routers/dayview.py @@ -6,8 +6,9 @@ from app.database.models import Event, Task, User from app.dependencies import get_db, templates -from app.internal import international_days, zodiac +from app.internal import hebrew_date_view, international_days, zodiac from app.internal.security.dependencies import current_user +from app.internal.utils import get_user from app.routers.user import get_all_user_events router = APIRouter() @@ -198,6 +199,11 @@ async def dayview( except ValueError as err: raise HTTPException(status_code=404, detail=f"{err}") zodiac_obj = zodiac.get_zodiac_of_day(session, day) + user_from_db = get_user(session, user.user_id) + hebrew_obj = hebrew_date_view.get_hebrew_date_in_words( + day.date(), + user_from_db.language_id, + ) events_with_attrs = get_events_and_attributes( day=day, session=session, @@ -211,10 +217,8 @@ async def dayview( current_time_with_attrs = CurrentTimeAttributes(date=day) inter_day = international_days.get_international_day_per_day(session, day) tasks = ( - session.query(Task) - .filter(Task.owner_id == user.user_id) - .filter(Task.date == day.date()) - .order_by(Task.time) + session.query(Task).filter(Task.owner_id == user.user_id).filter( + Task.date == day.date()).order_by(Task.time) ) month = day.strftime("%B").upper() return templates.TemplateResponse( @@ -229,6 +233,7 @@ async def dayview( "international_day": inter_day, "zodiac": zodiac_obj, "view": view, + "hebrew_view": hebrew_obj, "current_time": current_time_with_attrs, "tasks": tasks, }, diff --git a/app/static/dayview.css b/app/static/dayview.css index 3cde2aa8..c78acf46 100644 --- a/app/static/dayview.css +++ b/app/static/dayview.css @@ -167,8 +167,6 @@ body { position: absolute; right: 0.5rem; bottom: 0.5rem; - margin-bottom: 1.5em; - z-index: 60; } .plus_image { @@ -181,6 +179,26 @@ body { height: 1.2rem; } +.hebrew-dates { + position: absolute; + right: 1.2rem; + top: 5rem; + padding-right: var(--space_xs); + padding-left: var(--space_xs); + padding-bottom: var(--space_xxs); + border: solid 0.1px var(--primary); + background-color: var(--surface-variant); + box-shadow: 1px 1px 2px #999; + line-height: 1; + height: 3.5rem; + width: 3.5rem; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.8rem; + font-weight: bold; +} + #current_time_cursor { border-bottom: 2.5px dotted rgba(255, 0, 0, 0.808); } diff --git a/app/templates/calendar_day_view.html b/app/templates/calendar_day_view.html index 272e3558..9829f70d 100644 --- a/app/templates/calendar_day_view.html +++ b/app/templates/calendar_day_view.html @@ -21,6 +21,11 @@ alt="zodiac sign" width="14em" height="13em"> {% endif %} + {% if hebrew_view %} +
+ {{ hebrew_view }} +
+ {% endif %} {% else %} {{day}} / {{month}} {% endif %} diff --git a/requirements.txt b/requirements.txt index 9612912e..4c6e9df4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -56,6 +56,7 @@ google-auth-oauthlib==0.4.2 googleapis-common-protos==1.52.0 h11==0.12.0 h2==4.0.0 +python-hebrew-numbers==0.2.3 hiredis==1.1.0 hpack==4.0.0 httpcore==0.12.2 @@ -107,6 +108,7 @@ pycparser==2.20 pydantic==1.7.3 pyflakes==2.2.0 PyJWT==2.0.0 +pyluach==1.2.1 pyparsing==2.4.7 pytest==6.2.1 pytest-asyncio==0.12.0 diff --git a/tests/test_hebrew_date.py b/tests/test_hebrew_date.py new file mode 100644 index 00000000..6ed6e776 --- /dev/null +++ b/tests/test_hebrew_date.py @@ -0,0 +1,43 @@ +from datetime import datetime + +import pytest +from pyluach import dates + +from app.internal.hebrew_date_view import ( + from_gregorian_to_hebrew_date, + get_hebrew_date_in_words, + get_month_name_by_num +) +from app.internal.languages import set_ui_language + +DAY = datetime.strptime("2021-01-01", "%Y-%m-%d").date() +ADAR = datetime.strptime("2021-02-15", "%Y-%m-%d").date() +ADAR_A = datetime.strptime("2019-02-15", "%Y-%m-%d").date() +ADAR_B = datetime.strptime("2019-03-08", "%Y-%m-%d").date() + +TRANSLATION_DATES = [ + (1, "en", "17 Teves 5781"), + (2, "he", "י״ז טבת תשפ״א"), +] + + +@pytest.mark.parametrize( + "language_id, language_code, expected_translation", TRANSLATION_DATES +) +def test_get_hebrew_date(language_id, language_code, expected_translation): + set_ui_language(language_code) + result = get_hebrew_date_in_words(DAY, language_id) + assert result == expected_translation + + +def test_from_gregorian_to_hebrew_date_and_find_month_name(): + result = from_gregorian_to_hebrew_date(ADAR) + assert result == dates.HebrewDate(5781, 12, 3) + assert get_month_name_by_num(result) == "Adar" + + +def test_if_leap_year(): + result_a = from_gregorian_to_hebrew_date(ADAR_A) + result_b = from_gregorian_to_hebrew_date(ADAR_B) + assert get_month_name_by_num(result_a) == "Adar Rishon" + assert get_month_name_by_num(result_b) == "Adar Sheni"