@@ -117,20 +117,24 @@ public string SerializeToString(ResourceFile file)
117117 ? CreateXliff20Document ( file )
118118 : CreateXliff12Document ( file ) ;
119119
120+ // Use UTF-8 without BOM to avoid double-BOM issues when file is rewritten
121+ var utf8NoBom = new UTF8Encoding ( false ) ;
120122 var settings = new XmlWriterSettings
121123 {
122124 Indent = true ,
123125 IndentChars = " " ,
124- Encoding = Encoding . UTF8 ,
126+ Encoding = utf8NoBom ,
125127 OmitXmlDeclaration = false
126128 } ;
127129
128- using var sw = new StringWriter ( ) ;
129- using ( var writer = XmlWriter . Create ( sw , settings ) )
130+ // Use MemoryStream instead of StringWriter to properly handle UTF-8 encoding
131+ // StringWriter always reports UTF-16 encoding regardless of XmlWriterSettings
132+ using var ms = new MemoryStream ( ) ;
133+ using ( var writer = XmlWriter . Create ( ms , settings ) )
130134 {
131135 doc . Save ( writer ) ;
132- } // XmlWriter is disposed and flushed here
133- return sw . ToString ( ) ;
136+ }
137+ return utf8NoBom . GetString ( ms . ToArray ( ) ) ;
134138 }
135139
136140 /// <summary>
@@ -140,17 +144,19 @@ private XDocument CreateXliff12Document(ResourceFile file)
140144 {
141145 var root = new XElement ( Ns12 + "xliff" ,
142146 new XAttribute ( "version" , "1.2" ) ,
143- new XAttribute ( XNamespace . Xmlns + "xsi" , "http://www.w3.org/2001/XMLSchema-instance" ) ,
144147 new XAttribute ( "xmlns" , Ns12 . NamespaceName ) ) ;
145148
149+ // For XLIFF, we always use the language code for both source and target
150+ // Even for default language files, we write target-language to preserve bilingual structure
146151 var sourceLanguage = file . Language . IsDefault ? file . Language . Code : "en" ;
147- var targetLanguage = file . Language . IsDefault ? "" : file . Language . Code ;
152+ var targetLanguage = file . Language . Code ;
148153
149154 var fileElement = new XElement ( Ns12 + "file" ,
150155 new XAttribute ( "original" , file . Language . BaseName ?? "resources" ) ,
151156 new XAttribute ( "source-language" , sourceLanguage ) ,
152157 new XAttribute ( "datatype" , "plaintext" ) ) ;
153158
159+ // Always write target-language attribute to preserve bilingual structure
154160 if ( ! string . IsNullOrEmpty ( targetLanguage ) )
155161 {
156162 fileElement . Add ( new XAttribute ( "target-language" , targetLanguage ) ) ;
@@ -187,22 +193,17 @@ private XDocument CreateXliff12Document(ResourceFile file)
187193
188194 /// <summary>
189195 /// Creates a trans-unit element for XLIFF 1.2.
196+ /// Always creates both source and target elements to preserve bilingual structure.
190197 /// </summary>
191198 private XElement CreateTransUnit12 ( ResourceEntry entry , bool isDefault )
192199 {
193200 var unit = new XElement ( Ns12 + "trans-unit" ,
194201 new XAttribute ( "id" , entry . Key ) ) ;
195202
196- // Source is the key for default language, or include bilingual content
197- if ( isDefault || _config . Bilingual )
198- {
199- unit . Add ( new XElement ( Ns12 + "source" , entry . Value ?? "" ) ) ;
200- }
201- else
202- {
203- unit . Add ( new XElement ( Ns12 + "source" , entry . Key ) ) ;
204- unit . Add ( new XElement ( Ns12 + "target" , entry . Value ?? "" ) ) ;
205- }
203+ // Always write both source (key) and target (value) for proper bilingual structure
204+ // Source contains the key identifier, target contains the translated value
205+ unit . Add ( new XElement ( Ns12 + "source" , entry . Key ) ) ;
206+ unit . Add ( new XElement ( Ns12 + "target" , entry . Value ?? "" ) ) ;
206207
207208 if ( ! string . IsNullOrEmpty ( entry . Comment ) )
208209 {
@@ -272,6 +273,7 @@ private XDocument CreateXliff20Document(ResourceFile file)
272273
273274 /// <summary>
274275 /// Creates a unit element for XLIFF 2.0.
276+ /// Always creates both source and target elements to preserve bilingual structure.
275277 /// </summary>
276278 private XElement CreateUnit20 ( ResourceEntry entry , bool isDefault )
277279 {
@@ -299,18 +301,10 @@ private XElement CreateUnit20(ResourceEntry entry, bool isDefault)
299301 }
300302 else
301303 {
302- var segment = new XElement ( Ns20 + "segment" ) ;
303-
304- if ( isDefault )
305- {
306- segment . Add ( new XElement ( Ns20 + "source" , entry . Value ?? "" ) ) ;
307- }
308- else
309- {
310- segment . Add ( new XElement ( Ns20 + "source" , entry . Key ) ) ;
311- segment . Add ( new XElement ( Ns20 + "target" , entry . Value ?? "" ) ) ;
312- }
313-
304+ // Always write both source (key) and target (value) for proper bilingual structure
305+ var segment = new XElement ( Ns20 + "segment" ,
306+ new XElement ( Ns20 + "source" , entry . Key ) ,
307+ new XElement ( Ns20 + "target" , entry . Value ?? "" ) ) ;
314308 unit . Add ( segment ) ;
315309 }
316310
0 commit comments