Refactored IDateTimeLocalization and moved it into Orchard.Framework.

Refactored IDateServices to use format strings provided by IDateTimeLocalization.
Removed duplicated date localization logic from DateEditorDriver, ArchiveLaterPartDriver, PublishLaterPartDriver, FieldTokens, DateTokens, and replaced with calls to IDateServices instead.
This commit is contained in:
Daniel Stolt
2013-11-28 22:24:40 +01:00
committed by Sebastien Ros
parent 14ed42a53e
commit 6eb9599450
13 changed files with 232 additions and 257 deletions

View File

@@ -4,18 +4,18 @@ using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Core.Common.Models;
using Orchard.Localization;
using Orchard.Localization.Services;
namespace Orchard.Core.Common.DateEditor {
public class DateEditorDriver : ContentPartDriver<CommonPart> {
private readonly Lazy<CultureInfo> _cultureInfo;
private readonly IDateServices _dateServices;
public DateEditorDriver(
IOrchardServices services) {
T = NullLocalizer.Instance;
Services = services;
// initializing the culture info lazy initializer
_cultureInfo = new Lazy<CultureInfo>(() => CultureInfo.GetCultureInfo(Services.WorkContext.CurrentCulture));
IOrchardServices services,
IDateServices dateServices) {
_dateServices = dateServices;
T = NullLocalizer.Instance;
Services = services;
}
public Localizer T { get; set; }
@@ -53,40 +53,30 @@ namespace Orchard.Core.Common.DateEditor {
thisIsTheInitialVersionRecord &&
theDatesHaveNotBeenModified;
if (theEditorShouldBeBlank == false) {
// date and time are formatted using the same patterns as DateTimePicker is, preventing other cultures issues
var createdLocal = TimeZoneInfo.ConvertTimeFromUtc(part.CreatedUtc.Value, Services.WorkContext.CurrentTimeZone);
model.CreatedDate = createdLocal.ToString("d", _cultureInfo.Value);
model.CreatedTime = createdLocal.ToString("t", _cultureInfo.Value);
if (!theEditorShouldBeBlank) {
model.CreatedDate = _dateServices.ConvertToLocalDateString(part.CreatedUtc, "");
model.CreatedTime = _dateServices.ConvertToLocalTimeString(part.CreatedUtc, "");
}
}
if (updater != null) {
updater.TryUpdateModel(model, Prefix, null, null);
if (!string.IsNullOrWhiteSpace(model.CreatedDate) && !string.IsNullOrWhiteSpace(model.CreatedTime)) {
DateTime createdUtc;
string parseDateTime = String.Concat(model.CreatedDate, " ", model.CreatedTime);
// use current culture
if (DateTime.TryParse(parseDateTime, _cultureInfo.Value, DateTimeStyles.None, out createdUtc)) {
// the date time is entered locally for the configured timezone
part.CreatedUtc = TimeZoneInfo.ConvertTimeToUtc(createdUtc, Services.WorkContext.CurrentTimeZone);
part.VersionCreatedUtc = part.CreatedUtc;
if (!String.IsNullOrWhiteSpace(model.CreatedDate) && !String.IsNullOrWhiteSpace(model.CreatedTime)) {
try {
var utcDateTime = _dateServices.ConvertFromLocalString(model.CreatedDate, model.CreatedTime);
part.CreatedUtc = utcDateTime;
part.VersionCreatedUtc = utcDateTime;
}
else {
updater.AddModelError(Prefix, T("{0} is an invalid date and time", parseDateTime));
catch (FormatException) {
updater.AddModelError(Prefix, T("'{0} {1}' could not be parsed as a valid date and time.", model.CreatedDate, model.CreatedTime));
}
}
else if (!string.IsNullOrWhiteSpace(model.CreatedDate) || !string.IsNullOrWhiteSpace(model.CreatedTime)) {
// only one part is specified
else if (!String.IsNullOrWhiteSpace(model.CreatedDate) || !String.IsNullOrWhiteSpace(model.CreatedTime)) {
updater.AddModelError(Prefix, T("Both the date and time need to be specified."));
}
// none date/time part is specified => do nothing
// Neither date/time part is specified => do nothing.
}
return model;

View File

@@ -249,7 +249,6 @@
<Compile Include="Settings\Models\SiteSettingsPart.cs" />
<Compile Include="Settings\Services\SiteService.cs" />
<Compile Include="Settings\ViewModels\SiteSettingsPartViewModel.cs" />
<Compile Include="Shapes\Localization\DateTimeLocalization.cs" />
<Compile Include="Shapes\ResourceManifest.cs" />
<Compile Include="Shapes\CoreShapes.cs" />
<Compile Include="Shapes\DateTimeShapes.cs" />

View File

@@ -1,41 +1,38 @@
using System;
using System.Globalization;
using System.Web;
using System.Web.Mvc;
using Orchard.Core.Shapes.Localization;
using Orchard.DisplayManagement;
using Orchard.Localization;
using Orchard.Localization.Services;
using Orchard.Mvc.Html;
using Orchard.Services;
using System.Globalization;
namespace Orchard.Core.Shapes {
public class DateTimeShapes : IDependency {
private readonly IClock _clock;
private readonly IDateServices _dateServices;
private readonly IDateTimeLocalization _dateTimeLocalization;
private readonly IWorkContextAccessor _workContextAccessor;
private readonly Lazy<CultureInfo> _cultureInfo;
public DateTimeShapes(
IClock clock,
IDateTimeLocalization dateTimeLocalization,
IWorkContextAccessor workContextAccessor
IDateServices dateServices,
IDateTimeLocalization dateTimeLocalization
) {
_clock = clock;
_dateServices = dateServices;
_dateTimeLocalization = dateTimeLocalization;
_workContextAccessor = workContextAccessor;
T = NullLocalizer.Instance;
_cultureInfo = new Lazy<CultureInfo>(() => CultureInfo.GetCultureInfo(_workContextAccessor.GetContext().CurrentCulture));
}
public Localizer T { get; set; }
[Shape]
public IHtmlString DateTimeRelative(dynamic Display, DateTime dateTimeUtc) {
var time = _clock.UtcNow - dateTimeUtc;
public IHtmlString DateTimeRelative(dynamic Display, DateTime DateTimeUtc) {
var time = _clock.UtcNow - DateTimeUtc;
if (time.TotalDays > 7 || time.TotalDays < -7)
return Display.DateTime(DateTimeUtc: dateTimeUtc, CustomFormat: T("'on' MMM d yyyy 'at' h:mm tt"));
return Display.DateTime(DateTimeUtc: DateTimeUtc, CustomFormat: _dateTimeLocalization.LongDateTimeFormat);
if (time.TotalHours > 24)
return T.Plural("1 day ago", "{0} days ago", time.Days);
@@ -67,24 +64,10 @@ namespace Orchard.Core.Shapes {
//using a LocalizedString forces the caller to use a localizable format
if (CustomFormat == null || String.IsNullOrWhiteSpace(CustomFormat.Text)) {
return DateTime(DateTimeUtc, _dateTimeLocalization.LongDateTimeFormat);
return new MvcHtmlString(_dateServices.ConvertToLocalString(DateTimeUtc, _dateTimeLocalization.LongDateTimeFormat.Text));
}
return new MvcHtmlString(ConvertToDisplayTime(DateTimeUtc).ToString(CustomFormat.Text, _cultureInfo.Value));
return new MvcHtmlString(_dateServices.ConvertToLocalString(DateTimeUtc, CustomFormat.Text));
}
/// <summary>
/// Converts a Coordinated Universal Time (UTC) to the time in the current time zone.
/// </summary>
/// <param name="dateTimeUtc">The Coordinated Universal Time (UTC).</param>
/// <returns>The date and time in the selected time zone. Its System.DateTime.Kind property is System.DateTimeKind.Utc if the current zone is System.TimeZoneInfo.Utc; otherwise, its System.DateTime.Kind property is System.DateTimeKind.Unspecified.</returns>
private DateTime ConvertToDisplayTime(DateTime dateTimeUtc) {
// get the time zone for the current request
var timeZone = _workContextAccessor.GetContext().CurrentTimeZone;
return TimeZoneInfo.ConvertTimeFromUtc(dateTimeUtc, timeZone);
}
}
}

View File

@@ -1,112 +0,0 @@
using System;
using Orchard.Localization;
namespace Orchard.Core.Shapes.Localization {
public interface IDateTimeLocalization : IDependency {
LocalizedString MonthNames { get; }
LocalizedString MonthNamesShort { get; }
LocalizedString DayNames { get; }
LocalizedString DayNamesShort { get; }
LocalizedString DayNamesMin { get; }
LocalizedString ShortDateFormat { get; }
LocalizedString ShortTimeFormat { get; }
LocalizedString LongDateTimeFormat { get; }
/// <summary>
/// The first day of the week, Sun = 0, Mon = 1, ...
/// </summary>
int FirstDay { get; }
/// <summary>
/// True if the year select precedes month, false for month then year
/// </summary>
bool ShowMonthAfterYear { get; }
/// <summary>
/// Additional text to append to the year in the month headers
/// </summary>
string YearSuffix { get; }
}
public class DateTimeLocalization : IDateTimeLocalization {
public Localizer T { get; set; }
public DateTimeLocalization() {
T = NullLocalizer.Instance;
}
public LocalizedString MonthNames {
get { return T("January, February, March, April, May, June, July, August, September, October, November, December"); }
}
public LocalizedString MonthNamesShort {
get { return T("Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec"); }
}
public LocalizedString DayNames {
get { return T("Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday"); }
}
public LocalizedString DayNamesShort {
get { return T("Sun, Mon, Tue, Wed, Thu, Fri, Sat"); }
}
public LocalizedString DayNamesMin {
get { return T("Su, Mo, Tu, We, Th, Fr, Sa"); }
}
public LocalizedString ShortDateFormat {
get { return T("M/d/yyyy"); }
}
public LocalizedString ShortTimeFormat {
get { return T("h:mm tt"); }
}
public LocalizedString LongDateTimeFormat {
get { return T("MMM d yyyy h:mm tt"); }
}
public int FirstDay {
get {
var firstDay = 1;
var t = T("firstDay: 1").Text;
var parts = t.Split(':');
if(parts.Length == 2) {
Int32.TryParse(parts[1], out firstDay);
}
return firstDay;
}
}
public bool ShowMonthAfterYear {
get {
var showMonthAfterYear = false;
var t = T("showMonthAfterYear: false").Text;
var parts = t.Split(':');
if (parts.Length == 2) {
Boolean.TryParse(parts[1], out showMonthAfterYear);
}
return showMonthAfterYear;
}
}
public string YearSuffix {
get {
var yearSuffix = String.Empty;
var t = T("yearSuffix: ").Text;
var parts = t.Split(':');
if (parts.Length == 2) {
return parts[1].Trim();
}
return yearSuffix;
}
}
}
}

View File

@@ -8,29 +8,38 @@ using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers;
using Orchard.Localization;
using System.Globalization;
using Orchard.Localization.Services;
namespace Orchard.ArchiveLater.Drivers {
public class ArchiveLaterPartDriver : ContentPartDriver<ArchiveLaterPart> {
private const string TemplateName = "Parts/ArchiveLater";
private readonly IArchiveLaterService _archiveLaterService;
private readonly Lazy<CultureInfo> _cultureInfo;
private readonly IDateServices _dateServices;
public ArchiveLaterPartDriver(
IOrchardServices services,
IArchiveLaterService archiveLaterService) {
IArchiveLaterService archiveLaterService,
IDateServices dateServices) {
_archiveLaterService = archiveLaterService;
_dateServices = dateServices;
T = NullLocalizer.Instance;
Services = services;
// initializing the culture info lazy initializer
_cultureInfo = new Lazy<CultureInfo>(() => CultureInfo.GetCultureInfo(Services.WorkContext.CurrentCulture));
}
public Localizer T { get; set; }
public IOrchardServices Services { get; set; }
public Localizer T {
get;
set;
}
public IOrchardServices Services {
get;
set;
}
protected override string Prefix { get { return "ArchiveLater"; } }
protected override string Prefix {
get {
return "ArchiveLater";
}
}
protected override DriverResult Display(ArchiveLaterPart part, string displayType, dynamic shapeHelper) {
return ContentShape("Parts_ArchiveLater_Metadata_SummaryAdmin",
@@ -47,8 +56,8 @@ namespace Orchard.ArchiveLater.Drivers {
var model = new ArchiveLaterViewModel(part) {
ScheduledArchiveUtc = part.ScheduledArchiveUtc.Value,
ArchiveLater = part.ScheduledArchiveUtc.Value.HasValue,
ScheduledArchiveDate = part.ScheduledArchiveUtc.Value.HasValue ? localDate.Value.ToString("d", _cultureInfo.Value) : String.Empty,
ScheduledArchiveTime = part.ScheduledArchiveUtc.Value.HasValue ? localDate.Value.ToString("t", _cultureInfo.Value) : String.Empty
ScheduledArchiveDate = _dateServices.ConvertToLocalDateString(part.ScheduledArchiveUtc.Value, ""),
ScheduledArchiveTime = _dateServices.ConvertToLocalTimeString(part.ScheduledArchiveUtc.Value, "")
};
return ContentShape("Parts_ArchiveLater_Edit",
@@ -58,21 +67,15 @@ namespace Orchard.ArchiveLater.Drivers {
protected override DriverResult Editor(ArchiveLaterPart part, IUpdateModel updater, dynamic shapeHelper) {
var model = new ArchiveLaterViewModel(part);
if (updater.TryUpdateModel(model, Prefix, null, null) ) {
if ( model.ArchiveLater ) {
DateTime scheduled;
var parseDateTime = String.Concat(model.ScheduledArchiveDate, " ", model.ScheduledArchiveTime);
// use an english culture as it is the one used by jQuery.datepicker by default
if (DateTime.TryParse(parseDateTime, _cultureInfo.Value, DateTimeStyles.None, out scheduled)) {
// the date time is entered locally for the configured timezone
var timeZone = Services.WorkContext.CurrentTimeZone;
model.ScheduledArchiveUtc = TimeZoneInfo.ConvertTimeToUtc(scheduled, timeZone);
if (updater.TryUpdateModel(model, Prefix, null, null)) {
if (model.ArchiveLater) {
try {
var utcDateTime = _dateServices.ConvertFromLocalString(model.ScheduledArchiveDate, model.ScheduledArchiveTime);
model.ScheduledArchiveUtc = utcDateTime;
_archiveLaterService.ArchiveLater(model.ContentItem, model.ScheduledArchiveUtc.HasValue ? model.ScheduledArchiveUtc.Value : DateTime.MaxValue);
}
else {
updater.AddModelError(Prefix, T("{0} is an invalid date and time", parseDateTime));
catch (FormatException) {
updater.AddModelError(Prefix, T("'{0} {1}' could not be parsed as a valid date and time.", model.ScheduledArchiveDate, model.ScheduledArchiveTime));
}
}
else {

View File

@@ -2,7 +2,7 @@
using Orchard.Events;
using Orchard.Fields.Fields;
using Orchard.Localization;
using Orchard.Core.Shapes.Localization;
using Orchard.Localization.Services;
using System.Globalization;
namespace Orchard.Fields.Tokens {
@@ -17,7 +17,6 @@ namespace Orchard.Fields.Tokens {
private readonly IWorkContextAccessor _workContextAccessor;
private readonly Lazy<CultureInfo> _cultureInfo;
public FieldTokens(
IDateTimeLocalization dateTimeLocalization,
IWorkContextAccessor workContextAccessor) {
@@ -58,7 +57,7 @@ namespace Orchard.Fields.Tokens {
context.For<DateTimeField>("DateTimeField")
.Token("Date", (Func<DateTimeField, object>)(d => d.DateTime.ToString(_dateTimeLocalization.ShortDateFormat.Text, _cultureInfo.Value)))
.Token("Time", (Func<DateTimeField, object>)(d => d.DateTime.ToString(_dateTimeLocalization.ShortTimeFormat.Text, _cultureInfo.Value)))
.Token("DateTime", (Func<DateTimeField, object>)(d => d.DateTime.ToString(_dateTimeLocalization.ShortDateFormat.Text + " " + _dateTimeLocalization.ShortTimeFormat.Text, _cultureInfo.Value)))
.Token("DateTime", (Func<DateTimeField, object>)(d => d.DateTime.ToString(_dateTimeLocalization.ShortDateTimeFormat.Text, _cultureInfo.Value)))
.Chain("DateTime", "Date", (Func<DateTimeField, object>)(field => field.DateTime))
;
}

View File

@@ -10,6 +10,7 @@ using Orchard.PublishLater.ViewModels;
using Orchard.Localization;
using System.Globalization;
using Orchard.Services;
using Orchard.Localization.Services;
namespace Orchard.PublishLater.Drivers {
public class PublishLaterPartDriver : ContentPartDriver<PublishLaterPart> {
@@ -17,29 +18,35 @@ namespace Orchard.PublishLater.Drivers {
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IPublishLaterService _publishLaterService;
private readonly IClock _clock;
private readonly IDateServices _dateServices;
private readonly Lazy<CultureInfo> _cultureInfo;
public PublishLaterPartDriver(
IOrchardServices services,
IHttpContextAccessor httpContextAccessor,
IPublishLaterService publishLaterService,
IClock clock) {
IClock clock,
IDateServices dateServices) {
_httpContextAccessor = httpContextAccessor;
_publishLaterService = publishLaterService;
_clock = clock;
_dateServices = dateServices;
T = NullLocalizer.Instance;
Services = services;
// initializing the culture info lazy initializer
_cultureInfo = new Lazy<CultureInfo>(() => CultureInfo.GetCultureInfo(Services.WorkContext.CurrentCulture));
}
public Localizer T { get; set; }
public IOrchardServices Services { get; set; }
public Localizer T {
get;
set;
}
public IOrchardServices Services {
get;
set;
}
protected override string Prefix {
get { return "PublishLater"; }
get {
return "PublishLater";
}
}
protected override DriverResult Display(PublishLaterPart part, string displayType, dynamic shapeHelper) {
@@ -54,49 +61,39 @@ namespace Orchard.PublishLater.Drivers {
}
protected override DriverResult Editor(PublishLaterPart part, dynamic shapeHelper) {
// date and time are formatted using the same patterns as DateTimePicker is, preventing other cultures issues
var localDate = new Lazy<DateTime>( () => TimeZoneInfo.ConvertTimeFromUtc(part.ScheduledPublishUtc.Value.Value, Services.WorkContext.CurrentTimeZone));
var model = new PublishLaterViewModel(part) {
ScheduledPublishUtc = part.ScheduledPublishUtc.Value,
ScheduledPublishDate = part.ScheduledPublishUtc.Value.HasValue && !part.IsPublished() ? localDate.Value.ToString("d", _cultureInfo.Value) : String.Empty,
ScheduledPublishTime = part.ScheduledPublishUtc.Value.HasValue && !part.IsPublished() ? localDate.Value.ToString("t", _cultureInfo.Value) : String.Empty,
ScheduledPublishDate = !part.IsPublished() ? _dateServices.ConvertToLocalDateString(part.ScheduledPublishUtc.Value, "") : "",
ScheduledPublishTime = !part.IsPublished() ? _dateServices.ConvertToLocalTimeString(part.ScheduledPublishUtc.Value, "") : ""
};
return ContentShape("Parts_PublishLater_Edit",
() => shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix));
}
protected override DriverResult Editor(PublishLaterPart part, IUpdateModel updater, dynamic shapeHelper) {
var model = new PublishLaterViewModel(part);
updater.TryUpdateModel(model, Prefix, null, null);
var httpContext = _httpContextAccessor.Current();
if (httpContext.Request.Form["submit.Save"] == "submit.PublishLater") {
if (!string.IsNullOrWhiteSpace(model.ScheduledPublishDate) && !string.IsNullOrWhiteSpace(model.ScheduledPublishTime)) {
DateTime scheduled;
string parseDateTime = String.Concat(model.ScheduledPublishDate, " ", model.ScheduledPublishTime);
// use current culture
if (DateTime.TryParse(parseDateTime, _cultureInfo.Value, DateTimeStyles.None, out scheduled)) {
// the date time is entered locally for the configured timezone
var timeZone = Services.WorkContext.CurrentTimeZone;
model.ScheduledPublishUtc = part.ScheduledPublishUtc.Value = TimeZoneInfo.ConvertTimeToUtc(scheduled, timeZone);
if (!String.IsNullOrWhiteSpace(model.ScheduledPublishDate) && !String.IsNullOrWhiteSpace(model.ScheduledPublishTime)) {
try {
var utcDateTime = _dateServices.ConvertFromLocalString(model.ScheduledPublishDate, model.ScheduledPublishTime);
model.ScheduledPublishUtc = part.ScheduledPublishUtc.Value = utcDateTime;
if (model.ScheduledPublishUtc < _clock.UtcNow) {
updater.AddModelError("ScheduledPublishUtcDate", T("You cannot schedule a publishing date in the past"));
updater.AddModelError("ScheduledPublishUtcDate", T("You cannot schedule a publishing date in the past."));
}
else {
_publishLaterService.Publish(model.ContentItem, model.ScheduledPublishUtc.Value);
}
}
else {
updater.AddModelError(Prefix, T("{0} is an invalid date and time", parseDateTime));
catch (FormatException) {
updater.AddModelError(Prefix, T("'{0} {1}' could not be parsed as a valid date and time.", model.ScheduledPublishDate, model.ScheduledPublishTime));
}
}
else if (!string.IsNullOrWhiteSpace(model.ScheduledPublishDate) || !string.IsNullOrWhiteSpace(model.ScheduledPublishTime)) {
else if (!String.IsNullOrWhiteSpace(model.ScheduledPublishDate) || !String.IsNullOrWhiteSpace(model.ScheduledPublishTime)) {
updater.AddModelError(Prefix, T("Both the date and time need to be specified for when this is to be published. If you don't want to schedule publishing then click Save or Publish Now."));
}
}

View File

@@ -1,9 +1,9 @@
using System;
using Orchard.Core.Shapes.Localization;
using System.Globalization;
using Orchard.Localization;
using Orchard.Localization.Services;
using Orchard.Mvc.Html;
using Orchard.Services;
using System.Globalization;
namespace Orchard.Tokens.Providers {
public class DateTokens : ITokenProvider {
@@ -11,18 +11,18 @@ namespace Orchard.Tokens.Providers {
private readonly IDateTimeLocalization _dateTimeLocalization;
private readonly IWorkContextAccessor _workContextAccessor;
private readonly Lazy<CultureInfo> _cultureInfo;
private readonly Lazy<TimeZoneInfo> _timeZone;
private readonly IDateServices _dateServices;
public DateTokens(
IClock clock,
IDateTimeLocalization dateTimeLocalization,
IWorkContextAccessor workContextAccessor) {
IWorkContextAccessor workContextAccessor,
IDateServices dateServices) {
_clock = clock;
_dateTimeLocalization = dateTimeLocalization;
_workContextAccessor = workContextAccessor;
_cultureInfo = new Lazy<CultureInfo>(() => CultureInfo.GetCultureInfo(_workContextAccessor.GetContext().CurrentCulture));
_timeZone = new Lazy<TimeZoneInfo>(() => _workContextAccessor.GetContext().CurrentTimeZone);
_dateServices = dateServices;
T = NullLocalizer.Instance;
}
@@ -32,7 +32,7 @@ namespace Orchard.Tokens.Providers {
public void Describe(DescribeContext context) {
context.For("Date", T("Date/time"), T("Current date/time tokens"))
.Token("Since", T("Since"), T("Relative to the current date/time."), "Date")
.Token("Local", T("Local"), T("Based on the configured time zone."), "Date")
.Token("Local", T("Local"), T("Based on the configured time zone and calendar."), "Date")
.Token("ShortDate", T("Short Date"), T("Short date format."))
.Token("ShortTime", T("Short Time"), T("Short time format."))
.Token("Long", T("Long Date and Time"), T("Long date and time format."))
@@ -45,8 +45,8 @@ namespace Orchard.Tokens.Providers {
.Token("Since", DateTimeRelative)
.Chain("Since", "Date", DateTimeRelative)
// {Date.Local}
.Token("Local", d => TimeZoneInfo.ConvertTimeFromUtc(d, _timeZone.Value))
.Chain("Local", "Date", d => TimeZoneInfo.ConvertTimeFromUtc(d, _timeZone.Value))
.Token("Local", d => _dateServices.ConvertToLocal(d))
.Chain("Local", "Date", d => _dateServices.ConvertToLocal(d))
// {Date.ShortDate}
.Token("ShortDate", d => d.ToString(_dateTimeLocalization.ShortDateFormat.Text, _cultureInfo.Value))
// {Date.ShortTime}

View File

@@ -2,7 +2,7 @@
using System.Globalization;
using Autofac;
using NUnit.Framework;
using Orchard.Core.Shapes.Localization;
using Orchard.Localization.Services;
using Orchard.Services;
using Orchard.Tokens.Implementation;
using Orchard.Tokens.Providers;
@@ -22,7 +22,7 @@ namespace Orchard.Tokens.Tests {
builder.RegisterType<Tokenizer>().As<ITokenizer>();
builder.RegisterType<DateTokens>().As<ITokenProvider>();
builder.RegisterType<StubClock>().As<IClock>();
builder.RegisterType<DateTimeLocalization>().As<IDateTimeLocalization>();
builder.RegisterType<DefaultDateTimeLocalization>().As<IDateTimeLocalization>();
builder.RegisterType<StubWorkContextAccessor>().As<IWorkContextAccessor>();
_container = builder.Build();
_tokenizer = _container.Resolve<ITokenizer>();

View File

@@ -8,30 +8,39 @@ namespace Orchard.Localization.Services {
public class DefaultDateServices : IDateServices {
public DefaultDateServices(IOrchardServices orchardServices) {
private readonly IOrchardServices _orchardServices;
private readonly IDateTimeLocalization _dateTimeLocalization;
private readonly Lazy<CultureInfo> _cultureInfo;
public DefaultDateServices(
IOrchardServices orchardServices,
IDateTimeLocalization dateTimeLocalization) {
_orchardServices = orchardServices;
_dateTimeLocalization = dateTimeLocalization;
_cultureInfo = new Lazy<CultureInfo>(() => CultureInfo.GetCultureInfo(_orchardServices.WorkContext.CurrentCulture));
}
private readonly IOrchardServices _orchardServices;
private readonly Lazy<CultureInfo> _cultureInfo;
public DateTime? ConvertToLocal(DateTime date) {
public virtual DateTime? ConvertToLocal(DateTime date) {
return ConvertToLocal(ToNullable(date));
}
public DateTime? ConvertToLocal(DateTime? date) {
public virtual DateTime? ConvertToLocal(DateTime? date) {
if (!date.HasValue) {
return null;
}
return TimeZoneInfo.ConvertTimeFromUtc(date.Value, _orchardServices.WorkContext.CurrentTimeZone);
}
public string ConvertToLocalString(DateTime date, string format, string nullText = null) {
public virtual string ConvertToLocalString(DateTime date, string nullText = null) {
return ConvertToLocalString(ToNullable(date), _dateTimeLocalization.LongDateTimeFormat.Text, nullText);
}
public virtual string ConvertToLocalString(DateTime date, string format, string nullText = null) {
return ConvertToLocalString(ToNullable(date), format, nullText);
}
public string ConvertToLocalString(DateTime? date, string format, string nullText = null) {
public virtual string ConvertToLocalString(DateTime? date, string format, string nullText = null) {
var localDate = ConvertToLocal(date);
if (!localDate.HasValue) {
return nullText;
@@ -39,34 +48,34 @@ namespace Orchard.Localization.Services {
return localDate.Value.ToString(format, _cultureInfo.Value);
}
public string ConvertToLocalDateString(DateTime date, string nullText = null) {
public virtual string ConvertToLocalDateString(DateTime date, string nullText = null) {
return ConvertToLocalDateString(ToNullable(date), nullText);
}
public string ConvertToLocalDateString(DateTime? date, string nullText = null) {
return ConvertToLocalString(date, "d", nullText);
public virtual string ConvertToLocalDateString(DateTime? date, string nullText = null) {
return ConvertToLocalString(date, _dateTimeLocalization.ShortDateFormat.Text, nullText);
}
public string ConvertToLocalTimeString(DateTime date, string nullText = null) {
public virtual string ConvertToLocalTimeString(DateTime date, string nullText = null) {
return ConvertToLocalTimeString(ToNullable(date), nullText);
}
public string ConvertToLocalTimeString(DateTime? date, string nullText = null) {
return ConvertToLocalString(date, "t", nullText);
public virtual string ConvertToLocalTimeString(DateTime? date, string nullText = null) {
return ConvertToLocalString(date, _dateTimeLocalization.ShortTimeFormat.Text, nullText);
}
public DateTime? ConvertFromLocal(DateTime date) {
public virtual DateTime? ConvertFromLocal(DateTime date) {
return ConvertToLocal(ToNullable(date));
}
public DateTime? ConvertFromLocal(DateTime? date) {
public virtual DateTime? ConvertFromLocal(DateTime? date) {
if (!date.HasValue) {
return null;
}
return TimeZoneInfo.ConvertTimeToUtc(date.Value, _orchardServices.WorkContext.CurrentTimeZone);
}
public DateTime? ConvertFromLocalString(string dateString) {
public virtual DateTime? ConvertFromLocalString(string dateString) {
if (String.IsNullOrWhiteSpace(dateString)) {
return null;
}
@@ -74,7 +83,7 @@ namespace Orchard.Localization.Services {
return ConvertFromLocal(localDate);
}
public DateTime? ConvertFromLocalString(string dateString, string timeString) {
public virtual DateTime? ConvertFromLocalString(string dateString, string timeString) {
if (String.IsNullOrWhiteSpace(dateString) && String.IsNullOrWhiteSpace(timeString)) {
return null;
}
@@ -84,7 +93,7 @@ namespace Orchard.Localization.Services {
return ConvertFromLocal(localDateTime);
}
private DateTime? ToNullable(DateTime date) {
protected virtual DateTime? ToNullable(DateTime date) {
return date == DateTime.MinValue ? new DateTime?() : new DateTime?(date);
}
}

View File

@@ -23,6 +23,14 @@ namespace Orchard.Localization.Services {
/// <returns></returns>
DateTime? ConvertToLocal(DateTime? date);
/// <summary>
/// Converts a non-nullable date from Gregorian calendar UTC to the Orchard configured calendar and time zone and formats it using the default long date and time format string.
/// </summary>
/// <param name="date">The non-nullable UTC date to convert. DateTime.MinValue is translated to null.</param>
/// <param name="nullText">A text to be returned if the supplied UTC date is equal to DateTime.MinValue.</param>
/// <returns></returns>
string ConvertToLocalString(DateTime date, string nullText = null);
/// <summary>
/// Converts a non-nullable date from Gregorian calendar UTC to the Orchard configured calendar and time zone and formats it using the specified format string using the Orchard configured culture.
/// </summary>

View File

@@ -0,0 +1,97 @@
using System;
using Orchard.Localization;
namespace Orchard.Localization.Services {
/// <summary>
/// Provides a set of localizable strings which in turn control localization of dates and
/// times in Orchard. These strings can be changed for other cultures using the normal
/// string localization process.
/// </summary>
public interface IDateTimeLocalization : IDependency {
/// <summary>
/// Returns a comma-separated list of month names.
/// </summary>
LocalizedString MonthNames {
get;
}
/// <summary>
/// Returns a comma-separated list of abbreviated month names.
/// </summary>
LocalizedString MonthNamesShort {
get;
}
/// <summary>
/// Returns a comma-separated list of weekday names.
/// </summary>
LocalizedString DayNames {
get;
}
/// <summary>
/// Returns a comma-separated list of abbreviated weekday names.
/// </summary>
LocalizedString DayNamesShort {
get;
}
/// <summary>
/// Returns a comma-separated list of maximally abbreviated weekday names.
/// </summary>
LocalizedString DayNamesMin {
get;
}
/// <summary>
/// Returns a standard or custom DateTime format string used to format dates for short date display.
/// </summary>
LocalizedString ShortDateFormat {
get;
}
/// <summary>
/// Returns a standard or custom DateTime format string used to format dates for short time display.
/// </summary>
LocalizedString ShortTimeFormat {
get;
}
/// <summary>
/// Returns a standard or custom DateTime format string used to format dates for general (short) date and time display.
/// </summary>
LocalizedString ShortDateTimeFormat {
get;
}
/// <summary>
/// Returns a standard or custom DateTime format string used to format dates for full date and time display.
/// </summary>
LocalizedString LongDateTimeFormat {
get;
}
/// <summary>
/// Returns an integer representing the first day of the week, where 0 is Sunday, 1 is Monday etc.
/// </summary>
int FirstDay {
get;
}
/// <summary>
/// Returns true if the year select precedes month, false for month then year.
/// </summary>
bool ShowMonthAfterYear {
get;
}
/// <summary>
/// Returns an additional text to append to the year in the month headers.
/// </summary>
string YearSuffix {
get;
}
}
}

View File

@@ -267,9 +267,11 @@
<Compile Include="FileSystems\Media\IMimeTypeProvider.cs" />
<Compile Include="Indexing\ISearchBits.cs" />
<Compile Include="Localization\Services\CurrentCultureWorkContext.cs" />
<Compile Include="Localization\Services\DefaultDateTimeLocalization.cs" />
<Compile Include="Localization\Services\DefaultDateServices.cs" />
<Compile Include="Localization\Services\DefaultLocalizedStringManager.cs" />
<Compile Include="Localization\Services\IDateServices.cs" />
<Compile Include="Localization\Services\IDateTimeLocalization.cs" />
<Compile Include="Localization\Services\ILocalizedStringManager.cs" />
<Compile Include="Logging\OrchardFileAppender.cs" />
<Compile Include="Logging\OrchardLog4netFactory.cs" />