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 .
20 #ifndef INCLUDED_UNOTOOLS_LOCALEDATAWRAPPER_HXX
21 #define INCLUDED_UNOTOOLS_LOCALEDATAWRAPPER_HXX
23 #include <com/sun/star/uno/Reference.hxx>
24 #include <com/sun/star/uno/Sequence.hxx>
25 #include <com/sun/star/i18n/LocaleItem.hpp>
26 #include <com/sun/star/i18n/LocaleDataItem2.hpp>
27 #include <com/sun/star/i18n/LanguageCountryInfo.hpp>
28 #include <com/sun/star/i18n/ForbiddenCharacters.hpp>
29 #include <com/sun/star/i18n/reservedWords.hpp>
30 #include <rtl/ustring.hxx>
32 #include <i18nlangtag/languagetag.hxx>
33 #include <unotools/readwritemutexguard.hxx>
34 #include <unotools/unotoolsdllapi.h>
38 namespace com
{ namespace sun
{ namespace star
{
40 class XComponentContext
;
44 namespace com
{ namespace sun
{ namespace star
{ namespace i18n
{ class XLocaleData5
; } } } }
45 namespace com
{ namespace sun
{ namespace star
{ namespace i18n
{ struct Calendar2
; } } } }
46 namespace com
{ namespace sun
{ namespace star
{ namespace i18n
{ struct Currency2
; } } } }
47 namespace com
{ namespace sun
{ namespace star
{ namespace i18n
{ struct FormatElement
; } } } }
48 namespace com
{ namespace sun
{ namespace star
{ namespace i18n
{ struct CalendarItem2
; } } } }
51 namespace tools
{ class Time
; }
52 class CalendarWrapper
;
54 enum class DateOrder
{
61 enum class MeasurementSystem
{
66 class UNOTOOLS_DLLPUBLIC LocaleDataWrapper
68 static sal_uInt8 nLocaleDataChecking
; // 0:=dontknow, 1:=yes, 2:=no
70 css::uno::Reference
< css::uno::XComponentContext
> m_xContext
;
71 css::uno::Reference
< css::i18n::XLocaleData5
> xLD
;
72 LanguageTag maLanguageTag
;
73 std::shared_ptr
< css::i18n::Calendar2
> xDefaultCalendar
;
74 std::shared_ptr
< css::i18n::Calendar2
> xSecondaryCalendar
;
75 css::i18n::LocaleDataItem2 aLocaleDataItem
;
76 css::uno::Sequence
< OUString
> aReservedWordSeq
;
77 css::uno::Sequence
< OUString
> aDateAcceptancePatterns
;
78 css::uno::Sequence
< sal_Int32
> aGrouping
;
80 OUString aLocaleItem
[css::i18n::LocaleItem::COUNT2
];
81 OUString aReservedWord
[css::i18n::reservedWords::COUNT
];
83 OUString aCurrBankSymbol
;
85 DateOrder nLongDateOrder
;
86 sal_uInt16 nCurrPositiveFormat
;
87 sal_uInt16 nCurrNegativeFormat
;
88 sal_uInt16 nCurrDigits
;
89 bool bLocaleDataItemValid
;
90 bool bReservedWordValid
;
91 bool bSecondaryCalendarValid
;
92 mutable ::utl::ReadWriteMutex aMutex
;
93 struct SAL_DLLPRIVATE Locale_Compare
95 bool operator()(const css::lang::Locale
& rLocale1
, const css::lang::Locale
& rLocale2
) const;
97 mutable std::map
<css::lang::Locale
, css::i18n::LocaleDataItem2
, Locale_Compare
> maDataItemCache
;
99 // whenever Locale changes
100 void invalidateData();
102 void getOneLocaleItemImpl( sal_Int16 nItem
);
103 const OUString
& getOneLocaleItem( sal_Int16 nItem
) const;
105 void getOneReservedWordImpl( sal_Int16 nWord
);
106 const OUString
& getOneReservedWord( sal_Int16 nWord
) const;
108 void getCurrSymbolsImpl();
109 void getCurrFormatsImpl();
111 void scanCurrFormatImpl( const OUString
& rCode
,
112 sal_Int32 nStart
, sal_Int32
& nSign
,
113 sal_Int32
& nPar
, sal_Int32
& nNum
,
114 sal_Int32
& nBlank
, sal_Int32
& nSym
) const;
116 void getDateOrdersImpl();
117 DateOrder
scanDateOrderImpl( const OUString
& rCode
) const;
119 void getDefaultCalendarImpl();
120 void getSecondaryCalendarImpl();
122 void ImplAddFormatNum( rtl::OUStringBuffer
& rBuf
,
123 sal_Int64 nNumber
, sal_uInt16 nDecimals
,
124 bool bUseThousandSep
, bool bTrailingZeros
) const;
126 void getDigitGroupingImpl();
130 const css::uno::Reference
< css::uno::XComponentContext
> & rxContext
,
131 const LanguageTag
& rLanguageTag
134 const LanguageTag
& rLanguageTag
136 ~LocaleDataWrapper();
138 /** Get the service factory, meant to be able to create a CalendarWrapper
139 from a LocaleDataWrapper. Note that the service factory may be
140 non-existent if this LocaleDataWrapper was created without one and
141 lives "on the grassland". The CalendarWrapper ctor can handle that
143 const css::uno::Reference
<
144 css::uno::XComponentContext
> & getComponentContext()
145 const { return m_xContext
; }
147 /// set a new Locale to request
148 void setLanguageTag( const LanguageTag
& rLanguageTag
);
150 /// get current requested Locale
151 const LanguageTag
& getLanguageTag() const;
153 /// get current loaded Locale, which might differ from the requested Locale
154 LanguageTag
getLoadedLanguageTag() const;
156 // Wrapper implementations of service LocaleData
158 css::i18n::LanguageCountryInfo
getLanguageCountryInfo() const;
159 /// NOTE: this wraps XLocaleData5::getLocaleItem2() in fact.
160 const css::i18n::LocaleDataItem2
& getLocaleItem() const;
161 /// NOTE: this wraps XLocaleData3::getAllCalendars2() in fact.
162 css::uno::Sequence
< css::i18n::Calendar2
> getAllCalendars() const;
163 /// NOTE: this wraps XLocaleData2::getAllCurrencies2() in fact.
164 css::uno::Sequence
< css::i18n::Currency2
> getAllCurrencies() const;
165 css::uno::Sequence
< css::i18n::FormatElement
> getAllFormats() const;
166 css::i18n::ForbiddenCharacters
getForbiddenCharacters() const;
167 css::uno::Sequence
< OUString
> getReservedWord() const;
168 css::uno::Sequence
< css::lang::Locale
> getAllInstalledLocaleNames() const;
169 css::uno::Sequence
< OUString
> getDateAcceptancePatterns() const;
171 /** Override locale's date acceptance patterns.
172 An empty sequence resets the patterns to the locale's pattern sequence.
174 void setDateAcceptancePatterns( const css::uno::Sequence
< OUString
> & rPatterns
);
176 /// same as the wrapper implementation but static
177 static css::uno::Sequence
< css::lang::Locale
> getInstalledLocaleNames();
179 /** Get LanguageTypes for all installed locales which are unambiguous
180 convertible back and forth between locale ISO strings and MS-LCID
181 LanguageType. Upon the first time the function is called when
182 locale data checking is enabled, messages are shown for locales not
183 matching, excluding already known problems.
184 (e.g. used in number formatter dialog init)
186 static std::vector
< LanguageType
> getInstalledLanguageTypes();
188 /// maps the LocaleData string to the International enum
189 MeasurementSystem
mapMeasurementStringToEnum( const OUString
& rMS
) const;
191 /// Convenience method to obtain the default calendar.
192 const std::shared_ptr
< css::i18n::Calendar2
>& getDefaultCalendar() const;
194 /// Convenience method to obtain the day names of the default calendar.
195 css::uno::Sequence
< css::i18n::CalendarItem2
> const & getDefaultCalendarDays() const;
197 /// Convenience method to obtain the month names of the default calendar.
198 css::uno::Sequence
< css::i18n::CalendarItem2
> const & getDefaultCalendarMonths() const;
200 /** If the secondary calendar, if any, is of the name passed AND number
201 formats using it usually use the E or EE keyword (EC|EEC). */
202 bool doesSecondaryCalendarUseEC( const OUString
& rName
) const;
204 /** Obtain digit grouping. The usually known grouping by thousands (#,###)
205 is actually only one of possible groupings. Another one, for example,
206 used in India is group by 3 and then by 2 indefinitely (#,##,###). The
207 integer sequence returned here specifies grouping from right to left
208 (!), with a 0 entry designating the end of rules and the previous value
209 to be repeated indefinitely. Hence the sequence {3,0} specifies the
210 usual grouping by thousands, whereas the sequence {3,2,0} specifies
211 Indian grouping. The sal_Int32* getConstArray() can be passed directly
212 to the ::rtl::math::doubleToString() methods as argument for the
213 pGroups parameter. */
214 css::uno::Sequence
< sal_Int32
> getDigitGrouping() const;
216 // Functionality of class International methods, LocaleItem
218 const OUString
& getDateSep() const
219 { return getOneLocaleItem( css::i18n::LocaleItem::DATE_SEPARATOR
); }
220 const OUString
& getNumThousandSep() const
221 { return getOneLocaleItem( css::i18n::LocaleItem::THOUSAND_SEPARATOR
); }
222 const OUString
& getNumDecimalSep() const
223 { return getOneLocaleItem( css::i18n::LocaleItem::DECIMAL_SEPARATOR
); }
224 const OUString
& getNumDecimalSepAlt() const
225 { return getOneLocaleItem( css::i18n::LocaleItem::DECIMAL_SEPARATOR_ALTERNATIVE
); }
226 const OUString
& getTimeSep() const
227 { return getOneLocaleItem( css::i18n::LocaleItem::TIME_SEPARATOR
); }
228 const OUString
& getTime100SecSep() const
229 { return getOneLocaleItem( css::i18n::LocaleItem::TIME_100SEC_SEPARATOR
); }
230 const OUString
& getListSep() const
231 { return getOneLocaleItem( css::i18n::LocaleItem::LIST_SEPARATOR
); }
232 const OUString
& getQuotationMarkStart() const
233 { return getOneLocaleItem( css::i18n::LocaleItem::SINGLE_QUOTATION_START
); }
234 const OUString
& getQuotationMarkEnd() const
235 { return getOneLocaleItem( css::i18n::LocaleItem::SINGLE_QUOTATION_END
); }
236 const OUString
& getDoubleQuotationMarkStart() const
237 { return getOneLocaleItem( css::i18n::LocaleItem::DOUBLE_QUOTATION_START
); }
238 const OUString
& getDoubleQuotationMarkEnd() const
239 { return getOneLocaleItem( css::i18n::LocaleItem::DOUBLE_QUOTATION_END
); }
240 MeasurementSystem
getMeasurementSystemEnum() const
241 { return mapMeasurementStringToEnum( getOneLocaleItem( css::i18n::LocaleItem::MEASUREMENT_SYSTEM
) ); }
242 const OUString
& getTimeAM() const
243 { return getOneLocaleItem( css::i18n::LocaleItem::TIME_AM
); }
244 const OUString
& getTimePM() const
245 { return getOneLocaleItem( css::i18n::LocaleItem::TIME_PM
); }
246 const OUString
& getLongDateDayOfWeekSep() const
247 { return getOneLocaleItem( css::i18n::LocaleItem::LONG_DATE_DAY_OF_WEEK_SEPARATOR
); }
248 const OUString
& getLongDateDaySep() const
249 { return getOneLocaleItem( css::i18n::LocaleItem::LONG_DATE_DAY_SEPARATOR
); }
250 const OUString
& getLongDateMonthSep() const
251 { return getOneLocaleItem( css::i18n::LocaleItem::LONG_DATE_MONTH_SEPARATOR
); }
252 const OUString
& getLongDateYearSep() const
253 { return getOneLocaleItem( css::i18n::LocaleItem::LONG_DATE_YEAR_SEPARATOR
); }
255 /** A wrapper around rtl::math::stringToDouble() using the locale dependent
256 decimal separator, group separator, and if needed decimal separator
259 The decimal separator is tried first, if the conversion does not match
260 the entire string then the decimal separator alternative is tried if it
261 occurs in the string and was the reason to stop.
263 Leading blanks are skipped, trailing blanks are not skipped. The number
264 is parsed up to the first non-floating point number character, same as
265 rtl::math::stringToDouble() does. The caller is responsible for proper
266 error checking and end comparison.
269 The string to parse as floating point number.
271 Whether group separator is used/accepted during parsing.
273 Pointer to receive the conversion status as in
274 rtl::math::stringToDouble().
276 Pointer to receive the parse end (exclusive) as in
277 rtl::math::stringToDouble().
278 @return The floating point number as parsed.
280 double stringToDouble( const OUString
& rString
, bool bUseGroupSep
,
281 rtl_math_ConversionStatus
* pStatus
, sal_Int32
* pParseEnd
) const;
283 /** A wrapper around rtl_math_uStringToDouble() using the locale dependent
284 decimal separator, group separator, and if needed decimal separator
287 The decimal separator is tried first, if the conversion does not match
288 the entire string then the decimal separator alternative is tried if it
289 occurs in the string and was the reason to stop.
291 Leading blanks are skipped, trailing blanks are not skipped. The number
292 is parsed up to the first non-floating point number character, same as
293 rtl_math_uStringToDouble() does. The caller is responsible for proper
294 error checking and end comparison.
297 The string position to start parsing a floating point number.
299 The string position to stop parsing, exclusive.
301 Whether group separator is used/accepted during parsing.
303 Pointer to receive the conversion status as in
304 rtl_math_uStringToDouble().
306 Pointer to receive the parse end (exclusive) as in
307 rtl_math_uStringToDouble().
308 @return The floating point number as parsed.
310 double stringToDouble( const sal_Unicode
* pBegin
, const sal_Unicode
* pEnd
, bool bUseGroupSep
,
311 rtl_math_ConversionStatus
* pStatus
, const sal_Unicode
** ppParseEnd
) const;
314 const OUString
& getCurrSymbol() const;
315 const OUString
& getCurrBankSymbol() const;
316 sal_uInt16
getCurrPositiveFormat() const;
317 sal_uInt16
getCurrNegativeFormat() const;
318 sal_uInt16
getCurrDigits() const;
320 // simple date and time formatting
321 DateOrder
getDateOrder() const;
322 DateOrder
getLongDateOrder() const;
323 /// only numerical values of Gregorian calendar
324 OUString
getDate( const Date
& rDate
) const;
325 OUString
getTime( const tools::Time
& rTime
, bool bSec
= true,
326 bool b100Sec
= false ) const;
327 OUString
getDuration( const tools::Time
& rTime
,
328 bool bSec
= true, bool b100Sec
= false ) const;
330 /** The CalendarWrapper already <b>MUST</b>
331 have loaded a calendar.
333 <FALSE/> := full year
334 <TRUE/> := year % 100
336 OUString
getLongDate( const Date
& rDate
,
337 CalendarWrapper
& rCal
,
341 /** Simple number formatting
343 value * 10**nDecimals
344 @param bTrailingZeros
345 </sal_True> := always display trailing zeros in
346 decimal places, even if integer value.
347 </sal_False> := trailing zeros are only displayed
348 if the value is not an integer value.
350 OUString
getNum( sal_Int64 nNumber
, sal_uInt16 nDecimals
,
351 bool bUseThousandSep
= true,
352 bool bTrailingZeros
= true ) const;
354 /// "Secure" currency formatted string.
355 OUString
getCurr( sal_Int64 nNumber
, sal_uInt16 nDecimals
,
356 const OUString
& rCurrencySymbol
,
357 bool bUseThousandSep
= true ) const;
359 // dummy returns, to be implemented
360 sal_Unicode
getCurrZeroChar() const
362 static bool isNumLeadingZero()
364 /// standard decimal places
365 static sal_uInt16
getNumDigits()
367 static bool isNumTrailingZeros()
372 const OUString
& getTrueWord() const
373 { return getOneReservedWord( css::i18n::reservedWords::TRUE_WORD
); }
374 const OUString
& getFalseWord() const
375 { return getOneReservedWord( css::i18n::reservedWords::FALSE_WORD
); }
376 const OUString
& getAboveWord() const
377 { return getOneReservedWord( css::i18n::reservedWords::ABOVE_WORD
); }
378 const OUString
& getBelowWord() const
379 { return getOneReservedWord( css::i18n::reservedWords::BELOW_WORD
); }
380 /// return a quarter abbreviation string matching nQuarter (0..3) => "Q1" .. "Q2"
381 const OUString
& getQuarterAbbreviation( sal_Int16 nQuarter
) const
382 { return getOneReservedWord( css::i18n::reservedWords::QUARTER1_ABBREVIATION
+ nQuarter
); }
384 /** Return whether locale data checks are enabled.
385 Checks are enabled if the environment variable
386 OOO_ENABLE_LOCALE_DATA_CHECKS is set to 'Y' or 'Yes' (or any other
387 string starting with 'Y') or '1'.
388 Also used in conjunction with the number formatter. */
389 static bool areChecksEnabled()
391 if (nLocaleDataChecking
== 0)
392 evaluateLocaleDataChecking();
393 return nLocaleDataChecking
== 1;
396 /** Append locale info to string, used with locale data checking.
397 A string similar to "de_DE requested\n en_US loaded" is appended. */
398 OUString
appendLocaleInfo(const OUString
& rDebugMsg
) const;
400 /** Output a message during locale data checking. The (UTF-8) string is
401 written to stderr and in a non-product build or if DBG_UTIL is enabled
402 also raised as an assertion message box. */
403 static void outputCheckMessage( const OUString
& rMsg
);
404 static void outputCheckMessage( const char* pStr
);
406 LocaleDataWrapper(const LocaleDataWrapper
&) = delete;
407 LocaleDataWrapper
& operator=(const LocaleDataWrapper
&) = delete;
411 const css::lang::Locale
& getMyLocale() const;
413 static void evaluateLocaleDataChecking();
416 #endif // INCLUDED_UNOTOOLS_LOCALEDATAWRAPPER_HXX
418 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */