1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <sal/config.h>
12 #include <cppunit/TestFixture.h>
13 #include <cppunit/TestAssert.h>
14 #include <cppunit/extensions/HelperMacros.h>
15 #include <cppunit/plugin/TestPlugIn.h>
17 #include <i18nlangtag/mslangid.hxx>
18 #include <i18nlangtag/languagetag.hxx>
20 #include <rtl/ustring.hxx>
21 #include <rtl/ustrbuf.hxx>
22 #include <sal/log.hxx>
23 #include <osl/file.hxx>
25 #include <com/sun/star/lang/Locale.hpp>
26 #include <com/sun/star/i18n/ScriptType.hpp>
28 using namespace com::sun::star
;
32 class TestLanguageTag
: public CppUnit::TestFixture
38 void testAllIsoLangEntries();
40 CPPUNIT_TEST_SUITE(TestLanguageTag
);
41 CPPUNIT_TEST(testAllTags
);
42 CPPUNIT_TEST(testAllIsoLangEntries
);
43 CPPUNIT_TEST_SUITE_END();
46 void TestLanguageTag::testAllTags()
49 OUString
const s_de_Latn_DE( "de-Latn-DE" );
50 LanguageTag
de_DE( s_de_Latn_DE
, true );
51 OUString aBcp47
= de_DE
.getBcp47();
52 lang::Locale aLocale
= de_DE
.getLocale();
53 LanguageType nLanguageType
= de_DE
.getLanguageType();
54 CPPUNIT_ASSERT_EQUAL_MESSAGE("Default script should be stripped after canonicalize.", OUString("de-DE"), aBcp47
);
55 CPPUNIT_ASSERT_EQUAL( OUString("de"), aLocale
.Language
);
56 CPPUNIT_ASSERT_EQUAL( OUString("DE"), aLocale
.Country
);
57 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
58 CPPUNIT_ASSERT_EQUAL( LANGUAGE_GERMAN
, nLanguageType
);
59 CPPUNIT_ASSERT_EQUAL( OUString("de"), de_DE
.getLanguage() );
60 CPPUNIT_ASSERT_EQUAL( OUString("DE"), de_DE
.getCountry() );
61 CPPUNIT_ASSERT( de_DE
.getScript().isEmpty() );
62 CPPUNIT_ASSERT_EQUAL( OUString("de"), de_DE
.getLanguageAndScript() );
63 CPPUNIT_ASSERT_EQUAL( OUString("de-DE"), de_DE
.makeFallback().getBcp47() );
67 OUString
const s_klingon( "i-klingon" );
68 LanguageTag
klingon( s_klingon
, true );
69 lang::Locale aLocale
= klingon
.getLocale();
70 CPPUNIT_ASSERT_EQUAL( OUString("tlh"), klingon
.getBcp47() );
71 CPPUNIT_ASSERT_EQUAL( OUString("tlh"), aLocale
.Language
);
72 CPPUNIT_ASSERT( aLocale
.Country
.isEmpty() );
73 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
74 CPPUNIT_ASSERT( LanguageTag::isOnTheFlyID( klingon
.getLanguageType()) );
75 CPPUNIT_ASSERT( klingon
.isValidBcp47() );
76 CPPUNIT_ASSERT( klingon
.isIsoLocale() );
77 CPPUNIT_ASSERT( klingon
.isIsoODF() );
78 LanguageType nLang
= klingon
.getLanguageType();
79 LanguageTag
klingon_id( nLang
);
80 CPPUNIT_ASSERT_EQUAL( OUString("tlh"), klingon_id
.getBcp47() );
84 OUString
s_sr_RS( "sr-RS" );
85 LanguageTag
sr_RS( s_sr_RS
, true );
86 lang::Locale aLocale
= sr_RS
.getLocale();
87 CPPUNIT_ASSERT_EQUAL( s_sr_RS
, sr_RS
.getBcp47() );
88 CPPUNIT_ASSERT_EQUAL( OUString("sr"), aLocale
.Language
);
89 CPPUNIT_ASSERT_EQUAL( OUString("RS"), aLocale
.Country
);
90 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
91 CPPUNIT_ASSERT_EQUAL( LANGUAGE_USER_SERBIAN_CYRILLIC_SERBIA
, sr_RS
.getLanguageType() );
92 CPPUNIT_ASSERT( sr_RS
.isValidBcp47() );
93 CPPUNIT_ASSERT( sr_RS
.isIsoLocale() );
94 CPPUNIT_ASSERT( sr_RS
.isIsoODF() );
98 OUString
s_sr_Latn_RS( "sr-Latn-RS" );
99 LanguageTag
sr_RS( s_sr_Latn_RS
, true );
100 lang::Locale aLocale
= sr_RS
.getLocale();
101 CPPUNIT_ASSERT_EQUAL( s_sr_Latn_RS
, sr_RS
.getBcp47() );
102 CPPUNIT_ASSERT_EQUAL( OUString("qlt"), aLocale
.Language
);
103 CPPUNIT_ASSERT_EQUAL( OUString("RS"), aLocale
.Country
);
104 CPPUNIT_ASSERT_EQUAL( s_sr_Latn_RS
, aLocale
.Variant
);
105 CPPUNIT_ASSERT_EQUAL( LANGUAGE_USER_SERBIAN_LATIN_SERBIA
, sr_RS
.getLanguageType() );
106 CPPUNIT_ASSERT( sr_RS
.isValidBcp47() );
107 CPPUNIT_ASSERT( !sr_RS
.isIsoLocale() );
108 CPPUNIT_ASSERT( sr_RS
.isIsoODF() );
109 CPPUNIT_ASSERT_EQUAL( OUString("sr"), sr_RS
.getLanguage() );
110 CPPUNIT_ASSERT_EQUAL( OUString("RS"), sr_RS
.getCountry() );
111 CPPUNIT_ASSERT_EQUAL( OUString("Latn"), sr_RS
.getScript() );
112 CPPUNIT_ASSERT_EQUAL( OUString("sr-Latn"), sr_RS
.getLanguageAndScript() );
116 OUString
s_sr_Latn_CS( "sr-Latn-CS" );
117 LanguageTag
sr_Latn_CS( s_sr_Latn_CS
, true );
118 lang::Locale aLocale
= sr_Latn_CS
.getLocale();
119 CPPUNIT_ASSERT_EQUAL( s_sr_Latn_CS
, sr_Latn_CS
.getBcp47() );
120 CPPUNIT_ASSERT_EQUAL( OUString("qlt"), aLocale
.Language
);
121 CPPUNIT_ASSERT_EQUAL( OUString("CS"), aLocale
.Country
);
122 CPPUNIT_ASSERT_EQUAL( s_sr_Latn_CS
, aLocale
.Variant
);
123 CPPUNIT_ASSERT_EQUAL( LANGUAGE_SERBIAN_LATIN_SAM
, sr_Latn_CS
.getLanguageType() );
124 CPPUNIT_ASSERT( sr_Latn_CS
.isValidBcp47() );
125 CPPUNIT_ASSERT( !sr_Latn_CS
.isIsoLocale() );
126 CPPUNIT_ASSERT( sr_Latn_CS
.isIsoODF() );
127 CPPUNIT_ASSERT_EQUAL( OUString("sr"), sr_Latn_CS
.getLanguage() );
128 CPPUNIT_ASSERT_EQUAL( OUString("CS"), sr_Latn_CS
.getCountry() );
129 CPPUNIT_ASSERT_EQUAL( OUString("Latn"), sr_Latn_CS
.getScript() );
130 CPPUNIT_ASSERT_EQUAL( OUString("sr-Latn"), sr_Latn_CS
.getLanguageAndScript() );
131 ::std::vector
< OUString
> sr_Latn_CS_Fallbacks( sr_Latn_CS
.getFallbackStrings( true));
132 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(9), sr_Latn_CS_Fallbacks
.size());
133 CPPUNIT_ASSERT_EQUAL( OUString("sr-Latn-CS"), sr_Latn_CS_Fallbacks
[0]);
134 CPPUNIT_ASSERT_EQUAL( OUString("sr-Latn-YU"), sr_Latn_CS_Fallbacks
[1]);
135 CPPUNIT_ASSERT_EQUAL( OUString("sh-CS"), sr_Latn_CS_Fallbacks
[2]);
136 CPPUNIT_ASSERT_EQUAL( OUString("sh-YU"), sr_Latn_CS_Fallbacks
[3]);
137 CPPUNIT_ASSERT_EQUAL( OUString("sr-Latn"), sr_Latn_CS_Fallbacks
[4]);
138 CPPUNIT_ASSERT_EQUAL( OUString("sh"), sr_Latn_CS_Fallbacks
[5]);
139 CPPUNIT_ASSERT_EQUAL( OUString("sr-CS"), sr_Latn_CS_Fallbacks
[6]);
140 CPPUNIT_ASSERT_EQUAL( OUString("sr-YU"), sr_Latn_CS_Fallbacks
[7]);
141 CPPUNIT_ASSERT_EQUAL( OUString("sr"), sr_Latn_CS_Fallbacks
[8]);
142 CPPUNIT_ASSERT_EQUAL( OUString("sr-Latn-CS"), sr_Latn_CS
.makeFallback().getBcp47());
145 // 'sh-RS' has an internal override to 'sr-Latn-RS'
147 OUString
const s_sh_RS( "sh-RS" );
148 LanguageTag
sh_RS( s_sh_RS
, true );
149 lang::Locale aLocale
= sh_RS
.getLocale();
150 CPPUNIT_ASSERT_EQUAL( OUString("sr-Latn-RS"), sh_RS
.getBcp47() );
151 CPPUNIT_ASSERT_EQUAL( OUString(I18NLANGTAG_QLT
) , aLocale
.Language
);
152 CPPUNIT_ASSERT_EQUAL( OUString("RS"), aLocale
.Country
);
153 CPPUNIT_ASSERT_EQUAL( OUString("sr-Latn-RS"), aLocale
.Variant
);
154 CPPUNIT_ASSERT_EQUAL( LANGUAGE_USER_SERBIAN_LATIN_SERBIA
, sh_RS
.getLanguageType() );
155 CPPUNIT_ASSERT( sh_RS
.isValidBcp47() );
156 CPPUNIT_ASSERT( !sh_RS
.isIsoLocale() );
157 CPPUNIT_ASSERT( sh_RS
.isIsoODF() );
158 CPPUNIT_ASSERT_EQUAL( OUString("sr"), sh_RS
.getLanguage() );
159 CPPUNIT_ASSERT_EQUAL( OUString("RS"), sh_RS
.getCountry() );
160 CPPUNIT_ASSERT_EQUAL( OUString("Latn"), sh_RS
.getScript() );
161 CPPUNIT_ASSERT_EQUAL( OUString("sr-Latn"), sh_RS
.getLanguageAndScript() );
162 ::std::vector
< OUString
> sh_RS_Fallbacks( sh_RS
.getFallbackStrings( true));
163 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(6), sh_RS_Fallbacks
.size());
164 CPPUNIT_ASSERT_EQUAL( OUString("sr-Latn-RS"), sh_RS_Fallbacks
[0]);
165 CPPUNIT_ASSERT_EQUAL( OUString("sh-RS"), sh_RS_Fallbacks
[1]);
166 CPPUNIT_ASSERT_EQUAL( OUString("sr-Latn"), sh_RS_Fallbacks
[2]);
167 CPPUNIT_ASSERT_EQUAL( OUString("sh"), sh_RS_Fallbacks
[3]);
168 CPPUNIT_ASSERT_EQUAL( OUString("sr-RS"), sh_RS_Fallbacks
[4]);
169 CPPUNIT_ASSERT_EQUAL( OUString("sr"), sh_RS_Fallbacks
[5]);
170 CPPUNIT_ASSERT_EQUAL( OUString("sr-Latn-RS"), sh_RS
.makeFallback().getBcp47());
171 CPPUNIT_ASSERT_EQUAL( OUString("sr-Latn-RS"), sh_RS
.getBcp47());
172 CPPUNIT_ASSERT_EQUAL( LANGUAGE_USER_SERBIAN_LATIN_SERBIA
, sh_RS
.getLanguageType() );
175 // 'bs-Latn-BA' with 'Latn' suppress-script, we map that ourselves for a
176 // known LangID with an override and canonicalization should work the same
177 // without liblangtag.
179 OUString
const s_bs_Latn_BA( "bs-Latn-BA" );
180 LanguageTag
bs_Latn_BA( s_bs_Latn_BA
, true );
181 lang::Locale aLocale
= bs_Latn_BA
.getLocale();
182 CPPUNIT_ASSERT_EQUAL( OUString("bs-BA"), bs_Latn_BA
.getBcp47() );
183 CPPUNIT_ASSERT_EQUAL( OUString("bs"), aLocale
.Language
);
184 CPPUNIT_ASSERT_EQUAL( OUString("BA"), aLocale
.Country
);
185 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
186 CPPUNIT_ASSERT_EQUAL( LANGUAGE_BOSNIAN_LATIN_BOSNIA_HERZEGOVINA
, bs_Latn_BA
.getLanguageType() );
187 CPPUNIT_ASSERT( bs_Latn_BA
.isValidBcp47() );
188 CPPUNIT_ASSERT( bs_Latn_BA
.isIsoLocale() );
189 CPPUNIT_ASSERT( bs_Latn_BA
.isIsoODF() );
190 CPPUNIT_ASSERT_EQUAL( OUString("bs"), bs_Latn_BA
.getLanguage() );
191 CPPUNIT_ASSERT_EQUAL( OUString("BA"), bs_Latn_BA
.getCountry() );
192 CPPUNIT_ASSERT( bs_Latn_BA
.getScript().isEmpty() );
193 CPPUNIT_ASSERT_EQUAL( OUString("bs"), bs_Latn_BA
.getLanguageAndScript() );
194 ::std::vector
< OUString
> bs_Latn_BA_Fallbacks( bs_Latn_BA
.getFallbackStrings( true));
195 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(2), bs_Latn_BA_Fallbacks
.size());
196 CPPUNIT_ASSERT_EQUAL( OUString("bs-BA"), bs_Latn_BA_Fallbacks
[0]);
197 CPPUNIT_ASSERT_EQUAL( OUString("bs"), bs_Latn_BA_Fallbacks
[1]);
198 CPPUNIT_ASSERT_EQUAL( OUString("bs-BA"), bs_Latn_BA
.makeFallback().getBcp47());
199 CPPUNIT_ASSERT_EQUAL( OUString("bs-BA"), bs_Latn_BA
.getBcp47());
200 CPPUNIT_ASSERT_EQUAL( LANGUAGE_BOSNIAN_LATIN_BOSNIA_HERZEGOVINA
, bs_Latn_BA
.getLanguageType() );
204 OUString
s_ca_ES_valencia( "ca-ES-valencia" );
205 LanguageTag
ca_ES_valencia( s_ca_ES_valencia
, true );
206 lang::Locale aLocale
= ca_ES_valencia
.getLocale();
207 CPPUNIT_ASSERT_EQUAL( s_ca_ES_valencia
, ca_ES_valencia
.getBcp47() );
208 CPPUNIT_ASSERT_EQUAL( OUString("qlt"), aLocale
.Language
);
209 CPPUNIT_ASSERT_EQUAL( OUString("ES"), aLocale
.Country
);
210 CPPUNIT_ASSERT_EQUAL( s_ca_ES_valencia
, aLocale
.Variant
);
211 CPPUNIT_ASSERT_EQUAL( LANGUAGE_CATALAN_VALENCIAN
, ca_ES_valencia
.getLanguageType() );
212 CPPUNIT_ASSERT( ca_ES_valencia
.isValidBcp47() );
213 CPPUNIT_ASSERT( !ca_ES_valencia
.isIsoLocale() );
214 CPPUNIT_ASSERT( !ca_ES_valencia
.isIsoODF() );
215 CPPUNIT_ASSERT_EQUAL( OUString("ca"), ca_ES_valencia
.getLanguage() );
216 CPPUNIT_ASSERT_EQUAL( OUString("ES"), ca_ES_valencia
.getCountry() );
217 CPPUNIT_ASSERT( ca_ES_valencia
.getScript().isEmpty() );
218 CPPUNIT_ASSERT_EQUAL( OUString("ca"), ca_ES_valencia
.getLanguageAndScript() );
219 ::std::vector
< OUString
> ca_ES_valencia_Fallbacks( ca_ES_valencia
.getFallbackStrings( true));
220 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(5), ca_ES_valencia_Fallbacks
.size());
221 CPPUNIT_ASSERT_EQUAL( OUString("ca-ES-valencia"), ca_ES_valencia_Fallbacks
[0]);
222 CPPUNIT_ASSERT_EQUAL( OUString("ca-XV"), ca_ES_valencia_Fallbacks
[1]);
223 CPPUNIT_ASSERT_EQUAL( OUString("ca-valencia"), ca_ES_valencia_Fallbacks
[2]);
224 CPPUNIT_ASSERT_EQUAL( OUString("ca-ES"), ca_ES_valencia_Fallbacks
[3]);
225 CPPUNIT_ASSERT_EQUAL( OUString("ca"), ca_ES_valencia_Fallbacks
[4]);
226 CPPUNIT_ASSERT_EQUAL( OUString("ca-ES-valencia"), ca_ES_valencia
.makeFallback().getBcp47());
230 OUString
s_ca_valencia( "ca-valencia" );
231 LanguageTag
ca_valencia( s_ca_valencia
, true );
232 lang::Locale aLocale
= ca_valencia
.getLocale();
233 CPPUNIT_ASSERT_EQUAL( s_ca_valencia
, ca_valencia
.getBcp47() );
234 CPPUNIT_ASSERT_EQUAL( OUString("qlt"), aLocale
.Language
);
235 CPPUNIT_ASSERT( aLocale
.Country
.isEmpty() );
236 CPPUNIT_ASSERT_EQUAL( s_ca_valencia
, aLocale
.Variant
);
237 CPPUNIT_ASSERT( LanguageTag::isOnTheFlyID( ca_valencia
.getLanguageType()) );
238 CPPUNIT_ASSERT( ca_valencia
.isValidBcp47() );
239 CPPUNIT_ASSERT( !ca_valencia
.isIsoLocale() );
240 CPPUNIT_ASSERT( !ca_valencia
.isIsoODF() );
241 CPPUNIT_ASSERT_EQUAL( OUString("ca"), ca_valencia
.getLanguage() );
242 CPPUNIT_ASSERT( ca_valencia
.getCountry().isEmpty() );
243 CPPUNIT_ASSERT( ca_valencia
.getScript().isEmpty() );
244 CPPUNIT_ASSERT_EQUAL( OUString("ca"), ca_valencia
.getLanguageAndScript() );
245 ::std::vector
< OUString
> ca_valencia_Fallbacks( ca_valencia
.getFallbackStrings( true));
246 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(2), ca_valencia_Fallbacks
.size());
247 CPPUNIT_ASSERT_EQUAL( OUString("ca-valencia"), ca_valencia_Fallbacks
[0]);
248 CPPUNIT_ASSERT_EQUAL( OUString("ca"), ca_valencia_Fallbacks
[1]);
249 CPPUNIT_ASSERT_EQUAL( OUString("ca-ES-valencia"), ca_valencia
.makeFallback().getBcp47());
252 // 'ca-XV' has an internal override to 'ca-ES-valencia'
254 OUString
const s_ca_XV( "ca-XV" );
255 OUString
s_ca_ES_valencia( "ca-ES-valencia" );
256 LanguageTag
ca_XV( s_ca_XV
, true );
257 lang::Locale aLocale
= ca_XV
.getLocale();
258 CPPUNIT_ASSERT_EQUAL( s_ca_ES_valencia
, ca_XV
.getBcp47() );
259 CPPUNIT_ASSERT_EQUAL( OUString(I18NLANGTAG_QLT
) , aLocale
.Language
);
260 CPPUNIT_ASSERT_EQUAL( OUString("ES"), aLocale
.Country
);
261 CPPUNIT_ASSERT_EQUAL( s_ca_ES_valencia
, aLocale
.Variant
);
262 CPPUNIT_ASSERT_EQUAL( LANGUAGE_CATALAN_VALENCIAN
, ca_XV
.getLanguageType() );
263 CPPUNIT_ASSERT( ca_XV
.isValidBcp47() );
264 CPPUNIT_ASSERT( !ca_XV
.isIsoLocale() );
265 CPPUNIT_ASSERT( !ca_XV
.isIsoODF() );
266 CPPUNIT_ASSERT_EQUAL( OUString("ca"), ca_XV
.getLanguage() );
267 CPPUNIT_ASSERT_EQUAL( OUString("ES"), ca_XV
.getCountry() );
268 CPPUNIT_ASSERT( ca_XV
.getScript().isEmpty() );
269 CPPUNIT_ASSERT_EQUAL( OUString("ca"), ca_XV
.getLanguageAndScript() );
270 ::std::vector
< OUString
> ca_XV_Fallbacks( ca_XV
.getFallbackStrings( true));
271 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(5), ca_XV_Fallbacks
.size());
272 CPPUNIT_ASSERT_EQUAL( OUString("ca-ES-valencia"), ca_XV_Fallbacks
[0]);
273 CPPUNIT_ASSERT_EQUAL( OUString("ca-XV"), ca_XV_Fallbacks
[1]);
274 CPPUNIT_ASSERT_EQUAL( OUString("ca-valencia"), ca_XV_Fallbacks
[2]);
275 CPPUNIT_ASSERT_EQUAL( OUString("ca-ES"), ca_XV_Fallbacks
[3]);
276 CPPUNIT_ASSERT_EQUAL( OUString("ca"), ca_XV_Fallbacks
[4]);
277 CPPUNIT_ASSERT_EQUAL( OUString("ca-ES-valencia"), ca_XV
.makeFallback().getBcp47());
281 OUString
s_de_DE( "de-DE" );
282 LanguageTag
de_DE( s_de_DE
, true );
283 lang::Locale aLocale
= de_DE
.getLocale();
284 CPPUNIT_ASSERT_EQUAL( s_de_DE
, de_DE
.getBcp47() );
285 CPPUNIT_ASSERT_EQUAL( OUString("de"), aLocale
.Language
);
286 CPPUNIT_ASSERT_EQUAL( OUString("DE"), aLocale
.Country
);
287 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
288 CPPUNIT_ASSERT_EQUAL( LANGUAGE_GERMAN
, de_DE
.getLanguageType() );
289 CPPUNIT_ASSERT( de_DE
.isValidBcp47() );
290 CPPUNIT_ASSERT( de_DE
.isIsoLocale() );
291 CPPUNIT_ASSERT( de_DE
.isIsoODF() );
292 CPPUNIT_ASSERT_EQUAL( OUString("de"), de_DE
.getLanguage() );
293 CPPUNIT_ASSERT_EQUAL( OUString("DE"), de_DE
.getCountry() );
294 CPPUNIT_ASSERT( de_DE
.getScript().isEmpty() );
295 CPPUNIT_ASSERT_EQUAL( OUString("de"), de_DE
.getLanguageAndScript() );
296 ::std::vector
< OUString
> de_DE_Fallbacks( de_DE
.getFallbackStrings( true));
297 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(2), de_DE_Fallbacks
.size());
298 CPPUNIT_ASSERT_EQUAL( OUString("de-DE"), de_DE_Fallbacks
[0]);
299 CPPUNIT_ASSERT_EQUAL( OUString("de"), de_DE_Fallbacks
[1]);
300 CPPUNIT_ASSERT_EQUAL( OUString("de-DE"), de_DE
.makeFallback().getBcp47());
304 OUString
const s_de_DE( "de-DE" );
305 LanguageTag
de_DE( lang::Locale( "de", "DE", "" ) );
306 lang::Locale aLocale
= de_DE
.getLocale();
307 CPPUNIT_ASSERT_EQUAL( s_de_DE
, de_DE
.getBcp47() );
308 CPPUNIT_ASSERT_EQUAL( OUString("de"), aLocale
.Language
);
309 CPPUNIT_ASSERT_EQUAL( OUString("DE"), aLocale
.Country
);
310 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
311 CPPUNIT_ASSERT_EQUAL( LANGUAGE_GERMAN
, de_DE
.getLanguageType() );
315 OUString
const s_de_DE( "de-DE" );
316 LanguageTag
de_DE( LANGUAGE_GERMAN
);
317 lang::Locale aLocale
= de_DE
.getLocale();
318 CPPUNIT_ASSERT_EQUAL( s_de_DE
, de_DE
.getBcp47() );
319 CPPUNIT_ASSERT_EQUAL( OUString("de"), aLocale
.Language
);
320 CPPUNIT_ASSERT_EQUAL( OUString("DE"), aLocale
.Country
);
321 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
322 CPPUNIT_ASSERT_EQUAL( LANGUAGE_GERMAN
, de_DE
.getLanguageType() );
325 // Unmapped but known language-only.
327 OUString
s_de( "de" );
328 LanguageTag
de( s_de
, true );
329 lang::Locale aLocale
= de
.getLocale();
330 CPPUNIT_ASSERT_EQUAL( s_de
, de
.getBcp47() );
331 CPPUNIT_ASSERT_EQUAL( OUString("de"), aLocale
.Language
);
332 CPPUNIT_ASSERT( aLocale
.Country
.isEmpty() );
333 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
334 LanguageType de_LangID
= de
.getLanguageType();
335 CPPUNIT_ASSERT( de_LangID
!= LANGUAGE_GERMAN
);
336 CPPUNIT_ASSERT_EQUAL( MsLangId::getPrimaryLanguage( LANGUAGE_GERMAN
) , de_LangID
);
337 CPPUNIT_ASSERT_EQUAL( OUString("de-DE"), de
.makeFallback().getBcp47());
338 // Check registered mapping.
339 LanguageTag
de_l( de_LangID
);
340 CPPUNIT_ASSERT_EQUAL( s_de
, de_l
.getBcp47() );
343 // "bo" and "dz" share the same primary language ID, only one gets it
344 // assigned, "dz" language-only has a special mapping.
346 LanguageTag
bo( "bo", true );
347 CPPUNIT_ASSERT_EQUAL( MsLangId::getPrimaryLanguage( LANGUAGE_TIBETAN
), bo
.getLanguageType() );
348 LanguageTag
dz( "dz", true );
349 CPPUNIT_ASSERT_EQUAL( LANGUAGE_USER_DZONGKHA_MAP_LONLY
, dz
.getLanguageType() );
352 // "no", "nb" and "nn" share the same primary language ID, which even is
353 // assigned to "no-NO" for legacy so none gets it assigned, all on-the-fly
354 // except if there is a defined MS-LCID for LanguageScriptOnly (LSO).
356 LanguageTag
no( "no", true );
357 CPPUNIT_ASSERT( LanguageTag::isOnTheFlyID( no
.getLanguageType()) );
358 LanguageTag
nb( "nb", true );
359 CPPUNIT_ASSERT_EQUAL( LANGUAGE_NORWEGIAN_BOKMAL_LSO
, nb
.getLanguageType() );
360 LanguageTag
nn( "nn", true );
361 CPPUNIT_ASSERT_EQUAL( LANGUAGE_NORWEGIAN_NYNORSK_LSO
, nn
.getLanguageType() );
362 LanguageTag
no_NO( "no-NO", true );
363 CPPUNIT_ASSERT_EQUAL( LANGUAGE_NORWEGIAN
, no_NO
.getLanguageType() );
366 // 'de-1901' derived from 'de-DE-1901' grandfathered to check that it is
367 // accepted as (DIGIT 3ALNUM) variant
369 OUString
s_de_1901( "de-1901" );
370 LanguageTag
de_1901( s_de_1901
);
371 lang::Locale aLocale
= de_1901
.getLocale();
372 CPPUNIT_ASSERT_EQUAL( s_de_1901
, de_1901
.getBcp47() );
373 CPPUNIT_ASSERT_EQUAL( OUString("qlt"), aLocale
.Language
);
374 CPPUNIT_ASSERT( aLocale
.Country
.isEmpty() );
375 CPPUNIT_ASSERT_EQUAL( s_de_1901
, aLocale
.Variant
);
376 CPPUNIT_ASSERT( LanguageTag::isOnTheFlyID( de_1901
.getLanguageType()) );
377 CPPUNIT_ASSERT( de_1901
.isValidBcp47() );
378 CPPUNIT_ASSERT( !de_1901
.isIsoLocale() );
379 CPPUNIT_ASSERT( !de_1901
.isIsoODF() );
380 CPPUNIT_ASSERT_EQUAL( OUString("de"), de_1901
.getLanguageAndScript() );
381 CPPUNIT_ASSERT_EQUAL( OUString("1901"), de_1901
.getVariants() );
382 ::std::vector
< OUString
> de_1901_Fallbacks( de_1901
.getFallbackStrings( true));
383 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(2), de_1901_Fallbacks
.size());
384 CPPUNIT_ASSERT_EQUAL( OUString("de-1901"), de_1901_Fallbacks
[0]);
385 CPPUNIT_ASSERT_EQUAL( OUString("de"), de_1901_Fallbacks
[1]);
388 // 'en-GB-oed' is known grandfathered for English, Oxford English
389 // Dictionary spelling.
390 // Deprecated as of 2015-04-17, prefer en-GB-oxendict instead.
391 // As of 2017-03-14 we also alias to en-GB-oxendict.
393 OUString
s_en_GB_oxendict( "en-GB-oxendict" );
394 LanguageTag
en_GB_oed( "en-GB-oed" );
395 lang::Locale aLocale
= en_GB_oed
.getLocale();
396 CPPUNIT_ASSERT_EQUAL( s_en_GB_oxendict
, en_GB_oed
.getBcp47() );
397 CPPUNIT_ASSERT_EQUAL( OUString("qlt"), aLocale
.Language
);
398 CPPUNIT_ASSERT_EQUAL( OUString("GB"), aLocale
.Country
);
399 CPPUNIT_ASSERT_EQUAL( s_en_GB_oxendict
, aLocale
.Variant
);
400 CPPUNIT_ASSERT_EQUAL( LANGUAGE_USER_ENGLISH_UK_OXENDICT
, en_GB_oed
.getLanguageType() );
401 CPPUNIT_ASSERT( en_GB_oed
.isValidBcp47() );
402 CPPUNIT_ASSERT( !en_GB_oed
.isIsoLocale() );
403 CPPUNIT_ASSERT( !en_GB_oed
.isIsoODF() );
404 CPPUNIT_ASSERT_EQUAL( OUString("en"), en_GB_oed
.getLanguageAndScript() );
405 CPPUNIT_ASSERT_EQUAL( OUString("oxendict"), en_GB_oed
.getVariants() );
406 ::std::vector
< OUString
> en_GB_oed_Fallbacks( en_GB_oed
.getFallbackStrings( true));
407 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(5), en_GB_oed_Fallbacks
.size() );
408 CPPUNIT_ASSERT_EQUAL( OUString("en-GB-oxendict"), en_GB_oed_Fallbacks
[0]);
409 CPPUNIT_ASSERT_EQUAL( OUString("en-GB-oed"), en_GB_oed_Fallbacks
[1]);
410 CPPUNIT_ASSERT_EQUAL( OUString("en-oxendict"), en_GB_oed_Fallbacks
[2]);
411 CPPUNIT_ASSERT_EQUAL( OUString("en-GB"), en_GB_oed_Fallbacks
[3]);
412 CPPUNIT_ASSERT_EQUAL( OUString("en"), en_GB_oed_Fallbacks
[4]);
413 // 'en-oed' is not a valid fallback!
416 // 'en-GB-oxendict' as preferred over 'en-GB-oed'.
418 OUString
s_en_GB_oxendict( "en-GB-oxendict" );
419 LanguageTag
en_GB_oxendict( s_en_GB_oxendict
);
420 lang::Locale aLocale
= en_GB_oxendict
.getLocale();
421 CPPUNIT_ASSERT_EQUAL( s_en_GB_oxendict
, en_GB_oxendict
.getBcp47() );
422 CPPUNIT_ASSERT_EQUAL( OUString("qlt"), aLocale
.Language
);
423 CPPUNIT_ASSERT_EQUAL( OUString("GB"), aLocale
.Country
);
424 CPPUNIT_ASSERT_EQUAL( s_en_GB_oxendict
, aLocale
.Variant
);
425 CPPUNIT_ASSERT_EQUAL( LANGUAGE_USER_ENGLISH_UK_OXENDICT
, en_GB_oxendict
.getLanguageType() );
426 CPPUNIT_ASSERT( en_GB_oxendict
.isValidBcp47() );
427 CPPUNIT_ASSERT( !en_GB_oxendict
.isIsoLocale() );
428 CPPUNIT_ASSERT( !en_GB_oxendict
.isIsoODF() );
429 CPPUNIT_ASSERT_EQUAL( OUString("en"), en_GB_oxendict
.getLanguageAndScript() );
430 CPPUNIT_ASSERT_EQUAL( OUString("oxendict"), en_GB_oxendict
.getVariants() );
431 ::std::vector
< OUString
> en_GB_oxendict_Fallbacks( en_GB_oxendict
.getFallbackStrings( true));
432 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(5), en_GB_oxendict_Fallbacks
.size() );
433 CPPUNIT_ASSERT_EQUAL( OUString("en-GB-oxendict"), en_GB_oxendict_Fallbacks
[0]);
434 CPPUNIT_ASSERT_EQUAL( OUString("en-GB-oed"), en_GB_oxendict_Fallbacks
[1]);
435 CPPUNIT_ASSERT_EQUAL( OUString("en-oxendict"), en_GB_oxendict_Fallbacks
[2]);
436 CPPUNIT_ASSERT_EQUAL( OUString("en-GB"), en_GB_oxendict_Fallbacks
[3]);
437 CPPUNIT_ASSERT_EQUAL( OUString("en"), en_GB_oxendict_Fallbacks
[4]);
440 // 'es-ES-u-co-trad' is a valid (and known) Extension U tag
442 OUString
s_es_ES_u_co_trad( "es-ES-u-co-trad" );
443 LanguageTag
es_ES_u_co_trad( s_es_ES_u_co_trad
);
444 lang::Locale aLocale
= es_ES_u_co_trad
.getLocale();
445 CPPUNIT_ASSERT_EQUAL( s_es_ES_u_co_trad
, es_ES_u_co_trad
.getBcp47() );
446 CPPUNIT_ASSERT_EQUAL( OUString("qlt"), aLocale
.Language
);
447 CPPUNIT_ASSERT_EQUAL( OUString("ES"), aLocale
.Country
);
448 CPPUNIT_ASSERT_EQUAL( s_es_ES_u_co_trad
, aLocale
.Variant
);
449 CPPUNIT_ASSERT_EQUAL( LANGUAGE_SPANISH_DATED
, es_ES_u_co_trad
.getLanguageType() );
450 CPPUNIT_ASSERT( es_ES_u_co_trad
.isValidBcp47() );
451 CPPUNIT_ASSERT( !es_ES_u_co_trad
.isIsoLocale() );
452 CPPUNIT_ASSERT( !es_ES_u_co_trad
.isIsoODF() );
453 CPPUNIT_ASSERT_EQUAL( OUString("es"), es_ES_u_co_trad
.getLanguageAndScript() );
454 CPPUNIT_ASSERT_EQUAL( OUString("u-co-trad"), es_ES_u_co_trad
.getVariants() );
455 ::std::vector
< OUString
> es_ES_u_co_trad_Fallbacks( es_ES_u_co_trad
.getFallbackStrings( true));
456 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(4), es_ES_u_co_trad_Fallbacks
.size() );
457 CPPUNIT_ASSERT_EQUAL( OUString("es-ES-u-co-trad"), es_ES_u_co_trad_Fallbacks
[0]);
458 CPPUNIT_ASSERT_EQUAL( OUString("es-u-co-trad"), es_ES_u_co_trad_Fallbacks
[1]);
459 CPPUNIT_ASSERT_EQUAL( OUString("es-ES"), es_ES_u_co_trad_Fallbacks
[2]);
460 CPPUNIT_ASSERT_EQUAL( OUString("es"), es_ES_u_co_trad_Fallbacks
[3]);
462 CPPUNIT_ASSERT_EQUAL( OUString("es-ES_tradnl"), es_ES_u_co_trad
.getBcp47MS() );
465 // 'es-ES_tradnl' (broken MS) maps to 'es-ES-u-co-trad'
467 OUString
s_es_ES_u_co_trad( "es-ES-u-co-trad" );
468 OUString
s_es_ES_tradnl( "es-ES_tradnl" );
469 LanguageTag
es_ES_tradnl( s_es_ES_tradnl
);
470 lang::Locale aLocale
= es_ES_tradnl
.getLocale();
471 CPPUNIT_ASSERT_EQUAL( s_es_ES_u_co_trad
, es_ES_tradnl
.getBcp47() );
472 CPPUNIT_ASSERT_EQUAL( OUString("qlt"), aLocale
.Language
);
473 CPPUNIT_ASSERT_EQUAL( OUString("ES"), aLocale
.Country
);
474 CPPUNIT_ASSERT_EQUAL( s_es_ES_u_co_trad
, aLocale
.Variant
);
475 CPPUNIT_ASSERT_EQUAL( LANGUAGE_SPANISH_DATED
, es_ES_tradnl
.getLanguageType() );
476 CPPUNIT_ASSERT( es_ES_tradnl
.isValidBcp47() );
477 CPPUNIT_ASSERT( !es_ES_tradnl
.isIsoLocale() );
478 CPPUNIT_ASSERT( !es_ES_tradnl
.isIsoODF() );
479 CPPUNIT_ASSERT_EQUAL( OUString("es"), es_ES_tradnl
.getLanguageAndScript() );
480 CPPUNIT_ASSERT_EQUAL( OUString("u-co-trad"), es_ES_tradnl
.getVariants() );
481 ::std::vector
< OUString
> es_ES_tradnl_Fallbacks( es_ES_tradnl
.getFallbackStrings( true));
482 CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(4), es_ES_tradnl_Fallbacks
.size() );
483 CPPUNIT_ASSERT_EQUAL( OUString("es-ES-u-co-trad"), es_ES_tradnl_Fallbacks
[0]);
484 CPPUNIT_ASSERT_EQUAL( OUString("es-u-co-trad"), es_ES_tradnl_Fallbacks
[1]);
485 CPPUNIT_ASSERT_EQUAL( OUString("es-ES"), es_ES_tradnl_Fallbacks
[2]);
486 CPPUNIT_ASSERT_EQUAL( OUString("es"), es_ES_tradnl_Fallbacks
[3]);
487 // Map back to broken MS.
488 CPPUNIT_ASSERT_EQUAL( s_es_ES_tradnl
, es_ES_tradnl
.getBcp47MS() );
491 // 'zh-yue-HK' uses redundant 'zh-yue' and should be preferred 'yue-HK'
493 /* XXX Disabled because liblangtag in lt_tag_canonicalize() after replacing
494 * 'zh-yue' with the preferred 'yue' does:
495 * "If the language tag starts with a primary language subtag that is also
496 * an extlang subtag, then the language tag is prepended with the extlang's
498 * Primary language 'yue' is also extlang 'yue' for which the prefix
499 * happens to be 'zh' ... so the result is 'zh-yue-HK' again. */
501 OUString
s_zh_yue_HK( "zh-yue-HK" );
502 LanguageTag
zh_yue_HK( s_zh_yue_HK
);
503 lang::Locale aLocale
= zh_yue_HK
.getLocale();
504 CPPUNIT_ASSERT( zh_yue_HK
.getBcp47() == "yue-HK" );
505 CPPUNIT_ASSERT( aLocale
.Language
== "yue" );
506 CPPUNIT_ASSERT( aLocale
.Country
== "HK" );
507 CPPUNIT_ASSERT( aLocale
.Variant
== "" );
508 CPPUNIT_ASSERT( zh_yue_HK
.getLanguageType() == LANGUAGE_YUE_CHINESE_HONGKONG
);
509 CPPUNIT_ASSERT( zh_yue_HK
.isValidBcp47() == true );
510 CPPUNIT_ASSERT( zh_yue_HK
.isIsoLocale() == true );
511 CPPUNIT_ASSERT( zh_yue_HK
.isIsoODF() == true );
512 CPPUNIT_ASSERT( zh_yue_HK
.getLanguageAndScript() == "yue" );
513 CPPUNIT_ASSERT( zh_yue_HK
.getVariants() == "" );
514 ::std::vector
< OUString
> zh_yue_HK_Fallbacks( zh_yue_HK
.getFallbackStrings( true));
515 CPPUNIT_ASSERT( zh_yue_HK_Fallbacks
.size() == 2);
516 CPPUNIT_ASSERT( zh_yue_HK_Fallbacks
[0] == "yue-HK");
517 CPPUNIT_ASSERT( zh_yue_HK_Fallbacks
[1] == "yue");
521 // 'qtz' is a local use known pseudolocale for key ID resource
523 OUString
s_qtz( "qtz" );
524 LanguageTag
qtz( s_qtz
);
525 lang::Locale aLocale
= qtz
.getLocale();
526 CPPUNIT_ASSERT_EQUAL( s_qtz
, qtz
.getBcp47() );
527 CPPUNIT_ASSERT_EQUAL( OUString("qtz"), aLocale
.Language
);
528 CPPUNIT_ASSERT( aLocale
.Country
.isEmpty() );
529 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
530 CPPUNIT_ASSERT_EQUAL( LANGUAGE_USER_KEYID
, qtz
.getLanguageType() );
533 // 'qty' is a local use unknown locale
535 OUString
s_qty( "qty" );
536 LanguageTag
qty( s_qty
);
537 lang::Locale aLocale
= qty
.getLocale();
538 CPPUNIT_ASSERT_EQUAL( s_qty
, qty
.getBcp47() );
539 CPPUNIT_ASSERT_EQUAL( OUString("qty"), aLocale
.Language
);
540 CPPUNIT_ASSERT( aLocale
.Country
.isEmpty() );
541 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
542 CPPUNIT_ASSERT( LanguageTag::isOnTheFlyID( qty
.getLanguageType()) );
545 // 'qtx' is an unknown new mslangid
547 OUString
const s_qtx( "qtx" );
548 LanguageTag
qtx( s_qtx
);
549 qtx
.setScriptType( LanguageTag::ScriptType::RTL
);
550 LanguageType n_qtx
= qtx
.getLanguageType();
551 CPPUNIT_ASSERT_EQUAL( css::i18n::ScriptType::COMPLEX
, MsLangId::getScriptType(n_qtx
) );
552 CPPUNIT_ASSERT( MsLangId::isRightToLeft(n_qtx
) );
553 CPPUNIT_ASSERT( !MsLangId::isCJK(n_qtx
) );
556 // 'x-comment' is a privateuse known "locale"
558 OUString
s_xcomment( "x-comment" );
559 LanguageTag
xcomment( s_xcomment
);
560 lang::Locale aLocale
= xcomment
.getLocale();
561 CPPUNIT_ASSERT_EQUAL( s_xcomment
, xcomment
.getBcp47() );
562 CPPUNIT_ASSERT_EQUAL( OUString("qlt"), aLocale
.Language
);
563 CPPUNIT_ASSERT( aLocale
.Country
.isEmpty() );
564 CPPUNIT_ASSERT_EQUAL( OUString("x-comment"), aLocale
.Variant
);
565 CPPUNIT_ASSERT_EQUAL( LANGUAGE_USER_PRIV_COMMENT
, xcomment
.getLanguageType() );
568 // 'x-foobar' is a privateuse unknown "locale"
570 OUString
s_xfoobar( "x-foobar" );
571 LanguageTag
xfoobar( s_xfoobar
);
572 lang::Locale aLocale
= xfoobar
.getLocale();
573 CPPUNIT_ASSERT_EQUAL( s_xfoobar
, xfoobar
.getBcp47() );
574 CPPUNIT_ASSERT_EQUAL( OUString("qlt"), aLocale
.Language
);
575 CPPUNIT_ASSERT( aLocale
.Country
.isEmpty() );
576 CPPUNIT_ASSERT_EQUAL( OUString("x-foobar"), aLocale
.Variant
);
577 CPPUNIT_ASSERT( LanguageTag::isOnTheFlyID( xfoobar
.getLanguageType()) );
580 // '*' the dreaded jolly joker is a "privateuse" known "locale"
582 OUString
s_joker( "*" );
583 LanguageTag
joker( s_joker
);
584 lang::Locale aLocale
= joker
.getLocale();
585 CPPUNIT_ASSERT_EQUAL( s_joker
, joker
.getBcp47() );
586 CPPUNIT_ASSERT_EQUAL( OUString("qlt"), aLocale
.Language
);
587 CPPUNIT_ASSERT( aLocale
.Country
.isEmpty() );
588 CPPUNIT_ASSERT_EQUAL( OUString("*"), aLocale
.Variant
);
589 CPPUNIT_ASSERT_EQUAL( LANGUAGE_USER_PRIV_JOKER
, joker
.getLanguageType() );
591 joker
.reset( LANGUAGE_USER_PRIV_JOKER
);
592 aLocale
= joker
.getLocale();
593 CPPUNIT_ASSERT_EQUAL( s_joker
, joker
.getBcp47() );
594 CPPUNIT_ASSERT_EQUAL( OUString("qlt"), aLocale
.Language
);
595 CPPUNIT_ASSERT( aLocale
.Country
.isEmpty() );
596 CPPUNIT_ASSERT_EQUAL( OUString("*"), aLocale
.Variant
);
597 CPPUNIT_ASSERT_EQUAL( LANGUAGE_USER_PRIV_JOKER
, joker
.getLanguageType() );
600 // 'C' locale shall map to 'en-US'
602 LanguageTag
aTag( "C" );
603 CPPUNIT_ASSERT_EQUAL( OUString("en"), aTag
.getLanguage() );
604 CPPUNIT_ASSERT_EQUAL( OUString("US"), aTag
.getCountry() );
605 lang::Locale aLocale
= aTag
.getLocale();
606 CPPUNIT_ASSERT_EQUAL( OUString("en-US"), aTag
.getBcp47() );
607 CPPUNIT_ASSERT_EQUAL( OUString("en"), aLocale
.Language
);
608 CPPUNIT_ASSERT_EQUAL( OUString("US"), aLocale
.Country
);
609 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
610 CPPUNIT_ASSERT_EQUAL( LANGUAGE_ENGLISH_US
, aTag
.getLanguageType() );
613 LanguageTag
aTag( lang::Locale("C","","") );
614 CPPUNIT_ASSERT_EQUAL( OUString("en"), aTag
.getLanguage() );
615 CPPUNIT_ASSERT_EQUAL( OUString("US"), aTag
.getCountry() );
616 lang::Locale aLocale
= aTag
.getLocale();
617 CPPUNIT_ASSERT_EQUAL( OUString("en-US"), aTag
.getBcp47() );
618 CPPUNIT_ASSERT_EQUAL( OUString("en"), aLocale
.Language
);
619 CPPUNIT_ASSERT_EQUAL( OUString("US"), aLocale
.Country
);
620 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
621 CPPUNIT_ASSERT_EQUAL( LANGUAGE_ENGLISH_US
, aTag
.getLanguageType() );
624 // test reset() methods
626 LanguageTag
aTag( LANGUAGE_DONTKNOW
);
627 lang::Locale aLocale
;
629 aTag
.reset( LANGUAGE_GERMAN
);
630 aLocale
= aTag
.getLocale();
631 CPPUNIT_ASSERT_EQUAL( OUString("de-DE"), aTag
.getBcp47() );
632 CPPUNIT_ASSERT_EQUAL( OUString("de"), aLocale
.Language
);
633 CPPUNIT_ASSERT_EQUAL( OUString("DE"), aLocale
.Country
);
634 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
635 CPPUNIT_ASSERT_EQUAL( LANGUAGE_GERMAN
, aTag
.getLanguageType() );
637 aTag
.reset( "en-US" );
638 aLocale
= aTag
.getLocale();
639 CPPUNIT_ASSERT_EQUAL( OUString("en-US"), aTag
.getBcp47() );
640 CPPUNIT_ASSERT_EQUAL( OUString("en"), aLocale
.Language
);
641 CPPUNIT_ASSERT_EQUAL( OUString("US"), aLocale
.Country
);
642 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
643 CPPUNIT_ASSERT_EQUAL( LANGUAGE_ENGLISH_US
, aTag
.getLanguageType() );
645 aTag
.reset( lang::Locale( "de", "DE", "" ) );
646 aLocale
= aTag
.getLocale();
647 CPPUNIT_ASSERT_EQUAL( OUString("de-DE"), aTag
.getBcp47() );
648 CPPUNIT_ASSERT_EQUAL( OUString("de"), aLocale
.Language
);
649 CPPUNIT_ASSERT_EQUAL( OUString("DE"), aLocale
.Country
);
650 CPPUNIT_ASSERT( aLocale
.Variant
.isEmpty() );
651 CPPUNIT_ASSERT_EQUAL( LANGUAGE_GERMAN
, aTag
.getLanguageType() );
655 OUString
s_uab( "unreg-and-bad" );
656 LanguageTag
uab( s_uab
, true );
657 lang::Locale aLocale
= uab
.getLocale();
658 CPPUNIT_ASSERT_EQUAL( s_uab
, uab
.getBcp47() );
659 CPPUNIT_ASSERT_EQUAL( OUString("qlt"), aLocale
.Language
);
660 CPPUNIT_ASSERT( aLocale
.Country
.isEmpty() );
661 CPPUNIT_ASSERT_EQUAL( s_uab
, aLocale
.Variant
);
662 CPPUNIT_ASSERT_EQUAL( LANGUAGE_DONTKNOW
, uab
.getLanguageType() );
663 CPPUNIT_ASSERT( !uab
.isValidBcp47() );
664 CPPUNIT_ASSERT( !uab
.isIsoLocale() );
665 CPPUNIT_ASSERT( !uab
.isIsoODF() );
668 // test static isValidBcp47() method
670 OUString aCanonicalized
;
671 CPPUNIT_ASSERT( LanguageTag::isValidBcp47( "en-US", &aCanonicalized
) && aCanonicalized
== "en-US" );
672 CPPUNIT_ASSERT( LanguageTag::isValidBcp47( "x-foobar", &aCanonicalized
) && aCanonicalized
== "x-foobar" );
673 CPPUNIT_ASSERT( LanguageTag::isValidBcp47( "qaa", &aCanonicalized
) && aCanonicalized
== "qaa" );
674 CPPUNIT_ASSERT( !LanguageTag::isValidBcp47( "unreg-and-bad", &aCanonicalized
) );
675 CPPUNIT_ASSERT( LanguageTag::isValidBcp47( "en-US", &aCanonicalized
, true) && aCanonicalized
== "en-US" );
676 CPPUNIT_ASSERT( !LanguageTag::isValidBcp47( "x-foobar", &aCanonicalized
, true) && aCanonicalized
== "x-foobar" );
677 CPPUNIT_ASSERT( LanguageTag::isValidBcp47( "qaa", &aCanonicalized
, true) && aCanonicalized
== "qaa" );
678 CPPUNIT_ASSERT( LanguageTag::isValidBcp47( "de-Latn-DE", &aCanonicalized
) && aCanonicalized
== "de-DE" );
679 /* TODO: at least some (those we know) grandfathered tags should be
680 * recognized by the replacement code. */
681 CPPUNIT_ASSERT( LanguageTag::isValidBcp47( "en-GB-oed", &aCanonicalized
) );
682 // en-GB-oed has become deprecated in updated language-subtag-registry database
683 // (liblangtag 0.5.7)
684 CPPUNIT_ASSERT( ( aCanonicalized
== "en-GB-oxendict" ) || ( aCanonicalized
== "en-GB-oed" ) );
688 bool checkMapping( const OUString
& rStr1
, const OUString
& rStr2
)
690 if (rStr1
== "la-Latn" ) return rStr2
== "la";
691 if (rStr1
== "tzm-Latn-DZ" ) return rStr2
== "kab-DZ";
692 if (rStr1
== "bs-Latn-BA" ) return rStr2
== "bs-BA";
693 if (rStr1
== "bs-Latn" ) return rStr2
== "bs";
694 if (rStr1
== "cz" ) return rStr2
== "cs-CZ";
695 if (rStr1
== "iw-IL" ) return rStr2
== "he-IL";
696 if (rStr1
== "in-ID" ) return rStr2
== "id-ID";
697 if (rStr1
== "sr-YU" ) return rStr2
== "sr-CS";
698 if (rStr1
== "sh-RS" ) return rStr2
== "sr-Latn-RS";
699 if (rStr1
== "sh-YU" ) return rStr2
== "sr-Latn-CS";
700 if (rStr1
== "sh-CS" ) return rStr2
== "sr-Latn-CS";
701 if (rStr1
== "sh-ME" ) return rStr2
== "sr-Latn-ME";
702 if (rStr1
== "sh-BA" ) return rStr2
== "sr-Latn-BA";
703 if (rStr1
== "sh" ) return rStr2
== "sr-Latn";
704 if (rStr1
== "lah-PK" ) return rStr2
== "pnb-Arab-PK";
705 if (rStr1
== "pa-PK" ) return rStr2
== "pnb-Arab-PK";
706 if (rStr1
== "ca-XV" ) return rStr2
== "ca-ES-valencia";
707 if (rStr1
== "qcv-ES" ) return rStr2
== "ca-ES-valencia";
708 if (rStr1
== "ns-ZA" ) return rStr2
== "nso-ZA";
709 if (rStr1
== "ven-ZA" ) return rStr2
== "ve-ZA";
710 if (rStr1
== "qu-EC" ) return rStr2
== "quz-EC";
711 if (rStr1
== "qu-PE" ) return rStr2
== "quz-PE";
712 if (rStr1
== "ff-NG" ) return rStr2
== "fuv-NG";
713 if (rStr1
== "ji-IL" ) return rStr2
== "yi-IL";
714 if (rStr1
== "iu-CA" ) return rStr2
== "iu-Latn-CA";
715 if (rStr1
== "iu" ) return rStr2
== "iu-Latn";
716 if (rStr1
== "gbz-AF" ) return rStr2
== "prs-AF";
717 if (rStr1
== "ber-DZ" ) return rStr2
== "kab-DZ";
718 if (rStr1
== "tmz-MA" ) return rStr2
== "tzm-Tfng-MA";
719 if (rStr1
== "ber-MA" ) return rStr2
== "tzm-Tfng-MA";
720 if (rStr1
== "mg-MG" ) return rStr2
== "plt-MG";
721 if (rStr1
== "pli" ) return rStr2
== "pi-Latn";
722 if (rStr1
== "ks" ) return rStr2
== "ks-Arab";
723 if (rStr1
== "chr-US" ) return rStr2
== "chr-Cher-US";
724 if (rStr1
== "sd-PK" ) return rStr2
== "sd-Arab-PK";
725 if (rStr1
== "sr-Cyrl-RS" ) return rStr2
== "sr-RS";
726 if (rStr1
== "sr-Cyrl-ME" ) return rStr2
== "sr-ME";
727 if (rStr1
== "sr-Cyrl-BA" ) return rStr2
== "sr-BA";
728 if (rStr1
== "sr-Cyrl-CS" ) return rStr2
== "sr-CS";
729 if (rStr1
== "sr-Cyrl" ) return rStr2
== "sr";
730 if (rStr1
== "yi-Hebr-US" ) return rStr2
== "yi-US";
731 if (rStr1
== "yi-Hebr-IL" ) return rStr2
== "yi-IL";
732 if (rStr1
== "ha-NG" ) return rStr2
== "ha-Latn-NG";
733 if (rStr1
== "ha-GH" ) return rStr2
== "ha-Latn-GH";
734 if (rStr1
== "ku-Arab-IQ" ) return rStr2
== "ckb-IQ";
735 if (rStr1
== "ku-Arab" ) return rStr2
== "ckb";
736 if (rStr1
== "kmr-TR" ) return rStr2
== "kmr-Latn-TR";
737 if (rStr1
== "ku-TR" ) return rStr2
== "kmr-Latn-TR";
738 if (rStr1
== "kmr-SY" ) return rStr2
== "kmr-Latn-SY";
739 if (rStr1
== "ku-SY" ) return rStr2
== "kmr-Latn-SY";
740 if (rStr1
== "ku-IQ" ) return rStr2
== "ckb-IQ";
741 if (rStr1
== "ku-IR" ) return rStr2
== "ckb-IR";
742 if (rStr1
== "eu" ) return rStr2
== "eu-ES";
743 if (rStr1
== "crk-Latn-CN" ) return rStr2
== "crk-Latn-CA";
744 if (rStr1
== "crk-Cans-CN" ) return rStr2
== "crk-Cans-CA";
745 if (rStr1
== "en-GB-oed" ) return rStr2
== "en-GB-oxendict";
746 if (rStr1
== "es-ES_tradnl") return rStr2
== "es-ES-u-co-trad";
747 if (rStr1
== "sd-IN" ) return rStr2
== "sd-Deva-IN";
748 return rStr1
== rStr2
;
751 void TestLanguageTag::testAllIsoLangEntries()
753 const ::std::vector
< MsLangId::LanguagetagMapping
> aList( MsLangId::getDefinedLanguagetags());
754 for (auto const& elem
: aList
)
757 if (elem
.maBcp47
== "la-VA")
761 LanguageTag
aTagString( elem
.maBcp47
, true);
762 LanguageTag
aTagID( elem
.mnLang
);
763 if (!checkMapping( elem
.maBcp47
, aTagString
.getBcp47()))
765 OString
aMessage( OUStringToOString( elem
.maBcp47
, RTL_TEXTENCODING_ASCII_US
));
766 aMessage
+= " -> " + OUStringToOString( aTagString
.getBcp47(), RTL_TEXTENCODING_ASCII_US
);
767 CPPUNIT_ASSERT_EQUAL_MESSAGE( aMessage
.getStr(), aTagString
.getBcp47(), elem
.maBcp47
);
769 if (elem
.maBcp47
!= aTagID
.getBcp47())
771 // There are multiple mappings, ID must be equal after conversions.
772 LanguageTag
aTagBack( aTagID
.getBcp47(), true);
773 if (aTagString
.getLanguageType() != aTagBack
.getLanguageType())
775 OString
aMessage( OUStringToOString( elem
.maBcp47
, RTL_TEXTENCODING_ASCII_US
));
776 aMessage
+= " " + OUStringToOString( aTagString
.getBcp47(), RTL_TEXTENCODING_ASCII_US
) + ": " +
777 OUStringToOString( aTagString
.getBcp47(), RTL_TEXTENCODING_ASCII_US
) + " " +
778 OString::number( static_cast<sal_uInt16
>(aTagString
.getLanguageType()), 16) +
779 " -> " + OUStringToOString( aTagBack
.getBcp47(), RTL_TEXTENCODING_ASCII_US
) + " " +
780 OString::number( static_cast<sal_uInt16
>(aTagBack
.getLanguageType()), 16);
781 CPPUNIT_ASSERT_EQUAL_MESSAGE( aMessage
.getStr(), aTagBack
.getLanguageType(), aTagString
.getLanguageType());
785 // This does not hold, there are cases like 'ar'
786 // LANGUAGE_ARABIC_PRIMARY_ONLY that when mapped back results in
787 // 'ar-SA' as default locale.
788 if (elem
.mnLang
!= aTagString
.getLanguageType())
790 // There are multiple mappings, string must be equal after conversions.
791 LanguageTag
aTagBack( aTagString
.getLanguageType());
792 if (aTagID
.getBcp47() != aTagBack
.getBcp47())
794 OString
aMessage( OUStringToOString( elem
.maBcp47
, RTL_TEXTENCODING_ASCII_US
));
795 aMessage
+= " " + OUStringToOString( aTagID
.getBcp47(), RTL_TEXTENCODING_ASCII_US
) +
796 " -> " + OUStringToOString( aTagBack
.getBcp47(), RTL_TEXTENCODING_ASCII_US
);
797 CPPUNIT_ASSERT_MESSAGE( aMessage
.getStr(), aTagID
.getBcp47() == aTagBack
.getBcp47());
803 // Uncommenting this makes the test break and output SAL_WARN/INFO
804 //CPPUNIT_ASSERT( true == false );
807 CPPUNIT_TEST_SUITE_REGISTRATION( TestLanguageTag
);
811 CPPUNIT_PLUGIN_IMPLEMENT();
813 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */