| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2012 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions are | |
| 6 * met: | |
| 7 * | |
| 8 * * Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * * Redistributions in binary form must reproduce the above | |
| 11 * copyright notice, this list of conditions and the following disclaimer | |
| 12 * in the documentation and/or other materials provided with the | |
| 13 * distribution. | |
| 14 * * Neither the name of Google Inc. nor the names of its | |
| 15 * contributors may be used to endorse or promote products derived from | |
| 16 * this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 */ | |
| 30 | |
| 31 #include "config.h" | |
| 32 #include "core/platform/text/mac/LocaleMac.h" | |
| 33 | |
| 34 #import <Foundation/NSDateFormatter.h> | |
| 35 #import <Foundation/NSLocale.h> | |
| 36 #include "platform/Language.h" | |
| 37 #include "platform/LocalizedStrings.h" | |
| 38 #include "wtf/DateMath.h" | |
| 39 #include "wtf/PassOwnPtr.h" | |
| 40 #include "wtf/RetainPtr.h" | |
| 41 #include "wtf/text/StringBuilder.h" | |
| 42 | |
| 43 using namespace std; | |
| 44 | |
| 45 namespace WebCore { | |
| 46 | |
| 47 static inline String languageFromLocale(const String& locale) | |
| 48 { | |
| 49 String normalizedLocale = locale; | |
| 50 normalizedLocale.replace('-', '_'); | |
| 51 size_t separatorPosition = normalizedLocale.find('_'); | |
| 52 if (separatorPosition == kNotFound) | |
| 53 return normalizedLocale; | |
| 54 return normalizedLocale.left(separatorPosition); | |
| 55 } | |
| 56 | |
| 57 static RetainPtr<NSLocale> determineLocale(const String& locale) | |
| 58 { | |
| 59 RetainPtr<NSLocale> currentLocale = [NSLocale currentLocale]; | |
| 60 String currentLocaleLanguage = languageFromLocale(String([currentLocale.get(
) localeIdentifier])); | |
| 61 String localeLanguage = languageFromLocale(locale); | |
| 62 if (equalIgnoringCase(currentLocaleLanguage, localeLanguage)) | |
| 63 return currentLocale; | |
| 64 // It seems initWithLocaleIdentifier accepts dash-separated locale identifie
r. | |
| 65 return RetainPtr<NSLocale>(AdoptNS, [[NSLocale alloc] initWithLocaleIdentif
ier:locale]); | |
| 66 } | |
| 67 | |
| 68 PassOwnPtr<Locale> Locale::create(const AtomicString& locale) | |
| 69 { | |
| 70 return LocaleMac::create(determineLocale(locale.string()).get()); | |
| 71 } | |
| 72 | |
| 73 static RetainPtr<NSDateFormatter> createDateTimeFormatter(NSLocale* locale, NSCa
lendar* calendar, NSDateFormatterStyle dateStyle, NSDateFormatterStyle timeStyle
) | |
| 74 { | |
| 75 NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; | |
| 76 [formatter setLocale:locale]; | |
| 77 [formatter setDateStyle:dateStyle]; | |
| 78 [formatter setTimeStyle:timeStyle]; | |
| 79 [formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; | |
| 80 [formatter setCalendar:calendar]; | |
| 81 return adoptNS(formatter); | |
| 82 } | |
| 83 | |
| 84 LocaleMac::LocaleMac(NSLocale* locale) | |
| 85 : m_locale(locale) | |
| 86 , m_gregorianCalendar(AdoptNS, [[NSCalendar alloc] initWithCalendarIdentifie
r:NSGregorianCalendar]) | |
| 87 , m_didInitializeNumberData(false) | |
| 88 { | |
| 89 NSArray* availableLanguages = [NSLocale ISOLanguageCodes]; | |
| 90 // NSLocale returns a lower case NSLocaleLanguageCode so we don't have care
about case. | |
| 91 NSString* language = [m_locale.get() objectForKey:NSLocaleLanguageCode]; | |
| 92 if ([availableLanguages indexOfObject:language] == NSNotFound) | |
| 93 m_locale.adoptNS([[NSLocale alloc] initWithLocaleIdentifier:defaultLangu
age()]); | |
| 94 [m_gregorianCalendar.get() setLocale:m_locale.get()]; | |
| 95 } | |
| 96 | |
| 97 LocaleMac::~LocaleMac() | |
| 98 { | |
| 99 } | |
| 100 | |
| 101 PassOwnPtr<LocaleMac> LocaleMac::create(const String& localeIdentifier) | |
| 102 { | |
| 103 RetainPtr<NSLocale> locale = [[NSLocale alloc] initWithLocaleIdentifier:loca
leIdentifier]; | |
| 104 return adoptPtr(new LocaleMac(locale.get())); | |
| 105 } | |
| 106 | |
| 107 PassOwnPtr<LocaleMac> LocaleMac::create(NSLocale* locale) | |
| 108 { | |
| 109 return adoptPtr(new LocaleMac(locale)); | |
| 110 } | |
| 111 | |
| 112 RetainPtr<NSDateFormatter> LocaleMac::shortDateFormatter() | |
| 113 { | |
| 114 return createDateTimeFormatter(m_locale.get(), m_gregorianCalendar.get(), NS
DateFormatterShortStyle, NSDateFormatterNoStyle); | |
| 115 } | |
| 116 | |
| 117 const Vector<String>& LocaleMac::monthLabels() | |
| 118 { | |
| 119 if (!m_monthLabels.isEmpty()) | |
| 120 return m_monthLabels; | |
| 121 m_monthLabels.reserveCapacity(12); | |
| 122 NSArray *array = [shortDateFormatter().get() monthSymbols]; | |
| 123 if ([array count] == 12) { | |
| 124 for (unsigned i = 0; i < 12; ++i) | |
| 125 m_monthLabels.append(String([array objectAtIndex:i])); | |
| 126 return m_monthLabels; | |
| 127 } | |
| 128 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(WTF::monthFullName); ++i) | |
| 129 m_monthLabels.append(WTF::monthFullName[i]); | |
| 130 return m_monthLabels; | |
| 131 } | |
| 132 | |
| 133 #if ENABLE(CALENDAR_PICKER) | |
| 134 const Vector<String>& LocaleMac::weekDayShortLabels() | |
| 135 { | |
| 136 if (!m_weekDayShortLabels.isEmpty()) | |
| 137 return m_weekDayShortLabels; | |
| 138 m_weekDayShortLabels.reserveCapacity(7); | |
| 139 NSArray *array = [shortDateFormatter().get() shortWeekdaySymbols]; | |
| 140 if ([array count] == 7) { | |
| 141 for (unsigned i = 0; i < 7; ++i) | |
| 142 m_weekDayShortLabels.append(String([array objectAtIndex:i])); | |
| 143 return m_weekDayShortLabels; | |
| 144 } | |
| 145 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(WTF::weekdayName); ++i) { | |
| 146 // weekdayName starts with Monday. | |
| 147 m_weekDayShortLabels.append(WTF::weekdayName[(i + 6) % 7]); | |
| 148 } | |
| 149 return m_weekDayShortLabels; | |
| 150 } | |
| 151 | |
| 152 unsigned LocaleMac::firstDayOfWeek() | |
| 153 { | |
| 154 // The document for NSCalendar - firstWeekday doesn't have an explanation of | |
| 155 // firstWeekday value. We can guess it by the document of NSDateComponents - | |
| 156 // weekDay, so it can be 1 through 7 and 1 is Sunday. | |
| 157 return [m_gregorianCalendar.get() firstWeekday] - 1; | |
| 158 } | |
| 159 | |
| 160 bool LocaleMac::isRTL() | |
| 161 { | |
| 162 return NSLocaleLanguageDirectionRightToLeft == [NSLocale characterDirectionF
orLanguage:[NSLocale canonicalLanguageIdentifierFromString:[m_locale.get() local
eIdentifier]]]; | |
| 163 } | |
| 164 #endif | |
| 165 | |
| 166 RetainPtr<NSDateFormatter> LocaleMac::timeFormatter() | |
| 167 { | |
| 168 return createDateTimeFormatter(m_locale.get(), m_gregorianCalendar.get(), NS
DateFormatterNoStyle, NSDateFormatterMediumStyle); | |
| 169 } | |
| 170 | |
| 171 RetainPtr<NSDateFormatter> LocaleMac::shortTimeFormatter() | |
| 172 { | |
| 173 return createDateTimeFormatter(m_locale.get(), m_gregorianCalendar.get(), NS
DateFormatterNoStyle, NSDateFormatterShortStyle); | |
| 174 } | |
| 175 | |
| 176 RetainPtr<NSDateFormatter> LocaleMac::dateTimeFormatterWithSeconds() | |
| 177 { | |
| 178 return createDateTimeFormatter(m_locale.get(), m_gregorianCalendar.get(), NS
DateFormatterShortStyle, NSDateFormatterMediumStyle); | |
| 179 } | |
| 180 | |
| 181 RetainPtr<NSDateFormatter> LocaleMac::dateTimeFormatterWithoutSeconds() | |
| 182 { | |
| 183 return createDateTimeFormatter(m_locale.get(), m_gregorianCalendar.get(), NS
DateFormatterShortStyle, NSDateFormatterShortStyle); | |
| 184 } | |
| 185 | |
| 186 String LocaleMac::dateFormat() | |
| 187 { | |
| 188 if (!m_dateFormat.isNull()) | |
| 189 return m_dateFormat; | |
| 190 m_dateFormat = [shortDateFormatter().get() dateFormat]; | |
| 191 return m_dateFormat; | |
| 192 } | |
| 193 | |
| 194 String LocaleMac::monthFormat() | |
| 195 { | |
| 196 if (!m_monthFormat.isNull()) | |
| 197 return m_monthFormat; | |
| 198 // Gets a format for "MMMM" because Windows API always provides formats for | |
| 199 // "MMMM" in some locales. | |
| 200 m_monthFormat = [NSDateFormatter dateFormatFromTemplate:@"yyyyMMMM" options:
0 locale:m_locale.get()]; | |
| 201 return m_monthFormat; | |
| 202 } | |
| 203 | |
| 204 String LocaleMac::shortMonthFormat() | |
| 205 { | |
| 206 if (!m_shortMonthFormat.isNull()) | |
| 207 return m_shortMonthFormat; | |
| 208 m_shortMonthFormat = [NSDateFormatter dateFormatFromTemplate:@"yyyyMMM" opti
ons:0 locale:m_locale.get()]; | |
| 209 return m_shortMonthFormat; | |
| 210 } | |
| 211 | |
| 212 String LocaleMac::timeFormat() | |
| 213 { | |
| 214 if (!m_timeFormatWithSeconds.isNull()) | |
| 215 return m_timeFormatWithSeconds; | |
| 216 m_timeFormatWithSeconds = [timeFormatter().get() dateFormat]; | |
| 217 return m_timeFormatWithSeconds; | |
| 218 } | |
| 219 | |
| 220 String LocaleMac::shortTimeFormat() | |
| 221 { | |
| 222 if (!m_timeFormatWithoutSeconds.isNull()) | |
| 223 return m_timeFormatWithoutSeconds; | |
| 224 m_timeFormatWithoutSeconds = [shortTimeFormatter().get() dateFormat]; | |
| 225 return m_timeFormatWithoutSeconds; | |
| 226 } | |
| 227 | |
| 228 String LocaleMac::dateTimeFormatWithSeconds() | |
| 229 { | |
| 230 if (!m_dateTimeFormatWithSeconds.isNull()) | |
| 231 return m_dateTimeFormatWithSeconds; | |
| 232 m_dateTimeFormatWithSeconds = [dateTimeFormatterWithSeconds().get() dateForm
at]; | |
| 233 return m_dateTimeFormatWithSeconds; | |
| 234 } | |
| 235 | |
| 236 String LocaleMac::dateTimeFormatWithoutSeconds() | |
| 237 { | |
| 238 if (!m_dateTimeFormatWithoutSeconds.isNull()) | |
| 239 return m_dateTimeFormatWithoutSeconds; | |
| 240 m_dateTimeFormatWithoutSeconds = [dateTimeFormatterWithoutSeconds().get() da
teFormat]; | |
| 241 return m_dateTimeFormatWithoutSeconds; | |
| 242 } | |
| 243 | |
| 244 const Vector<String>& LocaleMac::shortMonthLabels() | |
| 245 { | |
| 246 if (!m_shortMonthLabels.isEmpty()) | |
| 247 return m_shortMonthLabels; | |
| 248 m_shortMonthLabels.reserveCapacity(12); | |
| 249 NSArray *array = [shortDateFormatter().get() shortMonthSymbols]; | |
| 250 if ([array count] == 12) { | |
| 251 for (unsigned i = 0; i < 12; ++i) | |
| 252 m_shortMonthLabels.append([array objectAtIndex:i]); | |
| 253 return m_shortMonthLabels; | |
| 254 } | |
| 255 for (unsigned i = 0; i < WTF_ARRAY_LENGTH(WTF::monthName); ++i) | |
| 256 m_shortMonthLabels.append(WTF::monthName[i]); | |
| 257 return m_shortMonthLabels; | |
| 258 } | |
| 259 | |
| 260 const Vector<String>& LocaleMac::standAloneMonthLabels() | |
| 261 { | |
| 262 if (!m_standAloneMonthLabels.isEmpty()) | |
| 263 return m_standAloneMonthLabels; | |
| 264 NSArray *array = [shortDateFormatter().get() standaloneMonthSymbols]; | |
| 265 if ([array count] == 12) { | |
| 266 m_standAloneMonthLabels.reserveCapacity(12); | |
| 267 for (unsigned i = 0; i < 12; ++i) | |
| 268 m_standAloneMonthLabels.append([array objectAtIndex:i]); | |
| 269 return m_standAloneMonthLabels; | |
| 270 } | |
| 271 m_standAloneMonthLabels = shortMonthLabels(); | |
| 272 return m_standAloneMonthLabels; | |
| 273 } | |
| 274 | |
| 275 const Vector<String>& LocaleMac::shortStandAloneMonthLabels() | |
| 276 { | |
| 277 if (!m_shortStandAloneMonthLabels.isEmpty()) | |
| 278 return m_shortStandAloneMonthLabels; | |
| 279 NSArray *array = [shortDateFormatter().get() shortStandaloneMonthSymbols]; | |
| 280 if ([array count] == 12) { | |
| 281 m_shortStandAloneMonthLabels.reserveCapacity(12); | |
| 282 for (unsigned i = 0; i < 12; ++i) | |
| 283 m_shortStandAloneMonthLabels.append([array objectAtIndex:i]); | |
| 284 return m_shortStandAloneMonthLabels; | |
| 285 } | |
| 286 m_shortStandAloneMonthLabels = shortMonthLabels(); | |
| 287 return m_shortStandAloneMonthLabels; | |
| 288 } | |
| 289 | |
| 290 const Vector<String>& LocaleMac::timeAMPMLabels() | |
| 291 { | |
| 292 if (!m_timeAMPMLabels.isEmpty()) | |
| 293 return m_timeAMPMLabels; | |
| 294 m_timeAMPMLabels.reserveCapacity(2); | |
| 295 RetainPtr<NSDateFormatter> formatter = shortTimeFormatter(); | |
| 296 m_timeAMPMLabels.append([formatter.get() AMSymbol]); | |
| 297 m_timeAMPMLabels.append([formatter.get() PMSymbol]); | |
| 298 return m_timeAMPMLabels; | |
| 299 } | |
| 300 | |
| 301 void LocaleMac::initializeLocaleData() | |
| 302 { | |
| 303 if (m_didInitializeNumberData) | |
| 304 return; | |
| 305 m_didInitializeNumberData = true; | |
| 306 | |
| 307 RetainPtr<NSNumberFormatter> formatter(AdoptNS, [[NSNumberFormatter alloc] i
nit]); | |
| 308 [formatter.get() setLocale:m_locale.get()]; | |
| 309 [formatter.get() setNumberStyle:NSNumberFormatterDecimalStyle]; | |
| 310 [formatter.get() setUsesGroupingSeparator:NO]; | |
| 311 | |
| 312 RetainPtr<NSNumber> sampleNumber(AdoptNS, [[NSNumber alloc] initWithDouble:9
876543210]); | |
| 313 String nineToZero([formatter.get() stringFromNumber:sampleNumber.get()]); | |
| 314 if (nineToZero.length() != 10) | |
| 315 return; | |
| 316 Vector<String, DecimalSymbolsSize> symbols; | |
| 317 for (unsigned i = 0; i < 10; ++i) | |
| 318 symbols.append(nineToZero.substring(9 - i, 1)); | |
| 319 ASSERT(symbols.size() == DecimalSeparatorIndex); | |
| 320 symbols.append([formatter.get() decimalSeparator]); | |
| 321 ASSERT(symbols.size() == GroupSeparatorIndex); | |
| 322 symbols.append([formatter.get() groupingSeparator]); | |
| 323 ASSERT(symbols.size() == DecimalSymbolsSize); | |
| 324 | |
| 325 String positivePrefix([formatter.get() positivePrefix]); | |
| 326 String positiveSuffix([formatter.get() positiveSuffix]); | |
| 327 String negativePrefix([formatter.get() negativePrefix]); | |
| 328 String negativeSuffix([formatter.get() negativeSuffix]); | |
| 329 setLocaleData(symbols, positivePrefix, positiveSuffix, negativePrefix, negat
iveSuffix); | |
| 330 } | |
| 331 | |
| 332 } | |
| OLD | NEW |