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: matchlocale.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_configmgr.hxx"
33 #include "matchlocale.hxx"
35 #include <rtl/ustrbuf.hxx>
42 // -----------------------------------------------------------------------------
43 namespace localehelper
45 // -----------------------------------------------------------------------------
46 namespace uno
= ::com::sun::star::uno
;
47 namespace lang
= ::com::sun::star::lang
;
49 #define ARRAYSIZE( arr ) (sizeof(arr) / sizeof 0[arr] )
50 // -----------------------------------------------------------------------------
53 char const * aLanguage
;
54 char const * aCountry
;
57 char const * const c_sAnyLanguage
= "*"; // exported !
58 char const * const c_sDefLanguage
= "x-default"; // exported !
60 char const * const c_sNoCountry
= "";
62 char const * const c_sLanguageEnglish
= "en";
63 char const * const c_sCountryUS
= "US";
65 StaticLocale
const c_aFallbackLocales
[] =
67 { c_sLanguageEnglish
, c_sCountryUS
}, // english [cannot make 'en' better than 'en-US' :-(]
68 { c_sAnyLanguage
, c_sNoCountry
} // just take the first you find
70 std::vector
< com::sun::star::lang::Locale
>::size_type
const c_nFallbackLocales
= ARRAYSIZE(c_aFallbackLocales
);
72 // -----------------------------------------------------------------------------
73 bool isAnyLanguage(rtl::OUString
const & _sLanguage
)
75 return !!_sLanguage
.equalsAscii(c_sAnyLanguage
);
78 // -----------------------------------------------------------------------------
79 bool isDefaultLanguage(rtl::OUString
const & _sLanguage
)
81 return !!_sLanguage
.equalsAscii(c_sDefLanguage
);
84 // -----------------------------------------------------------------------------
85 rtl::OUString
getAnyLanguage()
87 return rtl::OUString::createFromAscii( c_sAnyLanguage
);
90 // -----------------------------------------------------------------------------
91 rtl::OUString
getDefaultLanguage()
93 return rtl::OUString::createFromAscii( c_sDefLanguage
);
96 // -----------------------------------------------------------------------------
97 com::sun::star::lang::Locale
getAnyLocale()
99 return com::sun::star::lang::Locale( getAnyLanguage(), rtl::OUString(), rtl::OUString() );
102 // -----------------------------------------------------------------------------
103 com::sun::star::lang::Locale
getDefaultLocale()
105 return com::sun::star::lang::Locale( getDefaultLanguage(), rtl::OUString(), rtl::OUString() );
108 // -----------------------------------------------------------------------------
109 static inline sal_Int32
countrySeparatorPos(rtl::OUString
const& aLocaleName_
)
111 sal_Int32 pos
= aLocaleName_
.indexOf('-');
112 if (pos
== 1) // allow for x-LL or i-LL
113 pos
= aLocaleName_
.indexOf('-',pos
+1);
116 pos
= aLocaleName_
.indexOf('_');
120 // -------------------------------------------------------------------------
121 static inline sal_Int32
countryLength(rtl::OUString
const& aLocaleName_
, sal_Int32 nCountryPos
)
123 sal_Int32 pos1
= aLocaleName_
.indexOf('.',nCountryPos
);
124 sal_Int32 pos2
= aLocaleName_
.indexOf('_',nCountryPos
);
126 if (pos1
< 0) pos1
= aLocaleName_
.getLength();
128 if (pos2
< 0 || pos1
< pos2
)
129 return pos1
- nCountryPos
;
132 return pos2
- nCountryPos
;
134 // -------------------------------------------------------------------------
135 static inline void splitLocaleString(rtl::OUString
const& aLocaleName_
, rtl::OUString
& rLanguage_
, rtl::OUString
& rCountry_
)
137 sal_Int32 nCountryPos
= countrySeparatorPos(aLocaleName_
);
138 if (nCountryPos
>= 0)
140 rLanguage_
= aLocaleName_
.copy(0,nCountryPos
).toAsciiLowerCase();
142 ++nCountryPos
; // advance past separator
143 sal_Int32 nCountryLength
= countryLength(aLocaleName_
, nCountryPos
);
145 rCountry_
= aLocaleName_
.copy(nCountryPos
,nCountryLength
).toAsciiUpperCase();
149 rLanguage_
= aLocaleName_
.toAsciiLowerCase();
150 rCountry_
= rtl::OUString();
153 // -----------------------------------------------------------------------------
155 // -----------------------------------------------------------------------------
156 // conversion helpers
157 com::sun::star::lang::Locale
makeLocale(rtl::OUString
const& sLocaleName_
)
159 com::sun::star::lang::Locale aResult
;
160 splitLocaleString(sLocaleName_
, aResult
.Language
, aResult
.Country
);
163 rtl::OUString
makeIsoLocale(com::sun::star::lang::Locale
const& aUnoLocale_
)
165 rtl::OUStringBuffer
aResult(aUnoLocale_
.Language
.toAsciiLowerCase());
166 if (aUnoLocale_
.Country
.getLength())
168 aResult
.append( sal_Unicode('-') ).append(aUnoLocale_
.Country
.toAsciiUpperCase());
170 return aResult
.makeStringAndClear();
173 com::sun::star::lang::Locale
makeLocale(StaticLocale
const& aConstLocale_
)
175 com::sun::star::lang::Locale aResult
;
176 aResult
.Language
= rtl::OUString::createFromAscii(aConstLocale_
.aLanguage
);
177 aResult
.Country
= rtl::OUString::createFromAscii(aConstLocale_
.aCountry
);
180 // -----------------------------------------------------------------------------
183 void addLocaleSeq_impl(T
const* first
, T
const* last
, std::vector
< com::sun::star::lang::Locale
>& rSeq
)
185 com::sun::star::lang::Locale (* const xlate
)(T
const&) = &makeLocale
;
187 std::transform(first
, last
, std::back_inserter(rSeq
), xlate
);
189 // -----------------------------------------------------------------------------
190 // -----------------------------------------------------------------------------
193 std::vector
< com::sun::star::lang::Locale
> makeLocaleSeq_impl(uno::Sequence
< T
> const& aLocales_
)
195 sal_Int32
const nLocaleCount
= aLocales_
.getLength();
197 T
const* pLocaleBegin
= aLocales_
.getConstArray();
199 std::vector
< com::sun::star::lang::Locale
> aResult
;
200 aResult
.reserve( nLocaleCount
+ c_nFallbackLocales
); // make room for fallback stuff as well
202 addLocaleSeq_impl(pLocaleBegin
, pLocaleBegin
+ nLocaleCount
, aResult
);
206 // -----------------------------------------------------------------------------
208 void addFallbackLocales(std::vector
< com::sun::star::lang::Locale
>& aTargetList_
)
210 addLocaleSeq_impl(c_aFallbackLocales
, c_aFallbackLocales
+ c_nFallbackLocales
, aTargetList_
);
212 // -----------------------------------------------------------------------------
214 std::vector
< com::sun::star::lang::Locale
> makeLocaleSequence(uno::Sequence
<rtl::OUString
> const& sLocaleNames_
)
216 return makeLocaleSeq_impl(sLocaleNames_
);
218 // -----------------------------------------------------------------------------
220 uno::Sequence
<rtl::OUString
> makeIsoSequence(std::vector
< com::sun::star::lang::Locale
> const& aLocales_
)
222 std::vector
< com::sun::star::lang::Locale
>::size_type
const nLocaleCount
= aLocales_
.size();
223 sal_Int32
const nSeqSize
= sal_Int32(nLocaleCount
);
224 OSL_ASSERT( nSeqSize
>= 0 && sal_uInt32(nSeqSize
) == nLocaleCount
);
226 uno::Sequence
<rtl::OUString
> aResult(nSeqSize
);
227 std::transform(aLocales_
.begin(), aLocales_
.end(), aResult
.getArray(), &makeIsoLocale
);
231 // -----------------------------------------------------------------------------
232 bool designatesAllLocales(com::sun::star::lang::Locale
const& aLocale_
)
234 return aLocale_
.Language
.equalsAscii(c_sAnyLanguage
);
236 bool designatesAllLocales(std::vector
< com::sun::star::lang::Locale
> const& aLocales_
)
238 return aLocales_
.size() <= 1 &&
239 (aLocales_
.size() == 0 || designatesAllLocales(aLocales_
));
241 // -----------------------------------------------------------------------------
243 MatchQuality
match(com::sun::star::lang::Locale
const& aLocale_
, com::sun::star::lang::Locale
const& aTarget_
)
246 if (!aLocale_
.Language
.equals(aTarget_
.Language
))
248 // can we accept any language
249 if (aTarget_
.Language
.equalsAscii(c_sAnyLanguage
))
250 return MATCH_LANGUAGE
;
255 // check for exact match
256 else if (aLocale_
.Country
.equals(aTarget_
.Country
))
259 // check for plain language
260 else if (aLocale_
.Country
.getLength() == 0)
261 return MATCH_LANGUAGE_PLAIN
;
263 // so we are left with the wrong country
265 return MATCH_LANGUAGE
;
268 // -----------------------------------------------------------------------------
270 /// check the given position and quality, if they are an improvement
271 bool MatchResult::improve(std::vector
< com::sun::star::lang::Locale
>::size_type nPos_
, MatchQuality eQuality_
)
273 // is this a match at all ?
274 if (eQuality_
== MISMATCH
)
277 // is the position worse ?
281 // is this just a non-positive quality change ?
282 if (nPos_
== m_nPos
&& eQuality_
<= m_eQuality
)
287 m_eQuality
= eQuality_
;
292 // -----------------------------------------------------------------------------
294 bool isMatch(com::sun::star::lang::Locale
const& aLocale_
, std::vector
< com::sun::star::lang::Locale
> const& aTarget_
, MatchQuality eRequiredQuality_
)
296 std::vector
< com::sun::star::lang::Locale
>::size_type
const nEnd
= aTarget_
.size();
298 for (std::vector
< com::sun::star::lang::Locale
>::size_type nPos
= 0; nPos
< nEnd
; ++nPos
)
300 MatchQuality eQuality
= match(aLocale_
, aTarget_
[nPos
]);
301 if (eQuality
>= eRequiredQuality_
)
308 // -----------------------------------------------------------------------------
312 std::vector
< com::sun::star::lang::Locale
>::size_type
getSearchLimitPosition(MatchResult
const& aPrevMatch_
,std::vector
< com::sun::star::lang::Locale
> const& aTarget_
)
314 std::vector
< com::sun::star::lang::Locale
>::size_type nSize
= aTarget_
.size();
316 if (aPrevMatch_
.isMatch())
318 std::vector
< com::sun::star::lang::Locale
>::size_type nMatchPos
= aPrevMatch_
.position();
320 OSL_ENSURE(nMatchPos
< nSize
,"localehelper::getSearchLimitPosition: ERROR - previous position is out-of-bounds");
322 if (nMatchPos
< nSize
)
324 return nMatchPos
+ 1;
329 // -----------------------------------------------------------------------------
331 bool improveMatch(MatchResult
& rMatch_
, com::sun::star::lang::Locale
const& aLocale_
, std::vector
< com::sun::star::lang::Locale
> const& aTarget_
)
333 std::vector
< com::sun::star::lang::Locale
>::size_type
const nEnd
= getSearchLimitPosition(rMatch_
,aTarget_
);
335 for (std::vector
< com::sun::star::lang::Locale
>::size_type nPos
= 0; nPos
< nEnd
; ++nPos
)
337 if (rMatch_
.improve(nPos
, match(aLocale_
, aTarget_
[nPos
])))
344 // -----------------------------------------------------------------------------
347 // -----------------------------------------------------------------------------
348 // class FindBestLocale
349 // -----------------------------------------------------------------------------
352 void FindBestLocale::implSetTarget(std::vector
< com::sun::star::lang::Locale
> const& aTarget_
)
354 m_aTarget
= aTarget_
;
355 addFallbackLocales(m_aTarget
);
357 // -----------------------------------------------------------------------------
359 FindBestLocale::FindBestLocale(com::sun::star::lang::Locale
const& aTarget_
)
361 std::vector
< com::sun::star::lang::Locale
> aSeq(1,aTarget_
);
362 implSetTarget( aSeq
);
364 // -----------------------------------------------------------------------------
366 bool FindBestLocale::accept(com::sun::star::lang::Locale
const& aLocale_
)
368 return improveMatch(m_aResult
, aLocale_
, m_aTarget
);
370 // -----------------------------------------------------------------------------
372 void FindBestLocale::reset(bool bNeedLocale_
)
377 else // mark as best match already (no improvement possible)
378 m_aResult
= m_aResult
.best();
380 // -----------------------------------------------------------------------------
382 } // namespace locale helper
383 // -----------------------------------------------------------------------------