diff --git a/README.md b/README.md index e73aa0e..c2b1250 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,83 @@ # message_lint -`message_lint` checks each message for localizability (L12y) issues. - -## What it looks for - -| `message_lint` checks each message if it... | L12y Issues | -|-----------------------------------------------------------------|--------------------------------| -| begins with `,` or `.` | Text Fragments | -| begins with one of the following: `and` `or` | | -| ends with `,` | | -| ends with one of the following: `the` `to` `by` `on` `and` `or` | | -| | | -| contains `{placeholder}` preceded by | Articles before placeholders | -| `a` `an` `a(n)` or `the` | | -| | | -| contains `{placeholder}%` `{0}%` | Percentage Formatting | -| | | -| contains one of the following: `http://` `https://` | URIs/URLs embedded in messages | -| `...` | | -| | | -| contains `{placeholder}` followed by: | Lack of Pluralization | -| `year` `month` `week` `day` | | -| `hour` `min` `sec` | | -| `groups` `issues` `users` `people` `other` `boards` `spaces` | | -| | | -| contains placeholder that uses a number `{[0-9]+}` | Non-named placeholders | -| | | -| contains any of following: | use of ASCII Punctuation Chars | -| `'` apostrophe (U+0027) | | -| `"` double quote (U+0022) | | -| `...` 3 periods (U+002E) | | - -## Install dependencies +`message_lint` is for software developers or product localization managers who want to +find out if their product source content contains any localizability (L12y) issues +before it goes for localization. + + +This command line tool can read in: +* `react-intl` message resource (JSON) and +* Java properties files + +## A bird eye's view of `message_lint` + +![Alt text here](images/message_lint_diagram.svg) + +## What common L12y issues does `message_lint` look for? + +| L12y Issue | How to resolve | +|--------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------| +| text fragments | each message should be a complete sentence/phrase | +| articles before placeholders | the value that goes into the placeholder should include the article | +| percentage formatting | the value that goes into the placeholder should include the percent sign either prefixed or suffixed | +| embedded URLs/URIs -- this is really not part of the user-facing content. Updating a URL should not trigger a localization workflow. | the URLs/URLs should be external to the messages. They come into the message through the placeholders. | +| inadequate plural nouns | use the ICU message format to support multiple plural noun forms | +| use of ASCII punctuation | replace apostrophe with Unicode Right Single Quotation (U+2019) | +| | replace double quotation with Unicode Left and Right Double Quotation (U+201C, U+201D ) | +| | replace ellipses "..." with Unicode Ellipses (U+2026) | + +## How does it find these issues? + +`message_lint` uses regular expressions (regex) to find these issues. + +| `message_lint` checks each message if it... | L12y Issues | +|-----------------------------------------------------------------|----------------------------------------------| +| begins with `,` or `.` | Text Fragments | +| begins with one of the following: `and` `or` | | +| ends with `,` | | +| ends with one of the following: `the` `to` `by` `on` `and` `or` | | +| | | +| contains `{placeholder}` preceded by | Articles before placeholders | +| `a` `an` `a(n)` or `the` | | +| | | +| contains `{placeholder}%` `{0}%` | Percentage Formatting | +| | | +| contains one of the following: `http://` `https://` | URIs/URLs embedded in messages | +| `...` | | +| | | +| contains `{placeholder}` followed by: | Inadequate support for multiple plural nouns | +| `year` `month` `week` `day` | | +| `hour` `min` `sec` | | +| `groups` `issues` `users` `people` `other` `boards` `spaces` | | +| | | +| contains placeholder that uses a number `{[0-9]+}` | Non-named placeholders | +| | | +| contains any of following: | use of ASCII Punctuation Chars | +| `'` apostrophe (U+0027) | | +| `"` double quote (U+0022) | | +| `...` 3 periods (U+002E) | | + + +## Why you should check your source content? + +Checking your source content for L12y issues will save time and money if you do it early +in the product development life cycle (PDLC). + +Localization specialists will be grateful too :smile: + +## Getting Started + +### Install dependencies + +Run the following at the command line: + % `cd message_lint` % `pip install -r requirements.txt` -## First, do this +### First, take a look at the command line help for `message_lint` -% `message-lint/bin/message_lint --help` +*message_lint %* `bin/message_lint --help` ``` usage: message_lint [-h] [-o OUTPUT_FOLDER] [-v] files [files ...] @@ -59,20 +98,40 @@ Thanks for using message_lint! % ``` -## Now try your files +### Now try out the test files we provided You must pass JSON message files and Java (message) Properties files to `message_lint`. -The lint reports for `test.json` will be located in the same directory under `message_lint_reports` +By default, the lint reports will be generated and located in the same directory +as the test_files under `message_lint_reports`. + +The lint reports will only be generated in `.json` format. + +Here are some example command lines you can try out: + +#### Example 1.1 + +When you run the following command line, `message_lint` will examine each message in `test_files\test.json` +and generate a report of localizability issues if any. By default, the lint reports will be generated and located in +the same directory as the `test_files` but in `message_lint_reports` + +*message_lint %* `bin/message_lint test_files\test.json` + +#### Example 1.2 + +You can also pass it more than one file. + +*message_lint %* `bin/message_lint test_files\test.json test_files\test.properties` + +A lint report will be generated for each message resource file. -Here are some example command lines: +#### Example 2 -% `message_lint/bin/message_lint test.json test.properties` +You can specify a custom output folder where the lint reports will go. -You can also pass it an output folder where the lint reports will go. The lint reports for this next command will -located in `output\message_lint_reports` +*message_lint %* `bin/message_lint test.json test.properties --output_folder ..\output` -% `message-lint/bin/message_lint test.json test.properties --output_folder ..\output` +The lint reports for this next command will located in `output\message_lint_reports` ---- \ No newline at end of file +--- diff --git a/bin/message_lint b/bin/message_lint index aa669d2..afe1644 100644 --- a/bin/message_lint +++ b/bin/message_lint @@ -3,52 +3,11 @@ import os import sys import argparse -import pathlib fpath = os.path.join(os.path.dirname(__file__), '..') sys.path.append(fpath) -import utils - - -def build_file_path(filename, target_path, extra_folder=None) -> str: - """ build a file_path """ - file_path = os.path.abspath(filename) - p = pathlib.Path(file_path) - src_path = p.parents[0] - filename = p.name - print(src_path, filename) - - if target_path is None: - target_path = src_path - else: - target_path = os.path.abspath(target_path) - - if extra_folder is not None: - target_path = os.path.join(target_path, extra_folder, filename) - print("path of target folder:", target_path) - - os.makedirs(target_path, exist_ok=True) - file_path = os.path.join(target_path, filename) - print("path of target file:", file_path) - - return file_path - - -def main(args): - print(args.files) - print(args.output_folder) - - for file in args.files: - reader = utils.FileReader.get(file) - - # build file path for the output folder - file_path = build_file_path(file, args.output_folder, extra_folder="message_lint_reports") - - writer = utils.FileWriter.get(file_path) - - utils.FileProcessor(reader, writer).execute() - +import message_lint if __name__ == "__main__": parser = argparse.ArgumentParser( @@ -65,7 +24,10 @@ if __name__ == "__main__": parser.add_argument( "-v", "--version", action="version", - version="%(prog)s 0.1.0") - + version="%(prog)s {version}".format(version=message_lint.__version__)) + parser.add_argument( + "--verbose", + action="store_true", + required=False) arguments = parser.parse_args(args=None if sys.argv[1:] else ["--help"]) - main(arguments) + message_lint.main(arguments) diff --git a/images/message_lint_diagram.svg b/images/message_lint_diagram.svg new file mode 100644 index 0000000..d4c8757 --- /dev/null +++ b/images/message_lint_diagram.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/message_lint/__init__.py b/message_lint/__init__.py new file mode 100644 index 0000000..cd63ff0 --- /dev/null +++ b/message_lint/__init__.py @@ -0,0 +1,3 @@ +from message_lint.main import main + +__version__ = "0.1.1" diff --git a/message_lint/fileprocessor.py b/message_lint/fileprocessor.py new file mode 100644 index 0000000..284a13d --- /dev/null +++ b/message_lint/fileprocessor.py @@ -0,0 +1,56 @@ +from .linter import lint +from pprint import PrettyPrinter + +pp = PrettyPrinter( + indent=2, + width=100, + compact=True +) + + +class FileProcessor: + def __init__(self, reader, writer, logger): + self.reader = reader + self.writer = writer + self.logger = logger + self.content = {} + + def execute(self) -> dict: + try: + self.content = self.reader.read() + # pp.pprint(self.content) + except FileNotFoundError: + print("Error: File Not Found: {0}".format(self.reader.filename)) + return {} + + # lookup-table that maps a message to its findings + findings = {} + for message_id, message in self.content.items(): + if message is None: + continue + + self.logger.log_info("Processing...\"{0}\": \"{1}\"".format(message_id, message)) + + if type(message) is dict and message['message'] is not None: + message = message['message'] + elif type(message) is not str: + continue + else: # type(message) is str + pass + + findings[message_id] = { + "message": message, + "linted": [] + } + + found_something = lint(message) + + if len(found_something): + print(">>> '{0}': \"{1}\"".format(message_id, message)) + for something in found_something: + findings[message_id]["linted"].append(something['desc']) + print(">>> {0}".format(something['desc'])) + print('~' * 10) + self.writer.write(findings) + return findings + diff --git a/message_lint/linter/__init__.py b/message_lint/linter/__init__.py new file mode 100644 index 0000000..6b6ce29 --- /dev/null +++ b/message_lint/linter/__init__.py @@ -0,0 +1 @@ +from message_lint.linter.str_lint import lint diff --git a/utils/lint_rules.json b/message_lint/linter/lint_rules.json similarity index 58% rename from utils/lint_rules.json rename to message_lint/linter/lint_rules.json index 4c3ba96..c0647f3 100644 --- a/utils/lint_rules.json +++ b/message_lint/linter/lint_rules.json @@ -3,7 +3,6 @@ "regexp": [ "([\\s]{2,})" ], - "outputFile": "extraneous_spaces", "desc": "Extraneous Spaces detected" }, { @@ -12,40 +11,36 @@ "(\\,)$", "^\\s*(and|or)\\b", "\\b(the|to|by|on|or|and)\\b$", - "^{\\w+}$" + "^{\\w*\\}$" ], - "outputFile": "fragments", "desc": "Sentence Fragments" }, { "regexp": [ - "(the\\b\\{\\w+\\})", - "(a\\b\\{\\w+\\})", - "(an\\b\\{\\w+\\})", - "(a\\(n\\)\\b\\{\\w+\\})" + "(the\\s*\\{\\w*\\})", + "(a\\s*\\{\\w*\\})", + "(an\\s*\\{\\w*\\})", + "(a\\(n\\)\\s*\\{\\w*\\})" ], - "outputFile": "articles", - "desc": "definite and indefinite articles" + "desc": "definite and indefinite articles before placeholders" }, { "regexp": [ - "(\\{\\w+\\}\\s*%)" + "(\\{\\w*\\}\\s*%)" ], - "outputFile": "percentage", "desc": "percentage format" }, { "regexp": [ "\\'\\{\\'" ], - "outputFile": "placeholder_quotations", "desc": "Incorrect placeholder quoting." }, { "regexp": [ - "\\{\\w+\\}\\s*(year|month|week|day|hour|min|sec|groups|issues|users|people|other|boards|spaces)" + "\\{\\w+\\}\\s*(year|month|week|day|hour|min|sec)", + "\\{\\w+\\}\\s*(groups|issues|users|people|other|boards|spaces)" ], - "outputFile": "plural_nouns", "desc": "Plural Nouns" }, { @@ -53,7 +48,6 @@ "(http|https)://", "(\\s*.*<\\/a>)" ], - "outputFile": "url_uri", "desc": "String Resource contains URIs/URLs" }, { @@ -61,14 +55,12 @@ "\\{\\d+\\}", "\\{\\s*\\}" ], - "outputFile": "numbered_placeholders", - "desc": "String Resource contains numbered placeholders like \u2019{0}\u2019. Please use variable names in placeholders. " + "desc": "Message contains numbered placeholders like \u2019{0}\u2019. Please use variable names in placeholders. " }, { "regexp": [ "\\{\\s*\\d\\s*,\\s*choice.+\\}" ], - "outputFile": "choice_formatted", "desc": "Find string resources using the choice format" }, { @@ -77,7 +69,12 @@ "\\\"", "[\\.]{3}" ], - "outputFile": "ascii_punct", "desc": "ASCII punctuation in use. Best Practice is to use their Unicode equivalents." + }, + { + "regexp": [ + "^\\s*$" + ], + "desc": "empty string" } ] \ No newline at end of file diff --git a/utils/lint_rules.py b/message_lint/linter/lint_rules.py similarity index 100% rename from utils/lint_rules.py rename to message_lint/linter/lint_rules.py diff --git a/utils/mk_lint_rules b/message_lint/linter/mk_lint_rules similarity index 59% rename from utils/mk_lint_rules rename to message_lint/linter/mk_lint_rules index b65746e..2d0f519 100644 --- a/utils/mk_lint_rules +++ b/message_lint/linter/mk_lint_rules @@ -7,55 +7,50 @@ import json rules = [ { "regexp": [r"([\s]{2,})"], - "outputFile": "extraneous_spaces", "desc": "Extraneous Spaces detected" }, { - "regexp": [r"^(\,)", r"(\,)$", r"^\s*(and|or)\b", r"\b(the|to|by|on|or|and)\b$", r"^{\w+}$"], - "outputFile": "fragments", + "regexp": [r"^(\,)", r"(\,)$", r"^\s*(and|or)\b", r"\b(the|to|by|on|or|and)\b$", r"^{\w*\}$"], "desc": "Sentence Fragments" }, { - "regexp": [r"(the\b\{\w+\})", r"(a\b\{\w+\})", r"(an\b\{\w+\})", r"(a\(n\)\b\{\w+\})"], - "outputFile": "articles", - "desc": "definite and indefinite articles" + "regexp": [r"(the\s*\{\w*\})", r"(a\s*\{\w*\})", r"(an\s*\{\w*\})", r"(a\(n\)\s*\{\w*\})"], + "desc": "definite and indefinite articles before placeholders" }, { - "regexp": [r"(\{\w+\}\s*%)"], - "outputFile": "percentage", + "regexp": [r"(\{\w*\}\s*%)"], "desc": "percentage format" }, { "regexp": [r"\'\{\'"], - "outputFile": "placeholder_quotations", "desc": "Incorrect placeholder quoting." }, { - "regexp": [r"\{\w+\}\s*(year|month|week|day|hour|min|sec|groups|issues|users|people|other|boards|spaces)"], - "outputFile": "plural_nouns", + "regexp": [r"\{\w+\}\s*(year|month|week|day|hour|min|sec)", + r"\{\w+\}\s*(groups|issues|users|people|other|boards|spaces)"], "desc": "Plural Nouns" }, { "regexp": [r"(http|https)://", r"(\s*.*<\/a>)"], - "outputFile": "url_uri", "desc": "String Resource contains URIs/URLs" }, { "regexp": [r"\{\d+\}", r"\{\s*\}"], - "outputFile": "numbered_placeholders", - "desc": "String Resource contains numbered placeholders like \u2019{0}\u2019. Please use variable names in " + "desc": "Message contains numbered placeholders like \u2019{0}\u2019. Please use variable names in " "placeholders. " }, { "regexp": [r"\{\s*\d\s*,\s*choice.+\}"], - "outputFile": "choice_formatted", "desc": "Find string resources using the choice format" }, { "regexp": [r"\'", r"\"", r"[\.]{3}"], - "outputFile": "ascii_punct", "desc": "ASCII punctuation in use. Best Practice is to use their Unicode equivalents." }, + { + "regexp": [r"^\s*$"], + "desc": "empty string" + } ] diff --git a/utils/str_lint.py b/message_lint/linter/str_lint.py similarity index 89% rename from utils/str_lint.py rename to message_lint/linter/str_lint.py index 0f1ccae..f89e898 100644 --- a/utils/str_lint.py +++ b/message_lint/linter/str_lint.py @@ -2,7 +2,7 @@ from .lint_rules import rules -def lint(text) -> list: +def lint(text: str) -> list: result = [] for entry in rules: pattern = '|'.join(entry['regexp']) diff --git a/message_lint/logger.py b/message_lint/logger.py new file mode 100644 index 0000000..3d9d0f6 --- /dev/null +++ b/message_lint/logger.py @@ -0,0 +1,41 @@ +import logging + + +class Logger: + def __init__(self): + self._verbose = False + + def log_info(self, text: str): + pass + + @property + def verbose(self): + return self._verbose + + @verbose.setter + def verbose(self): + pass + + @staticmethod + def get(verbose=False): + if verbose: + return AppLogger() + else: + return NullLogger() + + +class AppLogger(Logger): + def __init__(self): + self._verbose = True + logging.basicConfig( + format='%(asctime)s %(levelname)-8s %(message)s', + datefmt="%Y-%m-%d %H:%M:%S", + filename='message_lint.log', level=logging.INFO) + + def log_info(self, text: str): + logging.info(text) + + +class NullLogger(Logger): + def __init__(self): + pass diff --git a/message_lint/main.py b/message_lint/main.py new file mode 100644 index 0000000..7692869 --- /dev/null +++ b/message_lint/main.py @@ -0,0 +1,71 @@ +import os +import sys +import pathlib +import time +from .logger import Logger + +fpath = os.path.join(os.path.dirname(__file__), '..') +sys.path.append(fpath) + +import utils +from .fileprocessor import FileProcessor + + +def build_file_path(filename, target_path, extra_folder=None) -> str: + """ build a file_path """ + file_path = os.path.abspath(filename) + p = pathlib.Path(file_path) + src_path = p.parents[0] + filename = p.name + + # print(src_path, filename) + + if target_path is None: + target_path = src_path + else: + target_path = os.path.abspath(target_path) + + if extra_folder is not None: + target_path = os.path.join(target_path, extra_folder) + + # print("path of target folder:", target_path) + + os.makedirs(target_path, exist_ok=True) + + # prefix output filename with timestamp + str_time = time.strftime("%Y%m%d-%H%M%S") + filename = str_time + "_" + filename + + file_path = os.path.join(target_path, filename) + + # print("path of target file:", file_path) + + return file_path + + +def main(args): + startup_logger = Logger().get(verbose=True) + startup_logger.log_info(f"Input files: {args.files}") + startup_logger.log_info(f"Output folder path: {args.output_folder}") + startup_logger.log_info(f"Verbose: {args.verbose}") + + logger = Logger().get(verbose=args.verbose) + + for file in args.files: + reader = utils.FileReader.get(file) + + # build file path for the output folder + file_path = build_file_path(file, args.output_folder, extra_folder="message_lint_reports") + + # print("output file path:", file_path) + + if pathlib.Path(file_path).suffix == ".properties": + file_path = file_path + ".json" + + print(f"The lint report for file \"{file}\" will be saved here: {file_path}") + + writer = utils.FileWriter.get(file_path) + + FileProcessor(reader, writer, logger).execute() + + print(f"The lint report for file \"{file}\" has been saved here: {file_path}") diff --git a/message_lint/test_main.py b/message_lint/test_main.py new file mode 100644 index 0000000..e795942 --- /dev/null +++ b/message_lint/test_main.py @@ -0,0 +1,10 @@ +import unittest + + +class MainTest(unittest.TestCase): + def test_something(self): + self.assertEqual(True, False) # add assertion here + + +if __name__ == '__main__': + unittest.main() diff --git a/test_files/simple.json b/test_files/simple.json new file mode 100644 index 0000000..12e2a54 --- /dev/null +++ b/test_files/simple.json @@ -0,0 +1,6 @@ +{ + "simple.message": "This is a simple message.", + "simple.message.2": { + "message": "Here's another simple message." + } +} \ No newline at end of file diff --git a/test_files/simple.properties b/test_files/simple.properties new file mode 100644 index 0000000..0d7bd21 --- /dev/null +++ b/test_files/simple.properties @@ -0,0 +1,2 @@ +simple.message=This is a simple message. +simple.message.2=Here's another simple message. diff --git a/test_files/test.json b/test_files/test.json index 7cb917e..4b56a30 100644 --- a/test_files/test.json +++ b/test_files/test.json @@ -1,18 +1,83 @@ { - "action-buttons.page.star.error.title": { + "message.with.ascii.quotes": { "message": "We're having \"trouble\" starring this page", "description": "Title of error flag shown when a user attempts to click the 'Star this page' button but the starring action fails" }, - "message.with.orphan.placeholder": { + "message.with.ascii.ellipses": { + "message": "Hmm..." + }, + "message.incomplete.sentence.1": { + "message": ", only to be told a lie." + }, + "message.incomplete.sentence.2": { + "message": ". After that," + }, + "message.incomplete.sentence.3": { + "message": "Login and" + }, + "message.incomplete.sentence.ending.with.or": "Send them an email or", + "message.incomplete.sentence.beginning.with.or": "or contact support", + "message.incomplete.sentence.beginning.with.and": "and contact support", + "message.with.plural.1": { + "message": "{count} minutes ago" + }, + "message.with.plural.2": { + "message": "{count} weeks ago" + }, + "message.with.plural.3": "in {count} day", + "message.with.orphan.placeholder.1": { "message": "{0}" }, - "message.2.with.orphan.placeholder": { - "message":"{placeholder}" + "message.with.plural.hours": { + "message": "The meeting went on for {0} hours" + }, + "message.with.orphan.placeholder.2": { + "message": "{placeholder}" + }, + "message.with.orphan.placeholder.3": { + "message": "{}" }, - "message.3.with.indefinite.article": { + "message.with.definite.article.1": { "message": "The {0} was not ready to be picked up" }, - "message.incomplete sentence": { - "message": ", only to be told a lie." - } + "message.with.definite.article.2": { + "message": "the {0} was not ready to be picked up" + }, + "message.with.definite.article.3": { + "message": "the {} was not ready to be picked up" + }, + "message.with.indefinite.article.1": { + "message": "There was a {0} ready to be picked up" + }, + "message.with.indefinite.article.2": { + "message": "There was A {0} ready to be picked up" + }, + "message.with.indefinite.article.3": { + "message": "There was a(n) {0} that wasn't reported" + }, + "message.incomplete.sentence": ", only to be told a lie.", + "message.with.url.1": { + "message": "Please visit our website by clicking here." + }, + "message.with.url.2": { + "message": "Please visit our website: https://www.msn.com" + }, + "message.with.percentage.1": { + "message": "The projections are not {value}% accurate." + }, + "message.with.percentage.2": { + "message": "The projections are not {value} % accurate." + }, + "message.with.percentage.3": { + "message": "The projections are not {0} % accurate." + }, + "message.with.percentage.4": { + "message": "The projections are not {} % accurate." + }, + "message.with.no_description": "This is a message with no description", + "message.with.nothing.1": " ", + "message.with.nothing.2": { + "message": "" + }, + "message.with.pangram": "The quick brown fox jumps over the lazy dog." } diff --git a/test_files/test.properties b/test_files/test.properties index 6896133..13f65b2 100644 --- a/test_files/test.properties +++ b/test_files/test.properties @@ -1 +1,32 @@ -hello.world=The party went on for {0} hours +message.with.ascii.quotes=We're having "trouble" starring this page +message.with.ascii.ellipses=Hmm... +message.incomplete.sentence.1=, only to be told a lie. +message.incomplete.sentence.2=. After that, +message.incomplete.sentence.3=Login and +message.incomplete.sentence.ending.with.or=Send them an email or +message.incomplete.sentence.beginning.with.or=or contact support +message.incomplete.sentence.beginning.with.and=and contact support +message.with.plural.1={count} minutes ago +message.with.plural.2={count} weeks ago +message.with.plural.3=in {count} day +message.with.orphan.placeholder.1={0} +message.with.plural.hours=The meeting went on for {0} hours +message.with.orphan.placeholder.2={placeholder} +message.with.orphan.placeholder.3={} +message.with.definite.article.1=The {0} was not ready to be picked up +message.with.definite.article.2=the {0} was not ready to be picked up +message.with.definite.article.3=the {} was not ready to be picked up +message.with.indefinite.article.1=There was a {0} ready to be picked up +message.with.indefinite.article.2=There was A {0} ready to be picked up +message.with.indefinite.article.3=There was a(n) {0} that wasn't reported +message.incomplete.sentence=, only to be told a lie. +message.with.url.1=Please visit our website by clicking here. +message.with.url.2=Please visit our website: https://www.msn.com +message.with.percentage.1=The projections are not {value}% accurate. +message.with.percentage.2=The projections are not {value} % accurate. +message.with.percentage.3=The projections are not {0} % accurate. +message.with.percentage.4=The projections are not {} % accurate. +message.with.no_description=This is a message with no description +message.with.nothing.1= +message.with.nothing.2= +message.with.pangram=The quick brown fox jumps over the lazy dog. \ No newline at end of file diff --git a/utils/__init__.py b/utils/__init__.py index 2466e86..9969997 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -1,4 +1,2 @@ -from utils.fileprocessor import FileProcessor from utils.filewriter import FileWriter from utils.filereader import FileReader -from utils.str_lint import lint diff --git a/utils/fileprocessor.py b/utils/fileprocessor.py deleted file mode 100644 index 65c4970..0000000 --- a/utils/fileprocessor.py +++ /dev/null @@ -1,52 +0,0 @@ -from .str_lint import lint -from pprint import PrettyPrinter - -pp = PrettyPrinter( - indent=4, - width=100, - compact=True -) - - -class FileProcessor: - def __init__(self, reader, writer): - self.reader = reader - self.writer = writer - self.bins = {} - self.content = {} - - def execute(self) -> dict: - try: - self.content = self.reader.read() - pp.pprint(self.content) - except FileNotFoundError: - print("Error: File Not Found: {}".format(self.reader.filename)) - return {} - - for item in self.content.items(): - if item[1] is None or 'message' not in item[1]: - continue - message_id, message = [item[0], item[1]['message']] - print("'{0}': \"{1}\"\n".format(message_id, message)) - found_something = lint(message) - if len(found_something): - print("found_something:", found_something) - print("'{0}': >>> \"{1}\"\n".format(message_id, message)) - for something in found_something: - bin_name = something['outputFile'] - if bin_name not in self.bins: - self.bins[bin_name] = {} - self.bins[bin_name][message_id] = message - - for binName, contents in self.bins.items(): - print("Printing contents of bin...") - pp.pprint(contents) - - print("binName:", binName) - self.writer.write(binName, contents) - - if len(self.bins): - print("bins:", self.bins.keys()) - - return self.bins - diff --git a/utils/filereader.py b/utils/filereader.py index 2131c2b..0a6a770 100644 --- a/utils/filereader.py +++ b/utils/filereader.py @@ -6,10 +6,8 @@ class FileReader: def __init__(self, filename): self._filename = filename - print("FileReader:", filename) def read(self) -> dict: - print("FileReader read") return {} @property @@ -31,13 +29,9 @@ def get(filename): class JsonFileReader(FileReader): def __init__(self, filename): - print("JsonFileReader") super().__init__(filename) - print("JsonFileReader:", self.filename) def read(self) -> dict: - print("Json FileReader perform:", self._filename) - with open(self._filename) as f: content = json.load(f) @@ -46,7 +40,6 @@ def read(self) -> dict: class PropertiesFileReader(FileReader): def __init__(self, filename): - print("PropertiesReader") super().__init__(filename) def read(self) -> dict: diff --git a/utils/filewriter.py b/utils/filewriter.py index add4331..efb7892 100644 --- a/utils/filewriter.py +++ b/utils/filewriter.py @@ -34,29 +34,21 @@ def write(self, bin_name, dict_obj): class JsonFileWriter(FileWriter): def __init__(self, filename): super().__init__(filename) - self.file_extension = ".json" - - def write(self, bin_name, dict_obj): - output_filename = bin_name + self.file_extension - output_path = os.path.join(self.folder_path, output_filename) + def write(self, dict_obj): json_obj_str = json.dumps(dict_obj, indent=4) - with open(output_path, 'w') as outputHandle: + with open(self.filename, 'w') as outputHandle: outputHandle.write(json_obj_str) class PropertiesFileWriter(FileWriter): def __init__(self, filename): super().__init__(filename) - self.file_extension = ".properties" - - def write(self, bin_name, dict_obj): - output_filename = bin_name + self.file_extension - output_path = os.path.join(self.folder_path, output_filename) + def write(self, dict_obj): properties = Properties() for message_id, message in dict_obj.items(): - properties[message_id] = message + properties[message_id] = message['message'] - with open(output_path, "wb") as f: + with open(self.filename, "wb") as f: properties.store(f, encoding="utf-8")