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