source: cfg_itronx+oil_gcc/toppers/gettext.cpp@ 165

Last change on this file since 165 was 54, checked in by ertl-ishikawa, 12 years ago

cfg+oil対応コンフィギュレータを追加

File size: 7.0 KB
Line 
1/*
2 * TOPPERS Software
3 * Toyohashi Open Platform for Embedded Real-Time Systems
4 *
5 * Copyright (C) 2007-2011 by TAKAGI Nobuhisa
6 *
7 * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
8 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
9 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
10 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
11 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
12 * スコード中に含まれていること.
13 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
14 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
15 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
16 * の無保証規定を掲載すること.
17 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
18 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
19 * と.
20 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
21 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
22 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
23 * 報告すること.
24 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
25 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
26 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
27 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
28 * 免責すること.
29 *
30 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
31 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
32 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
33 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
34 * の責任を負わない.
35 *
36 */
37#include <cstdlib>
38#include <stdlib.h> // Cygwin対策
39#include <cstring>
40#include <clocale>
41#include <string>
42#include <map>
43#include <fstream>
44#include <stdexcept>
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>
52
53namespace toppers
54{
55 namespace
56 {
57
58 std::map< std::string, std::string > msgcat;
59
60 void register_msgcat( std::string const& msgid, std::string const& msgstr )
61 {
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();
66 wchar_t wc = 0;
67 for ( std::string::const_iterator iter( msgstr.begin() ), last( msgstr.end() ); iter != last; ++iter )
68 {
69 int c = static_cast< unsigned char >( *iter );
70 if ( ( ( c & 0xc0 ) == 0xc0 ) || ( c < 0x80 ) ) // 先行バイト
71 {
72 if ( wc != 0 )
73 {
74 *wcs++ = wc;
75 wc = 0;
76 }
77 if ( ( c & 0x80 ) == 0 )
78 {
79 wc = static_cast< wchar_t >( c );
80 }
81 else if ( ( c & 0xe0 ) == 0xc0 )
82 {
83 wc = static_cast< wchar_t >( c & 0x1f );
84 }
85 else if ( ( c & 0xf0 ) == 0xe0 )
86 {
87 wc = static_cast< wchar_t >( c & 0xf );
88 }
89 else
90 {
91 // サロゲートは未対応(ここで対応したとしても、文字コード変換時にしくじる可能性大)
92 }
93 }
94 else // 後続バイト
95 {
96 wc = static_cast< wchar_t >( ( wc << 6 ) | ( c & 0x3f ) );
97 }
98 }
99 if ( wc != 0 )
100 {
101 *wcs++ = wc;
102 }
103 *wcs = L'\0';
104
105 // ↓ この間は決して例外が発生しない
106 char const* locale = std::setlocale( LC_CTYPE, "" );
107 /* std:: */wcstombs( buf.get(), wbuf.get(), size + 1 ); // Unicode から環境依存の文字コードへ変換
108 std::setlocale( LC_CTYPE, locale );
109 // ↑ この間は決して例外が発生しない
110
111 msgcat[ msgid ] = std::string( buf.get() );
112 }
113
114 bool msgcat_loaded = false;
115
116 }
117
118 /*!
119 * \brief メッセージカタログのロード
120 * \param[in] dir *.po ファイルが存在するディレクトリ
121 * \retval true 成功
122 * \retval false 失敗
123 *
124 * 実装を簡便化するため、.poファイルの記述方法には以下の制約がある。
125 * - msgid, msgstr は必ず行の先頭に記述する。
126 * - msgid, msgstr の直後には、必ず空白類文字一文字とし、その直後に文字列を記述する。
127 * - 文字列のみを記述する行は必ず " で始める。
128 * - .poファイルはの文字コードは必ず UTF-8N とする。
129 */
130 bool load_msgcat( std::string const& dir )
131 {
132 namespace fs = boost::filesystem;
133 char const* env = std::getenv( "TOPPERS_CFG_LANG" );
134// env = "ja";
135 if ( env == 0 )
136 {
137 return false;
138 }
139 std::string lang( env );
140
141// fs::path cfg_dir( dir, fs::native );
142 fs::path cfg_dir( dir ); // filesystem3対応
143// fs::path po_file( cfg_dir/fs::path( lang + ".po", fs::native ) );
144 fs::path po_file( cfg_dir/fs::path( lang + ".po" ) ); // filesystem3対応
145
146// std::ifstream ifs( po_file.native_file_string().c_str() );
147 std::ifstream ifs( po_file.string().c_str() ); // filesystem3対応
148 std::string msgid;
149 std::string msgstr;
150
151 while ( ifs )
152 {
153 std::string str;
154 std::getline( ifs, str );
155
156 // 改行文字の違いを吸収
157 std::string::size_type pos = str.find_last_not_of( " \t\r\n" ); // ついでに行末の空白類も除去
158 if ( pos != std::string::npos && pos < str.size() - 1 )
159 {
160 char c = str[pos];
161 str.erase( pos + 1, std::string::npos );
162 }
163
164 if ( str.empty() || str[ 0 ] == '#' || str == "" )
165 {
166 ; // 空行またはコメント行
167 }
168 else
169 {
170 try
171 {
172 if ( std::strncmp( str.c_str(), "msgid", sizeof( "msgid" )-1 ) == 0 )
173 {
174 str.erase( 0, sizeof( "msgid" )-1+1 );
175 msgid = expand_quote( str );
176 }
177 else if ( std::strncmp( str.c_str(), "msgstr", sizeof( "msgstr" )-1 ) == 0 )
178 {
179 str.erase( 0, sizeof( "msgstr" )-1+1 );
180 msgstr = expand_quote( str );
181 }
182 else
183 {
184 msgstr += expand_quote( str );
185 }
186 if ( !msgid.empty() && !msgstr.empty() ) // 直前の msgid / msgstr を登録
187 {
188 register_msgcat( msgid, msgstr );
189 msgid.clear();
190 msgstr.clear();
191 }
192 }
193 catch ( std::invalid_argument& )
194 {
195 return false;
196 }
197 }
198 }
199 msgcat_loaded = true;
200 return true;
201 }
202
203 /*!
204 * \brief メッセージの翻訳
205 * \param[in] message メッセージID
206 * \return 翻訳後のメッセージ
207 */
208 std::string const& gettext( std::string const& message )
209 {
210 static bool f = load_msgcat( get_global< std::string >( "cfg-directory" ) );
211 if ( !msgcat_loaded )
212 {
213 return message;
214 }
215
216 std::map< std::string, std::string >::const_iterator iter( msgcat.find( message ) ), last( msgcat.end() );
217 if ( iter != last )
218 {
219 std::string const& result( iter->second );
220 return result;
221 }
222 return message;
223 }
224
225}
Note: See TracBrowser for help on using the repository browser.