{"id":15470454,"url":"https://github.com/ergenius/t__","last_synced_at":"2025-07-08T14:04:04.573Z","repository":{"id":58479587,"uuid":"530443234","full_name":"ergenius/t__","owner":"ergenius","description":"Erlang gettext","archived":false,"fork":false,"pushed_at":"2024-08-24T12:03:19.000Z","size":486,"stargazers_count":7,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-22T12:10:06.585Z","etag":null,"topics":["erlang","erlang-gettext","erlang-gettext-po","erlang-translation","erlang-translation-application","erlang-translation-library"],"latest_commit_sha":null,"homepage":"","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ergenius.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2022-08-30T00:39:46.000Z","updated_at":"2024-08-24T12:03:22.000Z","dependencies_parsed_at":"2025-03-03T16:47:14.975Z","dependency_job_id":null,"html_url":"https://github.com/ergenius/t__","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ergenius%2Ft__","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ergenius%2Ft__/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ergenius%2Ft__/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ergenius%2Ft__/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ergenius","download_url":"https://codeload.github.com/ergenius/t__/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250237832,"owners_count":21397401,"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","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":["erlang","erlang-gettext","erlang-gettext-po","erlang-translation","erlang-translation-application","erlang-translation-library"],"created_at":"2024-10-02T02:04:46.128Z","updated_at":"2025-04-22T12:10:25.323Z","avatar_url":"https://github.com/ergenius.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"# t__\nErlang gettext\n\nt__ is an implementation of the Gettext system in Erlang. \n\ngettext is an internationalization and localization system commonly used for writing multilingual programs on Unix-like computer operating systems. \n\n[![Erlang CI](https://github.com/ergenius/t__/actions/workflows/erlang.yml/badge.svg)](https://github.com/ergenius/t__/actions/workflows/erlang.yml)\n\nt__ is also available on [HEX](https://hex.pm/packages/t\u0026lowbar;\u0026lowbar;/)\n\n## Features\n- ?T__(\"I have a joke about Erlang, but it requires a prologue.\")\n- Fast.\n- Simple. Reading this file should be enough for understanding most use case scenarios.\n- Documented source code with comments and specs.\n- Highly configurable with multiple PO sources and languages per Erlang application or process.\n- Supports contexts.\n- Supports interpolation using familiar Erlang format control sequences (from io:format).\n- Supports translating singular term with or without interpolation and with or without context.\n- Supports translating plural term with or without interpolation and with or without context.\n- Supports all plural terms formulas defined by UNICODE CLDR.\n- Supports ETS tables based caching.\n\n## Alternatives\n\n- Erlang Gettext tools for multi-lingual capabilities: https://github.com/etnt/gettext\n\n### Quick comparison with Erlang Gettext\n\n| #   | Feature                                                               | t__                                                   | gettext                                                 |\n|-----|-----------------------------------------------------------------------|-------------------------------------------------------|---------------------------------------------------------|\n| 1   | Single macro that handles everything                                  | YES: T__                                              | NO: TXT \u0026 TXT2                                          |\n| 2   | gettext contexts                                                      | YES                                                   | NO                                                      |\n| 3   | gettext plural terms                                                  | YES                                                   | NO                                                      |\n| 4   | Separate configurations for each application started at the same node | YES                                                   | NO                                                      |\n| 5   | Different language sources                                             | YES: using application 'repositories'                 | YES: using different languages servers                   |\n| 6   | Developer mode/monitoring PO file changes                             | YES: automatically detecting PO changes               | NO: requires manual reloading of the PO files           |\n| 7   | Cache                                                                 | YES: ETS reads/writes on the calling process (faster) | YES: ETS reads/writes inside the translation gen_server |\n\n## Limitations\n\n- Gettext plural-forms formulas are hardcoded using a database. Work is underway to bypass this limitation and provide a full interpreter of any arbitrary gettext C formula.\n\n## Documentation\n\n- Github pages: https://ergenius.github.io/t__/\n- '/doc' subdirectory (generated by ex_doc)\n\n## Usage\n\n### Full demo application provided\n\nYou can find a full demo application on [Github t__ demoapp](https://github.com/ergenius/t__/tree/main/demoapp).\nThe application demonstrate most functionalities, including using multiple repositories and t__ being able to monitor repositories PO changes and reload them in real time. \nYou can test this feature by modifying any PO files used by the demoapp while you run the application in console mode. A gen_server constinously translating strings on a timer is provided, so you can easily check the updates. \n\n### Set/get the calling process language\n\n#### Set the language\n\nIt is highly recommended to set the calling process language in order to avoid specifying the language for each ?T__ macro call.\nThe specified language will be used by all ?T__ macros and functions for the current process if no explicit language is specified as a macro or function parameter.\n\n```erlang\n?T__LANGUAGE(\"en\").\n?T__LANGUAGE(\"en_GB\").\n?T__LANGUAGE(\"ro\").\n```\n\n#### Get the language\n\nGet the calling process language.\n\nWhen you properly setup the language for the process, the expected time complexity for the current implementation\nof this macro is O(1) and the worst case time complexity is O(N), where N is the number of items in the process dictionary.\n\nThe function will perform the following steps in order to determine the default language:\n- call erlang:get(t__language)\n- call application:get_env(t__language)\n- call application:get_env(t__, t__language)\n- if no t__language environment key was set for both the current application or the t__ application\nwe return t__ default language defined in t__.hrl file (which is \"en\").\n\n```erlang\nLanguage = ?T__LANGUAGE().\n```\n\n### T__ macro examples\n\n#### Singular terms\n\n```erlang\n?T__(\"I have a joke about Erlang, but it requires a prologue.\").\n```\n\nYou can use binaries and atoms, however it is not recommended.\n\n```erlang\n?T__(\u003c\u003c\"Erlang is user-friendly, it’s just picky about its friends!\"\u003e\u003e).\n?T__('Why can\\'t you trust atoms? Because they make up everything!').\n```\n\n#### Singular with context\n\nContext is useful for the translators to distinguish in between identical strings.\n\n```erlang\n?T__({\"menu\", \"Save\"}).\n?T__({\"menu\", \"Quit\"}).\n?T__({\"button\", \"Save\"}).\n?T__({\"button\", \"Cancel\"}).\n```\n\nContext can also be used to create proper translations based on grammatical gender.\n\n```erlang\n?T__({\"female\", \"The cat belong to him/her\"}).\n?T__({\"male\", \"The cat belong to him/her\"}).\n```\n\n#### Singular with repository\n\nRepositories are used to have different translations sources directories for the same application.\nFor example let's assume your application has many HTML templates, each with his own translation directory.\n\n```erlang\n?T__({\"template1\", {\"Simple term from repository template1\"}}).\n?T__({\"template2\", {\"Simple term from repository template2\"}}).\n```\n\nRepository can be combined with context also.\n\n```erlang\n?T__({\"template1\", {\"menu\", \"Save\"}}).\n```\n\n#### Singular terms with interpolation\n\n```erlang\n?T__(\"~4.2f\", [3.56]). \n```\n\n#### Context for gramatical gender with interpolation\n\nContext can also be used to create the proper translation based on grammatical gender combined with interpolation:\n\n```erlang\n?T__({\"female\", \"Her/his name is ~s\"}, [\"Marry\"]).\n?T__({\"male\", \"Her/his name is ~s\"}, [\"John\"]).\n```\n\n#### Plural terms with interpolation:\n\n```erlang\n?T__([\"~B user\", \"~B users\"], [3]).\n```\n\n#### Plural terms with context and interpolation\n\n```erlang\n?T__({\"female\", [\"~B file belongs to her/him\", \"~B files belong to her/him\"]}, [3]).\n?T__({\"male\", [\"~B file belongs to her/him\", \"~B files belong to her/him\"]}, [3]).\n```\n\n#### Plural terms with context, interpolation and repositories\n\n```erlang\n?T__({\"template1\", {\"female\", [\"~B file belongs to her/him\", \"~B files belong to her/him\"]}}, [3]).\n?T__({\"template1\", {\"male\", [\"~B file belongs to her/him\", \"~B files belong to her/him\"]}}, [3]).\n```\n\n#### Translate using #t__p{} record\n\nYou can also specify everything using the #t__p{} record as a single parameter to the T__ macro.\nThis is actually the performance wise way of doing it. You will save some extra functions calls necessary\nto understand your tuples. All #t__p{} fields except msg are optional.\n\n```erlang\n?T__(#t__p{msg = \"Hello world\"}).\n?T__(#t__p{msg = \"Her name is ~s\", data = [\"Marry\"]}).\n?T__(#t__p{language = \"ro\", context = \"female\", msg = \"Her/his name is ~s\", data = [\"Marry\"]}).\n?T__(#t__p{repository = \"module1\", language = \"ro\", context = \"male\", msg = \"Her/his name is ~s\", data = [\"John\"]}).\n?T__(#t__p{application=myapp, repository = \"module1\", language = \"ro\", context = \"female\", msg = \"Her/his name is ~s\", data = [\"Marry\"]}).\n```\n\n#### Macro with all possible parameters separated\n\nFor your convenience a macro also exists with all possible parameters:\n\n```erlang\n?T__(Application, Repository, Language, Context, Msg, Data).\n```\n\n## Plural formulas\n\n### Is plural formula data correct?\n\nShort answer: Yes, if you trust CLDR Project.\n\n### How plural formulas where generated from CLDR?\n\nFor maintaining plural formulas database we started another project here: [gettext-po-samples](https://github.com/ergenius/gettext-po-samples)\n\nWe use the following sources and tools for compiling the database:\n\n- [cldr.unicode.org](https://cldr.unicode.org/)\n- [PHP gettext language list](https://github.com/php-gettext/Languages)\n- [TranslateHouse](http://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/pluralforms.html)\n\nFormulas are automated generated by [PHP gettext language list](https://github.com/php-gettext/Languages) from CLDR. Each new release is manually checked and compared with the sources mentioned above. Data is compiled into [plural-forms.eterm](https://github.com/ergenius/gettext-po-samples/blob/main/data/plural-forms.eterm) file.\nThe same [plural-forms.eterm](https://github.com/ergenius/gettext-po-samples/blob/main/data/plural-forms.eterm) file is used to generate [src/t__plural.erl](src/t__plural.erl) file.\n\n## Project roadmap\n\n1. Continuously fixing bugs and tuning performance.\n2. Writing more testing units.\n3. Add more features.\n\n## Erlang versions supported\n\nt__ officially supports OTP release 21 and later.\n\nDevelopment takes place using OTP 27 release and tests are done on:\n- 27.0.1\n- 26.2.5\n- 25.3.2\n- 24.3.4\n- 23.3.4\n- 22.3.4\n- 21.3.8\n\nUnofficially, you may be able to use t__ with older Erlang versions. No guarantee included.\n\n## Dependencies\n\nNone.\n\n## Authors\n\n- Madalin Grigore-Enescu (ergenius) - [Github](https://github.com/ergenius) [ergenius.com](\u003chttps://ergenius.com\u003e)\n\n## License\n\nt__ is available under the MIT license (see `LICENSE`).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fergenius%2Ft__","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fergenius%2Ft__","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fergenius%2Ft__/lists"}