/// ------------------------------------------------------------------------------------
        /// <summary>
        /// Processes a new translation on a phrase.
        /// </summary>
        /// ------------------------------------------------------------------------------------
        internal void ProcessTranslation(TranslatablePhrase tp)
        {
            string initialPunct, finalPunct;

            StringBuilder bldr = new StringBuilder();

            if (tp.Translation.StartsWith("\u00BF"))
            {
                bldr.Append(tp.Translation[0]);
            }
            if (bldr.Length > 0 && bldr.Length < tp.Translation.Length)
            {
                m_initialPunct[tp.TypeOfPhrase] = initialPunct = bldr.ToString();
            }
            else
            {
                initialPunct = InitialPunctuationForType(tp.TypeOfPhrase);
            }

            bldr.Length = 0;
            foreach (char t in tp.Translation.Reverse().TakeWhile(Char.IsPunctuation))
            {
                bldr.Insert(0, t);
            }
            if (bldr.Length > 0 && bldr.Length < tp.Translation.Length)
            {
                m_finalPunct[tp.TypeOfPhrase] = finalPunct = bldr.ToString();
            }
            else
            {
                finalPunct = InitialPunctuationForType(tp.TypeOfPhrase);
            }

            List <Part> tpParts = tp.TranslatableParts.ToList();

            if (tpParts.Count == 0)
            {
                return;
            }

            string translation = tp.GetTranslationTemplate();

            foreach (TranslatablePhrase similarPhrase in tpParts[0].OwningPhrases.Where(phrase => !phrase.HasUserTranslation && phrase.PartPatternMatches(tp)))
            {
                if (similarPhrase.PhraseInUse == tp.PhraseInUse)
                {
                    similarPhrase.Translation = tp.Translation;
                }
                else if (tp.AllTermsMatch)
                {
                    similarPhrase.SetProvisionalTranslation(translation);
                }
            }

            if (tp.AllTermsMatch)
            {
                if (tpParts.Count == 1)
                {
                    if (translation.StartsWith(initialPunct))
                    {
                        translation = translation.Remove(0, initialPunct.Length);
                    }
                    if (translation.EndsWith(finalPunct))
                    {
                        translation = translation.Substring(0, translation.Length - finalPunct.Length);
                    }

                    tpParts[0].Translation = Regex.Replace(translation, @"\{.+\}", string.Empty).Trim();
                    if (TranslationsChanged != null)
                    {
                        TranslationsChanged();
                    }
                    return;
                }
            }

            if (m_justGettingStarted)
            {
                return;
            }

            if (translation.StartsWith(initialPunct))
            {
                translation = translation.Remove(0, initialPunct.Length);
            }
            if (translation.EndsWith(finalPunct))
            {
                translation = translation.Substring(0, translation.Length - finalPunct.Length);
            }

            List <Part>    unTranslatedParts    = new List <Part>(tpParts);
            HashSet <Part> partsNeedingUpdating = new HashSet <Part>();

            foreach (Part part in tpParts)
            {
                partsNeedingUpdating.UnionWith(RecalculatePartTranslation(part).Where(p => !tpParts.Contains(p)));
                if (part.Translation.Length > 0)
                {
                    int ichMatch = translation.IndexOf(part.Translation, StringComparison.Ordinal);
                    if (ichMatch >= 0)
                    {
                        translation = translation.Remove(ichMatch, part.Translation.Length);
                    }
                    unTranslatedParts.Remove(part);
                }
            }
            if (unTranslatedParts.Count == 1)
            {
                unTranslatedParts[0].Translation = Regex.Replace(translation, @"\{.+\}", string.Empty).Trim();
            }

            foreach (Part partNeedingUpdating in partsNeedingUpdating)
            {
                RecalculatePartTranslation(partNeedingUpdating);
            }

            if (TranslationsChanged != null)
            {
                TranslationsChanged();
            }
        }