示例#1
0
        public static void RenderItem(StringBuilder sb, string currTrg, EntryStatus currStatus,
                                      ChangeItem change, string lang)
        {
            CedictParser parser = new CedictParser();

            histRenderChange(sb, change, false, lang, parser, "reloaded");
        }
示例#2
0
        public async Task ReadAsync_ShouldSkipComments()
        {
            string s = "# This is a comment\n" +
                       "再見 再见 [zai4 jian4] /goodbye/see you again later/";

            byte[] b = Encoding.UTF8.GetBytes(s);

            var stream = new MemoryStream(b);

            using (var reader = new StreamReader(stream))
            {
                var parser = new CedictParser(reader);

                CedictEntry entry = await parser.ReadAsync();

                Assert.IsNotNull(entry);
                Assert.AreEqual("再見", entry.Traditional);
                Assert.AreEqual("再见", entry.Simplified);
                Assert.AreEqual("zai4 jian4", entry.Pinyin);
                Assert.IsNotNull(entry.Definitions);
                Assert.AreEqual(2, entry.Definitions.Length);
                Assert.AreEqual("goodbye", entry.Definitions[0]);
                Assert.AreEqual("see you again later", entry.Definitions[1]);
            }
        }
示例#3
0
        public IActionResult SaveFullEntry([FromForm] string entryId, [FromForm] string hw, [FromForm] string trg,
                                           [FromForm] string note, [FromForm] string lang)
        {
            if (entryId == null || hw == null || trg == null || note == null || lang == null)
            {
                return(StatusCode(400, "Missing parameter(s)."));
            }

            // Must be authenticated user
            int    userId;
            string userName;

            auth.CheckSession(HttpContext.Request.Headers, out userId, out userName);
            if (userId < 0)
            {
                return(StatusCode(401, "Request must contain authentication token."));
            }

            EditEntryResult res = new EditEntryResult();

            int idVal = EntryId.StringToId(entryId);

            trg = trg.Replace("\r\n", "\n");
            trg = trg.Replace('/', '\\');
            trg = trg.Replace('\n', '/');
            trg = "/" + trg + "/";
            CedictParser parser = new CedictParser();
            CedictEntry  entry  = null;

            try { entry = parser.ParseEntry(hw + " " + trg, 0, null); }
            catch { }
            if (entry == null)
            {
                res.Error = TextProvider.Instance.GetString(lang, "editEntry.badDataOnSave");
                return(new ObjectResult(res));
            }

            bool persisted;

            using (SqlDict.SimpleBuilder builder = dict.GetSimpleBuilder(userId))
            {
                persisted = builder.ChangeHeadAndTarget(userId, idVal, hw, trg, note);
            }
            // Not persisted: violates uniqueness constraint
            if (!persisted)
            {
                res.Error = TextProvider.Instance.GetString(lang, "editEntry.duplicateOnSave");
                return(new ObjectResult(res));
            }

            // Refresh cached contrib score
            auth.RefreshUserInfo(userId);
            // Tell our caller we dun it
            res.Success = true;
            return(new ObjectResult(res));
        }
示例#4
0
        /// <summary>
        /// Import new entries from file as a single bulk change.
        /// </summary>
        public void BulkAdd(string dictPath, string workingFolder)
        {
            CedictParser parser = new CedictParser();

            Startup.InitDB(config, null, false);
            SqlDict dict    = new SqlDict(null, mut);
            int     lineNum = 0;

            DateTime dt    = DateTime.Now;
            string   fnLog = "importlog-" + dt.Year + "-" + dt.Month.ToString("00") + "-" + dt.Day.ToString("00") + "!" + dt.Hour.ToString("00") + "-" + dt.Minute.ToString("00") + "-" + dt.Second.ToString("00") + ".txt";

            fnLog = Path.Combine(workingFolder, fnLog);
            using (FileStream fs = new FileStream(dictPath, FileMode.Open, FileAccess.Read))
                using (StreamReader sr = new StreamReader(fs))
                    using (FileStream fsLog = new FileStream(fnLog, FileMode.Create, FileAccess.ReadWrite))
                        using (StreamWriter swLog = new StreamWriter(fsLog))
                        {
                            // First two lines are commented and have metainfo
                            // First line: user name
                            // Second line: bulk change's comment
                            string user = sr.ReadLine().Substring(1).Trim();
                            string note = sr.ReadLine().Substring(1).Trim();
                            lineNum = 2;
                            using (SqlDict.ImportBuilder builder = dict.GetBulkBuilder(user, note))
                            {
                                string line;
                                while ((line = sr.ReadLine()) != null)
                                {
                                    ++lineNum;
                                    if (line == "" || line.StartsWith("#"))
                                    {
                                        continue;
                                    }
                                    CedictEntry entry = parser.ParseEntry(line, lineNum, swLog);
                                    if (entry == null)
                                    {
                                        swLog.WriteLine(line);
                                        continue;
                                    }
                                    entry.Status = EntryStatus.Approved;
                                    bool ok = builder.AddNewEntry(entry);
                                    if (!ok)
                                    {
                                        swLog.WriteLine("Line " + lineNum + ": Entry rejected by importer.");
                                        swLog.WriteLine(line);
                                        continue;
                                    }
                                }
                                builder.CommitRest();
                            }
                        }
        }
示例#5
0
        public void Work()
        {
            Random        rnd    = new Random(0);
            CedictParser  parser = new CedictParser();
            HashSet <int> idSet  = new HashSet <int>();
            StringBuilder sb     = new StringBuilder();

            using (FileStream fsIn = new FileStream("handedict.u8", FileMode.Open, FileAccess.Read))
                using (StreamReader sr = new StreamReader(fsIn))
                {
                    string line;
                    while ((line = sr.ReadLine()) != null)
                    {
                        if (line.StartsWith("#"))
                        {
                            continue;
                        }
                        CedictEntry entry = parser.ParseEntry(line, 0, null);
                        if (entry == null)
                        {
                            continue;
                        }
                        if (entry.ChSimpl.Length > 16)
                        {
                            continue;
                        }

                        int id = rnd.Next();
                        while (idSet.Contains(id))
                        {
                            id = rnd.Next();
                        }
                        idSet.Add(id);
                        string strId   = EntryId.IdToString(id);
                        bool   isVerif = isVerified(entry);

                        sb.Clear();
                        // Line with ID
                        sb.AppendLine("# ID-" + strId);
                        // First version metainfo
                        string statStr = isVerif ? "Stat-Verif" : "Stat-New";
                        sb.AppendLine("# Ver 2011-05-28T01:27:49Z HanDeDict " + statStr + " 001>Originalversion HanDeDict-Datei");
                        // The entry itself
                        sb.AppendLine(CedictWriter.Write(entry));

                        items.Add(new ResItem {
                            ID = id, Lines = sb.ToString()
                        });
                    }
                }
        }
示例#6
0
        public static void RenderEntryChanges(StringBuilder sb,
                                              string currHead, string currTrg, EntryStatus currStatus,
                                              List <ChangeItem> changes, string lang)
        {
            sb.AppendLine("<div class='pastChanges'><div class='pastInner'>");
            CedictParser parser    = new CedictParser();
            string       headNow   = currHead;
            string       trgNow    = currTrg;
            EntryStatus  statusNow = currStatus;

            foreach (var ci in changes)
            {
                renderPastChange(sb, parser, ref headNow, ref trgNow, ref statusNow, ci, lang);
            }
            sb.AppendLine("</div></div>"); // <div class='pastChanges'><div class='pastInner'>
        }
示例#7
0
        public void Read_ShouldReturnNull_WhenNothingToRead()
        {
            string s = "";

            byte[] b = Encoding.UTF8.GetBytes(s);

            var stream = new MemoryStream(b);

            using (var reader = new StreamReader(stream))
            {
                var parser = new CedictParser(reader);

                CedictEntry entry = parser.Read();

                Assert.IsNull(entry);
            }
        }
示例#8
0
        public async Task ReadToEndAsync_ShouldReturnEmpty_WhenNothingToRead()
        {
            string s = "";

            byte[] b = Encoding.UTF8.GetBytes(s);

            var stream = new MemoryStream(b);

            using (var reader = new StreamReader(stream))
            {
                var parser = new CedictParser(reader);

                IList <CedictEntry> entries = await parser.ReadToEndAsync();

                Assert.IsNotNull(entries);
                Assert.AreEqual(0, entries.Count);
            }
        }
示例#9
0
        public async Task ReadToEndAsync_ShouldReturnAllEntries()
        {
            string s = "你好 你好 [ni3 hao3] /hello/hi/\n" +
                       "再見 再见 [zai4 jian4] /goodbye/see you again later/";

            byte[] b = Encoding.UTF8.GetBytes(s);

            var stream = new MemoryStream(b);

            using (var reader = new StreamReader(stream))
            {
                var parser = new CedictParser(reader);

                IList <CedictEntry> entries = await parser.ReadToEndAsync();

                Assert.IsNotNull(entries);
                Assert.AreEqual(2, entries.Count);

                CedictEntry entry = entries[0];

                Assert.IsNotNull(entry);
                Assert.AreEqual("你好", entry.Traditional);
                Assert.AreEqual("你好", entry.Simplified);
                Assert.AreEqual("ni3 hao3", entry.Pinyin);
                Assert.IsNotNull(entry.Definitions);
                Assert.AreEqual(2, entry.Definitions.Length);
                Assert.AreEqual("hello", entry.Definitions[0]);
                Assert.AreEqual("hi", entry.Definitions[1]);

                entry = entries[1];

                Assert.IsNotNull(entry);
                Assert.AreEqual("再見", entry.Traditional);
                Assert.AreEqual("再见", entry.Simplified);
                Assert.AreEqual("zai4 jian4", entry.Pinyin);
                Assert.IsNotNull(entry.Definitions);
                Assert.AreEqual(2, entry.Definitions.Length);
                Assert.AreEqual("goodbye", entry.Definitions[0]);
                Assert.AreEqual("see you again later", entry.Definitions[1]);
            }
        }
示例#10
0
        public void Read_ShouldReturnEntryWithDefaultPropertyValues_WhenEntryIsMalformed()
        {
            string s = "你好你好 [ni3 hao3] /hello/hi/";

            byte[] b = Encoding.UTF8.GetBytes(s);

            var stream = new MemoryStream(b);

            using (var reader = new StreamReader(stream))
            {
                var parser = new CedictParser(reader);

                CedictEntry entry = parser.Read();

                Assert.IsNotNull(entry);
                Assert.IsNull(entry.Traditional);
                Assert.IsNull(entry.Simplified);
                Assert.IsNull(entry.Pinyin);
                Assert.IsNull(entry.Definitions);
            }
        }
示例#11
0
        public async Task ReadAsync_ShouldReturnNull_WhenNothingLeftToRead()
        {
            string s = "你好 你好 [ni3 hao3] /hello/hi/";

            byte[] b = Encoding.UTF8.GetBytes(s);

            var stream = new MemoryStream(b);

            using (var reader = new StreamReader(stream))
            {
                var parser = new CedictParser(reader);

                CedictEntry entry = await parser.ReadAsync();

                Assert.IsNotNull(entry);

                entry = parser.Read();

                Assert.IsNull(entry);
            }
        }
示例#12
0
        public static CedictEntry BuildEntry(string simp, string trad, string pinyin, string trg)
        {
            // Prepare pinyin as list of proper syllables
            List <PinyinSyllable> pyList = new List <PinyinSyllable>();

            string[] pyRawArr = pinyin.Split(' ');
            foreach (string pyRaw in pyRawArr)
            {
                PinyinSyllable ps = PinyinSyllable.FromDisplayString(pyRaw);
                if (ps == null)
                {
                    ps = new PinyinSyllable(pyRaw, -1);
                }
                pyList.Add(ps);
            }

            // Build TRG entry in "canonical" form; parse; render
            trg = trg.Replace("\r\n", "\n");
            string[] senses = trg.Split('\n');
            string   can    = trad + " " + simp + " [";

            for (int i = 0; i != pyList.Count; ++i)
            {
                if (i != 0)
                {
                    can += " ";
                }
                can += pyList[i].GetDisplayString(false);
            }
            can += "] /";
            foreach (string str in senses)
            {
                can += str.Replace('/', '\\') + "/";
            }
            CedictParser parser = new CedictParser();

            return(parser.ParseEntry(can, 0, null));
        }
