Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/intl/locale/windows/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 11 kB image not shown  

Quelle  OSPreferences_win.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "OSPreferences.h"
#include "mozilla/intl/Locale.h"
#include "mozilla/intl/LocaleService.h"
#include "nsReadableUtils.h"

#include <windows.h>

#ifndef __MINGW32__  // WinRT headers not yet supported by MinGW
#  include <roapi.h>
#  include <wrl.h>
#  include <Windows.System.UserProfile.h>

using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation::Collections;
using namespace ABI::Windows::System::UserProfile;
#endif

using namespace mozilla::intl;

OSPreferences::OSPreferences() {}

bool OSPreferences::ReadSystemLocales(nsTArray<nsCString>& aLocaleList) {
  MOZ_ASSERT(aLocaleList.IsEmpty());

#ifndef __MINGW32__
  // Try to get language list from GlobalizationPreferences; if this fails,
  // we'll fall back to GetUserPreferredUILanguages.
  // Per MSDN, these APIs are not available prior to Win8.
  ComPtr<IGlobalizationPreferencesStatics> globalizationPrefs;
  ComPtr<IVectorView<HSTRING>> languages;
  uint32_t count;
  if (SUCCEEDED(RoGetActivationFactory(
          HStringReference(
              RuntimeClass_Windows_System_UserProfile_GlobalizationPreferences)
              .Get(),
          IID_PPV_ARGS(&globalizationPrefs))) &&
      SUCCEEDED(globalizationPrefs->get_Languages(&languages)) &&
      SUCCEEDED(languages->get_Size(&count))) {
    for (uint32_t i = 0; i < count; ++i) {
      HString lang;
      if (SUCCEEDED(languages->GetAt(i, lang.GetAddressOf()))) {
        unsigned int length;
        const wchar_t* text = lang.GetRawBuffer(&length);
        NS_LossyConvertUTF16toASCII loc(text, length);
        if (CanonicalizeLanguageTag(loc)) {
          if (!loc.Contains('-')) {
            // DirectWrite font-name code doesn't like to be given a bare
            // language code with no region subtag, but the
            // GlobalizationPreferences API may give us one (e.g. "ja").
            // So if there's no hyphen in the string at this point, we use
            // AddLikelySubtags to get a suitable region code to
            // go with it.
            Locale locale;
            auto result = LocaleParser::TryParse(loc, locale);
            if (result.isOk() && locale.AddLikelySubtags().isOk() &&
                locale.Region().Present()) {
              loc.Append('-');
              loc.Append(locale.Region().Span());
            }
          }
          aLocaleList.AppendElement(loc);
        }
      }
    }
  }
#endif

  // Per MSDN, GetUserPreferredUILanguages is available from Vista onwards,
  // so we can use it unconditionally (although it may not work well!)
  if (aLocaleList.IsEmpty()) {
    // Note that according to the questioner at
    // https://stackoverflow.com/questions/52849233/getuserpreferreduilanguages-never-returns-more-than-two-languages,
    // this may not always return the full list of languages we'd expect.
    // We should always get at least the first-preference lang, though.
    ULONG numLanguages = 0;
    DWORD cchLanguagesBuffer = 0;
    if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &numLanguages, nullptr,
                                     &cchLanguagesBuffer)) {
      return false;
    }

    AutoTArray<WCHAR, 64> locBuffer;
    locBuffer.SetCapacity(cchLanguagesBuffer);
    if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &numLanguages,
                                     locBuffer.Elements(),
                                     &cchLanguagesBuffer)) {
      return false;
    }

    const WCHAR* start = locBuffer.Elements();
    const WCHAR* bufEnd = start + cchLanguagesBuffer;
    while (bufEnd - start > 1 && *start) {
      const WCHAR* end = start + 1;
      while (bufEnd - end > 1 && *end) {
        end++;
      }
      NS_LossyConvertUTF16toASCII loc(start, end - start);
      if (CanonicalizeLanguageTag(loc)) {
        aLocaleList.AppendElement(loc);
      }
      start = end + 1;
    }
  }

  return !aLocaleList.IsEmpty();
}

