Beispiel #1
0
 /// <summary>
 ///     Clean up after BackgroundWorker finished.
 ///     Throws Exceptions, but cannot interupt main thread.
 /// </summary>
 /// <exception cref="FileFormatException">
 ///     Thrown, if file at <see cref="Path" /> is not a valid Excel sheet.
 /// </exception>
 public void LoadExcelLanguageFileAsyncCompleted(object sender, RunWorkerCompletedEventArgs e)
 {
     if (e.Cancelled)
     {
         _logger.Log(LogLevel.Debug, "Loading of the language file was stoped.");
     }
     else if (e.Error != null)
     {
         if (e.Error.HResult == -2146827284)
         {
             ExceptionLoggingUtils.Throw(_logger, new FileFormatException(new Uri(Path),
                     "Expected Excel file format.", e.Error),
                 "File at given path may be corrupted or not have correct format. " +
                 "Expected Excel sheet (.xlsx, .xls, ...).");
         }
         else if (e.Error.GetType() == typeof(CultureNotFoundException))
         {
             _logger.Log(LogLevel.Error, e.Error, "One of the cells in the first row was expected to " +
                                                  "contain a language code, but did not.");
         }
         else
         {
             _logger.Log(LogLevel.Error, e.Error, "Unknown error occurred during language file loading.");
         }
     }
     else
     {
         _logger.Log(LogLevel.Debug, "BackgroundWorker successfully finished loading the language file.");
     }
 }
        /// <summary>
        ///     Creates the instance of the ExcelFileProvider, which reads and persists all translations as Excel-files.
        ///     A backup Excel-file will be created for all edits.
        /// </summary>
        /// <param name="translationFilePath">Path to the file containing the translations.</param>
        /// <param name="glossaryTag">
        ///     (Optional) Entries in the Excel table that start with this tag will be interpreted as part of the glossary.
        /// </param>
        /// <param name="oldTranslationFilePath">
        ///     (Optional) The path to where the original translation file will be copied as a backup.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     Thrown, if <paramref name="translationFilePath" /> is null.
        /// </exception>
        /// <exception cref="UnauthorizedAccessException">
        ///     Thrown, if the permissions are missing that are needed to create the directory for
        ///     <paramref name="translationFilePath" /> / <paramref name="oldTranslationFilePath" /> or one of them
        ///     is write-only, read-only, a directory, hidden, the needed permissions for opening or writing are
        ///     missing or the operation is not supported on the current platform.
        /// </exception>
        /// <exception cref="System.Security.SecurityException">
        ///     Thrown, if certain permissions are missing. (CLR level)
        /// </exception>
        /// <exception cref="FileNotFoundException">
        ///     Thrown, if <paramref name="translationFilePath" /> / <paramref name="oldTranslationFilePath" />
        ///     does not exist or cannot be found.
        /// </exception>
        /// <exception cref="IOException">
        ///     Thrown, if an unknown I/O-Error occurs.
        /// </exception>
        /// <exception cref="NotSupportedException">
        ///     Thrown, if <paramref name="translationFilePath" /> / <paramref name="oldTranslationFilePath" />
        ///     contains a colon anywhere other than as part of a volume identifier ("C:\").
        /// </exception>
        /// <exception cref="PathTooLongException">
        ///     Thrown, if <paramref name="translationFilePath" /> / <paramref name="oldTranslationFilePath" />
        ///     is too long.
        /// </exception>
        /// <exception cref="DirectoryNotFoundException">
        ///     Thrown, if the directory was not found.
        ///     For example because it is on an unmapped device.
        /// </exception>
        public ExcelFileProvider(string translationFilePath, string glossaryTag = null,
                                 string oldTranslationFilePath = null)
        {
            //set Status.
            Status = ProviderStatus.InitializationInProgress;

            //easy initializations.
            _logger = GlobalSettings.LibraryLoggerFactory.CreateLogger <ExcelFileProvider>();
            _logger.Log(LogLevel.Trace, "Initializing ExcelFileProvider.");
            _fileHandler = new ExcelFileHandler(typeof(ExcelFileProvider),
                                                //make sure all possible not-null values for glossaryTag can be recognized in sheet.
                                                glossaryTag == string.Empty ? null : glossaryTag);

            //null check.
            ExceptionLoggingUtils.ThrowIfNull(_logger, (object)translationFilePath, nameof(translationFilePath),
                                              "Unable to open null path.", "ExcelFileProvider received null parameter in constructor.");

            //start difficult initializations.
            if (oldTranslationFilePath != null)
            {
                _fileHandler.VerifyPath(oldTranslationFilePath);
                _backupPath = oldTranslationFilePath;
            }

            _fileHandler.VerifyPath(translationFilePath);
            _path             = translationFilePath;
            _fileHandler.Path = _path;

            Initialize();
        }
        /// <summary>
        ///     Goes through all elements nested inside <paramref name="rootElement" /> and writes the current
        ///     translation into each element.
        /// </summary>
        /// <param name="rootElement">
        ///     The element, based on which all nested elements will recursively be translated.
        ///     <paramref name="rootElement" /> itself will also be translated.
        /// </param>
        public static void TranslateGui(FrameworkElement rootElement)
        {
            //null check.
            ExceptionLoggingUtils.ThrowIfNull(Logger, rootElement, nameof(rootElement),
                                              "Unable to translate null UserControl / Window.",
                                              "TranslateGui received null as root element for translation.");

            //TranslateGuiElement will do nothing if visual is a non translatable like Grid.
            TranslateGuiElement(rootElement);

            foreach (var childVisual in LogicalTreeHelper.GetChildren(rootElement))
            {
                //if View or Window contain a TabControl - break foreach to prevent translating sub View.
                if (childVisual is TabControl)
                {
                    break;
                }

                if (childVisual is FrameworkElement element)
                {
                    //also iterate all childs of visual, if they are FrameworkElements.
                    //as DataGridColumns are not FrameworkElements, they require special treatment in TranslateGuiElement.
                    TranslateGui(element);
                }
            }
        }
        /// <exception cref="ResourcesNotFoundException">
        ///     Thrown, if both <see cref="GlobalSettings.ResourcesAssembly" /> is not set and the entry assembly
        ///     cannot be accesed.
        /// </exception>
        private void ReadDicts()
        {
            var rm = ResourcesManagerProvider.GetResourcesManager();

            Dictionary <string, string> invariantFallback = null;

            //collect all Resource entries.
            var langs = CultureInfo.GetCultures(CultureTypes.AllCultures);

            foreach (var lang in langs)
            {
                try
                {
                    //tryParents is false and will be handled in CultureInfoUtils insted, to avoid registering
                    //same dict multiple times.
                    var resourceSet = rm.GetResourceSet(lang, true, false);
                    if (resourceSet == null)
                    {
                        continue;
                    }

                    if (lang.Equals(CultureInfo.InvariantCulture))
                    {
                        invariantFallback = resourceSet.Cast <DictionaryEntry>().ToDictionary(
                            r => r.Key.ToString(), r => r.Value.ToString());
                    }
                    else
                    {
                        _dictOfDicts.Add(lang, resourceSet.Cast <DictionaryEntry>().ToDictionary(
                                             r => r.Key.ToString(), r => r.Value.ToString()));
                    }
                }
                catch (CultureNotFoundException)
                {
                    //all non-existent languages will be ignored.
                }
            }

            TryAddChangesIntoDictOfDicts();

            if (_dictOfDicts.ContainsKey(InputLanguage))
            {
                _dictOfDicts.Add(CultureInfo.InvariantCulture, invariantFallback);
            }
            //if Inputlanguage is not present, use invariant as replacement instead, because
            //InputLanguage is expected to always exist.
            else
            {
                ExceptionLoggingUtils.ThrowIf <InputLanguageNotFoundException>(invariantFallback == null,
                                                                               _logger, $"The given input language ({InputLanguage.EnglishName}) was not found in the " +
                                                                               "Resources files.");

                _dictOfDicts.Add(InputLanguage, invariantFallback);
            }

            _status = ProviderStatus.Initialized;
        }
        /// <summary>
        ///     Returns the internal dictionary of translations.
        /// </summary>
        /// <exception cref="FileProviderNotInitializedException">
        ///     Will be thrown if the object has not found a language file to pull translations from.
        /// </exception>
        public Dictionary <CultureInfo, Dictionary <string, string> > GetDictionary()
        {
            if (Status == ProviderStatus.Empty || Status == ProviderStatus.Initialized)
            {
                return(_dictOfDicts);
            }

            //ExcelFileProvider is still initializing, cancelling or cancelled.
            ExceptionLoggingUtils.Throw <FileProviderNotInitializedException>(_logger,
                                                                              "Dictionary was accessed, without ExcelFileProvider being initialized.");

            throw new NotSupportedException("unreachable code.");
        }
Beispiel #6
0
        /// <summary>
        ///     Handles Exception logging for the given <paramref name="path" />.
        ///     Returns the given <paramref name="path" /> with the appropriate ending, if it was not present.
        /// </summary>
        /// <param name="path">The path that should be verified.</param>
        /// <exception cref="ArgumentNullException">Thrown, if <paramref name="path" /> is null.</exception>
        /// <exception cref="ArgumentException">
        ///     Thrown, if <paramref name="path" /> contains only white space, includes
        ///     unsupported characters or if the system fails to get the fully qualified
        ///     location for the given path.
        /// </exception>
        /// <exception cref="System.Security.SecurityException">
        ///     Thrown, if the permissions for accessing the full path are missing.
        /// </exception>
        /// <exception cref="NotSupportedException">
        ///     Thrown, if <paramref name="path" /> contains a colon anywhere other than as part of a
        ///     volume identifier ("C:\").
        /// </exception>
        /// <exception cref="PathTooLongException">
        ///     Thrown, if <paramref name="path" /> is too long.
        /// </exception>
        /// <exception cref="UnauthorizedAccessException">
        ///     Thrown, if permissions to create the directory are missing.
        /// </exception>
        /// <exception cref="DirectoryNotFoundException">
        ///     Thrown, if the directory was not found.
        ///     For example because it is on an unmapped device.
        /// </exception>
        /// <exception cref="IOException">
        ///     Thrown, if a file with the name of the dictionary that should be created already exists.
        /// </exception>
        /// <exception cref="FileNotFoundException">
        ///     Thrown, if <paramref name="path" /> is a dictionary.
        /// </exception>
        public void VerifyPath(string path)
        {
            ExceptionLoggingUtils.ThrowIfNull(_logger, nameof(VerifyPath), (object)path, nameof(path),
                                              "Unable to open path, because it is null.");

            var fullPath = GetFullPathWrapper(path);

            if (File.Exists(fullPath))
            {
                return;
            }

            ExceptionLoggingUtils.ThrowIf(Directory.Exists(fullPath), _logger, new FileNotFoundException(
                                              "Unable to find file, because directory with same name exists.", path),
                                          "Given path is directory instead of file.");

            CreateDirectoryWrapper(fullPath);
        }
        /// <summary>
        ///     Updates the internal dictionary of translations at <paramref name="key" /> with the given dictionary.
        ///     Only languages contained in <paramref name="texts" /> will be updated.
        ///     Will automatically write to file, if this is the first Update call
        ///     and no file existed upon creation of this object.
        /// </summary>
        /// <exception cref="ArgumentNullException">Thrown, if <paramref name="key" /> is null.</exception>
        /// <param name="key">The entry for which translations should be updated.</param>
        /// <param name="texts">
        ///     The new translations. If list is null or empty, no changes will be made to the dictionary.
        /// </param>
        public void Update(string key, IEnumerable <TextLocalization> texts)
        {
            //null checks.
            ExceptionLoggingUtils.ThrowIfNull(_logger, nameof(Update), (object)key, nameof(key),
                                              "Unable to update dictionary for null key.");
            if (texts == null)
            {
                //no exception has to be thrown here, because null is treated like empty list and
                //no translations will be updated.
                _logger.Log(LogLevel.Debug, "Unable to update dictionary for null translations. " +
                            "No translations were updated.");
                return;
            }

            //logging.
            IList <TextLocalization> textsEnumerated = texts.ToList();
            var textsString = string.Join(", ", textsEnumerated.Select(l => l.ToString()));

            _logger.Log(LogLevel.Trace, $"Update was called with {{{textsString}}} as translations for key ({key}).");

            //dictionary updates.
            if (!UpdateDictionary(key, textsEnumerated))
            {
                _logger.Log(LogLevel.Debug, "Did not update dictionary.");
                return;
            }

            //create file based on first entry,
            //if dictionary was updated and the file was created by JsonFileProvider itself.
            if (Status == ProviderStatus.Empty)
            {
                _logger.Log(LogLevel.Debug, "First update after empty sheet was created.");
                _fileHandler.ExcelWriteActions(_dictOfDicts);

                Status = ProviderStatus.Initialized;
                _logger.Log(LogLevel.Information, "Finished updating dictionary. " +
                            "ExcelFileProvider is now in State Initialized.");
            }
            else
            {
                _logger.Log(LogLevel.Debug, "Finished updating dictionary.");
            }
        }
        /// <summary>
        ///     Creates the instance of the JsonFileProvider, which reads and persists all translations from Json-files.
        /// </summary>
        /// <param name="translationFilePath">The path under which the dictionary will be saved.</param>
        /// <exception cref="ArgumentNullException">
        ///     Thrown, if <paramref name="translationFilePath" /> is null.
        /// </exception>
        /// <exception cref="UnauthorizedAccessException">
        ///     Thrown, if the permissions are missing that are needed to create the directory for
        ///     <paramref name="translationFilePath" /> or <paramref name="translationFilePath" /> is write-only,
        ///     read-only, a directory, hidden, the needed permissions for opening or writing are missing or
        ///     the operation is not supported on the current platform.
        /// </exception>
        /// <exception cref="System.Security.SecurityException">
        ///     Thrown, if certain permissions are missing. (CLR level)
        /// </exception>
        /// <exception cref="FileNotFoundException">
        ///     Thrown, if <paramref name="translationFilePath" /> does not exist or cannot be found.
        ///     For example because it is a direcory.
        /// </exception>
        /// <exception cref="IOException">
        ///     Thrown, if an unknown I/O-Error occurs.
        /// </exception>
        /// <exception cref="NotSupportedException">
        ///     Thrown, if <paramref name="translationFilePath" /> contains a colon anywhere other than as part of a
        ///     volume identifier ("C:\").
        /// </exception>
        /// <exception cref="PathTooLongException">
        ///     Thrown, if <paramref name="translationFilePath" /> is too long.
        /// </exception>
        /// <exception cref="DirectoryNotFoundException">
        ///     Thrown, if the directory was not found.
        ///     For example because it is on an unmapped device.
        /// </exception>
        public JsonFileProvider(string translationFilePath)
        {
            //set Status.
            Status = ProviderStatus.InitializationInProgress;

            //easy initializations.
            _logger = GlobalSettings.LibraryLoggerFactory.CreateLogger <JsonFileProvider>();
            _logger.Log(LogLevel.Trace, "Initializing JsonFileProvider.");
            _fileHandler = new UniversalFileHandler(typeof(JsonFileProvider));

            //null check.
            ExceptionLoggingUtils.ThrowIfNull(_logger, (object)translationFilePath, nameof(translationFilePath),
                                              "Unable to open null path.", "JsonFileProvider received null parameter in constructor.");

            //start proper initialization.
            _fileHandler.VerifyPath(translationFilePath);
            _path = translationFilePath;
            Initialize();
        }
Beispiel #9
0
        /// <summary>
        ///     Work for BackgroundWorker.
        ///     Loads the excel sheet at <see cref="Path" /> and saves it as its result.
        ///     <see cref="Path" /> has to be set to a value, before this handler is used.
        /// </summary>
        /// <exception cref="ArgumentNullException">
        ///     Thrown, if <paramref name="sender" /> or <paramref name="e" /> is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        ///     Thrown, if <paramref name="sender" /> is not of type BackgroundWorker.
        /// </exception>
        /// <exception cref="NotSupportedException">
        ///     Thrown, if <see cref="Path" /> is not set before this function is called
        ///     - or - if <see cref="Path" /> contains a colon anywhere other than as part of a
        ///     volume identifier ("C:\").
        /// </exception>
        /// <exception cref="System.Security.SecurityException">
        ///     Thrown, if the permissions for accessing the full path are missing.
        /// </exception>
        /// <exception cref="PathTooLongException">
        ///     Thrown, if <see cref="Path" /> is too long.
        /// </exception>
        /// <exception cref="UnauthorizedAccessException">
        ///     Thrown, if permissions to create the directory are missing.
        /// </exception>
        /// <exception cref="DirectoryNotFoundException">
        ///     Thrown, if the directory was not found.
        ///     For example because it is on an unmapped device.
        /// </exception>
        /// <exception cref="IOException">
        ///     Thrown, if a file with the name of the dictionary that should be created already exists.
        /// </exception>
        /// <exception cref="FileNotFoundException">
        ///     Thrown, if <see cref="Path" /> is a dictionary.
        /// </exception>
        public void LoadExcelLanguageFileAsync(object sender, DoWorkEventArgs e)
        {
            var bw = sender as BackgroundWorker;

            //null and argument checks.
            ExceptionLoggingUtils.VerifyMultiple(e, nameof(e))
                .AlsoVerify(sender, nameof(sender))
                .ThrowIfNull(_logger, nameof(LoadExcelLanguageFileAsync),
                    "Parameter for DoWork event handler cannot be null.");
            ExceptionLoggingUtils.ThrowIf(bw == null, _logger, new ArgumentException(
                    "Sender for DoWork event handler is not of type BackgroundWorker.", nameof(sender)),
                "LoadExcelLanguageFileAsync functions was called without BackgroundWorker.");
            ExceptionLoggingUtils.ThrowIf(Path == null, _logger,
                new NotSupportedException("Path property for DoWork event handler was not set."),
                "LoadExcelLanguageFileAsync functions was called without Path property being set beforehand.");

            _logger.Log(LogLevel.Trace, "LoadExcelLanguageFileAsync functions was called by BackgroundWorker.");

            VerifyPath(Path);
            LoadExcelLanguageFileAsyncInternal(bw, e, Path);
        }