All Projects â†’ ptaoussanis â†’ Tempura

ptaoussanis / Tempura

Licence: epl-1.0
Pure Clojure/Script i18n translations library

Programming Languages

clojure
4091 projects
clojurescript
191 projects

Projects that are alternatives of or similar to Tempura

Gotext
Go (Golang) GNU gettext utilities package
Stars: ✭ 292 (+38.39%)
Mutual labels:  translation, i18n, gettext
Glotpress Wp
🌍 🌎 🌏 GlotPress is a WordPress plugin to let you set up your own collaborative, web-based software translation tool.
Stars: ✭ 205 (-2.84%)
Mutual labels:  translation, i18n, gettext
gettext-extractor
A flexible and powerful Gettext message extractor with support for JavaScript, TypeScript, JSX and HTML.
Stars: ✭ 82 (-61.14%)
Mutual labels:  i18n, translation, gettext
Gettext
PHP library to collect and manipulate gettext (.po, .mo, .php, .json, etc)
Stars: ✭ 578 (+173.93%)
Mutual labels:  translation, i18n, gettext
Node Gettext
A JavaScript implementation of gettext, a localization framework.
Stars: ✭ 175 (-17.06%)
Mutual labels:  translation, i18n, gettext
Gettext Go
🆎 GNU gettext for Go (Imported By Kubernetes)
Stars: ✭ 66 (-68.72%)
Mutual labels:  translation, i18n, gettext
Django Rosetta
Rosetta is a Django application that eases the translation process of your Django projects
Stars: ✭ 806 (+281.99%)
Mutual labels:  translation, i18n, gettext
Weblate
Web based localization tool with tight version control integration.
Stars: ✭ 2,719 (+1188.63%)
Mutual labels:  translation, i18n, gettext
Punic
PHP translation and localization made easy!
Stars: ✭ 133 (-36.97%)
Mutual labels:  translation, i18n
Kiwi
🐤 Kiwi-国际化全流程解决方案
Stars: ✭ 1,872 (+787.2%)
Mutual labels:  translation, i18n
Jquery I18next
i18next plugin for jquery usage
Stars: ✭ 143 (-32.23%)
Mutual labels:  translation, i18n
Talkr
Talkr is a super small i18n provider for React applications. It supports Typescript, has 0 dependencies, and is very easy to use.
Stars: ✭ 129 (-38.86%)
Mutual labels:  translation, i18n
I18next Express Middleware
[deprecated] can be replaced with i18next-http-middleware
Stars: ✭ 195 (-7.58%)
Mutual labels:  translation, i18n
I18n Debug
Ever wondered which translations are being looked up by Rails, a gem, or simply your app? Wonder no more!
Stars: ✭ 143 (-32.23%)
Mutual labels:  translation, i18n
Go I18n
Translate your Go program into multiple languages.
Stars: ✭ 1,834 (+769.19%)
Mutual labels:  translation, i18n
I18n Extract
Manage localization with static analysis. 🔍
Stars: ✭ 152 (-27.96%)
Mutual labels:  translation, i18n
Dom I18n
Provides a very basic HTML multilingual support using JavaScript
Stars: ✭ 125 (-40.76%)
Mutual labels:  translation, i18n
Deeply
PHP client for the DeepL.com translation API (unofficial)
Stars: ✭ 152 (-27.96%)
Mutual labels:  translation, i18n
Strsync
A CLI tool for localization resource management on Xcode. Built with Google Translator.
Stars: ✭ 157 (-25.59%)
Mutual labels:  translation, i18n
Es2015 I18n Tag
ES2015 template literal tag for i18n and l10n (translation and internationalization)
Stars: ✭ 171 (-18.96%)
Mutual labels:  translation, i18n
Taoensso open-source

CHANGELOG | API | current Break Version:

[com.taoensso/tempura "1.2.1"]

See here if you're interested in helping support my open-source work, thanks! - Peter Taoussanis

Tempura: a pure Clojure/Script i18n translations library

Objectives

  • Tiny (single fn), cross-platform all-Clojure API for providing multilingual content.
  • Match gettext's convenience for embedding default content directly in code (optional).
  • Exceed gettext's ability to handle versioned content through unique content ids.
  • Work out-the-box with plain text, Hiccup, Reactjs, ...
  • Easy, optional platform-appropriate support for simple Markdown styles.
  • Flexibility: completely open/pluggable resource compiler.
  • Performance: match or exceed format performance through compilation + smart caching.
  • All-Clojure (edn) dictionary format for ease of use, easy compile-and-runtime manipulation, etc.
  • Focus only on common-case translation and no other aspects of i18n/L10n.

Tutorial

See here for a detailed tutorial by Dr. Wolfram Schroers (thanks Wolfram!).

Quickstart

Add the necessary dependency to your project:

Leiningen: [com.taoensso/tempura "1.2.1"] ; or
deps.edn:   com.taoensso/tempura {:mvn/version "1.2.1"}

Setup your namespace imports:

(def my-clj-or-cljs-ns
  (:require [taoensso.tempura :as tempura :refer [tr]]))

Define a dictionary for translation resources:

