Esempio n. 1
0
        /// ------------------------------------------------------------------------------------
        private void SaveFileForLangId(string langId, bool forceCreation)
        {
            var tmxDoc = CreateEmptyStringFile();

            tmxDoc.Header.SourceLang = langId;
            tmxDoc.Header.SetPropValue(LocalizationManager.kAppVersionPropTag, OwningManager.AppVersion);

            foreach (var tu in TmxDocument.Body.TransUnits)
            {
                var tuv = tu.GetVariantForLang(langId);
                if (tuv == null)
                {
                    continue;
                }

                var newTu = new TMXTransUnit {
                    Id = tu.Id
                };
                tmxDoc.AddTransUnit(newTu);
                newTu.AddOrReplaceVariant(tu.GetVariantForLang(LocalizationManager.kDefaultLang));
                newTu.AddOrReplaceVariant(tuv);
                newTu.Notes = tu.CopyNotes();
                newTu.Props = tu.CopyProps();
            }

            tmxDoc.Body.TransUnits.Sort(TuComparer);

            if (forceCreation || OwningManager.DoesCustomizedTranslationExistForLanguage(langId))
            {
                tmxDoc.Save(OwningManager.GetTmxPathForLanguage(langId, true));
            }
        }
Esempio n. 2
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Saves the cache to the files from which the cache was originally loaded, but only
        /// if the cache is dirty. If the cache is dirty and saved, then true is returned.
        /// Otherwise, false is returned.
        /// </summary>
        /// ------------------------------------------------------------------------------------
        internal void SaveIfDirty(ICollection <string> langIdsToForceCreate)
        {
            if (!IsDirty)
            {
                return;
            }

            StringBuilder errorMsg = null;

            foreach (var langId in XliffDocuments.Keys)
            {
                try
                {
                    if (XliffDocuments[langId].IsDirty)
                    {
                        SaveFileForLangId(langId, langIdsToForceCreate != null && langIdsToForceCreate.Contains(langId), XliffDocuments[langId]);
                    }
                }
                catch (Exception e)
                {
                    if (e is SecurityException || e is UnauthorizedAccessException || e is IOException)
                    {
                        if (errorMsg == null)
                        {
                            errorMsg = new StringBuilder();
                            errorMsg.AppendLine("Failed to save localization changes in the following files:");
                        }
                        errorMsg.AppendLine();
                        errorMsg.Append("File: ");
                        errorMsg.AppendLine(OwningManager.GetPathForLanguage(langId, true));
                        errorMsg.Append("Error Type: ");
                        errorMsg.AppendLine(e.GetType().ToString());
                        errorMsg.Append("Message: ");
                        errorMsg.AppendLine(e.Message);
                    }
                }
            }

            if (errorMsg != null)
            {
                throw new IOException(errorMsg.ToString());
            }

            IsDirty = false;
        }
Esempio n. 3
0
        /// ------------------------------------------------------------------------------------
        private void SaveFileForLangId(string langId, bool forceCreation, XLiffDocument xliffOriginal)
        {
            if (!forceCreation && !OwningManager.DoesCustomizedTranslationExistForLanguage(langId))
            {
                return;
            }

            var xliffOutput = CreateEmptyStringFile();

            if (langId != LocalizationManager.kDefaultLang)
            {
                xliffOutput.File.TargetLang = langId;
            }
            xliffOutput.File.ProductVersion           = OwningManager.AppVersion;
            xliffOutput.File.HardLineBreakReplacement = s_literalNewline;
            xliffOutput.File.AmpersandReplacement     = _ampersandReplacement;
            if (OwningManager != null && OwningManager.Name != null)
            {
                xliffOutput.File.Original = OwningManager.Name + ".dll";
            }

            foreach (var tu in DefaultXliffDocument.File.Body.TransUnits)
            {
                var tuTarget = xliffOriginal.File.Body.GetTransUnitForId(tu.Id);
                XLiffTransUnitVariant tuv = null;
                if (tuTarget != null)
                {
                    tuv = tuTarget.GetVariantForLang(langId);
                }
                // REVIEW: should we write units with no translation (target)?
                var newTu = new XLiffTransUnit {
                    Id = tu.Id, Dynamic = tu.Dynamic
                };
                newTu.AddOrReplaceVariant(tu.GetVariantForLang(LocalizationManager.kDefaultLang));
                if (tuv != null)
                {
                    newTu.AddOrReplaceVariant(tuv);
                }
                newTu.Notes = tu.CopyNotes();
                xliffOutput.AddTransUnit(newTu);
            }
            xliffOutput.File.Body.TransUnits.Sort(TuComparer);
            xliffOutput.Save(OwningManager.GetPathForLanguage(langId, true));
        }
