bump product version to 4.1.6.2
[LibreOffice.git] / desktop / source / app / langselect.cxx
blobd89174e36ae5131671086296877934b8546e2c43
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 .
21 #include "app.hxx"
22 #include "langselect.hxx"
23 #include "cmdlineargs.hxx"
24 #include <stdio.h>
26 #include <rtl/string.hxx>
27 #include <rtl/bootstrap.hxx>
28 #include <unotools/pathoptions.hxx>
29 #include <tools/resid.hxx>
30 #include <tools/config.hxx>
31 #include <i18nlangtag/mslangid.hxx>
32 #include <i18nlangtag/languagetag.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <com/sun/star/configuration/theDefaultProvider.hpp>
35 #include <com/sun/star/container/XNameAccess.hpp>
36 #include <com/sun/star/lang/XComponent.hpp>
37 #include <com/sun/star/beans/NamedValue.hpp>
38 #include <com/sun/star/util/XChangesBatch.hpp>
39 #include <com/sun/star/uno/Any.hxx>
40 #include <com/sun/star/lang/XLocalizable.hpp>
41 #include <com/sun/star/lang/Locale.hpp>
42 #include "com/sun/star/util/XFlushable.hpp"
43 #include <rtl/instance.hxx>
44 #include <osl/process.h>
45 #include <osl/file.hxx>
47 using namespace com::sun::star::uno;
48 using namespace com::sun::star::lang;
49 using namespace com::sun::star::container;
50 using namespace com::sun::star::beans;
51 using namespace com::sun::star::util;
54 namespace desktop {
56 static char const SOFFICE_BOOTSTRAP[] = "Bootstrap";
57 static char const SOFFICE_STARTLANG[] = "STARTLANG";
59 sal_Bool LanguageSelection::bFoundLanguage = sal_False;
60 OUString LanguageSelection::aFoundLanguage;
61 LanguageSelection::LanguageSelectionStatus LanguageSelection::m_eStatus = LS_STATUS_OK;
63 static sal_Bool existsURL( OUString const& sURL )
65 using namespace osl;
66 DirectoryItem aDirItem;
68 if (!sURL.isEmpty())
69 return ( DirectoryItem::get( sURL, aDirItem ) == DirectoryItem::E_None );
71 return sal_False;
74 // locate soffice.ini/.rc file
75 static OUString locateSofficeIniFile()
77 OUString aUserDataPath;
78 OUString aSofficeIniFileURL;
80 // Retrieve the default file URL for the soffice.ini/rc
81 rtl::Bootstrap().getIniName( aSofficeIniFileURL );
83 if ( utl::Bootstrap::locateUserData( aUserDataPath ) == utl::Bootstrap::PATH_EXISTS )
85 sal_Int32 nIndex = aSofficeIniFileURL.lastIndexOf( '/');
86 if ( nIndex > 0 )
88 OUString aUserSofficeIniFileURL = aUserDataPath + "/config" + aSofficeIniFileURL.copy( nIndex );
90 if ( existsURL( aUserSofficeIniFileURL ))
91 return aUserSofficeIniFileURL;
94 // Fallback try to use the soffice.ini/rc from program folder
95 return aSofficeIniFileURL;
98 bool LanguageSelection::prepareLanguage()
100 m_eStatus = LS_STATUS_OK;
101 Reference< XLocalizable > theConfigProvider(
102 com::sun::star::configuration::theDefaultProvider::get(
103 comphelper::getProcessComponentContext() ),
104 UNO_QUERY_THROW );
106 sal_Bool bSuccess = sal_False;
108 // #i42730#get the windows 16Bit locale - it should be preferred over the UI language
111 Reference< XPropertySet > xProp(getConfigAccess("org.openoffice.System/L10N/", sal_False), UNO_QUERY_THROW);
112 Any aWin16SysLocale = xProp->getPropertyValue("SystemLocale");
113 OUString sWin16SysLocale;
114 aWin16SysLocale >>= sWin16SysLocale;
115 if( !sWin16SysLocale.isEmpty())
116 setDefaultLanguage(sWin16SysLocale);
118 catch(const Exception&)
120 m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN;
123 // #i32939# use system locale to set document default locale
126 OUString usLocale;
127 Reference< XPropertySet > xLocaleProp(getConfigAccess(
128 "org.openoffice.System/L10N", sal_True), UNO_QUERY_THROW);
129 xLocaleProp->getPropertyValue("Locale") >>= usLocale;
130 setDefaultLanguage(usLocale);
132 catch (const Exception&)
134 m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN;
137 // get the selected UI language as string
138 bool bCmdLanguage( false );
139 bool bIniLanguage( false );
140 OUString aLocaleString = getUserUILanguage();
142 if ( aLocaleString.isEmpty() )
144 OUString aEmpty;
146 const CommandLineArgs& rCmdLineArgs = Desktop::GetCommandLineArgs();
147 aLocaleString = rCmdLineArgs.GetLanguage();
148 if (isInstalledLanguage(aLocaleString, sal_False))
150 bCmdLanguage = true;
151 bFoundLanguage = true;
152 aFoundLanguage = aLocaleString;
154 else
155 aLocaleString = aEmpty;
157 if ( !bCmdLanguage )
159 OUString aSOfficeIniURL = locateSofficeIniFile();
160 Config aConfig(aSOfficeIniURL);
161 aConfig.SetGroup( SOFFICE_BOOTSTRAP );
162 OString sLang = aConfig.ReadKey( SOFFICE_STARTLANG );
163 aLocaleString = OUString( sLang.getStr(), sLang.getLength(), RTL_TEXTENCODING_ASCII_US );
164 if (isInstalledLanguage(aLocaleString, sal_False))
166 bIniLanguage = true;
167 bFoundLanguage = true;
168 aFoundLanguage = aLocaleString;
170 else
171 aLocaleString = aEmpty;
175 // user further fallbacks for the UI language
176 if ( aLocaleString.isEmpty() )
177 aLocaleString = getLanguageString();
179 if ( !aLocaleString.isEmpty() )
183 // prepare default config provider by localizing it to the selected
184 // locale this will ensure localized configuration settings to be
185 // selected according to the UI language.
186 LanguageTag aUILanguageTag(aLocaleString);
187 theConfigProvider->setLocale(aUILanguageTag.getLocale( false));
189 Reference< XPropertySet > xProp(getConfigAccess("org.openoffice.Setup/L10N/", sal_True), UNO_QUERY_THROW);
190 if ( !bCmdLanguage )
192 // Store language only
193 xProp->setPropertyValue("ooLocale", makeAny(aLocaleString));
194 Reference< XChangesBatch >(xProp, UNO_QUERY_THROW)->commitChanges();
197 if ( bIniLanguage )
199 // Store language only
200 Reference< XPropertySet > xProp2(getConfigAccess("org.openoffice.Office.Linguistic/General/", sal_True), UNO_QUERY_THROW);
201 xProp2->setPropertyValue("UILocale", makeAny(aLocaleString));
202 Reference< XChangesBatch >(xProp2, UNO_QUERY_THROW)->commitChanges();
205 MsLangId::setConfiguredSystemUILanguage( aUILanguageTag.getLanguageType( false) );
207 OUString sLocale;
208 xProp->getPropertyValue("ooSetupSystemLocale") >>= sLocale;
209 if ( !sLocale.isEmpty() )
211 LanguageTag aLocaleLanguageTag(sLocale);
212 MsLangId::setConfiguredSystemLanguage( aLocaleLanguageTag.getLanguageType( false) );
214 else
215 MsLangId::setConfiguredSystemLanguage( MsLangId::getSystemLanguage() );
217 bSuccess = sal_True;
219 catch ( const PropertyVetoException& )
221 // we are not allowed to change this
223 catch (const Exception& e)
225 OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US);
226 OSL_FAIL(aMsg.getStr());
231 // #i32939# setting of default document locale
232 // #i32939# this should not be based on the UI language
233 setDefaultLanguage(aLocaleString);
235 return bSuccess;
238 void LanguageSelection::setDefaultLanguage(const OUString& sLocale)
240 // #i32939# setting of default document language
241 // See #i42730# for rules for determining source of settings
243 // determine script type of locale
244 LanguageType nLang = LanguageTag(sLocale).getLanguageType();
245 sal_uInt16 nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage(nLang);
247 switch (nScriptType)
249 case SCRIPTTYPE_ASIAN:
250 MsLangId::setConfiguredAsianFallback( nLang );
251 break;
252 case SCRIPTTYPE_COMPLEX:
253 MsLangId::setConfiguredComplexFallback( nLang );
254 break;
255 default:
256 MsLangId::setConfiguredWesternFallback( nLang );
257 break;
261 OUString LanguageSelection::getUserUILanguage()
263 // check whether the user has selected a specific language
264 OUString aUserLanguage = getUserLanguage();
265 if (!aUserLanguage.isEmpty() )
267 if (isInstalledLanguage(aUserLanguage))
269 // all is well
270 bFoundLanguage = sal_True;
271 aFoundLanguage = aUserLanguage;
272 return aFoundLanguage;
274 else
276 // selected language is not/no longer installed
277 resetUserLanguage();
281 return aUserLanguage;
284 OUString LanguageSelection::getLanguageString()
286 // did we already find a language?
287 if (bFoundLanguage)
288 return aFoundLanguage;
290 // check whether the user has selected a specific language
291 OUString aUserLanguage = getUserUILanguage();
292 if (!aUserLanguage.isEmpty() )
293 return aUserLanguage ;
295 // try to use system default
296 aUserLanguage = getSystemLanguage();
297 if (!aUserLanguage.isEmpty() )
299 if (isInstalledLanguage(aUserLanguage, sal_False))
301 // great, system default language is available
302 bFoundLanguage = sal_True;
303 aFoundLanguage = aUserLanguage;
304 return aFoundLanguage;
307 // fallback 1: en-US
308 OUString usFB("en-US");
309 if (isInstalledLanguage(usFB))
311 bFoundLanguage = sal_True;
312 aFoundLanguage = "en-US";
313 return aFoundLanguage;
316 // fallback didn't work use first installed language
317 aUserLanguage = getFirstInstalledLanguage();
319 bFoundLanguage = sal_True;
320 aFoundLanguage = aUserLanguage;
321 return aFoundLanguage;
324 Reference< XNameAccess > LanguageSelection::getConfigAccess(const sal_Char* pPath, sal_Bool bUpdate)
326 Reference< XNameAccess > xNameAccess;
327 try{
328 OUString sAccessSrvc;
329 if (bUpdate)
330 sAccessSrvc = "com.sun.star.configuration.ConfigurationUpdateAccess";
331 else
332 sAccessSrvc = "com.sun.star.configuration.ConfigurationAccess";
334 OUString sConfigURL = OUString::createFromAscii(pPath);
336 Reference< XMultiServiceFactory > theConfigProvider(
337 com::sun::star::configuration::theDefaultProvider::get(
338 comphelper::getProcessComponentContext() ) );
340 // access the provider
341 Sequence< Any > theArgs(1);
342 theArgs[ 0 ] <<= sConfigURL;
343 xNameAccess = Reference< XNameAccess > (
344 theConfigProvider->createInstanceWithArguments(
345 sAccessSrvc, theArgs ), UNO_QUERY_THROW );
346 } catch (const com::sun::star::uno::Exception& e)
348 OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US);
349 OSL_FAIL(aMsg.getStr());
351 return xNameAccess;
354 Sequence< OUString > LanguageSelection::getInstalledLanguages()
356 Sequence< OUString > seqLanguages;
357 Reference< XNameAccess > xAccess = getConfigAccess("org.openoffice.Setup/Office/InstalledLocales", sal_False);
358 if (!xAccess.is()) return seqLanguages;
359 seqLanguages = xAccess->getElementNames();
360 return seqLanguages;
363 // FIXME
364 // it's not very clever to handle language fallbacks here, but
365 // right now, there is no place that handles those fallbacks globally
366 static Sequence< OUString > _getFallbackLocales(const OUString& aIsoLang)
368 Sequence< OUString > seqFallbacks;
369 if ( aIsoLang == "zh-HK" ) {
370 seqFallbacks = Sequence< OUString >(1);
371 seqFallbacks[0] = "zh-TW";
373 return seqFallbacks;
376 sal_Bool LanguageSelection::isInstalledLanguage(OUString& usLocale, sal_Bool bExact)
378 sal_Bool bInstalled = sal_False;
379 Sequence< OUString > seqLanguages = getInstalledLanguages();
380 for (sal_Int32 i=0; i<seqLanguages.getLength(); i++)
382 if (usLocale.equals(seqLanguages[i]))
384 bInstalled = sal_True;
385 break;
389 if (!bInstalled && !bExact)
391 // try fallback locales
392 Sequence< OUString > seqFallbacks = _getFallbackLocales(usLocale);
393 for (sal_Int32 j=0; j<seqFallbacks.getLength(); j++)
395 for (sal_Int32 i=0; i<seqLanguages.getLength(); i++)
397 if (seqFallbacks[j].equals(seqLanguages[i]))
399 bInstalled = sal_True;
400 usLocale = seqFallbacks[j];
401 break;
407 if (!bInstalled && !bExact)
409 // no exact match was found, well try to find a substitute
410 for (sal_Int32 i=0; i<seqLanguages.getLength(); i++)
412 if (usLocale.indexOf(seqLanguages[i]) == 0)
414 // requested locale starts with the installed locale
415 // (i.e. installed locale has index 0 in requested locale)
416 bInstalled = sal_True;
417 usLocale = seqLanguages[i];
418 break;
422 return bInstalled;
425 OUString LanguageSelection::getFirstInstalledLanguage()
427 OUString aLanguage;
428 Sequence< OUString > seqLanguages = getInstalledLanguages();
429 if (seqLanguages.getLength() > 0)
430 aLanguage = seqLanguages[0];
431 return aLanguage;
434 OUString LanguageSelection::getUserLanguage()
436 OUString aUserLanguage;
437 Reference< XNameAccess > xAccess(getConfigAccess("org.openoffice.Office.Linguistic/General", sal_False));
438 if (xAccess.is())
442 xAccess->getByName("UILocale") >>= aUserLanguage;
444 catch ( NoSuchElementException const & )
446 m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN;
447 return OUString();
449 catch ( WrappedTargetException const & )
451 m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN;
452 return OUString();
455 return aUserLanguage;
458 OUString LanguageSelection::getSystemLanguage()
460 OUString aUserLanguage;
461 Reference< XNameAccess > xAccess(getConfigAccess("org.openoffice.System/L10N", sal_False));
462 if (xAccess.is())
466 xAccess->getByName("UILocale") >>= aUserLanguage;
468 catch ( NoSuchElementException const & )
470 m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN;
471 return OUString();
473 catch ( WrappedTargetException const & )
475 m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN;
476 return OUString();
479 return aUserLanguage;
483 void LanguageSelection::resetUserLanguage()
487 Reference< XPropertySet > xProp(getConfigAccess("org.openoffice.Office.Linguistic/General", sal_True), UNO_QUERY_THROW);
488 xProp->setPropertyValue("UILocale", makeAny(OUString()));
489 Reference< XChangesBatch >(xProp, UNO_QUERY_THROW)->commitChanges();
491 catch ( const PropertyVetoException& )
493 // we are not allowed to change this
495 catch (const Exception& e)
497 OString aMsg = OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US);
498 OSL_FAIL(aMsg.getStr());
499 m_eStatus = LS_STATUS_CONFIGURATIONACCESS_BROKEN;
503 LanguageSelection::LanguageSelectionStatus LanguageSelection::getStatus()
505 return m_eStatus;
508 } // namespace desktop
510 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */