diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -545,10 +545,12 @@ 'phutil_get_library_root' => 'moduleutils/moduleutils.php', 'phutil_get_library_root_for_path' => 'moduleutils/moduleutils.php', 'phutil_get_signal_name' => 'future/exec/execx.php', + 'phutil_get_system_locale' => 'utils/utf8.php', 'phutil_hashes_are_identical' => 'utils/utils.php', 'phutil_implode_html' => 'markup/render.php', 'phutil_ini_decode' => 'utils/utils.php', 'phutil_is_hiphop_runtime' => 'utils/utils.php', + 'phutil_is_system_locale_available' => 'utils/utf8.php', 'phutil_is_utf8' => 'utils/utf8.php', 'phutil_is_utf8_slowly' => 'utils/utf8.php', 'phutil_is_utf8_with_only_bmp_characters' => 'utils/utf8.php', @@ -563,6 +565,7 @@ 'phutil_register_library' => 'moduleutils/core.php', 'phutil_register_library_map' => 'moduleutils/core.php', 'phutil_safe_html' => 'markup/render.php', + 'phutil_set_system_locale' => 'utils/utf8.php', 'phutil_split_lines' => 'utils/utils.php', 'phutil_tag' => 'markup/render.php', 'phutil_tag_div' => 'markup/render.php', diff --git a/src/utils/__tests__/PhutilUTF8TestCase.php b/src/utils/__tests__/PhutilUTF8TestCase.php --- a/src/utils/__tests__/PhutilUTF8TestCase.php +++ b/src/utils/__tests__/PhutilUTF8TestCase.php @@ -739,4 +739,70 @@ } } + public function testSystemLocaleManagement() { + $original_locale = phutil_get_system_locale(); + $this->assertTrue( + (strlen($original_locale) > 0), + pht('System has some identifiable locale.')); + + $this->assertFalse( + phutil_is_system_locale_available('duck.quack'), + pht('Imaginary locale should be unavailable.')); + + $this->assertEqual( + $original_locale, + phutil_get_system_locale(), + pht('Testing locale availability should not change the locale.')); + + $this->assertTrue( + phutil_is_system_locale_available($original_locale), + pht('The current locale should be available.')); + + $caught = null; + try { + phutil_set_system_locale('duck.quack'); + } catch (Exception $ex) { + $caught = $ex; + } + + $this->assertTrue( + ($caught instanceof Exception), + pht('Setting an imaginary locale should raise an exception.')); + + // We need two locales for the next part because one of them might be the + // current locale, and we want to make sure we can actually change the + // locale value. + + // If the current locale was "zz_ZZ", and then we do this: + // + // set_locale("zz_ZZ"); + // assert("zz_ZZ" == get_locale()); + // + // ...the test could pass even if "set_locale(...)" does nothing. + + $has_us = phutil_is_system_locale_available('en_US.UTF-8'); + $has_gb = phutil_is_system_locale_available('en_GB.UTF-8'); + if (!$has_us || !$has_gb) { + $this->assertSkipped( + pht( + 'System does not have en_US + en_GB to do locale adjustment '. + 'tests.')); + } + + phutil_set_system_locale('en_US.UTF-8'); + $this->assertEqual( + 'en_US.UTF-8', + phutil_get_system_locale(), + pht('Set locale to en_US.')); + + phutil_set_system_locale('en_GB.UTF-8'); + $this->assertEqual( + 'en_GB.UTF-8', + phutil_get_system_locale(), + pht('Set locale to en_GB.')); + + // Put things back the way they were. + phutil_set_system_locale($original_locale); + } + } diff --git a/src/utils/utf8.php b/src/utils/utf8.php --- a/src/utils/utf8.php +++ b/src/utils/utf8.php @@ -897,3 +897,54 @@ return $parts; } + + +/** + * Return the current system locale setting (LC_ALL). + * + * @return string Current system locale setting. + */ +function phutil_get_system_locale() { + $locale = setlocale(LC_ALL, 0); + + if ($locale === false) { + throw new Exception( + pht( + 'Unable to determine current system locale (call to '. + '"setlocale(LC_ALL, 0)" failed).')); + } + + return $locale; +} + + +/** + * Test if a system locale (LC_ALL) is available on the system. + * + * @param string Locale name like "en_US.UTF-8". + * @return bool True if the locale is available. + */ +function phutil_is_system_locale_available($locale) { + $old_locale = phutil_get_system_locale(); + $is_available = @setlocale(LC_ALL, $locale); + setlocale(LC_ALL, $old_locale); + + return ($is_available !== false); +} + + +/** + * Set the system locale (LC_ALL) to a particular value. + * + * @param string New locale setting. + * @return void + */ +function phutil_set_system_locale($locale) { + $ok = @setlocale(LC_ALL, $locale); + if (!$ok) { + throw new Exception( + pht( + 'Failed to set system locale (to "%s").', + $locale)); + } +}