diff --git a/i18n/i18n.php b/i18n/i18n.php index 3ede6ee56..e0b121eda 100644 --- a/i18n/i18n.php +++ b/i18n/i18n.php @@ -2208,6 +2208,24 @@ class i18n extends Object implements TemplateGlobalProvider { return (array)Config::inst()->get('i18n', 'all_locales'); } + /** + * Matches a given locale with the closest translation available in the system + * + * @param string $locale locale code + * @return string Locale of closest available translation, if available + */ + public static function get_closest_translation($locale) { + + // Check if exact match + $pool = self::get_existing_translations(); + if(isset($pool[$locale])) return $locale; + + // Fallback to best locale for common language + $lang = self::get_lang_from_locale($locale); + $candidate = self::get_locale_from_lang($lang); + if(isset($pool[$candidate])) return $candidate; + } + /** * Searches the root-directory for module-directories * (identified by having a _config.php on their first directory-level). diff --git a/security/Member.php b/security/Member.php index 966af2b7e..0f5b0f0d5 100644 --- a/security/Member.php +++ b/security/Member.php @@ -176,7 +176,7 @@ class Member extends DataObject implements TemplateGlobalProvider { */ public function populateDefaults() { parent::populateDefaults(); - $this->Locale = i18n::get_locale(); + $this->Locale = i18n::get_closest_translation(i18n::get_locale()); } public function requireDefaultRecords() { diff --git a/tests/i18n/i18nTest.php b/tests/i18n/i18nTest.php index fd98cbf82..1d2cc131c 100644 --- a/tests/i18n/i18nTest.php +++ b/tests/i18n/i18nTest.php @@ -102,6 +102,32 @@ class i18nTest extends SapphireTest { $this->assertTrue(isset($translations['de_DE']), 'Checking for de_DE translation'); } + public function testGetClosestTranslation() { + + // Validate necessary assumptions for this test + $translations = i18n::get_existing_translations(); + $this->assertTrue(isset($translations['en_US'])); + $this->assertTrue(isset($translations['en_GB'])); + $this->assertTrue(isset($translations['es_ES'])); + $this->assertTrue(isset($translations['es_AR'])); + $this->assertFalse(isset($translations['en_ZZ'])); + $this->assertFalse(isset($translations['es_ZZ'])); + $this->assertFalse(isset($translations['zz_ZZ'])); + + // Test indeterminate locales + $this->assertEmpty(i18n::get_closest_translation('zz_ZZ')); + + // Test english fallback + $this->assertEquals('en_US', i18n::get_closest_translation('en_US')); + $this->assertEquals('en_GB', i18n::get_closest_translation('en_GB')); + $this->assertEquals('en_US', i18n::get_closest_translation('en_ZZ')); + + // Test spanish fallbacks + $this->assertEquals('es_AR', i18n::get_closest_translation('es_AR')); + $this->assertEquals('es_ES', i18n::get_closest_translation('es_ES')); + $this->assertEquals('es_ES', i18n::get_closest_translation('es_XX')); + } + public function testDataObjectFieldLabels() { $oldLocale = i18n::get_locale(); i18n::set_locale('de_DE');