1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <numberformatsbuffer.hxx>
21 #include <biffhelper.hxx>
22 
23 #include <com/sun/star/i18n/NumberFormatIndex.hpp>
24 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
25 #include <com/sun/star/util/XNumberFormatTypes.hpp>
26 #include <com/sun/star/util/XNumberFormats.hpp>
27 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
28 #include <officecfg/Setup.hxx>
29 #include <officecfg/System.hxx>
30 #include <rtl/strbuf.hxx>
31 #include <rtl/string.hxx>
32 #include <osl/diagnose.h>
33 #include <osl/thread.h>
34 #include <rtl/ustrbuf.hxx>
35 #include <svl/intitem.hxx>
36 #include <svl/itemset.hxx>
37 #include <oox/helper/binaryinputstream.hxx>
38 #include <oox/helper/attributelist.hxx>
39 #include <oox/token/tokens.hxx>
40 #include <scitems.hxx>
41 #include <document.hxx>
42 #include <ftools.hxx>
43 
44 namespace oox::xls {
45 
46 using namespace ::com::sun::star::lang;
47 using namespace ::com::sun::star::uno;
48 using namespace ::com::sun::star::util;
49 
50 namespace {
51 
52 /** Stores the number format used in Calc for an Excel built-in number format. */
53 struct BuiltinFormat
54 {
55     sal_Int32           mnNumFmtId;         /// Built-in number format index.
56     const char*         mpcFmtCode;         /// Format string, UTF-8, may be 0 (mnPredefId is used then).
57     sal_Int16           mnPredefId;         /// Predefined format index, if mpcFmtCode is 0.
58     sal_Int32           mnReuseId;          /// Use this format, if mpcFmtCode is 0 and mnPredefId is -1.
59 };
60 
61 /** Defines a literal built-in number format. */
62 #define NUMFMT_STRING( INDEX, FORMATCODE ) \
63     { INDEX, FORMATCODE, -1, -1 }
64 
65 /** Defines a built-in number format that maps to an own predefined format. */
66 #define NUMFMT_PREDEF( INDEX, PREDEFINED ) \
67     { INDEX, nullptr, css::i18n::NumberFormatIndex::PREDEFINED, -1 }
68 
69 /** Defines a built-in number format that is the same as the specified in nReuseId. */
70 #define NUMFMT_REUSE( INDEX, REUSED_INDEX ) \
71     { INDEX, nullptr, -1, REUSED_INDEX }
72 
73 /** Terminates a built-in number format table. */
74 #define NUMFMT_ENDTABLE() \
75     { -1, nullptr, -1, -1 }
76 
77 /** Defines builtin date and time formats 14...22.
78     @param SYSTEMDATE  Complete short system date (for formats 14 and 22).
79     @param DAY  Day format (for formats 15 and 16).
80     @param DAYSEP  Separator between day and month (for formats 15 and 16).
81     @param MONTH  Month format (for formats 15...17).
82     @param MONTHSEP  Separator between month and year (for formats 15 and 17).
83     @param YEAR  Year format (for formats 15 and 17).
84     @param HOUR12  Hour format for 12-hour AM/PM formats (formats 18 and 19).
85     @param HOUR24  Hour format for 24-hour formats (formats 20...22). */
86 #define NUMFMT_ALLDATETIMES( SYSTEMDATE, DAY, DAYSEP, MONTH, MONTHSEP, YEAR, HOUR12, HOUR24 ) \
87     NUMFMT_STRING(  14, SYSTEMDATE ), \
88     NUMFMT_STRING(  15, DAY DAYSEP MONTH MONTHSEP YEAR ), \
89     NUMFMT_STRING(  16, DAY DAYSEP MONTH ), \
90     NUMFMT_STRING(  17, MONTH MONTHSEP YEAR ), \
91     NUMFMT_STRING(  18, HOUR12 ":mm AM/PM" ), \
92     NUMFMT_STRING(  19, HOUR12 ":mm:ss AM/PM" ), \
93     NUMFMT_STRING(  20, HOUR24 ":mm" ), \
94     NUMFMT_STRING(  21, HOUR24 ":mm:ss" ), \
95     NUMFMT_STRING(  22, SYSTEMDATE " " HOUR24 ":mm" )
96 
97 /** Defines builtin time formats INDEX and INDEX+1 for CJK locales.
98     @param INDEX  First number format index.
99     @param HOURFORMAT  Hour format.
100     @param HOUR  Hour symbol.
101     @param MINUTE  Minute symbol.
102     @param SECOND  Second symbol. */
103 #define NUMFMT_TIME_CJK( INDEX, HOURFORMAT, HOUR, MINUTE, SECOND ) \
104     NUMFMT_STRING( INDEX + 0, HOURFORMAT "\"" HOUR "\"mm\"" MINUTE "\"" ), \
105     NUMFMT_STRING( INDEX + 1, HOURFORMAT "\"" HOUR "\"mm\"" MINUTE "\"ss\"" SECOND "\"" )
106 
107 /** Defines builtin time formats 32...35 for CJK locales.
108     @param HOUR12  Hour format for 12-hour AM/PM formats (formats 34 and 35).
109     @param HOUR24  Hour format for 24-hour formats (formats 32 and 33).
110     @param HOUR  Hour symbol.
111     @param MINUTE  Minute symbol.
112     @param SECOND  Second symbol. */
113 #define NUMFMT_ALLTIMES_CJK( HOUR12, HOUR24, HOUR, MINUTE, SECOND ) \
114     NUMFMT_TIME_CJK( 32, HOUR24, HOUR, MINUTE, SECOND ), \
115     NUMFMT_TIME_CJK( 34, "AM/PM" HOUR12, HOUR, MINUTE, SECOND )
116 
117 /** Defines builtin currency formats INDEX...INDEX+3 in the following format:
118     "symbol, [minus], number".
119     @param INDEX  First number format index.
120     @param SYMBOL  Currency symbol.
121     @param SPACE  Space character(s) between currency symbol and number.
122     @param MODIF  Leading modifier for each portion (e.g. "t" for Thai formats). */
123 #define NUMFMT_CURRENCY_SYMBOL_MINUS_NUMBER( INDEX, SYMBOL, SPACE, MODIF ) \
124     NUMFMT_STRING( INDEX + 0, MODIF SYMBOL SPACE "#,##0;"            MODIF SYMBOL SPACE "-#,##0" ), \
125     NUMFMT_STRING( INDEX + 1, MODIF SYMBOL SPACE "#,##0;"    "[RED]" MODIF SYMBOL SPACE "-#,##0" ), \
126     NUMFMT_STRING( INDEX + 2, MODIF SYMBOL SPACE "#,##0.00;"         MODIF SYMBOL SPACE "-#,##0.00" ), \
127     NUMFMT_STRING( INDEX + 3, MODIF SYMBOL SPACE "#,##0.00;" "[RED]" MODIF SYMBOL SPACE "-#,##0.00" )
128 
129 /** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
130     "symbol, [minus], number".
131     @param INDEX  First number format index.
132     @param SYMBOL  Currency symbol.
133     @param SPACE  Space character(s) between currency symbol and number. */
134 #define NUMFMT_ACCOUNTING_SYMBOL_MINUS_NUMBER( INDEX, SYMBOL, SPACE ) \
135     NUMFMT_STRING( INDEX + 0, "_ "              "* #,##0_ ;"    "_ "              "* -#,##0_ ;"    "_ "              "* \"-\"_ ;"    "_ @_ " ), \
136     NUMFMT_STRING( INDEX + 1, "_ " SYMBOL SPACE "* #,##0_ ;"    "_ " SYMBOL SPACE "* -#,##0_ ;"    "_ " SYMBOL SPACE "* \"-\"_ ;"    "_ @_ " ), \
137     NUMFMT_STRING( INDEX + 2, "_ "              "* #,##0.00_ ;" "_ "              "* -#,##0.00_ ;" "_ "              "* \"-\"?\?_ ;" "_ @_ " ), \
138     NUMFMT_STRING( INDEX + 3, "_ " SYMBOL SPACE "* #,##0.00_ ;" "_ " SYMBOL SPACE "* -#,##0.00_ ;" "_ " SYMBOL SPACE "* \"-\"?\?_ ;" "_ @_ " )
139 
140 /** Defines builtin currency formats 5...8 (with currency symbol), 37...40
141     (blind currency symbol), and 41...44 (accounting), in the following format:
142     "symbol, [minus], number".
143     @param SYMBOL  Currency symbol.
144     @param SPACE  Space character(s) between currency symbol and number. */
145 #define NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( SYMBOL, SPACE ) \
146     NUMFMT_CURRENCY_SYMBOL_MINUS_NUMBER( 5, SYMBOL, SPACE, "" ), \
147     NUMFMT_CURRENCY_SYMBOL_MINUS_NUMBER( 37, "", "", "" ), \
148     NUMFMT_ACCOUNTING_SYMBOL_MINUS_NUMBER( 41, SYMBOL, SPACE )
149 
150 /** Defines builtin currency formats INDEX...INDEX+3 in the following format:
151     "symbol, number, [minus]".
152     @param INDEX  First number format index.
153     @param SYMBOL  Currency symbol.
154     @param SPACE  Space character(s) between currency symbol and number.
155     @param MODIF  Leading modifier for each portion (e.g. "t" for Thai formats). */
156 #define NUMFMT_CURRENCY_SYMBOL_NUMBER_MINUS( INDEX, SYMBOL, SPACE, MODIF ) \
157     NUMFMT_STRING( INDEX + 0, MODIF SYMBOL SPACE "#,##0_-;"            MODIF SYMBOL SPACE "#,##0-" ), \
158     NUMFMT_STRING( INDEX + 1, MODIF SYMBOL SPACE "#,##0_-;"    "[RED]" MODIF SYMBOL SPACE "#,##0-" ), \
159     NUMFMT_STRING( INDEX + 2, MODIF SYMBOL SPACE "#,##0.00_-;"         MODIF SYMBOL SPACE "#,##0.00-" ), \
160     NUMFMT_STRING( INDEX + 3, MODIF SYMBOL SPACE "#,##0.00_-;" "[RED]" MODIF SYMBOL SPACE "#,##0.00-" )
161 
162 /** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
163     "symbol, number, [minus]".
164     @param INDEX  First number format index.
165     @param SYMBOL  Currency symbol.
166     @param SPACE  Space character(s) between currency symbol and number. */
167 #define NUMFMT_ACCOUNTING_SYMBOL_NUMBER_MINUS( INDEX, SYMBOL, SPACE ) \
168     NUMFMT_STRING( INDEX + 0, "_-"              "* #,##0_-;"    "_-"              "* #,##0-;"    "_-"              "* \"-\"_-;"    "_-@_-" ), \
169     NUMFMT_STRING( INDEX + 1, "_-" SYMBOL SPACE "* #,##0_-;"    "_-" SYMBOL SPACE "* #,##0-;"    "_-" SYMBOL SPACE "* \"-\"_-;"    "_-@_-" ), \
170     NUMFMT_STRING( INDEX + 2, "_-"              "* #,##0.00_-;" "_-"              "* #,##0.00-;" "_-"              "* \"-\"?\?_-;" "_-@_-" ), \
171     NUMFMT_STRING( INDEX + 3, "_-" SYMBOL SPACE "* #,##0.00_-;" "_-" SYMBOL SPACE "* #,##0.00-;" "_-" SYMBOL SPACE "* \"-\"?\?_-;" "_-@_-" )
172 
173 /** Defines builtin currency formats 5...8 (with currency symbol), 37...40
174     (blind currency symbol), and 41...44 (accounting), in the following format:
175     "symbol, number, [minus]".
176     @param SYMBOL  Currency symbol.
177     @param SPACE  Space character(s) between currency symbol and number. */
178 #define NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( SYMBOL, SPACE ) \
179     NUMFMT_CURRENCY_SYMBOL_NUMBER_MINUS( 5, SYMBOL, SPACE, "" ), \
180     NUMFMT_CURRENCY_SYMBOL_NUMBER_MINUS( 37, "", "", "" ), \
181     NUMFMT_ACCOUNTING_SYMBOL_NUMBER_MINUS( 41, SYMBOL, SPACE )
182 
183 /** Defines builtin currency formats INDEX...INDEX+3 in the following format:
184     "number, symbol, [minus]".
185     @param INDEX  First number format index.
186     @param SYMBOL  Currency symbol.
187     @param SPACE  Space character(s) between number and currency symbol.
188     @param MODIF  Leading modifier for each portion (e.g. "t" for Thai formats). */
189 #define NUMFMT_CURRENCY_NUMBER_SYMBOL_MINUS( INDEX, SYMBOL, SPACE, MODIF ) \
190     NUMFMT_STRING( INDEX + 0, MODIF "#,##0"    SPACE SYMBOL "_-;"         MODIF "#,##0"    SPACE SYMBOL "-" ), \
191     NUMFMT_STRING( INDEX + 1, MODIF "#,##0"    SPACE SYMBOL "_-;" "[RED]" MODIF "#,##0"    SPACE SYMBOL "-" ), \
192     NUMFMT_STRING( INDEX + 2, MODIF "#,##0.00" SPACE SYMBOL "_-;"         MODIF "#,##0.00" SPACE SYMBOL "-" ), \
193     NUMFMT_STRING( INDEX + 3, MODIF "#,##0.00" SPACE SYMBOL "_-;" "[RED]" MODIF "#,##0.00" SPACE SYMBOL "-" )
194 
195 /** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
196     "number, symbol, [minus]".
197     @param INDEX  First number format index.
198     @param SYMBOL  Currency symbol.
199     @param BLINDS  Blind currency symbol.
200     @param SPACE  Space character(s) between number and currency symbol. */
201 #define NUMFMT_ACCOUNTING_NUMBER_SYMBOL_MINUS( INDEX, SYMBOL, BLINDS, SPACE ) \
202     NUMFMT_STRING( INDEX + 0, "_-* #,##0"    SPACE BLINDS "_-;_-* #,##0"    SPACE BLINDS "-;_-* \"-\""    SPACE BLINDS "_-;_-@_-" ), \
203     NUMFMT_STRING( INDEX + 1, "_-* #,##0"    SPACE SYMBOL "_-;_-* #,##0"    SPACE SYMBOL "-;_-* \"-\""    SPACE SYMBOL "_-;_-@_-" ), \
204     NUMFMT_STRING( INDEX + 2, "_-* #,##0.00" SPACE BLINDS "_-;_-* #,##0.00" SPACE BLINDS "-;_-* \"-\"?\?" SPACE BLINDS "_-;_-@_-" ), \
205     NUMFMT_STRING( INDEX + 3, "_-* #,##0.00" SPACE SYMBOL "_-;_-* #,##0.00" SPACE SYMBOL "-;_-* \"-\"?\?" SPACE SYMBOL "_-;_-@_-" )
206 
207 /** Defines builtin currency formats 5...8 (with currency symbol), 37...40
208     (blind currency symbol), and 41...44 (accounting), in the following format:
209     "number, symbol, [minus]".
210     @param SYMBOL  Currency symbol.
211     @param BLINDS  Blind currency symbol.
212     @param SPACE  Space character(s) between number and currency symbol. */
213 #define NUMFMT_ALLCURRENCIES_NUMBER_SYMBOL_MINUS( SYMBOL, BLINDS, SPACE ) \
214     NUMFMT_CURRENCY_NUMBER_SYMBOL_MINUS( 5, SYMBOL, SPACE, "" ), \
215     NUMFMT_CURRENCY_NUMBER_SYMBOL_MINUS( 37, BLINDS, SPACE, "" ), \
216     NUMFMT_ACCOUNTING_NUMBER_SYMBOL_MINUS( 41, SYMBOL, BLINDS, SPACE )
217 
218 /** Defines builtin currency formats INDEX...INDEX+3 in the following format:
219     "[minus], symbol, number".
220     @param INDEX  First number format index.
221     @param SYMBOL  Currency symbol.
222     @param SPACE  Space character(s) between currency symbol and number.
223     @param MODIF  Leading modifier for each portion (e.g. "t" for Thai formats). */
224 #define NUMFMT_CURRENCY_MINUS_SYMBOL_NUMBER( INDEX, SYMBOL, SPACE, MODIF ) \
225     NUMFMT_STRING( INDEX + 0, MODIF SYMBOL SPACE "#,##0;"            MODIF "-" SYMBOL SPACE "#,##0" ), \
226     NUMFMT_STRING( INDEX + 1, MODIF SYMBOL SPACE "#,##0;"    "[RED]" MODIF "-" SYMBOL SPACE "#,##0" ), \
227     NUMFMT_STRING( INDEX + 2, MODIF SYMBOL SPACE "#,##0.00;"         MODIF "-" SYMBOL SPACE "#,##0.00" ), \
228     NUMFMT_STRING( INDEX + 3, MODIF SYMBOL SPACE "#,##0.00;" "[RED]" MODIF "-" SYMBOL SPACE "#,##0.00" )
229 
230 /** Defines builtin accounting formats INDEX...INDEX+3 in the following order:
231     "[minus], symbol, number".
232     @param INDEX  First number format index.
233     @param SYMBOL  Currency symbol.
234     @param SPACE  Space character(s) between currency symbol and number. */
235 #define NUMFMT_ACCOUNTING_MINUS_SYMBOL_NUMBER( INDEX, SYMBOL, SPACE ) \
236     NUMFMT_STRING( INDEX + 0, "_-"              "* #,##0_-;"    "-"              "* #,##0_-;"    "_-"              "* \"-\"_-;"    "_-@_-" ), \
237     NUMFMT_STRING( INDEX + 1, "_-" SYMBOL SPACE "* #,##0_-;"    "-" SYMBOL SPACE "* #,##0_-;"    "_-" SYMBOL SPACE "* \"-\"_-;"    "_-@_-" ), \
238     NUMFMT_STRING( INDEX + 2, "_-"              "* #,##0.00_-;" "-"              "* #,##0.00_-;" "_-"              "* \"-\"?\?_-;" "_-@_-" ), \
239     NUMFMT_STRING( INDEX + 3, "_-" SYMBOL SPACE "* #,##0.00_-;" "-" SYMBOL SPACE "* #,##0.00_-;" "_-" SYMBOL SPACE "* \"-\"?\?_-;" "_-@_-" )
240 
241 /** Defines builtin currency formats 5...8 (with currency symbol), 37...40
242     (blind currency symbol), and 41...44 (accounting), in the following order:
243     "[minus], symbol, number".
244     @param SYMBOL  Currency symbol.
245     @param SPACE  Space character(s) between currency symbol and number. */
246 #define NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( SYMBOL, SPACE ) \
247     NUMFMT_CURRENCY_MINUS_SYMBOL_NUMBER( 5, SYMBOL, SPACE, "" ), \
248     NUMFMT_CURRENCY_MINUS_SYMBOL_NUMBER( 37, "", "", "" ), \
249     NUMFMT_ACCOUNTING_MINUS_SYMBOL_NUMBER( 41, SYMBOL, SPACE )
250 
251 /** Defines builtin currency formats INDEX...INDEX+3 in the following format:
252     "[minus], number, symbol".
253     @param INDEX  First number format index.
254     @param SYMBOL  Currency symbol.
255     @param SPACE  Space character(s) between number and currency symbol.
256     @param MODIF  Leading modifier for each portion (e.g. "t" for Thai formats). */
257 #define NUMFMT_CURRENCY_MINUS_NUMBER_SYMBOL( INDEX, SYMBOL, SPACE, MODIF ) \
258     NUMFMT_STRING( INDEX + 0, MODIF "#,##0"    SPACE SYMBOL ";"         MODIF "-#,##0"    SPACE SYMBOL ), \
259     NUMFMT_STRING( INDEX + 1, MODIF "#,##0"    SPACE SYMBOL ";" "[RED]" MODIF "-#,##0"    SPACE SYMBOL ), \
260     NUMFMT_STRING( INDEX + 2, MODIF "#,##0.00" SPACE SYMBOL ";"         MODIF "-#,##0.00" SPACE SYMBOL ), \
261     NUMFMT_STRING( INDEX + 3, MODIF "#,##0.00" SPACE SYMBOL ";" "[RED]" MODIF "-#,##0.00" SPACE SYMBOL )
262 
263 /** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
264     "[minus], number, symbol".
265     @param INDEX  First number format index.
266     @param SYMBOL  Currency symbol.
267     @param BLINDS  Blind currency symbol.
268     @param SPACE  Space character(s) between number and currency symbol. */
269 #define NUMFMT_ACCOUNTING_MINUS_NUMBER_SYMBOL( INDEX, SYMBOL, BLINDS, SPACE ) \
270     NUMFMT_STRING( INDEX + 0, "_-* #,##0"    SPACE BLINDS "_-;-* #,##0"    SPACE BLINDS "_-;_-* \"-\""    SPACE BLINDS "_-;_-@_-" ), \
271     NUMFMT_STRING( INDEX + 1, "_-* #,##0"    SPACE SYMBOL "_-;-* #,##0"    SPACE SYMBOL "_-;_-* \"-\""    SPACE SYMBOL "_-;_-@_-" ), \
272     NUMFMT_STRING( INDEX + 2, "_-* #,##0.00" SPACE BLINDS "_-;-* #,##0.00" SPACE BLINDS "_-;_-* \"-\"?\?" SPACE BLINDS "_-;_-@_-" ), \
273     NUMFMT_STRING( INDEX + 3, "_-* #,##0.00" SPACE SYMBOL "_-;-* #,##0.00" SPACE SYMBOL "_-;_-* \"-\"?\?" SPACE SYMBOL "_-;_-@_-" )
274 
275 /** Defines builtin currency formats 5...8 (with currency symbol), 37...40
276     (blind currency symbol), and 41...44 (accounting), in the following format:
277     "[minus], number, symbol".
278     @param SYMBOL  Currency symbol.
279     @param BLINDS  Blind currency symbol.
280     @param SPACE  Space character(s) between number and currency symbol. */
281 #define NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( SYMBOL, BLINDS, SPACE ) \
282     NUMFMT_CURRENCY_MINUS_NUMBER_SYMBOL( 5, SYMBOL, SPACE, "" ), \
283     NUMFMT_CURRENCY_MINUS_NUMBER_SYMBOL( 37, BLINDS, SPACE, "" ), \
284     NUMFMT_ACCOUNTING_MINUS_NUMBER_SYMBOL( 41, SYMBOL, BLINDS, SPACE )
285 
286 /** Defines builtin currency formats INDEX...INDEX+3 in the following format:
287     "[opening parenthesis], symbol, number, [closing parenthesis].".
288     @param INDEX  First number format index.
289     @param SYMBOL  Currency symbol.
290     @param SPACE  Space character(s) between currency symbol and number.
291     @param MODIF  Leading modifier for each portion (e.g. "t" for Thai formats). */
292 #define NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( INDEX, SYMBOL, SPACE, MODIF ) \
293     NUMFMT_STRING( INDEX + 0, MODIF SYMBOL SPACE "#,##0_);"            MODIF "(" SYMBOL SPACE "#,##0)" ), \
294     NUMFMT_STRING( INDEX + 1, MODIF SYMBOL SPACE "#,##0_);"    "[RED]" MODIF "(" SYMBOL SPACE "#,##0)" ), \
295     NUMFMT_STRING( INDEX + 2, MODIF SYMBOL SPACE "#,##0.00_);"         MODIF "(" SYMBOL SPACE "#,##0.00)" ), \
296     NUMFMT_STRING( INDEX + 3, MODIF SYMBOL SPACE "#,##0.00_);" "[RED]" MODIF "(" SYMBOL SPACE "#,##0.00)" )
297 
298 /** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
299     "[opening parenthesis], symbol, number, [closing parenthesis].".
300     @param INDEX  First number format index.
301     @param SYMBOL  Currency symbol.
302     @param SPACE  Space character(s) between currency symbol and number. */
303 #define NUMFMT_ACCOUNTING_OPEN_SYMBOL_NUMBER_CLOSE( INDEX, SYMBOL, SPACE ) \
304     NUMFMT_STRING( INDEX + 0, "_("              "* #,##0_);"    "_("              "* (#,##0);"    "_("              "* \"-\"_);"    "_(@_)" ), \
305     NUMFMT_STRING( INDEX + 1, "_(" SYMBOL SPACE "* #,##0_);"    "_(" SYMBOL SPACE "* (#,##0);"    "_(" SYMBOL SPACE "* \"-\"_);"    "_(@_)" ), \
306     NUMFMT_STRING( INDEX + 2, "_("              "* #,##0.00_);" "_("              "* (#,##0.00);" "_("              "* \"-\"?\?_);" "_(@_)" ), \
307     NUMFMT_STRING( INDEX + 3, "_(" SYMBOL SPACE "* #,##0.00_);" "_(" SYMBOL SPACE "* (#,##0.00);" "_(" SYMBOL SPACE "* \"-\"?\?_);" "_(@_)" )
308 
309 /** Defines builtin currency formats 5...8 (with currency symbol), 37...40
310     (blind currency symbol), and 41...44 (accounting), in the following format:
311     "[opening parenthesis], symbol, number, [closing parenthesis].".
312     @param SYMBOL  Currency symbol.
313     @param SPACE  Space character(s) between currency symbol and number. */
314 #define NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( SYMBOL, SPACE ) \
315     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 5, SYMBOL, SPACE, "" ), \
316     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 37, "", "", "" ), \
317     NUMFMT_ACCOUNTING_OPEN_SYMBOL_NUMBER_CLOSE( 41, SYMBOL, SPACE )
318 
319 /** Defines builtin currency formats INDEX...INDEX+3 in the following format:
320     "[opening parenthesis], number, symbol, [closing parenthesis].".
321     @param INDEX  First number format index.
322     @param SYMBOL  Currency symbol.
323     @param SPACE  Space character(s) between number and currency symbol.
324     @param MODIF  Leading modifier for each portion (e.g. "t" for Thai formats). */
325 #define NUMFMT_CURRENCY_OPEN_NUMBER_SYMBOL_CLOSE( INDEX, SYMBOL, SPACE, MODIF ) \
326     NUMFMT_STRING( INDEX + 0, MODIF "#,##0"    SPACE SYMBOL "_);"         MODIF "(#,##0"    SPACE SYMBOL ")" ), \
327     NUMFMT_STRING( INDEX + 1, MODIF "#,##0"    SPACE SYMBOL "_);" "[RED]" MODIF "(#,##0"    SPACE SYMBOL ")" ), \
328     NUMFMT_STRING( INDEX + 2, MODIF "#,##0.00" SPACE SYMBOL "_);"         MODIF "(#,##0.00" SPACE SYMBOL ")" ), \
329     NUMFMT_STRING( INDEX + 3, MODIF "#,##0.00" SPACE SYMBOL "_);" "[RED]" MODIF "(#,##0.00" SPACE SYMBOL ")" )
330 
331 /** Defines builtin accounting formats INDEX...INDEX+3 in the following format:
332     "[opening parenthesis], number, symbol, [closing parenthesis].".
333     @param INDEX  First number format index.
334     @param SYMBOL  Currency symbol.
335     @param BLINDS  Blind currency symbol.
336     @param SPACE  Space character(s) between number and currency symbol. */
337 #define NUMFMT_ACCOUNTING_OPEN_NUMBER_SYMBOL_CLOSE( INDEX, SYMBOL, BLINDS, SPACE ) \
338     NUMFMT_STRING( INDEX + 0, "_ * #,##0_)"    SPACE BLINDS "_ ;_ * (#,##0)"    SPACE BLINDS "_ ;_ * \"-\"_)"    SPACE BLINDS "_ ;_ @_ " ), \
339     NUMFMT_STRING( INDEX + 1, "_ * #,##0_)"    SPACE SYMBOL "_ ;_ * (#,##0)"    SPACE SYMBOL "_ ;_ * \"-\"_)"    SPACE SYMBOL "_ ;_ @_ " ), \
340     NUMFMT_STRING( INDEX + 2, "_ * #,##0.00_)" SPACE BLINDS "_ ;_ * (#,##0.00)" SPACE BLINDS "_ ;_ * \"-\"?\?_)" SPACE BLINDS "_ ;_ @_ " ), \
341     NUMFMT_STRING( INDEX + 3, "_ * #,##0.00_)" SPACE SYMBOL "_ ;_ * (#,##0.00)" SPACE SYMBOL "_ ;_ * \"-\"?\?_)" SPACE SYMBOL "_ ;_ @_ " )
342 
343 /** Defines builtin currency formats 5...8 (with currency symbol), 37...40
344     (blind currency symbol), and 41...44 (accounting), in the following format:
345     "[opening parenthesis], number, symbol, [closing parenthesis].".
346     @param SYMBOL  Currency symbol.
347     @param BLINDS  Blind currency symbol.
348     @param SPACE  Space character(s) between number and currency symbol. */
349 #define NUMFMT_ALLCURRENCIES_OPEN_NUMBER_SYMBOL_CLOSE( SYMBOL, BLINDS, SPACE ) \
350     NUMFMT_CURRENCY_OPEN_NUMBER_SYMBOL_CLOSE( 5, SYMBOL, SPACE, "" ), \
351     NUMFMT_CURRENCY_OPEN_NUMBER_SYMBOL_CLOSE( 37, BLINDS, SPACE, "" ), \
352     NUMFMT_ACCOUNTING_OPEN_NUMBER_SYMBOL_CLOSE( 41, SYMBOL, BLINDS, SPACE )
353 
354 // currency unit characters
355 #define UTF8_BAHT           "\340\270\277"
356 #define UTF8_COLON          "\342\202\241"
357 #define UTF8_CURR_AR_AE     "\330\257.\330\245."
358 #define UTF8_CURR_AR_BH     "\330\257.\330\250."
359 #define UTF8_CURR_AR_DZ     "\330\257.\330\254."
360 #define UTF8_CURR_AR_EG     "\330\254.\331\205."
361 #define UTF8_CURR_AR_IQ     "\330\257.\330\271."
362 #define UTF8_CURR_AR_JO     "\330\257.\330\247."
363 #define UTF8_CURR_AR_KW     "\330\257.\331\203."
364 #define UTF8_CURR_AR_LB     "\331\204.\331\204."
365 #define UTF8_CURR_AR_LY     "\330\257.\331\204."
366 #define UTF8_CURR_AR_MA     "\330\257.\331\205."
367 #define UTF8_CURR_AR_OM     "\330\261.\330\271."
368 #define UTF8_CURR_AR_QA     "\330\261.\331\202."
369 #define UTF8_CURR_AR_SA     "\330\261.\330\263."
370 #define UTF8_CURR_AR_SY     "\331\204.\330\263."
371 #define UTF8_CURR_AR_TN     "\330\257.\330\252."
372 #define UTF8_CURR_AR_YE     "\330\261.\331\212."
373 #define UTF8_CURR_BN_IN     "\340\246\237\340\246\276"
374 #define UTF8_CURR_FA_IR     "\330\261\331\212\330\247\331\204"
375 #define UTF8_CURR_GU_IN     "\340\252\260\340\253\202"
376 #define UTF8_CURR_HI_IN     "\340\244\260\340\245\201"
377 #define UTF8_CURR_KN_IN     "\340\262\260\340\263\202"
378 #define UTF8_CURR_ML_IN     "\340\264\225"
379 #define UTF8_CURR_PA_IN     "\340\250\260\340\251\201"
380 #define UTF8_CURR_TA_IN     "\340\256\260\340\257\202"
381 #define UTF8_CURR_TE_IN     "\340\260\260\340\261\202"
382 #define UTF8_DONG           "\342\202\253"
383 #define UTF8_EURO           "\342\202\254"
384 #define UTF8_POUND_GB       "\302\243"
385 #define UTF8_RUFIYAA        "\336\203"
386 #define UTF8_SHEQEL         "\342\202\252"
387 #define UTF8_TUGRUG         "\342\202\256"
388 #define UTF8_WON            "\342\202\251"
389 #define UTF8_YEN_CN         "\357\277\245"
390 #define UTF8_YEN_JP         "\302\245"
391 
392 // Unicode characters for currency units
393 #define UTF8_CCARON_LC      "\304\215"
394 #define UTF8_LSTROKE_LC     "\305\202"
395 // Armenian
396 #define UTF8_HY_DA_LC       "\325\244"
397 #define UTF8_HY_REH_LC      "\326\200"
398 // Cyrillic
399 #define UTF8_CYR_G_LC       "\320\263"
400 #define UTF8_CYR_L_LC       "\320\273"
401 #define UTF8_CYR_M_LC       "\320\274"
402 #define UTF8_CYR_N_LC       "\320\275"
403 #define UTF8_CYR_O_LC       "\320\276"
404 #define UTF8_CYR_R_LC       "\321\200"
405 #define UTF8_CYR_S_LC       "\321\201"
406 #define UTF8_CYR_W_LC       "\320\262"
407 
408 // Japanese/Chinese date/time characters
409 #define UTF8_CJ_YEAR        "\345\271\264"
410 #define UTF8_CJ_MON         "\346\234\210"
411 #define UTF8_CJ_DAY         "\346\227\245"
412 #define UTF8_CJ_HOUR        "\346\231\202"
413 #define UTF8_CJ_MIN         "\345\210\206"
414 #define UTF8_CJ_SEC         "\347\247\222"
415 
416 // Chinese Simplified date/time characters
417 #define UTF8_CS_YEAR        "\345\271\264"
418 #define UTF8_CS_MON         "\346\234\210"
419 #define UTF8_CS_DAY         "\346\227\245"
420 #define UTF8_CS_HOUR        "\346\227\266"
421 #define UTF8_CS_MIN         "\345\210\206"
422 #define UTF8_CS_SEC         "\347\247\222"
423 
424 // Korean date/time characters
425 #define UTF8_KO_YEAR        "\353\205\204"
426 #define UTF8_KO_MON         "\354\233\224"
427 #define UTF8_KO_DAY         "\354\235\274"
428 #define UTF8_KO_HOUR        "\354\213\234"
429 #define UTF8_KO_MIN         "\353\266\204"
430 #define UTF8_KO_SEC         "\354\264\210"
431 
432 /** Default number format table. Last parent of all other tables, used for unknown locales. */
433 const BuiltinFormat spBuiltinFormats_BASE[] =
434 {
435     // 0..13 numeric and currency formats
436     NUMFMT_PREDEF(   0, NUMBER_STANDARD ),          // General
437     NUMFMT_PREDEF(   1, NUMBER_INT ),               // 0
438     NUMFMT_PREDEF(   2, NUMBER_DEC2 ),              // 0.00
439     NUMFMT_PREDEF(   3, NUMBER_1000INT ),           // #,##0
440     NUMFMT_PREDEF(   4, NUMBER_1000DEC2 ),          // #,##0.00
441     NUMFMT_PREDEF(   5, CURRENCY_1000INT ),         // #,##0[symbol]
442     NUMFMT_PREDEF(   6, CURRENCY_1000INT_RED ),     // #,##0[symbol];[RED]-#,##0[symbol]
443     NUMFMT_PREDEF(   7, CURRENCY_1000DEC2 ),        // #,##0.00[symbol]
444     NUMFMT_PREDEF(   8, CURRENCY_1000DEC2_RED ),    // #,##0.00[symbol];[RED]-#,##0.00[symbol]
445     NUMFMT_PREDEF(   9, PERCENT_INT ),              // 0%
446     NUMFMT_PREDEF(  10, PERCENT_DEC2 ),             // 0.00%
447     NUMFMT_PREDEF(  11, SCIENTIFIC_000E00 ),        // 0.00E+00
448     NUMFMT_PREDEF(  12, FRACTION_1 ),               // # ?/?
449     NUMFMT_PREDEF(  13, FRACTION_2 ),               // # ??/??
450 
451     // 14...22 date and time formats
452     NUMFMT_PREDEF(  14, DATE_SYS_DDMMYYYY ),
453     NUMFMT_PREDEF(  15, DATE_SYS_DMMMYY ),
454     NUMFMT_PREDEF(  16, DATE_SYS_DDMMM ),
455     NUMFMT_PREDEF(  17, DATE_SYS_MMYY ),
456     NUMFMT_PREDEF(  18, TIME_HHMMAMPM ),
457     NUMFMT_PREDEF(  19, TIME_HHMMSSAMPM ),
458     NUMFMT_PREDEF(  20, TIME_HHMM ),
459     NUMFMT_PREDEF(  21, TIME_HHMMSS ),
460     NUMFMT_PREDEF(  22, DATETIME_SYSTEM_SHORT_HHMM ),
461 
462     // 23...36 international formats
463     NUMFMT_REUSE(   23, 0 ),
464     NUMFMT_REUSE(   24, 0 ),
465     NUMFMT_REUSE(   25, 0 ),
466     NUMFMT_REUSE(   26, 0 ),
467     NUMFMT_REUSE(   27, 14 ),
468     NUMFMT_REUSE(   28, 14 ),
469     NUMFMT_REUSE(   29, 14 ),
470     NUMFMT_REUSE(   30, 14 ),
471     NUMFMT_REUSE(   31, 14 ),
472     NUMFMT_REUSE(   32, 21 ),
473     NUMFMT_REUSE(   33, 21 ),
474     NUMFMT_REUSE(   34, 21 ),
475     NUMFMT_REUSE(   35, 21 ),
476     NUMFMT_REUSE(   36, 14 ),
477 
478     // 37...44 accounting formats, defaults without currency symbol here
479     NUMFMT_CURRENCY_MINUS_SYMBOL_NUMBER( 37, "", "", "" ),
480     NUMFMT_ACCOUNTING_MINUS_SYMBOL_NUMBER( 41, "", "" ),
481 
482     // 45...49 more special formats
483     NUMFMT_STRING(  45, "mm:ss" ),
484     NUMFMT_STRING(  46, "[h]:mm:ss" ),
485     NUMFMT_STRING(  47, "mm:ss.0" ),
486     NUMFMT_STRING(  48, "##0.0E+0" ),
487     NUMFMT_PREDEF(  49, TEXT ),
488 
489     // 50...81 international formats
490     NUMFMT_REUSE(   50, 14 ),
491     NUMFMT_REUSE(   51, 14 ),
492     NUMFMT_REUSE(   52, 14 ),
493     NUMFMT_REUSE(   53, 14 ),
494     NUMFMT_REUSE(   54, 14 ),
495     NUMFMT_REUSE(   55, 14 ),
496     NUMFMT_REUSE(   56, 14 ),
497     NUMFMT_REUSE(   57, 14 ),
498     NUMFMT_REUSE(   58, 14 ),
499     NUMFMT_REUSE(   59, 1 ),
500     NUMFMT_REUSE(   60, 2 ),
501     NUMFMT_REUSE(   61, 3 ),
502     NUMFMT_REUSE(   62, 4 ),
503     NUMFMT_REUSE(   63, 5 ),
504     NUMFMT_REUSE(   64, 6 ),
505     NUMFMT_REUSE(   65, 7 ),
506     NUMFMT_REUSE(   66, 8 ),
507     NUMFMT_REUSE(   67, 9 ),
508     NUMFMT_REUSE(   68, 10 ),
509     NUMFMT_REUSE(   69, 12 ),
510     NUMFMT_REUSE(   70, 13 ),
511     NUMFMT_REUSE(   71, 14 ),
512     NUMFMT_REUSE(   72, 14 ),
513     NUMFMT_REUSE(   73, 15 ),
514     NUMFMT_REUSE(   74, 16 ),
515     NUMFMT_REUSE(   75, 17 ),
516     NUMFMT_REUSE(   76, 20 ),
517     NUMFMT_REUSE(   77, 21 ),
518     NUMFMT_REUSE(   78, 22 ),
519     NUMFMT_REUSE(   79, 45 ),
520     NUMFMT_REUSE(   80, 46 ),
521     NUMFMT_REUSE(   81, 47 ),
522 
523     // 82...163 not used, must not occur in a file (Excel may crash)
524 
525     NUMFMT_ENDTABLE()
526 };
527 
528 /** Arabic, U.A.E. */
529 const BuiltinFormat spBuiltinFormats_ar_AE[] =
530 {
531     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
532     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_AE "\"", " " ),
533     NUMFMT_ENDTABLE()
534 };
535 
536 /** Arabic, Bahrain. */
537 const BuiltinFormat spBuiltinFormats_ar_BH[] =
538 {
539     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
540     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_BH "\"", " " ),
541     NUMFMT_ENDTABLE()
542 };
543 
544 /** Arabic, Algeria. */
545 const BuiltinFormat spBuiltinFormats_ar_DZ[] =
546 {
547     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
548     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_DZ "\"", " " ),
549     NUMFMT_ENDTABLE()
550 };
551 
552 /** Arabic, Egypt. */
553 const BuiltinFormat spBuiltinFormats_ar_EG[] =
554 {
555     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
556     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_EG "\"", " " ),
557     NUMFMT_ENDTABLE()
558 };
559 
560 /** Arabic, Iraq. */
561 const BuiltinFormat spBuiltinFormats_ar_IQ[] =
562 {
563     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
564     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_IQ "\"", " " ),
565     NUMFMT_ENDTABLE()
566 };
567 
568 /** Arabic, Jordan. */
569 const BuiltinFormat spBuiltinFormats_ar_JO[] =
570 {
571     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
572     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_JO "\"", " " ),
573     NUMFMT_ENDTABLE()
574 };
575 
576 /** Arabic, Kuwait. */
577 const BuiltinFormat spBuiltinFormats_ar_KW[] =
578 {
579     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
580     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_KW "\"", " " ),
581     NUMFMT_ENDTABLE()
582 };
583 
584 /** Arabic, Lebanon. */
585 const BuiltinFormat spBuiltinFormats_ar_LB[] =
586 {
587     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
588     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_LB "\"", " " ),
589     NUMFMT_ENDTABLE()
590 };
591 
592 /** Arabic, Libya. */
593 const BuiltinFormat spBuiltinFormats_ar_LY[] =
594 {
595     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
596     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_LY "\"", " " ),
597     NUMFMT_ENDTABLE()
598 };
599 
600 /** Arabic, Morocco. */
601 const BuiltinFormat spBuiltinFormats_ar_MA[] =
602 {
603     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
604     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_MA "\"", " " ),
605     NUMFMT_ENDTABLE()
606 };
607 
608 /** Arabic, Oman. */
609 const BuiltinFormat spBuiltinFormats_ar_OM[] =
610 {
611     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
612     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_OM "\"", " " ),
613     NUMFMT_ENDTABLE()
614 };
615 
616 /** Arabic, Qatar. */
617 const BuiltinFormat spBuiltinFormats_ar_QA[] =
618 {
619     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
620     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_QA "\"", " " ),
621     NUMFMT_ENDTABLE()
622 };
623 
624 /** Arabic, Saudi Arabia. */
625 const BuiltinFormat spBuiltinFormats_ar_SA[] =
626 {
627     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
628     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_SA "\"", " " ),
629     NUMFMT_ENDTABLE()
630 };
631 
632 /** Arabic, Syria. */
633 const BuiltinFormat spBuiltinFormats_ar_SY[] =
634 {
635     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
636     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_SY "\"", " " ),
637     NUMFMT_ENDTABLE()
638 };
639 
640 /** Arabic, Tunisia. */
641 const BuiltinFormat spBuiltinFormats_ar_TN[] =
642 {
643     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
644     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_TN "\"", " " ),
645     NUMFMT_ENDTABLE()
646 };
647 
648 /** Arabic, Yemen. */
649 const BuiltinFormat spBuiltinFormats_ar_YE[] =
650 {
651     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
652     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_AR_YE "\"", " " ),
653     NUMFMT_ENDTABLE()
654 };
655 
656 /** Belarusian, Belarus. */
657 const BuiltinFormat spBuiltinFormats_be_BY[] =
658 {
659     // space character is group separator, literal spaces must be quoted
660     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
661     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_R_LC ".\"", "_" UTF8_CYR_R_LC "_.", "\\ " ),
662     NUMFMT_ENDTABLE()
663 };
664 
665 /** Bulgarian, Bulgaria. */
666 const BuiltinFormat spBuiltinFormats_bg_BG[] =
667 {
668     // space character is group separator, literal spaces must be quoted
669     NUMFMT_ALLDATETIMES( "DD.M.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
670     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_L_LC UTF8_CYR_W_LC "\"", "_" UTF8_CYR_L_LC "_" UTF8_CYR_W_LC, "\\ " ),
671     NUMFMT_ENDTABLE()
672 };
673 
674 /** Bengali, India. */
675 const BuiltinFormat spBuiltinFormats_bn_IN[] =
676 {
677     NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
678     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_BN_IN "\"", " " ),
679     NUMFMT_ENDTABLE()
680 };
681 
682 /** Czech, Czech Republic. */
683 const BuiltinFormat spBuiltinFormats_cs_CZ[] =
684 {
685     // space character is group separator, literal spaces must be quoted
686     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
687     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"K" UTF8_CCARON_LC "\"", "_K_" UTF8_CCARON_LC, "\\ " ),
688     NUMFMT_ENDTABLE()
689 };
690 
691 /** Danish, Denmark. */
692 const BuiltinFormat spBuiltinFormats_da_DK[] =
693 {
694     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
695     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"kr\"", " " ),
696     NUMFMT_ENDTABLE()
697 };
698 
699 /** German, Austria. */
700 const BuiltinFormat spBuiltinFormats_de_AT[] =
701 {
702     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
703     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_EURO, " " ),
704     NUMFMT_ENDTABLE()
705 };
706 
707 /** German, Switzerland. */
708 const BuiltinFormat spBuiltinFormats_de_CH[] =
709 {
710     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ". ", "MMM", " ", "YY", "h", "hh" ),
711     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"SFr.\"", " " ),
712     NUMFMT_ENDTABLE()
713 };
714 
715 /** German, Germany. */
716 const BuiltinFormat spBuiltinFormats_de_DE[] =
717 {
718     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ". ", "MMM", " ", "YY", "h", "hh" ),
719     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
720     NUMFMT_ENDTABLE()
721 };
722 
723 /** German, Liechtenstein. */
724 const BuiltinFormat spBuiltinFormats_de_LI[] =
725 {
726     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ". ", "MMM", " ", "YY", "h", "hh" ),
727     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"CHF\"", " " ),
728     NUMFMT_ENDTABLE()
729 };
730 
731 /** German, Luxembourg. */
732 const BuiltinFormat spBuiltinFormats_de_LU[] =
733 {
734     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
735     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
736     NUMFMT_ENDTABLE()
737 };
738 
739 /** Divehi, Maldives. */
740 const BuiltinFormat spBuiltinFormats_div_MV[] =
741 {
742     NUMFMT_ALLDATETIMES( "DD/MM/YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
743     NUMFMT_ALLCURRENCIES_NUMBER_SYMBOL_MINUS( "\"" UTF8_RUFIYAA ".\"", "_" UTF8_RUFIYAA "_.", " " ),
744     NUMFMT_ENDTABLE()
745 };
746 
747 /** Greek, Greece. */
748 const BuiltinFormat spBuiltinFormats_el_GR[] =
749 {
750     NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
751     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
752     NUMFMT_ENDTABLE()
753 };
754 
755 /** English, Australia. */
756 const BuiltinFormat spBuiltinFormats_en_AU[] =
757 {
758     NUMFMT_ALLDATETIMES( "D/MM/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
759     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
760     NUMFMT_ENDTABLE()
761 };
762 
763 /** English, Belize. */
764 const BuiltinFormat spBuiltinFormats_en_BZ[] =
765 {
766     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
767     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"BZ$\"", "" ),
768     NUMFMT_ENDTABLE()
769 };
770 
771 /** English, Canada. */
772 const BuiltinFormat spBuiltinFormats_en_CA[] =
773 {
774     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
775     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
776     NUMFMT_ENDTABLE()
777 };
778 
779 /** English, Caribbean. */
780 const BuiltinFormat spBuiltinFormats_en_CB[] =
781 {
782     NUMFMT_ALLDATETIMES( "MM/DD/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
783     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
784     NUMFMT_ENDTABLE()
785 };
786 
787 /** English, United Kingdom. */
788 const BuiltinFormat spBuiltinFormats_en_GB[] =
789 {
790     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
791     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_POUND_GB, "" ),
792     NUMFMT_ENDTABLE()
793 };
794 
795 /** English, Ireland. */
796 const BuiltinFormat spBuiltinFormats_en_IE[] =
797 {
798     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
799     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_EURO, "" ),
800     NUMFMT_ENDTABLE()
801 };
802 
803 /** English, Jamaica. */
804 const BuiltinFormat spBuiltinFormats_en_JM[] =
805 {
806     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
807     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "\"J$\"", "" ),
808     NUMFMT_ENDTABLE()
809 };
810 
811 /** English, New Zealand. */
812 const BuiltinFormat spBuiltinFormats_en_NZ[] =
813 {
814     NUMFMT_ALLDATETIMES( "D/MM/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
815     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
816     NUMFMT_ENDTABLE()
817 };
818 
819 /** English, Philippines. */
820 const BuiltinFormat spBuiltinFormats_en_PH[] =
821 {
822     NUMFMT_ALLDATETIMES( "M/D/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
823     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"Php\"", "" ),
824     NUMFMT_ENDTABLE()
825 };
826 
827 /** English, Trinidad and Tobago. */
828 const BuiltinFormat spBuiltinFormats_en_TT[] =
829 {
830     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
831     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"TT$\"", "" ),
832     NUMFMT_ENDTABLE()
833 };
834 
835 /** English, USA. */
836 const BuiltinFormat spBuiltinFormats_en_US[] =
837 {
838     NUMFMT_ALLDATETIMES( "M/D/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
839     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", "" ),
840     NUMFMT_ENDTABLE()
841 };
842 
843 /** English, South Africa. */
844 const BuiltinFormat spBuiltinFormats_en_ZA[] =
845 {
846     NUMFMT_ALLDATETIMES( "YYYY/MM/DD", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
847     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\\R", " " ),
848     NUMFMT_ENDTABLE()
849 };
850 
851 /** English, Zimbabwe. */
852 const BuiltinFormat spBuiltinFormats_en_ZW[] =
853 {
854     NUMFMT_ALLDATETIMES( "M/D/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
855     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"Z$\"", "" ),
856     NUMFMT_ENDTABLE()
857 };
858 
859 /** Spanish, Argentina. */
860 const BuiltinFormat spBuiltinFormats_es_AR[] =
861 {
862     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
863     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "$", " " ),
864     NUMFMT_ENDTABLE()
865 };
866 
867 /** Spanish, Bolivia. */
868 const BuiltinFormat spBuiltinFormats_es_BO[] =
869 {
870     // slashes must be quoted to prevent conversion to minus
871     NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
872     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"$b\"", " " ),
873     NUMFMT_ENDTABLE()
874 };
875 
876 /** Spanish, Chile. */
877 const BuiltinFormat spBuiltinFormats_es_CL[] =
878 {
879     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
880     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", " " ),
881     NUMFMT_ENDTABLE()
882 };
883 
884 /** Spanish, Colombia. */
885 const BuiltinFormat spBuiltinFormats_es_CO[] =
886 {
887     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
888     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", " " ),
889     NUMFMT_ENDTABLE()
890 };
891 
892 /** Spanish, Costa Rica. */
893 const BuiltinFormat spBuiltinFormats_es_CR[] =
894 {
895     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
896     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( UTF8_COLON, "" ),
897     NUMFMT_ENDTABLE()
898 };
899 
900 /** Spanish, Dominican Republic. */
901 const BuiltinFormat spBuiltinFormats_es_DO[] =
902 {
903     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
904     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"RD$\"", "" ),
905     NUMFMT_ENDTABLE()
906 };
907 
908 /** Spanish, Ecuador. */
909 const BuiltinFormat spBuiltinFormats_es_EC[] =
910 {
911     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
912     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", " " ),
913     NUMFMT_ENDTABLE()
914 };
915 
916 /** Spanish, Spain. */
917 const BuiltinFormat spBuiltinFormats_es_ES[] =
918 {
919     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
920     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
921     NUMFMT_ENDTABLE()
922 };
923 
924 /** Spanish, Guatemala. */
925 const BuiltinFormat spBuiltinFormats_es_GT[] =
926 {
927     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
928     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\\Q", "" ),
929     NUMFMT_ENDTABLE()
930 };
931 
932 /** Spanish, Honduras. */
933 const BuiltinFormat spBuiltinFormats_es_HN[] =
934 {
935     // slashes must be quoted to prevent conversion to minus
936     NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
937     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"L.\"", " " ),
938     NUMFMT_ENDTABLE()
939 };
940 
941 /** Spanish, Mexico. */
942 const BuiltinFormat spBuiltinFormats_es_MX[] =
943 {
944     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
945     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
946     NUMFMT_ENDTABLE()
947 };
948 
949 /** Spanish, Nicaragua. */
950 const BuiltinFormat spBuiltinFormats_es_NI[] =
951 {
952     // slashes must be quoted to prevent conversion to minus
953     NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
954     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"C$\"", " " ),
955     NUMFMT_ENDTABLE()
956 };
957 
958 /** Spanish, Panama. */
959 const BuiltinFormat spBuiltinFormats_es_PA[] =
960 {
961     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
962     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"B/.\"", " " ),
963     NUMFMT_ENDTABLE()
964 };
965 
966 /** Spanish, Peru. */
967 const BuiltinFormat spBuiltinFormats_es_PE[] =
968 {
969     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
970     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"S/.\"", " " ),
971     NUMFMT_ENDTABLE()
972 };
973 
974 /** Spanish, Puerto Rico. */
975 const BuiltinFormat spBuiltinFormats_es_PR[] =
976 {
977     // slashes must be quoted to prevent conversion to minus
978     NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
979     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", " " ),
980     NUMFMT_ENDTABLE()
981 };
982 
983 /** Spanish, Paraguay. */
984 const BuiltinFormat spBuiltinFormats_es_PY[] =
985 {
986     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
987     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"Gs\"", " " ),
988     NUMFMT_ENDTABLE()
989 };
990 
991 /** Spanish, El Salvador. */
992 const BuiltinFormat spBuiltinFormats_es_SV[] =
993 {
994     // slashes must be quoted to prevent conversion to minus
995     NUMFMT_ALLDATETIMES( "DD\\/MM\\/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
996     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", "" ),
997     NUMFMT_ENDTABLE()
998 };
999 
1000 /** Spanish, Uruguay. */
1001 const BuiltinFormat spBuiltinFormats_es_UY[] =
1002 {
1003     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
1004     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"$U\"", " " ),
1005     NUMFMT_ENDTABLE()
1006 };
1007 
1008 /** Spanish, Venezuela. */
1009 const BuiltinFormat spBuiltinFormats_es_VE[] =
1010 {
1011     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
1012     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "Bs", " " ),
1013     NUMFMT_ENDTABLE()
1014 };
1015 
1016 /** Estonian, Estonia. */
1017 const BuiltinFormat spBuiltinFormats_et_EE[] =
1018 {
1019     // space character is group separator, literal spaces must be quoted
1020     NUMFMT_ALLDATETIMES( "D.MM.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
1021     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"kr\"", "_k_r", "\\ " ),
1022     NUMFMT_ENDTABLE()
1023 };
1024 
1025 /** Farsi, Iran. */
1026 const BuiltinFormat spBuiltinFormats_fa_IR[] =
1027 {
1028     NUMFMT_ALLDATETIMES( "YYYY/MM/DD", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
1029     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"" UTF8_CURR_FA_IR "\"", " " ),
1030     NUMFMT_ENDTABLE()
1031 };
1032 
1033 /** Finnish, Finland. */
1034 const BuiltinFormat spBuiltinFormats_fi_FI[] =
1035 {
1036     // space character is group separator, literal spaces must be quoted
1037     NUMFMT_STRING(  9, "0\\ %" ),
1038     NUMFMT_STRING( 10, "0.00\\ %" ),
1039     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
1040     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
1041     NUMFMT_ENDTABLE()
1042 };
1043 
1044 /** Faroese, Faroe Islands. */
1045 const BuiltinFormat spBuiltinFormats_fo_FO[] =
1046 {
1047     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1048     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"kr\"", " " ),
1049     NUMFMT_ENDTABLE()
1050 };
1051 
1052 /** French, Belgium. */
1053 const BuiltinFormat spBuiltinFormats_fr_BE[] =
1054 {
1055     NUMFMT_ALLDATETIMES( "D/MM/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
1056     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
1057     NUMFMT_ENDTABLE()
1058 };
1059 
1060 /** French, Canada. */
1061 const BuiltinFormat spBuiltinFormats_fr_CA[] =
1062 {
1063     // space character is group separator, literal spaces must be quoted
1064     NUMFMT_ALLDATETIMES( "YYYY-MM-DD", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1065     NUMFMT_ALLCURRENCIES_OPEN_NUMBER_SYMBOL_CLOSE( "$", "_$", "\\ " ),
1066     NUMFMT_ENDTABLE()
1067 };
1068 
1069 /** French, Switzerland. */
1070 const BuiltinFormat spBuiltinFormats_fr_CH[] =
1071 {
1072     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
1073     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"SFr.\"", " " ),
1074     NUMFMT_ENDTABLE()
1075 };
1076 
1077 /** French, France. */
1078 const BuiltinFormat spBuiltinFormats_fr_FR[] =
1079 {
1080     // space character is group separator, literal spaces must be quoted
1081     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1082     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
1083     NUMFMT_ENDTABLE()
1084 };
1085 
1086 /** French, Luxembourg. */
1087 const BuiltinFormat spBuiltinFormats_fr_LU[] =
1088 {
1089     // space character is group separator, literal spaces must be quoted
1090     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1091     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
1092     NUMFMT_ENDTABLE()
1093 };
1094 
1095 /** French, Monaco. */
1096 const BuiltinFormat spBuiltinFormats_fr_MC[] =
1097 {
1098     // space character is group separator, literal spaces must be quoted
1099     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1100     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
1101     NUMFMT_ENDTABLE()
1102 };
1103 
1104 /** Galizian, Spain. */
1105 const BuiltinFormat spBuiltinFormats_gl_ES[] =
1106 {
1107     NUMFMT_ALLDATETIMES( "DD/MM/YY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1108     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_EURO, " " ),
1109     NUMFMT_ENDTABLE()
1110 };
1111 
1112 /** Gujarati, India. */
1113 const BuiltinFormat spBuiltinFormats_gu_IN[] =
1114 {
1115     NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1116     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_GU_IN "\"", " " ),
1117     NUMFMT_ENDTABLE()
1118 };
1119 
1120 /** Hebrew, Israel. */
1121 const BuiltinFormat spBuiltinFormats_he_IL[] =
1122 {
1123     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1124     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( UTF8_SHEQEL, " " ),
1125     NUMFMT_ENDTABLE()
1126 };
1127 
1128 /** Hindi, India. */
1129 const BuiltinFormat spBuiltinFormats_hi_IN[] =
1130 {
1131     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1132     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_HI_IN "\"", " " ),
1133     NUMFMT_ENDTABLE()
1134 };
1135 
1136 /** Croatian, Bosnia and Herzegowina. */
1137 const BuiltinFormat spBuiltinFormats_hr_BA[] =
1138 {
1139     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
1140     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"KM\"", "_K_M", " " ),
1141     NUMFMT_ENDTABLE()
1142 };
1143 
1144 /** Croatian, Croatia. */
1145 const BuiltinFormat spBuiltinFormats_hr_HR[] =
1146 {
1147     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
1148     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"kn\"", "_k_n", " " ),
1149     NUMFMT_ENDTABLE()
1150 };
1151 
1152 /** Hungarian, Hungary. */
1153 const BuiltinFormat spBuiltinFormats_hu_HU[] =
1154 {
1155     // space character is group separator, literal spaces must be quoted
1156     // MMM is rendered differently in Calc and Excel (see #i41488#)
1157     NUMFMT_ALLDATETIMES( "YYYY.MM.DD", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1158     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"Ft\"", "_F_t", "\\ " ),
1159     NUMFMT_ENDTABLE()
1160 };
1161 
1162 /** Armenian, Armenia. */
1163 const BuiltinFormat spBuiltinFormats_hy_AM[] =
1164 {
1165     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1166     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_HY_DA_LC UTF8_HY_REH_LC ".\"", "_" UTF8_HY_DA_LC "_" UTF8_HY_REH_LC "_.", " " ),
1167     NUMFMT_ENDTABLE()
1168 };
1169 
1170 /** Indonesian, Indonesia. */
1171 const BuiltinFormat spBuiltinFormats_id_ID[] =
1172 {
1173     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1174     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"Rp\"", "" ),
1175     NUMFMT_ENDTABLE()
1176 };
1177 
1178 /** Icelandic, Iceland. */
1179 const BuiltinFormat spBuiltinFormats_is_IS[] =
1180 {
1181     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "hh" ),
1182     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"kr.\"", "_k_r_.", " " ),
1183     NUMFMT_ENDTABLE()
1184 };
1185 
1186 /** Italian, Switzerland. */
1187 const BuiltinFormat spBuiltinFormats_it_CH[] =
1188 {
1189     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
1190     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"SFr.\"", " " ),
1191     NUMFMT_ENDTABLE()
1192 };
1193 
1194 /** Italian, Italy. */
1195 const BuiltinFormat spBuiltinFormats_it_IT[] =
1196 {
1197     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1198     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_EURO, " " ),
1199     NUMFMT_ENDTABLE()
1200 };
1201 
1202 /** Georgian, Georgia. */
1203 const BuiltinFormat spBuiltinFormats_ka_GE[] =
1204 {
1205     // space character is group separator, literal spaces must be quoted
1206     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1207     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"Lari\"", "_L_a_r_i", "\\ " ),
1208     NUMFMT_ENDTABLE()
1209 };
1210 
1211 /** Kazakh, Kazakhstan. */
1212 const BuiltinFormat spBuiltinFormats_kk_KZ[] =
1213 {
1214     // space character is group separator, literal spaces must be quoted
1215     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1216     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "\\T", "" ),
1217     NUMFMT_ENDTABLE()
1218 };
1219 
1220 /** Kannada, India. */
1221 const BuiltinFormat spBuiltinFormats_kn_IN[] =
1222 {
1223     NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1224     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_KN_IN "\"", " " ),
1225     NUMFMT_ENDTABLE()
1226 };
1227 
1228 /** Kyrgyz, Kyrgyzstan. */
1229 const BuiltinFormat spBuiltinFormats_ky_KG[] =
1230 {
1231     // space character is group separator, literal spaces must be quoted
1232     NUMFMT_ALLDATETIMES( "DD.MM.YY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1233     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_S_LC UTF8_CYR_O_LC UTF8_CYR_M_LC "\"", "_" UTF8_CYR_S_LC "_" UTF8_CYR_O_LC "_" UTF8_CYR_M_LC, "\\ " ),
1234     NUMFMT_ENDTABLE()
1235 };
1236 
1237 /** Lithuanian, Lithuania. */
1238 const BuiltinFormat spBuiltinFormats_lt_LT[] =
1239 {
1240     NUMFMT_ALLDATETIMES( "YYYY.MM.DD", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
1241     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"Lt\"", "_L_t", " " ),
1242     NUMFMT_ENDTABLE()
1243 };
1244 
1245 /** Latvian, Latvia. */
1246 const BuiltinFormat spBuiltinFormats_lv_LV[] =
1247 {
1248     // space character is group separator, literal spaces must be quoted
1249     NUMFMT_ALLDATETIMES( "YYYY.MM.DD", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1250     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "\"Ls\"", "\\ " ),
1251     NUMFMT_ENDTABLE()
1252 };
1253 
1254 /** Malayalam, India. */
1255 const BuiltinFormat spBuiltinFormats_ml_IN[] =
1256 {
1257     NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1258     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_ML_IN "\"", " " ),
1259     NUMFMT_ENDTABLE()
1260 };
1261 
1262 /** Mongolian, Mongolia. */
1263 const BuiltinFormat spBuiltinFormats_mn_MN[] =
1264 {
1265     NUMFMT_ALLDATETIMES( "YY.MM.DD", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1266     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_TUGRUG, "_" UTF8_TUGRUG, "" ),
1267     NUMFMT_ENDTABLE()
1268 };
1269 
1270 /** Malay, Brunei Darussalam. */
1271 const BuiltinFormat spBuiltinFormats_ms_BN[] =
1272 {
1273     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1274     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", "" ),
1275     NUMFMT_ENDTABLE()
1276 };
1277 
1278 /** Malay, Malaysia. */
1279 const BuiltinFormat spBuiltinFormats_ms_MY[] =
1280 {
1281     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1282     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\\R", "" ),
1283     NUMFMT_ENDTABLE()
1284 };
1285 
1286 /** Maltese, Malta. */
1287 const BuiltinFormat spBuiltinFormats_mt_MT[] =
1288 {
1289     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1290     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "\"Lm\"", "" ),
1291     NUMFMT_ENDTABLE()
1292 };
1293 
1294 /** Dutch, Belgium. */
1295 const BuiltinFormat spBuiltinFormats_nl_BE[] =
1296 {
1297     // slashes must be quoted to prevent conversion to minus
1298     NUMFMT_ALLDATETIMES( "D\\/MM\\/YYYY", "D", "\\/", "MMM", "\\/", "YY", "h", "h" ),
1299     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
1300     NUMFMT_ENDTABLE()
1301 };
1302 
1303 /** Dutch, Netherlands. */
1304 const BuiltinFormat spBuiltinFormats_nl_NL[] =
1305 {
1306     NUMFMT_ALLDATETIMES( "D-M-YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
1307     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( UTF8_EURO, " " ),
1308     NUMFMT_ENDTABLE()
1309 };
1310 
1311 /** Norwegian (Bokmal and Nynorsk), Norway. */
1312 const BuiltinFormat spBuiltinFormats_no_NO[] =
1313 {
1314     // space character is group separator, literal spaces must be quoted
1315     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
1316     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"kr\"", "\\ " ),
1317     NUMFMT_ENDTABLE()
1318 };
1319 
1320 /** Punjabi, India. */
1321 const BuiltinFormat spBuiltinFormats_pa_IN[] =
1322 {
1323     NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "hh", "hh" ),
1324     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_PA_IN "\"", " " ),
1325     NUMFMT_ENDTABLE()
1326 };
1327 
1328 /** Polish, Poland. */
1329 const BuiltinFormat spBuiltinFormats_pl_PL[] =
1330 {
1331     // space character is group separator, literal spaces must be quoted
1332     // MMM is rendered differently in Calc and Excel (see #i72300#)
1333     NUMFMT_ALLDATETIMES( "YYYY-MM-DD", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1334     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"z" UTF8_LSTROKE_LC "\"", "_z_" UTF8_LSTROKE_LC, "\\ " ),
1335     NUMFMT_ENDTABLE()
1336 };
1337 
1338 /** Portuguese, Brazil. */
1339 const BuiltinFormat spBuiltinFormats_pt_BR[] =
1340 {
1341     NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "/", "MMM", "/", "YY", "h", "hh" ),
1342     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"R$\"", " " ),
1343     NUMFMT_ENDTABLE()
1344 };
1345 
1346 /** Portuguese, Portugal. */
1347 const BuiltinFormat spBuiltinFormats_pt_PT[] =
1348 {
1349     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1350     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, " " ),
1351     NUMFMT_ENDTABLE()
1352 };
1353 
1354 /** Romanian, Romania. */
1355 const BuiltinFormat spBuiltinFormats_ro_RO[] =
1356 {
1357     // space character is group separator, literal spaces must be quoted (but see #i75367#)
1358     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
1359     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"lei\"", "_l_e_i", "\\ " ),
1360     NUMFMT_ENDTABLE()
1361 };
1362 
1363 /** Russian, Russian Federation. */
1364 const BuiltinFormat spBuiltinFormats_ru_RU[] =
1365 {
1366     // space character is group separator, literal spaces must be quoted
1367     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1368     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_R_LC ".\"", "_" UTF8_CYR_R_LC "_.", "" ),
1369     NUMFMT_ENDTABLE()
1370 };
1371 
1372 /** Slovak, Slovakia. */
1373 const BuiltinFormat spBuiltinFormats_sk_SK[] =
1374 {
1375     // space character is group separator, literal spaces must be quoted
1376     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
1377     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"Sk\"", "_S_k", "\\ " ),
1378     NUMFMT_ENDTABLE()
1379 };
1380 
1381 /** Slovenian, Slovenia. */
1382 const BuiltinFormat spBuiltinFormats_sl_SI[] =
1383 {
1384     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "h" ),
1385     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"SIT\"", "_S_I_T", " " ),
1386     NUMFMT_ENDTABLE()
1387 };
1388 
1389 /** Swedish, Finland. */
1390 const BuiltinFormat spBuiltinFormats_sv_FI[] =
1391 {
1392     // space character is group separator, literal spaces must be quoted
1393     NUMFMT_STRING(  9, "0\\ %" ),
1394     NUMFMT_STRING( 10, "0.00\\ %" ),
1395     NUMFMT_ALLDATETIMES( "D.M.YYYY", "D", ".", "MMM", ".", "YY", "h", "hh" ),
1396     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_EURO, "_" UTF8_EURO, "\\ " ),
1397     NUMFMT_ENDTABLE()
1398 };
1399 
1400 /** Swedish, Sweden. */
1401 const BuiltinFormat spBuiltinFormats_sv_SE[] =
1402 {
1403     // space character is group separator, literal spaces must be quoted
1404     NUMFMT_ALLDATETIMES( "YYYY-MM-DD", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1405     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"kr\"", "_k_r", "\\ " ),
1406     NUMFMT_ENDTABLE()
1407 };
1408 
1409 /** Swahili, Tanzania. */
1410 const BuiltinFormat spBuiltinFormats_sw_TZ[] =
1411 {
1412     NUMFMT_ALLDATETIMES( "M/D/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
1413     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\\S", "" ),
1414     NUMFMT_ENDTABLE()
1415 };
1416 
1417 /** Tamil, India. */
1418 const BuiltinFormat spBuiltinFormats_ta_IN[] =
1419 {
1420     NUMFMT_ALLDATETIMES( "DD-MM-YYYY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1421     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_TA_IN "\"", " " ),
1422     NUMFMT_ENDTABLE()
1423 };
1424 
1425 /** Telugu, India. */
1426 const BuiltinFormat spBuiltinFormats_te_IN[] =
1427 {
1428     NUMFMT_ALLDATETIMES( "DD-MM-YY", "DD", "-", "MMM", "-", "YY", "h", "hh" ),
1429     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( "\"" UTF8_CURR_TE_IN "\"", " " ),
1430     NUMFMT_ENDTABLE()
1431 };
1432 
1433 /** Thai, Thailand. */
1434 const BuiltinFormat spBuiltinFormats_th_TH[] =
1435 {
1436     NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
1437     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_BAHT, "" ),
1438     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 63, UTF8_BAHT, "", "t" ),
1439     NUMFMT_STRING( 59, "t0" ),
1440     NUMFMT_STRING( 60, "t0.00" ),
1441     NUMFMT_STRING( 61, "t#,##0" ),
1442     NUMFMT_STRING( 62, "t#,##0.00" ),
1443     NUMFMT_STRING( 67, "t0%" ),
1444     NUMFMT_STRING( 68, "t0.00%" ),
1445     NUMFMT_STRING( 69, "t# ?/?" ),
1446     NUMFMT_STRING( 70, "t# ?\?/?\?" ),
1447     NUMFMT_STRING( 71, "tD/M/EE" ),
1448     NUMFMT_STRING( 72, "tD-MMM-E" ),
1449     NUMFMT_STRING( 73, "tD-MMM" ),
1450     NUMFMT_STRING( 74, "tMMM-E" ),
1451     NUMFMT_STRING( 75, "th:mm" ),
1452     NUMFMT_STRING( 76, "th:mm:ss" ),
1453     NUMFMT_STRING( 77, "tD/M/EE h:mm" ),
1454     NUMFMT_STRING( 78, "tmm:ss" ),
1455     NUMFMT_STRING( 79, "t[h]:mm:ss" ),
1456     NUMFMT_STRING( 80, "tmm:ss.0" ),
1457     NUMFMT_STRING( 81, "D/M/E" ),
1458     NUMFMT_ENDTABLE()
1459 };
1460 
1461 /** Turkish, Turkey. */
1462 const BuiltinFormat spBuiltinFormats_tr_TR[] =
1463 {
1464     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "hh" ),
1465     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"TL\"", "_T_L", " " ),
1466     NUMFMT_ENDTABLE()
1467 };
1468 
1469 /** Tatar, Russian Federation. */
1470 const BuiltinFormat spBuiltinFormats_tt_RU[] =
1471 {
1472     // space character is group separator, literal spaces must be quoted
1473     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1474     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_R_LC ".\"", "_" UTF8_CYR_R_LC "_.", "\\ " ),
1475     NUMFMT_ENDTABLE()
1476 };
1477 
1478 /** Ukrainian, Ukraine. */
1479 const BuiltinFormat spBuiltinFormats_uk_UA[] =
1480 {
1481     // space character is group separator, literal spaces must be quoted
1482     NUMFMT_ALLDATETIMES( "DD.MM.YYYY", "DD", ".", "MMM", ".", "YY", "h", "h" ),
1483     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( "\"" UTF8_CYR_G_LC UTF8_CYR_R_LC UTF8_CYR_N_LC ".\"", "_" UTF8_CYR_G_LC "_" UTF8_CYR_R_LC "_" UTF8_CYR_N_LC "_.", "\\ " ),
1484     NUMFMT_ENDTABLE()
1485 };
1486 
1487 /** Urdu, Pakistan. */
1488 const BuiltinFormat spBuiltinFormats_ur_PK[] =
1489 {
1490     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1491     NUMFMT_ALLCURRENCIES_SYMBOL_NUMBER_MINUS( "\"Rs\"", "" ),
1492     NUMFMT_ENDTABLE()
1493 };
1494 
1495 /** Vietnamese, Viet Nam. */
1496 const BuiltinFormat spBuiltinFormats_vi_VN[] =
1497 {
1498     NUMFMT_ALLDATETIMES( "DD/MM/YYYY", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1499     NUMFMT_ALLCURRENCIES_MINUS_NUMBER_SYMBOL( UTF8_DONG, "_" UTF8_DONG, " " ),
1500     NUMFMT_ENDTABLE()
1501 };
1502 
1503 // CJK ------------------------------------------------------------------------
1504 
1505 /** Base table for CJK locales. */
1506 const BuiltinFormat spBuiltinFormats_CJK[] =
1507 {
1508     NUMFMT_REUSE( 29, 28 ),
1509     NUMFMT_REUSE( 36, 27 ),
1510     NUMFMT_REUSE( 50, 27 ),
1511     NUMFMT_REUSE( 51, 28 ),
1512     NUMFMT_REUSE( 52, 34 ),
1513     NUMFMT_REUSE( 53, 35 ),
1514     NUMFMT_REUSE( 54, 28 ),
1515     NUMFMT_REUSE( 55, 34 ),
1516     NUMFMT_REUSE( 56, 35 ),
1517     NUMFMT_REUSE( 57, 27 ),
1518     NUMFMT_REUSE( 58, 28 ),
1519     NUMFMT_ENDTABLE()
1520 };
1521 
1522 /** Japanese, Japan. */
1523 const BuiltinFormat spBuiltinFormats_ja_JP[] =
1524 {
1525     NUMFMT_ALLDATETIMES( "YYYY/MM/DD", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1526     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_YEN_JP, "" ),
1527     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "$", "", "" ),
1528     NUMFMT_STRING( 27, "[$-411]GE.MM.DD" ),
1529     NUMFMT_STRING( 28, "[$-411]GGGE\"" UTF8_CJ_YEAR "\"MM\"" UTF8_CJ_MON "\"DD\"" UTF8_CJ_DAY "\"" ),
1530     NUMFMT_STRING( 30, "MM/DD/YY" ),
1531     NUMFMT_STRING( 31, "YYYY\"" UTF8_CJ_YEAR "\"MM\"" UTF8_CJ_MON "\"DD\"" UTF8_CJ_DAY "\"" ),
1532     NUMFMT_TIME_CJK( 32, "h", UTF8_CJ_HOUR, UTF8_CJ_MIN, UTF8_CJ_SEC ),
1533     NUMFMT_STRING( 34, "YYYY\"" UTF8_CJ_YEAR "\"MM\"" UTF8_CJ_MON "\"" ),
1534     NUMFMT_STRING( 35, "MM\"" UTF8_CJ_MON "\"DD\"" UTF8_CJ_DAY "\"" ),
1535     NUMFMT_ENDTABLE()
1536 };
1537 
1538 /** Korean, South Korea. */
1539 const BuiltinFormat spBuiltinFormats_ko_KR[] =
1540 {
1541     NUMFMT_ALLDATETIMES( "YYYY-MM-DD", "DD", "-", "MMM", "-", "YY", "h", "h" ),
1542     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( UTF8_WON, "" ),
1543     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "$", "", "" ),
1544     NUMFMT_STRING( 27, "YYYY" UTF8_CJ_YEAR " MM" UTF8_CJ_MON " DD" UTF8_CJ_DAY ),
1545     NUMFMT_STRING( 28, "MM-DD" ),
1546     NUMFMT_STRING( 30, "MM-DD-YY" ),
1547     NUMFMT_STRING( 31, "YYYY" UTF8_KO_YEAR " MM" UTF8_KO_MON " DD" UTF8_KO_DAY ),
1548     NUMFMT_TIME_CJK( 32, "h", UTF8_KO_HOUR, UTF8_KO_MIN, UTF8_KO_SEC ),
1549     // slashes must be quoted to prevent conversion to minus
1550     NUMFMT_STRING( 34, "YYYY\\/MM\\/DD" ),
1551     NUMFMT_REUSE( 35, 14 ),
1552     NUMFMT_ENDTABLE()
1553 };
1554 
1555 /** Chinese, China. */
1556 const BuiltinFormat spBuiltinFormats_zh_CN[] =
1557 {
1558     NUMFMT_ALLDATETIMES( "YYYY-M-D", "D", "-", "MMM", "-", "YY", "h", "h" ),
1559     NUMFMT_ALLCURRENCIES_SYMBOL_MINUS_NUMBER( UTF8_YEN_CN, "" ),
1560     NUMFMT_ALLTIMES_CJK( "h", "h", UTF8_CS_HOUR, UTF8_CS_MIN, UTF8_CS_SEC ),
1561     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "$", "", "" ),
1562     NUMFMT_STRING( 27, "YYYY\"" UTF8_CS_YEAR "\"M\"" UTF8_CS_MON "\"" ),
1563     NUMFMT_STRING( 28, "M\"" UTF8_CS_MON "\"D\"" UTF8_CS_DAY "\"" ),
1564     NUMFMT_STRING( 30, "M-D-YY" ),
1565     NUMFMT_STRING( 31, "YYYY\"" UTF8_CS_YEAR "\"M\"" UTF8_CS_MON "\"D\"" UTF8_CS_DAY "\"" ),
1566     NUMFMT_REUSE( 52, 27 ),
1567     NUMFMT_REUSE( 53, 28 ),
1568     NUMFMT_ENDTABLE()
1569 };
1570 
1571 /** Chinese, Hong Kong. */
1572 const BuiltinFormat spBuiltinFormats_zh_HK[] =
1573 {
1574     NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
1575     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\"HK$\"", "" ),
1576     NUMFMT_ALLTIMES_CJK( "h", "h", UTF8_CJ_HOUR, UTF8_CJ_MIN, UTF8_CJ_SEC ),
1577     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "\"US$\"", "", "" ),
1578     NUMFMT_STRING( 27, "[$-404]D/M/E" ),
1579     NUMFMT_STRING( 28, "[$-404]D\"" UTF8_CJ_DAY "\"M\"" UTF8_CJ_MON "\"E\"" UTF8_CJ_YEAR "\"" ),
1580     NUMFMT_STRING( 30, "M/D/YY" ),
1581     NUMFMT_STRING( 31, "D\"" UTF8_CJ_DAY "\"M\"" UTF8_CJ_MON "\"YYYY\"" UTF8_CJ_YEAR "\"" ),
1582     NUMFMT_ENDTABLE()
1583 };
1584 
1585 /** Chinese, Macau. */
1586 const BuiltinFormat spBuiltinFormats_zh_MO[] =
1587 {
1588     NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
1589     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "\\P", "" ),
1590     NUMFMT_ALLTIMES_CJK( "h", "h", UTF8_CJ_HOUR, UTF8_CJ_MIN, UTF8_CJ_SEC ),
1591     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "\"US$\"", "", "" ),
1592     NUMFMT_STRING( 27, "[$-404]D/M/E" ),
1593     NUMFMT_STRING( 28, "[$-404]D\"" UTF8_CJ_DAY "\"M\"" UTF8_CJ_MON "\"E\"" UTF8_CJ_YEAR "\"" ),
1594     NUMFMT_STRING( 30, "M/D/YY" ),
1595     NUMFMT_STRING( 31, "D\"" UTF8_CJ_DAY "\"M\"" UTF8_CJ_MON "\"YYYY\"" UTF8_CJ_YEAR "\"" ),
1596     NUMFMT_ENDTABLE()
1597 };
1598 
1599 /** Chinese, Singapore. */
1600 const BuiltinFormat spBuiltinFormats_zh_SG[] =
1601 {
1602     NUMFMT_ALLDATETIMES( "D/M/YYYY", "D", "-", "MMM", "-", "YY", "h", "h" ),
1603     NUMFMT_ALLCURRENCIES_OPEN_SYMBOL_NUMBER_CLOSE( "$", "" ),
1604     NUMFMT_ALLTIMES_CJK( "h", "h", UTF8_CS_HOUR, UTF8_CS_MIN, UTF8_CS_SEC ),
1605     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "$", "", "" ),
1606     NUMFMT_STRING( 27, "YYYY\"" UTF8_CS_YEAR "\"M\"" UTF8_CS_MON "\"" ),
1607     NUMFMT_STRING( 28, "M\"" UTF8_CS_MON "\"D\"" UTF8_CS_DAY "\"" ),
1608     NUMFMT_STRING( 30, "M/D/YY" ),
1609     NUMFMT_STRING( 31, "D\"" UTF8_CS_DAY "\"M\"" UTF8_CS_MON "\"YYYY\"" UTF8_CS_YEAR "\"" ),
1610     NUMFMT_ENDTABLE()
1611 };
1612 
1613 /** Chinese, Taiwan. */
1614 const BuiltinFormat spBuiltinFormats_zh_TW[] =
1615 {
1616     NUMFMT_ALLDATETIMES( "YYYY/M/D", "D", "-", "MMM", "-", "YY", "hh", "hh" ),
1617     NUMFMT_ALLCURRENCIES_MINUS_SYMBOL_NUMBER( "$", "" ),
1618     NUMFMT_ALLTIMES_CJK( "hh", "hh", UTF8_CJ_HOUR, UTF8_CJ_MIN, UTF8_CJ_SEC ),
1619     NUMFMT_CURRENCY_OPEN_SYMBOL_NUMBER_CLOSE( 23, "\"US$\"", "", "" ),
1620     NUMFMT_STRING( 27, "[$-404]E/M/D" ),
1621     NUMFMT_STRING( 28, "[$-404]E\"" UTF8_CJ_YEAR "\"M\"" UTF8_CJ_MON "\"D\"" UTF8_CJ_DAY "\"" ),
1622     NUMFMT_STRING( 30, "M/D/YY" ),
1623     NUMFMT_STRING( 31, "YYYY\"" UTF8_CJ_YEAR "\"M\"" UTF8_CJ_MON "\"D\"" UTF8_CJ_DAY "\"" ),
1624     NUMFMT_ENDTABLE()
1625 };
1626 
1627 /** Specifies a built-in number format table for a specific locale. */
1628 struct BuiltinFormatTable
1629 {
1630     const char*          mpcLocale;          /// The locale for this table.
1631     const char*          mpcParent;          /// The locale of the parent table.
1632     const BuiltinFormat* mpFormats;         /// The number format table (may be 0, if equal to parent).
1633 };
1634 
1635 const BuiltinFormatTable spBuiltinFormatTables[] =
1636 { //  locale    parent      format table
1637     { "*",      "",         spBuiltinFormats_BASE   },  // Base table
1638     { "af-ZA",  "*",        spBuiltinFormats_en_ZA  },  // Afrikaans, South Africa
1639     { "ar-AE",  "*",        spBuiltinFormats_ar_AE  },  // Arabic, U.A.E.
1640     { "ar-BH",  "*",        spBuiltinFormats_ar_BH  },  // Arabic, Bahrain
1641     { "ar-DZ",  "*",        spBuiltinFormats_ar_DZ  },  // Arabic, Algeria
1642     { "ar-EG",  "*",        spBuiltinFormats_ar_EG  },  // Arabic, Egypt
1643     { "ar-IQ",  "*",        spBuiltinFormats_ar_IQ  },  // Arabic, Iraq
1644     { "ar-JO",  "*",        spBuiltinFormats_ar_JO  },  // Arabic, Jordan
1645     { "ar-KW",  "*",        spBuiltinFormats_ar_KW  },  // Arabic, Kuwait
1646     { "ar-LB",  "*",        spBuiltinFormats_ar_LB  },  // Arabic, Lebanon
1647     { "ar-LY",  "*",        spBuiltinFormats_ar_LY  },  // Arabic, Libya
1648     { "ar-MA",  "*",        spBuiltinFormats_ar_MA  },  // Arabic, Morocco
1649     { "ar-OM",  "*",        spBuiltinFormats_ar_OM  },  // Arabic, Oman
1650     { "ar-QA",  "*",        spBuiltinFormats_ar_QA  },  // Arabic, Qatar
1651     { "ar-SA",  "*",        spBuiltinFormats_ar_SA  },  // Arabic, Saudi Arabia
1652     { "ar-SY",  "*",        spBuiltinFormats_ar_SY  },  // Arabic, Syria
1653     { "ar-TN",  "*",        spBuiltinFormats_ar_TN  },  // Arabic, Tunisia
1654     { "ar-YE",  "*",        spBuiltinFormats_ar_YE  },  // Arabic, Yemen
1655     { "be-BY",  "*",        spBuiltinFormats_be_BY  },  // Belarusian, Belarus
1656     { "bg-BG",  "*",        spBuiltinFormats_bg_BG  },  // Bulgarian, Bulgaria
1657     { "bn-IN",  "*",        spBuiltinFormats_bn_IN  },  // Bengali, India
1658     { "ca-ES",  "*",        spBuiltinFormats_es_ES  },  // Catalan, Spain
1659     { "cs-CZ",  "*",        spBuiltinFormats_cs_CZ  },  // Czech, Czech Republic
1660     { "cy-GB",  "*",        spBuiltinFormats_en_GB  },  // Welsh, United Kingdom
1661     { "da-DK",  "*",        spBuiltinFormats_da_DK  },  // Danish, Denmark
1662     { "de-AT",  "*",        spBuiltinFormats_de_AT  },  // German, Austria
1663     { "de-CH",  "*",        spBuiltinFormats_de_CH  },  // German, Switzerland
1664     { "de-DE",  "*",        spBuiltinFormats_de_DE  },  // German, Germany
1665     { "de-LI",  "*",        spBuiltinFormats_de_LI  },  // German, Liechtenstein
1666     { "de-LU",  "*",        spBuiltinFormats_de_LU  },  // German, Luxembourg
1667     { "div-MV", "*",        spBuiltinFormats_div_MV },  // Divehi, Maldives
1668     { "el-GR",  "*",        spBuiltinFormats_el_GR  },  // Greek, Greece
1669     { "en-AU",  "*",        spBuiltinFormats_en_AU  },  // English, Australia
1670     { "en-BZ",  "*",        spBuiltinFormats_en_BZ  },  // English, Belize
1671     { "en-CA",  "*",        spBuiltinFormats_en_CA  },  // English, Canada
1672     { "en-CB",  "*",        spBuiltinFormats_en_CB  },  // English, Caribbean
1673     { "en-GB",  "*",        spBuiltinFormats_en_GB  },  // English, United Kingdom
1674     { "en-IE",  "*",        spBuiltinFormats_en_IE  },  // English, Ireland
1675     { "en-JM",  "*",        spBuiltinFormats_en_JM  },  // English, Jamaica
1676     { "en-NZ",  "*",        spBuiltinFormats_en_NZ  },  // English, New Zealand
1677     { "en-PH",  "*",        spBuiltinFormats_en_PH  },  // English, Philippines
1678     { "en-TT",  "*",        spBuiltinFormats_en_TT  },  // English, Trinidad and Tobago
1679     { "en-US",  "*",        spBuiltinFormats_en_US  },  // English, USA
1680     { "en-ZA",  "*",        spBuiltinFormats_en_ZA  },  // English, South Africa
1681     { "en-ZW",  "*",        spBuiltinFormats_en_ZW  },  // English, Zimbabwe
1682     { "es-AR",  "*",        spBuiltinFormats_es_AR  },  // Spanish, Argentina
1683     { "es-BO",  "*",        spBuiltinFormats_es_BO  },  // Spanish, Bolivia
1684     { "es-CL",  "*",        spBuiltinFormats_es_CL  },  // Spanish, Chile
1685     { "es-CO",  "*",        spBuiltinFormats_es_CO  },  // Spanish, Colombia
1686     { "es-CR",  "*",        spBuiltinFormats_es_CR  },  // Spanish, Costa Rica
1687     { "es-DO",  "*",        spBuiltinFormats_es_DO  },  // Spanish, Dominican Republic
1688     { "es-EC",  "*",        spBuiltinFormats_es_EC  },  // Spanish, Ecuador
1689     { "es-ES",  "*",        spBuiltinFormats_es_ES  },  // Spanish, Spain
1690     { "es-GT",  "*",        spBuiltinFormats_es_GT  },  // Spanish, Guatemala
1691     { "es-HN",  "*",        spBuiltinFormats_es_HN  },  // Spanish, Honduras
1692     { "es-MX",  "*",        spBuiltinFormats_es_MX  },  // Spanish, Mexico
1693     { "es-NI",  "*",        spBuiltinFormats_es_NI  },  // Spanish, Nicaragua
1694     { "es-PA",  "*",        spBuiltinFormats_es_PA  },  // Spanish, Panama
1695     { "es-PE",  "*",        spBuiltinFormats_es_PE  },  // Spanish, Peru
1696     { "es-PR",  "*",        spBuiltinFormats_es_PR  },  // Spanish, Puerto Rico
1697     { "es-PY",  "*",        spBuiltinFormats_es_PY  },  // Spanish, Paraguay
1698     { "es-SV",  "*",        spBuiltinFormats_es_SV  },  // Spanish, El Salvador
1699     { "es-UY",  "*",        spBuiltinFormats_es_UY  },  // Spanish, Uruguay
1700     { "es-VE",  "*",        spBuiltinFormats_es_VE  },  // Spanish, Venezuela
1701     { "et-EE",  "*",        spBuiltinFormats_et_EE  },  // Estonian, Estonia
1702     { "fa-IR",  "*",        spBuiltinFormats_fa_IR  },  // Farsi, Iran
1703     { "fi-FI",  "*",        spBuiltinFormats_fi_FI  },  // Finnish, Finland
1704     { "fo-FO",  "*",        spBuiltinFormats_fo_FO  },  // Faroese, Faroe Islands
1705     { "fr-BE",  "*",        spBuiltinFormats_fr_BE  },  // French, Belgium
1706     { "fr-CA",  "*",        spBuiltinFormats_fr_CA  },  // French, Canada
1707     { "fr-CH",  "*",        spBuiltinFormats_fr_CH  },  // French, Switzerland
1708     { "fr-FR",  "*",        spBuiltinFormats_fr_FR  },  // French, France
1709     { "fr-LU",  "*",        spBuiltinFormats_fr_LU  },  // French, Luxembourg
1710     { "fr-MC",  "*",        spBuiltinFormats_fr_MC  },  // French, Monaco
1711     { "gl-ES",  "*",        spBuiltinFormats_gl_ES  },  // Galizian, Spain
1712     { "gu-IN",  "*",        spBuiltinFormats_gu_IN  },  // Gujarati, India
1713     { "he-IL",  "*",        spBuiltinFormats_he_IL  },  // Hebrew, Israel
1714     { "hi-IN",  "*",        spBuiltinFormats_hi_IN  },  // Hindi, India
1715     { "hr-BA",  "*",        spBuiltinFormats_hr_BA  },  // Croatian, Bosnia and Herzegowina
1716     { "hr-HR",  "*",        spBuiltinFormats_hr_HR  },  // Croatian, Croatia
1717     { "hu-HU",  "*",        spBuiltinFormats_hu_HU  },  // Hungarian, Hungary
1718     { "hy-AM",  "*",        spBuiltinFormats_hy_AM  },  // Armenian, Armenia
1719     { "id-ID",  "*",        spBuiltinFormats_id_ID  },  // Indonesian, Indonesia
1720     { "is-IS",  "*",        spBuiltinFormats_is_IS  },  // Icelandic, Iceland
1721     { "it-CH",  "*",        spBuiltinFormats_it_CH  },  // Italian, Switzerland
1722     { "it-IT",  "*",        spBuiltinFormats_it_IT  },  // Italian, Italy
1723     { "ka-GE",  "*",        spBuiltinFormats_ka_GE  },  // Georgian, Georgia
1724     { "kk-KZ",  "*",        spBuiltinFormats_kk_KZ  },  // Kazakh, Kazakhstan
1725     { "kn-IN",  "*",        spBuiltinFormats_kn_IN  },  // Kannada, India
1726     { "kok-IN", "*",        spBuiltinFormats_hi_IN  },  // Konkani, India
1727     { "ky-KG",  "*",        spBuiltinFormats_ky_KG  },  // Kyrgyz, Kyrgyzstan
1728     { "lt-LT",  "*",        spBuiltinFormats_lt_LT  },  // Lithuanian, Lithuania
1729     { "lv-LV",  "*",        spBuiltinFormats_lv_LV  },  // Latvian, Latvia
1730     { "mi-NZ",  "*",        spBuiltinFormats_en_NZ  },  // Maori, New Zealand
1731     { "ml-IN",  "*",        spBuiltinFormats_ml_IN  },  // Malayalam, India
1732     { "mn-MN",  "*",        spBuiltinFormats_mn_MN  },  // Mongolian, Mongolia
1733     { "mr-IN",  "*",        spBuiltinFormats_hi_IN  },  // Marathi, India
1734     { "ms-BN",  "*",        spBuiltinFormats_ms_BN  },  // Malay, Brunei Darussalam
1735     { "ms-MY",  "*",        spBuiltinFormats_ms_MY  },  // Malay, Malaysia
1736     { "mt-MT",  "*",        spBuiltinFormats_mt_MT  },  // Maltese, Malta
1737     { "nb-NO",  "*",        spBuiltinFormats_no_NO  },  // Norwegian Bokmal, Norway
1738     { "nl-BE",  "*",        spBuiltinFormats_nl_BE  },  // Dutch, Belgium
1739     { "nl-NL",  "*",        spBuiltinFormats_nl_NL  },  // Dutch, Netherlands
1740     { "nn-NO",  "*",        spBuiltinFormats_no_NO  },  // Norwegian Nynorsk, Norway
1741     { "nso-ZA", "*",        spBuiltinFormats_en_ZA  },  // Northern Sotho, South Africa
1742     { "pa-IN",  "*",        spBuiltinFormats_pa_IN  },  // Punjabi, India
1743     { "pl-PL",  "*",        spBuiltinFormats_pl_PL  },  // Polish, Poland
1744     { "pt-BR",  "*",        spBuiltinFormats_pt_BR  },  // Portuguese, Brazil
1745     { "pt-PT",  "*",        spBuiltinFormats_pt_PT  },  // Portuguese, Portugal
1746     { "qu-BO",  "*",        spBuiltinFormats_es_BO  },  // Quechua, Bolivia
1747     { "qu-EC",  "*",        spBuiltinFormats_es_EC  },  // Quechua, Ecuador
1748     { "qu-PE",  "*",        spBuiltinFormats_es_PE  },  // Quechua, Peru
1749     { "ro-RO",  "*",        spBuiltinFormats_ro_RO  },  // Romanian, Romania
1750     { "ru-RU",  "*",        spBuiltinFormats_ru_RU  },  // Russian, Russian Federation
1751     { "sa-IN",  "*",        spBuiltinFormats_hi_IN  },  // Sanskrit, India
1752     { "se-FI",  "*",        spBuiltinFormats_fi_FI  },  // Sami, Finland
1753     { "se-NO",  "*",        spBuiltinFormats_no_NO  },  // Sami, Norway
1754     { "se-SE",  "*",        spBuiltinFormats_sv_SE  },  // Sami, Sweden
1755     { "sk-SK",  "*",        spBuiltinFormats_sk_SK  },  // Slovak, Slovakia
1756     { "sl-SI",  "*",        spBuiltinFormats_sl_SI  },  // Slovenian, Slovenia
1757     { "sv-FI",  "*",        spBuiltinFormats_sv_FI  },  // Swedish, Finland
1758     { "sv-SE",  "*",        spBuiltinFormats_sv_SE  },  // Swedish, Sweden
1759     { "sw-TZ",  "*",        spBuiltinFormats_sw_TZ  },  // Swahili, Tanzania
1760     { "syr-SY", "*",        spBuiltinFormats_ar_SY  },  // Syriac, Syria
1761     { "syr-TR", "*",        spBuiltinFormats_tr_TR  },  // Syriac, Turkey
1762     { "ta-IN",  "*",        spBuiltinFormats_ta_IN  },  // Tamil, India
1763     { "te-IN",  "*",        spBuiltinFormats_te_IN  },  // Telugu, India
1764     { "th-TH",  "*",        spBuiltinFormats_th_TH  },  // Thai, Thailand
1765     { "tn-ZA",  "*",        spBuiltinFormats_en_ZA  },  // Tswana, South Africa
1766     { "tr-TR",  "*",        spBuiltinFormats_tr_TR  },  // Turkish, Turkey
1767     { "tt-RU",  "*",        spBuiltinFormats_tt_RU  },  // Tatar, Russian Federation
1768     { "uk-UA",  "*",        spBuiltinFormats_uk_UA  },  // Ukrainian, Ukraine
1769     { "ur-PK",  "*",        spBuiltinFormats_ur_PK  },  // Urdu, Pakistan
1770     { "vi-VN",  "*",        spBuiltinFormats_vi_VN  },  // Vietnamese, Viet Nam
1771     { "xh-ZA",  "*",        spBuiltinFormats_en_ZA  },  // Xhosa, South Africa
1772     { "zu-ZA",  "*",        spBuiltinFormats_en_ZA  },  // Zulu, South Africa
1773 
1774     { "*CJK",   "*",        spBuiltinFormats_CJK    },  // CJK base table
1775     { "ja-JP",  "*CJK",     spBuiltinFormats_ja_JP  },  // Japanese, Japan
1776     { "ko-KR",  "*CJK",     spBuiltinFormats_ko_KR  },  // Korean, South Korea
1777     { "zh-CN",  "*CJK",     spBuiltinFormats_zh_CN  },  // Chinese, China
1778     { "zh-HK",  "*CJK",     spBuiltinFormats_zh_HK  },  // Chinese, Hong Kong
1779     { "zh-MO",  "*CJK",     spBuiltinFormats_zh_MO  },  // Chinese, Macau
1780     { "zh-SG",  "*CJK",     spBuiltinFormats_zh_SG  },  // Chinese, Singapore
1781     { "zh-TW",  "*CJK",     spBuiltinFormats_zh_TW  }   // Chinese, Taiwan
1782 };
1783 
1784 } // namespace
1785 
1786 NumFmtModel::NumFmtModel() :
1787     mnPredefId( -1 )
1788 {
1789 }
1790 
1791 ApiNumFmtData::ApiNumFmtData() :
1792     mnIndex( 0 )
1793 {
1794 }
1795 
1796 namespace {
1797 
1798 sal_Int32 lclCreatePredefinedFormat( const Reference< XNumberFormats >& rxNumFmts,
1799         sal_Int16 nPredefId, const Locale& rToLocale )
1800 {
1801     sal_Int32 nIndex = 0;
1802     try
1803     {
1804         Reference< XNumberFormatTypes > xNumFmtTypes( rxNumFmts, UNO_QUERY_THROW );
1805         nIndex = (nPredefId >= 0) ?
1806             xNumFmtTypes->getFormatIndex( nPredefId, rToLocale ) :
1807             xNumFmtTypes->getStandardIndex( rToLocale );
1808     }
1809     catch( Exception& )
1810     {
1811         OSL_FAIL( OStringBuffer( "lclCreatePredefinedFormat - cannot create predefined number format " ).
1812             append( OString::number( nPredefId ) ).getStr() );
1813     }
1814     return nIndex;
1815 }
1816 
1817 sal_Int32 lclCreateFormat( const Reference< XNumberFormats >& rxNumFmts,
1818         const OUString& rFmtCode, const Locale& rToLocale, const Locale& rFromLocale )
1819 {
1820     sal_Int32 nIndex = 0;
1821     try
1822     {
1823         nIndex = rxNumFmts->addNewConverted( rFmtCode, rFromLocale, rToLocale );
1824     }
1825     catch( Exception& )
1826     {
1827         // BIFF2-BIFF4 stores standard format explicitly in stream
1828         if( rFmtCode.equalsIgnoreAsciiCase( "general" ) )
1829         {
1830             nIndex = lclCreatePredefinedFormat( rxNumFmts, 0, rToLocale );
1831         }
1832         else
1833         {
1834             // do not assert fractional number formats with fixed denominator
1835             OSL_ENSURE( rFmtCode.startsWith( "#\\ ?/" ) ||
1836                         rFmtCode.startsWith( "#\\ ?\?/" ) ||
1837                         rFmtCode.startsWith( "#\\ ?\?\?/" ),
1838                 OStringBuffer( "lclCreateFormat - cannot create number format '" ).
1839                 append( OUStringToOString( rFmtCode, osl_getThreadTextEncoding() ) ).
1840                 append( '\'' ).getStr() );
1841         }
1842     }
1843     return nIndex;
1844 }
1845 
1846 /** Functor for converting an XML number format to an API number format index. */
1847 class NumberFormatFinalizer
1848 {
1849 public:
1850     explicit            NumberFormatFinalizer( const WorkbookHelper& rHelper );
1851 
1852     void         operator()( NumberFormat& rNumFmt ) const
1853                             { rNumFmt.finalizeImport( mxNumFmts, maEnUsLocale ); }
1854 
1855 private:
1856     Reference< XNumberFormats > mxNumFmts;
1857     Locale              maEnUsLocale;
1858 };
1859 
1860 NumberFormatFinalizer::NumberFormatFinalizer( const WorkbookHelper& rHelper ) :
1861     maEnUsLocale( "en", "US", OUString() )
1862 {
1863     try
1864     {
1865         Reference< XNumberFormatsSupplier > xNumFmtsSupp( rHelper.getDocument(), UNO_QUERY_THROW );
1866         mxNumFmts = xNumFmtsSupp->getNumberFormats();
1867     }
1868     catch( Exception& )
1869     {
1870     }
1871     OSL_ENSURE( mxNumFmts.is(), "NumberFormatFinalizer::NumberFormatFinalizer - cannot get number formats" );
1872 }
1873 
1874 sal_Int32 lclPosToken ( const OUString& sFormat, const OUString& sSearch, sal_Int32 nStartPos )
1875 {
1876     sal_Int32 nLength = sFormat.getLength();
1877     for ( sal_Int32 i = nStartPos; i < nLength && i >= 0 ; i++ )
1878     {
1879         switch(sFormat[i])
1880         {
1881             case '\"' : // skip text
1882                 i = sFormat.indexOf('\"',i+1);
1883                 break;
1884             case '['  : // skip condition
1885                 i = sFormat.indexOf(']',i+1);
1886                 break;
1887             default :
1888                 if ( sFormat.match(sSearch, i) )
1889                     return i;
1890                 break;
1891         }
1892         if ( i < 0 )
1893             i--;
1894     }
1895     return -2;
1896 }
1897 
1898 } // namespace
1899 
1900 NumberFormat::NumberFormat( const WorkbookHelper& rHelper ) :
1901     WorkbookHelper( rHelper )
1902 {
1903 }
1904 
1905 void NumberFormat::setFormatCode( const OUString& rFmtCode )
1906 {
1907     // Special case for fraction code '\ ?/?', it is passed to us in xml, the '\' is not
1908     // an escape character but merely should be telling the formatter to display the next
1909     // char in the format ( afaics it does that anyhow )
1910     sal_Int32 nPosEscape = 0;
1911     sal_Int32 nErase = 0;
1912     sal_Int32 nLastIndex = rFmtCode.getLength() - 1;
1913     OUStringBuffer sFormat = rFmtCode;
1914 
1915     while ( ( nPosEscape = lclPosToken( rFmtCode, "\\ ", nPosEscape ) ) > 0 )
1916     {
1917         sal_Int32 nPos = nPosEscape + 2;
1918         while ( nPos < nLastIndex && ( rFmtCode[nPos] == '?' || rFmtCode[nPos] == '#' || rFmtCode[nPos] == '0' ) )
1919             nPos++;
1920         if ( nPos < nLastIndex && rFmtCode[nPos] == '/' )
1921         {
1922             sFormat.remove(nPosEscape - nErase, 1);
1923             nErase ++;
1924         }  // tdf#81939 preserve other escape characters
1925         nPosEscape = lclPosToken( rFmtCode, ";", nPosEscape ); // skip to next format
1926     }
1927     maModel.maFmtCode = sFormat.makeStringAndClear();
1928 }
1929 
1930 void NumberFormat::setFormatCode( const Locale& rLocale, const char* pcFmtCode )
1931 {
1932     maModel.maLocale = rLocale;
1933     maModel.maFmtCode = OStringToOUString( OString( pcFmtCode ), RTL_TEXTENCODING_UTF8 );
1934     maModel.mnPredefId = -1;
1935 }
1936 
1937 void NumberFormat::setPredefinedId( const Locale& rLocale, sal_Int16 nPredefId )
1938 {
1939     maModel.maLocale = rLocale;
1940     maModel.maFmtCode.clear();
1941     maModel.mnPredefId = nPredefId;
1942 }
1943 
1944 void NumberFormat::finalizeImport( const Reference< XNumberFormats >& rxNumFmts, const Locale& rFromLocale )
1945 {
1946     if( rxNumFmts.is() && !maModel.maFmtCode.isEmpty() )
1947         maApiData.mnIndex = lclCreateFormat( rxNumFmts, maModel.maFmtCode, maModel.maLocale, rFromLocale );
1948     else
1949         maApiData.mnIndex = lclCreatePredefinedFormat( rxNumFmts, maModel.mnPredefId, maModel.maLocale );
1950 }
1951 
1952 sal_uInt32 NumberFormat::fillToItemSet( SfxItemSet& rItemSet, bool bSkipPoolDefs ) const
1953 {
1954     const ScDocument& rDoc = getScDocument();
1955     static sal_uInt32  nDflt = rDoc.GetFormatTable()->GetStandardIndex( ScGlobal::eLnge );
1956     sal_uInt32 nScNumFmt = nDflt;
1957     if ( maApiData.mnIndex )
1958         nScNumFmt = maApiData.mnIndex;
1959 
1960     ScfTools::PutItem( rItemSet, SfxUInt32Item( ATTR_VALUE_FORMAT, nScNumFmt ), bSkipPoolDefs );
1961     if( rItemSet.GetItemState( ATTR_VALUE_FORMAT, false ) == SfxItemState::SET )
1962         ScGlobal::AddLanguage( rItemSet, *(rDoc.GetFormatTable()) );
1963     else
1964         nScNumFmt = 0;
1965 
1966     return nScNumFmt;
1967 }
1968 
1969 NumberFormatsBuffer::NumberFormatsBuffer( const WorkbookHelper& rHelper )
1970     : WorkbookHelper(rHelper)
1971     , mnHighestId(0)
1972 {
1973     // get the current locale
1974     // try user-defined locale setting
1975     maLocaleStr = officecfg::Setup::L10N::ooSetupSystemLocale::get();
1976     // if set to "use system", get locale from system
1977     if( maLocaleStr.isEmpty() )
1978         maLocaleStr = officecfg::System::L10N::Locale::get();
1979 
1980     // create built-in formats for current locale
1981     insertBuiltinFormats();
1982 }
1983 
1984 NumberFormatRef NumberFormatsBuffer::createNumFmt( sal_uInt32 nNumFmtId, const OUString& rFmtCode )
1985 {
1986     NumberFormatRef xNumFmt;
1987     xNumFmt = std::make_shared<NumberFormat>( *this );
1988     maNumFmts[ nNumFmtId ] = xNumFmt;
1989     if ( nNumFmtId > mnHighestId )
1990         mnHighestId = nNumFmtId;
1991     xNumFmt->setFormatCode( rFmtCode );
1992     return xNumFmt;
1993 }
1994 
1995 NumberFormatRef NumberFormatsBuffer::importNumFmt( const AttributeList& rAttribs )
1996 {
1997     sal_Int32 nNumFmtId = rAttribs.getInteger( XML_numFmtId, -1 );
1998     OUString aFmtCode = rAttribs.getXString( XML_formatCode, OUString() );
1999     return createNumFmt( nNumFmtId, aFmtCode );
2000 }
2001 
2002 void NumberFormatsBuffer::importNumFmt( SequenceInputStream& rStrm )
2003 {
2004     sal_Int32 nNumFmtId = rStrm.readuInt16();
2005     OUString aFmtCode = BiffHelper::readString( rStrm );
2006     createNumFmt( nNumFmtId, aFmtCode );
2007 }
2008 
2009 void NumberFormatsBuffer::finalizeImport()
2010 {
2011     maNumFmts.forEach( NumberFormatFinalizer( *this ) );
2012 }
2013 
2014 sal_uInt32 NumberFormatsBuffer::fillToItemSet( SfxItemSet& rItemSet, sal_uInt32 nNumFmtId, bool bSkipPoolDefs ) const
2015 {
2016     const NumberFormat* pNumFmt = maNumFmts.get(nNumFmtId).get();
2017     if (!pNumFmt)
2018         return 0;
2019 
2020     return pNumFmt->fillToItemSet( rItemSet, bSkipPoolDefs);
2021 }
2022 
2023 void NumberFormatsBuffer::insertBuiltinFormats()
2024 {
2025     // build a map containing pointers to all tables
2026     typedef ::std::map< OUString, const BuiltinFormatTable* > BuiltinMap;
2027     BuiltinMap aBuiltinMap;
2028     for(auto const &rTable : spBuiltinFormatTables)
2029         aBuiltinMap[ OUString::createFromAscii(rTable.mpcLocale) ] = &rTable;
2030 
2031     // convert locale string to locale struct
2032     Locale aSysLocale( LanguageTag::convertToLocale( maLocaleStr));
2033 
2034     // build a list of table pointers for the current locale, with all parent tables
2035     typedef ::std::vector< const BuiltinFormatTable* > BuiltinVec;
2036     BuiltinVec aBuiltinVec;
2037     BuiltinMap::const_iterator aMIt = aBuiltinMap.find( maLocaleStr ), aMEnd = aBuiltinMap.end();
2038     OSL_ENSURE( aMIt != aMEnd,
2039         OStringBuffer( "NumberFormatsBuffer::insertBuiltinFormats - locale '" ).
2040         append( OUStringToOString( maLocaleStr, RTL_TEXTENCODING_ASCII_US ) ).
2041         append( "' not supported (#i29949#)" ).getStr() );
2042     // start with default table, if no table has been found
2043     if( aMIt == aMEnd )
2044         aMIt = aBuiltinMap.find( "*" );
2045     OSL_ENSURE( aMIt != aMEnd, "NumberFormatsBuffer::insertBuiltinFormats - default map not found" );
2046     // insert all tables into the vector
2047     for( ; aMIt != aMEnd; aMIt = aBuiltinMap.find( OUString::createFromAscii( aMIt->second->mpcParent ) ) )
2048         aBuiltinVec.push_back( aMIt->second );
2049 
2050     // insert the default formats in the format map (in reverse order from default table to system locale)
2051     std::map< sal_uInt32, sal_uInt32 > aReuseMap;
2052     for( BuiltinVec::reverse_iterator aVIt = aBuiltinVec.rbegin(), aVEnd = aBuiltinVec.rend(); aVIt != aVEnd; ++aVIt )
2053     {
2054         // do not put the current system locale for default table
2055         Locale aLocale;
2056         if( (*aVIt)->mpcParent[ 0 ] != '\0' && OUString::createFromAscii((*aVIt)->mpcLocale) != maLocaleStr )
2057             aLocale = aSysLocale;
2058         for( const BuiltinFormat* pBuiltin = (*aVIt)->mpFormats; pBuiltin && (pBuiltin->mnNumFmtId >= 0); ++pBuiltin )
2059         {
2060             NumberFormatRef& rxNumFmt = maNumFmts[ pBuiltin->mnNumFmtId ];
2061             rxNumFmt = std::make_shared<NumberFormat>( *this );
2062 
2063             bool bReuse = false;
2064             if( pBuiltin->mpcFmtCode )
2065                 rxNumFmt->setFormatCode( aLocale, pBuiltin->mpcFmtCode );
2066             else if( pBuiltin->mnPredefId >= 0 )
2067                 rxNumFmt->setPredefinedId( aLocale, pBuiltin->mnPredefId );
2068             else
2069                 bReuse = pBuiltin->mnReuseId >= 0;
2070 
2071             if( bReuse )
2072                 aReuseMap[ pBuiltin->mnNumFmtId ] = pBuiltin->mnReuseId;
2073             else
2074                 aReuseMap.erase( pBuiltin->mnNumFmtId );
2075         }
2076     }
2077 
2078     // copy reused number formats
2079     for( const auto& [rNumFmtId, rReuseId] : aReuseMap )
2080     {
2081         maNumFmts[ rNumFmtId ] = maNumFmts[ rReuseId ];
2082         if ( rNumFmtId > mnHighestId )
2083             mnHighestId = rNumFmtId;
2084     }
2085 }
2086 
2087 } // namespace oox
2088 
2089 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2090