示例#13
0
        public IActionResult GetEntryPreview([FromQuery] string origHw,
                                             [FromQuery] string trad, [FromQuery] string simp, [FromQuery] string pinyin,
                                             [FromQuery] string trgTxt, [FromQuery] string lang)
        {
            if (origHw == null || trgTxt == null || lang == null)
            {
                return(StatusCode(400, "Missing parameter(s)."));
            }
            if (trad == null)
            {
                trad = "";
            }
            if (simp == null)
            {
                simp = "";
            }
            if (pinyin == null)
            {
                pinyin = "";
            }
            EditEntryPreviewResult res = new EditEntryPreviewResult();

            // Ugly try-catch, but some incorrect input just generates an exception.
            // We still want to return a meaningful "no preview" response.
            try
            {
                // DBG
                if (trgTxt.Contains("micu-barf"))
                {
                    throw new Exception("barf");
                }

                // Validate current headword
                bool hwParses = validateHeadword(lang, simp, trad, pinyin,
                                                 res.ErrorsSimp, res.ErrorsTrad, res.ErrorsPinyin);

                trgTxt = trgTxt.Replace("\r\n", "\n");
                trgTxt = trgTxt.Replace('/', '\\');
                trgTxt = trgTxt.Replace('\n', '/');
                trgTxt = "/" + trgTxt + "/";

                // Headword: use original if current headword has errors
                string hw = trad + " " + simp + " [" + pinyin + "]";
                if (!hwParses)
                {
                    hw = origHw;
                }

                CedictParser parser = new CedictParser();
                CedictEntry  entry  = parser.ParseEntry(hw + " " + trgTxt, 0, null);
                if (entry != null)
                {
                    EntryRenderer er = new EntryRenderer(lang, entry, true, "mainEntry");
                    er.OneLineHanziLimit = 12;
                    StringBuilder sb = new StringBuilder();
                    er.Render(sb, null);
                    res.PreviewHtml = sb.ToString();
                }
            }
            catch { }
            return(new ObjectResult(res));
        }
示例#14
0
        public IActionResult GetEditEntryData([FromQuery] string entryId, [FromQuery] string lang)
        {
            if (entryId == null || lang == null)
            {
                return(StatusCode(400, "Missing parameter(s)."));
            }

            // The data we'll return.
            EditEntryData res = new EditEntryData();

            // Is this an authenticated user?
            int    userId;
            string userName;

            auth.CheckSession(HttpContext.Request.Headers, out userId, out userName);
            // Can she approve entries?
            if (userId != -1)
            {
                res.CanApprove = auth.CanApprove(userId);
            }

            // Retrieve entry
            int         idVal = EntryId.StringToId(entryId);
            string      hw, trg;
            EntryStatus status;

            SqlDict.GetEntryById(idVal, out hw, out trg, out status);
            CedictParser parser = new CedictParser();
            CedictEntry  entry  = parser.ParseEntry(hw + " " + trg, 0, null);

            res.Status     = status.ToString().ToLowerInvariant();
            res.HeadSimp   = entry.ChSimpl;
            res.HeadTrad   = entry.ChTrad;
            res.HeadPinyin = "";
            for (int i = 0; i != entry.PinyinCount; ++i)
            {
                if (res.HeadPinyin.Length > 0)
                {
                    res.HeadPinyin += " ";
                }
                var pys = entry.GetPinyinAt(i);
                res.HeadPinyin += pys.GetDisplayString(false);
            }
            res.TrgTxt = trg.Trim('/').Replace('/', '\n').Replace('\\', '/');

            // Entry HTML
            entry.Status = status;
            EntryRenderer er = new EntryRenderer(lang, entry, true, "mainEntry");

            er.OneLineHanziLimit = 12;
            StringBuilder sb = new StringBuilder();

            er.Render(sb, null);
            res.EntryHtml = sb.ToString();

            // Entry history
            List <ChangeItem> changes = SqlDict.GetEntryChanges(idVal);

            sb.Clear();
            HistoryRenderer.RenderEntryChanges(sb, hw, trg, status, changes, lang);
            res.HistoryHtml = sb.ToString();

            return(new ObjectResult(res));
        }
