|
|
f7b64dc |
Implement customization of date and time format with new FF91+ preferences
|
|
|
f7b64dc |
"intl.date_time.pattern_override.{date,time}_{short.medium,long,full}", plus
|
|
|
f7b64dc |
"intl.date_time.pattern_override.connector_short".
|
|
|
f7b64dc |
|
|
|
f7b64dc |
See user guide at https://support.mozilla.org/en-US/kb/customize-date-time-formats-thunderbird
|
|
|
f7b64dc |
|
|
|
f7b64dc |
As usual, a lot of additional things were changed during the implementation of this feature.
|
|
|
f7b64dc |
Originally, it is bug 1426907 (5 commits) plus 1674212 plus 1706318. As prerequisite, bug 1669573
|
|
|
f7b64dc |
(6 commits) plus 1671532 plus 1671695 plus 1681251 are needed (and then two commits of 1672548
|
|
|
f7b64dc |
to return back a feature which was broken by 1669573-3).
|
|
|
f7b64dc |
|
|
|
f7b64dc |
Fortunately, the actually needed changes can be safely applied in a minimal form:
|
|
|
f7b64dc |
|
|
|
f7b64dc |
- get 1426907 commit 5 (https://bugzilla.mozilla.org/show_bug.cgi?id=1426907#c179)
|
|
|
f7b64dc |
- drop observer/callback stuff for simplicity (the cost is user have to restart SM
|
|
|
f7b64dc |
to take changes effect), drop tests
|
|
|
f7b64dc |
- add 1674212, drop tests
|
|
|
f7b64dc |
- add 1706318 (it just renames pref from 1674212)
|
|
|
f7b64dc |
- in the changes added, revert back from "CString" to "String" (since we do not apply 1426907 part 4).
|
|
|
f7b64dc |
|
|
|
f7b64dc |
This patch is against SeaMonkey 2.53.8.1 tree.
|
|
|
f7b64dc |
|
|
|
f7b64dc |
|
|
|
f7b64dc |
--- mozilla/intl/locale/OSPreferences.cpp.orig 2020-10-20 22:17:58.000000000 +0300
|
|
|
f7b64dc |
+++ mozilla/intl/locale/OSPreferences.cpp 2021-08-23 21:32:05.586135214 +0300
|
|
|
f7b64dc |
@@ -226,16 +226,136 @@ OSPreferences::GetDateTimeSkeletonForSty
|
|
|
f7b64dc |
return false;
|
|
|
f7b64dc |
}
|
|
|
f7b64dc |
|
|
|
f7b64dc |
aRetVal.Assign((const char16_t*)skeleton, skelsize);
|
|
|
f7b64dc |
return true;
|
|
|
f7b64dc |
}
|
|
|
f7b64dc |
|
|
|
f7b64dc |
/**
|
|
|
f7b64dc |
+ * This method checks for preferences that override the defaults
|
|
|
f7b64dc |
+ */
|
|
|
f7b64dc |
+bool OSPreferences::OverrideDateTimePattern(DateTimeFormatStyle aDateStyle,
|
|
|
f7b64dc |
+ DateTimeFormatStyle aTimeStyle,
|
|
|
f7b64dc |
+ const nsACString& aLocale,
|
|
|
f7b64dc |
+ nsAString& aRetVal) {
|
|
|
f7b64dc |
+ const auto PrefToMaybeString = [](const char* pref) -> Maybe<nsAutoString> {
|
|
|
f7b64dc |
+ nsAutoString value;
|
|
|
f7b64dc |
+ nsresult nr = Preferences::GetString(pref, value);
|
|
|
f7b64dc |
+ if (NS_FAILED(nr) || value.IsEmpty()) {
|
|
|
f7b64dc |
+ return Nothing();
|
|
|
f7b64dc |
+ }
|
|
|
f7b64dc |
+ return Some(std::move(value));
|
|
|
f7b64dc |
+ };
|
|
|
f7b64dc |
+
|
|
|
f7b64dc |
+ Maybe<nsAutoString> timeSkeleton;
|
|
|
f7b64dc |
+ switch (aTimeStyle) {
|
|
|
f7b64dc |
+ case DateTimeFormatStyle::Short:
|
|
|
f7b64dc |
+ timeSkeleton =
|
|
|
f7b64dc |
+ PrefToMaybeString("intl.date_time.pattern_override.time_short");
|
|
|
f7b64dc |
+ break;
|
|
|
f7b64dc |
+ case DateTimeFormatStyle::Medium:
|
|
|
f7b64dc |
+ timeSkeleton =
|
|
|
f7b64dc |
+ PrefToMaybeString("intl.date_time.pattern_override.time_medium");
|
|
|
f7b64dc |
+ break;
|
|
|
f7b64dc |
+ case DateTimeFormatStyle::Long:
|
|
|
f7b64dc |
+ timeSkeleton =
|
|
|
f7b64dc |
+ PrefToMaybeString("intl.date_time.pattern_override.time_long");
|
|
|
f7b64dc |
+ break;
|
|
|
f7b64dc |
+ case DateTimeFormatStyle::Full:
|
|
|
f7b64dc |
+ timeSkeleton =
|
|
|
f7b64dc |
+ PrefToMaybeString("intl.date_time.pattern_override.time_full");
|
|
|
f7b64dc |
+ break;
|
|
|
f7b64dc |
+ default:
|
|
|
f7b64dc |
+ break;
|
|
|
f7b64dc |
+ }
|
|
|
f7b64dc |
+
|
|
|
f7b64dc |
+ Maybe<nsAutoString> dateSkeleton;
|
|
|
f7b64dc |
+ switch (aDateStyle) {
|
|
|
f7b64dc |
+ case DateTimeFormatStyle::Short:
|
|
|
f7b64dc |
+ dateSkeleton =
|
|
|
f7b64dc |
+ PrefToMaybeString("intl.date_time.pattern_override.date_short");
|
|
|
f7b64dc |
+ break;
|
|
|
f7b64dc |
+ case DateTimeFormatStyle::Medium:
|
|
|
f7b64dc |
+ dateSkeleton =
|
|
|
f7b64dc |
+ PrefToMaybeString("intl.date_time.pattern_override.date_medium");
|
|
|
f7b64dc |
+ break;
|
|
|
f7b64dc |
+ case DateTimeFormatStyle::Long:
|
|
|
f7b64dc |
+ dateSkeleton =
|
|
|
f7b64dc |
+ PrefToMaybeString("intl.date_time.pattern_override.date_long");
|
|
|
f7b64dc |
+ break;
|
|
|
f7b64dc |
+ case DateTimeFormatStyle::Full:
|
|
|
f7b64dc |
+ dateSkeleton =
|
|
|
f7b64dc |
+ PrefToMaybeString("intl.date_time.pattern_override.date_full");
|
|
|
f7b64dc |
+ break;
|
|
|
f7b64dc |
+ default:
|
|
|
f7b64dc |
+ break;
|
|
|
f7b64dc |
+ }
|
|
|
f7b64dc |
+
|
|
|
f7b64dc |
+ nsAutoCString locale;
|
|
|
f7b64dc |
+ if (aLocale.IsEmpty()) {
|
|
|
f7b64dc |
+ AutoTArray<nsCString, 10> regionalPrefsLocales;
|
|
|
f7b64dc |
+ LocaleService::GetInstance()->GetRegionalPrefsLocales(regionalPrefsLocales);
|
|
|
f7b64dc |
+ locale.Assign(regionalPrefsLocales[0]);
|
|
|
f7b64dc |
+ } else {
|
|
|
f7b64dc |
+ locale.Assign(aLocale);
|
|
|
f7b64dc |
+ }
|
|
|
f7b64dc |
+
|
|
|
f7b64dc |
+ const auto FillConnectorPattern = [&locale](
|
|
|
f7b64dc |
+ const nsAutoString& datePattern,
|
|
|
f7b64dc |
+ const nsAutoString& timePattern) {
|
|
|
f7b64dc |
+ nsAutoString pattern;
|
|
|
f7b64dc |
+ GetDateTimeConnectorPattern(nsDependentCString(locale.get()), pattern);
|
|
|
f7b64dc |
+ int32_t index = pattern.Find("{1}");
|
|
|
f7b64dc |
+ if (index != kNotFound) {
|
|
|
f7b64dc |
+ pattern.Replace(index, 3, datePattern);
|
|
|
f7b64dc |
+ }
|
|
|
f7b64dc |
+ index = pattern.Find("{0}");
|
|
|
f7b64dc |
+ if (index != kNotFound) {
|
|
|
f7b64dc |
+ pattern.Replace(index, 3, timePattern);
|
|
|
f7b64dc |
+ }
|
|
|
f7b64dc |
+ return pattern;
|
|
|
f7b64dc |
+ };
|
|
|
f7b64dc |
+
|
|
|
f7b64dc |
+ if (timeSkeleton && dateSkeleton) {
|
|
|
f7b64dc |
+ aRetVal.Assign(FillConnectorPattern(*dateSkeleton, *timeSkeleton));
|
|
|
f7b64dc |
+ } else if (timeSkeleton) {
|
|
|
f7b64dc |
+ if (aDateStyle != DateTimeFormatStyle::None) {
|
|
|
f7b64dc |
+ nsAutoString pattern;
|
|
|
f7b64dc |
+ if (!ReadDateTimePattern(aDateStyle, DateTimeFormatStyle::None, aLocale,
|
|
|
f7b64dc |
+ pattern) &&
|
|
|
f7b64dc |
+ !GetDateTimePatternForStyle(aDateStyle, DateTimeFormatStyle::None,
|
|
|
f7b64dc |
+ aLocale, pattern)) {
|
|
|
f7b64dc |
+ return false;
|
|
|
f7b64dc |
+ }
|
|
|
f7b64dc |
+ aRetVal.Assign(FillConnectorPattern(pattern, *timeSkeleton));
|
|
|
f7b64dc |
+ } else {
|
|
|
f7b64dc |
+ aRetVal.Assign(*timeSkeleton);
|
|
|
f7b64dc |
+ }
|
|
|
f7b64dc |
+ } else if (dateSkeleton) {
|
|
|
f7b64dc |
+ if (aTimeStyle != DateTimeFormatStyle::None) {
|
|
|
f7b64dc |
+ nsAutoString pattern;
|
|
|
f7b64dc |
+ if (!ReadDateTimePattern(DateTimeFormatStyle::None, aTimeStyle, aLocale,
|
|
|
f7b64dc |
+ pattern) &&
|
|
|
f7b64dc |
+ !GetDateTimePatternForStyle(DateTimeFormatStyle::None, aTimeStyle,
|
|
|
f7b64dc |
+ aLocale, pattern)) {
|
|
|
f7b64dc |
+ return false;
|
|
|
f7b64dc |
+ }
|
|
|
f7b64dc |
+ aRetVal.Assign(FillConnectorPattern(*dateSkeleton, pattern));
|
|
|
f7b64dc |
+ } else {
|
|
|
f7b64dc |
+ aRetVal.Assign(*dateSkeleton);
|
|
|
f7b64dc |
+ }
|
|
|
f7b64dc |
+ } else {
|
|
|
f7b64dc |
+ return false;
|
|
|
f7b64dc |
+ }
|
|
|
f7b64dc |
+
|
|
|
f7b64dc |
+ return true;
|
|
|
f7b64dc |
+}
|
|
|
f7b64dc |
+
|
|
|
f7b64dc |
+/**
|
|
|
f7b64dc |
* This function is a counterpart to GetDateTimeSkeletonForStyle.
|
|
|
f7b64dc |
*
|
|
|
f7b64dc |
* It takes a skeleton and returns the best available pattern for a given locale
|
|
|
f7b64dc |
* that represents the provided skeleton.
|
|
|
f7b64dc |
*
|
|
|
f7b64dc |
* For example:
|
|
|
f7b64dc |
* "Hm" skeleton for "en-US" will return "H:m"
|
|
|
f7b64dc |
*/
|
|
|
f7b64dc |
@@ -275,16 +395,27 @@ OSPreferences::GetPatternForSkeleton(con
|
|
|
f7b64dc |
*
|
|
|
f7b64dc |
* An example output is "{1}, {0}".
|
|
|
f7b64dc |
*/
|
|
|
f7b64dc |
bool
|
|
|
f7b64dc |
OSPreferences::GetDateTimeConnectorPattern(const nsACString& aLocale,
|
|
|
f7b64dc |
nsAString& aRetVal)
|
|
|
f7b64dc |
{
|
|
|
f7b64dc |
bool result = false;
|
|
|
f7b64dc |
+
|
|
|
f7b64dc |
+ // Check for a valid override pref and use that if present.
|
|
|
f7b64dc |
+ nsAutoString value;
|
|
|
f7b64dc |
+ nsresult nr = Preferences::GetString(
|
|
|
f7b64dc |
+ "intl.date_time.pattern_override.connector_short", value);
|
|
|
f7b64dc |
+ if (NS_SUCCEEDED(nr) && value.Find("{0}") != kNotFound &&
|
|
|
f7b64dc |
+ value.Find("{1}") != kNotFound) {
|
|
|
f7b64dc |
+ aRetVal = std::move(value);
|
|
|
f7b64dc |
+ return true;
|
|
|
f7b64dc |
+ }
|
|
|
f7b64dc |
+
|
|
|
f7b64dc |
UErrorCode status = U_ZERO_ERROR;
|
|
|
f7b64dc |
UDateTimePatternGenerator* pg = udatpg_open(PromiseFlatCString(aLocale).get(), &status);
|
|
|
f7b64dc |
if (U_SUCCESS(status)) {
|
|
|
f7b64dc |
int32_t resultSize;
|
|
|
f7b64dc |
const UChar* value = udatpg_getDateTimeFormat(pg, &resultSize);
|
|
|
f7b64dc |
MOZ_ASSERT(resultSize >= 0);
|
|
|
f7b64dc |
|
|
|
f7b64dc |
aRetVal.Assign((char16_t*)value, resultSize);
|
|
|
f7b64dc |
@@ -409,19 +540,21 @@ OSPreferences::GetDateTimePattern(int32_
|
|
|
f7b64dc |
key.AppendInt(aTimeFormatStyle);
|
|
|
f7b64dc |
|
|
|
f7b64dc |
nsString pattern;
|
|
|
f7b64dc |
if (mPatternCache.Get(key, &pattern)) {
|
|
|
f7b64dc |
aRetVal = pattern;
|
|
|
f7b64dc |
return NS_OK;
|
|
|
f7b64dc |
}
|
|
|
f7b64dc |
|
|
|
f7b64dc |
- if (!ReadDateTimePattern(dateStyle, timeStyle, aLocale, pattern)) {
|
|
|
f7b64dc |
- if (!GetDateTimePatternForStyle(dateStyle, timeStyle, aLocale, pattern)) {
|
|
|
f7b64dc |
- return NS_ERROR_FAILURE;
|
|
|
f7b64dc |
+ if (!OverrideDateTimePattern(dateStyle, timeStyle, aLocale, pattern)) {
|
|
|
f7b64dc |
+ if (!ReadDateTimePattern(dateStyle, timeStyle, aLocale, pattern)) {
|
|
|
f7b64dc |
+ if (!GetDateTimePatternForStyle(dateStyle, timeStyle, aLocale, pattern)) {
|
|
|
f7b64dc |
+ return NS_ERROR_FAILURE;
|
|
|
f7b64dc |
+ }
|
|
|
f7b64dc |
}
|
|
|
f7b64dc |
}
|
|
|
f7b64dc |
|
|
|
f7b64dc |
if (mPatternCache.Count() == kMaxCachedPatterns) {
|
|
|
f7b64dc |
// Don't allow unlimited cache growth; just throw it away in the case of
|
|
|
f7b64dc |
// pathological behavior where a page keeps requesting different formats
|
|
|
f7b64dc |
// and locales.
|
|
|
f7b64dc |
NS_WARNING("flushing DateTimePattern cache");
|
|
|
f7b64dc |
--- mozilla/intl/locale/OSPreferences.h.orig 2020-10-20 22:17:58.000000000 +0300
|
|
|
f7b64dc |
+++ mozilla/intl/locale/OSPreferences.h 2021-08-23 22:07:02.638953273 +0300
|
|
|
f7b64dc |
@@ -163,16 +163,21 @@ private:
|
|
|
f7b64dc |
const nsACString& aLocale,
|
|
|
f7b64dc |
nsAString& aRetVal);
|
|
|
f7b64dc |
|
|
|
f7b64dc |
bool GetDateTimeSkeletonForStyle(DateTimeFormatStyle aDateStyle,
|
|
|
f7b64dc |
DateTimeFormatStyle aTimeStyle,
|
|
|
f7b64dc |
const nsACString& aLocale,
|
|
|
f7b64dc |
nsAString& aRetVal);
|
|
|
f7b64dc |
|
|
|
f7b64dc |
+ bool OverrideDateTimePattern(DateTimeFormatStyle aDateStyle,
|
|
|
f7b64dc |
+ DateTimeFormatStyle aTimeStyle,
|
|
|
f7b64dc |
+ const nsACString& aLocale,
|
|
|
f7b64dc |
+ nsAString& aRetVal);
|
|
|
f7b64dc |
+
|
|
|
f7b64dc |
bool GetPatternForSkeleton(const nsAString& aSkeleton,
|
|
|
f7b64dc |
const nsACString& aLocale,
|
|
|
f7b64dc |
nsAString& aRetVal);
|
|
|
f7b64dc |
|
|
|
f7b64dc |
/**
|
|
|
f7b64dc |
* This is a host environment specific method that will be implemented
|
|
|
f7b64dc |
* separately for each platform.
|
|
|
f7b64dc |
*
|