{"id":21881860,"url":"https://github.com/open-amdocs/textcrate","last_synced_at":"2025-10-11T11:44:51.095Z","repository":{"id":79846624,"uuid":"120288943","full_name":"open-amdocs/textcrate","owner":"open-amdocs","description":"Java libraries for application message repositories and message formatting","archived":false,"fork":false,"pushed_at":"2019-01-14T09:39:20.000Z","size":84,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-07-10T21:27:12.660Z","etag":null,"topics":["java"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/open-amdocs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-02-05T10:20:38.000Z","updated_at":"2019-01-14T09:39:21.000Z","dependencies_parsed_at":null,"dependency_job_id":"68781f78-6921-430e-83c0-a875bcb74f78","html_url":"https://github.com/open-amdocs/textcrate","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/open-amdocs/textcrate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-amdocs%2Ftextcrate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-amdocs%2Ftextcrate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-amdocs%2Ftextcrate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-amdocs%2Ftextcrate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/open-amdocs","download_url":"https://codeload.github.com/open-amdocs/textcrate/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-amdocs%2Ftextcrate/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279007062,"owners_count":26084230,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java"],"created_at":"2024-11-28T09:21:43.320Z","updated_at":"2025-10-11T11:44:51.075Z","avatar_url":"https://github.com/open-amdocs.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Build Status](https://travis-ci.org/open-amdocs/textcrate.svg?branch=master)](https://travis-ci.org/open-amdocs/textcrate)\n[![codebeat badge](https://codebeat.co/badges/74153047-7dd8-4c01-adc6-3bdf9693aadd)](https://codebeat.co/projects/github-com-open-amdocs-textcrate-master)\n[![codecov](https://codecov.io/gh/open-amdocs/textcrate/branch/master/graph/badge.svg)](https://codecov.io/gh/open-amdocs/textcrate)\n\n# TextCrate Message Repositories\n\nThe main purpose of this library is to enable external repositories of parametrized messages for easy modification,\nlocalization, proof-reading, and automatic checking at build-time, as well as to provide convenient access to the\nmessages from the code of a Java application.\n\n## Example\n\n### Message Repository\n\n```java\n@CodeSpec(offset=20, pattern=\"BOR-{}\")\n@MessageProperty(name=\"type\", value=\"Error\")\npublic interface BookBorrowingErrors {\n    \n    @MessageSpec(id=1, pattern=\"'{}' is currently not available\")\n    Message bookUnavailable(String title);\n    \n    @MessageSpec(id=2, pattern=\"Attempt to borrow more than {} books\")\n    Message attemptToBorrowMoreThanAllowed(int maxAllowed);\n}\n```\n\n### Printing to Stdout\n\n```java\n    BookBorrowingErrors borrowingErrors = Messages.from(BookBorrowingErrors.class);\n\n    Message unavailable = borrowingErrors.bookUnavailable(\"The Mythical Man-Month\");\n    \n    // Prints \"[BOR-21] 'The Mythical Man-Month' is currently not available\" to stdout\n    System.out.printf(\"[%s] %s\\n\", unavailable.getCode(), unavailable.getMessage());   \n```\n\n### SLF4J Logging\n\n```java\n    BookBorrowingErrors borrowingErrors = Messages.from(BookBorrowingErrors.class);\n   \n    Message reachedMaxBooks = borrowingErrors.attemptToBorrowMoreThanAllowed(12);\n    \n    // Logs \"Attempt to borrow more than 12 books\" in SLF4J format \n    if (\"Error\".equals(reachedMaxBooks.getProperty(\"type\"))) {\n        LOGGER.error(reachedMaxBooks.getPattern(), reachedMaxBooks.getArguments());\n    }\n```\n\nNote, that in a real application `\"type\"` and `\"Error\"` will probably be constants. \nThe instance of `BookBorrowingErrors` is also likely to be kept in a constant.\n\n## Motivation\n\nWe were looking for an application message repository API that would be easy to use, and would allow for streamlined \ndevelopment. Adding or using a message should require minimum disruption from a developer, and be IDE friendly. \n\nActually, adding a new message type to a repository, and instantiating a message object should be as easy as adding and \ncalling a method! This is easily done \"on the fly\" in any modern IDE. This approach would also automatically enforce the\nuniqueness and number of parameters of a message, and allow for typed parameters as an additional advantage if needed. \nAuto code completion when selecting/using an existing message is yet another advantage.\n\n## Modules\n\nThe library includes modules as follows:\n\n1. The API module is the only one that application code should see. It contains application-facing interfaces and\n   factories, as well as some basic classes that can be used by a concrete implementation of message loading and\n   formatting.\n      \n   This module also exposes a Service Provider Interface (SPI) to allow custom mechanisms for message loading and \n   creation.\n   \n   If no service providers are configured, the default implementation based on Java dynamic proxy is used.  \n\n2. _Work in Progress_: A compiler that generates optimized code for efficient loading of message repositories. It may\n   also validate the correct return type, message parameters and formatting rules in build time, as well as check that \n   external message sources (i.e. message bundles) contain all the messages defined by an interface. \n\n   Possible validations:\n   - A default message must be specified.\n   - The format must match the formatter.\n   - Each message must exist in the available external repositories.\n   - The type and number of parameters must be correct.\n   - Enforce message code uniqueness per repository.\n\n3. _Work in Progress_: Tools (e.g. Maven plugin) for generating user documentation showing message codes and their \n  descriptions.\n\n## TODO\n\n- Support inheritance, when an interface extends another interface or even multiple interfaces.\n \n- Support interfaces declared inside classes.\n\n- Implement loading non-default formatting patterns using Java Resource Bundles.\n\n- Implement message localization in the API module. Currently, only the default formatting pattern is read.\n\n## Contributing\n\nContributions in any form and shape are welcomed! Code, bug reports, suggestions for improvement \u0026mdash; all will be \ngreatly appreciated. There is no established procedure for code contributions yet, so please open an issue for that.\n\n### If It Does Not Compile...\n\n- This project uses [Lombok](https://projectlombok.org/) to avoid boilerplate code (`toString()`, `equals()`, \n  `hashCode()`, etc.). There is no problem to build it with Maven, but to work comfortably in an IDE you will have to \n  install a [Lombok plugin](https://projectlombok.org/setup/overview).  \n\n### Code Style\n\n- The style and coding convention used for this project are based on \n  [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html), with the exception of line length \n  (120 instead of 100), and indentation size (4 spaces instead of 2). \n\n## License\n\n    Copyright © 2016-2018 European Support Limited\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n        http://www.apache.org/licenses/LICENSE-2.0\n    \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.  \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopen-amdocs%2Ftextcrate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopen-amdocs%2Ftextcrate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopen-amdocs%2Ftextcrate/lists"}