示例#15
0
        public void Work()
        {
            Random         rnd       = new Random(0);
            CedictParser   parser    = new CedictParser();
            HashSet <int>  idSet     = new HashSet <int>();
            StringBuilder  sb        = new StringBuilder();
            HashSet <char> simpChars = new HashSet <char>();

            using (FileStream fsIn = new FileStream("chdict.u8", FileMode.Open, FileAccess.Read))
                using (StreamReader sr = new StreamReader(fsIn))
                {
                    string line;
                    while ((line = sr.ReadLine()) != null)
                    {
                        if (line.StartsWith("#"))
                        {
                            continue;
                        }

                        int ix1 = line.IndexOf(" [");
                        int ix2 = line.IndexOf("] /");
                        line = line.Substring(0, ix1) + " [" + line.Substring(ix1 + 2, ix2 - ix1).ToLower() + line.Substring(ix2 + 2);

                        CedictEntry entry = parser.ParseEntry(line, 0, null);
                        if (entry == null)
                        {
                            continue;
                        }
                        if (entry.ChSimpl.Length > 16)
                        {
                            continue;
                        }

                        int id = rnd.Next();
                        while (idSet.Contains(id))
                        {
                            id = rnd.Next();
                        }
                        idSet.Add(id);
                        string strId = EntryId.IdToString(id);

                        sb.Clear();
                        // Line with ID
                        sb.AppendLine("# ID-" + strId);
                        // First version metainfo
                        string statStr = "Stat-Verif";
                        sb.AppendLine("# Ver 2017-05-02T22:41:05Z gabor " + statStr + " 001>CHDICT törzsanyag");
                        // The entry itself
                        sb.AppendLine(CedictWriter.Write(entry));

                        foreach (char c in entry.ChSimpl)
                        {
                            simpChars.Add(c);
                        }

                        items.Add(new ResItem {
                            ID = id, Lines = sb.ToString()
                        });
                    }
                }
        }
示例#16
0
        private static void renderPastChange(StringBuilder sb, CedictParser parser,
                                             ref string headNow, ref string trgNow, ref EntryStatus statusNow,
                                             ChangeItem ci, string lang)
        {
            sb.AppendLine("<div class='pastItem'>");

            sb.Append("<div class='changeSummary'>");
            sb.Append("<span class='changeType'>");
            sb.Append(HtmlEncoder.Default.Encode(getChangeTypeStr(ci.ChangeType, ci.CountB, statusNow, lang)));
            sb.Append(" &bull; </span>");
            sb.Append("<span class='changeUser'>");
            sb.Append(HtmlEncoder.Default.Encode(ci.User));
            sb.Append("</span>");
            sb.Append("<span class='changeTime'>");
            sb.Append(HtmlEncoder.Default.Encode(getTimeStr(ci.When, lang)));
            sb.Append("</span>");
            sb.AppendLine("</div>"); // <div class='changeSummary'>

            sb.AppendLine("<div class='changeNote'>");
            sb.Append("<span class='changeNoteText'>");

            if (ci.BulkRef != -1)
            {
                sb.Append("<span class='bulkLink'>[");
                sb.Append("<a href='/" + lang + "/read/details/change-" + ci.BulkRef.ToString("000") + "' target='_blank'>");
                sb.Append(TextProvider.Instance.GetString(lang, "history.bulkLink") + "</a>");
                sb.Append("]</span> ");
            }

            string note = HtmlEncoder.Default.Encode(ci.Note);

            note = note.Replace("&#xA;", "<br/>");
            sb.Append(note);
            sb.Append("</span>");
            sb.AppendLine("</div>"); // <div class='changeNote'>

            if (ci.HeadBefore != null)
            {
                CedictEntry eCurr         = parser.ParseEntry(headNow + " /x/", -1, null);
                CedictEntry eOld          = parser.ParseEntry(ci.HeadBefore + " /x/", -1, null);
                bool        simpChanged   = eCurr.ChSimpl != eOld.ChSimpl;
                bool        tradChanged   = eCurr.ChTrad != eOld.ChTrad;
                bool        pinyinChanged = CedictWriter.WritePinyin(eCurr) != CedictWriter.WritePinyin(eOld);
                // Render in parts
                sb.AppendLine("<div class='entry'>");
                // Let's not dim identical chars if anything changed in HW
                EntryRenderer rCurr = new EntryRenderer(lang, eCurr, !simpChanged && !tradChanged);
                EntryRenderer rOld  = new EntryRenderer(lang, eOld, !simpChanged && !tradChanged);
                rCurr.OneLineHanziLimit = rOld.OneLineHanziLimit = 12;
                if (simpChanged || tradChanged)
                {
                    rCurr.XRenderHanzi(sb, simpChanged ? "new" : "", tradChanged ? "new" : "");
                    rOld.XRenderHanzi(sb, simpChanged ? "old" : "", tradChanged ? "old" : "");
                }
                if (pinyinChanged)
                {
                    rCurr.XRenderPinyin(sb, pinyinChanged ? "new" : "");
                    rOld.XRenderPinyin(sb, "old");
                }
                sb.AppendLine("</div>"); // <div class='entry'>
                // Propagate change
                headNow = ci.HeadBefore;
            }

            if (ci.BodyBefore != null)
            {
                CedictEntry   entryNew = parser.ParseEntry("的 的 [de5] " + trgNow, -1, null);
                EntryRenderer er       = new EntryRenderer(lang, entryNew, true);
                er.XRenderSenses(sb, "new");
                CedictEntry entryOld = parser.ParseEntry("的 的 [de5] " + ci.BodyBefore, -1, null);
                er = new EntryRenderer(lang, entryOld, true);
                er.XRenderSenses(sb, "old");
                // Propagate change
                trgNow = ci.BodyBefore;
            }
            if (ci.StatusBefore != 99)
            {
                statusNow = (EntryStatus)ci.StatusBefore;
            }

            sb.AppendLine("</div>"); // <div class='pastItem'>
        }
示例#17
0
        private static void histRenderChange(StringBuilder sb, ChangeItem ci, bool trailingSeparator, string lang,
                                             CedictParser parser, string extraItemClass = "")
        {
            var tprov = TextProvider.Instance;

            sb.AppendLine();
            string itemClass = "historyItem";

            if (!string.IsNullOrEmpty(extraItemClass))
            {
                itemClass += " " + extraItemClass;
            }
            if (ci.EntryId >= 0)
            {
                sb.AppendLine("<div class='" + itemClass + "' data-entry-id='" + EntryId.IdToString(ci.EntryId) + "'>");
            }
            else
            {
                sb.AppendLine("<div class='" + itemClass + "'>");
            }
            sb.AppendLine("<div class='changeHead'>");

            string iconClass = "";

            if (ci.ChangeType == ChangeType.New)
            {
                iconClass = "fa fa-lightbulb-o ctNew";
            }
            else if (ci.ChangeType == ChangeType.Edit)
            {
                iconClass = "fa fa-pencil-square-o ctEdit";
            }
            else if (ci.ChangeType == ChangeType.Note)
            {
                iconClass = "fa fa-commenting-o ctNote";
            }
            else if (ci.ChangeType == ChangeType.BulkImport)
            {
                iconClass = "fa fa-newspaper-o ctBulk";
            }
            else if (ci.ChangeType == ChangeType.StatusChange)
            {
                if (ci.EntryStatus == EntryStatus.Approved)
                {
                    iconClass = "fa fa-check-square-o ctApprove";
                }
                else if (ci.EntryStatus == EntryStatus.Flagged)
                {
                    iconClass = "fa fa-flag-o ctFlag";
                }
                else
                {
                    iconClass = "fa fa-flag-o ctUnflag";
                }
            }

            sb.Append("<i class='" + iconClass + "' />");
            sb.Append("<div class='changeSummary'>");

            string changeMsg = getChangeTypeStr(ci.ChangeType, ci.CountB, ci.EntryStatus, lang);
            string changeCls = "changeType";

            sb.Append("<span class='" + changeCls + "'>");
            sb.Append(HtmlEncoder.Default.Encode(changeMsg));
            sb.Append(" &bull; </span>");

            sb.Append("<span class='changeUser'>");
            sb.Append(HtmlEncoder.Default.Encode(ci.User));
            sb.Append("</span>");

            sb.Append("<span class='changeTime'>");
            sb.Append(HtmlEncoder.Default.Encode(getTimeStr(ci.When, lang)));
            sb.Append("</span>");

            if (ci.ChangeType != ChangeType.BulkImport && ci.CountA > 0)
            {
                sb.Append("<span class='revealPast'>+" + ci.CountA.ToString() + "</span>");
            }

            sb.Append("</div>"); // <div class='changeSummary'>

            sb.AppendLine("<div class='changeNote'>");
            if (ci.ChangeType == ChangeType.BulkImport)
            {
                string newCount = null;
                string chgCount = null;
                if (ci.CountA > 0)
                {
                    newCount = tprov.GetString(lang, "history.bulkNewWords");
                    newCount = string.Format(newCount, ci.CountA);
                }
                if (ci.CountB > 0)
                {
                    chgCount = tprov.GetString(lang, "history.bulkChangedWords");
                    chgCount = string.Format(chgCount, ci.CountB);
                }
                if (chgCount != null || newCount != null)
                {
                    sb.Append("<p>");
                    if (newCount != null)
                    {
                        sb.Append(HtmlEncoder.Default.Encode(newCount));
                    }
                    if (newCount != null && chgCount != null)
                    {
                        sb.Append(" &bull; ");
                    }
                    if (chgCount != null)
                    {
                        sb.Append(HtmlEncoder.Default.Encode(chgCount));
                    }
                    sb.Append("</p>");
                }
                sb.Append("<span class='bulkLink'>[");
                sb.Append("<a href='/" + lang + "/read/details/change-" + ci.BulkRef.ToString("000") + "' target='_blank'>");
                sb.Append(tprov.GetString(lang, "history.bulkLink") + "</a>");
                sb.Append("]</span> ");
            }
            sb.Append("<span class='changeNoteText'>");
            string note = HtmlEncoder.Default.Encode(ci.Note);

            note = note.Replace("&#xA;", "<br/>");
            sb.Append(note);
            sb.Append("</span>");
            sb.Append("</div>");

            sb.Append("</div>"); // <div class='changeHead'>

            sb.AppendLine("<div class='changeEntry'>");
            if (ci.ChangeType != ChangeType.BulkImport)
            {
                sb.AppendLine("<div class='histEntryOps'>");
                sb.Append("<a class='ajax' href='/" + lang + "/edit/existing/" + EntryId.IdToString(ci.EntryId) + "'>");
                sb.Append("<i class='opHistEdit fa fa-pencil'></i></a>");
                //sb.Append("<i class='opHistEdit fa fa-pencil' />");
                sb.Append("<i class='opHistComment fa fa-commenting-o' />");
                sb.Append("<i class='opHistFlag fa fa-flag-o' />");
                sb.Append("</div>"); // <div class='histEntryOps'>
            }

            if (ci.ChangeType != ChangeType.BulkImport)
            {
                // NOT edited
                if (ci.BodyBefore == null && ci.HeadBefore == null)
                {
                    CedictEntry entry = parser.ParseEntry(ci.EntryHead + " " + ci.EntryBody, 0, null);
                    entry.Status = ci.EntryStatus;
                    EntryRenderer er = new EntryRenderer(lang, entry, true);
                    er.OneLineHanziLimit = 12;
                    er.Render(sb, null);
                }
                // Entry edited: show "diff" in head and/or body
                else
                {
                    // Current, and comparison base
                    CedictEntry eCurr = parser.ParseEntry(ci.EntryHead + " " + ci.EntryBody, 0, null);
                    eCurr.Status = ci.EntryStatus;
                    string      headOld       = ci.HeadBefore == null ? ci.EntryHead : ci.HeadBefore;
                    string      bodyOld       = ci.BodyBefore == null ? ci.EntryBody : ci.BodyBefore;
                    CedictEntry eOld          = parser.ParseEntry(headOld + " " + bodyOld, 0, null);
                    bool        simpChanged   = eCurr.ChSimpl != eOld.ChSimpl;
                    bool        tradChanged   = eCurr.ChTrad != eOld.ChTrad;
                    bool        pinyinChanged = CedictWriter.WritePinyin(eCurr) != CedictWriter.WritePinyin(eOld);
                    bool        bodyChanged   = ci.BodyBefore != null;
                    // Render in parts
                    sb.AppendLine("<div class='entry'>");
                    // Let's not dim identical chars if anything changed in HW
                    EntryRenderer rCurr = new EntryRenderer(lang, eCurr, !simpChanged && !tradChanged);
                    EntryRenderer rOld  = new EntryRenderer(lang, eOld, !simpChanged && !tradChanged);
                    rCurr.OneLineHanziLimit = rOld.OneLineHanziLimit = 12;
                    rCurr.XRenderStatus(sb);
                    rCurr.XRenderHanzi(sb, simpChanged ? "new" : "", tradChanged ? "new" : "");
                    if (simpChanged || tradChanged)
                    {
                        rOld.XRenderHanzi(sb, simpChanged ? "old" : "", tradChanged ? "old" : "");
                    }
                    rCurr.XRenderPinyin(sb, pinyinChanged ? "new" : "");
                    if (pinyinChanged)
                    {
                        rOld.XRenderPinyin(sb, "old");
                    }
                    rCurr.XRenderSenses(sb, bodyChanged ? "new" : "");
                    if (bodyChanged)
                    {
                        rOld.XRenderSenses(sb, "old");
                    }
                    sb.AppendLine("</div>"); // <div class='entry'>
                }
            }
            sb.Append("</div>"); // <div class='changeEntry'>

            sb.Append("</div>"); // <div class='changeHead'>
            sb.Append("</div>"); // <div class='historyItem'>
            sb.AppendLine();

            if (trailingSeparator)
            {
                sb.AppendLine("<div class='historySep'></div>");
            }
        }
