tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / shell / source / backends / localebe / localebackend.cxx
blob9263a599c4b89f9b3689f56cfc19b528688d1a24
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <cassert>
24 #include <limits>
26 #include "localebackend.hxx"
27 #include <com/sun/star/beans/Optional.hpp>
28 #include <com/sun/star/uno/XComponentContext.hpp>
29 #include <cppuhelper/supportsservice.hxx>
30 #include <rtl/character.hxx>
31 #include <o3tl/char16_t2wchar_t.hxx>
32 #include <i18nlangtag/languagetag.hxx>
33 #include <i18nlangtag/mslangid.hxx>
35 #ifdef _WIN32
36 #if !defined WIN32_LEAN_AND_MEAN
37 # define WIN32_LEAN_AND_MEAN
38 #endif
39 #include <windows.h>
41 static css::beans::Optional<css::uno::Any> ImplGetLocale(LCID lcid)
43 WCHAR buffer[8];
44 PWSTR cp = buffer;
46 cp += GetLocaleInfoW( lcid, LOCALE_SISO639LANGNAME, buffer, 4 );
47 if( cp > buffer )
49 if( 0 < GetLocaleInfoW( lcid, LOCALE_SISO3166CTRYNAME, cp, buffer + 8 - cp) )
50 // #i50822# minus character must be written before cp
51 *(cp - 1) = '-';
53 return {true, css::uno::Any(OUString(o3tl::toU(buffer)))};
56 return {false, {}};
59 #elif defined(MACOSX)
61 #include <rtl/ustrbuf.hxx>
62 #include <locale.h>
63 #include <string.h>
65 #include <premac.h>
66 #include <CoreServices/CoreServices.h>
67 #include <CoreFoundation/CoreFoundation.h>
68 #include <postmac.h>
70 namespace /* private */
73 void OUStringBufferAppendCFString(OUStringBuffer& buffer, const CFStringRef s)
75 CFIndex lstr = CFStringGetLength(s);
76 for (CFIndex i = 0; i < lstr; i++)
77 buffer.append(sal_Unicode(CFStringGetCharacterAtIndex(s, i)));
80 template <typename T>
81 class CFGuard
83 public:
84 explicit CFGuard(T& rT) : rT_(rT) {}
85 ~CFGuard() { if (rT_) CFRelease(rT_); }
86 private:
87 T& rT_;
90 typedef CFGuard<CFArrayRef> CFArrayGuard;
91 typedef CFGuard<CFStringRef> CFStringGuard;
92 typedef CFGuard<CFTypeRef> CFTypeRefGuard;
94 /* For more information on the Apple locale concept please refer to
95 http://developer.apple.com/documentation/CoreFoundation/Conceptual/CFLocales/Articles/CFLocaleConcepts.html
96 According to this documentation a locale identifier has the format: language[_country][_variant]*
97 e.g. es_ES_PREEURO -> spain prior Euro support
98 Note: The calling code should be able to handle locales with only language information e.g. 'en' for certain
99 UI languages just the language code will be returned.
102 CFStringRef ImplGetAppPreference(const char* pref)
104 CFStringRef csPref = CFStringCreateWithCString(nullptr, pref, kCFStringEncodingASCII);
105 CFStringGuard csRefGuard(csPref);
107 CFTypeRef ref = CFPreferencesCopyAppValue(csPref, kCFPreferencesCurrentApplication);
108 CFTypeRefGuard refGuard(ref);
110 if (ref == nullptr)
111 return nullptr;
113 CFStringRef sref = (CFGetTypeID(ref) == CFArrayGetTypeID()) ? static_cast<CFStringRef>(CFArrayGetValueAtIndex(static_cast<CFArrayRef>(ref), 0)) : static_cast<CFStringRef>(ref);
115 // NOTE: this API is only available with macOS >=10.3. We need to use it because
116 // Apple used non-ISO values on systems <10.2 like "German" for instance but didn't
117 // upgrade those values during upgrade to newer macOS versions. See also #i54337#
118 return CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorDefault, sref);
121 css::beans::Optional<css::uno::Any> ImplGetLocale(const char* pref)
123 CFStringRef sref = ImplGetAppPreference(pref);
124 CFStringGuard srefGuard(sref);
126 OUStringBuffer aLocaleBuffer("en-US"); // initialize with fallback value
128 if (sref != nullptr)
130 // split the string into substrings; the first two (if there are two) substrings
131 // are language and country
132 CFArrayRef subs = CFStringCreateArrayBySeparatingStrings(nullptr, sref, CFSTR("_"));
133 CFArrayGuard subsGuard(subs);
135 if (subs != nullptr)
137 aLocaleBuffer.setLength(0); // clear buffer which still contains fallback value
139 CFStringRef lang = static_cast<CFStringRef>(CFArrayGetValueAtIndex(subs, 0));
140 OUStringBufferAppendCFString(aLocaleBuffer, lang);
142 // country also available? Assumption: if the array contains more than one
143 // value the second value is always the country!
144 if (CFArrayGetCount(subs) > 1)
146 aLocaleBuffer.append("-");
147 CFStringRef country = static_cast<CFStringRef>(CFArrayGetValueAtIndex(subs, 1));
148 OUStringBufferAppendCFString(aLocaleBuffer, country);
152 return {true, css::uno::Any(aLocaleBuffer.makeStringAndClear())};
155 } // namespace /* private */
157 #else
159 #include <rtl/ustrbuf.hxx>
160 #include <cstdlib>
161 #include <cstring>
163 static css::beans::Optional<css::uno::Any> ImplGetLocale(char const * category)
165 const char *locale = std::getenv("LC_ALL");
166 if (locale == nullptr || *locale == '\0') {
167 locale = std::getenv(category);
168 if (locale == nullptr || *locale == '\0') {
169 locale = std::getenv("LANG");
173 // Return "en-US" for C locales
174 if( (locale == nullptr) || *locale == '\0' || std::strcmp(locale, "C") == 0
175 || std::strcmp(locale, "POSIX") == 0 )
176 return {true, css::uno::Any(u"en-US"_ustr)};
179 const char *cp;
180 const char *uscore = nullptr;
181 const char *end = nullptr;
183 // locale string have the format lang[_ctry][.encoding][@modifier]
184 // Let LanguageTag handle all conversion, but do a sanity and length check
185 // first.
186 // For the fallback we are only interested in the first two items, so we
187 // handle '.' and '@' as string end for that.
188 for (cp = locale; *cp; cp++)
190 if (*cp == '_' && !uscore)
191 uscore = cp;
192 if ((*cp == '.' || *cp == '@') && !end)
193 end = cp;
194 if (!rtl::isAscii(static_cast<unsigned char>(*cp))) {
195 SAL_INFO("shell", "locale env var with non-ASCII content");
196 return {false, {}};
199 assert(cp >= locale);
200 if (cp - locale > std::numeric_limits<sal_Int32>::max()) {
201 SAL_INFO("shell", "locale env var content too long");
202 return {false, {}};
205 // This is a tad awkward... but the easiest way to obtain what we're
206 // actually interested in. For example this also converts
207 // "ca_ES.UTF-8@valencia" to "ca-ES-valencia".
208 const OString aLocaleStr(locale);
209 const LanguageType nLang = MsLangId::convertUnxByteStringToLanguage( aLocaleStr);
210 if (nLang != LANGUAGE_DONTKNOW)
212 const OUString aLangTagStr( LanguageTag::convertToBcp47( nLang));
213 return {true, css::uno::Any(aLangTagStr)};
216 // As a fallback, strip encoding and modifier and return just a
217 // language-country combination and let the caller handle unknowns.
218 OUStringBuffer aLocaleBuffer;
219 if (!end)
220 end = cp;
221 if( uscore != nullptr )
223 aLocaleBuffer.appendAscii(locale, uscore++ - locale);
224 aLocaleBuffer.append("-");
225 aLocaleBuffer.appendAscii(uscore, end - uscore);
227 else
229 aLocaleBuffer.appendAscii(locale, end - locale);
232 return {true, css::uno::Any(aLocaleBuffer.makeStringAndClear())};
235 #endif
238 LocaleBackend::LocaleBackend()
243 LocaleBackend::~LocaleBackend()
249 css::beans::Optional<css::uno::Any> LocaleBackend::getLocale()
251 #if defined(_WIN32)
252 return ImplGetLocale( GetUserDefaultLCID() );
253 #elif defined (MACOSX)
254 return ImplGetLocale("AppleLocale");
255 #else
256 return ImplGetLocale("LC_CTYPE");
257 #endif
261 css::beans::Optional<css::uno::Any> LocaleBackend::getUILocale()
263 #if defined(_WIN32)
264 return ImplGetLocale( MAKELCID(GetUserDefaultUILanguage(), SORT_DEFAULT) );
265 #elif defined(MACOSX)
266 return ImplGetLocale("AppleLanguages");
267 #else
268 return ImplGetLocale("LC_MESSAGES");
269 #endif
273 css::beans::Optional<css::uno::Any> LocaleBackend::getSystemLocale()
275 // note: the implementation differs from getLocale() only on Windows
276 #if defined(_WIN32)
277 return ImplGetLocale( GetSystemDefaultLCID() );
278 #else
279 return getLocale();
280 #endif
284 void LocaleBackend::setPropertyValue(
285 OUString const &, css::uno::Any const &)
287 throw css::lang::IllegalArgumentException(
288 u"setPropertyValue not supported"_ustr,
289 getXWeak(), -1);
292 css::uno::Any LocaleBackend::getPropertyValue(
293 OUString const & PropertyName)
295 if ( PropertyName == "Locale" ) {
296 return css::uno::Any(getLocale());
297 } else if (PropertyName == "SystemLocale")
299 return css::uno::Any(getSystemLocale());
300 } else if (PropertyName == "UILocale")
302 return css::uno::Any(getUILocale());
303 } else {
304 throw css::beans::UnknownPropertyException(
305 PropertyName, getXWeak());
310 OUString SAL_CALL LocaleBackend::getImplementationName()
312 return u"com.sun.star.comp.configuration.backend.LocaleBackend"_ustr ;
315 sal_Bool SAL_CALL LocaleBackend::supportsService(const OUString& aServiceName)
317 return cppu::supportsService(this, aServiceName);
320 uno::Sequence<OUString> SAL_CALL LocaleBackend::getSupportedServiceNames()
322 return { u"com.sun.star.configuration.backend.LocaleBackend"_ustr };
325 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
326 shell_LocaleBackend_get_implementation(
327 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
329 return cppu::acquire(new LocaleBackend());
332 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */