Quotes.cpp (2859B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "Quotes.h" 7 #include "mozilla/ClearOnShutdown.h" 8 #include "mozilla/StaticPtr.h" 9 #include "mozilla/intl/Locale.h" 10 #include "nsTHashMap.h" 11 #include "nsPrintfCString.h" 12 13 using namespace mozilla; 14 using namespace mozilla::intl; 15 16 namespace { 17 struct LangQuotesRec { 18 const char* mLangs; 19 Quotes mQuotes; 20 }; 21 22 #include "cldr-quotes.inc" 23 24 static StaticAutoPtr<nsTHashMap<nsCStringHashKey, Quotes>> sQuotesForLang; 25 } // anonymous namespace 26 27 namespace mozilla { 28 namespace intl { 29 30 const Quotes* QuotesForLang(const nsAtom* aLang) { 31 MOZ_ASSERT(NS_IsMainThread()); 32 33 // On first use, initialize the hashtable from our CLDR-derived data array. 34 if (!sQuotesForLang) { 35 sQuotesForLang = new nsTHashMap<nsCStringHashKey, Quotes>(32); 36 ClearOnShutdown(&sQuotesForLang); 37 for (const auto& i : sLangQuotes) { 38 const char* s = i.mLangs; 39 size_t len; 40 while ((len = strlen(s))) { 41 sQuotesForLang->InsertOrUpdate(nsDependentCString(s, len), i.mQuotes); 42 s += len + 1; 43 } 44 } 45 } 46 47 nsAtomCString langStr(aLang); 48 const Quotes* entry = sQuotesForLang->Lookup(langStr).DataPtrOrNull(); 49 if (entry) { 50 // Found an exact match for the requested lang. 51 return entry; 52 } 53 54 // Try parsing lang as a Locale, then see if we can match it with region or 55 // script subtags, if present, or just the primary language tag. 56 // Note that the locale code (if well-formed) will have been canonicalized by 57 // the attribute-mapping code, so we can rely on the expected casing for each 58 // type of subtag. 59 Locale loc; 60 auto result = LocaleParser::TryParse(langStr, loc); 61 if (result.isErr()) { 62 return nullptr; 63 } 64 // Extract the primary language tag. 65 const Span<const char> langAsSpan = loc.Language().Span(); 66 nsAutoCString lang(langAsSpan.data(), langAsSpan.size()); 67 const auto langLen = lang.Length(); 68 // See if we can match language + region. 69 if (loc.Region().Present()) { 70 lang.Append('-'); 71 lang.Append(loc.Region().Span()); 72 if ((entry = sQuotesForLang->Lookup(lang).DataPtrOrNull())) { 73 return entry; 74 } 75 lang.Truncate(langLen); 76 } 77 // See if we can match language + script. 78 if (loc.Script().Present()) { 79 lang.Append('-'); 80 lang.Append(loc.Script().Span()); 81 if ((entry = sQuotesForLang->Lookup(lang).DataPtrOrNull())) { 82 return entry; 83 } 84 lang.Truncate(langLen); 85 } 86 // OK, just try the primary language tag alone. 87 if ((entry = sQuotesForLang->Lookup(lang).DataPtrOrNull())) { 88 return entry; 89 } 90 91 return nullptr; 92 } 93 94 } // namespace intl 95 } // namespace mozilla