def status(ctx, showuntranslated, showfuzzy, path): """Show status of a .po file.""" out('dennis version {version}'.format(version=__version__)) po_files = [] for item in path: if os.path.isdir(item): for root, dirs, files in os.walk(item): po_files.extend( [os.path.join(root, fn) for fn in files if fn.endswith('.po')]) else: po_files.append(item) po_files = [os.path.abspath(fn) for fn in po_files if fn.endswith('.po')] for fn in po_files: try: if not os.path.exists(fn): raise IOError('File "{fn}" does not exist.'.format( fn=click.format_filename(fn))) pofile = parse_pofile(fn) except IOError as ioe: err('>>> Problem opening file: {fn}'.format( fn=click.format_filename(fn))) err(repr(ioe)) continue out('') out(TERM.bold_green, '>>> Working on: {fn}'.format(fn=click.format_filename(fn)), TERM.normal) out('Metadata:') for key in ('Language', 'Report-Msgid-Bugs-To', 'PO-Revision-Date', 'Last-Translator', 'Language-Team', 'Plural-Forms'): if key in pofile.metadata and pofile.metadata[key]: out(' ', key, ': ', pofile.metadata[key]) out('') if showuntranslated: out('Untranslated strings:') out('') for poentry in pofile.untranslated_entries(): out(withlines(poentry.linenum, poentry.original)) out('') if showfuzzy: out('Fuzzy strings:') out('') for poentry in pofile.fuzzy_entries(): out(withlines(poentry.linenum, poentry.original)) out('') total_words = 0 translated_words = 0 untranslated_words = 0 for entry in pofile.translated_entries() + pofile.untranslated_entries(): if not entry.translated(): untranslated_words += len(entry.msgid.split()) else: translated_words += len(entry.msgid.split()) total_words += len(entry.msgid.split()) total_strings = len(pofile) translated_total = len(pofile.translated_entries()) fuzzy_total = len(pofile.fuzzy_entries()) untranslated_total = len(pofile.untranslated_entries()) out('Statistics:') out(' Total strings: {}'.format(total_strings)) out(' Translated: {}'.format(translated_total)) out(' Untranslated: {}'.format(untranslated_total)) out(' Fuzzy: {}'.format(fuzzy_total)) out(' Total translateable words: {}'.format(total_words)) out(' Translated: {}'.format(translated_words)) out(' Untranslated: {}'.format(untranslated_words)) if untranslated_words == 0: out(' Percentage: 100% COMPLETE!') else: out(' Percentage: {}%'.format( pofile.percent_translated())) ctx.exit(0)
def lint(ctx, quiet, color, varformat, rules, excluderules, reporter, errorsonly, path): """ Lints .po/.pot files for issues You can ignore rules on a string-by-string basis by adding an extracted comment "dennis-ignore: <comma-separated-rules>". See documentation for details. """ global TERM if not quiet: out('dennis version {version}'.format(version=__version__)) if not color: TERM = FauxTerminal() # Make sure requested rules are valid all_rules = get_linter_rules(with_names=True) all_rules.update(get_template_linter_rules(with_names=True)) rules = [rule.strip() for rule in rules.split(',') if rule.strip()] invalid_rules = [rule for rule in rules if rule not in all_rules] if invalid_rules: raise click.UsageError('invalid rules: %s.' % ', '.join(invalid_rules)) if not rules: rules = get_linter_rules() rules.update(get_template_linter_rules()) rules = rules.keys() if excluderules: excludes = [rule.strip() for rule in excluderules.split(',') if rule.strip()] invalid_rules = [rule for rule in excludes if rule not in all_rules] if invalid_rules: raise click.UsageError('invalid exclude rules: %s.' % ', '.join(invalid_rules)) # Remove excluded rules rules = [rule for rule in rules if rule not in excludes] # Build linters and lint linter = Linter(varformat.split(','), rules) templatelinter = TemplateLinter(varformat.split(','), rules) po_files = [] for item in path: if os.path.isdir(item): for root, dirs, files in os.walk(item): po_files.extend( [os.path.join(root, fn) for fn in files if fn.endswith(('.po', '.pot'))]) else: po_files.append(item) po_files = [os.path.abspath(fn) for fn in po_files if fn.endswith(('.po', '.pot'))] if not po_files: raise click.UsageError('nothing to work on. Use --help for help.') files_to_errors = {} total_error_count = 0 total_warning_count = 0 total_files_with_errors = 0 for fn in po_files: try: if not os.path.exists(fn): raise click.UsageError('File "{fn}" does not exist.'.format( fn=click.format_filename(fn))) if fn.endswith('.po'): results = linter.verify_file(fn) else: results = templatelinter.verify_file(fn) except IOError as ioe: # This is not a valid .po file. So mark it as an error. err('>>> Problem opening file: {fn}'.format( fn=click.format_filename(fn))) err(repr(ioe)) out('') # FIXME - should we track this separately as an invalid # file? files_to_errors[fn] = (1, 0) total_error_count += 1 continue if errorsonly: # Go through and nix all the non-error LintMessages results = [res for res in results if res.kind == 'err'] # We don't want to print output for files that are fine, so we # update the bookkeeping and move on. if not results: files_to_errors[fn] = (0, 0) continue if not quiet and not reporter: out(TERM.bold_green, '>>> Working on: {fn}'.format(fn=click.format_filename(fn)), TERM.normal) error_results = [res for res in results if res.kind == 'err'] warning_results = [res for res in results if res.kind == 'warn'] error_count = len(error_results) total_error_count += error_count warning_count = len(warning_results) total_warning_count += warning_count if not quiet: for msg in error_results: if reporter == 'line': out(fn, ':', str(msg.poentry.linenum), ':', '0', ':', msg.code, ':', msg.msg) else: out(TERM.bold_red, msg.code, ': ', msg.msg, TERM.normal) out(withlines(msg.poentry.linenum, msg.poentry.original)) out('') if not quiet and not errorsonly: for msg in warning_results: if reporter == 'line': out(fn, ':', str(msg.poentry.linenum), ':', '0', ':', msg.code, ':', msg.msg) else: out(TERM.bold_yellow, msg.code, ': ', msg.msg, TERM.normal) out(withlines(msg.poentry.linenum, msg.poentry.original)) out('') files_to_errors[fn] = (error_count, warning_count) if error_count > 0: total_files_with_errors += 1 if not quiet and reporter != 'line': out('Totals') if not errorsonly: out(' Warnings: {warnings:5}'.format(warnings=warning_count)) out(' Errors: {errors:5}\n'.format(errors=error_count)) if len(po_files) > 1 and not quiet and reporter != 'line': out('Final totals') out(' Number of files examined: {count:5}'.format( count=len(po_files))) out(' Total number of files with errors: {count:5}'.format( count=total_files_with_errors)) if not errorsonly: out(' Total number of warnings: {count:5}'.format( count=total_warning_count)) out(' Total number of errors: {count:5}'.format( count=total_error_count)) out('') file_counts = [ (counts[0], counts[1], fn.split(os.sep)[-3], fn.split(os.sep)[-1]) for (fn, counts) in files_to_errors.items() ] # If we're showing errors only, then don't talk about warnings. if errorsonly: header = 'Errors Filename' line = ' {errors:5} {locale} ({fn})' else: header = 'Warnings Errors Filename' line = ' {warnings:5} {errors:5} {locale} ({fn})' file_counts = list(reversed(sorted(file_counts))) printed_header = False for error_count, warning_count, locale, fn in file_counts: if not error_count and not warning_count: continue if not printed_header: out(header) printed_header = True out(line.format( warnings=warning_count, errors=error_count, fn=fn, locale=locale)) # Return 0 if everything was fine or 1 if there were errors. ctx.exit(code=1 if total_error_count else 0)
def status(ctx, showuntranslated, showfuzzy, path): """Show status of a .po file.""" out("dennis version {version}".format(version=__version__)) po_files = [] for item in path: if os.path.isdir(item): for root, dirs, files in os.walk(item): po_files.extend([ os.path.join(root, fn) for fn in files if fn.endswith(".po") ]) else: po_files.append(item) po_files = [os.path.abspath(fn) for fn in po_files if fn.endswith(".po")] for fn in po_files: try: if not os.path.exists(fn): raise IOError('File "{fn}" does not exist.'.format( fn=click.format_filename(fn))) pofile = parse_pofile(fn) except IOError as ioe: err(">>> Problem opening file: {fn}".format( fn=click.format_filename(fn))) err(repr(ioe)) continue out("") out( TERM.bold_green, ">>> Working on: {fn}".format(fn=click.format_filename(fn)), TERM.normal, ) out("Metadata:") for key in ( "Language", "Report-Msgid-Bugs-To", "PO-Revision-Date", "Last-Translator", "Language-Team", "Plural-Forms", ): if key in pofile.metadata and pofile.metadata[key]: out(" ", key, ": ", pofile.metadata[key]) out("") if showuntranslated: out("Untranslated strings:") out("") for poentry in pofile.untranslated_entries(): out(withlines(poentry.linenum, poentry.original)) out("") if showfuzzy: out("Fuzzy strings:") out("") for poentry in pofile.fuzzy_entries(): out(withlines(poentry.linenum, poentry.original)) out("") total_words = 0 translated_words = 0 untranslated_words = 0 for entry in pofile.translated_entries() + pofile.untranslated_entries( ): if not entry.translated(): untranslated_words += len(entry.msgid.split()) else: translated_words += len(entry.msgid.split()) total_words += len(entry.msgid.split()) total_strings = len(pofile) translated_total = len(pofile.translated_entries()) fuzzy_total = len(pofile.fuzzy_entries()) untranslated_total = len(pofile.untranslated_entries()) out("Statistics:") out(" Total strings: {}".format(total_strings)) out(" Translated: {}".format(translated_total)) out(" Untranslated: {}".format(untranslated_total)) out(" Fuzzy: {}".format(fuzzy_total)) out(" Total translateable words: {}".format(total_words)) out(" Translated: {}".format(translated_words)) out(" Untranslated: {}".format(untranslated_words)) if untranslated_words == 0: out(" Percentage: 100% COMPLETE!") else: out(" Percentage: {}%".format( pofile.percent_translated())) ctx.exit(0)
def lint(ctx, quiet, color, varformat, rules, excluderules, reporter, errorsonly, path): """ Lints .po/.pot files for issues You can ignore rules on a string-by-string basis by adding an extracted comment "dennis-ignore: <comma-separated-rules>". See documentation for details. """ global TERM if not quiet: out("dennis version {version}".format(version=__version__)) if not color: TERM = FauxTerminal() # Make sure requested rules are valid all_rules = get_linter_rules(with_names=True) all_rules.update(get_template_linter_rules(with_names=True)) rules = [rule.strip() for rule in rules.split(",") if rule.strip()] invalid_rules = [rule for rule in rules if rule not in all_rules] if invalid_rules: raise click.UsageError("invalid rules: %s." % ", ".join(invalid_rules)) if not rules: rules = get_linter_rules() rules.update(get_template_linter_rules()) rules = rules.keys() if excluderules: excludes = [ rule.strip() for rule in excluderules.split(",") if rule.strip() ] invalid_rules = [rule for rule in excludes if rule not in all_rules] if invalid_rules: raise click.UsageError("invalid exclude rules: %s." % ", ".join(invalid_rules)) # Remove excluded rules rules = [rule for rule in rules if rule not in excludes] # Build linters and lint linter = Linter(varformat.split(","), rules) templatelinter = TemplateLinter(varformat.split(","), rules) po_files = [] for item in path: if os.path.isdir(item): for root, dirs, files in os.walk(item): po_files.extend([ os.path.join(root, fn) for fn in files if fn.endswith((".po", ".pot")) ]) else: po_files.append(item) po_files = [ os.path.abspath(fn) for fn in po_files if fn.endswith((".po", ".pot")) ] if not po_files: raise click.UsageError("nothing to work on. Use --help for help.") files_to_errors = {} total_error_count = 0 total_warning_count = 0 total_files_with_errors = 0 for fn in po_files: try: if not os.path.exists(fn): raise click.UsageError('File "{fn}" does not exist.'.format( fn=click.format_filename(fn))) if fn.endswith(".po"): results = linter.verify_file(fn) else: results = templatelinter.verify_file(fn) except IOError as ioe: # This is not a valid .po file. So mark it as an error. err(">>> Problem opening file: {fn}".format( fn=click.format_filename(fn))) err(repr(ioe)) out("") # FIXME - should we track this separately as an invalid # file? files_to_errors[fn] = (1, 0) total_error_count += 1 continue if errorsonly: # Go through and nix all the non-error LintMessages results = [res for res in results if res.kind == "err"] # We don't want to print output for files that are fine, so we # update the bookkeeping and move on. if not results: files_to_errors[fn] = (0, 0) continue if not quiet and not reporter: out( TERM.bold_green, ">>> Working on: {fn}".format(fn=click.format_filename(fn)), TERM.normal, ) error_results = [res for res in results if res.kind == "err"] warning_results = [res for res in results if res.kind == "warn"] error_count = len(error_results) total_error_count += error_count warning_count = len(warning_results) total_warning_count += warning_count if not quiet: for msg in error_results: if reporter == "line": out( fn, ":", str(msg.poentry.linenum), ":", "0", ":", msg.code, ":", msg.msg, ) else: out(TERM.bold_red, msg.code, ": ", msg.msg, TERM.normal) out(withlines(msg.poentry.linenum, msg.poentry.original)) out("") if not quiet and not errorsonly: for msg in warning_results: if reporter == "line": out( fn, ":", str(msg.poentry.linenum), ":", "0", ":", msg.code, ":", msg.msg, ) else: out(TERM.bold_yellow, msg.code, ": ", msg.msg, TERM.normal) out(withlines(msg.poentry.linenum, msg.poentry.original)) out("") files_to_errors[fn] = (error_count, warning_count) if error_count > 0: total_files_with_errors += 1 if not quiet and reporter != "line": out("Totals") if not errorsonly: out(" Warnings: {warnings:5}".format(warnings=warning_count)) out(" Errors: {errors:5}\n".format(errors=error_count)) if len(po_files) > 1 and not quiet and reporter != "line": out("Final totals") out(" Number of files examined: {count:5}".format( count=len(po_files))) out(" Total number of files with errors: {count:5}".format( count=total_files_with_errors)) if not errorsonly: out(" Total number of warnings: {count:5}".format( count=total_warning_count)) out(" Total number of errors: {count:5}".format( count=total_error_count)) out("") file_counts = [(counts[0], counts[1], fn.split(os.sep)[-3], fn.split(os.sep)[-1]) for (fn, counts) in files_to_errors.items()] # If we're showing errors only, then don't talk about warnings. if errorsonly: header = "Errors Filename" line = " {errors:5} {locale} ({fn})" else: header = "Warnings Errors Filename" line = " {warnings:5} {errors:5} {locale} ({fn})" file_counts = list(reversed(sorted(file_counts))) printed_header = False for error_count, warning_count, locale, fn in file_counts: if not error_count and not warning_count: continue if not printed_header: out(header) printed_header = True out( line.format(warnings=warning_count, errors=error_count, fn=fn, locale=locale)) # Return 0 if everything was fine or 1 if there were errors. ctx.exit(code=1 if total_error_count else 0)
def status(ctx, showuntranslated, path): """Show status of a .po file.""" out('dennis version {version}'.format(version=__version__)) po_files = [] for item in path: if os.path.isdir(item): for root, dirs, files in os.walk(item): po_files.extend( [os.path.join(root, fn) for fn in files if fn.endswith('.po')]) else: po_files.append(item) po_files = [os.path.abspath(fn) for fn in po_files if fn.endswith('.po')] for fn in po_files: try: if not os.path.exists(fn): raise IOError('File "{fn}" does not exist.'.format(fn=fn)) pofile = parse_pofile(fn) except IOError as ioe: err('>>> Problem opening file: {fn}'.format(fn=fn)) err(repr(ioe)) continue out('') out(TERM.bold_green, '>>> Working on: {fn}'.format(fn=fn), TERM.normal) out('Metadata:') for key in ('Language', 'Report-Msgid-Bugs-To', 'PO-Revision-Date', 'Last-Translator', 'Language-Team', 'Plural-Forms'): if key in pofile.metadata and pofile.metadata[key]: out(' ', key, ': ', pofile.metadata[key]) out('') if showuntranslated: out('Untranslated strings:') out('') for poentry in pofile.untranslated_entries(): out(withlines(poentry.linenum, poentry.original)) out('') total_words = 0 translated_words = 0 untranslated_words = 0 for entry in pofile.translated_entries() + pofile.untranslated_entries(): if not entry.translated(): untranslated_words += len(entry.msgid.split()) else: translated_words += len(entry.msgid.split()) total_words += len(entry.msgid.split()) total_strings = len(pofile) translated_total = len(pofile.translated_entries()) fuzzy_total = len(pofile.fuzzy_entries()) untranslated_total = len(pofile.untranslated_entries()) out('Statistics:') out(' Total strings: {0}'.format(total_strings)) out(' Translated: {0}'.format(translated_total)) out(' Untranslated: {0}'.format(untranslated_total)) out(' Fuzzy: {0}'.format(fuzzy_total)) out(' Total translateable words: {0}'.format(total_words)) out(' Translated: {0}'.format(translated_words)) out(' Untranslated: {0}'.format(untranslated_words)) if untranslated_words == 0: out(' Percentage: 100% COMPLETE!') else: out(' Percentage: {0}%'.format( pofile.percent_translated())) ctx.exit(0)
def lint(ctx, quiet, color, varformat, rules, reporter, errorsonly, path): """ Lints .po/.pot files for issues You can ignore rules on a string-by-string basis by adding an extracted comment "dennis-ignore: <comma-separated-rules>". See documentation for details. """ global TERM if not quiet: out('dennis version {version}'.format(version=__version__)) if not color: TERM = FauxTerminal() linter = Linter(varformat.split(','), rules.split(',')) templatelinter = TemplateLinter(varformat.split(','), rules.split(',')) po_files = [] for item in path: if os.path.isdir(item): for root, dirs, files in os.walk(item): po_files.extend( [os.path.join(root, fn) for fn in files if fn.endswith(('.po', '.pot'))]) else: po_files.append(item) po_files = [os.path.abspath(fn) for fn in po_files if fn.endswith(('.po', '.pot'))] if not po_files: err('Nothing to work on. Use --help for help.') ctx.exit(1) files_to_errors = {} total_error_count = 0 total_warning_count = 0 total_files_with_errors = 0 for fn in po_files: try: if not os.path.exists(fn): raise IOError('File "{fn}" does not exist.'.format(fn=fn)) if fn.endswith('.po'): results = linter.verify_file(fn) else: results = templatelinter.verify_file(fn) except IOError as ioe: # This is not a valid .po file. So mark it as an error. err('>>> Problem opening file: {fn}'.format(fn=fn)) err(repr(ioe)) out('') # FIXME - should we track this separately as an invalid # file? files_to_errors[fn] = (1, 0) total_error_count += 1 continue if errorsonly: # Go through and nix all the non-error LintMessages results = [res for res in results if res.kind == 'err'] # We don't want to print output for files that are fine, so we # update the bookkeeping and move on. if not results: files_to_errors[fn] = (0, 0) continue if not quiet and not reporter: out(TERM.bold_green, '>>> Working on: {fn}'.format(fn=fn), TERM.normal) error_results = [res for res in results if res.kind == 'err'] warning_results = [res for res in results if res.kind == 'warn'] error_count = len(error_results) total_error_count += error_count warning_count = len(warning_results) total_warning_count += warning_count if not quiet: for msg in error_results: if reporter == 'line': out(fn, ':', textclass(msg.poentry.linenum), ':', '0', ':', msg.code, ':', msg.msg) else: out(TERM.bold_red, msg.code, ': ', msg.msg, TERM.normal) out(withlines(msg.poentry.linenum, msg.poentry.original)) out('') if not quiet and not errorsonly: for msg in warning_results: if reporter == 'line': out(fn, ':', textclass(msg.poentry.linenum), ':', '0', ':', msg.code, ':', msg.msg) else: out(TERM.bold_yellow, msg.code, ': ', msg.msg, TERM.normal) out(withlines(msg.poentry.linenum, msg.poentry.original)) out('') files_to_errors[fn] = (error_count, warning_count) if error_count > 0: total_files_with_errors += 1 if not quiet and reporter != 'line': out('Totals') if not errorsonly: out(' Warnings: {warnings:5}'.format(warnings=warning_count)) out(' Errors: {errors:5}\n'.format(errors=error_count)) if len(po_files) > 1 and not quiet and reporter != 'line': out('Final totals') out(' Number of files examined: {count:5}'.format( count=len(po_files))) out(' Total number of files with errors: {count:5}'.format( count=total_files_with_errors)) if not errorsonly: out(' Total number of warnings: {count:5}'.format( count=total_warning_count)) out(' Total number of errors: {count:5}'.format( count=total_error_count)) out('') file_counts = [ (counts[0], counts[1], fn.split(os.sep)[-3], fn.split(os.sep)[-1]) for (fn, counts) in files_to_errors.items() ] # If we're showing errors only, then don't talk about warnings. if errorsonly: header = 'Errors Filename' line = ' {errors:5} {locale} ({fn})' else: header = 'Warnings Errors Filename' line = ' {warnings:5} {errors:5} {locale} ({fn})' file_counts = list(reversed(sorted(file_counts))) printed_header = False for error_count, warning_count, locale, fn in file_counts: if not error_count and not warning_count: continue if not printed_header: out(header) printed_header = True out(line.format( warnings=warning_count, errors=error_count, fn=fn, locale=locale)) # Return 0 if everything was fine or 1 if there were errors. ctx.exit(code=1 if total_error_count else 0)