(def my-tempura-dictionary
  {:en-GB ; Locale
   {:missing ":en-GB missing text" ; Fallback for missing resources
    :example ; You can nest ids if you like
    {:greet "Good day %1!" ; Note Clojure fn-style %1 args
     }}

   :en ; A second locale
   {:missing ":en missing text"
    :example
    {:greet "Hello %1"
     :farewell "Goodbye %1"
     :foo "foo"
     :bar "bar"
     :bar-copy :en.example/bar ; Can alias entries
     :baz [:div "This is a **Hiccup** form"]

     ;; Can use arbitrary fns as resources
     :qux (fn [[arg1 arg2]] (str arg1 " and " arg2))}

    :example-copy :en/example ; Can alias entire subtrees

    :import-example
    {:__load-resource ; Inline edn content loaded from disk/resource
     "resources/i18n.clj"}}})

And we're ready to go:

(tr ; Just a functional call
  {:dict my-tempura-dictionary} ; Opts map, see docstring for details
  [:en-GB :fr] ; Vector of descending-preference locales to search
  [:example/foo] ; Vector of descending-preference resource-ids to search
  ) ; => "foo"

(def opts {:dict my-tempura-dictionary})
(def tr (partial tr opts [:en])) ; You'll typically use a partial like this

;; Grab a resource
(tr [:example/foo]) ; => "foo"

;; Missing resource
(tr [:example/invalid])                       ; => ":en missing text"
(tr [:example/invalid "inline-fallback"])     ; => "inline-fallback"
(tr [:example/invalid :bar "final-fallback"]) ; => "bar"

;; Let's try some argument interpolation
(tr [:example/greet] ["Steve"]) ; => "Hello Steve"

;; With inline fallback
(tr [:example/invalid "Hi %1"] ["Steve"]) ; => "Hi Steve"

;; Example of a deeply-nested resource id
(tr [:example.buttons/login-button "Login!"]) ; => "Login!"

;; Let's get a Hiccup form for Reactjs, etc.
;; Note how the Markdown gets expanded into appropriate Hiccup forms:
(tr [:example/baz]) ; => [:div "This is a " [:strong "Hiccup"] " form"]

;; With inline fallback
(tr [:example/invalid [:div "My **fallback** div"]]) ; => [:div "My " [:strong "fallback"] " div"]

And that's it, you know the API:

(tr [opts locales resource-ids])               ; Without argument interpolation, or
(tr [opts locales resource-ids resource-args]) ; With    argument interpolation

Please see the tr docstring for more info on available opts, etc.

Pattern: adding translations in stages

The support for gettext-like inline fallback content makes it really easy to write your application in stages, without translations becoming a burden until if/when you need them.

Assuming we have a tr partial (tr [resource-ids] [resource-ids resource-args]):

"Please login here"        ; Phase 1: no locale support (avoid)
(tr ["Please login here"]) ; Phase 2: works just like a text literal during dev

;; Phase 3: now supports translations when provided under the `:please-login`
;; resource id, otherwise falls back to the (English) text literal:
(tr [:please-login "Please login here"])

This means:

  • You can write dev/prototype apps w/o worrying about translations or naming resource ids.
  • Once your app design settles down, you can add resource ids.
  • Your translation team can now populate locale dictionaries at their own pace.
  • You can keep the default inline content as context for your developers.

I'll note that since the API is so pleasant, it's actually often much less effort for your developers to use tr than it would be for them to write the equivalent Hiccup structures by hand, etc.:

;; Compare the following two equivalent values:
(tr [["Hi %1, please enter your **login details** below:"]] [user-name])
[:span "Hi " user-name ", please enter your " [:strong "login details"] " below:"]

Note that ["foo"] is an optional resource content shorthand for the common-case [:span "foo"]

If it's easy to use, it'll be easy to get your developers in the habit of writing content this way - which means that there's a trivial path to adding multilingual support whenever it makes sense to do so.

FAQ

How's the performance? These seem like expensive transformations.

There's two aspects of performance worth measuring: resource lookup, and resource compilation.

Both are highly optimized, and intelligently cached. In fact, caching is quite easy since most applications have a small number of unique multilingual text assets. Assets are compiled each time they're encountered for the first time, and the compilation cached.

As an example:

`(tr [["Hi %1, please enter your **login details** below:"]] [user-name])`

;; Will compile the inner resource to an optimized function like this:

(fn [user-name] [:span "Hi " user-name ", please enter your " [:strong "login details"] " below:"])

So performance is often on par with the best possible hand-optimized monolingual code.

How would you use this with Reagent, etc.?

Tempura was specifically designed to work with Reactjs applications, and works great with Reagent out-the-box.

  • Step 1: Setup your ns imports so that your client has access to tempura/tr.
  • Step 2: Make sure your client has an appropriate dictionary [1].
  • Step 3: Call tr with the appropriate dictionary.

Couldn't be simpler.

[1] If your dictionaries are small, you could just define them with the rest of your client code. Or you can define them on the server-side and clients can fetch the relevant part/s through an Ajax request, etc. Remember that Tempura dictionaries are just plain Clojure maps, so they're trivially easy to modify/filter.

Ring middleware?

Please see tempura/wrap-ring-request.

Use with XLIFF or other industry standard tools?

Shouldn't be hard to do, you'll just need a conversion tool to/from edn. Haven't had a need for this myself, but PRs welcome.

Contacting me / contributions

Please use the project's GitHub issues page for all questions, ideas, etc. Pull requests welcome. See the project's GitHub contributors page for a list of contributors.

Otherwise, you can reach me at Taoensso.com. Happy hacking!

- Peter Taoussanis

License

Distributed under the EPL v1.0 (same as Clojure).
Copyright Š 2016-2020 Peter Taoussanis.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].