1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: localebackend.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_shell.hxx"
34 #include "localebackend.hxx"
35 #include "localelayer.hxx"
36 #include <com/sun/star/configuration/backend/ComponentChangeEvent.hpp>
37 #include <uno/current_context.hxx>
42 #if defined(LINUX) || defined(SOLARIS) || defined(IRIX) || defined(NETBSD) || defined(FREEBSD) || defined(OS2)
44 #include <rtl/ustrbuf.hxx>
49 * Note: setlocale is not at all thread safe, so is this code. It could
50 * especially interfere with the stuff VCL is doing, so make sure this
51 * is called from the main thread only.
54 static rtl::OUString
ImplGetLocale(int category
)
56 const char *locale
= setlocale(category
, "");
58 // Return "en-US" for C locales
59 if( (locale
== NULL
) || ( locale
[0] == 'C' && locale
[1] == '\0' ) )
60 return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "en-US" ) );
64 const char *uscore
= NULL
;
66 // locale string have the format lang[_ctry][.encoding][@modifier]
67 // we are only interested in the first two items, so we handle
68 // '.' and '@' as string end.
69 for (cp
= locale
; *cp
; cp
++)
73 if (*cp
== '.' || *cp
== '@')
77 rtl::OUStringBuffer aLocaleBuffer
;
80 aLocaleBuffer
.appendAscii(locale
, uscore
++ - locale
);
81 aLocaleBuffer
.appendAscii("-");
82 aLocaleBuffer
.appendAscii(uscore
, cp
- uscore
);
86 aLocaleBuffer
.appendAscii(locale
, cp
- locale
);
89 return aLocaleBuffer
.makeStringAndClear();
94 #include <rtl/ustrbuf.hxx>
99 #include <CoreServices/CoreServices.h>
100 #include <CoreFoundation/CoreFoundation.h>
103 namespace /* private */
106 void OUStringBufferAppendCFString(rtl::OUStringBuffer
& buffer
, const CFStringRef s
)
108 CFIndex lstr
= CFStringGetLength(s
);
109 for (CFIndex i
= 0; i
< lstr
; i
++)
110 buffer
.append(CFStringGetCharacterAtIndex(s
, i
));
113 template <typename T
>
117 explicit CFGuard(T
& rT
) : rT_(rT
) {}
118 ~CFGuard() { if (rT_
) CFRelease(rT_
); }
123 typedef CFGuard
<CFArrayRef
> CFArrayGuard
;
124 typedef CFGuard
<CFStringRef
> CFStringGuard
;
125 typedef CFGuard
<CFTypeRef
> CFTypeRefGuard
;
127 /* For more information on the Apple locale concept please refer to
128 http://developer.apple.com/documentation/CoreFoundation/Conceptual/CFLocales/Articles/CFLocaleConcepts.html
129 According to this documentation a locale identifier has the format: language[_country][_variant]*
130 e.g. es_ES_PREEURO -> spain prior Euro support
131 Note: The calling code should be able to handle locales with only language information e.g. 'en' for certain
132 UI languages just the language code will be returned.
135 CFStringRef
ImplGetAppPreference(const char* pref
)
137 CFStringRef csPref
= CFStringCreateWithCString(NULL
, pref
, kCFStringEncodingASCII
);
138 CFStringGuard
csRefGuard(csPref
);
140 CFTypeRef ref
= CFPreferencesCopyAppValue(csPref
, kCFPreferencesCurrentApplication
);
141 CFTypeRefGuard
refGuard(ref
);
146 CFStringRef sref
= (CFGetTypeID(ref
) == CFArrayGetTypeID()) ? (CFStringRef
)CFArrayGetValueAtIndex((CFArrayRef
)ref
, 0) : (CFStringRef
)ref
;
148 // NOTE: this API is only available with Mac OS X >=10.3. We need to use it because
149 // Apple used non-ISO values on systems <10.2 like "German" for instance but didn't
150 // upgrade those values during upgrade to newer Mac OS X versions. See also #i54337#
151 return CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorDefault
, sref
);
154 rtl::OUString
ImplGetLocale(const char* pref
)
156 CFStringRef sref
= ImplGetAppPreference(pref
);
157 CFStringGuard
srefGuard(sref
);
159 rtl::OUStringBuffer aLocaleBuffer
;
160 aLocaleBuffer
.appendAscii("en-US"); // initialize with fallback value
164 // split the string into substrings; the first two (if there are two) substrings
165 // are language and country
166 CFArrayRef subs
= CFStringCreateArrayBySeparatingStrings(NULL
, sref
, CFSTR("_"));
167 CFArrayGuard
subsGuard(subs
);
171 aLocaleBuffer
.setLength(0); // clear buffer which still contains fallback value
173 CFStringRef lang
= (CFStringRef
)CFArrayGetValueAtIndex(subs
, 0);
174 OUStringBufferAppendCFString(aLocaleBuffer
, lang
);
176 // country also available? Assumption: if the array contains more than one
177 // value the second value is always the country!
178 if (CFArrayGetCount(subs
) > 1)
180 aLocaleBuffer
.appendAscii("-");
181 CFStringRef country
= (CFStringRef
)CFArrayGetValueAtIndex(subs
, 1);
182 OUStringBufferAppendCFString(aLocaleBuffer
, country
);
186 return aLocaleBuffer
.makeStringAndClear();
189 } // namespace /* private */
193 // -------------------------------------------------------------------------------
200 #define WINVER 0x0501
203 #pragma warning(push, 1)
210 rtl::OUString
ImplGetLocale(LCID lcid
)
215 cp
+= GetLocaleInfo( lcid
, LOCALE_SISO639LANGNAME
, buffer
, 4 );
218 if( 0 < GetLocaleInfo( lcid
, LOCALE_SISO3166CTRYNAME
, cp
, buffer
+ 8 - cp
) )
219 // #i50822# minus character must be written before cp
222 return rtl::OUString::createFromAscii(buffer
);
225 return rtl::OUString();
230 // -------------------------------------------------------------------------------
232 LocaleBackend::LocaleBackend(const uno::Reference
<uno::XComponentContext
>& xContext
)
233 throw (backend::BackendAccessException
) :
234 ::cppu::WeakImplHelper2
< backend::XSingleLayerStratum
, lang::XServiceInfo
> (),
240 //------------------------------------------------------------------------------
242 LocaleBackend::~LocaleBackend(void)
246 //------------------------------------------------------------------------------
248 LocaleBackend
* LocaleBackend::createInstance(
249 const uno::Reference
<uno::XComponentContext
>& xContext
252 return new LocaleBackend(xContext
);
255 // ---------------------------------------------------------------------------------------
257 rtl::OUString
LocaleBackend::getLocale(void)
259 #if defined(LINUX) || defined(SOLARIS) || defined(IRIX) || defined(NETBSD) || defined(FREEBSD) || defined(OS2)
260 return ImplGetLocale(LC_CTYPE
);
261 #elif defined (MACOSX)
262 return ImplGetLocale("AppleLocale");
264 return ImplGetLocale( GetUserDefaultLCID() );
268 //------------------------------------------------------------------------------
270 rtl::OUString
LocaleBackend::getUILocale(void)
272 #if defined(LINUX) || defined(SOLARIS) || defined(IRIX) || defined(NETBSD) || defined(FREEBSD) || defined(OS2)
273 return ImplGetLocale(LC_MESSAGES
);
274 #elif defined(MACOSX)
275 return ImplGetLocale("AppleLanguages");
277 return ImplGetLocale( MAKELCID(GetUserDefaultUILanguage(), SORT_DEFAULT
) );
281 // ---------------------------------------------------------------------------------------
283 rtl::OUString
LocaleBackend::getSystemLocale(void)
285 // note: the implementation differs from getLocale() only on Windows
287 return ImplGetLocale( GetSystemDefaultLCID() );
292 //------------------------------------------------------------------------------
294 rtl::OUString
LocaleBackend::createTimeStamp()
296 // the time stamp is free text, so just returning the values here.
297 return getLocale() + getUILocale() + getSystemLocale();
300 //------------------------------------------------------------------------------
302 uno::Reference
<backend::XLayer
> SAL_CALL
LocaleBackend::getLayer(
303 const rtl::OUString
& aComponent
, const rtl::OUString
& /*aTimestamp*/)
304 throw (backend::BackendAccessException
, lang::IllegalArgumentException
)
307 uno::Sequence
<rtl::OUString
> aComps( getSupportedComponents() );
308 if( aComponent
.equals( aComps
[0]) )
310 if( ! m_xSystemLayer
.is() )
312 uno::Sequence
<backend::PropertyInfo
> aPropInfoList(3);
314 aPropInfoList
[0].Name
= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.System/L10N/UILocale") );
315 aPropInfoList
[0].Type
= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "string" ) );
316 aPropInfoList
[0].Protected
= sal_False
;
317 aPropInfoList
[0].Value
= uno::makeAny( getUILocale() );
319 aPropInfoList
[1].Name
= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("org.openoffice.System/L10N/Locale") );
320 aPropInfoList
[1].Type
= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "string" ));
321 aPropInfoList
[1].Protected
= sal_False
;
322 aPropInfoList
[1].Value
= uno::makeAny( getLocale() );
324 aPropInfoList
[2].Name
= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("org.openoffice.System/L10N/SystemLocale") );
325 aPropInfoList
[2].Type
= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "string" ));
326 aPropInfoList
[2].Protected
= sal_False
;
327 aPropInfoList
[2].Value
= uno::makeAny( getSystemLocale() );
329 m_xSystemLayer
= new LocaleLayer(aPropInfoList
, createTimeStamp(), m_xContext
);
332 return m_xSystemLayer
;
335 return uno::Reference
<backend::XLayer
>();
338 //------------------------------------------------------------------------------
340 uno::Reference
<backend::XUpdatableLayer
> SAL_CALL
341 LocaleBackend::getUpdatableLayer(const rtl::OUString
& /*aComponent*/)
342 throw (backend::BackendAccessException
,lang::NoSupportException
,
343 lang::IllegalArgumentException
)
345 throw lang::NoSupportException(
346 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
347 "LocaleBackend: No Update Operation allowed, Read Only access") ),
351 //------------------------------------------------------------------------------
353 rtl::OUString SAL_CALL
LocaleBackend::getBackendName(void) {
354 return rtl::OUString::createFromAscii("com.sun.star.comp.configuration.backend.LocaleBackend") ;
357 //------------------------------------------------------------------------------
359 rtl::OUString SAL_CALL
LocaleBackend::getImplementationName(void)
360 throw (uno::RuntimeException
)
362 return getBackendName() ;
365 //------------------------------------------------------------------------------
367 uno::Sequence
<rtl::OUString
> SAL_CALL
LocaleBackend::getBackendServiceNames(void)
369 uno::Sequence
<rtl::OUString
> aServiceNameList(2);
370 aServiceNameList
[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.backend.LocaleBackend")) ;
371 aServiceNameList
[1] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.backend.PlatformBackend")) ;
373 return aServiceNameList
;
376 //------------------------------------------------------------------------------
378 sal_Bool SAL_CALL
LocaleBackend::supportsService(const rtl::OUString
& aServiceName
)
379 throw (uno::RuntimeException
)
381 uno::Sequence
< rtl::OUString
> const svc
= getBackendServiceNames();
383 for(sal_Int32 i
= 0; i
< svc
.getLength(); ++i
)
384 if(svc
[i
] == aServiceName
)
390 //------------------------------------------------------------------------------
392 uno::Sequence
<rtl::OUString
> SAL_CALL
LocaleBackend::getSupportedServiceNames(void)
393 throw (uno::RuntimeException
)
395 return getBackendServiceNames() ;
398 // ---------------------------------------------------------------------------------------
400 uno::Sequence
<rtl::OUString
> SAL_CALL
LocaleBackend::getSupportedComponents(void)
402 uno::Sequence
<rtl::OUString
> aSupportedComponentList(1);
403 aSupportedComponentList
[0] = rtl::OUString(
404 RTL_CONSTASCII_USTRINGPARAM( "org.openoffice.System" )
407 return aSupportedComponentList
;