private void UpdateTransUnitComment(XLiffDocument xliffTarget, XLiffTransUnit tu,
                                            LocalizingInfo locInfo)
        {
            if (tu == null)
            {
                return;
            }

            if (locInfo.DiscoveredDynamically && !tu.Dynamic)
            {
                tu.Dynamic = true;
                _updated   = true;
            }

            if ((locInfo.UpdateFields & UpdateFields.Comment) != UpdateFields.Comment)
            {
                return;
            }
            if (tu.Notes.Count == 0 && string.IsNullOrEmpty(locInfo.Comment))
            {
                return;                 // empty comment and already no comment in XLiffTransUnit
            }
            if (tu.NotesContain(locInfo.Comment))
            {
                return;                 // exactly the same comment already exists in XLiffTransUnit
            }
            _updated = true;
            tu.Notes.Clear();
            tu.AddNote("ID: " + tu.Id);
            if (!string.IsNullOrEmpty(locInfo.Comment))
            {
                tu.AddNote(locInfo.Comment);
            }
        }
Example #2
0
        /// <summary>
        /// When all but the last part of the id changed, this can help reunite things
        /// </summary>
        internal XLiffTransUnit GetTransUnitForOrphan(XLiffTransUnit orphan)
        {
            var terminalIdToMatch  = XLiffLocalizedStringCache.GetTerminalIdPart(orphan.Id);
            var defaultTextToMatch = GetDefaultVariantValue(orphan);

            return(_transUnits.FirstOrDefault(tu => XLiffLocalizedStringCache.GetTerminalIdPart(tu.Id) == terminalIdToMatch && GetDefaultVariantValue(tu) == defaultTextToMatch));
        }
Example #3
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Adds the specified translation unit.
        /// </summary>
        /// <param name="tu">The translation unit.</param>
        /// <returns>true if the translation unit was successfully added. Otherwise, false.</returns>
        /// ------------------------------------------------------------------------------------
        internal bool AddTransUnit(XLiffTransUnit tu)
        {
            if (tu == null || tu.IsEmpty)
            {
                return(false);
            }

            if (tu.Id == null)
            {
                tu.Id = (++_transUnitId).ToString();
            }

            // If a translation unit with the specified id already exists, then quit here.
            if (GetTransUnitForId(tu.Id) != null)
            {
                return(false);
            }

            _transUnits.Add(tu);
            // If the target exists, store its value in the dictionary lookup.  Otherwise, store
            // the source value there.
            if (tu.Target != null && tu.Target.Value != null)
            {
                TranslationsById[tu.Id] = tu.Target.Value;
            }
            else
            {
                TranslationsById[tu.Id] = tu.Source.Value;
            }
            return(true);
        }
        void UpdateValueAndComment(XLiffDocument xliffTarget, XLiffTransUnit tuSource,
                                   string newText, LocalizingInfo locInfo, string tuId)
        {
            var tuTarget = UpdateValue(xliffTarget, tuSource, newText, locInfo, tuId);

            UpdateTransUnitComment(xliffTarget, tuSource, locInfo);
            UpdateTransUnitComment(xliffTarget, tuTarget, locInfo);
        }
Example #5
0
        /// <summary>
        /// When all but the last part of the id changed, this can help reunite things
        /// </summary>
        internal XLiffTransUnit GetTransUnitForOrphan(XLiffTransUnit orphan, XLiffBody source)
        {
            var terminalIdToMatch  = XLiffLocalizedStringCache.GetTerminalIdPart(orphan.Id);
            var defaultTextToMatch = GetDefaultVariantValue(orphan);

            return(TransUnitsUnordered.FirstOrDefault(tu =>
                                                      XLiffLocalizedStringCache.GetTerminalIdPart(tu.Id) ==
                                                      terminalIdToMatch && // require last part of ID to match
                                                      GetDefaultVariantValue(tu) == defaultTextToMatch && // require text to match
                                                      source?.GetTransUnitForId(tu.Id) == null)); // and translation does not already have an element for this
        }
Example #6
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Removes the specified translation unit.
        /// </summary>
        /// ------------------------------------------------------------------------------------
        public void RemoveTransUnit(XLiffTransUnit tu)
        {
            // if the ID is null, it can't be in our dictionary, unless someone
            // cheated and changed the ID by putting it there after inserting it.
            if (tu == null || tu.Id == null)
            {
                return;
            }

            _transUnitDict.TryRemove(tu.Id, out _);
            TranslationsById.TryRemove(tu.Id, out _);
        }
Example #7
0
        private static int CountSubstitutionMarkers(XLiffTransUnit tu)
        {
            var matchesSource = Regex.Matches(tu.Source.Value, "{[0-9]+}");
            var markers       = new List <string>();

            for (int i = 0; i < matchesSource.Count; ++i)
            {
                var key = matchesSource[i].Value;
                if (!markers.Contains(key))
                {
                    markers.Add(key);
                }
            }
            return(markers.Count);
        }
Example #8
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// If a translation unit does not already exist for the id in the specified
        /// translation unit, then the translation unit is added. Otherwise, if the variant
        /// for the specified language does not exist in the translation unit, it is added.
        /// </summary>
        /// ------------------------------------------------------------------------------------
        internal void AddTransUnitOrVariantFromExisting(XLiffTransUnit tu, string langId)
        {
            var variantToAdd = tu.GetVariantForLang(langId);

            if (variantToAdd == null || AddTransUnit(tu))
            {
                return;
            }

            var existingTu = GetTransUnitForId(tu.Id);

            //notice, we don't care if there is already a string in there for this language
            //(that was the cause of a previous bug), because the XLiff of language X should
            //surely take precedence, as the translation for that language.
            existingTu.AddOrReplaceVariant(variantToAdd);
            TranslationsById[tu.Id] = variantToAdd.Value;
        }
Example #9
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));
        }
Example #10
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Gets the priority for the specified id.
        /// </summary>
        /// ------------------------------------------------------------------------------------
        internal LocalizationPriority GetPriority(string id)
        {
            XLiffTransUnit tu = DefaultXliffDocument.GetTransUnitForId(id);

            if (tu != null)
            {
                if (string.IsNullOrEmpty(tu.Priority))
                {
                    return(LocalizationPriority.High);
                }

                try
                {
                    return((LocalizationPriority)Enum.Parse(typeof(LocalizationPriority), tu.Priority));
                }
                catch { }
            }
            return(LocalizationPriority.NotLocalizable);
        }
Example #11
0
        public bool AddTransUnit(XLiffTransUnit tu)
        {
            if (!AddTransUnitRaw(tu))
            {
                return(false);
            }

            // If the target exists, store its value in the dictionary lookup.  Otherwise, store
            // the source value there.
            if (tu.Target != null && tu.Target.Value != null)
            {
                TranslationsById[tu.Id] = tu.Target.Value;
            }
            else
            {
                TranslationsById[tu.Id] = tu.Source.Value;
            }
            return(true);
        }
Example #12
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Adds the specified translation unit.
        /// </summary>
        /// <param name="tu">The translation unit.</param>
        /// <returns>true if the translation unit was successfully added. Otherwise, false.</returns>
        /// ------------------------------------------------------------------------------------
        internal bool AddTransUnitRaw(XLiffTransUnit tu)
        {
            if (tu == null || tu.IsEmpty)
            {
                return(false);
            }

            bool   lockTaken = false;
            string key;

            try
            {
                _transUnitIdLock.Enter(ref lockTaken);
                // Efficiently lock this very small task so that if we need to modify
                // the TU, the key that it gets is guaranteed to be the one used to insert
                // it into the dictionary. This assumes nothing else modifies IDs once they
                // are in this system: once our locked code has given the TU an ID, any other
                // thread will see that it is non-empty.
                key = tu.Id;
                if (string.IsNullOrEmpty(key))
                {
                    tu.Id = (System.Threading.Interlocked.Increment(ref _transUnitId)).ToString();
                    key   = tu.Id;
                }
            }
            finally
            {
                if (lockTaken)
                {
                    _transUnitIdLock.Exit(false);
                }
            }

            // If a translation unit with the specified id already exists, then quit here.
            if (GetTransUnitForId(tu.Id) != null)
            {
                return(false);
            }
            _transUnitDict[key] = tu;
            return(true);
        }
Example #13
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Gets the category for the specified id.
        /// </summary>
        /// ------------------------------------------------------------------------------------
        internal LocalizationCategory GetCategory(string id)
        {
            XLiffTransUnit tu = DefaultXliffDocument.GetTransUnitForId(id);

            if (tu != null)
            {
                string category = tu.Category;
                if (string.IsNullOrEmpty(category))
                {
                    return(LocalizationCategory.DontCare);
                }

                try
                {
                    return((LocalizationCategory)Enum.Parse(typeof(LocalizationCategory), category));
                }
                catch { }
            }

            return(LocalizationCategory.Other);
        }
Example #14
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Compares two translation units for equality.
        /// </summary>
        /// ------------------------------------------------------------------------------------
        internal static int TuComparer(XLiffTransUnit tu1, XLiffTransUnit tu2)
        {
            if (tu1 == null && tu2 == null)
            {
                return(0);
            }

            if (tu1 == null)
            {
                return(-1);
            }

            if (tu2 == null)
            {
                return(1);
            }

            string x = tu1.Group;
            string y = tu2.Group;

            if (x == y)
            {
                return(string.CompareOrdinal(tu1.Id, tu2.Id));
            }

            if (x == null)
            {
                return(-1);
            }

            if (y == null)
            {
                return(1);
            }

            return(string.CompareOrdinal(x, y));
        }
Example #15
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Removes the specified translation unit.
        /// </summary>
        /// ------------------------------------------------------------------------------------
        internal void RemoveTransUnit(XLiffTransUnit tu)
        {
            if (tu == null)
            {
                return;
            }

            if (_transUnits.Contains(tu))
            {
                _transUnits.Remove(tu);
            }
            else if (tu.Id != null)
            {
                var tmptu = GetTransUnitForId(tu.Id);
                if (tmptu != null)
                {
                    _transUnits.Remove(tmptu);
                }
            }
            if (tu.Id != null)
            {
                TranslationsById.Remove(tu.Id);
            }
        }
Example #16
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Gets the group for the specified id.
        /// </summary>
        /// ------------------------------------------------------------------------------------
        internal string GetGroup(string id)
        {
            XLiffTransUnit tu = DefaultXliffDocument.GetTransUnitForId(id);

            return(tu == null ? null : tu.Group);
        }
Example #17
0
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Gets the comment for the specified id.
        /// </summary>
        /// <remarks>
        /// The xliff standard allows multiple notes in a trans-unit element.  We use one to
        /// represent the id string (prefacing it with "ID: ").  Any other note is liable to be
        /// considered the "comment" if it exists.
        /// </remarks>
        /// ------------------------------------------------------------------------------------
        public string GetComment(string id)
        {
            XLiffTransUnit tu = DefaultXliffDocument.GetTransUnitForId(id);

            return(tu == null ? null : tu.GetComment());
        }
Example #18
0
 /// <summary>
 /// When we change ids after people have already been localizing, we have a BIG PROBLEM.
 /// This helps with the common case were we just changed the hierarchical organization of the id,
 /// that is, the parts of the id before th final '.'.
 /// </summary>
 public XLiffTransUnit GetTransUnitForOrphan(XLiffTransUnit orphan)
 {
     return(File.Body.GetTransUnitForOrphan(orphan));
 }
Example #19
0
        string GetDefaultVariantValue(XLiffTransUnit tu)
        {
            var variant = tu.GetVariantForLang(LocalizationManager.kDefaultLang);

            return(variant?.Value);
        }
        /// ------------------------------------------------------------------------------------
        /// <summary>
        /// Updates the value for the specified translation unit with the specified new value.
        /// </summary>
        /// ------------------------------------------------------------------------------------
        private XLiffTransUnit UpdateValue(XLiffDocument xliffTarget, XLiffTransUnit tuSource,
                                           string newValue, LocalizingInfo locInfo,
                                           string tuId)
        {
            // One would think there would be a source XLiffTransUnit, but that isn't necessarily true
            // with users editing interactively and adding tooltips or shortcuts.
            Debug.Assert(tuSource == null || tuId == tuSource.Id);
            Debug.Assert(tuId.StartsWith(locInfo.Id));
            var tuTarget = xliffTarget.GetTransUnitForId(tuId);

            // If the XLiffTransUnit exists in the target language, check whether we're removing the translation
            // instead of adding or changing it.
            if (tuTarget != null)
            {
                var tuvTarg = tuTarget.GetVariantForLang(locInfo.LangId);
                if (tuvTarg != null)
                {
                    // don't need to update if the value hasn't changed
                    if (tuvTarg.Value == newValue)
                    {
                        return(tuTarget);
                    }

                    if (string.IsNullOrEmpty(newValue))
                    {
                        _updated = true;
                        tuTarget.RemoveVariant(tuvTarg);
                        if ((tuTarget.Source == null ||
                             string.IsNullOrEmpty(tuTarget.Source.Value)) &&
                            (tuTarget.Target == null ||
                             string.IsNullOrEmpty(tuTarget.Target.Value)))
                        {
                            xliffTarget.RemoveTransUnit(tuTarget);
                            tuTarget = null;
                        }
                    }
                }
            }

            // If we're removing an existing translation, we can quit now.
            if (string.IsNullOrEmpty(newValue))
            {
                xliffTarget.File.Body.TranslationsById.TryRemove(tuId, out _);
                return(tuTarget);
            }

            // If the XLiffTransUnit does not exist in the target language yet, create it and fill in the
            // source language value (if any).
            if (tuTarget == null)
            {
                tuTarget         = new XLiffTransUnit();
                tuTarget.Id      = tuId;
                tuTarget.Dynamic = locInfo.DiscoveredDynamically;
                xliffTarget.AddTransUnit(tuTarget);
                if (tuSource != null && locInfo.LangId != _defaultLang)
                {
                    var tuvSrc = tuSource.GetVariantForLang(_defaultLang);
                    if (tuvSrc != null && !string.IsNullOrEmpty(tuvSrc.Value))
                    {
                        tuTarget.AddOrReplaceVariant(_defaultLang, tuvSrc.Value);
                    }
                }

                tuTarget.AddNote("ID: " + tuId);
            }

            tuTarget.AddOrReplaceVariant(locInfo.LangId, newValue);
            xliffTarget.File.Body.TranslationsById[tuId] = newValue;
            _updated = true;
            return(tuTarget);
        }
Example #21
0
 /// <summary>
 /// When we change ids after people have already been localizing, we have a BIG PROBLEM.
 /// This helps with the common case were we just changed the hierarchical organization of the id,
 /// that is, the parts of the id before th final '.'.
 /// If provided with the source document of the possible orphan, will not answer one that
 /// has an ID matching something in that. (This argument should always be supplied, but
 /// for backwards compatibility we allow it to be omitted.)
 /// </summary>
 public XLiffTransUnit GetTransUnitForOrphan(XLiffTransUnit orphan, XLiffBody source = null)
 {
     return(File.Body.GetTransUnitForOrphan(orphan, source));
 }