Esempio n. 4
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Saves the cache to the file from which the cache was originally loaded, but only
        /// if the cache is dirty. If the cache is dirty and saved, then true is returned.
        /// Otherwise, false is returned.
        /// </summary>
        /// ------------------------------------------------------------------------------------
        internal void SaveIfDirty(ICollection <string> langIdsToForceCreate)
        {
            if (!IsDirty)
            {
                return;
            }

            StringBuilder errorMsg = null;

            // ToArray() prevents exception "Collection was modified" in rare cases (e.g., Bloom BL-2400).
            foreach (var langId in TmxDocument.GetAllVariantLanguagesFound().ToArray())
            {
                try
                {
                    SaveFileForLangId(langId, langIdsToForceCreate != null && langIdsToForceCreate.Contains(langId));
                }
                catch (Exception e)
                {
                    if (e is SecurityException || e is UnauthorizedAccessException || e is IOException)
                    {
                        if (errorMsg == null)
                        {
                            errorMsg = new StringBuilder();
                            errorMsg.AppendLine("Failed to save localization changes in the following files:");
                        }
                        errorMsg.AppendLine();
                        errorMsg.Append("File: ");
                        errorMsg.AppendLine(OwningManager.GetTmxPathForLanguage(langId, true));
                        errorMsg.Append("Error Type: ");
                        errorMsg.AppendLine(e.GetType().ToString());
                        errorMsg.Append("Message: ");
                        errorMsg.AppendLine(e.Message);
                    }
                }
            }

            if (errorMsg != null)
            {
                throw new IOException(errorMsg.ToString());
            }

            IsDirty = false;
        }
Esempio n. 5
0
        /// ------------------------------------------------------------------------------------
        private void MergeTmxFilesIntoCache(IEnumerable <string> tmxFiles)
        {
            var defaultTmxDoc = TMXDocument.Read(OwningManager.DefaultStringFilePath);

            foreach (var tu in defaultTmxDoc.Body.TransUnits)
            {
                TmxDocument.Body.AddTransUnit(tu);
                // If this TMXTransUnit is marked NoLongerUsed in the English tmx, load its ID into the hashset
                // so we don't display this string in case the currentUI tmx doesn't have it marked as
                // NoLongerUsed.
                if (tu.GetPropValue(kNoLongerUsedPropTag) != null)
                {
                    _englishTuIdsNoLongerUsed.Add(tu.Id);
                }
            }
            // It's possible (I think when there is no customizable TMX, as on first install, but the version in the installed TMX
            // is out of date with the app) that we don't have all the info from the installed TMX in the customizable one.
            // We want to make sure that (a) any new dynamic strings in the installed one are considered valid by default
            // (b) any newly obsolete IDs are noted.
            if (File.Exists(OwningManager.DefaultInstalledStringFilePath))
            {
                var defaultInstalledTmxDoc = TMXDocument.Read(OwningManager.DefaultInstalledStringFilePath);
                foreach (var tu in defaultInstalledTmxDoc.Body.TransUnits)
                {
                    TmxDocument.Body.AddTransUnitOrVariantFromExisting(tu, "en");
                    // also needed in this, to prevent things we find here from being considered orphans.
                    defaultTmxDoc.Body.AddTransUnitOrVariantFromExisting(tu, "en");
                    // If this TMXTransUnit is marked NoLongerUsed in the English tmx, load its ID into the hashset
                    // so we don't display this string in case the currentUI tmx doesn't have it marked as
                    // NoLongerUsed.
                    if (tu.GetPropValue(kNoLongerUsedPropTag) != null)
                    {
                        _englishTuIdsNoLongerUsed.Add(tu.Id);
                    }
                }
            }
            // Map the default language onto itself.
            LocalizationManagerInternal <TMXDocument> .MapToExistingLanguage[LocalizationManager.kDefaultLang] = LocalizationManager.kDefaultLang;

            Exception error = null;
            var       stillNeedToLoadNoLongerUsed = _englishTuIdsNoLongerUsed.Count == 0;

            foreach (var file in tmxFiles.Where(f => Path.GetFileName(f) != OwningManager.DefaultStringFilePath))
            {
                try
                {
                    var tmxDoc = TMXDocument.Read(file);
                    var langId = tmxDoc.Header.SourceLang;
                    // Provide a mapping from a specific variant of a language to the base language.
                    // For example, "es-ES" can provide translations for "es" if we don't have "es" specifically.
                    var pieces = langId.Split('-');
                    if (pieces.Length > 1)
                    {
                        if (!LocalizationManagerInternal <TMXDocument> .MapToExistingLanguage.ContainsKey
                                (pieces[0]))
                        {
                            LocalizationManagerInternal <TMXDocument> .MapToExistingLanguage.TryAdd(pieces[0], langId);
                        }
                    }
                    // Identity mapping always wins.  Storing it simplifies code elsewhere.
                    LocalizationManagerInternal <TMXDocument> .MapToExistingLanguage[langId] = langId;

                    foreach (var tu in tmxDoc.Body.TransUnits)
                    {
                        // This block attempts to find 'orphans', that is, localizations that have been done using an obsolete ID.
                        // We assume the default language TMX has only current IDs, and therefore don't look for orphans in that case.
                        // This guards against cases such as recently occurred in Bloom, where a dynamic ID EditTab.AddPageDialog.Title
                        // was regarded as an obsolete id for PublishTab.Upload.Title
                        if (langId != LocalizationManager.kDefaultLang && defaultTmxDoc.GetTransUnitForId(tu.Id) == null &&
                            !tu.Id.EndsWith(kToolTipSuffix) && !tu.Id.EndsWith(kShortcutSuffix))
                        {
                            //if we couldn't find it, maybe the id just changed and then if so re-id it.
                            var movedUnit = defaultTmxDoc.GetTransUnitForOrphan(tu);
                            if (movedUnit == null)
                            {
                                if (tu.GetPropValue(kDiscoveredDynamically) == "true")
                                {
                                    //ok, no big deal, that what we expect with dynamic strings, by definition... that we won't find them during a static code scan
                                }
                                else
                                {
                                    tu.AddProp(kNoLongerUsedPropTag, "true");
                                }
                            }
                            else
                            {
                                tu.Id = movedUnit.Id;
                            }
                        }

                        TmxDocument.Body.AddTransUnitOrVariantFromExisting(tu, langId);
                        if (stillNeedToLoadNoLongerUsed && langId == LocalizationManager.kDefaultLang &&
                            tu.GetPropValue(kNoLongerUsedPropTag) != null)
                        {
                            _englishTuIdsNoLongerUsed.Add(tu.Id);
                        }
                    }
                }
                catch (Exception e)
                {
#if DEBUG
                    throw e;
#else
                    //REVIEW: Better explain the conditions where we get an error on a file but don't care about it?

                    // If error happened reading some localization file other than the one we care
                    // about right now, just ignore it.
                    if (file == OwningManager.GetTmxPathForLanguage(LocalizationManager.UILanguageId, false))
                    {
                        error = e;
                    }
#endif
                }
            }
            if (error != null)
            {
                throw error;
            }
        }
