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); } }
/// <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)); }
/// ------------------------------------------------------------------------------------ /// <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); }
/// <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 }
/// ------------------------------------------------------------------------------------ /// <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 _); }
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); }
/// ------------------------------------------------------------------------------------ /// <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; }
/// ------------------------------------------------------------------------------------ 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)); }
/// ------------------------------------------------------------------------------------ /// <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); }
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); }
/// ------------------------------------------------------------------------------------ /// <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); }
/// ------------------------------------------------------------------------------------ /// <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); }
/// ------------------------------------------------------------------------------------ /// <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)); }
/// ------------------------------------------------------------------------------------ /// <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); } }
/// ------------------------------------------------------------------------------------ /// <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); }
/// ------------------------------------------------------------------------------------ /// <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()); }
/// <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)); }
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); }
/// <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)); }