int QAChecker::Check(CatalogItemPtr item) { int issues = 0; for (auto& c: m_checks) { if (item->GetString().empty() || (item->HasPlural() && item->GetPluralString().empty())) continue; if (c->CheckItem(item)) issues++; } return issues; }
void Update(const CatalogItemPtr& item) override { auto text = CommentDialog::RemoveStartHash(item->GetComment()); text.Trim(); m_comment->SetLanguage(m_parent->GetCurrentLanguage()); m_comment->SetAndWrapText(text); }
bool CheckString(CatalogItemPtr item, const wxString& source, const wxString& translation) override { if (u_isupper(source[0]) && u_islower(translation[0])) { item->SetIssue(CatalogItem::Issue::Warning, _("The translation should start as a sentence.")); return true; } if (u_islower(source[0]) && u_isupper(translation[0])) { if (m_lang != "de") { item->SetIssue(CatalogItem::Issue::Warning, _("The translation should start with a lowercase character.")); return true; } // else: German nouns start uppercased, this would cause too many false positives } return false; }
void Update(const CatalogItemPtr& item) override { #ifdef __WXMSW__ auto add = _("Add comment"); auto edit = _("Edit comment"); #else auto add = _("Add Comment"); auto edit = _("Edit Comment"); #endif m_btn->SetLabel(item->HasComment() ? edit : add); }
void Update(const CatalogItemPtr& item) override { auto comment = wxJoin(item->GetExtractedComments(), '\n', '\0'); if (comment.StartsWith("TRANSLATORS:") || comment.StartsWith("translators:")) { comment.Remove(0, 12); if (!comment.empty() && comment[0] == ' ') comment.Remove(0, 1); } m_comment->SetAndWrapLabel(comment); }
bool CheckItem(CatalogItemPtr item) override { if (!item->HasPlural()) return false; bool foundTranslated = false; bool foundEmpty = false; for (auto& s: item->GetTranslations()) { if (s.empty()) foundEmpty = true; else foundTranslated = true; } if (foundEmpty && foundTranslated) { item->SetIssue(CatalogItem::Issue::Warning, _("Not all plural forms are translated.")); return true; } return false; }
void SuggestionsSidebarBlock::QueryProvider(SuggestionsBackend& backend, const CatalogItemPtr& item, uint64_t queryId) { m_pendingQueries++; // we need something to talk to GUI thread through that is guaranteed // to exist, and the app object is a good choice: auto backendPtr = &backend; std::weak_ptr<SuggestionsSidebarBlock> weakSelf = std::dynamic_pointer_cast<SuggestionsSidebarBlock>(shared_from_this()); m_provider->SuggestTranslation ( backend, m_parent->GetCurrentSourceLanguage(), m_parent->GetCurrentLanguage(), item->GetString().ToStdWstring(), // when receiving data [=](const SuggestionsList& hits){ call_on_main_thread([weakSelf,queryId,hits]{ auto self = weakSelf.lock(); // maybe this call is already out of date: if (!self || self->m_latestQueryId != queryId) return; self->UpdateSuggestions(hits); if (--self->m_pendingQueries == 0) self->OnQueriesFinished(); }); }, // on error: [=](std::exception_ptr e){ call_on_main_thread([weakSelf,queryId,backendPtr,e]{ auto self = weakSelf.lock(); // maybe this call is already out of date: if (!self || self->m_latestQueryId != queryId) return; self->ReportError(backendPtr, e); if (--self->m_pendingQueries == 0) self->OnQueriesFinished(); }); } ); }
bool QACheck::CheckItem(CatalogItemPtr item) { if (!item->GetTranslation().empty() && CheckString(item, item->GetString(), item->GetTranslation())) return true; if (item->HasPlural()) { unsigned count = item->GetNumberOfTranslations(); for (unsigned i = 1; i < count; i++) { auto t = item->GetTranslation(i); if (!t.empty() && CheckString(item, item->GetPluralString(), t)) return true; } } return false; }
bool CheckString(CatalogItemPtr item, const wxString& source, const wxString& translation) override { if (u_isspace(source[0]) && !u_isspace(translation[0])) { item->SetIssue(CatalogItem::Issue::Warning, _(L"The translation doesn’t start with a space.")); return true; } if (!u_isspace(source[0]) && u_isspace(translation[0])) { item->SetIssue(CatalogItem::Issue::Warning, _(L"The translation starts with a space, but the source text doesn’t.")); return true; } if (source.Last() == '\n' && translation.Last() != '\n') { item->SetIssue(CatalogItem::Issue::Warning, _(L"The translation is missing a newline at the end.")); return true; } if (source.Last() != '\n' && translation.Last() == '\n') { item->SetIssue(CatalogItem::Issue::Warning, _(L"The translation ends with a newline, but the source text doesn’t.")); return true; } if (u_isspace(source.Last()) && !u_isspace(translation.Last())) { item->SetIssue(CatalogItem::Issue::Warning, _(L"The translation is missing a space at the end.")); return true; } if (!u_isspace(source.Last()) && u_isspace(translation.Last())) { item->SetIssue(CatalogItem::Issue::Warning, _(L"The translation ends with a space, but the source text doesn’t.")); return true; } return false; }
bool CheckString(CatalogItemPtr item, const wxString& source, const wxString& translation) override { const UChar32 s_last = source.Last(); const UChar32 t_last = translation.Last(); const bool s_punct = u_ispunct(s_last); const bool t_punct = u_ispunct(t_last); if (u_getIntPropertyValue(s_last, UCHAR_BIDI_PAIRED_BRACKET_TYPE) == U_BPT_CLOSE || u_getIntPropertyValue(t_last, UCHAR_BIDI_PAIRED_BRACKET_TYPE) == U_BPT_CLOSE) { // too many reordering related false positives for brackets // e.g. "your {site} account" -> "váš účet na {site}" if ((wchar_t)u_getBidiPairedBracket(s_last) != (wchar_t)source[0]) { return false; } else { // OTOH, it's desirable to check strings fully enclosed in brackets like "(unsaved)" if (source.find_first_of((wchar_t)s_last, 1) != source.size() - 1) { // it's more complicated, possibly something like "your {foo} on {bar}" return false; } } } if (u_hasBinaryProperty(s_last, UCHAR_QUOTATION_MARK) || (!s_punct && u_hasBinaryProperty(t_last, UCHAR_QUOTATION_MARK))) { // quoted fragments can move around, e.g., so ignore quotes in reporting: // >> Invalid value for ‘{fieldName}’ field // >> Valor inválido para el campo ‘{fieldName}’ // TODO: count quote characters to check if used correctly in translation; don't check position return false; } if (s_punct && !t_punct) { item->SetIssue(CatalogItem::Issue::Warning, wxString::Format(_(L"The translation should end with “%s”."), wxString(wxUniChar(s_last)))); return true; } else if (!s_punct && t_punct) { item->SetIssue(CatalogItem::Issue::Warning, wxString::Format(_(L"The translation should not end with “%s”."), wxString(wxUniChar(t_last)))); return true; } else if (s_punct && t_punct && s_last != t_last) { if (t_last == L'…' && source.EndsWith("...")) { // as a special case, allow translating ... (3 dots) as … (ellipsis) } else if (u_hasBinaryProperty(s_last, UCHAR_QUOTATION_MARK) && u_hasBinaryProperty(t_last, UCHAR_QUOTATION_MARK)) { // don't check for correct quotes for now, accept any quotations marks as equal } else if (IsEquivalent(s_last, t_last)) { // some characters are mostly equivalent and we shouldn't warn about them } else { item->SetIssue(CatalogItem::Issue::Warning, wxString::Format(_(L"The translation ends with “%s”, but the source text ends with “%s”."), wxString(wxUniChar(t_last)), wxString(wxUniChar(s_last)))); return true; } } return false; }
void Update(const CatalogItemPtr& item) override { auto text = CommentDialog::RemoveStartHash(item->GetComment()); text.Trim(); m_comment->SetAndWrapLabel(text); }
bool ShouldShowForItem(const CatalogItemPtr& item) const override { return item->HasComment(); }
void Update(const CatalogItemPtr& item) override { auto txt = wxJoin(item->GetOldMsgid(), ' ', '\0'); m_text->SetAndWrapLabel(txt); }
bool ShouldShowForItem(const CatalogItemPtr& item) const override { return item->HasOldMsgid(); }
void Update(const CatalogItemPtr& item) override { m_text->SetAndWrapLabel(item->GetOldMsgid()); }