3 * Toyohashi Open Platform for Embedded Real-Time Systems
5 * Copyright (C) 2007-2008 by TAKAGI Nobuhisa
7 * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
8 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
9 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
10 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
11 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
13 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
14 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
15 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
17 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
18 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
20 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
21 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
22 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
24 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
25 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
26 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
27 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
30 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
31 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
32 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
33 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
38 #include <stdlib.h> // Cygwin対策
45 #include "toppers/gettext.hpp"
46 #include "toppers/cpp.hpp"
47 #include "toppers/global.hpp"
48 #include <boost/scoped_array.hpp>
49 #include <boost/any.hpp>
50 #include <boost/filesystem/path.hpp>
51 #include <boost/filesystem/operations.hpp>
58 std::map< std::string, std::string > msgcat;
60 void register_msgcat( std::string const& msgid, std::string const& msgstr )
62 std::string::size_type size = msgstr.size();
63 boost::scoped_array< wchar_t > wbuf( new wchar_t[ size + 1 ] );
64 boost::scoped_array< char > buf( new char[ size + 1 ] );
65 wchar_t* wcs = wbuf.get();
67 for ( std::string::const_iterator iter( msgstr.begin() ), last( msgstr.end() ); iter != last; ++iter )
69 int c = static_cast< unsigned char >( *iter );
70 if ( ( ( c & 0xc0 ) == 0xc0 ) || ( c < 0x80 ) ) // 先行バイト
77 if ( ( c & 0x80 ) == 0 )
79 wc = static_cast< wchar_t >( c );
81 else if ( ( c & 0xe0 ) == 0xc0 )
83 wc = static_cast< wchar_t >( c & 0x1f );
85 else if ( ( c & 0xf0 ) == 0xe0 )
87 wc = static_cast< wchar_t >( c & 0xf );
91 // サロゲートは未対応(ここで対応したとしても、文字コード変換時にしくじる可能性大)
96 wc = static_cast< wchar_t >( ( wc << 6 ) | ( c & 0x3f ) );
106 char const* locale = std::setlocale( LC_CTYPE, "" );
107 /* std:: */wcstombs( buf.get(), wbuf.get(), size + 1 ); // Unicode から環境依存の文字コードへ変換
108 std::setlocale( LC_CTYPE, locale );
111 msgcat[ msgid ] = std::string( buf.get() );
114 bool msgcat_loaded = false;
119 * \brief メッセージカタログのロード
120 * \param[in] dir *.po ファイルが存在するディレクトリ
124 * 実装を簡便化するため、.poファイルの記述方法には以下の制約がある。
125 * - msgid, msgstr は必ず行の先頭に記述する。
126 * - msgid, msgstr の直後には、必ず空白類文字一文字とし、その直後に文字列を記述する。
127 * - 文字列のみを記述する行は必ず " で始める。
128 * - .poファイルはの文字コードは必ず UTF-8N とする。
130 bool load_msgcat( std::string const& dir )
132 namespace fs = boost::filesystem;
133 char const* env = std::getenv( "TOPPERS_CFG_LANG" );
139 std::string lang( env );
141 fs::path cfg_dir( dir, fs::native );
142 fs::path po_file( cfg_dir/fs::path( lang + ".po", fs::native ) );
143 std::ifstream ifs( po_file.native_file_string().c_str() );
150 std::getline( ifs, str );
153 std::string::size_type pos = str.find_last_not_of( " \t\r\n" ); // ついでに行末の空白類も除去
154 if ( pos != std::string::npos && pos < str.size() - 1 )
157 str.erase( pos + 1, std::string::npos );
160 if ( str.empty() || str[ 0 ] == '#' || str == "" )
168 if ( std::strncmp( str.c_str(), "msgid", sizeof( "msgid" )-1 ) == 0 )
170 str.erase( 0, sizeof( "msgid" )-1+1 );
171 msgid = expand_quote( str );
173 else if ( std::strncmp( str.c_str(), "msgstr", sizeof( "msgstr" )-1 ) == 0 )
175 str.erase( 0, sizeof( "msgstr" )-1+1 );
176 msgstr = expand_quote( str );
180 msgstr += expand_quote( str );
182 if ( !msgid.empty() && !msgstr.empty() ) // 直前の msgid / msgstr を登録
184 register_msgcat( msgid, msgstr );
189 catch ( std::invalid_argument& )
195 msgcat_loaded = true;
201 * \param[in] message メッセージID
204 std::string const& gettext( std::string const& message )
206 static bool f = load_msgcat( get_global< std::string >( "cfg-directory" ) );
207 if ( !msgcat_loaded )
212 std::map< std::string, std::string >::const_iterator iter( msgcat.find( message ) ), last( msgcat.end() );
215 std::string const& result( iter->second );