def test_not_counting_outdated(self): """Out-of-date translations shouldn't count as "done". "Out-of-date" can mean either moderately or majorly out of date. The only thing we don't care about is typo-level outdatedness. """ t = TranslatedRevisionFactory(document__locale="de", is_approved=True) overview = l10n_overview_rows("de") eq_(1, overview["top-20"]["numerator"]) eq_(1, overview["top-50"]["numerator"]) eq_(1, overview["top-100"]["numerator"]) eq_(1, overview["all"]["numerator"]) # Update the parent with a typo-level revision: ApprovedRevisionFactory( document=t.document.parent, significance=TYPO_SIGNIFICANCE, is_ready_for_localization=True ) # Assert it still shows up in the numerators: overview = l10n_overview_rows("de") eq_(1, overview["top-20"]["numerator"]) eq_(1, overview["top-50"]["numerator"]) eq_(1, overview["top-100"]["numerator"]) eq_(1, overview["all"]["numerator"]) # Update the parent with a medium-level revision: ApprovedRevisionFactory( document=t.document.parent, significance=MEDIUM_SIGNIFICANCE, is_ready_for_localization=True ) # Assert it no longer shows up in the numerators: overview = l10n_overview_rows("de") eq_(0, overview["all"]["numerator"]) eq_(0, overview["top-20"]["numerator"]) eq_(0, overview["top-50"]["numerator"]) eq_(0, overview["top-100"]["numerator"])
def test_by_product(self): """Test the product filtering of the overview.""" p = ProductFactory(title='Firefox', slug='firefox') t = TranslatedRevisionFactory(is_approved=True, document__locale='de') eq_(0, l10n_overview_rows('de', product=p)['all']['numerator']) eq_(0, l10n_overview_rows('de', product=p)['all']['denominator']) t.document.parent.products.add(p) eq_(1, l10n_overview_rows('de', product=p)['all']['numerator']) eq_(1, l10n_overview_rows('de', product=p)['all']['denominator'])
def test_counting_unready_templates(self): """Templates without a ready-for-l10n rev don't count""" # Make a template with an approved but not-ready-for-l10n rev: d = TemplateDocumentFactory(is_localizable=True) r = ApprovedRevisionFactory(document=d, is_ready_for_localization=False) # It shouldn't show up in the total: eq_(0, l10n_overview_rows("de")["templates"]["denominator"]) r.is_ready_for_localization = True r.save() eq_(1, l10n_overview_rows("de")["templates"]["denominator"])
def test_by_product(self): """Test the product filtering of the overview.""" p = product(title="Firefox", slug="firefox", save=True) t = translated_revision(is_approved=True, save=True) eq_(0, l10n_overview_rows("de", product=p)["all"]["numerator"]) eq_(0, l10n_overview_rows("de", product=p)["all"]["denominator"]) t.document.parent.products.add(p) eq_(1, l10n_overview_rows("de", product=p)["all"]["numerator"]) eq_(1, l10n_overview_rows("de", product=p)["all"]["denominator"])
def test_by_product(self): """Test the product filtering of the overview.""" p = product(title='Firefox', slug='firefox', save=True) t = translated_revision(is_approved=True, save=True) eq_(0, l10n_overview_rows('de', product=p)['all']['numerator']) eq_(0, l10n_overview_rows('de', product=p)['all']['denominator']) t.document.parent.products.add(p) eq_(1, l10n_overview_rows('de', product=p)['all']['numerator']) eq_(1, l10n_overview_rows('de', product=p)['all']['denominator'])
def test_counting_unready_docs(self): """Docs without a ready-for-l10n rev shouldn't count in total.""" # Make a doc with an approved but not-ready-for-l10n rev: d = DocumentFactory(is_localizable=True) r = ApprovedRevisionFactory(document=d, is_ready_for_localization=False) # It shouldn't show up in the total: eq_(0, l10n_overview_rows('de')['all']['denominator']) r.is_ready_for_localization = True r.save() eq_(1, l10n_overview_rows('de')['all']['denominator'])
def test_by_product(self): """Test the product filtering of the overview.""" p = ProductFactory(title="Firefox", slug="firefox") t = TranslatedRevisionFactory(is_approved=True, document__locale="de") eq_(0, l10n_overview_rows("de", product=p)["all"]["numerator"]) eq_(0, l10n_overview_rows("de", product=p)["all"]["denominator"]) t.document.parent.products.add(p) eq_(1, l10n_overview_rows("de", product=p)["all"]["numerator"]) eq_(1, l10n_overview_rows("de", product=p)["all"]["denominator"])
def test_templates_and_docs_disjunct(self): """Make sure templates aren't included in the All Articles count.""" t = translated_revision(is_approved=True, save=True) # It shows up in All when it's a normal doc: eq_(1, l10n_overview_rows("de")["all"]["numerator"]) eq_(1, l10n_overview_rows("de")["all"]["denominator"]) t.document.parent.title = t.document.title = "Template:thing" t.document.parent.is_template = t.document.is_template = True t.document.parent.save() t.document.save() # ...but not when it's a template: eq_(0, l10n_overview_rows("de")["all"]["numerator"]) eq_(0, l10n_overview_rows("de")["all"]["denominator"])
def test_templates_and_docs_disjunct(self): """Make sure templates aren't included in the All Articles count.""" t = TranslatedRevisionFactory(document__locale="de", is_approved=True) # It shows up in All when it's a normal doc: eq_(1, l10n_overview_rows("de")["all"]["numerator"]) eq_(1, l10n_overview_rows("de")["all"]["denominator"]) t.document.parent.title = t.document.title = "Template:thing" t.document.parent.category = TEMPLATES_CATEGORY # is_template will be automatically set for both templates, and so will # the child document's category. t.document.parent.save() t.document.save() # ...but not when it's a template: eq_(0, l10n_overview_rows("de")["all"]["numerator"]) eq_(0, l10n_overview_rows("de")["all"]["denominator"])
def test_miscounting_archived(self): """ Verify that the l10n overview readout treats archived docs consistently. Bug 1012384 """ locale = 'nl' parent1 = DocumentFactory(category=CANNED_RESPONSES_CATEGORY, is_archived=False) translation1 = DocumentFactory(parent=parent1, locale=locale) parent2 = DocumentFactory(category=CANNED_RESPONSES_CATEGORY, is_archived=True) translation2 = DocumentFactory(parent=parent2, locale=locale) trans_rev1 = ApprovedRevisionFactory(document=parent1, is_ready_for_localization=True) ApprovedRevisionFactory(document=translation1, based_on=trans_rev1) trans_rev2 = ApprovedRevisionFactory(document=parent2, is_ready_for_localization=True) ApprovedRevisionFactory(document=translation2, based_on=trans_rev2) # Document.save() will enforce that parents and translations share is_archived. # The point of this is to test what happens when that isn't true though, # so bypass Document.save(). translation2.is_archived = False ModelBase.save(translation2) eq_(translation2.is_archived, False) overview = l10n_overview_rows(locale) eq_(1, overview['all']['denominator']) eq_(1, overview['all']['numerator'])
def test_templates_and_docs_disjunct(self): """Make sure templates aren't included in the All Articles count.""" t = translated_revision(is_approved=True, save=True) # It shows up in All when it's a normal doc: eq_(1, l10n_overview_rows('de')['all']['numerator']) eq_(1, l10n_overview_rows('de')['all']['denominator']) t.document.parent.title = t.document.title = 'Template:thing' t.document.parent.category = TEMPLATES_CATEGORY # is_template will be automatically set for both templates, and so will # the child document's category. t.document.parent.save() t.document.save() # ...but not when it's a template: eq_(0, l10n_overview_rows('de')['all']['numerator']) eq_(0, l10n_overview_rows('de')['all']['denominator'])
def test_counting_unready_docs(self): """Docs without a ready-for-l10n rev shouldn't count in total.""" # Make a doc with an approved but not-ready-for-l10n rev: r = revision( document=document(title="smoo", is_localizable=True, save=True), is_ready_for_localization=False, is_approved=True, save=True, ) # It shouldn't show up in the total: eq_(0, l10n_overview_rows("de")["all"]["denominator"]) r.is_ready_for_localization = True r.save() eq_(1, l10n_overview_rows("de")["all"]["denominator"])
def test_redirects_are_ignored(self): """Verify that redirects aren't counted in the overview.""" TranslatedRevisionFactory(document__locale="de", is_approved=True) eq_(1, l10n_overview_rows("de")["all"]["numerator"]) # A redirect shouldn't affect any of the tests. RedirectRevisionFactory( document__is_localizable=True, document__is_template=True, is_ready_for_localization=True ) overview = l10n_overview_rows("de") eq_(1, overview["all"]["numerator"]) eq_(1, overview["top-20"]["numerator"]) eq_(1, overview["top-50"]["numerator"]) eq_(1, overview["top-100"]["numerator"])
def test_counting_unready_templates(self): """Templates without a ready-for-l10n rev don't count""" # Make a template with an approved but not-ready-for-l10n rev: r = revision(document=document(title='Template:smoo', is_localizable=True, is_template=True, save=True), is_ready_for_localization=False, is_approved=True, save=True) # It shouldn't show up in the total: eq_(0, l10n_overview_rows('de')['templates']['denominator']) r.is_ready_for_localization = True r.save() eq_(1, l10n_overview_rows('de')['templates']['denominator'])
def test_not_counting_untranslated(self): """Translations with no approved revisions shouldn't count as done. """ translated_revision(is_approved=False, save=True) overview = l10n_overview_rows('de') eq_(0, overview['top-20']['numerator']) eq_(0, overview['top-50']['numerator']) eq_(0, overview['top-100']['numerator']) eq_(0, overview['all']['numerator'])
def test_not_counting_untranslated(self): """Translations with no approved revisions shouldn't count as done. """ TranslatedRevisionFactory(document__locale='de', is_approved=False) overview = l10n_overview_rows('de') eq_(0, overview['top-20']['numerator']) eq_(0, overview['top-50']['numerator']) eq_(0, overview['top-100']['numerator']) eq_(0, overview['all']['numerator'])
def test_not_counting_untranslated(self): """Translations with no approved revisions shouldn't count as done. """ translated_revision(is_approved=False, save=True) overview = l10n_overview_rows("de") eq_(0, overview["top-20"]["numerator"]) eq_(0, overview["top-50"]["numerator"]) eq_(0, overview["top-100"]["numerator"]) eq_(0, overview["all"]["numerator"])
def test_not_counting_untranslated(self): """Translations with no approved revisions shouldn't count as done. """ TranslatedRevisionFactory(document__locale="de", is_approved=False) overview = l10n_overview_rows("de") eq_(0, overview["top-20"]["numerator"]) eq_(0, overview["top-50"]["numerator"]) eq_(0, overview["top-100"]["numerator"]) eq_(0, overview["all"]["numerator"])
def test_redirects_are_ignored(self): """Verify that redirects aren't counted in the overview.""" translated_revision(is_approved=True, save=True) eq_(1, l10n_overview_rows("de")["all"]["numerator"]) # A redirect shouldn't affect any of the tests. revision( document=document(title="A redirect", is_localizable=True, is_template=True, save=True), is_ready_for_localization=True, is_approved=True, content="REDIRECT [[An article]]", save=True, ) overview = l10n_overview_rows("de") eq_(1, overview["all"]["numerator"]) eq_(1, overview["top-20"]["numerator"]) eq_(1, overview["top-50"]["numerator"]) eq_(1, overview["top-100"]["numerator"])
def test_not_counting_how_to_contribute(self): """Articles with the How to contribute category should not be counted. """ t = translated_revision(is_approved=True, save=True) overview = l10n_overview_rows('de') eq_(1, overview['all']['numerator']) eq_(1, overview['top-20']['numerator']) eq_(1, overview['top-50']['numerator']) eq_(1, overview['top-100']['numerator']) # Update the parent with the How To Contribute category d = t.document.parent d.category = HOW_TO_CONTRIBUTE_CATEGORY d.save() overview = l10n_overview_rows('de') eq_(0, overview['all']['numerator']) eq_(0, overview['top-20']['numerator']) eq_(0, overview['top-50']['numerator']) eq_(0, overview['top-100']['numerator'])
def test_counting_unready_parents(self): """Translations with no ready revs don't count in numerator By dint of factoring, this also tests that templates whose parents.... """ parent_rev = RevisionFactory(document__is_localizable=True, is_approved=True, is_ready_for_localization=False) translation = DocumentFactory(parent=parent_rev.document, locale="de", is_localizable=False) RevisionFactory(document=translation, is_approved=True, based_on=parent_rev) eq_(0, l10n_overview_rows("de")["all"]["numerator"])
def test_not_counting_how_to_contribute(self): """Articles with the How to contribute category should not be counted. """ t = TranslatedRevisionFactory(document__locale="de", is_approved=True) overview = l10n_overview_rows("de") eq_(1, overview["all"]["numerator"]) eq_(1, overview["top-20"]["numerator"]) eq_(1, overview["top-50"]["numerator"]) eq_(1, overview["top-100"]["numerator"]) # Update the parent with the How To Contribute category d = t.document.parent d.category = HOW_TO_CONTRIBUTE_CATEGORY d.save() overview = l10n_overview_rows("de") eq_(0, overview["all"]["numerator"]) eq_(0, overview["top-20"]["numerator"]) eq_(0, overview["top-50"]["numerator"]) eq_(0, overview["top-100"]["numerator"])
def test_redirects_are_ignored(self): """Verify that redirects aren't counted in the overview.""" translated_revision(is_approved=True, save=True) eq_(1, l10n_overview_rows('de')['all']['numerator']) # A redirect shouldn't affect any of the tests. revision(document=document(title='A redirect', is_localizable=True, is_template=True, save=True), is_ready_for_localization=True, is_approved=True, content='REDIRECT [[An article]]', save=True) overview = l10n_overview_rows('de') eq_(1, overview['all']['numerator']) eq_(1, overview['top-20']['numerator']) eq_(1, overview['top-50']['numerator']) eq_(1, overview['top-100']['numerator'])
def test_not_counting_templates(self): """Articles in the Templates category should not be counted. """ t = translated_revision(is_approved=True, save=True) overview = l10n_overview_rows("de") eq_(1, overview["all"]["numerator"]) eq_(1, overview["top-20"]["numerator"]) eq_(1, overview["top-50"]["numerator"]) eq_(1, overview["top-100"]["numerator"]) # Update the parent and translation to be a template d = t.document.parent d.title = "Template:Lorem Ipsum Dolor" d.save() t.document.title = "Template:Lorem Ipsum Dolor" t.document.save() overview = l10n_overview_rows("de") eq_(0, overview["all"]["numerator"]) eq_(0, overview["top-20"]["numerator"]) eq_(0, overview["top-50"]["numerator"]) eq_(0, overview["top-100"]["numerator"])
def test_not_counting_templates(self): """Articles in the Templates category should not be counted. """ t = translated_revision(is_approved=True, save=True) overview = l10n_overview_rows('de') eq_(1, overview['all']['numerator']) eq_(1, overview['top-20']['numerator']) eq_(1, overview['top-50']['numerator']) eq_(1, overview['top-100']['numerator']) # Update the parent and translation to be a template d = t.document.parent d.title = 'Template:Lorem Ipsum Dolor' d.save() t.document.title = 'Template:Lorem Ipsum Dolor' t.document.save() overview = l10n_overview_rows('de') eq_(0, overview['all']['numerator']) eq_(0, overview['top-20']['numerator']) eq_(0, overview['top-50']['numerator']) eq_(0, overview['top-100']['numerator'])
def update_l10n_coverage_metrics(): """Calculate and store the l10n metrics for each locale/product. The metrics are: * Percent localized of top 20 articles * Percent localized of all articles """ today = date.today() # Loop through all locales. for locale in settings.SUMO_LANGUAGES: # Skip en-US, it is always 100% localized. if locale == settings.WIKI_DEFAULT_LANGUAGE: continue # Loop through all enabled products, including None (really All). for product in [None] + list(Product.objects.filter(visible=True)): # (Ab)use the l10n_overview_rows helper from the readouts. rows = l10n_overview_rows(locale=locale, product=product) # % of top 20 articles top20 = rows['top-20'] try: percent = 100.0 * float(top20['numerator']) / top20['denominator'] except ZeroDivisionError: percent = 0.0 WikiMetric.objects.create( code=L10N_TOP20_CODE, locale=locale, product=product, date=today, value=percent) # % of all articles all_ = rows['all'] try: percent = 100 * float(all_['numerator']) / all_['denominator'] except ZeroDivisionError: percent = 0.0 WikiMetric.objects.create( code=L10N_ALL_CODE, locale=locale, product=product, date=today, value=percent)
def localization(request): """Render aggregate data about articles in a non-default locale.""" if request.LANGUAGE_CODE == settings.WIKI_DEFAULT_LANGUAGE: return HttpResponseRedirect(reverse('dashboards.contributors')) locales = Locale.objects.filter(locale=request.LANGUAGE_CODE) if locales: permission = user_can_announce(request.user, locales[0]) else: permission = False product = _get_product(request) data = { 'overview_rows': l10n_overview_rows( request.LANGUAGE_CODE, product=product), 'user_can_announce': permission, } return render_readouts(request, L10N_READOUTS, 'localization.html', extra_data=data, product=product)
def test_counting_unready_parents(self): """Translations with no ready revs don't count in numerator By dint of factoring, this also tests that templates whose parents.... """ parent_rev = revision(document=document(is_localizable=True, save=True), is_approved=True, is_ready_for_localization=False, save=True) translation = document(parent=parent_rev.document, locale='de', is_localizable=False, save=True) revision(document=translation, is_approved=True, based_on=parent_rev, save=True) eq_(0, l10n_overview_rows('de')['all']['numerator'])
def localization(request): """Render aggregate data about articles in a non-default locale.""" if request.LANGUAGE_CODE == settings.WIKI_DEFAULT_LANGUAGE: return HttpResponseRedirect(reverse('dashboards.contributors')) locales = Locale.objects.filter(locale=request.LANGUAGE_CODE) if locales: permission = user_can_announce(request.user, locales[0]) else: permission = False product = _get_product(request) data = { 'overview_rows': l10n_overview_rows(request.LANGUAGE_CODE, product=product), 'user_can_announce': permission, } return render_readouts(request, L10N_READOUTS, 'localization.html', extra_data=data, product=product)
def handle(self, **options): """ The metrics are: * Percent localized of top 20 articles * Percent localized of all articles """ today = date.today() # Loop through all locales. for locale in settings.SUMO_LANGUAGES: # Skip en-US, it is always 100% localized. if locale == settings.WIKI_DEFAULT_LANGUAGE: continue # Loop through all enabled products, including None (really All). for product in [None] + list(Product.objects.filter(visible=True)): # (Ab)use the l10n_overview_rows helper from the readouts. rows = l10n_overview_rows(locale=locale, product=product) # % of top 20 articles top20 = rows['top-20'] try: percent = 100.0 * float(top20['numerator']) / top20['denominator'] except ZeroDivisionError: percent = 0.0 WikiMetric.objects.create( code=L10N_TOP20_CODE, locale=locale, product=product, date=today, value=percent) # % of top 100 articles top100 = rows['top-100'] try: percent = 100.0 * float(top100['numerator']) / top100['denominator'] except ZeroDivisionError: percent = 0.0 WikiMetric.objects.create( code=L10N_TOP100_CODE, locale=locale, product=product, date=today, value=percent) # % of all articles all_ = rows['all'] try: percent = 100 * float(all_['numerator']) / all_['denominator'] except ZeroDivisionError: percent = 0.0 WikiMetric.objects.create( code=L10N_ALL_CODE, locale=locale, product=product, date=today, value=percent)