Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update United Kingdom & Isle of Man holidays: add l10n support #2258

Merged
merged 8 commits into from
Feb 10, 2025
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
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ All other default values are highlighted with bold:
* - Isle of Man
- IM
-
-
- **en_GB**, en_US, th
-
* - Israel
- IL
Expand Down Expand Up @@ -913,7 +913,7 @@ All other default values are highlighted with bold:
* - United Kingdom
- GB
- Subdivisions: ENG (England), NIR (Northern Ireland), SCT (Scotland), WLS (Wales)
-
- **en_GB**, en_US, th
-
* - United States Minor Outlying Islands
- UM
Expand Down
26 changes: 15 additions & 11 deletions holidays/countries/isle_of_man.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
# Website: https://github.com/vacanza/holidays
# License: MIT (see LICENSE file)

from gettext import gettext as tr

from holidays.countries.united_kingdom import UnitedKingdom, UnitedKingdomStaticHolidays
from holidays.groups import ChristianHolidays, InternationalHolidays, StaticHolidays
from holidays.observed_holiday_base import ObservedHolidayBase, SAT_SUN_TO_NEXT_MON
Expand All @@ -19,6 +21,7 @@ class IsleOfMan(UnitedKingdom):
"""Using existing code in UnitedKingdom for now."""

country = "IM"
parent_entity = UnitedKingdom
subdivisions = () # Override UnitedKingdom subdivisions.
subdivisions_aliases = {} # Override UnitedKingdom subdivisions aliases.

Expand All @@ -31,25 +34,26 @@ def __init__(self, *args, **kwargs): # Override UnitedKingdom __init__().

def _populate_public_holidays(self) -> None:
super()._populate_public_holidays()
# Easter Monday
self._add_easter_monday("Easter Monday")
# Easter Monday.
self._add_easter_monday(tr("Easter Monday"))

# Whit Monday.
if self._year <= 1970:
self._add_whit_monday("Whit Monday")
# Whit Monday.
self._add_whit_monday(tr("Whit Monday"))

# Late Summer bank holiday (last Monday in August)
if self._year >= 1971:
self._add_holiday_last_mon_of_aug("Late Summer Bank Holiday")
# Late Summer Bank Holiday.
self._add_holiday_last_mon_of_aug(tr("Late Summer Bank Holiday"))

# Isle of Man exclusive holidays
# TT bank holiday (first Friday in June)
self._add_holiday_1st_fri_of_jun("TT Bank Holiday")

# Tynwald Day
# Move to the next Monday if falls on a weekend.
jul_5 = self._add_holiday_jul_5("Tynwald Day")
# TT Bank Holiday.
self._add_holiday_1st_fri_of_jun(tr("TT Bank Holiday"))

# Tynwald Day.
jul_5 = self._add_holiday_jul_5(tr("Tynwald Day"))
if self._year >= 1992:
# Move to the next Monday if falls on a weekend.
self._move_holiday(jul_5, show_observed_label=False)


Expand Down
128 changes: 72 additions & 56 deletions holidays/countries/united_kingdom.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
# Website: https://github.com/vacanza/holidays
# License: MIT (see LICENSE file)

from gettext import gettext as tr
from typing import Union

