1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/Locale.cc
15 #include <zypp/Locale.h>
16 #include <zypp/ZConfig.h>
20 ///////////////////////////////////////////////////////////////////
23 /** Wrap static codemap data. */
26 /** Return IdString without trailing garbage. */
27 static IdString withoutTrash( IdString code_r )
29 boost::string_ref::size_type sep = trashStart( code_r );
30 if ( sep != boost::string_ref::npos )
31 code_r = IdString( code_r.c_str(), sep );
35 /** Return IdString without trailing garbage. */
36 static IdString withoutTrash( const std::string & code_r )
37 { return withoutTrash( boost::string_ref(code_r) ); }
39 /** Return IdString without trailing garbage. */
40 static IdString withoutTrash( const char * code_r )
41 { return( code_r ? withoutTrash( boost::string_ref(code_r) ) : IdString::Null ); }
43 /** Return IdString from language/country codes. */
44 static IdString combineLC( LanguageCode language_r, CountryCode country_r )
50 ret = IdString( std::string(language_r) + "_" + country_r.c_str() );
52 ret = IdString(language_r);
57 ret = IdString( "_" + std::string(country_r) );
58 else if ( ! ( IdString(language_r) || IdString(country_r) ) )
60 // else IdString::Empty
66 static CodeMaps & instance()
68 static CodeMaps _instance;
72 LanguageCode language( IdString index_r )
73 { return getIndex( index_r )._l; }
75 CountryCode country( IdString index_r )
76 { return getIndex( index_r )._c; }
78 std::string name( IdString index_r )
80 const LC & lc( getIndex( index_r ) );
81 std::string ret( lc._l.name() );
91 Locale fallback( IdString index_r )
93 static const IdString special( "pt_BR" );
95 if ( index_r == special ) // "pt_BR"->"en" - by now the only fallback exception
99 const LC & lc( getIndex( index_r ) );
102 else if ( lc._l && lc._l != LanguageCode::enCode )
103 ret = Locale::enCode;
109 static IdString withoutTrash( boost::string_ref code_r )
111 boost::string_ref::size_type sep = trashStart( code_r );
112 if ( sep != boost::string_ref::npos )
113 code_r = code_r.substr( 0, sep );
114 return IdString( code_r );
117 static boost::string_ref::size_type trashStart( boost::string_ref code_r )
118 { return code_r.find_first_of( "@." ); }
120 static boost::string_ref::size_type trashStart( IdString code_r )
121 { return trashStart( boost::string_ref(code_r.c_str()) ); }
126 LC( LanguageCode l_r ) : _l( l_r ) {}
127 LC( LanguageCode l_r, CountryCode c_r ) : _l( l_r ), _c( c_r ) {}
131 typedef std::unordered_map<IdString,LC> CodeMap;
133 /** Ctor initializes the code maps. */
135 : _codeMap( { { IdString::Null, LC( LanguageCode(IdString::Null), CountryCode(IdString::Null) ) }
136 , { IdString::Empty, LC( LanguageCode(IdString::Empty), CountryCode(IdString::Empty) ) } } )
139 /** Return \ref LC for \a index_r, creating it if necessary. */
140 const LC & getIndex( IdString index_r )
142 auto it = _codeMap.find( index_r );
143 if ( it == _codeMap.end() )
145 CodeMap::value_type newval( index_r, LC() );
147 boost::string_ref str( index_r.c_str() );
148 boost::string_ref::size_type sep = str.find( '_' );
149 if ( sep == boost::string_ref::npos )
150 newval.second._l = LanguageCode( index_r );
153 // bsc#1064999: dup! Creating a new IdString may invalidate the IdString.c_str() stored in str.
154 std::string dup( str );
156 newval.second._l = LanguageCode( IdString(str.substr( 0, sep )) );
157 newval.second._c = CountryCode( IdString(str.substr( sep+1 )) );
160 it = _codeMap.insert( std::move(newval) ).first;
169 ///////////////////////////////////////////////////////////////////
171 ///////////////////////////////////////////////////////////////////
173 const Locale Locale::noCode;
174 const LanguageCode LanguageCode::enCode("en"); // from in LanguageCode.cc as Locale::enCode depends on it
175 const Locale Locale::enCode( LanguageCode::enCode );
180 Locale::Locale( IdString str_r )
181 : _str( CodeMaps::withoutTrash( str_r ) )
184 Locale::Locale( const std::string & str_r )
185 : _str( CodeMaps::withoutTrash( str_r ) )
188 Locale::Locale( const char * str_r )
189 : _str( CodeMaps::withoutTrash( str_r ) )
192 Locale::Locale( LanguageCode language_r, CountryCode country_r )
193 : _str( CodeMaps::combineLC( language_r, country_r ) )
199 LanguageCode Locale::language() const
200 { return CodeMaps::instance().language( _str ); }
202 CountryCode Locale::country() const
203 { return CodeMaps::instance().country( _str ); }
205 std::string Locale::name() const
206 { return CodeMaps::instance().name( _str ); }
208 Locale Locale::fallback() const
209 { return CodeMaps::instance().fallback( _str ); }
211 ///////////////////////////////////////////////////////////////////
213 Locale Locale::bestMatch( const LocaleSet & avLocales_r, Locale requested_r )
215 if ( ! avLocales_r.empty() )
218 requested_r = ZConfig::instance().textLocale();
219 for ( ; requested_r; requested_r = requested_r.fallback() )
221 if ( avLocales_r.count( requested_r ) )
229 ///////////////////////////////////////////////////////////////////