mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
API Removed auto-detection for i18n date/time formats
Default to "yyyy-MM-dd" for date format, and "H:mm" for time_format. Switched to config API for setting/getting values. Avoid using "MMM" in particular, since it causes inconsistencies in month names between jQuery UI and Zend_Locale_Format. Fixes https://github.com/silverstripe/silverstripe-cms/issues/544
This commit is contained in:
parent
4af9143d3b
commit
6906c9bd1a
@ -31,4 +31,15 @@ use `setDisplayFolderName()` with a folder path relative to `assets/`:
|
|||||||
|
|
||||||
UploadField::create('MyField')->setDisplayFolderName('Uploads');
|
UploadField::create('MyField')->setDisplayFolderName('Uploads');
|
||||||
|
|
||||||
|
### Removed format detection in i18n::$date_format and i18n::$time_format
|
||||||
|
|
||||||
|
Localized dates cause inconsistencies in client-side vs. server-side formatting
|
||||||
|
and validation, particularly in abbreviated month names. The default date
|
||||||
|
format has been changed to "yyyy-MM-dd" (e.g. 2014-12-31).
|
||||||
|
New users will continue to have the option for a localized date
|
||||||
|
format in their profile (based on their chosen locale).
|
||||||
|
If you have existing users with `Member.DateFormat` set to a format
|
||||||
|
including "MMM" or "MMMM", consider deleting those formats to fall back to
|
||||||
|
the global (and more stable) default.
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
|
@ -37,6 +37,12 @@ You can define a custom dateformat for your Datefield based on [Zend_Date consta
|
|||||||
// will display a date in the following format: 31-06-2012
|
// will display a date in the following format: 31-06-2012
|
||||||
DateField::create('MyDate')->setConfig('dateformat', 'dd-MM-yyyy');
|
DateField::create('MyDate')->setConfig('dateformat', 'dd-MM-yyyy');
|
||||||
|
|
||||||
|
Caution: If you're using natural language date formats like abbreviated month names
|
||||||
|
alongside the "showcalendar" option, you'll need to ensure the formats
|
||||||
|
between the calendar widget and the SilverStripe validation are consistent.
|
||||||
|
As an example for the 'de' locale, check `framework/thirdparty/jquery-ui/datepicker/i18n/jquery.ui.datepicker-de.js`
|
||||||
|
and compare it to `framework/thirdparty/Zend/Locale/Data/de.xml`
|
||||||
|
(see `<calendar type="gregorian">` in the XML data).
|
||||||
|
|
||||||
## Min and Max Dates
|
## Min and Max Dates
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ class DateField extends TextField {
|
|||||||
|
|
||||||
$this->config = $this->config()->default_config;
|
$this->config = $this->config()->default_config;
|
||||||
if(!$this->getConfig('dateformat')) {
|
if(!$this->getConfig('dateformat')) {
|
||||||
$this->setConfig('dateformat', i18n::get_date_format());
|
$this->setConfig('dateformat', Config::inst()->get('i18n', 'date_format'));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->config()->default_config AS $defaultK => $defaultV) {
|
foreach ($this->config()->default_config AS $defaultK => $defaultV) {
|
||||||
|
@ -58,7 +58,7 @@ class TimeField extends TextField {
|
|||||||
$this->config = $this->config()->default_config;
|
$this->config = $this->config()->default_config;
|
||||||
|
|
||||||
if(!$this->getConfig('timeformat')) {
|
if(!$this->getConfig('timeformat')) {
|
||||||
$this->setConfig('timeformat', i18n::get_time_format());
|
$this->setConfig('timeformat', Config::inst()->get('i18n', 'time_format'));
|
||||||
}
|
}
|
||||||
|
|
||||||
parent::__construct($name,$title,$value);
|
parent::__construct($name,$title,$value);
|
||||||
|
@ -84,13 +84,13 @@ class i18n extends Object implements TemplateGlobalProvider {
|
|||||||
* @config
|
* @config
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private static $date_format;
|
private static $date_format = 'yyyy-MM-dd';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @config
|
* @config
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private static $time_format;
|
private static $time_format = 'H:mm';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array Array of priority keys to instances of Zend_Translate, mapped by name.
|
* @var array Array of priority keys to instances of Zend_Translate, mapped by name.
|
||||||
@ -141,9 +141,8 @@ class i18n extends Object implements TemplateGlobalProvider {
|
|||||||
* @return string ISO date format
|
* @return string ISO date format
|
||||||
*/
|
*/
|
||||||
public static function get_date_format() {
|
public static function get_date_format() {
|
||||||
require_once 'Zend/Date.php';
|
Deprecation::notice('3.2', 'Use the "i18n.date_format" config setting instead');
|
||||||
$dateFormat = Config::inst()->get('i18n', 'date_format');
|
return Config::inst()->get('i18n', 'date_format');
|
||||||
return ($dateFormat) ? $dateFormat : Zend_Locale_Format::getDateFormat(self::get_locale());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -159,9 +158,8 @@ class i18n extends Object implements TemplateGlobalProvider {
|
|||||||
* @return string ISO time format
|
* @return string ISO time format
|
||||||
*/
|
*/
|
||||||
public static function get_time_format() {
|
public static function get_time_format() {
|
||||||
require_once 'Zend/Date.php';
|
Deprecation::notice('3.2', 'Use the "i18n.time_format" config setting instead');
|
||||||
$timeFormat = Config::inst()->get('i18n', 'time_format');
|
return Config::inst()->get('i18n', 'time_format');
|
||||||
return ($timeFormat) ? $timeFormat : Zend_Locale_Format::getTimeFormat(self::get_locale());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1009,11 +1009,8 @@ class Member extends DataObject implements TemplateGlobalProvider {
|
|||||||
public function getDateFormat() {
|
public function getDateFormat() {
|
||||||
if($this->getField('DateFormat')) {
|
if($this->getField('DateFormat')) {
|
||||||
return $this->getField('DateFormat');
|
return $this->getField('DateFormat');
|
||||||
} elseif($this->getField('Locale')) {
|
|
||||||
require_once 'Zend/Date.php';
|
|
||||||
return Zend_Locale_Format::getDateFormat($this->Locale);
|
|
||||||
} else {
|
} else {
|
||||||
return i18n::get_date_format();
|
return Config::inst()->get('i18n', 'date_format');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1027,11 +1024,8 @@ class Member extends DataObject implements TemplateGlobalProvider {
|
|||||||
public function getTimeFormat() {
|
public function getTimeFormat() {
|
||||||
if($this->getField('TimeFormat')) {
|
if($this->getField('TimeFormat')) {
|
||||||
return $this->getField('TimeFormat');
|
return $this->getField('TimeFormat');
|
||||||
} elseif($this->getField('Locale')) {
|
|
||||||
require_once 'Zend/Date.php';
|
|
||||||
return Zend_Locale_Format::getTimeFormat($this->Locale);
|
|
||||||
} else {
|
} else {
|
||||||
return i18n::get_time_format();
|
return Config::inst()->get('i18n', 'time_format');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1265,15 +1259,16 @@ class Member extends DataObject implements TemplateGlobalProvider {
|
|||||||
$permissionsTab = $fields->fieldByName("Root")->fieldByName('Permissions');
|
$permissionsTab = $fields->fieldByName("Root")->fieldByName('Permissions');
|
||||||
if($permissionsTab) $permissionsTab->addExtraClass('readonly');
|
if($permissionsTab) $permissionsTab->addExtraClass('readonly');
|
||||||
|
|
||||||
$defaultDateFormat = Zend_Locale_Format::getDateFormat(new Zend_Locale($this->Locale));
|
$localDateFormat = Zend_Locale_Data::getContent(new Zend_Locale($this->Locale), 'date', 'short');
|
||||||
|
// Ensure short dates always use four digit dates to avoid confusion
|
||||||
|
$localDateFormat = preg_replace('/(^|[^y])yy($|[^y])/', '$1yyyy$2', $localDateFormat);
|
||||||
$dateFormatMap = array(
|
$dateFormatMap = array(
|
||||||
'MMM d, yyyy' => Zend_Date::now()->toString('MMM d, yyyy'),
|
$this->DateFormat => Zend_Date::now()->toString($this->DateFormat),
|
||||||
|
$localDateFormat => Zend_Date::now()->toString($localDateFormat),
|
||||||
'yyyy/MM/dd' => Zend_Date::now()->toString('yyyy/MM/dd'),
|
'yyyy/MM/dd' => Zend_Date::now()->toString('yyyy/MM/dd'),
|
||||||
'MM/dd/yyyy' => Zend_Date::now()->toString('MM/dd/yyyy'),
|
'MM/dd/yyyy' => Zend_Date::now()->toString('MM/dd/yyyy'),
|
||||||
'dd/MM/yyyy' => Zend_Date::now()->toString('dd/MM/yyyy'),
|
'dd/MM/yyyy' => Zend_Date::now()->toString('dd/MM/yyyy'),
|
||||||
);
|
);
|
||||||
$dateFormatMap[$defaultDateFormat] = Zend_Date::now()->toString($defaultDateFormat)
|
|
||||||
. sprintf(' (%s)', _t('Member.DefaultDateTime', 'default'));
|
|
||||||
$mainFields->push(
|
$mainFields->push(
|
||||||
$dateFormatField = new MemberDatetimeOptionsetField(
|
$dateFormatField = new MemberDatetimeOptionsetField(
|
||||||
'DateFormat',
|
'DateFormat',
|
||||||
@ -1283,13 +1278,13 @@ class Member extends DataObject implements TemplateGlobalProvider {
|
|||||||
);
|
);
|
||||||
$dateFormatField->setValue($this->DateFormat);
|
$dateFormatField->setValue($this->DateFormat);
|
||||||
|
|
||||||
$defaultTimeFormat = Zend_Locale_Format::getTimeFormat(new Zend_Locale($this->Locale));
|
$localTimeFormat = Zend_Locale_Format::getTimeFormat(new Zend_Locale($this->Locale));
|
||||||
$timeFormatMap = array(
|
$timeFormatMap = array(
|
||||||
|
$this->TimeFormat => Zend_Date::now()->toString($this->TimeFormat),
|
||||||
|
$localTimeFormat => Zend_Date::now()->toString($localTimeFormat),
|
||||||
'h:mm a' => Zend_Date::now()->toString('h:mm a'),
|
'h:mm a' => Zend_Date::now()->toString('h:mm a'),
|
||||||
'H:mm' => Zend_Date::now()->toString('H:mm'),
|
'H:mm' => Zend_Date::now()->toString('H:mm'),
|
||||||
);
|
);
|
||||||
$timeFormatMap[$defaultTimeFormat] = Zend_Date::now()->toString($defaultTimeFormat)
|
|
||||||
. sprintf(' (%s)', _t('Member.DefaultDateTime', 'default'));
|
|
||||||
$mainFields->push(
|
$mainFields->push(
|
||||||
$timeFormatField = new MemberDatetimeOptionsetField(
|
$timeFormatField = new MemberDatetimeOptionsetField(
|
||||||
'TimeFormat',
|
'TimeFormat',
|
||||||
|
@ -11,7 +11,7 @@ class MemberDatetimeOptionsetFieldTest extends SapphireTest {
|
|||||||
require_once 'Zend/Date.php';
|
require_once 'Zend/Date.php';
|
||||||
$defaultDateFormat = Zend_Locale_Format::getDateFormat($member->Locale);
|
$defaultDateFormat = Zend_Locale_Format::getDateFormat($member->Locale);
|
||||||
$dateFormatMap = array(
|
$dateFormatMap = array(
|
||||||
'MMM d, yyyy' => Zend_Date::now()->toString('MMM d, yyyy'),
|
'yyyy-MM-dd' => Zend_Date::now()->toString('yyyy-MM-dd'),
|
||||||
'yyyy/MM/dd' => Zend_Date::now()->toString('yyyy/MM/dd'),
|
'yyyy/MM/dd' => Zend_Date::now()->toString('yyyy/MM/dd'),
|
||||||
'MM/dd/yyyy' => Zend_Date::now()->toString('MM/dd/yyyy'),
|
'MM/dd/yyyy' => Zend_Date::now()->toString('MM/dd/yyyy'),
|
||||||
'dd/MM/yyyy' => Zend_Date::now()->toString('dd/MM/yyyy'),
|
'dd/MM/yyyy' => Zend_Date::now()->toString('dd/MM/yyyy'),
|
||||||
@ -44,15 +44,17 @@ class MemberDatetimeOptionsetFieldTest extends SapphireTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testDateFormatDefaultCheckedInFormField() {
|
public function testDateFormatDefaultCheckedInFormField() {
|
||||||
|
Config::inst()->update('i18n', 'date_format', 'yyyy-MM-dd');
|
||||||
$field = $this->createDateFormatFieldForMember($this->objFromFixture('Member', 'noformatmember'));
|
$field = $this->createDateFormatFieldForMember($this->objFromFixture('Member', 'noformatmember'));
|
||||||
$field->setForm(new Form(new MemberDatetimeOptionsetFieldTest_Controller(), 'Form', new FieldList(),
|
$field->setForm(new Form(new MemberDatetimeOptionsetFieldTest_Controller(), 'Form', new FieldList(),
|
||||||
new FieldList())); // fake form
|
new FieldList())); // fake form
|
||||||
$parser = new CSSContentParser($field->Field());
|
$parser = new CSSContentParser($field->Field());
|
||||||
$xmlArr = $parser->getBySelector('#Form_Form_DateFormat_MMM_d__y');
|
$xmlArr = $parser->getBySelector('#Form_Form_DateFormat_yyyy-MM-dd');
|
||||||
$this->assertEquals('checked', (string) $xmlArr[0]['checked']);
|
$this->assertEquals('checked', (string) $xmlArr[0]['checked']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testTimeFormatDefaultCheckedInFormField() {
|
public function testTimeFormatDefaultCheckedInFormField() {
|
||||||
|
Config::inst()->update('i18n', 'time_format', 'h:mm:ss a');
|
||||||
$field = $this->createTimeFormatFieldForMember($this->objFromFixture('Member', 'noformatmember'));
|
$field = $this->createTimeFormatFieldForMember($this->objFromFixture('Member', 'noformatmember'));
|
||||||
$field->setForm(new Form(new MemberDatetimeOptionsetFieldTest_Controller(), 'Form', new FieldList(),
|
$field->setForm(new Form(new MemberDatetimeOptionsetFieldTest_Controller(), 'Form', new FieldList(),
|
||||||
new FieldList())); // fake form
|
new FieldList())); // fake form
|
||||||
|
@ -65,36 +65,6 @@ class i18nTest extends SapphireTest {
|
|||||||
parent::tearDown();
|
parent::tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDateFormatFromLocale() {
|
|
||||||
i18n::set_locale('en_US');
|
|
||||||
$this->assertEquals('MMM d, y', i18n::get_date_format());
|
|
||||||
i18n::set_locale('en_NZ');
|
|
||||||
$this->assertEquals('d/MM/yyyy', i18n::get_date_format());
|
|
||||||
i18n::set_locale('en_US');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testTimeFormatFromLocale() {
|
|
||||||
i18n::set_locale('en_US');
|
|
||||||
$this->assertEquals('h:mm:ss a', i18n::get_time_format());
|
|
||||||
i18n::set_locale('de_DE');
|
|
||||||
$this->assertEquals('HH:mm:ss', i18n::get_time_format());
|
|
||||||
i18n::set_locale('en_US');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDateFormatCustom() {
|
|
||||||
i18n::set_locale('en_US');
|
|
||||||
$this->assertEquals('MMM d, y', i18n::get_date_format());
|
|
||||||
i18n::config()->date_format = 'd/MM/yyyy';
|
|
||||||
$this->assertEquals('d/MM/yyyy', i18n::get_date_format());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testTimeFormatCustom() {
|
|
||||||
i18n::set_locale('en_US');
|
|
||||||
$this->assertEquals('h:mm:ss a', i18n::get_time_format());
|
|
||||||
i18n::config()->time_format = 'HH:mm:ss';
|
|
||||||
$this->assertEquals('HH:mm:ss', i18n::get_time_format());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetExistingTranslations() {
|
public function testGetExistingTranslations() {
|
||||||
$translations = i18n::get_existing_translations();
|
$translations = i18n::get_existing_translations();
|
||||||
$this->assertTrue(isset($translations['en_US']), 'Checking for en translation');
|
$this->assertTrue(isset($translations['en_US']), 'Checking for en translation');
|
||||||
|
@ -320,15 +320,11 @@ class MemberTest extends FunctionalTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function testMemberWithNoDateFormatFallsbackToGlobalLocaleDefaultFormat() {
|
public function testMemberWithNoDateFormatFallsbackToGlobalLocaleDefaultFormat() {
|
||||||
|
Config::inst()->update('i18n', 'date_format', 'yyyy-MM-dd');
|
||||||
|
Config::inst()->update('i18n', 'time_format', 'H:mm');
|
||||||
$member = $this->objFromFixture('Member', 'noformatmember');
|
$member = $this->objFromFixture('Member', 'noformatmember');
|
||||||
$this->assertEquals('MMM d, y', $member->DateFormat);
|
$this->assertEquals('yyyy-MM-dd', $member->DateFormat);
|
||||||
$this->assertEquals('h:mm:ss a', $member->TimeFormat);
|
$this->assertEquals('H:mm', $member->TimeFormat);
|
||||||
}
|
|
||||||
|
|
||||||
public function testMemberWithNoDateFormatFallsbackToTheirLocaleDefaultFormat() {
|
|
||||||
$member = $this->objFromFixture('Member', 'delocalemember');
|
|
||||||
$this->assertEquals('dd.MM.yyyy', $member->DateFormat);
|
|
||||||
$this->assertEquals('HH:mm:ss', $member->TimeFormat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testInGroups() {
|
public function testInGroups() {
|
||||||
|
Loading…
Reference in New Issue
Block a user