from holidays.calendars.gregorian import APR, MAY, JUN, JUL, SEP, DEC
Expand Down Expand Up @@ -37,7 +38,9 @@ class UnitedKingdom(ObservedHolidayBase, ChristianHolidays, InternationalHoliday
"""

country = "GB"
observed_label = "%s (observed)"
default_language = "en_GB"
# %s (observed).
observed_label = tr("%s (observed)")
subdivisions: Union[tuple[()], tuple[str, ...]] = (
"ENG", # England
"NIR", # Northern Ireland
Expand All @@ -50,6 +53,7 @@ class UnitedKingdom(ObservedHolidayBase, ChristianHolidays, InternationalHoliday
"Scotland": "SCT",
"Wales": "WLS",
}
supported_languages = ("en_GB", "en_US", "th")
_deprecated_subdivisions = ("UK",)
# Bank Holidays Act 1871
start_year = 1872
Expand All @@ -64,120 +68,123 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def _populate_public_holidays(self) -> None:
# Good Friday
self._add_good_friday("Good Friday")
# Good Friday.
self._add_good_friday(tr("Good Friday"))

# May Day bank holiday (first Monday in May)
if self._year >= 1978:
name = "May Day"
# May Day.
name = tr("May Day")
if self._year in {1995, 2020}:
self._add_holiday_may_8(name)
else:
self._add_holiday_1st_mon_of_may(name)

# Spring bank holiday (last Monday in May)
if self._year >= 1971:
spring_bank_dates = {
2002: (JUN, 4),
2012: (JUN, 4),
2022: (JUN, 2),
}
name = "Spring Bank Holiday"
# Spring Bank Holiday.
name = tr("Spring Bank Holiday")
if self._year in spring_bank_dates:
self._add_holiday(name, spring_bank_dates[self._year])
else:
self._add_holiday_last_mon_of_may(name)

def _populate_subdiv_holidays(self):
if self.subdiv != "SCT":
# New Year's Day
if self._year >= 1975:
self._add_observed(self._add_new_years_day("New Year's Day"))
# New Year's Day.
self._add_observed(self._add_new_years_day(tr("New Year's Day")))

# Christmas Day
self._add_observed(
self._add_christmas_day("Christmas Day"), rule=SAT_SUN_TO_NEXT_MON_TUE
# Christmas Day.
self._add_christmas_day(tr("Christmas Day")),
rule=SAT_SUN_TO_NEXT_MON_TUE,
)

# Boxing Day
self._add_observed(
self._add_christmas_day_two("Boxing Day"), rule=SAT_SUN_TO_NEXT_MON_TUE
# Boxing Day.
self._add_christmas_day_two(tr("Boxing Day")),
rule=SAT_SUN_TO_NEXT_MON_TUE,
)

super()._populate_subdiv_holidays()

def _populate_subdiv_eng_public_holidays(self):
# Easter Monday
self._add_easter_monday("Easter Monday")
# Easter Monday.
self._add_easter_monday(tr("Easter Monday"))

# Whit Monday.
if self._year <= 1970:
self._add_whit_monday("Whit Monday")
# Whit Monday.
self._add_whit_monday(tr("Whit Monday"))

# Late Summer bank holiday (last Monday in August)
if self._year >= 1971:
self._add_holiday_last_mon_of_aug("Late Summer Bank Holiday")
# Late Summer Bank Holiday.
self._add_holiday_last_mon_of_aug(tr("Late Summer Bank Holiday"))

def _populate_subdiv_nir_public_holidays(self):
if self._year >= 1903:
# Saint Patrick's Day
self._add_observed(self._add_holiday_mar_17("Saint Patrick's Day"))
# Saint Patrick's Day.
self._add_observed(self._add_holiday_mar_17(tr("Saint Patrick's Day")))

# Easter Monday
self._add_easter_monday("Easter Monday")
# Easter Monday.
self._add_easter_monday(tr("Easter Monday"))

# Whit Monday.
if self._year <= 1970:
self._add_whit_monday("Whit Monday")
# Whit Monday.
self._add_whit_monday(tr("Whit Monday"))

# Battle of the Boyne
self._add_observed(self._add_holiday_jul_12("Battle of the Boyne"))
# Battle of the Boyne.
self._add_observed(self._add_holiday_jul_12(tr("Battle of the Boyne")))

# Late Summer bank holiday (last Monday in August)
if self._year >= 1971:
self._add_holiday_last_mon_of_aug("Late Summer Bank Holiday")
# Late Summer Bank Holiday.
self._add_holiday_last_mon_of_aug(tr("Late Summer Bank Holiday"))

def _populate_subdiv_sct_public_holidays(self):
# New Year's Day
jan_1 = self._add_new_years_day("New Year's Day")
# New Year's Day.
jan_1 = self._add_new_years_day(tr("New Year's Day"))

# New Year Holiday
self._add_observed(
self._add_new_years_day_two("New Year Holiday"),
# New Year Holiday.
self._add_new_years_day_two(tr("New Year Holiday")),
rule=SAT_SUN_TO_NEXT_MON_TUE + MON_TO_NEXT_TUE,
)
self._add_observed(jan_1)

# Summer bank holiday (first Monday in August)
self._add_holiday_1st_mon_of_aug("Summer Bank Holiday")
# Summer Bank Holiday.
self._add_holiday_1st_mon_of_aug(tr("Summer Bank Holiday"))

if self._year >= 2006:
# Saint Andrew's Day
self._add_observed(self._add_holiday_nov_30("Saint Andrew's Day"))
# Saint Andrew's Day.
self._add_observed(self._add_holiday_nov_30(tr("Saint Andrew's Day")))

# Christmas Day
self._add_observed(
self._add_christmas_day("Christmas Day"),
# Christmas Day.
self._add_christmas_day(tr("Christmas Day")),
rule=SAT_SUN_TO_NEXT_MON_TUE if self._year >= 1974 else SAT_SUN_TO_NEXT_MON,
)

if self._year >= 1974:
# Boxing Day
self._add_observed(
self._add_christmas_day_two("Boxing Day"), rule=SAT_SUN_TO_NEXT_MON_TUE
# Boxing Day.
self._add_christmas_day_two(tr("Boxing Day")),
rule=SAT_SUN_TO_NEXT_MON_TUE,
)

def _populate_subdiv_wls_public_holidays(self):
# Easter Monday
self._add_easter_monday("Easter Monday")
# Easter Monday.
self._add_easter_monday(tr("Easter Monday"))

# Whit Monday.
if self._year <= 1970:
self._add_whit_monday("Whit Monday")
# Whit Monday.
self._add_whit_monday(tr("Whit Monday"))

# Late Summer bank holiday (last Monday in August)
if self._year >= 1971:
self._add_holiday_last_mon_of_aug("Late Summer Bank Holiday")
# Late Summer Bank Holiday.
self._add_holiday_last_mon_of_aug(tr("Late Summer Bank Holiday"))


class UK(UnitedKingdom):
Expand All @@ -194,15 +201,24 @@ class GBR(UnitedKingdom):

class UnitedKingdomStaticHolidays:
special_public_holidays = {
1977: (JUN, 7, "Silver Jubilee of Elizabeth II"),
1981: (JUL, 29, "Wedding of Charles and Diana"),
1999: (DEC, 31, "Millennium Celebrations"),
2002: (JUN, 3, "Golden Jubilee of Elizabeth II"),
2011: (APR, 29, "Wedding of William and Catherine"),
2012: (JUN, 5, "Diamond Jubilee of Elizabeth II"),
# Silver Jubilee of Elizabeth II.
1977: (JUN, 7, tr("Silver Jubilee of Elizabeth II")),
# Wedding of Charles and Diana.
1981: (JUL, 29, tr("Wedding of Charles and Diana")),
# Millennium Celebrations.
1999: (DEC, 31, tr("Millennium Celebrations")),
# Golden Jubilee of Elizabeth II.
2002: (JUN, 3, tr("Golden Jubilee of Elizabeth II")),
# Wedding of William and Catherine.
2011: (APR, 29, tr("Wedding of William and Catherine")),
# Diamond Jubilee of Elizabeth II.
2012: (JUN, 5, tr("Diamond Jubilee of Elizabeth II")),
2022: (
(JUN, 3, "Platinum Jubilee of Elizabeth II"),
(SEP, 19, "State Funeral of Queen Elizabeth II"),
# Platinum Jubilee of Elizabeth II.
(JUN, 3, tr("Platinum Jubilee of Elizabeth II")),
# State Funeral of Queen Elizabeth II.
(SEP, 19, tr("State Funeral of Queen Elizabeth II")),
),
2023: (MAY, 8, "Coronation of Charles III"),
# Coronation of Charles III.
2023: (MAY, 8, tr("Coronation of Charles III")),
}
36 changes: 27 additions & 9 deletions holidays/holiday_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ def _populate(self, year):
"""Start year of holidays presence for this entity."""
end_year: int = DEFAULT_END_YEAR
"""End year of holidays presence for this entity."""
parent_entity: Optional[type["HolidayBase"]] = None
"""Optional parent entity to reference as a base."""

def __init__(
self,
Expand Down Expand Up @@ -364,16 +366,32 @@ def __init__(
self.weekend_workdays = getattr(self, "weekend_workdays", set())

supported_languages = set(self.supported_languages)
self.tr = (
translation(
if self._entity_code is not None:
fallback = language not in supported_languages
languages = [language] if language in supported_languages else None
locale_directory = str(Path(__file__).with_name("locale"))

# Add entity native content translations.
entity_translation = translation(
self._entity_code,
fallback=language not in supported_languages,
languages=[language] if language in supported_languages else None,
localedir=str(Path(__file__).with_name("locale")),
).gettext
if self._entity_code is not None
else gettext
)
fallback=fallback,
languages=languages,
localedir=locale_directory,
)
# Add a fallback if entity has parent translations.
if parent_entity := self.parent_entity:
entity_translation.add_fallback(
translation(
parent_entity.country or parent_entity.market,
fallback=fallback,
languages=languages,
localedir=locale_directory,
)
)
self.tr = entity_translation.gettext
else:
self.tr = gettext

self.years = _normalize_arguments(int, years)

# Populate holidays.
Expand Down
Loading