示例#18
0
        private bool validateHeadword(string lang, string simp, string trad, string pinyin,
                                      List <HeadwordProblem> errorsSimp, List <HeadwordProblem> errorsTrad, List <HeadwordProblem> errorsPinyin)
        {
            var    tprov = TextProvider.Instance;
            string msg;

            // Check each simplified: is it really simplified?
            UniHanziInfo[] uhiSimp = langRepo.GetUnihanInfo(simp);
            for (int i = 0; i != uhiSimp.Length; ++i)
            {
                var uhi = uhiSimp[i];
                if (!uhi.CanBeSimp)
                {
                    msg = tprov.GetString(lang, "editEntry.hwProblemNotSimplified");
                    msg = string.Format(msg, simp[i]);
                    errorsSimp.Add(new HeadwordProblem(false, msg));
                }
            }
            // Check each traditional: is it really traditional?
            UniHanziInfo[] uhiTrad = langRepo.GetUnihanInfo(trad);
            for (int i = 0; i != uhiTrad.Length; ++i)
            {
                var uhi = uhiTrad[i];
                // Traditional chars are listed as their own traditional variant
                if (Array.IndexOf(uhi.TradVariants, trad[i]) < 0)
                {
                    msg = tprov.GetString(lang, "editEntry.hwProblemNotTraditional");
                    msg = string.Format(msg, trad[i]);
                    errorsTrad.Add(new HeadwordProblem(false, msg));
                }
            }
            // Check each traditional against its simplified friend
            if (trad.Length != simp.Length)
            {
                errorsTrad.Add(new HeadwordProblem(true, tprov.GetString(lang, "editEntry.hwProblemSimpTradCounts")));
            }
            else
            {
                for (int i = 0; i != uhiSimp.Length; ++i)
                {
                    var uhi = uhiSimp[i];
                    if (Array.IndexOf(uhi.TradVariants, trad[i]) < 0)
                    {
                        msg = tprov.GetString(lang, "editEntry.hwProblemNotTradForSimp");
                        msg = string.Format(msg, simp[i], trad[i]);
                        errorsTrad.Add(new HeadwordProblem(false, msg));
                    }
                }
            }
            // Normalize pinyin (multiple spaces, leading/trailing spaces)
            string pyNorm = pinyin;

            while (true)
            {
                string x = pyNorm.Replace("  ", " ");
                if (x == pyNorm)
                {
                    break;
                }
                pyNorm = x;
            }
            pyNorm = pyNorm.Trim();
            if (pyNorm != pinyin)
            {
                errorsPinyin.Add(new HeadwordProblem(true, tprov.GetString(lang, "editEntry.hwProblemExtraSpacesPinyin")));
            }
            // Try to match up normalized pinyin with simplified Hanzi
            CedictParser parser = new CedictParser();
            CedictEntry  ee     = null;

            try { ee = parser.ParseEntry(trad + " " + simp + " [" + pyNorm + "] /x/", 0, null); }
            catch { }
            if (ee == null)
            {
                errorsPinyin.Add(new HeadwordProblem(true, tprov.GetString(lang, "editEntry.hwProblemInvalidPinyin")));
            }
            else
            {
                if (simp.Length == ee.ChSimpl.Length)
                {
                    for (int i = 0; i != uhiSimp.Length; ++i)
                    {
                        var uhi = uhiSimp[i];
                        var py  = ee.GetPinyinAt(i);
                        var cnt = uhi.Pinyin.Count(x => x.GetDisplayString(false) == py.GetDisplayString(false));
                        if (cnt == 0)
                        {
                            msg = tprov.GetString(lang, "editEntry.hwProblemWrongPinyin");
                            msg = string.Format(msg, py.GetDisplayString(false), simp[i]);
                            errorsPinyin.Add(new HeadwordProblem(false, msg));
                        }
                    }
                }
            }
            return(ee != null);
        }