xref: /trunk/main/comphelper/source/misc/locale.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_comphelper.hxx"
30 #include <comphelper/locale.hxx>
31 
32 //_______________________________________________
33 // includes
34 #include <rtl/ustrbuf.hxx>
35 
36 //_______________________________________________
37 // namespace
38 
39 namespace comphelper{
40 
41 //-----------------------------------------------
42 const sal_Unicode Locale::SEPERATOR_LC       = (sal_Unicode)'-';
43 const sal_Unicode Locale::SEPERATOR_CV       = (sal_Unicode)'_';
44 const sal_Unicode Locale::SEPERATOR_CV_LINUX = (sal_Unicode)'.';
45 
46 //-----------------------------------------------
47 const Locale Locale::X_DEFAULT()
48 {
49     static Locale aLocale(
50                     ::rtl::OUString::createFromAscii("x"),
51                     ::rtl::OUString::createFromAscii("default"));
52     return aLocale;
53 }
54 
55 //-----------------------------------------------
56 const Locale Locale::EN()
57 {
58     static Locale aLocale(
59                     ::rtl::OUString::createFromAscii("en"),
60                     ::rtl::OUString());
61     return aLocale;
62 }
63 
64 //-----------------------------------------------
65 const Locale Locale::EN_US()
66 {
67     static Locale aLocale(
68                     ::rtl::OUString::createFromAscii("en"),
69                     ::rtl::OUString::createFromAscii("US"));
70     return aLocale;
71 }
72 
73 //-----------------------------------------------
74 const Locale Locale::DE_DE()
75 {
76     static Locale aLocale(
77                     ::rtl::OUString::createFromAscii("de"),
78                     ::rtl::OUString::createFromAscii("DE"));
79     return aLocale;
80 }
81 
82 //-----------------------------------------------
83 const Locale Locale::DE_CH()
84 {
85     static Locale aLocale(
86                     ::rtl::OUString::createFromAscii("de"),
87                     ::rtl::OUString::createFromAscii("CH"));
88     return aLocale;
89 }
90 
91 //-----------------------------------------------
92 const Locale Locale::DE_AT()
93 {
94     static Locale aLocale(
95                     ::rtl::OUString::createFromAscii("de"),
96                     ::rtl::OUString::createFromAscii("AT"));
97     return aLocale;
98 }
99 
100 //-----------------------------------------------
101 const Locale Locale::AR()
102 {
103     static Locale aLocale(
104                     ::rtl::OUString::createFromAscii("ar"),
105                     ::rtl::OUString());
106     return aLocale;
107 }
108 
109 //-----------------------------------------------
110 const Locale Locale::CA()
111 {
112     static Locale aLocale(
113                     ::rtl::OUString::createFromAscii("ca"),
114                     ::rtl::OUString());
115     return aLocale;
116 }
117 
118 //-----------------------------------------------
119 const Locale Locale::CS()
120 {
121     static Locale aLocale(
122                     ::rtl::OUString::createFromAscii("cs"),
123                     ::rtl::OUString());
124     return aLocale;
125 }
126 
127 //-----------------------------------------------
128 const Locale Locale::DA()
129 {
130     static Locale aLocale(
131                     ::rtl::OUString::createFromAscii("da"),
132                     ::rtl::OUString());
133     return aLocale;
134 }
135 
136 //-----------------------------------------------
137 const Locale Locale::EL()
138 {
139     static Locale aLocale(
140                     ::rtl::OUString::createFromAscii("el"),
141                     ::rtl::OUString());
142     return aLocale;
143 }
144 
145 //-----------------------------------------------
146 const Locale Locale::ES()
147 {
148     static Locale aLocale(
149                     ::rtl::OUString::createFromAscii("es"),
150                     ::rtl::OUString());
151     return aLocale;
152 }
153 
154 //-----------------------------------------------
155 const Locale Locale::FI()
156 {
157     static Locale aLocale(
158                     ::rtl::OUString::createFromAscii("fi"),
159                     ::rtl::OUString());
160     return aLocale;
161 }
162 
163 //-----------------------------------------------
164 const Locale Locale::FR()
165 {
166     static Locale aLocale(
167                     ::rtl::OUString::createFromAscii("fr"),
168                     ::rtl::OUString());
169     return aLocale;
170 }
171 
172 //-----------------------------------------------
173 const Locale Locale::HE()
174 {
175     static Locale aLocale(
176                     ::rtl::OUString::createFromAscii("he"),
177                     ::rtl::OUString());
178     return aLocale;
179 }
180 
181 //-----------------------------------------------
182 const Locale Locale::HI_IN()
183 {
184     static Locale aLocale(
185                     ::rtl::OUString::createFromAscii("hi"),
186                     ::rtl::OUString::createFromAscii("IN"));
187     return aLocale;
188 }
189 
190 //-----------------------------------------------
191 const Locale Locale::HU()
192 {
193     static Locale aLocale(
194                     ::rtl::OUString::createFromAscii("hu"),
195                     ::rtl::OUString());
196     return aLocale;
197 }
198 
199 //-----------------------------------------------
200 const Locale Locale::IT()
201 {
202     static Locale aLocale(
203                     ::rtl::OUString::createFromAscii("it"),
204                     ::rtl::OUString());
205     return aLocale;
206 }
207 
208 //-----------------------------------------------
209 const Locale Locale::JA()
210 {
211     static Locale aLocale(
212                     ::rtl::OUString::createFromAscii("ja"),
213                     ::rtl::OUString());
214     return aLocale;
215 }
216 
217 //-----------------------------------------------
218 const Locale Locale::KO()
219 {
220     static Locale aLocale(
221                     ::rtl::OUString::createFromAscii("ko"),
222                     ::rtl::OUString());
223     return aLocale;
224 }
225 
226 //-----------------------------------------------
227 const Locale Locale::NL()
228 {
229     static Locale aLocale(
230                     ::rtl::OUString::createFromAscii("nl"),
231                     ::rtl::OUString());
232     return aLocale;
233 }
234 
235 //-----------------------------------------------
236 const Locale Locale::PL()
237 {
238     static Locale aLocale(
239                     ::rtl::OUString::createFromAscii("pl"),
240                     ::rtl::OUString());
241     return aLocale;
242 }
243 
244 //-----------------------------------------------
245 const Locale Locale::PT()
246 {
247     static Locale aLocale(
248                     ::rtl::OUString::createFromAscii("pt"),
249                     ::rtl::OUString());
250     return aLocale;
251 }
252 
253 //-----------------------------------------------
254 const Locale Locale::PT_BR()
255 {
256     static Locale aLocale(
257                     ::rtl::OUString::createFromAscii("pt"),
258                     ::rtl::OUString::createFromAscii("BR"));
259     return aLocale;
260 }
261 
262 //-----------------------------------------------
263 const Locale Locale::RU()
264 {
265     static Locale aLocale(
266                     ::rtl::OUString::createFromAscii("ru"),
267                     ::rtl::OUString());
268     return aLocale;
269 }
270 
271 //-----------------------------------------------
272 const Locale Locale::SK()
273 {
274     static Locale aLocale(
275                     ::rtl::OUString::createFromAscii("sk"),
276                     ::rtl::OUString());
277     return aLocale;
278 }
279 
280 //-----------------------------------------------
281 const Locale Locale::SL()
282 {
283     static Locale aLocale(
284                     ::rtl::OUString::createFromAscii("sl"),
285                     ::rtl::OUString());
286     return aLocale;
287 }
288 
289 //-----------------------------------------------
290 const Locale Locale::SV()
291 {
292     static Locale aLocale(
293                     ::rtl::OUString::createFromAscii("sv"),
294                     ::rtl::OUString());
295     return aLocale;
296 }
297 
298 //-----------------------------------------------
299 const Locale Locale::TH()
300 {
301     static Locale aLocale(
302                     ::rtl::OUString::createFromAscii("th"),
303                     ::rtl::OUString());
304     return aLocale;
305 }
306 
307 //-----------------------------------------------
308 const Locale Locale::TR()
309 {
310     static Locale aLocale(
311                     ::rtl::OUString::createFromAscii("tr"),
312                     ::rtl::OUString());
313     return aLocale;
314 }
315 
316 //-----------------------------------------------
317 const Locale Locale::X_COMMENT()
318 {
319     static Locale aLocale(
320                     ::rtl::OUString::createFromAscii("x"),
321                     ::rtl::OUString::createFromAscii("comment"));
322     return aLocale;
323 }
324 
325 //-----------------------------------------------
326 const Locale Locale::X_TRANSLATE()
327 {
328     static Locale aLocale(
329                     ::rtl::OUString::createFromAscii("x"),
330                     ::rtl::OUString::createFromAscii("translate"));
331     return aLocale;
332 }
333 
334 //-----------------------------------------------
335 const Locale Locale::X_NOTRANSLATE()
336 {
337     static Locale aLocale(
338                     ::rtl::OUString::createFromAscii("x"),
339                     ::rtl::OUString::createFromAscii("notranslate"));
340     return aLocale;
341 }
342 
343 //-----------------------------------------------
344 const Locale Locale::ZH_CN()
345 {
346     static Locale aLocale(
347                     ::rtl::OUString::createFromAscii("zh"),
348                     ::rtl::OUString::createFromAscii("CN"));
349     return aLocale;
350 }
351 
352 //-----------------------------------------------
353 const Locale Locale::ZH_TW()
354 {
355     static Locale aLocale(
356                     ::rtl::OUString::createFromAscii("zh"),
357                     ::rtl::OUString::createFromAscii("TW"));
358     return aLocale;
359 }
360 
361 //-----------------------------------------------
362 Locale::Locale(const ::rtl::OUString& sISO)
363     throw(Locale::MalFormedLocaleException)
364 {
365     fromISO(sISO);
366 }
367 
368 //-----------------------------------------------
369 Locale::Locale(const ::rtl::OUString& sLanguage,
370                const ::rtl::OUString& sCountry ,
371                const ::rtl::OUString& sVariant )
372 {
373     // Use set methods to check values too!
374     setLanguage(sLanguage);
375     setCountry (sCountry );
376     setVariant (sVariant );
377 }
378 
379 //-----------------------------------------------
380 Locale::Locale()
381 {
382     // Initialize instance ... otherwhise user will
383     // may be get exceptions if he e.g. copy this instance ...
384     (*this) = X_NOTRANSLATE();
385 }
386 
387 //-----------------------------------------------
388 Locale::Locale(const Locale& aCopy)
389 {
390     (*this) = aCopy; // recycle assign operator
391 }
392 
393 //-----------------------------------------------
394 ::rtl::OUString Locale::getLanguage() const
395 {
396     return m_sLanguage;
397 }
398 
399 //-----------------------------------------------
400 ::rtl::OUString Locale::getCountry() const
401 {
402     return m_sCountry;
403 }
404 
405 //-----------------------------------------------
406 ::rtl::OUString Locale::getVariant() const
407 {
408     return m_sVariant;
409 }
410 
411 //-----------------------------------------------
412 void Locale::setLanguage(const ::rtl::OUString& sLanguage)
413 {
414     m_sLanguage = sLanguage;
415 }
416 
417 //-----------------------------------------------
418 void Locale::setCountry(const ::rtl::OUString& sCountry)
419 {
420     m_sCountry = sCountry;
421 }
422 
423 //-----------------------------------------------
424 void Locale::setVariant(const ::rtl::OUString& sVariant)
425 {
426     m_sVariant = sVariant;
427 }
428 
429 //-----------------------------------------------
430 /* Attention: Use own interface methods to set the
431    different parts of this locale. Because the
432    check the incoming value and throw an exception
433    automaticly ...
434  */
435 void Locale::fromISO(const ::rtl::OUString& sISO)
436     throw(Locale::MalFormedLocaleException)
437 {
438     m_sLanguage = ::rtl::OUString();
439     m_sCountry  = ::rtl::OUString();
440     m_sVariant  = ::rtl::OUString();
441 
442     ::rtl::OUString sParser(sISO);
443     sParser.trim();
444 
445     sal_Int32 nStart = 0;
446     sal_Int32 nEnd   = 0;
447 
448     // extract language part
449     nEnd = sParser.indexOf(SEPERATOR_LC, nStart);
450     if (nEnd<0)
451     {
452         setLanguage(sParser);
453         return;
454     }
455     setLanguage(sParser.copy(nStart, nEnd-nStart));
456     nStart = nEnd+1;
457 
458     // extract country
459     nEnd = sParser.indexOf(SEPERATOR_CV, nStart);
460     if (nEnd<0)
461         nEnd = sParser.indexOf(SEPERATOR_CV_LINUX, nStart);
462     if (nEnd<0)
463     {
464         setCountry(sParser.copy(nStart, sParser.getLength()-nStart));
465         return;
466     }
467     nStart = nEnd+1;
468 
469     // extract variant
470     setVariant(sParser.copy(nStart, sParser.getLength()-nStart));
471 }
472 
473 //-----------------------------------------------
474 ::rtl::OUString Locale::toISO() const
475 {
476     ::rtl::OUStringBuffer sISO(64);
477 
478     sISO.append(m_sLanguage);
479     if (m_sCountry.getLength())
480     {
481         sISO.append(SEPERATOR_LC);
482         sISO.append(m_sCountry);
483 
484         if (m_sVariant.getLength())
485         {
486             sISO.append(SEPERATOR_CV);
487             sISO.append(m_sVariant);
488         }
489     }
490 
491     return sISO.makeStringAndClear();
492 }
493 
494 //-----------------------------------------------
495 sal_Bool Locale::equals(const Locale& aComparable) const
496 {
497     return (
498             m_sLanguage.equals(aComparable.m_sLanguage) &&
499             m_sCountry.equals (aComparable.m_sCountry ) &&
500             m_sVariant.equals (aComparable.m_sVariant )
501            );
502 }
503 
504 //-----------------------------------------------
505 sal_Bool Locale::similar(const Locale& aComparable) const
506 {
507     return (m_sLanguage.equals(aComparable.m_sLanguage));
508 }
509 
510 //-----------------------------------------------
511 ::std::vector< ::rtl::OUString >::const_iterator Locale::getFallback(const ::std::vector< ::rtl::OUString >& lISOList     ,
512                                                                      const ::rtl::OUString&                  sReferenceISO)
513     throw(Locale::MalFormedLocaleException)
514 {
515     Locale aReference(sReferenceISO);
516 
517     // Note: The same language or "en"/"en-US" should be preferred as fallback.
518     // On the other side some localized variables doesnt use localzation in real.
519     // May be the use a "fix" value only ... marked as X-DEFAULT or X-NOTRANSLATE.
520     // At least it can be discussed, if any language is a valid fallback ...
521     // But in case some office functionality depends on that (that means real functionality instead
522     // of pure UI descriptions) we should do anything, so it can work.
523 
524     ::std::vector< ::rtl::OUString >::const_iterator pSimilar      = lISOList.end();
525     ::std::vector< ::rtl::OUString >::const_iterator pEN_US        = lISOList.end();
526     ::std::vector< ::rtl::OUString >::const_iterator pEN           = lISOList.end();
527     ::std::vector< ::rtl::OUString >::const_iterator pXDefault     = lISOList.end();
528     ::std::vector< ::rtl::OUString >::const_iterator pXNoTranslate = lISOList.end();
529     ::std::vector< ::rtl::OUString >::const_iterator pAny          = lISOList.end();
530 
531     ::std::vector< ::rtl::OUString >::const_iterator pIt;
532     for (  pIt  = lISOList.begin();
533            pIt != lISOList.end()  ;
534          ++pIt                    )
535     {
536         Locale aCheck(*pIt);
537         // found Locale, which match with 100% => return it
538         if (aCheck.equals(aReference))
539             return pIt;
540 
541         // found similar Locale => safe it as possible fallback
542         if (
543             (pSimilar == lISOList.end()) &&
544             (aCheck.similar(aReference))
545            )
546         {
547             pSimilar = pIt;
548         }
549         else
550         // found en-US => safe it as fallback
551         if (
552             (pEN_US == lISOList.end()) &&
553             (aCheck.equals(EN_US())  )
554            )
555         {
556             pEN_US = pIt;
557         }
558         else
559         // found en[-XX] => safe it as fallback
560         if (
561             (pEN == lISOList.end()  ) &&
562             (aCheck.similar(EN_US()))
563            )
564         {
565             pEN = pIt;
566         }
567         else
568         // found an explicit default value(!) => safe it as fallback
569         if (
570             (pXDefault == lISOList.end()) &&
571             (aCheck.equals(X_DEFAULT()) )
572            )
573         {
574             pXDefault = pIt;
575         }
576         else
577         // found an implicit default value(!) => safe it as fallback
578         if (
579             (pXNoTranslate == lISOList.end()) &&
580             (aCheck.equals(X_NOTRANSLATE()) )
581            )
582         {
583             pXNoTranslate = pIt;
584         }
585         else
586         // safe the first locale, which isn't an explicit fallback
587         // as "last possible fallback"
588         if (pAny == lISOList.end())
589             pAny = pIt;
590     }
591 
592     if (pSimilar != lISOList.end())
593         return pSimilar;
594 
595     if (pEN_US != lISOList.end())
596         return pEN_US;
597 
598     if (pEN != lISOList.end())
599         return pEN;
600 
601     if (pXDefault != lISOList.end())
602         return pXDefault;
603 
604     if (pXNoTranslate != lISOList.end())
605         return pXNoTranslate;
606 
607     if (pAny != lISOList.end())
608         return pAny;
609 
610     return lISOList.end();
611 }
612 
613 //-----------------------------------------------
614 sal_Bool Locale::getFallback(Locale& aLocale)
615 {
616     // a)
617     // this was our last fallback!
618     // break any further calls to this method ...
619     if (aLocale.equals(X_NOTRANSLATE()))
620         return sal_False;
621 
622     // b)
623     // switch from X_DEFAULT to X_NOTRANSLATE
624     // next time we will go to a)
625     if (aLocale.equals(X_DEFAULT()))
626     {
627         aLocale = X_NOTRANSLATE();
628         return sal_True;
629     }
630 
631     // c)
632     // switch from EN to X_DEFAULT
633     // next time we will go to b)
634     if (aLocale.equals(EN()))
635     {
636         aLocale = X_DEFAULT();
637         return sal_True;
638     }
639 
640     // d) remove country from incoming locale
641     //    e.g. "de-DE" => "de" or "en-US" => "en"!
642     if (aLocale.getCountry().getLength())
643     {
644         aLocale.setCountry(::rtl::OUString());
645         return sal_True;
646     }
647 
648     // e) "en-US" possible?
649     if (!aLocale.equals(EN_US()))
650     {
651         aLocale = EN_US();
652         return sal_True;
653     }
654 
655     // f) no more fallbacks
656     return sal_False;
657 }
658 
659 //-----------------------------------------------
660 void  Locale::operator=(const Locale& rCopy)
661 {
662     // Take over these values without checking ...
663     // They was already checked if the copy was constructed
664     // and must be valid now!
665     m_sLanguage = rCopy.m_sLanguage;
666     m_sCountry  = rCopy.m_sCountry;
667     m_sVariant  = rCopy.m_sVariant;
668 }
669 
670 //-----------------------------------------------
671 sal_Bool Locale::operator==(const Locale& aComparable) const
672 {
673     return equals(aComparable);
674 }
675 
676 //-----------------------------------------------
677 sal_Bool Locale::operator!=(const Locale& aComparable) const
678 {
679     return !equals(aComparable);
680 }
681 
682 } // namespace comphelper
683 
684