@@ -67,18 +67,17 @@ private void Load() {
6767 string filename = $ "{ Translation . RESOURCES_PREFIX } Translations.{ Name } .csv";
6868 Log . Info ( $ "Loading translations: { filename } ") ;
6969
70- string [ ] lines ;
70+ string firstLine ;
71+ string dataBlock ;
7172 using ( Stream st = Assembly . GetExecutingAssembly ( )
7273 . GetManifestResourceStream ( filename ) ) {
7374 using ( var sr = new StreamReader ( st , Encoding . UTF8 ) ) {
74- lines = sr . ReadToEnd ( )
75- . Split ( new [ ] { "\n " , "\r \n " } , StringSplitOptions . None ) ;
75+ ReadLines ( sr , out firstLine , out dataBlock ) ;
7676 }
7777 }
7878
7979 // Read each line as CSV line
8080 // Read language order in the first line
81- string firstLine = lines [ 0 ] ;
8281 var languageCodes = new List < string > ( ) ;
8382 using ( var sr = new StringReader ( firstLine ) ) {
8483 ReadCsvCell ( sr ) ; // skip
@@ -96,19 +95,38 @@ private void Load() {
9695 }
9796 }
9897
98+ CollectTranslations ( dataBlock , languageCodes , out AllLanguages ) ;
99+
100+ #if DUMP_TRANSLATIONS
101+ DumpTranslationsToCsv ( ) ;
102+ #endif
103+ Log . _Debug ( $ "Loaded { AllLanguages . Count } different languages for { Name } ") ;
104+ }
105+
106+ /// <summary>
107+ /// Collects translations to map - collection of keyValue pairs for each language code
108+ /// </summary>
109+ /// <param name="dataBlock">block of data (all rows excluding first)</param>
110+ /// <param name="languageCodes">list of language codes</param>
111+ /// <param name="allLanguages">result dictionary where all translation string will be collected</param>
112+ private static void CollectTranslations ( string dataBlock ,
113+ List < string > languageCodes ,
114+ out Dictionary < string , Dictionary < string , string > > allLanguages ) {
115+ allLanguages = new Dictionary < string , Dictionary < string , string > > ( ) ;
99116 // Initialize empty dicts for each language
100117 foreach ( string lang in languageCodes ) {
101- AllLanguages [ lang ] = new Dictionary < string , string > ( ) ;
118+ allLanguages [ lang ] = new Dictionary < string , string > ( ) ;
102119 }
103120
104121 // first column is the translation key
105122 // Following columns are languages, following the order in AvailableLanguageCodes
106- foreach ( string line in lines . Skip ( 1 ) ) {
107- using ( var sr = new StringReader ( line ) ) {
123+ using ( var sr = new StringReader ( dataBlock ) ) {
124+ while ( true ) {
108125 string key = ReadCsvCell ( sr ) ;
109126 if ( key . Length == 0 ) {
110127 break ; // last line is empty
111128 }
129+
112130 foreach ( string lang in languageCodes ) {
113131 string cell = ReadCsvCell ( sr ) ;
114132 // Empty translations are not accepted for all languages other than English
@@ -117,15 +135,23 @@ private void Load() {
117135 lang != Translation . DEFAULT_LANGUAGE_CODE ) {
118136 continue ;
119137 }
120- AllLanguages [ lang ] [ key ] = cell ;
138+
139+ allLanguages [ lang ] [ key ] = cell ;
121140 }
122141 }
123142 }
143+ }
124144
125- #if DUMP_TRANSLATIONS
126- DumpTranslationsToCsv ( ) ;
127- #endif
128- Log . _Debug ( $ "Loaded { AllLanguages . Count } different languages for { Name } ") ;
145+ /// <summary>
146+ /// Split stream of data on first row and remaining dataBlock
147+ /// </summary>
148+ /// <param name="sr">stream to read from</param>
149+ /// <param name="firstLine">first line of tranlation - row with language code names</param>
150+ /// <param name="dataBlock">string block of data (all remaining lines)</param>
151+ /// <returns>collection of valid translation rows</returns>
152+ private static void ReadLines ( StreamReader sr , out string firstLine , out string dataBlock ) {
153+ firstLine = sr . ReadLine ( ) ;
154+ dataBlock = sr . ReadToEnd ( ) ;
129155 }
130156
131157 /// <summary>
@@ -162,18 +188,27 @@ private static string ReadCsvCell(StringReader sr) {
162188 break ;
163189 }
164190 case '\" ' : {
165- // Found a '""', or a '",'
191+ // Found a '""', or a '",', or a '"/r', or a '"/r'
166192 int peek = sr . Peek ( ) ;
167193 switch ( peek ) {
168194 case '\" ' : {
169195 sr . Read ( ) ; // consume the double quote
170196 sb . Append ( "\" " ) ;
171197 break ;
172198 }
199+ case '\r ' :
200+ //Followed by a \r then \n or just \n - end-of-string
201+ sr . Read ( ) ; // consume double quote
202+ sr . Read ( ) ; // consume \r
203+ if ( sr . Peek ( ) == '\n ' ) {
204+ sr . Read ( ) ; // consume \n
205+ }
206+ return sb . ToString ( ) ;
207+ case '\n ' :
173208 case ',' :
174209 case - 1 : {
175210 // Followed by a comma or end-of-string
176- sr . Read ( ) ; // Consume the comma
211+ sr . Read ( ) ; // Consume the comma or newLine(LF)
177212 return sb . ToString ( ) ;
178213 }
179214 default : {
@@ -191,11 +226,15 @@ private static string ReadCsvCell(StringReader sr) {
191226 }
192227 }
193228 } else {
194- // Simple reading rules apply, read to the next comma or end-of-string
229+ // Simple reading rules apply, read to the next comma, LF sequence or end-of-string
195230 while ( true ) {
196231 int next = sr . Read ( ) ;
197- if ( next == - 1 || next == ',' ) {
198- break ; // end-of-string or a comma
232+ if ( next == - 1 || next == ',' || next == '\n ' ) {
233+ break ; // end-of-string, a newLine or a comma
234+ }
235+ if ( next == '\r ' && sr . Peek ( ) == '\n ' ) {
236+ sr . Read ( ) ; //consume LF(\n) to complete CRLF(\r\n) newLine escape sequence
237+ break ;
199238 }
200239
201240 sb . Append ( ( char ) next , 1 ) ;
0 commit comments