bool OSPreferences::ReadRegionalPrefsLocales(nsTArray<nsCString>& aLocaleList) {
  MOZ_ASSERT(aLocaleList.IsEmpty());

  WCHAR locale[LOCALE_NAME_MAX_LENGTH];
  if (NS_WARN_IF(!LCIDToLocaleName(LOCALE_USER_DEFAULT, locale,
                                   LOCALE_NAME_MAX_LENGTH, 0))) {
    return false;
  }

  NS_LossyConvertUTF16toASCII loc(locale);

  if (CanonicalizeLanguageTag(loc)) {
    aLocaleList.AppendElement(loc);
    return true;
  }
  return false;
}

static LCTYPE ToDateLCType(OSPreferences::DateTimeFormatStyle aFormatStyle) {
  switch (aFormatStyle) {
    case OSPreferences::DateTimeFormatStyle::None:
      return LOCALE_SLONGDATE;
    case OSPreferences::DateTimeFormatStyle::Short:
      return LOCALE_SSHORTDATE;
    case OSPreferences::DateTimeFormatStyle::Medium:
      return LOCALE_SSHORTDATE;
    case OSPreferences::DateTimeFormatStyle::Long:
      return LOCALE_SLONGDATE;
    case OSPreferences::DateTimeFormatStyle::Full:
      return LOCALE_SLONGDATE;
    case OSPreferences::DateTimeFormatStyle::Invalid:
    default:
      MOZ_ASSERT_UNREACHABLE("invalid date format");
      return LOCALE_SLONGDATE;
  }
}

static LCTYPE ToTimeLCType(OSPreferences::DateTimeFormatStyle aFormatStyle) {
  switch (aFormatStyle) {
    case OSPreferences::DateTimeFormatStyle::None:
      return LOCALE_STIMEFORMAT;
    case OSPreferences::DateTimeFormatStyle::Short:
      return LOCALE_SSHORTTIME;
    case OSPreferences::DateTimeFormatStyle::Medium:
      return LOCALE_SSHORTTIME;
    case OSPreferences::DateTimeFormatStyle::Long:
      return LOCALE_STIMEFORMAT;
    case OSPreferences::DateTimeFormatStyle::Full:
      return LOCALE_STIMEFORMAT;
    case OSPreferences::DateTimeFormatStyle::Invalid:
    default:
      MOZ_ASSERT_UNREACHABLE("invalid time format");
      return LOCALE_STIMEFORMAT;
  }
}

/**
 * Windows API includes regional preferences from the user only
 * if we pass empty locale string or if the locale string matches
 * the current locale.
 *
 * Since Windows API only allows us to retrieve two options - short/long
 * we map it to our four options as:
 *
 *   short  -> short
 *   medium -> short
 *   long   -> long
 *   full   -> long
 *
 * In order to produce a single date/time format, we use CLDR pattern
 * for combined date/time string, since Windows API does not provide an
 * option for this.
 */

bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
                                        DateTimeFormatStyle aTimeStyle,
                                        const nsACString& aLocale,
                                        nsACString& aRetVal) {
  nsAutoString localeName;
  CopyASCIItoUTF16(aLocale, localeName);

  bool isDate = aDateStyle != DateTimeFormatStyle::None &&
                aDateStyle != DateTimeFormatStyle::Invalid;
  bool isTime = aTimeStyle != DateTimeFormatStyle::None &&
                aTimeStyle != DateTimeFormatStyle::Invalid;

  // If both date and time are wanted, we'll initially read them into a
  // local string, and then insert them into the overall date+time pattern;
  nsAutoString str;
  if (isDate && isTime) {
    if (!GetDateTimeConnectorPattern(aLocale, aRetVal)) {
      NS_WARNING("failed to get date/time connector");
      aRetVal.AssignLiteral("{1} {0}");
    }
  } else if (!isDate && !isTime) {
    aRetVal.Truncate(0);
    return true;
  }

  if (isDate) {
    LCTYPE lcType = ToDateLCType(aDateStyle);
    size_t len = GetLocaleInfoEx(
        reinterpret_cast<const wchar_t*>(localeName.BeginReading()), lcType,
        nullptr, 0);
    if (len == 0) {
      return false;
    }

    // We're doing it to ensure the terminator will fit when Windows writes the
    // data to its output buffer. See bug 1358159 for details.
    str.SetLength(len);
    GetLocaleInfoEx(reinterpret_cast<const wchar_t*>(localeName.BeginReading()),
                    lcType, (WCHAR*)str.BeginWriting(), len);
    str.SetLength(len - 1);  // -1 because len counts the null terminator

    // Windows uses "ddd" and "dddd" for abbreviated and full day names
    // respectively,
    //   https://msdn.microsoft.com/en-us/library/windows/desktop/dd317787(v=vs.85).aspx
    // but in a CLDR/ICU-style pattern these should be "EEE" and "EEEE".
    //   http://userguide.icu-project.org/formatparse/datetime
    // So we fix that up here.
    nsAString::const_iterator start, pos, end;
    start = str.BeginReading(pos);
    str.EndReading(end);
    if (FindInReadable(u"dddd"_ns, pos, end)) {
      str.ReplaceLiteral(pos - start, 4, u"EEEE");
    } else {
      pos = start;
      if (FindInReadable(u"ddd"_ns, pos, end)) {
        str.ReplaceLiteral(pos - start, 3, u"EEE");
      }
    }

    // Also, Windows uses lowercase "g" or "gg" for era, but ICU wants uppercase
    // "G" (it would interpret "g" as "modified Julian day"!). So fix that.
    int32_t index = str.FindChar('g');
    if (index >= 0) {
      str.Replace(index, 1, 'G');
      // If it was a double "gg", just drop the second one.
      index++;
      if (str.CharAt(index) == 'g') {
        str.Cut(index, 1);
      }
    }

    // If time was also requested, we need to substitute the date pattern from
    // Windows into the date+time format that we have in aRetVal.
    if (isTime) {
      nsACString::const_iterator start, pos, end;
      start = aRetVal.BeginReading(pos);
      aRetVal.EndReading(end);
      if (FindInReadable("{1}"_ns, pos, end)) {
        aRetVal.Replace(pos - start, 3, NS_ConvertUTF16toUTF8(str));
      }
    } else {
      aRetVal = NS_ConvertUTF16toUTF8(str);
    }
  }

  if (isTime) {
    LCTYPE lcType = ToTimeLCType(aTimeStyle);
    size_t len = GetLocaleInfoEx(
        reinterpret_cast<const wchar_t*>(localeName.BeginReading()), lcType,
        nullptr, 0);
    if (len == 0) {
      return false;
    }

    // We're doing it to ensure the terminator will fit when Windows writes the
    // data to its output buffer. See bug 1358159 for details.
    str.SetLength(len);
    GetLocaleInfoEx(reinterpret_cast<const wchar_t*>(localeName.BeginReading()),
                    lcType, (WCHAR*)str.BeginWriting(), len);
    str.SetLength(len - 1);

    // Windows uses "t" or "tt" for a "time marker" (am/pm indicator),
    //   https://msdn.microsoft.com/en-us/library/windows/desktop/dd318148(v=vs.85).aspx
    // but in a CLDR/ICU-style pattern that should be "a".
    //   http://userguide.icu-project.org/formatparse/datetime
    // So we fix that up here.
    int32_t index = str.FindChar('t');
    if (index >= 0) {
      str.Replace(index, 1, 'a');
      index++;
      if (str.CharAt(index) == 't') {
        str.Cut(index, 1);
      }
    }

    if (isDate) {
      nsACString::const_iterator start, pos, end;
      start = aRetVal.BeginReading(pos);
      aRetVal.EndReading(end);
      if (FindInReadable("{0}"_ns, pos, end)) {
        aRetVal.Replace(pos - start, 3, NS_ConvertUTF16toUTF8(str));
      }
    } else {
      aRetVal = NS_ConvertUTF16toUTF8(str);
    }
  }

  return true;
}

void OSPreferences::RemoveObservers() {}

Messung V0.5
C=88 H=96 G=91

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.