Esempio n. 6
0
        /// ------------------------------------------------------------------------------------
        private void MergeXliffFilesIntoCache(IEnumerable <string> xliffFiles)
        {
            DefaultXliffDocument = XLiffDocument.Read(OwningManager.DefaultStringFilePath);             // read the generated file
            // It's possible (I think when there is no customizable Xliff, as on first install, but the version in the installed Xliff
            // is out of date with the app) that we don't have all the info from the installed Xliff in the customizable one.
            // We want to make sure that (a) any new dynamic strings in the installed one are considered valid by default
            // (b) any newly obsolete IDs are noted.
            if (File.Exists(OwningManager.DefaultInstalledStringFilePath))
            {
                if (!XLiffLocalizationManager.ScanningForCurrentStrings)
                {
                    var defaultInstalledXliffDoc = XLiffDocument.Read(OwningManager.DefaultInstalledStringFilePath);
                    foreach (var tu in defaultInstalledXliffDoc.File.Body.TransUnits)
                    {
                        DefaultXliffDocument.File.Body.AddTransUnitOrVariantFromExisting(tu, LocalizationManager.kDefaultLang);
                    }
                }
            }
            XliffDocuments.Add(LocalizationManager.kDefaultLang, DefaultXliffDocument);
            // Map the default language onto itself.
            LocalizationManagerInternal <XLiffDocument> .MapToExistingLanguage[LocalizationManager.kDefaultLang] = LocalizationManager.kDefaultLang;

            Exception error = null;

            foreach (var file in xliffFiles)
            {
                try
                {
                    var xliffDoc = XLiffDocument.Read(file);
                    var langId   = xliffDoc.File.TargetLang;
                    Debug.Assert(!string.IsNullOrEmpty(langId));
                    Debug.Assert(langId != LocalizationManager.kDefaultLang);
                    // Provide a mapping from a specific variant of a language to the base language.
                    // For example, "es-ES" can provide translations for "es" if we don't have "es" specifically.
                    var pieces = langId.Split('-');
                    if (pieces.Length > 1)
                    {
                        if (!LocalizationManagerInternal <XLiffDocument> .MapToExistingLanguage.ContainsKey(pieces[0]))
                        {
                            LocalizationManagerInternal <XLiffDocument> .MapToExistingLanguage.Add(pieces[0], langId);
                        }
                    }
                    // Identity mapping always wins.  Storing it simplifies code elsewhere.
                    LocalizationManagerInternal <XLiffDocument> .MapToExistingLanguage[langId] = langId;
                    XliffDocuments.Add(langId, xliffDoc);
                    var defunctUnits = new List <XLiffTransUnit>();
                    foreach (var tu in xliffDoc.File.Body.TransUnits)
                    {
                        // This block attempts to find 'orphans', that is, localizations that have been done using an obsolete ID.
                        // We assume the default language Xliff has only current IDs, and therefore don't look for orphans in that case.
                        // This guards against cases such as recently occurred in Bloom, where a dynamic ID EditTab.AddPageDialog.Title
                        // was regarded as an obsolete id for PublishTab.Upload.Title
                        if (langId != LocalizationManager.kDefaultLang && DefaultXliffDocument.GetTransUnitForId(tu.Id) == null &&
                            !tu.Id.EndsWith(kToolTipSuffix) && !tu.Id.EndsWith(kShortcutSuffix))
                        {
                            //if we couldn't find it, maybe the id just changed and then if so re-id it.
                            var movedUnit = DefaultXliffDocument.GetTransUnitForOrphan(tu);
                            if (movedUnit == null)
                            {
                                // with dynamic strings, by definition we won't find them during a static code scan
                                if (!tu.Dynamic)
                                {
                                    defunctUnits.Add(tu);
                                    xliffDoc.IsDirty = true;
                                    IsDirty          = true;
                                }
                            }
                            else
                            {
                                if (xliffDoc.File.Body.TranslationsById.ContainsKey(tu.Id))
                                {
                                    // adjust the document's internal cache
                                    xliffDoc.File.Body.TranslationsById[movedUnit.Id] = xliffDoc.File.Body.TranslationsById[tu.Id];
                                    xliffDoc.File.Body.TranslationsById.Remove(tu.Id);
                                }
                                tu.Id            = movedUnit.Id;
                                xliffDoc.IsDirty = true;
                                IsDirty          = true;
                            }
                        }
                    }
                    // Now we can delete any invalid XLiffTransUnit objects from this document.
                    foreach (var tuBad in defunctUnits)
                    {
                        xliffDoc.File.Body.RemoveTransUnit(tuBad);
                    }
                }
                catch (Exception e)
                {
                    var msg = $"Caught exception in MergeXliffFilesIntoCache [{file}] - {e.Message}";
#if DEBUG
                    throw new Exception(msg, e);
#else
                    // If an error happened reading some localization file other than one we care
                    // about right now, just ignore it.
                    if (file == OwningManager.GetPathForLanguage(LocalizationManager.UILanguageId, false))
                    {
                        error = new Exception(msg, e);
                    }
#endif
                }
            }
            if (error != null)
            {
                throw error;
            }
        }