{"id":18812861,"url":"https://github.com/facundoolano/clojure-gettext","last_synced_at":"2025-04-13T21:25:59.636Z","repository":{"id":62432793,"uuid":"56462416","full_name":"facundoolano/clojure-gettext","owner":"facundoolano","description":"Utilities to write multilingual clojure programs","archived":false,"fork":false,"pushed_at":"2016-04-20T23:53:52.000Z","size":14,"stargazers_count":13,"open_issues_count":1,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-27T11:43:38.366Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/facundoolano.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}},"created_at":"2016-04-17T22:45:04.000Z","updated_at":"2019-01-10T18:43:42.000Z","dependencies_parsed_at":"2022-11-01T21:15:31.428Z","dependency_job_id":null,"html_url":"https://github.com/facundoolano/clojure-gettext","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/facundoolano%2Fclojure-gettext","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/facundoolano%2Fclojure-gettext/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/facundoolano%2Fclojure-gettext/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/facundoolano%2Fclojure-gettext/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/facundoolano","download_url":"https://codeload.github.com/facundoolano/clojure-gettext/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248784137,"owners_count":21161062,"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":[],"created_at":"2024-11-07T23:35:25.592Z","updated_at":"2025-04-13T21:25:59.600Z","avatar_url":"https://github.com/facundoolano.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# clojure-gettext\n\nUtilities to write multilingual Clojure programs, vaguely inspired by [GNU gettext](https://www.gnu.org/software/gettext/).\n\n## Installation\n\nTo install gettext, add the following to your project map as a dependency:\n\n```clojure\n[gettext \"0.1.1\"]\n```\n\n## Usage\n\n### Basic translations\n\nThe first step is to mark some strings within your program as being translatable,\nby using the `gettext` function or its shorter alias `_`:\n\n```clojure\n(ns myprogram.core\n  (:require [gettext.core :refer [_]]))\n\n(println (_ \"Hello, world!\"))\n```\n\nNote `gettext` wraps [`format`](https://clojuredocs.org/clojure.core/format) so\nyou can pass replacement arguments to the call:\n\n```clojure\n(println (_ \"Hello, %s!\" \"Facundo\"))\n```\n\nOnce the strings are marked for translation, a dictionary is needed to map them\nto a specific translation:\n\n```clojure\n(ns myprogram.translations.spanish)\n\n(def dictionary {\"Hello, world!\" \"Hola, mundo!\"\n                 \"Hello, %s\" \"Hola, %s\"})\n```\n\nThe dictionary to use for translations can be set statically in the `resources/config.clj` file.\nThe file should consist of a map with the `:gettext-source`:\n\n```clojure\n{:gettext-source 'myprogram.translations.spanish/dictionary}\n```\n\nAlternatively, the translations dictionary can be bound dynamically using\n`with-bindings`:\n\n```clojure\n(println (_ \"Hello, world!\")) ; Will use the translation set at project.clj or return the key if none set\n\n(with-bindings {#'gettext.core/*text-source* myprogram.translations.german/dictionary}\n  (println (_ \"Hello, world!\"))) ; Will print the german translation instead\n\n```\n\nWhen a key is not found in the translations dictionary, or if no dictionary\nhas been set, the result of the `gettext` call will be the key string itself.\n\n### Context based translations\n\nThere are cases when the original string is not enough to properly translate it\nto another language, for example, when working with plural forms or with gender.\nIn those cases `pgettext` or its alias `p_` can be used.\n\n`pgettext` takes an arbitrary context value as its first argument:\n\n```clojure\n(ns myprogram.core\n  (:require [gettext.core :refer [p_]]))\n\n(println (p_ {:gender :male} \"%s is my friend.\" \"John\"))\n(println (p_ {:gender :female} \"%s is my friend.\" \"Jane\"))\n```\n\nWhen defining the translations dictionary, the key string can be mapped to a\nfunction that will take the context and decide on the translation:\n\n```clojure\n(ns myprogram.translations.spanish)\n\n(def dictionary {\"Hello, world!\" \"Hola, mundo!\"\n                 \"Hello, %s\" \"Hola, %s\"\n                 \"%s is my friend.\" #(if (= (:gender %) :female) \"%s es mi amiga.\" \"%s es mi amigo.\") })\n```\n\n`pgettext` can also be useful even when using a single language, to decouple grammar\nlogic from app specific logic:\n\n```clojure\n(ns myprogram.translations.english)\n\n(defn starts-with-vowel\n  [ctx]\n  (let [vowel? (set \"aeiouAEIOU\")]\n    (vowel? (first ctx))))\n\n(def dictionary {\"I'm carrying a %\" #(if (starts-with-vowel %)\n                                         \"I'm carrying an %s\"\n                                         \"I'm carrying a %s\"))})\n```\n\n### Scan files for translatable strings\nThe function `gettext.scan/scan-files` takes a clojure file or directory and\nextracts all strings that are passed to `gettext` in any of its flavors. The\nstrings are packed in a map to facilitate their translation:\n\n```clojure\n(require '[gettext.scan :refer [scan-files]])\n\n(scan-files \"/Users/facundo/dev/advenjure/src/advenjure\")\n; Returns\n; {\"%s was closed.\" \"%s was closed.\",\n;  \"%s was empty.\" \"%s was empty.\",\n;  \"%s what?\" \"%s what?\",\n;  \"Bye!\" \"Bye!\",\n;  \"Closed.\" \"Closed.\"\n;  ...}\n```\n\n## License\n\nCopyright © 2016 Facundo Olano\n\nDistributed under the Eclipse Public License either version 1.0 or (at\nyour option) any later version.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffacundoolano%2Fclojure-gettext","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffacundoolano%2Fclojure-gettext","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffacundoolano%2Fclojure-gettext/lists"}