i18n.h

Go to the documentation of this file.
00001 /*
00002  * i18n.h
00003  *
00004  * Copyright (c) 2010 Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Internationalization and localization--particularly, management of
00032  * localized strings.
00033  */
00034 
00035 #ifndef WAVEPACKET_I18N_H__
00036 #define WAVEPACKET_I18N_H__
00037 
00038 
00039 // includes --------------------------------------------------------------------
00040 #include "nstream/nstream.h"
00041 
00042 
00043 namespace i18n {
00044 
00045 ////////////////////////////////////////////////////////////////////////////////
00046 ///
00047 /// \ingroup general
00048 /// \defgroup i18n Internationalization (i18n) Library
00049 ///
00050 ////////////////////////////////////////////////////////////////////////////////
00051 /*@{*/
00052 
00053 
00054 /// simple struct for managing a locale specification
00055 struct locale_t {
00056         // public enums
00057         enum eConstants {
00058                 eLanguageOffset         = 0,    ///< internal use only
00059                 eCountryOffset          = 3,    ///< internal use only
00060                 eEncodingOffset         = 6,    ///< internal use only
00061                 eBufferSize             = 8,    ///< use this for buffer sizes
00062                 eMaxLength              = 15    ///< max size of locale string
00063         };
00064 
00065         // constructor, manipulators
00066         locale_t(void) throw() { this->clear(); }
00067         void clear(void) throw() {
00068                         string[eLanguageOffset] = 0;    // null language
00069                         string[eCountryOffset] = 0;     // null country
00070                         string[eEncodingOffset] = 0;    // null encoding
00071                 }
00072 
00073         const char * getString(void) const throw() { return string; }
00074 
00075         /// is this a valid locale?
00076         bool isValid(void) const throw();
00077 
00078         /// NOTE: for now we use ISO 639-1 (2-character language codes), but
00079         ///     in the future this library could use ISO 639-2 (3-character
00080         ///     codes) if they become common enough.  Client code should use
00081         ///     the locale_t::eBufferSize constant to construct character
00082         ///     buffer arrays, to remain forward compatible.
00083         const char * getLanguageCode(OUT char * buffer) const throw() {
00084                         ASSERT(buffer, "null");
00085                         buffer[0] = string[eLanguageOffset];
00086                         buffer[1] = string[eLanguageOffset + 1];
00087                         buffer[2] = 0;
00088                         return buffer;
00089                 }
00090 
00091         const char * getCountryCode(OUT char * buffer) const throw() {
00092                         ASSERT(buffer, "null");
00093                         buffer[0] = string[eCountryOffset];
00094                         buffer[1] = string[eCountryOffset + 1];
00095                         buffer[2] = 0;
00096                         return buffer;
00097                 }
00098 
00099         const char * getEncoding(OUT char * buffer) const throw() {
00100                         ASSERT(buffer, "null");
00101                         strcpy(buffer, string + eEncodingOffset);
00102                         return buffer;
00103                 }
00104 
00105         // data fields
00106         char    string[eMaxLength + 1]; // up to 15 characters
00107 };
00108 
00109 
00110 
00111 class Manager {
00112 public:
00113         // virtual destructor --------------------------------------------------
00114         virtual ~Manager(void) throw();
00115 
00116         // i18n::Manager class interface methods -------------------------------
00117         virtual const char * getLocale(void) const throw() = 0;
00118 
00119         /// given a named stream (nstream::Stream), parses all localeInfo
00120         ///     blocks relevant to this Manager's locale.
00121         virtual void parseStrings(IN nstream::Stream * stream) = 0;
00122 
00123         /// recursively walks all child Entries beneath the specified Folder,
00124         ///     and calls parseStrings() on each.  Caller can provide a filter
00125         ///     (only Entries whose full path includes the filter as a substring
00126         ///     will be visited).  For many projects, the locale name can be
00127         ///     used as a filter (since filenames/paths will include the
00128         ///     locale specifier).  The caller can also (optionally) provide a
00129         ///     set of valid filename extensions.
00130         /// Skips files and directories beginning with a dot ('.').
00131         virtual void parseFolder(IN nstream::Folder * folder,
00132                                 IN const SetString * extensions = NULL,
00133                                 IN const char * filter = NULL) = 0;
00134 
00135         /// retrieves the specified string.  Returns null if ID is not
00136         ///     recognized.
00137         virtual const char * getString(IN const char * id) const throw() = 0;
00138 
00139         // static class methods (factory methods) ------------------------------
00140         static smart_ptr<Manager>  create(IN const char * locale);
00141 };
00142 
00143 
00144 
00145 ////////////////////////////////////////////////////////////////////////////////
00146 //
00147 //      public API
00148 //
00149 ////////////////////////////////////////////////////////////////////////////////
00150 
00151 /// given a locale string, of the form "xx_yy.zzzz", returns a locale_t
00152 ///  - xx: 2 character language code (ISO 639-1)
00153 ///  - yy: 2 character country code (ISO 3166)
00154 ///  - zzzz: encoding (arbitrary length, only "UTF-8" is supported right now)
00155 void getLocaleFromString(IN const char * localeString,
00156                         OUT locale_t& locale);
00157 
00158 /// is this a valid country code?  Based on ISO 3166
00159 bool isValidCountryCode(IN const char * country_code);
00160 
00161 /// is this a valid language code?  Only supports ISO 639-1 (2-character codes)
00162 ///     for now.
00163 bool isValidLanguageCode(IN const char * language_code);
00164 
00165 
00166 /// is this a valid encoding?  "valid" means "supported by this library", which
00167 ///     for right now is just "UTF-8"
00168 bool isValidEncoding(IN const char * encoding);
00169 
00170 
00171 /// returns the string from the given Manager.  If the string isn't found, a
00172 ///     general (probably English) error message is returned instead.  This is
00173 ///     handy if a missing string isn't fatal and you don't need richer error
00174 ///     messaging.  This will help missing strings be identified by the user.
00175 const char * getString(IN const Manager * mgr,
00176                                 IN const char * id);
00177 
00178 
00179 /// attempt to determine the local host locale.  Can return NULL!
00180 const char * getHostLocale(void);
00181 
00182 
00183 };      // i18n namespace
00184 
00185 /*@}*/  // end of documentation block
00186 
00187 #endif  // WAVEPACKET_I18N_H__
00188