2001-12-17 14:31:42 +00:00
|
|
|
/** GSLocale - various functions for localization
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
Copyright (C) 2000 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
Written by: Adam Fedor <fedor@gnu.org>
|
|
|
|
Created: Oct 2000
|
|
|
|
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-09-14 11:36:11 +00:00
|
|
|
modify it under the terms of the GNU Lesser General Public
|
2000-10-27 15:54:35 +00:00
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-08 10:38:33 +00:00
|
|
|
version 2 of the License, or (at your option) any later version.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
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
|
2019-12-09 23:36:00 +00:00
|
|
|
Lesser General Public License for more details.
|
2000-10-27 15:54:35 +00:00
|
|
|
|
2007-09-14 11:36:11 +00:00
|
|
|
You should have received a copy of the GNU Lesser General Public
|
2000-10-27 15:54:35 +00:00
|
|
|
License along with this library; if not, write to the Free
|
2006-10-09 14:00:01 +00:00
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
2019-12-09 23:36:00 +00:00
|
|
|
Boston, MA 02110 USA.
|
2000-10-27 15:54:35 +00:00
|
|
|
*/
|
2010-02-19 08:12:46 +00:00
|
|
|
#import "common.h"
|
2024-05-30 09:40:52 +00:00
|
|
|
#import "GSPrivate.h"
|
2007-11-29 20:53:26 +00:00
|
|
|
#import "GNUstepBase/GSLocale.h"
|
|
|
|
#import "Foundation/NSDictionary.h"
|
|
|
|
#import "Foundation/NSArray.h"
|
|
|
|
#import "Foundation/NSLock.h"
|
2000-10-27 15:54:35 +00:00
|
|
|
|
2012-02-28 06:20:53 +00:00
|
|
|
static NSString *
|
|
|
|
privateSetLocale(int category, NSString *locale);
|
|
|
|
|
|
|
|
const char*
|
|
|
|
GSSetLocaleC(int category, const char *loc)
|
|
|
|
{
|
|
|
|
NSWarnLog(@"GSSetLocaleC is deprecated and has no effect");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSString *
|
|
|
|
GSSetLocale(int category, NSString *locale)
|
|
|
|
{
|
|
|
|
NSWarnLog(@"GSSetLocale is deprecated and has no effect");
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2013-05-16 08:44:53 +00:00
|
|
|
#if defined(HAVE_LOCALE_H) && defined(HAVE_CURRENCY_SYMBOL_IN_LCONV)
|
|
|
|
/* There is little point in using locale.h if no useful information
|
|
|
|
is exposed through struct lconv. An example platform is Android. */
|
2000-10-27 15:54:35 +00:00
|
|
|
|
|
|
|
#include <locale.h>
|
2000-11-14 18:30:31 +00:00
|
|
|
#ifdef HAVE_LANGINFO_H
|
2000-10-27 15:54:35 +00:00
|
|
|
#include <langinfo.h>
|
2000-11-14 18:30:31 +00:00
|
|
|
#endif
|
2007-11-29 20:53:26 +00:00
|
|
|
#import "Foundation/NSUserDefaults.h"
|
2000-10-27 15:54:35 +00:00
|
|
|
|
2007-11-29 20:53:26 +00:00
|
|
|
#import "GSPrivate.h"
|
2007-04-01 11:12:12 +00:00
|
|
|
|
2009-09-30 20:44:41 +00:00
|
|
|
#define ToString(value) [NSString stringWithCString: (value) \
|
|
|
|
encoding: GSPrivateNativeCStringEncoding()]
|
|
|
|
|
2012-02-28 06:20:53 +00:00
|
|
|
static NSString *
|
|
|
|
privateSetLocale(int category, NSString *locale)
|
2000-10-27 15:54:35 +00:00
|
|
|
{
|
2012-02-28 06:20:53 +00:00
|
|
|
const char *clocale = NULL;
|
2017-11-04 22:53:12 +00:00
|
|
|
/* Need to get the encoding first as the function call invalidates
|
|
|
|
* the return value of setlocale()
|
|
|
|
*/
|
|
|
|
NSStringEncoding enc = GSPrivateNativeCStringEncoding();
|
2001-02-19 05:03:09 +00:00
|
|
|
if (locale != nil)
|
|
|
|
{
|
|
|
|
clocale = [locale cString];
|
|
|
|
}
|
2012-02-28 06:20:53 +00:00
|
|
|
clocale = setlocale(category, clocale);
|
2000-10-27 15:54:35 +00:00
|
|
|
|
2012-02-28 06:20:53 +00:00
|
|
|
if (clocale != NULL)
|
2001-02-19 05:03:09 +00:00
|
|
|
{
|
2017-11-04 22:53:12 +00:00
|
|
|
return [NSString stringWithCString: clocale encoding: enc];
|
2001-02-19 05:03:09 +00:00
|
|
|
}
|
2012-02-28 06:20:53 +00:00
|
|
|
return nil;
|
2000-10-27 15:54:35 +00:00
|
|
|
}
|
|
|
|
|
2009-09-30 20:44:41 +00:00
|
|
|
#define GSLanginfo(value) ToString(nl_langinfo (value))
|
2007-03-13 12:20:45 +00:00
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
|
|
|
|
/* Creates a locale dictionary from information provided by i18n functions.
|
|
|
|
Many, but not all, of the keys are filled in or inferred from the
|
|
|
|
available information */
|
|
|
|
NSDictionary *
|
|
|
|
GSDomainFromDefaultLocale(void)
|
|
|
|
{
|
2001-04-28 05:53:56 +00:00
|
|
|
static NSDictionary *saved = nil;
|
2001-02-19 05:03:09 +00:00
|
|
|
struct lconv *lconv;
|
|
|
|
NSMutableDictionary *dict;
|
|
|
|
NSString *str1;
|
|
|
|
NSString *str2;
|
2005-02-23 16:05:09 +00:00
|
|
|
#ifdef HAVE_LANGINFO_H
|
|
|
|
int i;
|
|
|
|
NSMutableArray *arr;
|
|
|
|
#endif
|
2012-02-28 06:20:53 +00:00
|
|
|
NSString *backupLocale;
|
2000-10-27 15:54:35 +00:00
|
|
|
|
2001-04-28 05:53:56 +00:00
|
|
|
if (saved != nil)
|
|
|
|
return saved;
|
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
dict = [NSMutableDictionary dictionary];
|
2000-10-30 05:03:28 +00:00
|
|
|
|
2007-12-21 14:37:37 +00:00
|
|
|
/* Protect locale access with locks to prevent multiple threads using
|
|
|
|
* it and interfering with the buffer.
|
|
|
|
*/
|
2024-05-30 09:40:52 +00:00
|
|
|
[GSPrivateGlobalLock() lock];
|
2007-12-21 14:37:37 +00:00
|
|
|
|
2012-02-28 06:20:53 +00:00
|
|
|
/**
|
|
|
|
* Set the current locale to the system default, and backup
|
|
|
|
* what it was previously (should have been @"C").
|
|
|
|
*/
|
|
|
|
backupLocale = privateSetLocale(LC_ALL, nil);
|
|
|
|
privateSetLocale(LC_ALL, @"");
|
|
|
|
|
2004-07-18 10:48:19 +00:00
|
|
|
#ifdef HAVE_LANGINFO_H
|
2000-10-30 05:03:28 +00:00
|
|
|
/* Time/Date Information */
|
2000-10-27 15:54:35 +00:00
|
|
|
arr = [NSMutableArray arrayWithCapacity: 7];
|
|
|
|
for (i = 0; i < 7; i++)
|
2001-02-19 05:03:09 +00:00
|
|
|
{
|
|
|
|
[arr addObject: GSLanginfo(DAY_1+i)];
|
|
|
|
}
|
2000-10-27 15:54:35 +00:00
|
|
|
[dict setObject: arr forKey: NSWeekDayNameArray];
|
|
|
|
|
|
|
|
arr = [NSMutableArray arrayWithCapacity: 7];
|
|
|
|
for (i = 0; i < 7; i++)
|
2001-02-19 05:03:09 +00:00
|
|
|
{
|
|
|
|
[arr addObject: GSLanginfo(ABDAY_1+i)];
|
|
|
|
}
|
2000-10-27 15:54:35 +00:00
|
|
|
[dict setObject: arr forKey: NSShortWeekDayNameArray];
|
|
|
|
|
|
|
|
arr = [NSMutableArray arrayWithCapacity: 12];
|
|
|
|
for (i = 0; i < 12; i++)
|
2001-02-19 05:03:09 +00:00
|
|
|
{
|
|
|
|
[arr addObject: GSLanginfo(MON_1+i)];
|
|
|
|
}
|
2000-10-27 15:54:35 +00:00
|
|
|
[dict setObject: arr forKey: NSMonthNameArray];
|
|
|
|
|
|
|
|
arr = [NSMutableArray arrayWithCapacity: 12];
|
|
|
|
for (i = 0; i < 12; i++)
|
2001-02-19 05:03:09 +00:00
|
|
|
{
|
|
|
|
[arr addObject: GSLanginfo(ABMON_1+i)];
|
|
|
|
}
|
2000-10-27 15:54:35 +00:00
|
|
|
[dict setObject: arr forKey: NSShortMonthNameArray];
|
|
|
|
|
|
|
|
str1 = GSLanginfo(AM_STR);
|
|
|
|
str2 = GSLanginfo(PM_STR);
|
2001-02-19 05:03:09 +00:00
|
|
|
if (str1 != nil && str2 != nil)
|
|
|
|
{
|
|
|
|
[dict setObject: [NSArray arrayWithObjects: str1, str2, nil]
|
|
|
|
forKey: NSAMPMDesignation];
|
|
|
|
}
|
2000-10-27 15:54:35 +00:00
|
|
|
|
2001-02-19 05:03:09 +00:00
|
|
|
[dict setObject: GSLanginfo(D_T_FMT)
|
|
|
|
forKey: NSTimeDateFormatString];
|
|
|
|
[dict setObject: GSLanginfo(D_FMT)
|
|
|
|
forKey: NSShortDateFormatString];
|
|
|
|
[dict setObject: GSLanginfo(T_FMT)
|
|
|
|
forKey: NSTimeFormatString];
|
2004-07-18 10:48:19 +00:00
|
|
|
#endif /* HAVE_LANGINFO_H */
|
2000-10-27 15:54:35 +00:00
|
|
|
|
|
|
|
lconv = localeconv();
|
|
|
|
|
|
|
|
/* Currency Information */
|
|
|
|
if (lconv->currency_symbol)
|
2001-02-19 05:03:09 +00:00
|
|
|
{
|
2009-09-30 20:44:41 +00:00
|
|
|
[dict setObject: ToString(lconv->currency_symbol)
|
2001-02-19 05:03:09 +00:00
|
|
|
forKey: NSCurrencySymbol];
|
|
|
|
}
|
2000-10-27 15:54:35 +00:00
|
|
|
if (lconv->int_curr_symbol)
|
2001-02-19 05:03:09 +00:00
|
|
|
{
|
2009-09-30 20:44:41 +00:00
|
|
|
[dict setObject: ToString(lconv->int_curr_symbol)
|
2001-02-19 05:03:09 +00:00
|
|
|
forKey: NSInternationalCurrencyString];
|
|
|
|
}
|
2000-10-27 15:54:35 +00:00
|
|
|
if (lconv->mon_decimal_point)
|
2001-02-19 05:03:09 +00:00
|
|
|
{
|
2009-09-30 20:44:41 +00:00
|
|
|
[dict setObject: ToString(lconv->mon_decimal_point)
|
2001-02-19 05:03:09 +00:00
|
|
|
forKey: NSInternationalCurrencyString];
|
|
|
|
}
|
2000-10-27 15:54:35 +00:00
|
|
|
if (lconv->mon_thousands_sep)
|
2001-02-19 05:03:09 +00:00
|
|
|
{
|
2009-09-30 20:44:41 +00:00
|
|
|
[dict setObject: ToString(lconv->mon_thousands_sep)
|
2001-02-19 05:03:09 +00:00
|
|
|
forKey: NSInternationalCurrencyString];
|
|
|
|
}
|
2001-04-28 05:53:56 +00:00
|
|
|
|
|
|
|
if (lconv->decimal_point)
|
|
|
|
{
|
2009-09-30 20:44:41 +00:00
|
|
|
[dict setObject: ToString(lconv->decimal_point)
|
2001-04-28 05:53:56 +00:00
|
|
|
forKey: NSDecimalSeparator];
|
|
|
|
}
|
|
|
|
if (lconv->thousands_sep)
|
|
|
|
{
|
2009-09-30 20:44:41 +00:00
|
|
|
[dict setObject: ToString(lconv->thousands_sep)
|
2001-04-28 05:53:56 +00:00
|
|
|
forKey: NSThousandsSeparator];
|
|
|
|
}
|
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
/* FIXME: Get currency format from localeconv */
|
|
|
|
|
2003-01-09 17:15:40 +00:00
|
|
|
#ifdef LC_MESSAGES
|
2012-02-28 06:20:53 +00:00
|
|
|
str1 = privateSetLocale(LC_MESSAGES, nil);
|
2003-01-09 17:15:40 +00:00
|
|
|
#else
|
|
|
|
str1 = nil;
|
|
|
|
#endif
|
2001-04-28 05:53:56 +00:00
|
|
|
if (str1 != nil)
|
|
|
|
{
|
2008-06-06 13:57:06 +00:00
|
|
|
[dict setObject: str1 forKey: GSLocale];
|
2001-04-28 05:53:56 +00:00
|
|
|
}
|
2000-10-27 15:54:35 +00:00
|
|
|
str2 = GSLanguageFromLocale(str1);
|
2001-04-28 05:53:56 +00:00
|
|
|
if (str2 != nil)
|
2001-02-19 05:03:09 +00:00
|
|
|
{
|
|
|
|
[dict setObject: str2 forKey: NSLanguageName];
|
|
|
|
}
|
2000-10-27 15:54:35 +00:00
|
|
|
|
2002-09-10 21:53:34 +00:00
|
|
|
/*
|
|
|
|
* Another thread might have been faster in setting the static variable.
|
|
|
|
* If so, we just drop our dict.
|
|
|
|
*/
|
|
|
|
if (saved == nil)
|
|
|
|
{
|
2011-06-19 09:26:03 +00:00
|
|
|
saved = [NSObject leak: dict];
|
2002-09-10 21:53:34 +00:00
|
|
|
}
|
2012-02-28 06:20:53 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Restore the current locale to what we backed up (again, should
|
|
|
|
* be restored to @"C")
|
|
|
|
*/
|
|
|
|
privateSetLocale(LC_ALL, backupLocale);
|
|
|
|
|
2024-05-30 09:40:52 +00:00
|
|
|
[GSPrivateGlobalLock() unlock];
|
2001-04-28 05:53:56 +00:00
|
|
|
return saved;
|
2000-10-27 15:54:35 +00:00
|
|
|
}
|
|
|
|
|
2002-10-22 03:22:30 +00:00
|
|
|
#else /* HAVE_LOCALE_H */
|
2012-02-28 06:20:53 +00:00
|
|
|
static NSString *
|
|
|
|
privateSetLocale(int category, NSString *locale)
|
2002-10-22 03:22:30 +00:00
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSDictionary *
|
|
|
|
GSDomainFromDefaultLocale(void)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* !HAVE_LOCALE_H */
|
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
NSString *
|
|
|
|
GSLanguageFromLocale(NSString *locale)
|
|
|
|
{
|
2001-02-19 05:03:09 +00:00
|
|
|
NSString *language = nil;
|
|
|
|
NSString *aliases = nil;
|
2003-04-28 02:29:49 +00:00
|
|
|
NSBundle *gbundle;
|
2000-10-27 15:54:35 +00:00
|
|
|
|
* Source/NSUserDefaults.m:
- Refactoring of the code to read the system language list
into a separate function, systemLanguages().
- Add support for the LANGUAGE environment variable, a GNU extension.
It holds a colon-separated list of locales, and is intended to let
the user specify a list of their preferred languages in order.
For example, the language settings GUI in Ubuntu modifies the
LANGUAGE variable.
More info here:
http://www.gnu.org/software/gettext/manual/gettext.html#The-LANGUAGE-variable
- When populating NSLanguages, "expand" locales into a list of
related variants, formed by stripping off region suffixes. This
ensures that if a user's environment is set to a regional version
of a language (say CanadaFrench) but an application is only
traslated into French, the plain French translation will still be used.
e.g. if the system locales are {fr_CA, en_CA}, expand the list to
{fr_CA, fr, en_CA, en}.
* Headers/GNUstepBase/GSLocale.h:
* Source/GSLocale.m:
New functions GSLocaleVariants and GSLanguagesFromLocale
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@33910 72102866-910b-0410-8b05-ffd578937521
2011-09-29 19:00:46 +00:00
|
|
|
if (locale == nil || [locale isEqual: @"C"] || [locale isEqual: @"POSIX"]
|
|
|
|
|| [locale length] < 2)
|
2000-10-27 15:54:35 +00:00
|
|
|
return @"English";
|
|
|
|
|
2003-04-28 02:29:49 +00:00
|
|
|
gbundle = [NSBundle bundleForLibrary: @"gnustep-base"];
|
|
|
|
aliases = [gbundle pathForResource: @"Locale"
|
|
|
|
ofType: @"aliases"
|
2005-02-22 11:22:44 +00:00
|
|
|
inDirectory: @"Languages"];
|
2001-02-19 05:03:09 +00:00
|
|
|
if (aliases != nil)
|
2000-10-27 15:54:35 +00:00
|
|
|
{
|
2001-02-19 05:03:09 +00:00
|
|
|
NSDictionary *dict;
|
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
dict = [NSDictionary dictionaryWithContentsOfFile: aliases];
|
|
|
|
language = [dict objectForKey: locale];
|
2001-02-19 05:03:09 +00:00
|
|
|
if (language == nil && [locale pathExtension] != nil)
|
2000-10-27 15:54:35 +00:00
|
|
|
{
|
|
|
|
locale = [locale stringByDeletingPathExtension];
|
2011-07-11 11:55:35 +00:00
|
|
|
if ([locale isEqual: @"C"] || [locale isEqual: @"POSIX"])
|
|
|
|
return @"English";
|
2000-10-27 15:54:35 +00:00
|
|
|
language = [dict objectForKey: locale];
|
|
|
|
}
|
|
|
|
if (language == nil)
|
|
|
|
{
|
2011-08-16 16:04:43 +00:00
|
|
|
locale = [locale substringWithRange: NSMakeRange(0, 2)];
|
2000-10-27 15:54:35 +00:00
|
|
|
language = [dict objectForKey: locale];
|
|
|
|
}
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
return language;
|
|
|
|
}
|
* Source/NSUserDefaults.m:
- Refactoring of the code to read the system language list
into a separate function, systemLanguages().
- Add support for the LANGUAGE environment variable, a GNU extension.
It holds a colon-separated list of locales, and is intended to let
the user specify a list of their preferred languages in order.
For example, the language settings GUI in Ubuntu modifies the
LANGUAGE variable.
More info here:
http://www.gnu.org/software/gettext/manual/gettext.html#The-LANGUAGE-variable
- When populating NSLanguages, "expand" locales into a list of
related variants, formed by stripping off region suffixes. This
ensures that if a user's environment is set to a regional version
of a language (say CanadaFrench) but an application is only
traslated into French, the plain French translation will still be used.
e.g. if the system locales are {fr_CA, en_CA}, expand the list to
{fr_CA, fr, en_CA, en}.
* Headers/GNUstepBase/GSLocale.h:
* Source/GSLocale.m:
New functions GSLocaleVariants and GSLanguagesFromLocale
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@33910 72102866-910b-0410-8b05-ffd578937521
2011-09-29 19:00:46 +00:00
|
|
|
|
|
|
|
NSArray *
|
|
|
|
GSLocaleVariants(NSString *locale)
|
|
|
|
{
|
|
|
|
NSRange under = [locale rangeOfString: @"_"];
|
|
|
|
if (under.location != NSNotFound)
|
|
|
|
{
|
|
|
|
return [NSArray arrayWithObjects:
|
|
|
|
locale,
|
|
|
|
[locale substringToIndex: under.location],
|
|
|
|
nil];
|
|
|
|
}
|
|
|
|
return [NSArray arrayWithObject: locale];
|
|
|
|
}
|
|
|
|
|
|
|
|
NSArray *
|
|
|
|
GSLanguagesFromLocale(NSString *locale)
|
|
|
|
{
|
|
|
|
NSArray *variants = GSLocaleVariants(locale);
|
|
|
|
NSMutableArray *result = [NSMutableArray arrayWithCapacity: [variants count]];
|
|
|
|
|
|
|
|
NSEnumerator *enumerator = [variants objectEnumerator];
|
|
|
|
NSString *variant;
|
|
|
|
while ((variant = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
NSString *language = GSLanguageFromLocale(variant);
|
|
|
|
if (language != nil)
|
|
|
|
{
|
|
|
|
[result addObject: language];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2012-02-28 06:20:53 +00:00
|
|
|
|
|
|
|
NSString *GSDefaultLanguageLocale()
|
|
|
|
{
|
2016-06-27 18:04:30 +00:00
|
|
|
NSString *locale = nil;
|
2012-02-28 06:20:53 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_LOCALE_H
|
2012-03-02 21:38:41 +00:00
|
|
|
#ifdef LC_MESSAGES
|
2016-06-27 18:04:30 +00:00
|
|
|
NSString *backup;
|
|
|
|
|
2024-05-30 09:40:52 +00:00
|
|
|
[GSPrivateGlobalLock() lock];
|
2012-02-28 06:20:53 +00:00
|
|
|
|
|
|
|
backup = privateSetLocale(LC_ALL, nil);
|
|
|
|
privateSetLocale(LC_ALL, @"");
|
|
|
|
locale = privateSetLocale(LC_MESSAGES, nil);
|
|
|
|
privateSetLocale(LC_ALL, backup);
|
|
|
|
|
2024-05-30 09:40:52 +00:00
|
|
|
[GSPrivateGlobalLock() unlock];
|
2012-03-02 21:38:41 +00:00
|
|
|
#endif
|
2012-02-28 06:20:53 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return locale;
|
|
|
|
}
|