From 7e8cadc849042fc626375feee97096d05a3dbc0e Mon Sep 17 00:00:00 2001
From: Shibin Das <shibinkidd@gmail.com>
Date: Wed, 25 Dec 2024 23:41:14 +0100
Subject: [PATCH] Issue #3495996: Define all Plural Form Rules as Plugins as
 mentioned in Gettext Manual

---
 .../StringPluralForm/FiveFormsIrish.php       | 62 +++++++++++++++++
 .../StringPluralForm/FourFormsSlavicType4.php | 61 ++++++++++++++++
 src/Plugin/StringPluralForm/OnlyOneForm.php   | 61 ++++++++++++++++
 .../StringPluralForm/SixFormsArabic.php       | 69 +++++++++++++++++++
 .../StringPluralForm/ThreeFormsLithuanian.php | 60 ++++++++++++++++
 .../StringPluralForm/ThreeFormsRomanian.php   | 60 ++++++++++++++++
 .../ThreeFormsSlavicType1.php                 | 64 +++++++++++++++++
 .../ThreeFormsSlavicType2.php                 | 61 ++++++++++++++++
 .../ThreeFormsSlavicType3.php                 | 60 ++++++++++++++++
 .../ThreeFormsSpecialCaseForZero.php          | 60 ++++++++++++++++
 .../ThreeFormsSpecialCasesForOneAndTwo.php    | 60 ++++++++++++++++
 .../TwoFormsSingularForZeroAndOne.php         | 60 ++++++++++++++++
 12 files changed, 738 insertions(+)
 create mode 100644 src/Plugin/StringPluralForm/FiveFormsIrish.php
 create mode 100644 src/Plugin/StringPluralForm/FourFormsSlavicType4.php
 create mode 100644 src/Plugin/StringPluralForm/OnlyOneForm.php
 create mode 100644 src/Plugin/StringPluralForm/SixFormsArabic.php
 create mode 100644 src/Plugin/StringPluralForm/ThreeFormsLithuanian.php
 create mode 100644 src/Plugin/StringPluralForm/ThreeFormsRomanian.php
 create mode 100644 src/Plugin/StringPluralForm/ThreeFormsSlavicType1.php
 create mode 100644 src/Plugin/StringPluralForm/ThreeFormsSlavicType2.php
 create mode 100644 src/Plugin/StringPluralForm/ThreeFormsSlavicType3.php
 create mode 100644 src/Plugin/StringPluralForm/ThreeFormsSpecialCaseForZero.php
 create mode 100644 src/Plugin/StringPluralForm/ThreeFormsSpecialCasesForOneAndTwo.php
 create mode 100644 src/Plugin/StringPluralForm/TwoFormsSingularForZeroAndOne.php

