Skip to content

Commit

Permalink
Merge pull request #177 from spatie/feature/localization
Browse files Browse the repository at this point in the history
Add support for multi languages
  • Loading branch information
Nielsvanpach authored Jan 24, 2024
2 parents f12d09f + faf22be commit 93bd4f6
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 10 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ use Spatie\Holidays\Holidays;
$holidays = Holidays::for(country: 'be', year: 2024))->get();
```

### Getting holidays in a specific language

```php
use Spatie\Holidays\Holidays;

$holidays = Holidays::for(country: 'be', locale: 'fr'))->get();
```

If the locale is not supported for a country, an exception will be thrown.

### Determining if a date is a holiday

If you need to see if a date is a holiday, you can use the `isHoliday` method.
Expand Down Expand Up @@ -112,6 +122,7 @@ This is a community driven package. If you find any errors, please create an iss
2. Add a test for the new country in the `tests` directory.
3. Run the tests so a snapshot gets created.
4. Verify the result in the newly created snapshot is correct.
5. If the country has multiple languages, add a file in the `lang/` directory.

In case your country has specific rules for calculating holidays,
for example region specific holidays, you can pass this to the constructor of your country class.
Expand Down
12 changes: 12 additions & 0 deletions lang/belgium/fr/holidays.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"Nieuwjaar": "Jour de l'An",
"Dag van de Arbeid": "Fête du Travail",
"Nationale Feestdag": "Fête nationale",
"OLV Hemelvaart": "Assomption",
"Allerheiligen": "Toussaint",
"Wapenstilstand": "Armistice",
"Kerstmis": "Noël",
"Paasmaandag": "Lundi de Pâques",
"OLH Hemelvaart": "Ascension",
"Pinkstermaandag": "Lundi de Pentecôte"
}
32 changes: 32 additions & 0 deletions src/Concerns/Translatable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Spatie\Holidays\Concerns;

use Spatie\Holidays\Exceptions\InvalidLocale;

trait Translatable
{
protected function translate(string $country, string $name, ?string $locale = null): string
{
if ($locale === null) {
return $name;
}

$countryName = strtolower($country);

$content = file_get_contents(__DIR__."/../../lang/{$countryName}/{$locale}/holidays.json");

if ($content === false) {
throw InvalidLocale::notFound($country, $locale);
}

/** @var array<string, string> $data */
$data = json_decode($content, true);

if (! isset($data[$name])) {
return $name;
}

return $data[$name];
}
}
18 changes: 12 additions & 6 deletions src/Countries/Country.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,42 @@
namespace Spatie\Holidays\Countries;

use Carbon\CarbonImmutable;
use Spatie\Holidays\Concerns\Translatable;
use Spatie\Holidays\Exceptions\InvalidYear;
use Spatie\Holidays\Exceptions\UnsupportedCountry;

abstract class Country
{
use Translatable;

abstract public function countryCode(): string;

/** @return array<string, string|CarbonImmutable> */
abstract protected function allHolidays(int $year): array;

/** @return array<string, CarbonImmutable|string> */
public function get(int $year): array
public function get(int $year, ?string $locale = null): array
{
$this->ensureYearCanBeCalculated($year);

$allHolidays = $this->allHolidays($year);

$allHolidays = array_map(function ($date) use ($year) {
$translatedHolidays = [];
foreach ($allHolidays as $name => $date) {
if (is_string($date)) {
$date = CarbonImmutable::createFromFormat('Y-m-d', "{$year}-{$date}");
}

return $date;
}, $allHolidays);
$name = $this->translate(basename(str_replace('\\', '/', static::class)), $name, $locale);

$translatedHolidays[$name] = $date;
}

uasort($allHolidays,
uasort($translatedHolidays,
fn (CarbonImmutable $a, CarbonImmutable $b) => $a->timestamp <=> $b->timestamp
);

return $allHolidays;
return $translatedHolidays;
}

public static function make(): static
Expand Down
13 changes: 13 additions & 0 deletions src/Exceptions/InvalidLocale.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Spatie\Holidays\Exceptions;

use RuntimeException;

class InvalidLocale extends RuntimeException
{
public static function notFound(string $country, string $locale): self
{
return new self("Locale `{$locale}` is not supported for country `{$country}`.");
}
}
9 changes: 5 additions & 4 deletions src/Holidays.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@ class Holidays
protected function __construct(
protected Country $country,
protected int $year,
protected ?string $locale = null,
) {
}

public static function for(Country|string $country, ?int $year = null): static
public static function for(Country|string $country, ?int $year = null, ?string $locale = null): static
{
$year ??= CarbonImmutable::now()->year;

if (is_string($country)) {
$country = Country::findOrFail($country);
}

return new static($country, $year);
return new static($country, $year, $locale);
}

public static function has(string $country): bool
Expand All @@ -39,7 +40,7 @@ public function get(Country|string|null $country = null, ?int $year = null): arr
$country ??= $this->country;
$year ??= $this->year;

return static::for($country, $year)
return static::for($country, $year, $this->locale)
->calculate()
->toArray();
}
Expand Down Expand Up @@ -91,7 +92,7 @@ public function getName(CarbonInterface|string $date, Country|string|null $count

protected function calculate(): self
{
$this->holidays = $this->country->get($this->year);
$this->holidays = $this->country->get($this->year, $this->locale);

return $this;
}
Expand Down
12 changes: 12 additions & 0 deletions tests/HolidaysTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use Carbon\CarbonImmutable;
use Spatie\Holidays\Countries\Belgium;
use Spatie\Holidays\Countries\Netherlands;
use Spatie\Holidays\Exceptions\InvalidLocale;
use Spatie\Holidays\Exceptions\InvalidYear;
use Spatie\Holidays\Exceptions\UnsupportedCountry;
use Spatie\Holidays\Holidays;
Expand Down Expand Up @@ -91,3 +92,14 @@
$result = Holidays::has(country: 'unknown');
expect($result)->toBeFalse();
});

it('can get translated holiday names', function () {
$result = Holidays::for(country: 'be', year: 2020, locale: 'fr')->get();

expect($result)->toBeArray();
expect($result[0]['name'])->toBe('Jour de l\'An');
});

it('cannot get translated holiday names for unsupported locales', function () {
Holidays::for(country: 'be', year: 2020, locale: 'en')->get();
})->throws(InvalidLocale::class, 'Locale `en` is not supported for country `Belgium`.');

0 comments on commit 93bd4f6

Please sign in to comment.