From cecb36c6a4185974d775024f546ba3cc4d34c7e7 Mon Sep 17 00:00:00 2001 From: Jordan Hall Date: Sat, 18 Jul 2026 05:21:53 +0100 Subject: [PATCH] Fix language loading and lookups --- .github/workflows/tests.yml | 30 +++++ README.md | 30 +++-- composer.json | 17 ++- phpunit.xml.dist | 8 ++ src/Language.php | 222 ++++++++++++++++++++++++++++++++++++ src/Languages.php | 157 ------------------------- tests/LanguageTest.php | 61 ++++++++++ 7 files changed, 352 insertions(+), 173 deletions(-) create mode 100644 .github/workflows/tests.yml create mode 100644 phpunit.xml.dist create mode 100644 src/Language.php delete mode 100644 src/Languages.php create mode 100644 tests/LanguageTest.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..b2a9331 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,30 @@ +name: Tests + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + test: + name: phpunit (${{ matrix.php }}, ${{ matrix.composer }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - php: '7.0' + composer: v2.2 + - php: '8.5' + composer: latest + steps: + - uses: actions/checkout@v4 + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: composer:${{ matrix.composer }} + coverage: none + - run: composer update --prefer-dist --no-interaction --no-progress + - run: vendor/bin/phpunit diff --git a/README.md b/README.md index d76519a..4d8ff32 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,12 @@ composer require jord-jd/php-languages ## Usage -First, you need to get a `Language` object. You can get object by -language name or ISO code. You can also find all languages that belong -to a particular family. +Get a `Language` object by its English name, native name, or ISO code. You can +also find every language in a family. Lookups trim surrounding whitespace and +are case-insensitive. ```php -use \JordJD\Languages\Language; +use JordJD\Languages\Language; $language = Language::getByName('German'); $language = Language::getByNativeName('Deutsch'); @@ -26,17 +26,23 @@ $language = Language::getByIso639_2_t('deu'); $language = Language::getByIso639_2_b('ger'); $language = Language::getByIso639_3('deu'); $languages = Language::getByFamily('Indo-European'); +$languages = Language::all(); ``` +The ISO methods also have aliases without underscores, such as +`Language::getByIso6391('de')` and `Language::getByIso6393('deu')`. A single +language lookup returns `null` when there is no match; family lookups return an +empty array. + Once you have your `Language` object, you can access its various public properties to yield information about the language. ```php -echo $language->family; // German -echo $language->name; // Deutsch -echo $language->nativeName; // de -echo $language->iso639_1; // deu -echo $language->iso639_2_t; // ger -echo $language->iso639_2_b; // deu -echo $language->iso639_3; // Indo-European -``` \ No newline at end of file +echo $language->family; // Indo-European +echo $language->name; // German +echo $language->nativeName; // Deutsch +echo $language->iso639_1; // de +echo $language->iso639_2_t; // deu +echo $language->iso639_2_b; // ger +echo $language->iso639_3; // deu +``` diff --git a/composer.json b/composer.json index e984c80..5e8bc3d 100644 --- a/composer.json +++ b/composer.json @@ -11,17 +11,26 @@ ], "autoload": { "psr-4": { - "JordJD\\Languages\\": "./src/" + "JordJD\\Languages\\": "src/" } }, - "require": {}, + "require": { + "php": ">=7.0" + }, "replace": { "divineomega/php-languages": "self.version" }, "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.1-dev" } }, - "require-dev": {} + "require-dev": { + "phpunit/phpunit": "^6.5||^9.6||^10.5||^11.5||^12.5" + }, + "config": { + "allow-plugins": { + "kylekatarnls/update-helper": false + } + } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..aa8b53d --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,8 @@ + + + + + tests + + + diff --git a/src/Language.php b/src/Language.php new file mode 100644 index 0000000..fddd05d --- /dev/null +++ b/src/Language.php @@ -0,0 +1,222 @@ +family = trim($row[0]); + $language->name = trim($row[1]); + $language->nativeName = trim($row[2]); + $language->iso639_1 = trim($row[3]); + $language->iso639_2_t = trim($row[4]); + $language->iso639_2_b = trim($row[5]); + $language->iso639_3 = trim($row[6]); + + self::$languages[] = $language; + } + } finally { + fclose($handle); + } + + return self::$languages; + } + + /** + * @param string $field + * @param string $value + * + * @return Language|null + */ + private static function getBy($field, $value) + { + $matches = self::getMultipleBy($field, $value); + + return isset($matches[0]) ? $matches[0] : null; + } + + /** + * @param string $field + * @param string $value + * + * @return Language[] + */ + private static function getMultipleBy($field, $value) + { + $matches = []; + $value = trim($value); + + foreach (self::languages() as $language) { + if (strcasecmp($language->$field, $value) === 0) { + $matches[] = clone $language; + } + } + + return $matches; + } + + /** + * @return Language[] + */ + public static function getByFamily(string $family) + { + return self::getMultipleBy('family', $family); + } + + /** + * @return Language|null + */ + public static function getByName(string $name) + { + return self::getBy('name', $name); + } + + /** + * @return Language|null + */ + public static function getByNativeName(string $nativeName) + { + return self::getBy('nativeName', $nativeName); + } + + /** + * @return Language|null + */ + public static function getByIso639_1(string $iso639_1) + { + return self::getBy('iso639_1', $iso639_1); + } + + /** + * @return Language|null + */ + public static function getByIso639_2_t(string $iso639_2_t) + { + return self::getBy('iso639_2_t', $iso639_2_t); + } + + /** + * @return Language|null + */ + public static function getByIso639_2_b(string $iso639_2_b) + { + return self::getBy('iso639_2_b', $iso639_2_b); + } + + /** + * @return Language|null + */ + public static function getByIso639_3(string $iso639_3) + { + return self::getBy('iso639_3', $iso639_3); + } + + /** + * Alias using a method name without underscores. + * + * @return Language|null + */ + public static function getByIso6391(string $iso639_1) + { + return self::getByIso639_1($iso639_1); + } + + /** + * Alias using a method name without underscores. + * + * @return Language|null + */ + public static function getByIso6392T(string $iso639_2_t) + { + return self::getByIso639_2_t($iso639_2_t); + } + + /** + * Alias using a method name without underscores. + * + * @return Language|null + */ + public static function getByIso6392B(string $iso639_2_b) + { + return self::getByIso639_2_b($iso639_2_b); + } + + /** + * Alias using a method name without underscores. + * + * @return Language|null + */ + public static function getByIso6393(string $iso639_3) + { + return self::getByIso639_3($iso639_3); + } +} diff --git a/src/Languages.php b/src/Languages.php deleted file mode 100644 index 256ebaf..0000000 --- a/src/Languages.php +++ /dev/null @@ -1,157 +0,0 @@ -family = $row[0]; - $language->name = $row[1]; - $language->nativeName = $row[2]; - $language->iso639_1 = $row[3]; - $language->iso639_2_t = $row[4]; - $language->iso639_2_b = $row[5]; - $language->iso639_3 = $row[6]; - - $languages[] = $language; - } - - return $languages; - } - - /** - * Get Language class with specific field and value - * - * @param string $field - * @param string $value - * - * @return Language|null - */ - private static function getBy(string $field, string $value) - { - foreach(self::all() as $language) { - if ($language->$field == $value) { - return $language; - } - } - - return null; - } - - /** - * Get multiple languanges informations with specific field and value - * - * @param string $field - * @param string $value - * - * @return array - */ - private static function getMultipleBy(string $field, string $value) - { - $languages = []; - - foreach(self::all() as $language) { - if ($language->$field == $value) { - $languages[] = $language; - } - } - - return $languages; - } - - /** - * Get languages with specific family - * - * @param string $family - * - * @return array - */ - public static function getByFamily(string $family) - { - return self::getMultipleBy('family', $family); - } - - /** - * Get language with name - * - * @param string $name - * - * @return Language|null - */ - public static function getByName(string $name) - { - return self::getBy('name', $name); - } - - /** - * Get language with native name - * - * @param string $nativeName - * - * @return Language|null - */ - public static function getByNativeName(string $nativeName) - { - return self::getBy('nativeName', $nativeName); - } - - /** - * Get language with specific iso639_1 encoding - * - * @param string $iso639_1 - * - * @return Language|null - */ - public static function getByIso639_1(string $iso639_1) - { - return self::getBy('iso639_1', $iso639_1); - } - - /** - * Get language with specific iso639_2_t encoding - * - * @param string $iso639_2_t - * - * @return Language|null - */ - public static function getByIso639_2_t(string $iso639_2_t) - { - return self::getBy('iso639_2_t', $iso639_2_t); - } - - /** - * Get language with specific iso639_2_b encoding - * - * @param string $iso639_2_b - * - * @return Language|null - */ - public static function getByIso639_2_b(string $iso639_2_b) - { - return self::getBy('iso639_2_b', $iso639_2_b); - } - - /** - * Get language with specific iso639_3 encoding - * - * @param string $iso639_3 - * - * @return Language|null - */ - public static function getByIso639_3(string $iso639_3) - { - return self::getBy('iso639_3', $iso639_3); - } -} diff --git a/tests/LanguageTest.php b/tests/LanguageTest.php new file mode 100644 index 0000000..cd83fec --- /dev/null +++ b/tests/LanguageTest.php @@ -0,0 +1,61 @@ +assertCount(185, $languages); + $this->assertSame('Abkhazian', $languages[0]->name); + $this->assertSame('Zulu', $languages[count($languages) - 1]->name); + } + + public function testLanguageCanBeFoundByEveryGermanIdentifier() + { + $this->assertGerman(Language::getByName(' german ')); + $this->assertGerman(Language::getByNativeName('Deutsch')); + $this->assertGerman(Language::getByIso639_1('DE')); + $this->assertGerman(Language::getByIso639_2_t('deu')); + $this->assertGerman(Language::getByIso639_2_b('ger')); + $this->assertGerman(Language::getByIso639_3('deu')); + $this->assertGerman(Language::getByIso6391('de')); + $this->assertGerman(Language::getByIso6393('deu')); + } + + public function testFamilyLookupAndMissingValuesHavePredictableResults() + { + $this->assertNotEmpty(Language::getByFamily('indo-european')); + $this->assertSame([], Language::getByFamily('Not a family')); + $this->assertNull(Language::getByName('Not a language')); + } + + public function testReturnedObjectsCannotMutateLaterResults() + { + $language = Language::getByIso6391('de'); + $language->name = 'Changed'; + + $this->assertSame('German', Language::getByIso6391('de')->name); + + $all = Language::all(); + $all[0]->name = 'Changed'; + + $this->assertSame('Abkhazian', Language::all()[0]->name); + } + + private function assertGerman(Language $language) + { + $this->assertSame('Indo-European', $language->family); + $this->assertSame('German', $language->name); + $this->assertSame('Deutsch', $language->nativeName); + $this->assertSame('de', $language->iso639_1); + $this->assertSame('deu', $language->iso639_2_t); + $this->assertSame('ger', $language->iso639_2_b); + $this->assertSame('deu', $language->iso639_3); + } +}