2010-06-25 07:18:20 +00:00
|
|
|
/* NSLocale.m
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
Copyright (C) 2010 Free Software Foundation, Inc.
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
Written by: Stefan Bidigaray
|
|
|
|
Date: June, 2010
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; see the file COPYING.LIB.
|
2010-07-19 07:54:52 +00:00
|
|
|
If not, see <http://www.gnu.org/licenses/> or write to the
|
|
|
|
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
2010-06-25 07:18:20 +00:00
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
2011-08-13 15:28:22 +00:00
|
|
|
#define EXPOSE_NSLocale_IVARS 1
|
2010-06-25 07:18:20 +00:00
|
|
|
#import "common.h"
|
|
|
|
#import "Foundation/NSLocale.h"
|
|
|
|
#import "Foundation/NSArray.h"
|
2010-12-15 01:41:34 +00:00
|
|
|
#import "Foundation/NSCalendar.h"
|
2010-06-25 17:57:03 +00:00
|
|
|
#import "Foundation/NSCoder.h"
|
2010-12-13 03:37:35 +00:00
|
|
|
#import "Foundation/NSCharacterSet.h"
|
2010-06-25 07:18:20 +00:00
|
|
|
#import "Foundation/NSDictionary.h"
|
|
|
|
#import "Foundation/NSLock.h"
|
2010-12-13 03:37:35 +00:00
|
|
|
#import "Foundation/NSValue.h"
|
2011-01-29 15:33:27 +00:00
|
|
|
#import "Foundation/NSNotification.h"
|
2011-01-09 21:16:20 +00:00
|
|
|
#import "Foundation/NSNumberFormatter.h"
|
2010-06-25 07:18:20 +00:00
|
|
|
#import "Foundation/NSUserDefaults.h"
|
|
|
|
#import "Foundation/NSString.h"
|
|
|
|
#import "GNUstepBase/GSLock.h"
|
|
|
|
|
2010-12-16 02:15:27 +00:00
|
|
|
NSString * const NSCurrentLocaleDidChangeNotification =
|
|
|
|
@"NSCurrentLocaleDidChangeNotification";
|
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
//
|
|
|
|
// NSLocale Component Keys
|
|
|
|
//
|
|
|
|
NSString * const NSLocaleIdentifier = @"NSLocaleIdentifier";
|
|
|
|
NSString * const NSLocaleLanguageCode = @"NSLocaleLanguageCode";
|
|
|
|
NSString * const NSLocaleCountryCode = @"NSLocaleCountryCode";
|
|
|
|
NSString * const NSLocaleScriptCode = @"NSLocaleScriptCode";
|
|
|
|
NSString * const NSLocaleVariantCode = @"NSLocaleVariantCode";
|
|
|
|
NSString * const NSLocaleExemplarCharacterSet = @"NSLocaleExemplarCharacterSet";
|
2010-12-16 02:15:27 +00:00
|
|
|
NSString * const NSLocaleCalendarIdentifier = @"calendar";
|
2010-06-25 07:18:20 +00:00
|
|
|
NSString * const NSLocaleCalendar = @"NSLocaleCalendar";
|
2010-12-16 02:15:27 +00:00
|
|
|
NSString * const NSLocaleCollationIdentifier = @"collation";
|
2010-06-25 07:18:20 +00:00
|
|
|
NSString * const NSLocaleUsesMetricSystem = @"NSLocaleUsesMetricSystem";
|
|
|
|
NSString * const NSLocaleMeasurementSystem = @"NSLocaleMeasurementSystem";
|
|
|
|
NSString * const NSLocaleDecimalSeparator = @"NSLocaleDecimalSeparator";
|
|
|
|
NSString * const NSLocaleGroupingSeparator = @"NSLocaleGroupingSeparator";
|
|
|
|
NSString * const NSLocaleCurrencySymbol = @"NSLocaleCurrencySymbol";
|
|
|
|
NSString * const NSLocaleCurrencyCode = @"NSLocaleCurrencyCode";
|
|
|
|
NSString * const NSLocaleCollatorIdentifier = @"NSLocaleCollatorIdentifier";
|
|
|
|
NSString * const NSLocaleQuotationBeginDelimiterKey =
|
|
|
|
@"NSLocaleQuotationBeginDelimiterKey";
|
2010-12-13 03:37:35 +00:00
|
|
|
NSString * const NSLocaleQuotationEndDelimiterKey =
|
|
|
|
@"NSLocaleQuotationEndDelimiterKey";
|
2010-06-25 07:18:20 +00:00
|
|
|
NSString * const NSLocaleAlternateQuotationBeginDelimiterKey =
|
|
|
|
@"NSLocaleAlternateQuotationBeginDelimiterKey";
|
|
|
|
NSString * const NSLocaleAlternateQuotationEndDelimiterKey =
|
|
|
|
@"NSLocaleAlternateQuotationEndDelimiterKey";
|
|
|
|
|
|
|
|
//
|
|
|
|
// NSLocale Calendar Keys
|
|
|
|
//
|
2010-12-13 03:37:35 +00:00
|
|
|
NSString * const NSGregorianCalendar = @"gregorian";
|
|
|
|
NSString * const NSBuddhistCalendar = @"buddhist";
|
|
|
|
NSString * const NSChineseCalendar = @"chinese";
|
|
|
|
NSString * const NSHebrewCalendar = @"hebrew";
|
|
|
|
NSString * const NSIslamicCalendar = @"islamic";
|
|
|
|
NSString * const NSIslamicCivilCalendar = @"islamic-civil";
|
|
|
|
NSString * const NSJapaneseCalendar = @"japanese";
|
|
|
|
NSString * const NSRepublicOfChinaCalendar = @"roc";
|
|
|
|
NSString * const NSPersianCalendar = @"persian";
|
|
|
|
NSString * const NSIndianCalendar = @"indian";
|
|
|
|
NSString * const NSISO8601Calendar = @"";
|
2010-06-25 07:18:20 +00:00
|
|
|
|
2010-10-27 11:24:44 +00:00
|
|
|
#if defined(HAVE_UNICODE_ULOC_H)
|
2010-06-25 16:42:09 +00:00
|
|
|
# include <unicode/uloc.h>
|
|
|
|
#endif
|
2010-10-27 11:24:44 +00:00
|
|
|
#if defined(HAVE_UNICODE_ULOCDATA_H)
|
2010-06-25 16:42:09 +00:00
|
|
|
# include <unicode/ulocdata.h>
|
|
|
|
#endif
|
2010-10-27 11:24:44 +00:00
|
|
|
#if defined(HAVE_UNICODE_UCURR_H)
|
2010-06-25 16:42:09 +00:00
|
|
|
# include <unicode/ucurr.h>
|
|
|
|
#endif
|
2010-06-25 07:18:20 +00:00
|
|
|
|
2011-01-09 15:54:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
@interface NSLocale (PrivateMethods)
|
|
|
|
+ (void) _updateCanonicalLocales;
|
|
|
|
- (NSString *) _getMeasurementSystem;
|
|
|
|
- (NSCharacterSet *) _getExemplarCharacterSet;
|
|
|
|
- (NSString *) _getDelimiterWithType: (NSInteger) delimiterType;
|
|
|
|
- (NSCalendar *) _getCalendar;
|
|
|
|
- (NSString *) _getDecimalSeparator;
|
|
|
|
- (NSString *) _getGroupingSeparator;
|
|
|
|
- (NSString *) _getCurrencySymbol;
|
|
|
|
- (NSString *) _getCurrencyCode;
|
|
|
|
@end
|
|
|
|
|
2010-12-16 10:09:43 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2010-06-25 07:18:20 +00:00
|
|
|
//
|
|
|
|
// ICU Component Keywords
|
|
|
|
//
|
|
|
|
static const char * ICUCalendarKeyword = "calendar";
|
|
|
|
static const char * ICUCollationKeyword = "collation";
|
|
|
|
|
2011-02-22 11:55:37 +00:00
|
|
|
static NSLocaleLanguageDirection
|
|
|
|
ICUToNSLocaleOrientation (ULayoutType layout)
|
2010-06-25 07:18:20 +00:00
|
|
|
{
|
|
|
|
switch (layout)
|
|
|
|
{
|
|
|
|
case ULOC_LAYOUT_LTR:
|
|
|
|
return NSLocaleLanguageDirectionLeftToRight;
|
|
|
|
case ULOC_LAYOUT_RTL:
|
|
|
|
return NSLocaleLanguageDirectionRightToLeft;
|
|
|
|
case ULOC_LAYOUT_TTB:
|
|
|
|
return NSLocaleLanguageDirectionTopToBottom;
|
|
|
|
case ULOC_LAYOUT_BTT:
|
|
|
|
return NSLocaleLanguageDirectionBottomToTop;
|
|
|
|
default:
|
|
|
|
return NSLocaleLanguageDirectionUnknown;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static NSArray *_currencyCodesWithType (uint32_t currType)
|
|
|
|
{
|
|
|
|
NSArray *result;
|
2011-02-12 06:51:42 +00:00
|
|
|
NSMutableArray *currencies;
|
2010-12-13 03:37:35 +00:00
|
|
|
UErrorCode err = U_ZERO_ERROR;
|
2010-07-19 07:54:52 +00:00
|
|
|
const char *currCode;
|
2011-02-12 06:51:42 +00:00
|
|
|
UEnumeration *codes;
|
|
|
|
|
|
|
|
codes = ucurr_openISOCurrencies (currType, &err);
|
2010-12-13 03:37:35 +00:00
|
|
|
if (U_FAILURE(err))
|
2010-06-25 07:18:20 +00:00
|
|
|
return nil;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2011-02-12 06:51:42 +00:00
|
|
|
currencies = [[NSMutableArray alloc] initWithCapacity: 10];
|
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
do
|
|
|
|
{
|
2010-12-13 03:37:35 +00:00
|
|
|
int strLength;
|
|
|
|
|
|
|
|
err = U_ZERO_ERROR;
|
|
|
|
currCode = uenum_next (codes, &strLength, &err);
|
|
|
|
if (U_FAILURE(err))
|
2010-06-25 07:18:20 +00:00
|
|
|
{
|
|
|
|
uenum_close (codes);
|
2011-02-12 06:51:42 +00:00
|
|
|
[currencies release];
|
2010-06-25 07:18:20 +00:00
|
|
|
return nil;
|
|
|
|
}
|
2010-12-13 03:37:35 +00:00
|
|
|
if (currCode == NULL)
|
|
|
|
break;
|
|
|
|
[currencies addObject: [NSString stringWithUTF8String: currCode]];
|
2010-06-25 07:18:20 +00:00
|
|
|
} while (NULL != currCode);
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
uenum_close (codes);
|
|
|
|
result = [NSArray arrayWithArray: currencies];
|
2011-02-12 06:51:42 +00:00
|
|
|
[currencies release];
|
2010-06-25 07:18:20 +00:00
|
|
|
return result;
|
|
|
|
}
|
2010-06-25 16:42:09 +00:00
|
|
|
#endif
|
2010-06-25 07:18:20 +00:00
|
|
|
|
|
|
|
@implementation NSLocale
|
|
|
|
|
2010-12-16 02:15:27 +00:00
|
|
|
static NSLocale *autoupdatingLocale = nil;
|
|
|
|
static NSLocale *currentLocale = nil;
|
|
|
|
static NSLocale *systemLocale = nil;
|
|
|
|
static NSMutableDictionary *allLocales = nil;
|
2010-12-31 17:46:46 +00:00
|
|
|
static NSDictionary *canonicalLocales = nil;
|
2010-12-16 02:15:27 +00:00
|
|
|
static NSRecursiveLock *classLock = nil;
|
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
+ (void) initialize
|
|
|
|
{
|
|
|
|
if (self == [NSLocale class])
|
|
|
|
{
|
|
|
|
classLock = [GSLazyRecursiveLock new];
|
2010-12-14 23:42:22 +00:00
|
|
|
allLocales = [[NSMutableDictionary alloc] initWithCapacity: 0];
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-29 15:33:27 +00:00
|
|
|
+ (void) defaultsDidChange: (NSNotification*)n
|
|
|
|
{
|
|
|
|
NSUserDefaults *defs;
|
|
|
|
NSString *name;
|
|
|
|
|
|
|
|
defs = [NSUserDefaults standardUserDefaults];
|
|
|
|
name = [defs stringForKey: @"Locale"];
|
2011-01-29 18:49:21 +00:00
|
|
|
if ([name isEqual: autoupdatingLocale->_localeId] == NO)
|
2011-01-29 15:33:27 +00:00
|
|
|
{
|
|
|
|
[classLock lock];
|
|
|
|
RELEASE(autoupdatingLocale->_localeId);
|
|
|
|
RELEASE(autoupdatingLocale->_components);
|
|
|
|
|
|
|
|
autoupdatingLocale->_localeId = RETAIN(name);
|
|
|
|
autoupdatingLocale->_components = nil;
|
|
|
|
|
|
|
|
RELEASE(currentLocale);
|
|
|
|
currentLocale = nil;
|
|
|
|
[classLock unlock];
|
|
|
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
postNotificationName: NSCurrentLocaleDidChangeNotification
|
|
|
|
object: nil];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
+ (id) autoupdatingCurrentLocale
|
|
|
|
{
|
|
|
|
NSLocale *result;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
[classLock lock];
|
|
|
|
if (nil == autoupdatingLocale)
|
|
|
|
{
|
2011-01-29 15:33:27 +00:00
|
|
|
autoupdatingLocale = [[self currentLocale] copy];
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
addObserver: self
|
|
|
|
selector: @selector(defaultsDidChange:)
|
|
|
|
name: NSUserDefaultsDidChangeNotification
|
|
|
|
object: nil];
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
result = RETAIN(autoupdatingLocale);
|
|
|
|
[classLock unlock];
|
|
|
|
return AUTORELEASE(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) availableLocaleIdentifiers
|
|
|
|
{
|
2010-06-25 16:42:09 +00:00
|
|
|
static NSArray *available = nil;
|
|
|
|
|
2010-07-19 07:54:52 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2010-06-25 16:42:09 +00:00
|
|
|
if (nil == available)
|
2010-06-25 07:18:20 +00:00
|
|
|
{
|
2010-06-25 16:42:09 +00:00
|
|
|
[classLock lock];
|
|
|
|
if (nil == available)
|
2010-12-13 03:37:35 +00:00
|
|
|
{
|
|
|
|
NSMutableArray *array;
|
|
|
|
int32_t i;
|
|
|
|
int32_t count = uloc_countAvailable ();
|
2010-06-25 16:42:09 +00:00
|
|
|
|
2010-12-13 03:37:35 +00:00
|
|
|
array = [[NSMutableArray alloc] initWithCapacity: count];
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-12-13 03:37:35 +00:00
|
|
|
for (i = 0; i < count; ++i)
|
|
|
|
{
|
|
|
|
const char *localeID = uloc_getAvailable (i);
|
2010-06-25 16:42:09 +00:00
|
|
|
|
2010-12-13 03:37:35 +00:00
|
|
|
[array addObject: [NSString stringWithUTF8String: localeID]];
|
|
|
|
}
|
|
|
|
available = [[NSArray alloc] initWithArray: array];
|
|
|
|
[array release];
|
|
|
|
}
|
2010-06-25 16:42:09 +00:00
|
|
|
[classLock unlock];
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
2010-06-25 16:42:09 +00:00
|
|
|
#endif
|
|
|
|
return [[available copy] autorelease];
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSString *) canonicalLanguageIdentifierFromString: (NSString *) string
|
|
|
|
{
|
2010-12-31 17:46:46 +00:00
|
|
|
NSString *result;
|
|
|
|
NSString *localeId;
|
|
|
|
NSArray *localeComps;
|
|
|
|
|
|
|
|
/* Can't use the ICU functions here because, according to Apple locale docs,
|
|
|
|
the language has a format like "zh-Hant". ICU, however, uses an
|
|
|
|
underscore to separate Scripts "zh_Hant". */
|
2011-01-09 15:54:49 +00:00
|
|
|
if (canonicalLocales == nil)
|
|
|
|
[self _updateCanonicalLocales];
|
|
|
|
|
|
|
|
localeId = [canonicalLocales objectForKey: string];
|
2011-02-07 17:21:00 +00:00
|
|
|
if (nil == localeId)
|
|
|
|
{
|
|
|
|
result = string;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
localeComps = [localeId componentsSeparatedByString: @"_"];
|
|
|
|
result = [localeComps objectAtIndex: 0];
|
|
|
|
}
|
2010-12-31 17:46:46 +00:00
|
|
|
return result;
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSString *) canonicalLocaleIdentifierFromString: (NSString *) string
|
|
|
|
{
|
2010-12-31 17:46:46 +00:00
|
|
|
/* The way this works, according to Apple docs, is a mess. It seems
|
|
|
|
that both BCP 47's "-" and ICU's "_" separators are used. According to
|
|
|
|
"Language and Locale Designations" (Apple docs) Taiwan, for example, has
|
|
|
|
zh-Hant_TW as it's locale identifier (was zh_TW on 10.3.9 and below).
|
|
|
|
Since ICU doesn't use "-" as a separator it will modify that identifier
|
|
|
|
to zh_Hant_TW. */
|
|
|
|
NSString *result;
|
2011-01-09 15:54:49 +00:00
|
|
|
NSMutableString *mStr;
|
|
|
|
NSRange range;
|
2010-12-31 17:46:46 +00:00
|
|
|
|
2011-01-29 15:33:27 +00:00
|
|
|
if (string == nil)
|
|
|
|
return nil;
|
|
|
|
|
2010-12-31 17:46:46 +00:00
|
|
|
if (canonicalLocales == nil)
|
2011-01-09 15:54:49 +00:00
|
|
|
[self _updateCanonicalLocales];
|
2010-12-31 17:46:46 +00:00
|
|
|
|
|
|
|
result = [canonicalLocales objectForKey: string];
|
|
|
|
if (result == nil)
|
|
|
|
result = string;
|
|
|
|
|
2011-01-09 15:54:49 +00:00
|
|
|
// Strip script info from locale
|
|
|
|
range = [result rangeOfString: @"-"];
|
|
|
|
if (range.location != NSNotFound)
|
|
|
|
{
|
|
|
|
NSUInteger start = range.location;
|
|
|
|
NSUInteger length;
|
|
|
|
range = [result rangeOfString: @"_"];
|
|
|
|
length = range.location - start;
|
|
|
|
|
|
|
|
mStr = [NSMutableString stringWithString: result];
|
|
|
|
[mStr deleteCharactersInRange: NSMakeRange (start, length)];
|
|
|
|
|
|
|
|
result = [NSString stringWithString: mStr];
|
|
|
|
}
|
|
|
|
|
2010-12-31 17:46:46 +00:00
|
|
|
return result;
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSLocaleLanguageDirection) characterDirectionForLanguage:
|
|
|
|
(NSString *)isoLangCode
|
|
|
|
{
|
2010-07-19 07:54:52 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2010-06-25 07:18:20 +00:00
|
|
|
ULayoutType result;
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-12-13 03:37:35 +00:00
|
|
|
result = uloc_getCharacterOrientation ([isoLangCode UTF8String], &status);
|
2010-06-25 07:18:20 +00:00
|
|
|
if (U_FAILURE(status) || ULOC_LAYOUT_UNKNOWN == result)
|
|
|
|
return NSLocaleLanguageDirectionUnknown;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2011-02-22 11:55:37 +00:00
|
|
|
return ICUToNSLocaleOrientation (result);
|
2010-06-25 16:42:09 +00:00
|
|
|
#else
|
|
|
|
return NSLocaleLanguageDirectionLeftToRight; // FIXME
|
|
|
|
#endif
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSDictionary *) componentsFromLocaleIdentifier: (NSString *) string
|
|
|
|
{
|
2010-07-19 07:54:52 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2010-12-16 02:15:27 +00:00
|
|
|
char buffer[ULOC_KEYWORD_AND_VALUES_CAPACITY];
|
2010-12-13 03:37:35 +00:00
|
|
|
const char *cLocaleId = [string UTF8String];
|
2010-06-25 07:18:20 +00:00
|
|
|
int32_t strLength;
|
2010-12-16 02:15:27 +00:00
|
|
|
UEnumeration *enumerator;
|
2010-06-25 07:18:20 +00:00
|
|
|
UErrorCode error = U_ZERO_ERROR;
|
|
|
|
NSDictionary *result;
|
|
|
|
NSMutableDictionary *tmpDict =
|
|
|
|
[[NSMutableDictionary alloc] initWithCapacity: 5];
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-12-16 02:15:27 +00:00
|
|
|
strLength = uloc_getLanguage (cLocaleId, buffer,
|
|
|
|
ULOC_KEYWORD_AND_VALUES_CAPACITY, &error);
|
2010-12-14 23:42:22 +00:00
|
|
|
if (U_SUCCESS(error) && strLength)
|
2010-06-25 07:18:20 +00:00
|
|
|
{
|
2010-12-13 03:37:35 +00:00
|
|
|
[tmpDict setValue: [NSString stringWithUTF8String: buffer]
|
|
|
|
forKey: NSLocaleLanguageCode];
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
error = U_ZERO_ERROR;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-12-16 02:15:27 +00:00
|
|
|
strLength = uloc_getCountry (cLocaleId, buffer,
|
|
|
|
ULOC_KEYWORD_AND_VALUES_CAPACITY, &error);
|
2010-12-14 23:42:22 +00:00
|
|
|
if (U_SUCCESS(error) && strLength)
|
2010-06-25 07:18:20 +00:00
|
|
|
{
|
2010-12-14 23:42:22 +00:00
|
|
|
[tmpDict setValue: [NSString stringWithUTF8String: buffer]
|
2010-06-25 07:18:20 +00:00
|
|
|
forKey: NSLocaleCountryCode];
|
|
|
|
}
|
|
|
|
error = U_ZERO_ERROR;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-12-16 02:15:27 +00:00
|
|
|
strLength = uloc_getScript (cLocaleId, buffer,
|
|
|
|
ULOC_KEYWORD_AND_VALUES_CAPACITY, &error);
|
2010-12-14 23:42:22 +00:00
|
|
|
if (U_SUCCESS(error) && strLength)
|
2010-06-25 07:18:20 +00:00
|
|
|
{
|
2010-12-14 23:42:22 +00:00
|
|
|
[tmpDict setValue: [NSString stringWithUTF8String: buffer]
|
2010-06-25 07:18:20 +00:00
|
|
|
forKey: NSLocaleScriptCode];
|
|
|
|
}
|
|
|
|
error = U_ZERO_ERROR;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-12-16 02:15:27 +00:00
|
|
|
strLength = uloc_getVariant (cLocaleId, buffer,
|
|
|
|
ULOC_KEYWORD_AND_VALUES_CAPACITY, &error);
|
2010-12-14 23:42:22 +00:00
|
|
|
if (U_SUCCESS(error) && strLength)
|
2010-06-25 07:18:20 +00:00
|
|
|
{
|
2010-12-14 23:42:22 +00:00
|
|
|
[tmpDict setValue: [NSString stringWithUTF8String: buffer]
|
2010-06-25 07:18:20 +00:00
|
|
|
forKey: NSLocaleVariantCode];
|
|
|
|
}
|
|
|
|
error = U_ZERO_ERROR;
|
2010-12-16 02:15:27 +00:00
|
|
|
|
|
|
|
enumerator = uloc_openKeywords (cLocaleId, &error);
|
|
|
|
if (U_SUCCESS(error))
|
|
|
|
{
|
|
|
|
const char *keyword;
|
|
|
|
error = U_ZERO_ERROR;
|
|
|
|
|
|
|
|
keyword = uenum_next(enumerator, NULL, &error);
|
|
|
|
while (keyword && U_SUCCESS(error))
|
|
|
|
{
|
|
|
|
error = U_ZERO_ERROR;
|
|
|
|
strLength = uloc_getKeywordValue (cLocaleId, keyword, buffer,
|
|
|
|
ULOC_KEYWORD_AND_VALUES_CAPACITY, &error);
|
|
|
|
if (strLength && U_SUCCESS(error))
|
|
|
|
{
|
|
|
|
// This is OK because NSLocaleCalendarIdentifier = "calendar"
|
|
|
|
// and NSLocaleCollationIdentifier = "collation".
|
|
|
|
[tmpDict setValue: [NSString stringWithUTF8String: buffer]
|
|
|
|
forKey: [NSString stringWithUTF8String: keyword]];
|
|
|
|
|
|
|
|
error = U_ZERO_ERROR;
|
|
|
|
keyword = uenum_next (enumerator, NULL, &error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
uenum_close (enumerator);
|
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
result = [NSDictionary dictionaryWithDictionary: tmpDict];
|
|
|
|
RELEASE(tmpDict);
|
|
|
|
return result;
|
2010-06-25 16:42:09 +00:00
|
|
|
#else
|
|
|
|
return nil; // FIXME
|
|
|
|
#endif
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (id) currentLocale
|
|
|
|
{
|
|
|
|
NSLocale *result;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
[classLock lock];
|
|
|
|
if (nil == currentLocale)
|
|
|
|
{
|
2011-01-29 15:33:27 +00:00
|
|
|
NSString *localeId;
|
|
|
|
[classLock unlock];
|
|
|
|
|
|
|
|
localeId =
|
|
|
|
[[NSUserDefaults standardUserDefaults] objectForKey: @"Locale"];
|
|
|
|
|
|
|
|
[classLock lock];
|
|
|
|
if (currentLocale == nil)
|
|
|
|
currentLocale = [[NSLocale alloc] initWithLocaleIdentifier: localeId];
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
result = RETAIN(currentLocale);
|
|
|
|
[classLock unlock];
|
|
|
|
return AUTORELEASE(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) commonISOCurrencyCodes
|
|
|
|
{
|
2010-07-19 07:54:52 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2010-06-25 07:18:20 +00:00
|
|
|
return _currencyCodesWithType (UCURR_COMMON | UCURR_NON_DEPRECATED);
|
2010-06-25 16:42:09 +00:00
|
|
|
#else
|
|
|
|
return nil; // FIXME
|
|
|
|
#endif
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) ISOCurrencyCodes
|
|
|
|
{
|
2010-07-19 07:54:52 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2010-06-25 07:18:20 +00:00
|
|
|
return _currencyCodesWithType (UCURR_ALL);
|
2010-06-25 16:42:09 +00:00
|
|
|
#else
|
|
|
|
return nil; // FIXME
|
|
|
|
#endif
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) ISOCountryCodes
|
|
|
|
{
|
2010-06-25 16:42:09 +00:00
|
|
|
static NSArray *countries = nil;
|
|
|
|
|
|
|
|
if (nil == countries)
|
2010-06-25 07:18:20 +00:00
|
|
|
{
|
2011-03-12 14:22:21 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2010-06-25 16:42:09 +00:00
|
|
|
[classLock lock];
|
|
|
|
if (nil == countries)
|
2011-03-12 14:22:21 +00:00
|
|
|
{
|
|
|
|
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity: 10];
|
|
|
|
const char *const *codes = uloc_getISOCountries ();
|
|
|
|
|
|
|
|
while (codes != NULL)
|
|
|
|
{
|
|
|
|
[array addObject: [NSString stringWithUTF8String: *codes]];
|
|
|
|
++codes;
|
|
|
|
}
|
|
|
|
countries = [[NSArray alloc] initWithArray: array];
|
|
|
|
[array release];
|
|
|
|
}
|
|
|
|
[classLock unlock];
|
2010-06-25 16:42:09 +00:00
|
|
|
#endif
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
2010-06-25 16:42:09 +00:00
|
|
|
return [[countries copy] autorelease];
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) ISOLanguageCodes
|
|
|
|
{
|
2010-06-25 16:42:09 +00:00
|
|
|
static NSArray *languages = nil;
|
|
|
|
|
|
|
|
if (nil == languages)
|
2010-06-25 07:18:20 +00:00
|
|
|
{
|
2011-03-12 14:22:21 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2010-06-25 16:42:09 +00:00
|
|
|
[classLock lock];
|
|
|
|
if (nil == languages)
|
2011-03-12 14:22:21 +00:00
|
|
|
{
|
|
|
|
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity: 10];
|
|
|
|
const char *const *codes = uloc_getISOCountries ();
|
|
|
|
|
|
|
|
while (codes != NULL)
|
|
|
|
{
|
|
|
|
[array addObject: [NSString stringWithUTF8String: *codes]];
|
|
|
|
++codes;
|
|
|
|
}
|
|
|
|
languages = [[NSArray alloc] initWithArray: array];
|
|
|
|
[array release];
|
|
|
|
}
|
|
|
|
[classLock unlock];
|
2010-06-25 16:42:09 +00:00
|
|
|
#endif
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
2010-06-25 16:42:09 +00:00
|
|
|
return [[languages copy] autorelease];
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSLocaleLanguageDirection) lineDirectionForLanguage: (NSString *) isoLangCode
|
|
|
|
{
|
2010-07-19 07:54:52 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2010-06-25 07:18:20 +00:00
|
|
|
ULayoutType result;
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-12-13 03:37:35 +00:00
|
|
|
result = uloc_getLineOrientation ([isoLangCode UTF8String], &status);
|
2010-06-25 07:18:20 +00:00
|
|
|
if (U_FAILURE(status) || ULOC_LAYOUT_UNKNOWN == result)
|
|
|
|
return NSLocaleLanguageDirectionUnknown;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2011-02-22 11:55:37 +00:00
|
|
|
return ICUToNSLocaleOrientation (result);
|
2010-06-25 16:42:09 +00:00
|
|
|
#else
|
|
|
|
return NSLocaleLanguageDirectionTopToBottom; // FIXME
|
|
|
|
#endif
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) preferredLanguages
|
|
|
|
{
|
2010-12-31 17:46:46 +00:00
|
|
|
NSArray *result;
|
|
|
|
NSMutableArray *mArray;
|
|
|
|
NSUInteger cnt;
|
|
|
|
NSUInteger idx = 0;
|
2011-03-05 07:54:05 +00:00
|
|
|
NSArray *languages;
|
2010-12-31 17:46:46 +00:00
|
|
|
|
2011-03-05 07:54:05 +00:00
|
|
|
languages = [[NSUserDefaults standardUserDefaults]
|
|
|
|
stringArrayForKey: @"NSLanguages"];
|
2010-12-31 17:46:46 +00:00
|
|
|
if (languages == nil)
|
|
|
|
return [NSArray arrayWithObject: @"en"];
|
|
|
|
|
|
|
|
mArray = [NSMutableArray array];
|
|
|
|
cnt = [languages count];
|
|
|
|
while (idx < cnt)
|
|
|
|
{
|
2011-01-29 15:33:27 +00:00
|
|
|
NSString *lang = [self canonicalLanguageIdentifierFromString:
|
|
|
|
[languages objectAtIndex: idx]];
|
2011-01-26 23:59:23 +00:00
|
|
|
if (![mArray containsObject: lang])
|
2011-01-29 15:33:27 +00:00
|
|
|
[mArray addObject: lang];
|
|
|
|
|
2010-12-31 17:46:46 +00:00
|
|
|
++idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = [NSArray arrayWithArray: mArray];
|
|
|
|
return result;
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (id) systemLocale
|
|
|
|
{
|
|
|
|
NSLocale *result;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
[classLock lock];
|
|
|
|
if (nil == systemLocale)
|
|
|
|
{
|
2010-12-16 10:09:43 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2010-12-13 03:37:35 +00:00
|
|
|
systemLocale = [[NSLocale alloc] initWithLocaleIdentifier: @""];
|
|
|
|
#endif
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
result = RETAIN(systemLocale);
|
|
|
|
[classLock unlock];
|
|
|
|
return AUTORELEASE(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSString *) localeIdentifierFromComponents: (NSDictionary *) dict
|
|
|
|
{
|
2010-12-13 03:37:35 +00:00
|
|
|
NSString *result;
|
|
|
|
NSMutableString *string;
|
|
|
|
const char *language = [[dict objectForKey: NSLocaleLanguageCode] UTF8String];
|
|
|
|
const char *script = [[dict objectForKey: NSLocaleScriptCode] UTF8String];
|
|
|
|
const char *country = [[dict objectForKey: NSLocaleCountryCode] UTF8String];
|
|
|
|
const char *variant = [[dict objectForKey: NSLocaleVariantCode] UTF8String];
|
2010-12-16 02:15:27 +00:00
|
|
|
const char *calendar =
|
|
|
|
[[[dict objectForKey: NSLocaleCalendar] calendarIdentifier] UTF8String];
|
2010-12-13 03:37:35 +00:00
|
|
|
const char *collation =
|
|
|
|
[[dict objectForKey: NSLocaleCollationIdentifier] UTF8String];
|
2011-01-27 00:37:52 +00:00
|
|
|
const char *currency = [[dict objectForKey: NSLocaleCurrencyCode] UTF8String];
|
2010-12-13 03:37:35 +00:00
|
|
|
|
2010-12-16 02:15:27 +00:00
|
|
|
// A locale cannot be constructed without a language.
|
2010-12-13 03:37:35 +00:00
|
|
|
if (language == NULL)
|
|
|
|
return nil;
|
2011-02-22 11:55:37 +00:00
|
|
|
#define TEST_CODE(x) (x ? "_" : ""), (x ? x : "")
|
2010-12-13 03:37:35 +00:00
|
|
|
string = [[NSMutableString alloc] initWithFormat: @"%s%s%s%s%s%s%s",
|
2011-02-22 11:55:37 +00:00
|
|
|
language, TEST_CODE(script), TEST_CODE(country), TEST_CODE(variant)];
|
|
|
|
#undef TEST_CODE
|
2010-12-13 03:37:35 +00:00
|
|
|
|
|
|
|
// I'm not using uloc_setKeywordValue() here because the format is easy
|
2010-12-16 02:15:27 +00:00
|
|
|
// enough to reproduce and has the added advatange that we doesn't need ICU.
|
2011-01-27 00:37:52 +00:00
|
|
|
if (calendar || calendar || currency)
|
|
|
|
[string appendString: @"@"];
|
2010-06-25 07:18:20 +00:00
|
|
|
if (calendar)
|
2011-01-27 00:37:52 +00:00
|
|
|
[string appendFormat: @"calendar=%s", calendar];
|
2010-06-25 07:18:20 +00:00
|
|
|
if (collation)
|
|
|
|
{
|
2010-12-13 03:37:35 +00:00
|
|
|
if (calendar)
|
|
|
|
[string appendString: @";"];
|
|
|
|
[string appendFormat: @"collation=%s", collation];
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
2011-01-27 00:37:52 +00:00
|
|
|
if (currency)
|
|
|
|
{
|
|
|
|
if (calendar || currency)
|
|
|
|
[string appendString: @";"];
|
|
|
|
[string appendFormat: @"currency=%s", currency];
|
|
|
|
}
|
2010-12-13 03:37:35 +00:00
|
|
|
|
|
|
|
result = [NSString stringWithString: string];
|
|
|
|
RELEASE(string);
|
|
|
|
return result;
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSString *) localeIdentifierFromWindowsLocaleCode: (uint32_t) lcid
|
|
|
|
{
|
2010-07-19 07:54:52 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2010-06-25 07:18:20 +00:00
|
|
|
char buffer[ULOC_FULLNAME_CAPACITY];
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-12-14 23:42:22 +00:00
|
|
|
uloc_getLocaleForLCID (lcid, buffer, ULOC_FULLNAME_CAPACITY, &status);
|
2010-06-25 07:18:20 +00:00
|
|
|
if (U_FAILURE(status))
|
|
|
|
return nil;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-12-13 03:37:35 +00:00
|
|
|
return [NSString stringWithUTF8String: buffer];
|
2010-06-25 16:42:09 +00:00
|
|
|
#else
|
2010-12-31 17:46:46 +00:00
|
|
|
return nil; // FIXME Check
|
|
|
|
// msdn.microsoft.com/en-us/library/0h88fahh%28v=vs.85%29.aspx
|
2010-06-25 16:42:09 +00:00
|
|
|
#endif
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (uint32_t) windowsLocaleCodeFromLocaleIdentifier: (NSString *)localeIdentifier
|
|
|
|
{
|
2010-07-19 07:54:52 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2010-12-13 03:37:35 +00:00
|
|
|
return uloc_getLCID ([localeIdentifier UTF8String]);
|
2010-06-25 16:42:09 +00:00
|
|
|
#else
|
2010-12-31 17:46:46 +00:00
|
|
|
return 0; // FIXME: Check
|
|
|
|
// msdn.microsoft.com/en-us/library/0h88fahh%28v=vs.85%29.aspx
|
2010-06-25 16:42:09 +00:00
|
|
|
#endif
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) displayNameForKey: (id) key value: (id) value
|
|
|
|
{
|
2010-07-19 07:54:52 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2010-10-26 19:31:37 +00:00
|
|
|
int32_t length = 0;
|
2010-06-25 07:18:20 +00:00
|
|
|
unichar buffer[ULOC_FULLNAME_CAPACITY];
|
2011-02-11 15:09:14 +00:00
|
|
|
UErrorCode status = 0;
|
2010-10-26 19:31:37 +00:00
|
|
|
const char *keyword = NULL;
|
2010-12-15 01:41:34 +00:00
|
|
|
const char *locale = [_localeId UTF8String];
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-10-26 19:31:37 +00:00
|
|
|
if ([key isEqualToString: NSLocaleIdentifier])
|
2010-12-13 03:37:35 +00:00
|
|
|
{
|
|
|
|
length = uloc_getDisplayName([value UTF8String], locale,
|
|
|
|
(UChar *)buffer, sizeof(buffer)/sizeof(unichar),
|
|
|
|
&status);
|
|
|
|
}
|
2010-10-26 19:31:37 +00:00
|
|
|
else if ([key isEqualToString: NSLocaleLanguageCode])
|
2010-12-13 03:37:35 +00:00
|
|
|
{
|
|
|
|
length = uloc_getDisplayLanguage([value UTF8String], locale,
|
|
|
|
(UChar *)buffer, sizeof(buffer)/sizeof(unichar),
|
|
|
|
&status);
|
|
|
|
}
|
2010-10-26 19:31:37 +00:00
|
|
|
else if ([key isEqualToString: NSLocaleCountryCode])
|
2010-12-13 03:37:35 +00:00
|
|
|
{
|
|
|
|
length = uloc_getDisplayCountry([value UTF8String], locale,
|
|
|
|
(UChar *)buffer, sizeof(buffer)/sizeof(unichar),
|
|
|
|
&status);
|
|
|
|
}
|
2010-10-26 19:31:37 +00:00
|
|
|
else if ([key isEqualToString: NSLocaleScriptCode])
|
2010-12-13 03:37:35 +00:00
|
|
|
{
|
|
|
|
length = uloc_getDisplayCountry([value UTF8String], locale,
|
|
|
|
(UChar *)buffer, sizeof(buffer)/sizeof(unichar),
|
|
|
|
&status);
|
|
|
|
}
|
2010-10-26 19:31:37 +00:00
|
|
|
else if ([key isEqualToString: NSLocaleVariantCode])
|
2010-12-13 03:37:35 +00:00
|
|
|
{
|
|
|
|
length = uloc_getDisplayVariant([value UTF8String], locale,
|
|
|
|
(UChar *)buffer, sizeof(buffer)/sizeof(unichar),
|
|
|
|
&status);
|
|
|
|
}
|
2010-10-26 19:31:37 +00:00
|
|
|
else if ([key isEqualToString: NSLocaleCalendar])
|
2010-12-13 03:37:35 +00:00
|
|
|
{
|
|
|
|
keyword = ICUCalendarKeyword;
|
|
|
|
}
|
2010-10-26 19:31:37 +00:00
|
|
|
else if ([key isEqualToString: NSLocaleCollationIdentifier])
|
2010-12-13 03:37:35 +00:00
|
|
|
{
|
|
|
|
keyword = ICUCollationKeyword;
|
|
|
|
}
|
2010-10-26 19:31:37 +00:00
|
|
|
else
|
2010-12-13 03:37:35 +00:00
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
2010-10-26 19:31:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO: Implement handling of the other locale component constants.
|
|
|
|
*/
|
|
|
|
if (NULL != keyword)
|
|
|
|
{
|
|
|
|
length = uloc_getDisplayKeywordValue ([value UTF8String], keyword,
|
|
|
|
locale, (UChar *)buffer, sizeof(buffer)/sizeof(unichar),
|
|
|
|
&status);
|
|
|
|
}
|
2010-06-25 07:18:20 +00:00
|
|
|
if (U_FAILURE(status))
|
|
|
|
return nil;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
return [NSString stringWithCharacters: buffer length: (NSUInteger)length];
|
2010-06-25 16:42:09 +00:00
|
|
|
#else
|
|
|
|
return nil; // FIXME
|
|
|
|
#endif
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
2010-06-25 16:42:09 +00:00
|
|
|
- (id) initWithLocaleIdentifier: (NSString*)string
|
2010-06-25 07:18:20 +00:00
|
|
|
{
|
2010-06-25 16:42:09 +00:00
|
|
|
NSLocale *newLocale;
|
|
|
|
NSString *localeId;
|
2010-07-19 07:54:52 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2010-06-25 16:42:09 +00:00
|
|
|
int32_t length;
|
2010-06-25 07:18:20 +00:00
|
|
|
char cLocaleId[ULOC_FULLNAME_CAPACITY];
|
|
|
|
UErrorCode error = U_ZERO_ERROR;
|
2010-12-31 17:46:46 +00:00
|
|
|
|
|
|
|
localeId = [NSLocale canonicalLocaleIdentifierFromString: string];
|
|
|
|
// Normalize locale ID
|
|
|
|
length = uloc_canonicalize ([localeId UTF8String], cLocaleId,
|
2010-06-25 07:18:20 +00:00
|
|
|
ULOC_FULLNAME_CAPACITY, &error);
|
|
|
|
if (U_FAILURE(error))
|
2010-06-25 16:42:09 +00:00
|
|
|
{
|
|
|
|
[self release];
|
|
|
|
return nil;
|
|
|
|
}
|
2010-12-31 17:46:46 +00:00
|
|
|
|
2010-12-13 03:37:35 +00:00
|
|
|
localeId = [NSString stringWithUTF8String: cLocaleId];
|
2010-06-25 16:42:09 +00:00
|
|
|
#else
|
2011-01-01 22:20:16 +00:00
|
|
|
localeId = [NSLocale canonicalLocaleIdentifierFromString: string];
|
2010-06-25 16:42:09 +00:00
|
|
|
#endif
|
2011-02-07 17:21:00 +00:00
|
|
|
if (nil == localeId)
|
|
|
|
{
|
|
|
|
[self release];
|
|
|
|
return nil;
|
|
|
|
}
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-06-25 16:42:09 +00:00
|
|
|
[classLock lock];
|
|
|
|
newLocale = [allLocales objectForKey: localeId];
|
|
|
|
if (nil == newLocale)
|
|
|
|
{
|
|
|
|
_localeId = [localeId copy];
|
2011-02-07 17:21:00 +00:00
|
|
|
_components = [[NSMutableDictionary alloc] initWithCapacity: 0];
|
2010-06-25 16:42:09 +00:00
|
|
|
[allLocales setObject: self forKey: localeId];
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-06-25 16:42:09 +00:00
|
|
|
[self release];
|
|
|
|
self = [newLocale retain];
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
2010-07-19 07:54:52 +00:00
|
|
|
[classLock unlock];
|
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) localeIdentifier
|
|
|
|
{
|
|
|
|
return _localeId;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id) objectForKey: (id) key
|
|
|
|
{
|
2010-12-13 03:37:35 +00:00
|
|
|
id result = nil;
|
2010-12-16 10:09:43 +00:00
|
|
|
#if GS_USE_ICU == 1
|
2011-01-09 15:54:49 +00:00
|
|
|
if (key == NSLocaleIdentifier || key == NSLocaleCollatorIdentifier)
|
2010-06-25 07:18:20 +00:00
|
|
|
return _localeId;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
if ((result = [_components objectForKey: key]))
|
|
|
|
return result;
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-06-25 16:42:09 +00:00
|
|
|
if ([_components count] == 0)
|
|
|
|
{
|
|
|
|
[_components addEntriesFromDictionary:
|
2010-12-15 01:41:34 +00:00
|
|
|
[NSLocale componentsFromLocaleIdentifier: _localeId]];
|
2010-06-25 16:42:09 +00:00
|
|
|
if ((result = [_components objectForKey: key]))
|
2010-12-13 03:37:35 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ([key isEqualToString: NSLocaleUsesMetricSystem])
|
|
|
|
{
|
2011-01-26 23:59:23 +00:00
|
|
|
NSString *mSys = [_components objectForKey: key];
|
|
|
|
mSys = (mSys == nil) ? [self _getMeasurementSystem] : mSys;
|
2010-12-13 03:37:35 +00:00
|
|
|
if (mSys != nil)
|
|
|
|
{
|
|
|
|
[_components setValue: mSys forKey: NSLocaleMeasurementSystem];
|
|
|
|
if ([mSys isEqualToString: @"Metric"])
|
|
|
|
result = [NSNumber numberWithBool: YES];
|
|
|
|
else
|
|
|
|
result = [NSNumber numberWithBool: NO];
|
|
|
|
}
|
2010-06-25 16:42:09 +00:00
|
|
|
}
|
2010-12-13 03:37:35 +00:00
|
|
|
else if ([key isEqualToString: NSLocaleMeasurementSystem])
|
|
|
|
result = [self _getMeasurementSystem];
|
|
|
|
else if ([key isEqualToString: NSLocaleExemplarCharacterSet])
|
|
|
|
result = [self _getExemplarCharacterSet];
|
2010-12-16 02:15:27 +00:00
|
|
|
#if OS_API_VERSION(MAC_OS_X_VERSION_10_6, GS_API_LATEST)
|
2010-12-13 03:37:35 +00:00
|
|
|
else if ([key isEqualToString: NSLocaleQuotationBeginDelimiterKey])
|
|
|
|
result = [self _getDelimiterWithType: ULOCDATA_QUOTATION_START];
|
2011-01-01 21:41:59 +00:00
|
|
|
else if ([key isEqualToString: NSLocaleQuotationEndDelimiterKey])
|
2010-12-13 03:37:35 +00:00
|
|
|
result = [self _getDelimiterWithType: ULOCDATA_QUOTATION_END];
|
|
|
|
else if ([key isEqualToString: NSLocaleAlternateQuotationBeginDelimiterKey])
|
|
|
|
result = [self _getDelimiterWithType: ULOCDATA_ALT_QUOTATION_START];
|
|
|
|
else if ([key isEqualToString: NSLocaleAlternateQuotationEndDelimiterKey])
|
|
|
|
result = [self _getDelimiterWithType: ULOCDATA_ALT_QUOTATION_END];
|
2010-12-16 02:15:27 +00:00
|
|
|
#endif
|
2010-12-13 03:37:35 +00:00
|
|
|
else if ([key isEqualToString: NSLocaleCalendar])
|
|
|
|
result = [self _getCalendar];
|
|
|
|
else if ([key isEqualToString: NSLocaleDecimalSeparator])
|
|
|
|
result = [self _getDecimalSeparator];
|
|
|
|
else if ([key isEqualToString: NSLocaleGroupingSeparator])
|
|
|
|
result = [self _getGroupingSeparator];
|
|
|
|
else if ([key isEqualToString: NSLocaleCurrencySymbol])
|
|
|
|
result = [self _getCurrencySymbol];
|
|
|
|
else if ([key isEqualToString: NSLocaleCurrencyCode])
|
|
|
|
result = [self _getCurrencyCode];
|
|
|
|
|
|
|
|
[_components setValue: result forKey: key];
|
|
|
|
#endif
|
|
|
|
return result;
|
|
|
|
}
|
2010-07-19 07:54:52 +00:00
|
|
|
|
2010-12-13 03:37:35 +00:00
|
|
|
- (NSString *) description
|
|
|
|
{
|
|
|
|
return _localeId;
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
2011-01-02 03:47:29 +00:00
|
|
|
- (BOOL) isEqual: (id) obj
|
|
|
|
{
|
|
|
|
if ([obj isKindOfClass: [self class]])
|
|
|
|
return [_localeId isEqual: [obj localeIdentifier]];
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2010-06-25 07:18:20 +00:00
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
RELEASE(_localeId);
|
|
|
|
RELEASE(_components);
|
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
2010-06-25 17:57:03 +00:00
|
|
|
- (void) encodeWithCoder: (NSCoder*)encoder
|
2010-06-25 07:18:20 +00:00
|
|
|
{
|
2010-06-25 17:57:03 +00:00
|
|
|
[encoder encodeObject: _localeId];
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
2010-06-25 17:57:03 +00:00
|
|
|
- (id) initWithCoder: (NSCoder*)decoder
|
2010-06-25 07:18:20 +00:00
|
|
|
{
|
2010-06-25 17:57:03 +00:00
|
|
|
NSString *s = [decoder decodeObject];
|
|
|
|
|
|
|
|
return [self initWithLocaleIdentifier: s];
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) copyWithZone: (NSZone *) zone
|
|
|
|
{
|
2011-01-02 03:47:29 +00:00
|
|
|
NSLocale *result;
|
|
|
|
|
2011-01-01 22:20:16 +00:00
|
|
|
if (NSShouldRetainWithZone(self, zone))
|
2011-01-02 03:47:29 +00:00
|
|
|
result = RETAIN(self);
|
2011-01-01 22:20:16 +00:00
|
|
|
else
|
2011-01-02 03:47:29 +00:00
|
|
|
{
|
|
|
|
result = (NSLocale *)NSCopyObject(self, 0, zone);
|
|
|
|
result->_localeId = [_localeId copyWithZone: zone];
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2010-06-25 07:18:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2011-01-09 15:54:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
@implementation NSLocale (PrimateMethods)
|
|
|
|
+ (void) _updateCanonicalLocales
|
|
|
|
{
|
|
|
|
NSBundle *gbundle = [NSBundle bundleForLibrary: @"gnustep-base"];
|
|
|
|
NSString *file = [gbundle pathForResource: @"Locale"
|
|
|
|
ofType: @"canonical"
|
|
|
|
inDirectory: @"Languages"];
|
|
|
|
if (file != nil)
|
|
|
|
canonicalLocales = [[NSDictionary alloc] initWithContentsOfFile: file];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) _getMeasurementSystem
|
|
|
|
{
|
|
|
|
#if GS_USE_ICU == 1
|
|
|
|
const char *cLocaleId;
|
|
|
|
ULocaleData *localeData;
|
|
|
|
UMeasurementSystem msystem;
|
|
|
|
UErrorCode err = U_ZERO_ERROR;
|
|
|
|
NSString *result = nil;
|
|
|
|
|
|
|
|
cLocaleId = [_localeId UTF8String];
|
|
|
|
localeData = ulocdata_open (cLocaleId, &err);
|
|
|
|
if (U_FAILURE(err))
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
msystem = ulocdata_getMeasurementSystem (cLocaleId, &err);
|
|
|
|
if (U_SUCCESS(err))
|
|
|
|
{
|
|
|
|
if (msystem == UMS_SI)
|
|
|
|
result = @"Metric";
|
|
|
|
else
|
|
|
|
result = @"U.S.";
|
|
|
|
}
|
2011-01-27 00:37:52 +00:00
|
|
|
ulocdata_close (localeData);
|
2011-01-09 15:54:49 +00:00
|
|
|
return result;
|
|
|
|
#else
|
|
|
|
return nil;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSCharacterSet *) _getExemplarCharacterSet
|
|
|
|
{
|
|
|
|
#if GS_USE_ICU == 1
|
|
|
|
const char *cLocaleId;
|
|
|
|
int idx;
|
|
|
|
int count;
|
|
|
|
UChar buffer[1024];
|
|
|
|
// This is an arbitrary size, increase it if it's not enough.
|
|
|
|
ULocaleData *localeData;
|
|
|
|
USet *charSet;
|
|
|
|
UErrorCode err = U_ZERO_ERROR;
|
|
|
|
NSCharacterSet *result;
|
|
|
|
NSMutableCharacterSet *mSet;
|
|
|
|
|
|
|
|
mSet = [[NSMutableCharacterSet alloc] init];
|
|
|
|
if (mSet == nil)
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
cLocaleId = [_localeId UTF8String];
|
|
|
|
localeData = ulocdata_open (cLocaleId, &err);
|
|
|
|
if (U_FAILURE(err))
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
charSet = ulocdata_getExemplarSet (localeData, NULL,
|
|
|
|
USET_ADD_CASE_MAPPINGS, ULOCDATA_ES_STANDARD, &err);
|
|
|
|
if (U_FAILURE(err))
|
|
|
|
return nil;
|
|
|
|
ulocdata_close(localeData);
|
|
|
|
|
|
|
|
count = uset_getItemCount(charSet);
|
|
|
|
for (idx = 0 ; idx < count ; ++idx)
|
|
|
|
{
|
|
|
|
UChar32 start, end;
|
|
|
|
int strLen;
|
|
|
|
|
|
|
|
err = U_ZERO_ERROR;
|
|
|
|
strLen = uset_getItem (charSet, idx, &start, &end, buffer, 1024, &err);
|
|
|
|
if (U_FAILURE(err))
|
|
|
|
{
|
|
|
|
RELEASE(mSet);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
if (strLen == 0)
|
|
|
|
{
|
|
|
|
[mSet addCharactersInRange: NSMakeRange(start, end)];
|
|
|
|
}
|
|
|
|
else if (strLen >= 2)
|
|
|
|
{
|
|
|
|
NSString *str = [NSString stringWithCharacters: buffer
|
|
|
|
length: strLen];
|
|
|
|
[mSet addCharactersInString: str];
|
|
|
|
}
|
|
|
|
// FIXME: The icu docs are a bit iffy and don't explain what len == 1
|
|
|
|
// means. So, if it is encountered, we simply skip it.
|
|
|
|
}
|
2011-01-26 23:59:23 +00:00
|
|
|
uset_close (charSet);
|
2011-01-09 15:54:49 +00:00
|
|
|
|
|
|
|
result = [mSet copyWithZone: NULL];
|
|
|
|
RELEASE(mSet);
|
|
|
|
return AUTORELEASE(result);
|
|
|
|
#else
|
|
|
|
return nil;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) _getDelimiterWithType: (NSInteger) delimiterType
|
|
|
|
{
|
|
|
|
#if GS_USE_ICU == 1
|
|
|
|
const char *cLocaleId;
|
|
|
|
int strLen;
|
|
|
|
UErrorCode err = U_ZERO_ERROR;
|
|
|
|
ULocaleData *localeData;
|
|
|
|
UChar result[32]; // Arbritrary size
|
|
|
|
|
|
|
|
cLocaleId = [_localeId UTF8String];
|
|
|
|
localeData = ulocdata_open (cLocaleId, &err);
|
|
|
|
strLen = ulocdata_getDelimiter (localeData, delimiterType, result, 32, &err);
|
2011-01-26 23:59:23 +00:00
|
|
|
ulocdata_close (localeData);
|
2011-01-09 15:54:49 +00:00
|
|
|
if (U_SUCCESS(err))
|
|
|
|
return [NSString stringWithCharacters: (unichar *)result length: strLen];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSCalendar *) _getCalendar
|
|
|
|
{
|
|
|
|
#if GS_USE_ICU == 1
|
|
|
|
NSCalendar *result;
|
|
|
|
NSString *calId;
|
|
|
|
int strLen;
|
|
|
|
char buffer[ULOC_KEYWORDS_CAPACITY];
|
|
|
|
UErrorCode err = U_ZERO_ERROR;
|
|
|
|
|
|
|
|
strLen = uloc_getKeywordValue ([_localeId UTF8String], ICUCalendarKeyword,
|
|
|
|
buffer, ULOC_KEYWORDS_CAPACITY, &err);
|
|
|
|
if (U_SUCCESS(err) && strLen > 0)
|
|
|
|
calId = [NSString stringWithUTF8String: buffer];
|
|
|
|
else
|
|
|
|
calId = NSGregorianCalendar;
|
|
|
|
|
|
|
|
result = [[NSCalendar alloc] initWithCalendarIdentifier: calId];
|
|
|
|
|
|
|
|
return result;
|
|
|
|
#else
|
|
|
|
return nil;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) _getDecimalSeparator
|
|
|
|
{
|
2011-01-09 21:16:20 +00:00
|
|
|
NSNumberFormatter *nFor;
|
|
|
|
NSString *result;
|
|
|
|
|
|
|
|
nFor = [[NSNumberFormatter alloc] init];
|
|
|
|
[nFor setLocale: self];
|
|
|
|
[nFor setNumberStyle: NSNumberFormatterDecimalStyle];
|
|
|
|
result = [nFor decimalSeparator];
|
|
|
|
|
|
|
|
RELEASE(nFor);
|
|
|
|
return result;
|
2011-01-09 15:54:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) _getGroupingSeparator
|
|
|
|
{
|
2011-01-09 21:16:20 +00:00
|
|
|
NSNumberFormatter *nFor;
|
|
|
|
NSString *result;
|
|
|
|
|
|
|
|
nFor = [[NSNumberFormatter alloc] init];
|
|
|
|
[nFor setLocale: self];
|
|
|
|
[nFor setNumberStyle: NSNumberFormatterDecimalStyle];
|
|
|
|
result = [nFor groupingSeparator];
|
|
|
|
|
|
|
|
RELEASE(nFor);
|
|
|
|
return result;
|
2011-01-09 15:54:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) _getCurrencySymbol
|
|
|
|
{
|
2011-01-09 21:16:20 +00:00
|
|
|
NSNumberFormatter *nFor;
|
|
|
|
NSString *result;
|
|
|
|
|
|
|
|
nFor = [[NSNumberFormatter alloc] init];
|
|
|
|
[nFor setLocale: self];
|
|
|
|
[nFor setNumberStyle: NSNumberFormatterCurrencyStyle];
|
|
|
|
result = [nFor currencySymbol];
|
|
|
|
|
|
|
|
RELEASE(nFor);
|
|
|
|
return result;
|
2011-01-09 15:54:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) _getCurrencyCode
|
|
|
|
{
|
2011-01-09 21:16:20 +00:00
|
|
|
NSNumberFormatter *nFor;
|
|
|
|
NSString *result;
|
|
|
|
|
|
|
|
nFor = [[NSNumberFormatter alloc] init];
|
|
|
|
[nFor setLocale: self];
|
|
|
|
[nFor setNumberStyle: NSNumberFormatterCurrencyStyle];
|
|
|
|
result = [nFor currencyCode];
|
|
|
|
|
|
|
|
RELEASE(nFor);
|
|
|
|
return result;
|
2011-01-09 15:54:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|