Index: src/OFApplication.m ================================================================== --- src/OFApplication.m +++ src/OFApplication.m @@ -115,11 +115,11 @@ } int OFApplicationMain(int *argc, char **argv[], id delegate) { - [[OFLocale alloc] init]; + [OFLocale currentLocale]; app = [[OFApplication alloc] of_init]; #ifdef OF_WINDOWS if ([OFSystemInfo isWindowsNT]) { Index: src/OFLocale.h ================================================================== --- src/OFLocale.h +++ src/OFLocale.h @@ -93,13 +93,12 @@ @property (readonly, nonatomic) OFString *decimalSeparator; /** * @brief Returns the current OFLocale. * - * @warning If you don't use @ref OFApplication, this might be `nil`! In this - * case, you need to manually allocate an instance and call - * @ref init once. + * @note If you don't use @ref OFApplication, you need to call this as early as + * possible to initialize the locale! * * @return The current OFLocale instance */ + (nullable OFLocale *)currentLocale; @@ -145,21 +144,12 @@ * * @param IRI The IRI to the directory to scan for localizations */ + (void)addLocalizationDirectoryIRI: (OFIRI *)IRI; -/** - * @brief Initializes the current OFLocale. - * - * @warning This sets the locale via `setlocale()`! - * - * @warning You should never call this yourself, except if you do not use - * @ref OFApplication. In this case, you need to allocate exactly one - * instance of OFLocale, which will become the current locale, and - * call this method. - */ -- (instancetype)init; +- (instancetype)init OF_DEPRECATED(ObjFW, 1, 1, "Manually creating an OFLocale " + "is no longer necessary. Use +[OFLocale currentLocale] instead."); /** * @brief Adds a directory to scan for localizations. * * @param IRI The IRI to the directory to scan for localizations Index: src/OFLocale.m ================================================================== --- src/OFLocale.m +++ src/OFLocale.m @@ -21,10 +21,12 @@ #import "OFArray.h" #import "OFDictionary.h" #import "OFIRI.h" #import "OFNumber.h" #import "OFString.h" + +#import "OFOnce.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOpenItemFailedException.h" @@ -35,12 +37,23 @@ # include # include # undef Class #endif +@interface OFLocale () +- (instancetype)of_init OF_METHOD_FAMILY(init); +@end + +static OFOnceControl initLocaleControl = OFOnceControlInitValue; static OFLocale *currentLocale = nil; static OFDictionary *operatorPrecedences = nil; + +static void +initLocale(void) +{ + currentLocale = [[OFLocale alloc] of_init]; +} #ifndef OF_AMIGAOS static void parseLocale(char *locale, OFStringEncoding *encoding, OFString **languageCode, OFString **countryCode) @@ -310,14 +323,17 @@ @synthesize languageCode = _languageCode, countryCode = _countryCode; @synthesize encoding = _encoding, decimalSeparator = _decimalSeparator; + (void)initialize { + void *pool; OFNumber *one, *two, *three, *four; if (self != [OFLocale class]) return; + + pool = objc_autoreleasePoolPush(); /* 1 is also used to denote a unary operator. */ one = [OFNumber numberWithUnsignedInt: 1]; two = [OFNumber numberWithUnsignedInt: 2]; three = [OFNumber numberWithUnsignedInt: 3]; @@ -335,34 +351,46 @@ @"&&", three, @"||", four, @"!", one, @"is_real", one, nil]; + + objc_autoreleasePoolPop(pool); } + (OFLocale *)currentLocale { + OFOnce(&initLocaleControl, initLocale); + return currentLocale; } + (OFString *)languageCode { + OFOnce(&initLocaleControl, initLocale); + return currentLocale.languageCode; } + (OFString *)countryCode { + OFOnce(&initLocaleControl, initLocale); + return currentLocale.countryCode; } + (OFStringEncoding)encoding { + OFOnce(&initLocaleControl, initLocale); + return currentLocale.encoding; } + (OFString *)decimalSeparator { + OFOnce(&initLocaleControl, initLocale); + return currentLocale.decimalSeparator; } + (void)addLocalizationDirectoryIRI: (OFIRI *)IRI { @@ -369,20 +397,30 @@ [currentLocale addLocalizationDirectoryIRI: IRI]; } - (instancetype)init { + /* + * In the past, applications not using OFApplication were required to + * create an instance of OFLocale manually. This is no longer needed + * and +[currentLocale] creates the singleton. However, in order to not + * break old applications, this method needs to just return the + * singleton now. + */ + [self release]; + + return [OFLocale currentLocale]; +} + +- (instancetype)of_init +{ self = [super init]; @try { #ifndef OF_AMIGAOS char *locale, *messagesLocale = NULL; - if (currentLocale != nil) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; - # ifdef OF_MSDOS _encoding = OFStringEncodingCodepage437; # else _encoding = OFStringEncodingUTF8; # endif @@ -482,24 +520,14 @@ } @catch (id e) { [self release]; @throw e; } - currentLocale = self; - return self; } -- (void)dealloc -{ - [_languageCode release]; - [_countryCode release]; - [_decimalSeparator release]; - [_localizedStrings release]; - - [super dealloc]; -} +OF_SINGLETON_METHODS - (void)addLocalizationDirectoryIRI: (OFIRI *)IRI { void *pool; OFIRI *mapIRI, *localizationIRI;