1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
22 #include "langselect.hxx"
23 #include "cmdlineargs.hxx"
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
;
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
)
66 DirectoryItem aDirItem
;
69 return ( DirectoryItem::get( sURL
, aDirItem
) == DirectoryItem::E_None
);
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( '/');
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() ),
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
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() )
146 const CommandLineArgs
& rCmdLineArgs
= Desktop::GetCommandLineArgs();
147 aLocaleString
= rCmdLineArgs
.GetLanguage();
148 if (isInstalledLanguage(aLocaleString
, sal_False
))
151 bFoundLanguage
= true;
152 aFoundLanguage
= aLocaleString
;
155 aLocaleString
= aEmpty
;
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
))
167 bFoundLanguage
= true;
168 aFoundLanguage
= aLocaleString
;
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
);
192 // Store language only
193 xProp
->setPropertyValue("ooLocale", makeAny(aLocaleString
));
194 Reference
< XChangesBatch
>(xProp
, UNO_QUERY_THROW
)->commitChanges();
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) );
208 xProp
->getPropertyValue("ooSetupSystemLocale") >>= sLocale
;
209 if ( !sLocale
.isEmpty() )
211 LanguageTag
aLocaleLanguageTag(sLocale
);
212 MsLangId::setConfiguredSystemLanguage( aLocaleLanguageTag
.getLanguageType( false) );
215 MsLangId::setConfiguredSystemLanguage( MsLangId::getSystemLanguage() );
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
);
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
);
249 case SCRIPTTYPE_ASIAN
:
250 MsLangId::setConfiguredAsianFallback( nLang
);
252 case SCRIPTTYPE_COMPLEX
:
253 MsLangId::setConfiguredComplexFallback( nLang
);
256 MsLangId::setConfiguredWesternFallback( nLang
);
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
))
270 bFoundLanguage
= sal_True
;
271 aFoundLanguage
= aUserLanguage
;
272 return aFoundLanguage
;
276 // selected language is not/no longer installed
281 return aUserLanguage
;
284 OUString
LanguageSelection::getLanguageString()
286 // did we already find a language?
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
;
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
;
328 OUString sAccessSrvc
;
330 sAccessSrvc
= "com.sun.star.configuration.ConfigurationUpdateAccess";
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());
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();
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";
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
;
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
];
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
];
425 OUString
LanguageSelection::getFirstInstalledLanguage()
428 Sequence
< OUString
> seqLanguages
= getInstalledLanguages();
429 if (seqLanguages
.getLength() > 0)
430 aLanguage
= seqLanguages
[0];
434 OUString
LanguageSelection::getUserLanguage()
436 OUString aUserLanguage
;
437 Reference
< XNameAccess
> xAccess(getConfigAccess("org.openoffice.Office.Linguistic/General", sal_False
));
442 xAccess
->getByName("UILocale") >>= aUserLanguage
;
444 catch ( NoSuchElementException
const & )
446 m_eStatus
= LS_STATUS_CONFIGURATIONACCESS_BROKEN
;
449 catch ( WrappedTargetException
const & )
451 m_eStatus
= LS_STATUS_CONFIGURATIONACCESS_BROKEN
;
455 return aUserLanguage
;
458 OUString
LanguageSelection::getSystemLanguage()
460 OUString aUserLanguage
;
461 Reference
< XNameAccess
> xAccess(getConfigAccess("org.openoffice.System/L10N", sal_False
));
466 xAccess
->getByName("UILocale") >>= aUserLanguage
;
468 catch ( NoSuchElementException
const & )
470 m_eStatus
= LS_STATUS_CONFIGURATIONACCESS_BROKEN
;
473 catch ( WrappedTargetException
const & )
475 m_eStatus
= LS_STATUS_CONFIGURATIONACCESS_BROKEN
;
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()
508 } // namespace desktop
510 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */