/// <summary>
        /// Store the changes in the data table back to the .RESX files
        /// </summary>
        private void saveTable(
            Project project,
            DataTable table,
            bool wantBackupFiles,
            bool omitEmptyStrings)
        {
            var index = 0;
            var languageCodeDetection = new LanguageCodeDetection(_gridEditableData.Project);

            foreach (var resxFile in _resxFiles)
            {
                try
                {
                    var checksum = resxFile.FileInformation.FileGroup.GetChecksum(project);
                    var document = resxFile.Document;
                    var fileName = resxFile.FilePath.Name;

                    //Member 802361: access value by culture and not by filename
                    var culture =
                        languageCodeDetection.DetectLanguageCodeFromFileName(
                            _gridEditableData.Project,
                            fileName);

                    // 2011-04-09, Uwe Keim: "nb" => "nb-NO".
                    var cultureLong = LanguageCodeDetection.MakeValidCulture(culture).Name;

                    foreach (DataRow row in table.Rows)
                    {
                        if (row.RowState != DataRowState.Deleted)
                        {
                            if (!FileGroup.IsInternalRow(row))
                            {
                                var fileGroupCheckSum = ConvertHelper.ToInt64(row[@"FileGroup"]);

                                // 2010-10-23, Uwe Keim: Only save if same file group.
                                if (fileGroupCheckSum == checksum)
                                {
                                    var tagName = (string)row[@"Name"];

                                    var xpathQuery = $@"child::data[attribute::name='{escapeXsltChars(tagName)}']";

                                    if (document.DocumentElement != null)
                                    {
                                        var node  = document.DocumentElement.SelectSingleNode(xpathQuery);
                                        var found = node != null;

                                        var content   = row[cultureLong] as string;
                                        var textToSet = content ?? string.Empty;

                                        var commentsAreVisible =
                                            CommentsAreVisible(project, row, CommentVisibilityScope.InMemory);

                                        // AJ CHANGE
                                        var commentToSet =
                                            commentsAreVisible
                                                ? row[@"Comment"] == DBNull.Value
                                                    ? string.Empty
                                                    : (string)row[@"Comment"]
                                                : null;

                                        if (found)
                                        {
                                            var n = node.SelectSingleNode(@"value");

                                            //CHANGED:  Member 802361 if content is null remove this entry
                                            if (content != null &&
                                                (!string.IsNullOrEmpty(textToSet) || !omitEmptyStrings))
                                            {
                                                // If not present (for whatever reason, e.g.
                                                // manually edited and therefore misformed).
                                                if (n == null)
                                                {
                                                    n = document.CreateElement(@"value");
                                                    node.AppendChild(n);
                                                }

                                                n.InnerText = textToSet;

                                                // AJ CHANGE
                                                // Only write the comment to the main resx file
                                                if (commentsAreVisible)
                                                {
                                                    if (resxFile == _resxFiles[0])
                                                    {
                                                        n = node.SelectSingleNode(@"comment");
                                                        // If not present (for whatever reason, e.g.
                                                        // manually edited and therefore misformed).
                                                        if (n == null)
                                                        {
                                                            n = document.CreateElement(@"comment");
                                                            node.AppendChild(n);
                                                        }

                                                        n.InnerText = commentToSet ?? string.Empty;
                                                    }
                                                }
                                            }
                                            else
                                            {
                                                if (n != null)
                                                {
                                                    node.RemoveChild(n);
                                                }

                                                node.ParentNode?.RemoveChild(node);
                                            }
                                        }
                                        else // Resource doesn't exist in XML.
                                        {
                                            if (content != null &&
                                                (!string.IsNullOrEmpty(textToSet) || !omitEmptyStrings))
                                            {
                                                // Member 802361: only do it if editing single fileGroup.
                                                // If no we don't know where to add the new entry.
                                                // TODO: may be add to default file in the list?
                                                if (_gridEditableData.FileGroup == null)
                                                {
                                                    //look if base file has same tagName
                                                    //if base file skip it
                                                    if (string.Compare(
                                                            _gridEditableData.Project.NeutralLanguageCode,
                                                            culture,
                                                            StringComparison.OrdinalIgnoreCase) == 0 ||
                                                        string.Compare(
                                                            _gridEditableData.Project.NeutralLanguageCode,
                                                            cultureLong,
                                                            StringComparison.OrdinalIgnoreCase) == 0)
                                                    {
                                                        continue;
                                                    }

                                                    // 2011-01-26, Uwe Keim:
                                                    var pattern =
                                                        resxFile.FileInformation.FileGroup.ParentSettings
                                                        .EffectiveNeutralLanguageFileNamePattern;
                                                    pattern =
                                                        pattern.Replace(@"[basename]",
                                                                        resxFile.FileInformation.FileGroup.BaseName);
                                                    pattern =
                                                        pattern.Replace(@"[languagecode]", project.NeutralLanguageCode);
                                                    pattern =
                                                        pattern.Replace(@"[extension]",
                                                                        resxFile.FileInformation.FileGroup.BaseExtension);
                                                    pattern = pattern.Replace(@"[optionaldefaulttypes]",
                                                                              resxFile.FileInformation.FileGroup.BaseOptionalDefaultType);

                                                    //has base culture value?
                                                    var baseName = pattern;

                                                    // 2011-01-26, Uwe Keim:
                                                    var file         = resxFile;
                                                    var baseResxFile =
                                                        _resxFiles.Find(
                                                            resx =>
                                                            resx.FilePath.Name == baseName &&
                                                            resx.FileInformation.FileGroup.UniqueID ==
                                                            file.FileInformation.FileGroup.UniqueID);

                                                    var baseNode =
                                                        baseResxFile?.Document?.DocumentElement
                                                        ?.SelectSingleNode(xpathQuery);
                                                    if (baseNode == null)
                                                    {
                                                        continue;
                                                    }
                                                    //ok we can add it.
                                                }
                                                //TODO: use default instead

                                                //Create the new Node
                                                XmlNode newData  = document.CreateElement(@"data");
                                                var     newName  = document.CreateAttribute(@"name");
                                                var     newSpace = document.CreateAttribute(@"xml:space");
                                                XmlNode newValue = document.CreateElement(@"value");

                                                // Set the Values
                                                newName.Value      = (string)row[@"Name"];
                                                newSpace.Value     = @"preserve";
                                                newValue.InnerText = textToSet;

                                                // Get them together
                                                if (newData.Attributes != null)
                                                {
                                                    newData.Attributes.Append(newName);
                                                    newData.Attributes.Append(newSpace);
                                                }
                                                newData.AppendChild(newValue);

                                                // AJ CHANGE
                                                // Only write the comment to the main resx file
                                                if (commentsAreVisible && index == 0)
                                                {
                                                    XmlNode newComment = document.CreateElement(@"comment");
                                                    newComment.InnerText = commentToSet ?? string.Empty;
                                                    newData.AppendChild(newComment);
                                                }

                                                XmlNode root = document.DocumentElement;
                                                root?.InsertAfter(newData, root.LastChild);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                finally
                {
                    index++;
                }
            }

            if (wantBackupFiles)
            {
                backupFiles();
            }

            // Store files back to filesystem
            storeFiles(project);
        }
		/// <summary>
		/// Store the changes in the data table back to the .RESX files
		/// </summary>
		private void saveTable(
			Project project,
			DataTable table,
			bool wantBackupFiles,
			bool omitEmptyStrings)
		{
			var index = 0;
			var languageCodeDetection = new LanguageCodeDetection(_gridEditableData.Project);

			foreach (var resxFile in _resxFiles)
			{
				try
				{
					var checksum = resxFile.FileInformation.FileGroup.GetChecksum(project);
					var document = resxFile.Document;
					var fileName = resxFile.FilePath.Name;

					//Member 802361: access value by culture and not by filename
					var culture =
						languageCodeDetection.DetectLanguageCodeFromFileName(
							_gridEditableData.Project,
							fileName);

					// 2011-04-09, Uwe Keim: "nb" => "nb-NO".
					var cultureLong = LanguageCodeDetection.MakeValidCulture(culture).Name;

					foreach (DataRow row in table.Rows)
					{
						if (row.RowState != DataRowState.Deleted)
						{
							if (!FileGroup.IsInternalRow(row))
							{
								var fileGroupCheckSum = ConvertHelper.ToInt64(row[@"FileGroup"]);

								// 2010-10-23, Uwe Keim: Only save if same file group.
								if (fileGroupCheckSum == checksum)
								{
									var tagName = (string)row[@"Name"];

									var xpathQuery =
										string.Format(
											@"child::data[attribute::name='{0}']",
											escapeXsltChars(tagName));

									if (document.DocumentElement != null)
									{
										var node = document.DocumentElement.SelectSingleNode(xpathQuery);
										var found = node != null;

										var content = row[cultureLong] as string;
										var textToSet = content ?? string.Empty;

										var commentsAreVisible =
											CommentsAreVisible(project, row, CommentVisibilityScope.InMemory);

										// AJ CHANGE
										var commentToSet =
											commentsAreVisible
												? row[@"Comment"] == DBNull.Value
													? string.Empty
													: (string)row[@"Comment"]
												: null;

										if (found)
										{
											var n = node.SelectSingleNode(@"value");

											//CHANGED: 	Member 802361 if content is null remove this entry
											if (content != null &&
												(!string.IsNullOrEmpty(textToSet) || !omitEmptyStrings))
											{
												// If not present (for whatever reason, e.g. 
												// manually edited and therefore misformed).
												if (n == null)
												{
													n = document.CreateElement(@"value");
													node.AppendChild(n);
												}

												n.InnerText = textToSet;

												// AJ CHANGE
												// Only write the comment to the main resx file
												if (commentsAreVisible)
												{
													if (resxFile == _resxFiles[0])
													{
														n = node.SelectSingleNode(@"comment");
														// If not present (for whatever reason, e.g. 
														// manually edited and therefore misformed).
														if (n == null)
														{
															n = document.CreateElement(@"comment");
															node.AppendChild(n);
														}

														n.InnerText = commentToSet ?? string.Empty;
													}
												}
											}
											else
											{
												if (n != null)
												{
													node.RemoveChild(n);
												}

												if (node.ParentNode != null)
												{
													node.ParentNode.RemoveChild(node);
												}
											}
										}
										else // Resource doesn't exist in XML.
										{
											if (content != null &&
												(!string.IsNullOrEmpty(textToSet) || !omitEmptyStrings))
											{
												// Member 802361: only do it if editing single fileGroup. 
												// If no we don't know where to add the new entry.
												// TODO: may be add to default file in the list?
												if (_gridEditableData.FileGroup == null)
												{
													//look if base file has same tagName
													//if base file skip it
													if (string.Compare(
														_gridEditableData.Project.NeutralLanguageCode,
														culture,
														true) == 0 ||
													    string.Compare(
													    	_gridEditableData.Project.NeutralLanguageCode,
													    	cultureLong,
													    	true) == 0)
													{
														continue;
													}

													// 2011-01-26, Uwe Keim:
													var pattern =
														resxFile.FileInformation.FileGroup.ParentSettings.EffectiveNeutralLanguageFileNamePattern;
													pattern = pattern.Replace(@"[basename]", resxFile.FileInformation.FileGroup.BaseName);
													pattern = pattern.Replace(@"[languagecode]", project.NeutralLanguageCode);
													pattern = pattern.Replace(@"[extension]", resxFile.FileInformation.FileGroup.BaseExtension);
													pattern = pattern.Replace(@"[optionaldefaulttypes]",
													                          resxFile.FileInformation.FileGroup.BaseOptionalDefaultType);

													//has base culture value?
													var baseName = pattern;

													// 2011-01-26, Uwe Keim:
													var file = resxFile;
													var baseResxFile =
														_resxFiles.Find(
															resx =>
															resx.FilePath.Name == baseName &&
															resx.FileInformation.FileGroup.UniqueID ==
															file.FileInformation.FileGroup.UniqueID);
													if (baseResxFile == null ||
													    baseResxFile.Document == null ||
													    baseResxFile.Document.DocumentElement == null)
													{
														continue;
													}

													var baseNode =
														baseResxFile.Document.DocumentElement.
															SelectSingleNode(xpathQuery);
													if (null == baseNode)
													{
														continue;
													}
													//ok we can add it.
												}
												//TODO: use default instead

												//Create the new Node
												XmlNode newData = document.CreateElement(@"data");
												var newName = document.CreateAttribute(@"name");
												var newSpace = document.CreateAttribute(@"xml:space");
												XmlNode newValue = document.CreateElement(@"value");

												// Set the Values
												newName.Value = (string)row[@"Name"];
												newSpace.Value = @"preserve";
												newValue.InnerText = textToSet;

												// Get them together
												if (newData.Attributes != null)
												{
													newData.Attributes.Append(newName);
													newData.Attributes.Append(newSpace);
												}
												newData.AppendChild(newValue);

												// AJ CHANGE
												// Only write the comment to the main resx file
												if (commentsAreVisible && index == 0)
												{
													XmlNode newComment = document.CreateElement(@"comment");
													newComment.InnerText = commentToSet ?? string.Empty;
													newData.AppendChild(newComment);
												}

												XmlNode root = document.DocumentElement;
												if (root != null)
												{
													root.InsertAfter(newData, root.LastChild);
												}
											}
										}
									}
								}
							}
						}
					}
				}
				finally
				{
					index++;
				}
			}

			if (wantBackupFiles)
			{
				backupFiles();
			}

			// Store files back to filesystem
			storeFiles();
		}