ThatLanguage::Service
A thin Sinatra wrapper that exposes the ThatLanguage language-detection library over HTTP as eight JSON endpoints.
This is a library gem, not an application: it ships a config.ru but
declares no web server, so the deployment picks its own.
Installation
Add it to your Gemfile:
gem "that_language-service"Requires Ruby 3.1 or later. The that_language core gem is pulled in
automatically; no git source or extra declaration is needed.
Running it
$ bundle install
$ bundle exec puma config.ru -p 9292Then:
$ curl --get --data-urlencode 'text=Hallo Welt' http://localhost:9292/detect
{"language":"German","language_code":"de","confidence":0.5}Endpoints
Every endpoint answers both GET and POST, takes the input in a text
parameter, and responds with Content-Type: application/json.
| Endpoint | Returns |
|---|---|
/language |
{"language": "German"} |
/language_code |
{"language_code": "de"} |
/detect |
{"language": …, "language_code": …, "confidence": …} |
/details |
the full ranked result set, best match first |
/available |
{"available": {"de": "German", …}} |
/available_languages |
list of language names |
/available_language_codes |
list of language codes |
/version |
{"version": …, "core_version": …} — this service, and the core library behind it |
/details returns every candidate language with its scoring breakdown:
{"results":[{"language":"German","language_code":"de","confidence":0.5,
"value":1.0,"hit_ratio":0.5,"hit_count":1,"words_count":2}]}Configuration
The wordlist tier is a property of the core library, not of this service. Configure it before the application is mounted:
ThatLanguage.configure do |config|
config.wordlist_path = File.join("wordlists", "100k")
endWarm the cache at boot. The wordlists are loaded lazily on the first request, which costs about a second and a few hundred megabytes. Without a warm-up the first user pays for it:
ThatLanguage.language_code("Hello world!") # in config.ru, before `run`Cross-origin requests
Rack::Protection::JsonCsrf is deliberately disabled — it answers 403 to any
request carrying a cross-origin Referer, which would block the intended
browser use case while guarding data that is already public. CORS headers are
not set here; the deployment adds them.
Development
$ bundle install
$ bundle exec rspec # 161 examples, 0 failures
$ bundle exec rubocop
$ bin/contract # this service vs the core gemRequires Ruby >= 3.1; developed and pinned against 4.0.6
(see .tool-versions).
.rspec sets --fail-fast, so a run that stops early reads as though examples
disappeared. If the count is below 161, look for a failure before concluding the
suite shrank.
The contract test
The specs are rack-test against the app in-process. They assert what this app
does, which means they cannot notice this app drifting from the core gem it
exposes — the same blind spot that let the client's return types diverge from
the core gem's for a decade while its suite stayed green.
bin/contract closes that gap. It starts a real service from the working tree
and compares every endpoint against the core gem in a separate process:
Each endpoint's payload must equal the JSON projection of the core gem's return value —
JSON.parse(body) == JSON.parse(<core value>.to_json).
Things worth knowing before you touch it:
-
The wire erases types. The core gem returns symbols for language names and
codes; JSON has no symbols, so the symbol/string distinction cannot be
asserted across HTTP. Sortedness, ranking and the
/detectkey set are therefore checked as explicit invariants — a diff alone proves the two sides agree, not that either is right. Seecontract/canonical.rb, which is where the reasoning lives. -
/detectis a deliberate subset ofResult#to_h: three keys, not seven. It is pinned in both directions, so returning all seven is drift too. -
contract/gemfiles/service.gemfileresolves this gem from the working tree, not from rubygems. From rubygems it would test the last release and pass on a branch that breaks the projection. - The job goes red when the core gem changes, not only this repository. That is the point of a contract test, but it means a red badge here is not always a bug here.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/Deradon/that_language-service. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
License
Available as open source under the terms of the MIT License.