diff --git a/Makefile.am b/Makefile.am index c5692fa1d..0d2d142dc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,4 +16,5 @@ EXTRA_DIST = \ deps/pugixml/src/pugiconfig.hpp \ deps/pugixml/src/pugixml.cpp \ deps/pugixml/src/pugixml.hpp \ + README.md \ bootstrap diff --git a/src/catalog.cpp b/src/catalog.cpp index 56394abe4..9d823305d 100644 --- a/src/catalog.cpp +++ b/src/catalog.cpp @@ -124,6 +124,45 @@ wxString Catalog::HeaderData::ToString(const wxString& line_delim) return hdr; } +void Catalog::HeaderData::NormalizeHeaderOrder() +{ + // This is the order of header lines in a POT file + // generated by GNU Gettext's xgettext utility, or + // rearranged by the msgmerge utility. + const wxString canonicalOrder[] = + { + "Project-Id-Version", + "Report-Msgid-Bugs-To", + "POT-Creation-Date", + "PO-Revision-Date", + "Last-Translator", + "Language-Team", + "Language", + "MIME-Version", + "Content-Type", + "Content-Transfer-Encoding", + "Plural-Forms" + }; + + const wxArrayString orderArr(sizeof(canonicalOrder) / sizeof(*canonicalOrder), + canonicalOrder); + + // Sort standard header lines to the beginning of the header, in their + // canonical order, and the rest after them, in their original order. + std::stable_sort(m_entries.begin(), m_entries.end(), + [&orderArr](const Entry& a, const Entry& b) + { + auto coalesce = [&orderArr](int x) -> int { + if (x == wxNOT_FOUND) + return 1 + static_cast(orderArr.GetCount()); + else + return x; + }; + + return coalesce(orderArr.Index(a.Key)) < coalesce(orderArr.Index(b.Key)); + }); +} + void Catalog::HeaderData::UpdateDict() { SetHeader("Project-Id-Version", Project); @@ -215,6 +254,8 @@ void Catalog::HeaderData::UpdateDict() path.Printf("X-Poedit-SearchPathExcluded-%i", i); SetHeader(path, SearchPathsExcluded[i]); } + + NormalizeHeaderOrder(); } void Catalog::HeaderData::ParseDict() diff --git a/src/catalog.h b/src/catalog.h index d3ea72a4d..39453bd51 100644 --- a/src/catalog.h +++ b/src/catalog.h @@ -393,6 +393,8 @@ class Catalog Entries m_entries; const Entry *Find(const wxString& key) const; + + void NormalizeHeaderOrder(); }; enum CreationFlags diff --git a/src/commentdlg.cpp b/src/commentdlg.cpp index ccd261546..2342ee4de 100644 --- a/src/commentdlg.cpp +++ b/src/commentdlg.cpp @@ -50,7 +50,8 @@ CommentDialog::CommentDialog(wxWindow *parent, const wxString& comment) : wxDial // else: button is labeled "Update" in XRC wxAcceleratorEntry entries[] = { - { wxACCEL_CMD, WXK_RETURN, wxID_OK } + { wxACCEL_CMD, WXK_RETURN, wxID_OK }, + { wxACCEL_CMD, WXK_NUMPAD_ENTER, wxID_OK } }; wxAcceleratorTable accel(WXSIZEOF(entries), entries); SetAcceleratorTable(accel); diff --git a/src/edframe.cpp b/src/edframe.cpp index c19a57959..469a9224e 100644 --- a/src/edframe.cpp +++ b/src/edframe.cpp @@ -2613,12 +2613,12 @@ void PoeditFrame::UpdateTitle() } else #endif +#endif // __WXOSX__ if (!subtitle.empty()) { title << MACOS_OR_OTHER(L" — ", L" • "); title << subtitle; } -#endif // __WXOSX__ m_fileNamePartOfTitle = title; diff --git a/src/editing_area.cpp b/src/editing_area.cpp index 760d5db82..3151bd703 100644 --- a/src/editing_area.cpp +++ b/src/editing_area.cpp @@ -1012,7 +1012,7 @@ void EditingArea::UpdateCharCounter(CatalogItemPtr item) if (!m_charCounter || !item) return; - if (item->HasPlural()) + if (item->HasPlural() && m_pluralNotebook) { int index = m_pluralNotebook->GetSelection(); if (index == 0) diff --git a/src/edlistctrl.cpp b/src/edlistctrl.cpp index 9c2218c76..d63545b53 100644 --- a/src/edlistctrl.cpp +++ b/src/edlistctrl.cpp @@ -848,6 +848,6 @@ void PoeditListCtrl::DoFreeze() void PoeditListCtrl::DoThaw() { - m_model->Thaw(); wxDataViewCtrl::DoThaw(); + m_model->Thaw(); } diff --git a/src/export_html.cpp b/src/export_html.cpp index d33241770..04b3efbd1 100644 --- a/src/export_html.cpp +++ b/src/export_html.cpp @@ -56,6 +56,8 @@ extern const char *CSS_STYLE; void Catalog::ExportToHTML(std::ostream& f) { const bool translated = HasCapability(Catalog::Cap::Translations); + const auto lang = translated ? GetLanguage() : Language(); + const auto srclang = GetSourceLanguage(); f << "\n" "\n" @@ -73,8 +75,8 @@ void Catalog::ExportToHTML(std::ostream& f) f << "\n"; if (!m_header.Project.empty()) TableRow(f, _("Project:"), m_header.Project); - if (translated && m_header.Lang.IsValid()) - TableRow(f, _("Language:"), m_header.Lang.DisplayName()); + if (translated && lang.IsValid()) + TableRow(f, _("Language:"), lang.DisplayName()); f << "
\n"; @@ -120,20 +122,20 @@ void Catalog::ExportToHTML(std::ostream& f) // Translations: std::string lang_src, lang_tra; - if (m_sourceLanguage.IsValid()) - lang_src = " lang='" + m_sourceLanguage.LanguageTag() + "'"; - if (m_header.Lang.IsValid()) + if (srclang.IsValid()) + lang_src = " lang='" + srclang.LanguageTag() + "'"; + if (lang.IsValid()) { - lang_tra = " lang='" + m_header.Lang.LanguageTag() + "'"; - if (m_header.Lang.IsRTL()) + lang_tra = " lang='" + lang.LanguageTag() + "'"; + if (lang.IsRTL()) lang_tra += " dir='rtl'"; } - auto thead_src = m_sourceLanguage.IsValid() - ? (wxString::Format(_(L"Source text — %s"), m_sourceLanguage.DisplayName())) + auto thead_src = srclang.IsValid() + ? (wxString::Format(_(L"Source text — %s"), srclang.DisplayName())) : _("Source text"); auto thead_tra = wxString::Format(_(L"Translation — %s"), - m_header.Lang.IsValid() ? m_header.Lang.DisplayName() : _("unknown language")); + lang.IsValid() ? lang.DisplayName() : _("unknown language")); f << "\n" " \n" @@ -244,21 +246,10 @@ Based on Minimal CSS (minimalcss.com) under the MIT license. * { margin: 0; padding: 0; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } /* Layout */ -body { background-color: #fff; color: #333; font: 14px/20px -apple-system, "HelveticaNeue", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; } - -header { width: 100%; margin: 0 auto; position: relative; padding: 20px 0; margin-bottom: 20px; } - -nav ul { margin: 0; } -nav ul li { display: inline; margin-right: 20px; font-size: 16px; line-height: 28px; color: #333; } -nav ul li a { color: #333; } +body { font: 14px/20px -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; } .container { position: relative; max-width: 90%; margin: 0 auto; } -footer { border-top:1px solid #ccc; font-size:11px; line-height:26px; color:#999; } -footer a { color:#999999; } -footer a:hover { color:#105CB6; } -footer ul li { display:inline; list-style:none; padding-left:20px; } - /* Typography */ a { color: #105CB6; text-decoration: none; } a:hover, a:focus { color: #105CB6; text-decoration: underline; } @@ -270,7 +261,6 @@ h3 { font-size: 16px; line-height: 20px; margin: 10px 0; } h4 { font-size: 14px; line-height: 20px; margin: 10px 0; } h5 { font-size: 12px; line-height: 20px; margin: 10px 0; } h5 { font-size: 10px; line-height: 20px; margin: 10px 0; } -h1,h2,h3,h4,h5,h6 { color: #333; } p { margin-bottom: 10px; } @@ -285,15 +275,6 @@ img.center { margin: 0 auto; display: block; } .text-right { text-align: right; } .text-justify { text-align: justify; } -/* Misc */ -hr { background-color: #ccc; border: 0px; color: #ccc; height: 1px; margin: 8px 0 20px 0; } -pre, code { background:#E0ECF6; display:block; margin-bottom: 20px; padding:10px; } - -blockquote { margin: 10px 10px 20px; padding: 9px; background-color: #f8f8f8; color: #666; border-left: 5px solid #ddd; font: 14px/20px Georgia, Times, serif; quotes: "\201C" "\201D"; } -blockquote p { margin: 0; } -blockquote:before { content: open-quote; font-weight: bold; } -blockquote:after { content: close-quote; font-weight: bold; } - /* List */ ul { list-style-position:inside; } ol { list-style-position:inside; } @@ -327,12 +308,8 @@ table.metadata td { .graph div { float: left; } .graph div:first-child { border-top-left-radius: 3px; border-bottom-left-radius: 3px; } .graph div:last-child { border-top-right-radius: 3px; border-bottom-right-radius: 3px; } -.percent-done { background-color: rgb(90, 228, 140); height: 10px; } -.percent-fuzzy { background-color: rgb(255, 167, 52); height: 10px; } -.percent-untrans { background-color: #F1F1F1; height: 10px; } .legend { font-size: smaller; - color: #aaa; padding-top: 12px; text-align: center; } @@ -345,7 +322,7 @@ table.translations { table.translations th, table.translations td { padding: 5px 10px; vertical-align: top; - border-bottom: 1px solid #E1E1E1; + border-bottom: 1px solid #F1F1F1; } table.translations th { text-align: left; @@ -360,24 +337,42 @@ tr.comments div { float: left; max-width: 90%; font-size: smaller; - color: #aaa; } tr.comments div p:last-child { margin-bottom: 0; } tr.comments td { padding-top: 0; } -.fuzzy .tra { - color: rgb(218, 123, 0); -} - .msgctxt { - color: rgb(70, 109, 137); font-size: smaller; - background-color: rgb(217, 232, 242); border-radius: 2px; padding: 2px 4px; margin-right: 4px; } + +/* Colors */ + +body { background-color: #fff; color: #333; } + +.percent-done { background-color: rgb(146, 236, 106); height: 10px; } +.percent-fuzzy { background-color: rgb(255, 149, 0); height: 10px; } +.percent-untrans { background-color: #F1F1F1; height: 10px; } +.legend { color: #aaa; } +tr.comments div { color: #aaa; } +.fuzzy .tra { color: rgb(230, 134, 0); } + +.msgctxt { color: rgb(70, 109, 137); background-color: rgb(217, 232, 242); } + + +@media (prefers-color-scheme: dark) { + body { background-color: rgb(45, 42, 41); color: #eee; } + .percent-untrans { background-color: rgba(255, 255, 255, 0.3); } + .legend { color: rgba(255, 255, 255, 0.6); } + tr.comments div { color: rgba(255, 255, 255, 0.6); } + .fuzzy .tra { color: rgb(253, 178, 72); } + .msgctxt { color: rgb(180, 222, 254); background-color: rgba(67, 94, 147, 0.6); } + table.translations th, table.translations td { border-bottom: 1px solid #333; } +} + )"; } // anonymous namespace diff --git a/src/tm/transmem.cpp b/src/tm/transmem.cpp index ca7d3b304..5fcaded8f 100644 --- a/src/tm/transmem.cpp +++ b/src/tm/transmem.cpp @@ -559,9 +559,11 @@ void TranslationMemoryImpl::ExportData(TranslationMemory::IOInterface& destinati try { auto reader = m_mng->Reader(); - int32_t numDocs = reader->numDocs(); + int32_t numDocs = reader->maxDoc(); for (int32_t i = 0; i < numDocs; i++) { + if (reader->isDeleted(i)) + continue; auto doc = reader->document(i); destination.Insert (