diff --git a/src/Plugin/StringPluralForm/FiveFormsIrish.php b/src/Plugin/StringPluralForm/FiveFormsIrish.php
new file mode 100644
index 0000000..8a3705e
--- /dev/null
+++ b/src/Plugin/StringPluralForm/FiveFormsIrish.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace Drupal\string_plural_form\Plugin\StringPluralForm;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\string_plural_form\Attribute\StringPluralForm;
+use Drupal\string_plural_form\StringPluralFormBase;
+
+/**
+ * Provides a custom block plugin.
+ */
+#[StringPluralForm(
+  id: "five_forms_irish",
+  admin_label: new TranslatableMarkup("Five Forms, special case for one, two, 3..6, 7..10, [0, 11, 12, ...]"),
+  description: new TranslatableMarkup("Case in the language like Gaeilge (Irish)."),
+)]
+class FiveFormsIrish extends StringPluralFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextNplurals(): int {
+    return 5;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextPlural(): string {
+    return "(n==1 ? 0 : n==2 ? 1 : n>=3 && n<=6 ? 2 : n>=7 && n<=10 ? 3 : 4)";
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAssociatedLanguageCodes(): array {
+    return [
+      "ga",
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndex(int $n): int {
+    return ($n == 1 ? 0 : ($n == 2 ? 1 : ($n >= 3 && $n <= 6 ? 2 : ($n >= 7 && $n <= 10 ? 3 : 4))));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndexLabel(int $index): TranslatableMarkup {
+    return match($index) {
+      0 => new TranslatableMarkup("One"),
+      1 => new TranslatableMarkup("Two"),
+      2 => new TranslatableMarkup("3, 4, 5, 6"),
+      3 => new TranslatableMarkup("7, 8, 9, 10"),
+      4 => new TranslatableMarkup("0, 11, 12, 13..."),
+    };
+  }
+
+}
diff --git a/src/Plugin/StringPluralForm/FourFormsSlavicType4.php b/src/Plugin/StringPluralForm/FourFormsSlavicType4.php
new file mode 100644
index 0000000..3b5c760
--- /dev/null
+++ b/src/Plugin/StringPluralForm/FourFormsSlavicType4.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace Drupal\string_plural_form\Plugin\StringPluralForm;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\string_plural_form\Attribute\StringPluralForm;
+use Drupal\string_plural_form\StringPluralFormBase;
+
+/**
+ * Provides a custom block plugin.
+ */
+#[StringPluralForm(
+  id: "four_forms_slavic_type_4",
+  admin_label: new TranslatableMarkup("Four forms, special case for one and all numbers ending in 02, 03, or 04"),
+  description: new TranslatableMarkup("Case in some Slavic family language like Slovenian."),
+)]
+class FourFormsSlavicType4 extends StringPluralFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextNplurals(): int {
+    return 4;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextPlural(): string {
+    return "n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3";
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAssociatedLanguageCodes(): array {
+    return [
+      "sl",
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndex(int $n): int {
+    return $n % 100 == 1 ? 0 : ($n % 100 == 2 ? 1 : ($n % 100 == 3 || $n % 100 == 4 ? 2 : 3));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndexLabel(int $index): TranslatableMarkup {
+    return match($index) {
+      0 => new TranslatableMarkup("1, 101, 201, 301..."),
+      1 => new TranslatableMarkup("2, 102, 202, 302..."),
+      2 => new TranslatableMarkup("3, 4, 103, 104..."),
+      3 => new TranslatableMarkup("0, 5, 6, 7..."),
+    };
+  }
+
+}
diff --git a/src/Plugin/StringPluralForm/OnlyOneForm.php b/src/Plugin/StringPluralForm/OnlyOneForm.php
new file mode 100644
index 0000000..f3476db
--- /dev/null
+++ b/src/Plugin/StringPluralForm/OnlyOneForm.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace Drupal\string_plural_form\Plugin\StringPluralForm;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\string_plural_form\Attribute\StringPluralForm;
+use Drupal\string_plural_form\StringPluralFormBase;
+
+/**
+ * Provides a custom block plugin.
+ */
+#[StringPluralForm(
+  id: "only_one_form",
+  admin_label: new TranslatableMarkup("Only one form"),
+  description: new TranslatableMarkup("Some languages only require one single form. There is no distinction between the singular and plural form."),
+)]
+class OnlyOneForm extends StringPluralFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextNplurals(): int {
+    return 1;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextPlural(): string {
+    return "0";
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAssociatedLanguageCodes(): array {
+    return [
+      "ja",
+      "vi",
+      "ko",
+      "th",
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndex(int $n): int {
+    return 0;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndexLabel(int $index): TranslatableMarkup {
+    return match($index) {
+      0 => new TranslatableMarkup("All cases"),
+    };
+  }
+
+}
diff --git a/src/Plugin/StringPluralForm/SixFormsArabic.php b/src/Plugin/StringPluralForm/SixFormsArabic.php
new file mode 100644
index 0000000..acfd012
--- /dev/null
+++ b/src/Plugin/StringPluralForm/SixFormsArabic.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace Drupal\string_plural_form\Plugin\StringPluralForm;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\string_plural_form\Attribute\StringPluralForm;
+use Drupal\string_plural_form\StringPluralFormBase;
+
+/**
+ * Provides a custom block plugin.
+ */
+#[StringPluralForm(
+  id: "six_forms_arabic",
+  admin_label: new TranslatableMarkup("Six forms, special cases for one, two, all numbers ending in 02, 03, … 10, all numbers ending in 11 … 99, and others"),
+  description: new TranslatableMarkup("Case in some Afroasiatic family language like Arabic."),
+)]
+class SixFormsArabic extends StringPluralFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextNplurals(): int {
+    return 6;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextPlural(): string {
+    return "n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n>10 && n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5";
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAssociatedLanguageCodes(): array {
+    return [
+      "ar",
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndex(int $n): int {
+    $index = match ($n) {
+      0 => 0,
+      1 => 1,
+      2 => 2,
+      default =>  ($n>10 && $n%100>=3 && $n%100<=10) ? 3 : ($n%100>=11 ? 4 : 5)
+    };
+    return $index;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndexLabel(int $index): TranslatableMarkup {
+    return match($index) {
+      0 => new TranslatableMarkup("zero"),
+      1 => new TranslatableMarkup("one"),
+      2 => new TranslatableMarkup("two"),
+      3 => new TranslatableMarkup("all numbers ending in 02, 03, … 10"),
+      4 => new TranslatableMarkup("all numbers ending in 11 … 99"),
+      5 => new TranslatableMarkup("other cases"),
+    };
+  }
+
+}
diff --git a/src/Plugin/StringPluralForm/ThreeFormsLithuanian.php b/src/Plugin/StringPluralForm/ThreeFormsLithuanian.php
new file mode 100644
index 0000000..7e43580
--- /dev/null
+++ b/src/Plugin/StringPluralForm/ThreeFormsLithuanian.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\string_plural_form\Plugin\StringPluralForm;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\string_plural_form\Attribute\StringPluralForm;
+use Drupal\string_plural_form\StringPluralFormBase;
+
+/**
+ * Provides a custom block plugin.
+ */
+#[StringPluralForm(
+  id: "three_forms_lithuanian",
+  admin_label: new TranslatableMarkup("Three forms, special case for numbers ending in 1[2-9]"),
+  description: new TranslatableMarkup("Case in the Lithuanian language."),
+)]
+class ThreeFormsLithuanian extends StringPluralFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextNplurals(): int {
+    return 3;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextPlural(): string {
+    return "n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2";
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAssociatedLanguageCodes(): array {
+    return [
+      "lt",
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndex(int $n): int {
+    return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n % 10 >= 2 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndexLabel(int $index): TranslatableMarkup {
+    return match($index) {
+      0 => new TranslatableMarkup("1, 21, 31, 41..."),
+      1 => new TranslatableMarkup("2, 3, 4, 5, ..."),
+      2 => new TranslatableMarkup("0, 10, 11, 12..."),
+    };
+  }
+
+}
diff --git a/src/Plugin/StringPluralForm/ThreeFormsRomanian.php b/src/Plugin/StringPluralForm/ThreeFormsRomanian.php
new file mode 100644
index 0000000..eaf0957
--- /dev/null
+++ b/src/Plugin/StringPluralForm/ThreeFormsRomanian.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\string_plural_form\Plugin\StringPluralForm;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\string_plural_form\Attribute\StringPluralForm;
+use Drupal\string_plural_form\StringPluralFormBase;
+
+/**
+ * Provides a custom block plugin.
+ */
+#[StringPluralForm(
+  id: "three_forms_romanian",
+  admin_label: new TranslatableMarkup("Three forms, special case for numbers ending in 00 or [2-9][0-9]"),
+  description: new TranslatableMarkup("Case in the Romanian language."),
+)]
+class ThreeFormsRomanian extends StringPluralFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextNplurals(): int {
+    return 3;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextPlural(): string {
+    return "n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2";
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAssociatedLanguageCodes(): array {
+    return [
+      "ro",
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndex(int $n): int {
+    return $n == 1 ? 0 : (($n == 0 || ($n % 100 > 0 && $n % 100 < 20)) ? 1 : 2);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndexLabel(int $index): TranslatableMarkup {
+    return match($index) {
+      0 => new TranslatableMarkup("One"),
+      1 => new TranslatableMarkup("0, 2, 3, 4..."),
+      2 => new TranslatableMarkup("20, 21, 22, 23..."),
+    };
+  }
+
+}
diff --git a/src/Plugin/StringPluralForm/ThreeFormsSlavicType1.php b/src/Plugin/StringPluralForm/ThreeFormsSlavicType1.php
new file mode 100644
index 0000000..4b9dd77
--- /dev/null
+++ b/src/Plugin/StringPluralForm/ThreeFormsSlavicType1.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace Drupal\string_plural_form\Plugin\StringPluralForm;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\string_plural_form\Attribute\StringPluralForm;
+use Drupal\string_plural_form\StringPluralFormBase;
+
+/**
+ * Provides a custom block plugin.
+ */
+#[StringPluralForm(
+  id: "three_forms_slavic_type_1",
+  admin_label: new TranslatableMarkup("Three forms, special cases for numbers ending in 1 and 2, 3, 4, except those ending in 1[1-4]"),
+  description: new TranslatableMarkup("Case in some Slavic family language like Russian, Ukranian, etc."),
+)]
+class ThreeFormsSlavicType1 extends StringPluralFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextNplurals(): int {
+    return 3;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextPlural(): string {
+    return "n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2";
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAssociatedLanguageCodes(): array {
+    return [
+      "ru",
+      "uk",
+      "be",
+      "sr",
+      "hr",
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndex(int $n): int {
+    return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndexLabel(int $index): TranslatableMarkup {
+    return match($index) {
+      0 => new TranslatableMarkup("1, 21, 31, 41..."),
+      1 => new TranslatableMarkup("2, 3, 4, 22..."),
+      2 => new TranslatableMarkup("0, 5, 6, 7..."),
+    };
+  }
+
+}
diff --git a/src/Plugin/StringPluralForm/ThreeFormsSlavicType2.php b/src/Plugin/StringPluralForm/ThreeFormsSlavicType2.php
new file mode 100644
index 0000000..cc7980e
--- /dev/null
+++ b/src/Plugin/StringPluralForm/ThreeFormsSlavicType2.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace Drupal\string_plural_form\Plugin\StringPluralForm;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\string_plural_form\Attribute\StringPluralForm;
+use Drupal\string_plural_form\StringPluralFormBase;
+
+/**
+ * Provides a custom block plugin.
+ */
+#[StringPluralForm(
+  id: "three_forms_slavic_type_2",
+  admin_label: new TranslatableMarkup("Three forms, special cases for 1 and 2, 3, 4"),
+  description: new TranslatableMarkup("Case in some Slavic family language like Czech, Slovak."),
+)]
+class ThreeFormsSlavicType2 extends StringPluralFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextNplurals(): int {
+    return 3;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextPlural(): string {
+    return "(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2";
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAssociatedLanguageCodes(): array {
+    return [
+      "cs",
+      "sk",
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndex(int $n): int {
+    return ($n == 1) ? 0 : (($n >= 2 && $n <= 4) ? 1 : 2);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndexLabel(int $index): TranslatableMarkup {
+    return match($index) {
+      0 => new TranslatableMarkup("One"),
+      1 => new TranslatableMarkup("2, 3, 4"),
+      2 => new TranslatableMarkup("0, 5, 6, 7..."),
+    };
+  }
+
+}
diff --git a/src/Plugin/StringPluralForm/ThreeFormsSlavicType3.php b/src/Plugin/StringPluralForm/ThreeFormsSlavicType3.php
new file mode 100644
index 0000000..f2e202a
--- /dev/null
+++ b/src/Plugin/StringPluralForm/ThreeFormsSlavicType3.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\string_plural_form\Plugin\StringPluralForm;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\string_plural_form\Attribute\StringPluralForm;
+use Drupal\string_plural_form\StringPluralFormBase;
+
+/**
+ * Provides a custom block plugin.
+ */
+#[StringPluralForm(
+  id: "three_forms_slavic_type_3",
+  admin_label: new TranslatableMarkup("Three forms, special case for one and some numbers ending in 2, 3, or 4"),
+  description: new TranslatableMarkup("Case in some Slavic family language like Polish."),
+)]
+class ThreeFormsSlavicType3 extends StringPluralFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextNplurals(): int {
+    return 3;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextPlural(): string {
+    return "n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2";
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAssociatedLanguageCodes(): array {
+    return [
+      "pl",
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndex(int $n): int {
+    return $n == 1 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndexLabel(int $index): TranslatableMarkup {
+    return match($index) {
+      0 => new TranslatableMarkup("One"),
+      1 => new TranslatableMarkup("2, 3, 4, 22..."),
+      2 => new TranslatableMarkup("0, 5, 6, 7..."),
+    };
+  }
+
+}
diff --git a/src/Plugin/StringPluralForm/ThreeFormsSpecialCaseForZero.php b/src/Plugin/StringPluralForm/ThreeFormsSpecialCaseForZero.php
new file mode 100644
index 0000000..1793cf9
--- /dev/null
+++ b/src/Plugin/StringPluralForm/ThreeFormsSpecialCaseForZero.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\string_plural_form\Plugin\StringPluralForm;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\string_plural_form\Attribute\StringPluralForm;
+use Drupal\string_plural_form\StringPluralFormBase;
+
+/**
+ * Provides a custom block plugin.
+ */
+#[StringPluralForm(
+  id: "three_forms_special_case_for_zero",
+  admin_label: new TranslatableMarkup("Three forms, special case for zero"),
+  description: new TranslatableMarkup("Case in the language like Latvian."),
+)]
+class ThreeFormsSpecialCaseForZero extends StringPluralFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextNplurals(): int {
+    return 3;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextPlural(): string {
+    return "n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2";
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAssociatedLanguageCodes(): array {
+    return [
+      "lv",
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndex(int $n): int {
+    return $n % 10 == 1 && $n % 100 != 11 ? 0 : ($n != 0 ? 1 : 2);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndexLabel(int $index): TranslatableMarkup {
+    return match($index) {
+      0 => new TranslatableMarkup("0, 10, 11, 12..."),
+      1 => new TranslatableMarkup("1, 21, 31, 41..."),
+      2 => new TranslatableMarkup("2, 3, 4, 5..."),
+    };
+  }
+
+}
diff --git a/src/Plugin/StringPluralForm/ThreeFormsSpecialCasesForOneAndTwo.php b/src/Plugin/StringPluralForm/ThreeFormsSpecialCasesForOneAndTwo.php
new file mode 100644
index 0000000..e220475
--- /dev/null
+++ b/src/Plugin/StringPluralForm/ThreeFormsSpecialCasesForOneAndTwo.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\string_plural_form\Plugin\StringPluralForm;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\string_plural_form\Attribute\StringPluralForm;
+use Drupal\string_plural_form\StringPluralFormBase;
+
+/**
+ * Provides a custom block plugin.
+ */
+#[StringPluralForm(
+  id: "three_forms_special_cases_for_one_and_two",
+  admin_label: new TranslatableMarkup("Three forms, special cases for one and two"),
+  description: new TranslatableMarkup("Case in the language like Gaeilge (Irish)."),
+)]
+class ThreeFormsSpecialCasesForOneAndTwo extends StringPluralFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextNplurals(): int {
+    return 3;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextPlural(): string {
+    return "n==1 ? 0 : n==2 ? 1 : 2";
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAssociatedLanguageCodes(): array {
+    return [
+      "ga",
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndex(int $n): int {
+    return $n == 1 ? 0 : ($n == 2 ? 1 : 2);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndexLabel(int $index): TranslatableMarkup {
+    return match($index) {
+      0 => new TranslatableMarkup("One"),
+      1 => new TranslatableMarkup("Two"),
+      2 => new TranslatableMarkup("3, 4, 5..."),
+    };
+  }
+
+}
diff --git a/src/Plugin/StringPluralForm/TwoFormsSingularForZeroAndOne.php b/src/Plugin/StringPluralForm/TwoFormsSingularForZeroAndOne.php
new file mode 100644
index 0000000..f058c5c
--- /dev/null
+++ b/src/Plugin/StringPluralForm/TwoFormsSingularForZeroAndOne.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\string_plural_form\Plugin\StringPluralForm;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\string_plural_form\Attribute\StringPluralForm;
+use Drupal\string_plural_form\StringPluralFormBase;
+
+/**
+ * Provides a custom block plugin.
+ */
+#[StringPluralForm(
+  id: "two_forms_singular_for_zero_and_one",
+  admin_label: new TranslatableMarkup("Two forms, singular used for zero and one"),
+  description: new TranslatableMarkup("Exceptional case in the language family like Brazilian Portuguese and French."),
+)]
+class TwoFormsSingularForZeroAndOne extends StringPluralFormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextNplurals(): int {
+    return 2;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGettextPlural(): string {
+    return "n != 1";
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAssociatedLanguageCodes(): array {
+    return [
+      "pt",
+      "fr",
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndex(int $n): int {
+    return ($n > 1);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndexLabel(int $index): TranslatableMarkup {
+    return match($index) {
+      0 => new TranslatableMarkup("Zero, Singular"),
+      1 => new TranslatableMarkup("Plural"),
+    };
+  }
+
+}
-- 
GitLab