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 <sal/config.h>
21 #include <rtl/ustring.hxx>
22 #include <com/sun/star/i18n/ScriptType.hpp>
23 
24 #include <i18nlangtag/mslangid.hxx>
25 
26 // Only very limited few functions that are guaranteed to not be called from
27 // LanguageTag may use LanguageTag ...
28 #include <i18nlangtag/languagetag.hxx>
29 
30 
31 LanguageType MsLangId::nConfiguredSystemLanguage   = LANGUAGE_SYSTEM;
32 LanguageType MsLangId::nConfiguredSystemUILanguage = LANGUAGE_SYSTEM;
33 
34 LanguageType MsLangId::nConfiguredWesternFallback  = LANGUAGE_SYSTEM;
35 LanguageType MsLangId::nConfiguredAsianFallback    = LANGUAGE_SYSTEM;
36 LanguageType MsLangId::nConfiguredComplexFallback  = LANGUAGE_SYSTEM;
37 
38 // static
setConfiguredSystemLanguage(LanguageType nLang)39 void MsLangId::LanguageTagAccess::setConfiguredSystemLanguage( LanguageType nLang )
40 {
41     nConfiguredSystemLanguage = nLang;
42 }
43 
44 
45 // static
setConfiguredSystemUILanguage(LanguageType nLang)46 void MsLangId::setConfiguredSystemUILanguage( LanguageType nLang )
47 {
48     nConfiguredSystemUILanguage = nLang;
49 }
50 
51 // static
setConfiguredWesternFallback(LanguageType nLang)52 void MsLangId::setConfiguredWesternFallback( LanguageType nLang )
53 {
54     nConfiguredWesternFallback = nLang;
55 }
56 
57 // static
setConfiguredAsianFallback(LanguageType nLang)58 void MsLangId::setConfiguredAsianFallback( LanguageType nLang )
59 {
60     nConfiguredAsianFallback = nLang;
61 }
62 
63 // static
setConfiguredComplexFallback(LanguageType nLang)64 void MsLangId::setConfiguredComplexFallback( LanguageType nLang )
65 {
66     nConfiguredComplexFallback = nLang;
67 }
68 
69 // static
simplifySystemLanguages(LanguageType nLang)70 inline LanguageType MsLangId::simplifySystemLanguages( LanguageType nLang )
71 {
72     if (nLang.anyOf( LANGUAGE_PROCESS_OR_USER_DEFAULT,
73         LANGUAGE_SYSTEM_DEFAULT,
74         LANGUAGE_SYSTEM))
75         nLang = LANGUAGE_SYSTEM;
76     return nLang;
77 }
78 
79 // static
getRealLanguage(LanguageType nLang)80 LanguageType MsLangId::getRealLanguage( LanguageType nLang )
81 {
82     LanguageType simplifyLang = simplifySystemLanguages( nLang);
83     if (simplifyLang == LANGUAGE_SYSTEM )
84     {
85         if (nConfiguredSystemLanguage == LANGUAGE_SYSTEM)
86             nLang = getSystemLanguage();
87         else
88             nLang = nConfiguredSystemLanguage;
89     }
90     else if (simplifyLang == LANGUAGE_HID_HUMAN_INTERFACE_DEVICE)
91     {
92         if (nConfiguredSystemUILanguage == LANGUAGE_SYSTEM)
93             nLang = getSystemUILanguage();
94         else
95             nLang = nConfiguredSystemUILanguage;
96     }
97     else
98     {
99         /* TODO: would this be useful here? */
100         //nLang = MsLangId::getReplacementForObsoleteLanguage( nLang);
101         ;   // nothing
102     }
103     if (nLang == LANGUAGE_DONTKNOW)
104         nLang = LANGUAGE_ENGLISH_US;
105     return nLang;
106 }
107 
108 
109 // static
resolveSystemLanguageByScriptType(LanguageType nLang,sal_Int16 nType)110 LanguageType MsLangId::resolveSystemLanguageByScriptType( LanguageType nLang, sal_Int16 nType )
111 {
112     if (nLang == LANGUAGE_NONE)
113         return nLang;
114 
115     nLang = getRealLanguage(nLang);
116     if (nType != css::i18n::ScriptType::WEAK && getScriptType(nLang) != nType)
117     {
118         switch(nType)
119         {
120             case css::i18n::ScriptType::ASIAN:
121                 if (nConfiguredAsianFallback == LANGUAGE_SYSTEM)
122                     nLang = LANGUAGE_CHINESE_SIMPLIFIED;
123                 else
124                     nLang = nConfiguredAsianFallback;
125                 break;
126             case css::i18n::ScriptType::COMPLEX:
127                 if (nConfiguredComplexFallback == LANGUAGE_SYSTEM)
128                     nLang = LANGUAGE_HINDI;
129                 else
130                     nLang = nConfiguredComplexFallback;
131                 break;
132             default:
133                 if (nConfiguredWesternFallback == LANGUAGE_SYSTEM)
134                     nLang = LANGUAGE_ENGLISH_US;
135                 else
136                     nLang = nConfiguredWesternFallback;
137                 break;
138         }
139     }
140     return nLang;
141 }
142 
143 
144 // static
convertLanguageToLocale(LanguageType nLang)145 css::lang::Locale MsLangId::Conversion::convertLanguageToLocale(
146         LanguageType nLang )
147 {
148     css::lang::Locale aLocale;
149     // Still resolve LANGUAGE_DONTKNOW if resolving is not requested,
150     // but not LANGUAGE_SYSTEM or others.
151     LanguageType nOrigLang = nLang;
152     nLang = MsLangId::getRealLanguage(nLang);
153     convertLanguageToLocaleImpl( nLang, aLocale, true );
154     if (aLocale.Language.isEmpty() && simplifySystemLanguages(nOrigLang) == LANGUAGE_SYSTEM)
155     {
156         // None found but resolve requested, last resort is "en-US".
157         aLocale.Language = "en";
158         aLocale.Country  = "US";
159         aLocale.Variant.clear();
160     }
161     return aLocale;
162 }
163 
164 
165 // static
convertLocaleToLanguage(const css::lang::Locale & rLocale)166 LanguageType MsLangId::Conversion::convertLocaleToLanguage(
167         const css::lang::Locale& rLocale )
168 {
169     // empty language => LANGUAGE_SYSTEM
170     if (rLocale.Language.isEmpty())
171         return LANGUAGE_SYSTEM;
172 
173     return convertLocaleToLanguageImpl( rLocale);
174 }
175 
176 
177 // static
getFallbackLocale(const css::lang::Locale & rLocale)178 css::lang::Locale MsLangId::getFallbackLocale(
179             const css::lang::Locale & rLocale )
180 {
181     // empty language => LANGUAGE_SYSTEM
182     if (rLocale.Language.isEmpty())
183         return Conversion::lookupFallbackLocale( Conversion::convertLanguageToLocale( LANGUAGE_SYSTEM ));
184     else
185         return Conversion::lookupFallbackLocale( rLocale);
186 }
187 
equalsPrimary(LanguageType lhs,LanguageType rhs)188 static constexpr bool equalsPrimary(LanguageType lhs, LanguageType rhs)
189 {
190     return (sal_uInt16(lhs) & LANGUAGE_MASK_PRIMARY )
191         == (sal_uInt16(rhs) & LANGUAGE_MASK_PRIMARY );
192 }
193 
194 // static
isRightToLeft(LanguageType nLang)195 bool MsLangId::isRightToLeft( LanguageType nLang )
196 {
197     if( equalsPrimary(nLang, LANGUAGE_ARABIC_SAUDI_ARABIA)
198         || equalsPrimary(nLang, LANGUAGE_HEBREW)
199         || equalsPrimary(nLang, LANGUAGE_YIDDISH)
200         || equalsPrimary(nLang, LANGUAGE_URDU_PAKISTAN)
201         || equalsPrimary(nLang, LANGUAGE_FARSI)
202         || equalsPrimary(nLang, LANGUAGE_KASHMIRI)
203         || equalsPrimary(nLang, LANGUAGE_SINDHI)
204         || equalsPrimary(nLang, LANGUAGE_UIGHUR_CHINA)
205         || equalsPrimary(nLang, LANGUAGE_USER_KYRGYZ_CHINA)
206         || equalsPrimary(nLang, LANGUAGE_USER_NKO) )
207     {
208         return true;
209     }
210     if (nLang.anyOf(
211         LANGUAGE_USER_KURDISH_IRAN,
212         LANGUAGE_OBSOLETE_USER_KURDISH_IRAQ,
213         LANGUAGE_KURDISH_ARABIC_IRAQ,
214         LANGUAGE_KURDISH_ARABIC_LSO,
215         LANGUAGE_USER_KURDISH_SOUTHERN_IRAN,
216         LANGUAGE_USER_KURDISH_SOUTHERN_IRAQ,
217         LANGUAGE_USER_HUNGARIAN_ROVAS,
218         LANGUAGE_USER_MALAY_ARABIC_MALAYSIA,
219         LANGUAGE_USER_MALAY_ARABIC_BRUNEI))
220     {
221             return true;
222     }
223     if (LanguageTag::isOnTheFlyID(nLang))
224         return LanguageTag::getOnTheFlyScriptType(nLang) == LanguageTag::ScriptType::RTL;
225     return false;
226 }
227 
228 // static
isRightToLeftMath(LanguageType nLang)229 bool MsLangId::isRightToLeftMath( LanguageType nLang )
230 {
231     //http://www.w3.org/TR/arabic-math/
232     if (nLang == LANGUAGE_FARSI || nLang == LANGUAGE_ARABIC_MOROCCO)
233         return false;
234     return isRightToLeft(nLang);
235 }
236 
237 // static
isSimplifiedChinese(LanguageType nLang)238 bool MsLangId::isSimplifiedChinese( LanguageType nLang )
239 {
240     return isChinese(nLang) && !isTraditionalChinese(nLang);
241 }
242 
243 // static
isSimplifiedChinese(const css::lang::Locale & rLocale)244 bool MsLangId::isSimplifiedChinese( const css::lang::Locale & rLocale )
245 {
246     return rLocale.Language == "zh" && !isTraditionalChinese(rLocale);
247 }
248 
249 // static
isTraditionalChinese(LanguageType nLang)250 bool MsLangId::isTraditionalChinese( LanguageType nLang )
251 {
252     return nLang.anyOf(
253          LANGUAGE_CHINESE_TRADITIONAL,
254          LANGUAGE_CHINESE_HONGKONG,
255          LANGUAGE_CHINESE_MACAU);
256 }
257 
258 // static
isTraditionalChinese(const css::lang::Locale & rLocale)259 bool MsLangId::isTraditionalChinese( const css::lang::Locale & rLocale )
260 {
261     return rLocale.Language == "zh" && (rLocale.Country == "TW" || rLocale.Country == "HK" || rLocale.Country == "MO");
262 }
263 
264 //static
isChinese(LanguageType nLang)265 bool MsLangId::isChinese( LanguageType nLang )
266 {
267     return MsLangId::getPrimaryLanguage(nLang) == MsLangId::getPrimaryLanguage(LANGUAGE_CHINESE) ||
268         MsLangId::getPrimaryLanguage(nLang) == MsLangId::getPrimaryLanguage(LANGUAGE_YUE_CHINESE_HONGKONG);
269 }
270 
271 //static
isKorean(LanguageType nLang)272 bool MsLangId::isKorean( LanguageType nLang )
273 {
274     return MsLangId::getPrimaryLanguage(nLang) == MsLangId::getPrimaryLanguage(LANGUAGE_KOREAN);
275 }
276 
277 // static
isCJK(LanguageType nLang)278 bool MsLangId::isCJK( LanguageType nLang )
279 {
280     if (primary(nLang).anyOf(
281          primary(LANGUAGE_CHINESE),
282          primary(LANGUAGE_YUE_CHINESE_HONGKONG),
283          primary(LANGUAGE_JAPANESE),
284          primary(LANGUAGE_KOREAN)))
285     {
286         return true;
287     }
288     if (LanguageTag::isOnTheFlyID(nLang))
289         return LanguageTag::getOnTheFlyScriptType(nLang) == LanguageTag::ScriptType::CJK;
290     return false;
291 }
292 
293 // static
isFamilyNameFirst(LanguageType nLang)294 bool MsLangId::isFamilyNameFirst( LanguageType nLang )
295 {
296     return isCJK(nLang) || nLang == LANGUAGE_HUNGARIAN;
297 }
298 
299 // static
hasForbiddenCharacters(LanguageType nLang)300 bool MsLangId::hasForbiddenCharacters( LanguageType nLang )
301 {
302     return isCJK(nLang);
303 }
304 
305 
306 // static
needsSequenceChecking(LanguageType nLang)307 bool MsLangId::needsSequenceChecking( LanguageType nLang )
308 {
309     return primary(nLang).anyOf(
310         primary(LANGUAGE_BURMESE),
311         primary(LANGUAGE_KHMER),
312         primary(LANGUAGE_LAO),
313         primary(LANGUAGE_THAI))
314         || nLang.anyOf(
315                 LANGUAGE_USER_PALI_THAI);
316 }
317 
318 
319 // static
getScriptType(LanguageType nLang)320 sal_Int16 MsLangId::getScriptType( LanguageType nLang )
321 {
322     sal_Int16 nScript;
323 
324         // CTL
325     if( nLang.anyOf(
326          LANGUAGE_MONGOLIAN_MONGOLIAN_MONGOLIA,
327          LANGUAGE_MONGOLIAN_MONGOLIAN_CHINA,
328          LANGUAGE_MONGOLIAN_MONGOLIAN_LSO,
329          LANGUAGE_USER_KURDISH_IRAN,
330          LANGUAGE_OBSOLETE_USER_KURDISH_IRAQ,
331          LANGUAGE_KURDISH_ARABIC_IRAQ,
332          LANGUAGE_KURDISH_ARABIC_LSO,
333          LANGUAGE_USER_KURDISH_SOUTHERN_IRAN,
334          LANGUAGE_USER_KURDISH_SOUTHERN_IRAQ,
335          LANGUAGE_USER_KYRGYZ_CHINA,
336          LANGUAGE_USER_HUNGARIAN_ROVAS,
337          LANGUAGE_USER_MANCHU,
338          LANGUAGE_USER_XIBE,
339          LANGUAGE_USER_MALAY_ARABIC_MALAYSIA,
340          LANGUAGE_USER_MALAY_ARABIC_BRUNEI,
341          LANGUAGE_USER_PALI_THAI))
342     {
343             nScript = css::i18n::ScriptType::COMPLEX;
344     }
345         // "Western"
346     else if (nLang.anyOf(
347         LANGUAGE_MONGOLIAN_CYRILLIC_MONGOLIA,
348         LANGUAGE_MONGOLIAN_CYRILLIC_LSO,
349         LANGUAGE_USER_KURDISH_SYRIA,
350         LANGUAGE_USER_KURDISH_TURKEY))
351     {
352             nScript = css::i18n::ScriptType::LATIN;
353     }
354 // currently not knowing scripttype - defaulted to LATIN:
355 /*
356 #define LANGUAGE_ARMENIAN                   0x042B
357 #define LANGUAGE_INDONESIAN                 0x0421
358 #define LANGUAGE_KAZAKH                     0x043F
359 #define LANGUAGE_KONKANI                    0x0457
360 #define LANGUAGE_MACEDONIAN                 0x042F
361 #define LANGUAGE_TATAR                      0x0444
362 */
363             // CJK catcher
364     else if ( primary(nLang).anyOf(
365         primary(LANGUAGE_CHINESE              ),
366         primary(LANGUAGE_YUE_CHINESE_HONGKONG ),
367         primary(LANGUAGE_JAPANESE             ),
368         primary(LANGUAGE_KOREAN               )
369         ))
370     {
371             nScript = css::i18n::ScriptType::ASIAN;
372     }
373             // CTL catcher
374     else if (primary(nLang).anyOf(
375         primary(LANGUAGE_AMHARIC_ETHIOPIA    ),
376         primary(LANGUAGE_ARABIC_SAUDI_ARABIA ),
377         primary(LANGUAGE_ASSAMESE            ),
378         primary(LANGUAGE_BENGALI             ),
379         primary(LANGUAGE_BURMESE             ),
380         primary(LANGUAGE_DHIVEHI             ),
381         primary(LANGUAGE_FARSI               ),
382         primary(LANGUAGE_GUJARATI            ),
383         primary(LANGUAGE_HEBREW              ),
384         primary(LANGUAGE_HINDI               ),
385         primary(LANGUAGE_KANNADA             ),
386         primary(LANGUAGE_KASHMIRI            ),
387         primary(LANGUAGE_KHMER               ),
388         primary(LANGUAGE_LAO                 ),
389         primary(LANGUAGE_MALAYALAM           ),
390         primary(LANGUAGE_MANIPURI            ),
391         primary(LANGUAGE_MARATHI             ),
392         primary(LANGUAGE_NEPALI              ),
393         primary(LANGUAGE_ODIA                ),
394         primary(LANGUAGE_PUNJABI             ),
395         primary(LANGUAGE_SANSKRIT            ),
396         primary(LANGUAGE_SINDHI              ),
397         primary(LANGUAGE_SINHALESE_SRI_LANKA ),
398         primary(LANGUAGE_SYRIAC              ),
399         primary(LANGUAGE_TAMIL               ),
400         primary(LANGUAGE_TELUGU              ),
401         primary(LANGUAGE_THAI                ),
402         primary(LANGUAGE_TIBETAN             ),  // also LANGUAGE_DZONGKHA
403         primary(LANGUAGE_TIGRIGNA_ETHIOPIA   ),
404         primary(LANGUAGE_UIGHUR_CHINA        ),
405         primary(LANGUAGE_URDU_INDIA          ),
406         primary(LANGUAGE_USER_BODO_INDIA     ),
407         primary(LANGUAGE_USER_DOGRI_INDIA    ),
408         primary(LANGUAGE_USER_LIMBU          ),
409         primary(LANGUAGE_USER_MAITHILI_INDIA ),
410         primary(LANGUAGE_USER_NKO            ),
411         primary(LANGUAGE_YIDDISH             )))
412     {
413             nScript = css::i18n::ScriptType::COMPLEX;
414     }
415         // Western (actually not necessarily Latin but also Cyrillic,
416         // for example)
417     else if (LanguageTag::isOnTheFlyID(nLang))
418     {
419         switch (LanguageTag::getOnTheFlyScriptType(nLang))
420         {
421             case LanguageTag::ScriptType::CJK :
422                 nScript = css::i18n::ScriptType::ASIAN;
423                 break;
424             case LanguageTag::ScriptType::CTL :
425             case LanguageTag::ScriptType::RTL :
426                 nScript = css::i18n::ScriptType::COMPLEX;
427                 break;
428             case LanguageTag::ScriptType::WESTERN :
429             case LanguageTag::ScriptType::UNKNOWN :
430             default:
431                 nScript = css::i18n::ScriptType::LATIN;
432                 break;
433         }
434     }
435     else
436     {
437         nScript = css::i18n::ScriptType::LATIN;
438     }
439     return nScript;
440 }
441 
442 
443 // static
isNonLatinWestern(LanguageType nLang)444 bool MsLangId::isNonLatinWestern( LanguageType nLang )
445 {
446     if (nLang.anyOf(
447         LANGUAGE_AZERI_CYRILLIC,
448         LANGUAGE_AZERI_CYRILLIC_LSO,
449         LANGUAGE_BELARUSIAN,
450         LANGUAGE_BOSNIAN_CYRILLIC_BOSNIA_HERZEGOVINA,
451         LANGUAGE_BOSNIAN_CYRILLIC_LSO,
452         LANGUAGE_BULGARIAN,
453         LANGUAGE_GREEK,
454         LANGUAGE_MONGOLIAN_CYRILLIC_LSO,
455         LANGUAGE_MONGOLIAN_CYRILLIC_MONGOLIA,
456         LANGUAGE_RUSSIAN,
457         LANGUAGE_RUSSIAN_MOLDOVA,
458         LANGUAGE_SERBIAN_CYRILLIC_BOSNIA_HERZEGOVINA,
459         LANGUAGE_SERBIAN_CYRILLIC_LSO,
460         LANGUAGE_SERBIAN_CYRILLIC_MONTENEGRO,
461         LANGUAGE_SERBIAN_CYRILLIC_SAM,
462         LANGUAGE_SERBIAN_CYRILLIC_SERBIA,
463         LANGUAGE_UKRAINIAN,
464         LANGUAGE_UZBEK_CYRILLIC,
465         LANGUAGE_UZBEK_CYRILLIC_LSO))
466     {
467             return true;
468     }
469     if (getScriptType( nLang) != css::i18n::ScriptType::LATIN)
470         return false;
471     LanguageTag aLanguageTag( nLang);
472     if (aLanguageTag.hasScript())
473         return aLanguageTag.getScript() != "Latn";
474     return false;
475 }
476 
477 
478 // static
isLegacy(LanguageType nLang)479 bool MsLangId::isLegacy( LanguageType nLang )
480 {
481     return nLang.anyOf(
482          LANGUAGE_SERBIAN_CYRILLIC_SAM,
483          LANGUAGE_SERBIAN_LATIN_SAM);
484             /* TODO: activate once dictionary was renamed from pap-AN to
485              * pap-CW, or the pap-CW one supports also pap-AN, see fdo#44112 */
486         //case LANGUAGE_PAPIAMENTU:
487 }
488 
489 
490 // static
getReplacementForObsoleteLanguage(LanguageType nLang)491 LanguageType MsLangId::getReplacementForObsoleteLanguage( LanguageType nLang )
492 {
493     if (nLang == LANGUAGE_OBSOLETE_USER_LATIN)
494         nLang = LANGUAGE_USER_LATIN_VATICAN;
495     else if (nLang == LANGUAGE_OBSOLETE_USER_MAORI)
496         nLang = LANGUAGE_MAORI_NEW_ZEALAND;
497     else if (nLang == LANGUAGE_OBSOLETE_USER_KINYARWANDA)
498         nLang = LANGUAGE_KINYARWANDA_RWANDA;
499     else if (nLang == LANGUAGE_OBSOLETE_USER_UPPER_SORBIAN)
500         nLang = LANGUAGE_UPPER_SORBIAN_GERMANY;
501     else if (nLang == LANGUAGE_OBSOLETE_USER_LOWER_SORBIAN)
502         nLang = LANGUAGE_LOWER_SORBIAN_GERMANY;
503     else if (nLang == LANGUAGE_OBSOLETE_USER_OCCITAN)
504         nLang = LANGUAGE_OCCITAN_FRANCE;
505     else if (nLang == LANGUAGE_OBSOLETE_USER_BRETON)
506         nLang = LANGUAGE_BRETON_FRANCE;
507     else if (nLang == LANGUAGE_OBSOLETE_USER_KALAALLISUT)
508         nLang = LANGUAGE_KALAALLISUT_GREENLAND;
509     else if (nLang == LANGUAGE_OBSOLETE_USER_LUXEMBOURGISH)
510         nLang = LANGUAGE_LUXEMBOURGISH_LUXEMBOURG;
511     else if (nLang == LANGUAGE_OBSOLETE_USER_KABYLE)
512         nLang = LANGUAGE_TAMAZIGHT_LATIN_ALGERIA;
513     else if (nLang == LANGUAGE_OBSOLETE_USER_CATALAN_VALENCIAN)
514         nLang = LANGUAGE_CATALAN_VALENCIAN;
515     else if (nLang == LANGUAGE_OBSOLETE_USER_MALAGASY_PLATEAU)
516         nLang = LANGUAGE_MALAGASY_PLATEAU;
517     else if (nLang == LANGUAGE_GAELIC_SCOTLAND_LEGACY)
518         nLang = LANGUAGE_GAELIC_SCOTLAND;
519     else if (nLang == LANGUAGE_OBSOLETE_USER_TSWANA_BOTSWANA)
520         nLang = LANGUAGE_TSWANA_BOTSWANA;
521     else if (nLang == LANGUAGE_OBSOLETE_USER_SERBIAN_LATIN_SERBIA)
522         nLang = LANGUAGE_SERBIAN_LATIN_SERBIA;
523     else if (nLang == LANGUAGE_OBSOLETE_USER_SERBIAN_LATIN_MONTENEGRO)
524         nLang = LANGUAGE_SERBIAN_LATIN_MONTENEGRO;
525     else if (nLang == LANGUAGE_OBSOLETE_USER_SERBIAN_CYRILLIC_SERBIA)
526         nLang = LANGUAGE_SERBIAN_CYRILLIC_SERBIA;
527     else if (nLang == LANGUAGE_OBSOLETE_USER_SERBIAN_CYRILLIC_MONTENEGRO)
528         nLang = LANGUAGE_SERBIAN_CYRILLIC_MONTENEGRO;
529     else if (nLang == LANGUAGE_OBSOLETE_USER_KURDISH_IRAQ)
530         nLang = LANGUAGE_KURDISH_ARABIC_IRAQ;
531     else if (nLang == LANGUAGE_OBSOLETE_USER_SPANISH_CUBA)
532         nLang = LANGUAGE_SPANISH_CUBA;
533 
534     // The following are not strictly obsolete but should be mapped to a
535     // replacement locale when encountered.
536 
537     // no_NO is an alias for nb_NO
538     else if (nLang == LANGUAGE_NORWEGIAN)
539         nLang = LANGUAGE_NORWEGIAN_BOKMAL;
540 
541     // The erroneous Tibetan vs. Dzongkha case, #i53497#
542     // We (and MS) have stored LANGUAGE_TIBETAN_BHUTAN. This will need
543     // special attention if MS one day decides to actually use
544     // LANGUAGE_TIBETAN_BHUTAN for bo-BT instead of having it reserved;
545     // then remove the mapping and hope every dz-BT user used ODF to store
546     // documents ;-)
547     else if (nLang == LANGUAGE_TIBETAN_BHUTAN)
548         nLang = LANGUAGE_DZONGKHA_BHUTAN;
549 
550     // en-GB-oed is deprecated, use en-GB-oxendict instead.
551     else if (nLang == LANGUAGE_USER_ENGLISH_UK_OED)
552         nLang = LANGUAGE_USER_ENGLISH_UK_OXENDICT;
553     return nLang;
554 }
555 
556 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
557