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`
+
+
+
+## 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")