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/unotoolsdllapi.h>
36 #include <string_view>
38 namespace com::sun::star::uno
{ class XComponentContext
; }
39 namespace com::sun::star::i18n
{ class XLocaleData5
; }
40 namespace com::sun::star::i18n
{ struct Calendar2
; }
41 namespace com::sun::star::i18n
{ struct Currency2
; }
42 namespace com::sun::star::i18n
{ struct FormatElement
; }
43 namespace com::sun::star::i18n
{ struct CalendarItem2
; }
46 namespace tools
{ class Time
; }
47 class CalendarWrapper
;
49 enum class DateOrder
{
56 enum class LongDateOrder
{
64 enum class MeasurementSystem
{
70 * This class can be accessed without locking because we load
71 * all of the data in the constructor.
73 class UNOTOOLS_DLLPUBLIC LocaleDataWrapper
75 static sal_uInt8 nLocaleDataChecking
; // 0:=dontknow, 1:=yes, 2:=no
77 css::uno::Reference
< css::uno::XComponentContext
> m_xContext
;
78 css::uno::Reference
< css::i18n::XLocaleData5
> xLD
;
79 LanguageTag maLanguageTag
;
80 std::shared_ptr
< css::i18n::Calendar2
> xDefaultCalendar
;
81 std::shared_ptr
< css::i18n::Calendar2
> xSecondaryCalendar
;
82 css::i18n::LocaleDataItem2 aLocaleDataItem
;
83 css::uno::Sequence
< OUString
> aDateAcceptancePatterns
;
84 css::uno::Sequence
< sal_Int32
> aGrouping
;
86 OUString aLocaleItem
[css::i18n::LocaleItem::COUNT2
];
87 std::vector
<OUString
> aReservedWords
;
89 OUString aCurrBankSymbol
;
91 LongDateOrder nLongDateOrder
;
92 sal_uInt16 nCurrPositiveFormat
;
93 sal_uInt16 nCurrNegativeFormat
;
94 sal_uInt16 nCurrDigits
;
97 void loadDateAcceptancePatterns(const std::vector
<OUString
> & rOverrideDateAcceptancePatterns
);
99 const OUString
& getOneLocaleItem( sal_Int16 nItem
) const;
101 const OUString
& getOneReservedWord( sal_Int16 nWord
) const;
103 void loadCurrencyFormats();
105 void scanCurrFormatImpl( const OUString
& rCode
,
106 sal_Int32 nStart
, sal_Int32
& nSign
,
107 sal_Int32
& nPar
, sal_Int32
& nNum
,
108 sal_Int32
& nBlank
, sal_Int32
& nSym
) const;
110 void loadDateOrders();
111 LongDateOrder
scanDateOrderImpl( const OUString
& rCode
) const;
113 void ImplAddFormatNum( rtl::OUStringBuffer
& rBuf
,
114 sal_Int64 nNumber
, sal_uInt16 nDecimals
,
115 bool bUseThousandSep
, bool bTrailingZeros
) const;
117 void loadDigitGrouping();
121 const css::uno::Reference
< css::uno::XComponentContext
> & rxContext
,
122 const LanguageTag
& rLanguageTag
125 @param rOverrideDateAcceptancePatterns Override locale's date acceptance patterns.
126 An empty sequence resets the patterns to the locale's pattern sequence.
129 const LanguageTag
& rLanguageTag
,
130 const std::vector
<OUString
> & rOverrideDateAcceptancePatterns
= {}
132 ~LocaleDataWrapper();
134 /** Get the service factory, meant to be able to create a CalendarWrapper
135 from a LocaleDataWrapper. Note that the service factory may be
136 non-existent if this LocaleDataWrapper was created without one and
137 lives "on the grassland". The CalendarWrapper ctor can handle that
139 const css::uno::Reference
<
140 css::uno::XComponentContext
> & getComponentContext()
141 const { return m_xContext
; }
143 /// get current requested Locale
144 const LanguageTag
& getLanguageTag() const;
146 /// get current loaded Locale, which might differ from the requested Locale
147 LanguageTag
getLoadedLanguageTag() const;
149 // Wrapper implementations of service LocaleData
151 css::i18n::LanguageCountryInfo
getLanguageCountryInfo() const;
152 /// NOTE: this wraps XLocaleData5::getLocaleItem2() in fact.
153 const css::i18n::LocaleDataItem2
& getLocaleItem() const;
154 /// NOTE: this wraps XLocaleData3::getAllCalendars2() in fact.
155 css::uno::Sequence
< css::i18n::Calendar2
> getAllCalendars() const;
156 /// NOTE: this wraps XLocaleData2::getAllCurrencies2() in fact.
157 css::uno::Sequence
< css::i18n::Currency2
> getAllCurrencies() const;
158 css::uno::Sequence
< css::i18n::FormatElement
> getAllFormats() const;
159 css::i18n::ForbiddenCharacters
getForbiddenCharacters() const;
160 const css::uno::Sequence
< css::lang::Locale
> & getAllInstalledLocaleNames() const;
161 const css::uno::Sequence
< OUString
> & getDateAcceptancePatterns() const;
164 /// same as the wrapper implementation but static
165 static const css::uno::Sequence
< css::lang::Locale
> & getInstalledLocaleNames();
167 /** Get LanguageTypes for all installed locales which are unambiguous
168 convertible back and forth between locale ISO strings and MS-LCID
169 LanguageType. Upon the first time the function is called when
170 locale data checking is enabled, messages are shown for locales not
171 matching, excluding already known problems.
172 (e.g. used in number formatter dialog init)
174 static const std::vector
< LanguageType
> & getInstalledLanguageTypes();
176 /// maps the LocaleData string to the International enum
177 MeasurementSystem
mapMeasurementStringToEnum( const OUString
& rMS
) const;
179 /// Convenience method to obtain the default calendar.
180 const std::shared_ptr
< css::i18n::Calendar2
>& getDefaultCalendar() const;
182 /// Convenience method to obtain the day names of the default calendar.
183 css::uno::Sequence
< css::i18n::CalendarItem2
> const & getDefaultCalendarDays() const;
185 /// Convenience method to obtain the month names of the default calendar.
186 css::uno::Sequence
< css::i18n::CalendarItem2
> const & getDefaultCalendarMonths() const;
188 /** If the secondary calendar, if any, is of the name passed AND number
189 formats using it usually use the E or EE keyword (EC|EEC). */
190 bool doesSecondaryCalendarUseEC( std::u16string_view rName
) const;
192 /** Obtain digit grouping. The usually known grouping by thousands (#,###)
193 is actually only one of possible groupings. Another one, for example,
194 used in India is group by 3 and then by 2 indefinitely (#,##,###). The
195 integer sequence returned here specifies grouping from right to left
196 (!), with a 0 entry designating the end of rules and the previous value
197 to be repeated indefinitely. Hence the sequence {3,0} specifies the
198 usual grouping by thousands, whereas the sequence {3,2,0} specifies
199 Indian grouping. The sal_Int32* getConstArray() can be passed directly
200 to the ::rtl::math::doubleToString() methods as argument for the
201 pGroups parameter. */
202 const css::uno::Sequence
< sal_Int32
>& getDigitGrouping() const;
204 // Functionality of class International methods, LocaleItem
206 const OUString
& getDateSep() const
207 { return getOneLocaleItem( css::i18n::LocaleItem::DATE_SEPARATOR
); }
208 const OUString
& getNumThousandSep() const
209 { return getOneLocaleItem( css::i18n::LocaleItem::THOUSAND_SEPARATOR
); }
210 const OUString
& getNumDecimalSep() const
211 { return getOneLocaleItem( css::i18n::LocaleItem::DECIMAL_SEPARATOR
); }
212 const OUString
& getNumDecimalSepAlt() const
213 { return getOneLocaleItem( css::i18n::LocaleItem::DECIMAL_SEPARATOR_ALTERNATIVE
); }
214 const OUString
& getTimeSep() const
215 { return getOneLocaleItem( css::i18n::LocaleItem::TIME_SEPARATOR
); }
216 const OUString
& getTime100SecSep() const
217 { return getOneLocaleItem( css::i18n::LocaleItem::TIME_100SEC_SEPARATOR
); }
218 const OUString
& getListSep() const
219 { return getOneLocaleItem( css::i18n::LocaleItem::LIST_SEPARATOR
); }
220 const OUString
& getQuotationMarkStart() const
221 { return getOneLocaleItem( css::i18n::LocaleItem::SINGLE_QUOTATION_START
); }
222 const OUString
& getQuotationMarkEnd() const
223 { return getOneLocaleItem( css::i18n::LocaleItem::SINGLE_QUOTATION_END
); }
224 const OUString
& getDoubleQuotationMarkStart() const
225 { return getOneLocaleItem( css::i18n::LocaleItem::DOUBLE_QUOTATION_START
); }
226 const OUString
& getDoubleQuotationMarkEnd() const
227 { return getOneLocaleItem( css::i18n::LocaleItem::DOUBLE_QUOTATION_END
); }
228 MeasurementSystem
getMeasurementSystemEnum() const
229 { return mapMeasurementStringToEnum( getOneLocaleItem( css::i18n::LocaleItem::MEASUREMENT_SYSTEM
) ); }
230 const OUString
& getTimeAM() const
231 { return getOneLocaleItem( css::i18n::LocaleItem::TIME_AM
); }
232 const OUString
& getTimePM() const
233 { return getOneLocaleItem( css::i18n::LocaleItem::TIME_PM
); }
234 const OUString
& getLongDateDayOfWeekSep() const
235 { return getOneLocaleItem( css::i18n::LocaleItem::LONG_DATE_DAY_OF_WEEK_SEPARATOR
); }
236 const OUString
& getLongDateDaySep() const
237 { return getOneLocaleItem( css::i18n::LocaleItem::LONG_DATE_DAY_SEPARATOR
); }
238 const OUString
& getLongDateMonthSep() const
239 { return getOneLocaleItem( css::i18n::LocaleItem::LONG_DATE_MONTH_SEPARATOR
); }
240 const OUString
& getLongDateYearSep() const
241 { return getOneLocaleItem( css::i18n::LocaleItem::LONG_DATE_YEAR_SEPARATOR
); }
243 /** A wrapper around rtl::math::stringToDouble() using the locale dependent
244 decimal separator, group separator, and if needed decimal separator
247 The decimal separator is tried first, if the conversion does not match
248 the entire string then the decimal separator alternative is tried if it
249 occurs in the string and was the reason to stop.
251 Leading blanks are skipped, trailing blanks are not skipped. The number
252 is parsed up to the first non-floating point number character, same as
253 rtl::math::stringToDouble() does. The caller is responsible for proper
254 error checking and end comparison.
257 The string to parse as floating point number.
259 Whether group separator is used/accepted during parsing.
261 Pointer to receive the conversion status as in
262 rtl::math::stringToDouble().
264 Pointer to receive the parse end (exclusive) as in
265 rtl::math::stringToDouble().
266 @return The floating point number as parsed.
268 double stringToDouble( const OUString
& rString
, bool bUseGroupSep
,
269 rtl_math_ConversionStatus
* pStatus
, sal_Int32
* pParseEnd
) const;
271 /** A wrapper around rtl_math_uStringToDouble() using the locale dependent
272 decimal separator, group separator, and if needed decimal separator
275 The decimal separator is tried first, if the conversion does not match
276 the entire string then the decimal separator alternative is tried if it
277 occurs in the string and was the reason to stop.
279 Leading blanks are skipped, trailing blanks are not skipped. The number
280 is parsed up to the first non-floating point number character, same as
281 rtl_math_uStringToDouble() does. The caller is responsible for proper
282 error checking and end comparison.
285 The string position to start parsing a floating point number.
287 The string position to stop parsing, exclusive.
289 Whether group separator is used/accepted during parsing.
291 Pointer to receive the conversion status as in
292 rtl_math_uStringToDouble().
294 Pointer to receive the parse end (exclusive) as in
295 rtl_math_uStringToDouble().
296 @return The floating point number as parsed.
298 double stringToDouble( const sal_Unicode
* pBegin
, const sal_Unicode
* pEnd
, bool bUseGroupSep
,
299 rtl_math_ConversionStatus
* pStatus
, const sal_Unicode
** ppParseEnd
) const;
302 const OUString
& getCurrSymbol() const;
303 const OUString
& getCurrBankSymbol() const;
304 sal_uInt16
getCurrPositiveFormat() const;
305 sal_uInt16
getCurrNegativeFormat() const;
306 sal_uInt16
getCurrDigits() const;
308 // simple date and time formatting
309 DateOrder
getDateOrder() const;
310 LongDateOrder
getLongDateOrder() const;
311 /// only numerical values of Gregorian calendar
312 OUString
getDate( const Date
& rDate
) const;
313 OUString
getTime( const tools::Time
& rTime
, bool bSec
= true,
314 bool b100Sec
= false ) const;
315 OUString
getDuration( const tools::Time
& rTime
,
316 bool bSec
= true, bool b100Sec
= false ) const;
318 /** Simple number formatting
320 value * 10**nDecimals
321 @param bTrailingZeros
322 </sal_True> := always display trailing zeros in
323 decimal places, even if integer value.
324 </sal_False> := trailing zeros are only displayed
325 if the value is not an integer value.
327 OUString
getNum( sal_Int64 nNumber
, sal_uInt16 nDecimals
,
328 bool bUseThousandSep
= true,
329 bool bTrailingZeros
= true ) const;
331 /// "Secure" currency formatted string.
332 OUString
getCurr( sal_Int64 nNumber
, sal_uInt16 nDecimals
,
333 const OUString
& rCurrencySymbol
,
334 bool bUseThousandSep
= true ) const;
336 // dummy returns, to be implemented
337 sal_Unicode
getCurrZeroChar() const
339 static bool isNumLeadingZero()
341 /// standard decimal places
342 static sal_uInt16
getNumDigits()
344 static bool isNumTrailingZeros()
349 const OUString
& getTrueWord() const
350 { return getOneReservedWord( css::i18n::reservedWords::TRUE_WORD
); }
351 const OUString
& getFalseWord() const
352 { return getOneReservedWord( css::i18n::reservedWords::FALSE_WORD
); }
353 const OUString
& getAboveWord() const
354 { return getOneReservedWord( css::i18n::reservedWords::ABOVE_WORD
); }
355 const OUString
& getBelowWord() const
356 { return getOneReservedWord( css::i18n::reservedWords::BELOW_WORD
); }
357 /// return a quarter abbreviation string matching nQuarter (0..3) => "Q1" .. "Q2"
358 const OUString
& getQuarterAbbreviation( sal_Int16 nQuarter
) const
359 { return getOneReservedWord( css::i18n::reservedWords::QUARTER1_ABBREVIATION
+ nQuarter
); }
361 /** Return whether locale data checks are enabled.
362 Checks are enabled if the environment variable
363 OOO_ENABLE_LOCALE_DATA_CHECKS is set to 'Y' or 'Yes' (or any other
364 string starting with 'Y') or '1'.
365 Also used in conjunction with the number formatter. */
366 static bool areChecksEnabled()
368 if (nLocaleDataChecking
== 0)
369 evaluateLocaleDataChecking();
370 return nLocaleDataChecking
== 1;
373 /** Append locale info to string, used with locale data checking.
374 A string similar to "de_DE requested\n en_US loaded" is appended. */
375 OUString
appendLocaleInfo(std::u16string_view rDebugMsg
) const;
377 /** Output a message during locale data checking. The (UTF-8) string is
378 written to stderr and in a non-product build or if DBG_UTIL is enabled
379 also raised as an assertion message box. */
380 static void outputCheckMessage( std::u16string_view rMsg
);
381 static void outputCheckMessage( const char* pStr
);
383 LocaleDataWrapper(const LocaleDataWrapper
&) = delete;
384 LocaleDataWrapper
& operator=(const LocaleDataWrapper
&) = delete;
388 const css::lang::Locale
& getMyLocale() const;
390 static void evaluateLocaleDataChecking();
393 #endif // INCLUDED_UNOTOOLS_LOCALEDATAWRAPPER_HXX
395 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */