babosa: Ruby slug generation with locale-aware transliteration
A library for creating slugs. Babosa is an extraction and improvement of the string code from FriendlyId, intended to help developers create similar libraries or plugins.
At a glance
- What is it?
- babosa turns a string into a human-friendly identifier, one operation at a time, so you can choose transliterate or strip, truncate by characters or by bytes, drop punctuation, or run it all at once. It grew out of the string handling code in FriendlyId and ships per-locale transliterators for fifteen languages.
- Who is it for?
- babosa fits a Rails or Ruby project that needs readable URLs or identifiers from non-Latin input, and that wants the transliteration rule for a specific language rather than a generic approximation. It is the wrong choice if Active Support's `parameterize` already covers your inputs, since the README itself points you at that comparison first, and the wrong choice if you need transliteration for a language outside the supported list.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 168 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A slug builder you compose step by step
babosa is a library for creating human-friendly identifiers, aka slugs, and it can also be useful for normalizing and sanitizing data. The API shape is what sets it apart from a single `slugify` helper. You call `to_slug` on a string and get back an object you can push through a chain of operations, each of which does one thing. The README's headings are the chain. Transliterate UTF-8 characters to ASCII, strip non-ASCII characters, truncate by characters, truncate by bytes, remove punctuation characters, or normalize all at once. The chain ends in `to_s` to get the string back. That means you choose the operation rather than accepting a fixed pipeline, and the difference between truncating by characters and truncating by bytes is a decision you make explicitly rather than a behaviour you inherit.
Transliteration is the interesting half, and it comes in two flavours
The first operation is transliteration, which converts UTF-8 characters to ASCII:
"Gölcük, Turkey".to_slug.transliterate.to_s #=> "Golcuk, Turkey"The second flavour is locale sensitive, and it is where the library earns its keep:
"Jürgen Müller".to_slug.transliterate.to_s #=> "Jurgen Muller"
"Jürgen Müller".to_slug.transliterate(:german).to_s #=> "Juergen Mueller"The same input produces different output depending on the language rules applied, because German writes ue where the generic transliterator writes u. The supported language list in the README is Bulgarian, Danish, German, Greek, Hindi, Macedonian, Norwegian, Romanian, Russian, Serbian, Spanish, Swedish, Turkish, Ukrainian and Vietnamese. On top of the per-language rules there are generic transliterators for the Cyrillic alphabet and for Latin with diacritics, and the Latin one is described as usable for Czech. The README is refreshingly honest about one gap: there is also a transliterator named Hindi which may be sufficient for other Indic languages using Devanagari, but the author does not know enough to say whether the transliterations would make sense.
Stripping and truncating are separate operations with different units
Stripping non-ASCII characters is the blunt version of transliteration:
"Gölcük, Turkey".to_slug.to_ascii.to_s #=> "Glck, Turkey"Note the difference in the result. Transliteration preserves the letters, so Gölcük becomes Golcuk, while stripping just removes what it cannot represent, so it becomes Glck. That is not a bug, it is a different operation with a different purpose, and it is exactly why the library exposes both. Truncation also comes in two flavours. By characters:
"üüü".to_slug.truncate(2).to_s #=> "üü"And by bytes:
"üüü".to_slug.truncate_bytes(2).to_s #=> "ü"The README gives the reason for the byte variant, which is that it can be useful to ensure the generated slug will fit in a database column whose length is limited by bytes rather than UTF-8 characters. That is a real constraint in PostgreSQL with certain collations and in MySQL with a utf8 column, so the byte-based truncation is the one to reach for when the limit is a schema constraint rather than a display width.
Punctuation removal and the all-in-one normalize
Removing punctuation characters is the `word_chars` operation:
It strips the punctuation but keeps the spaces, so the result reads as a sentence rather than a slug. The all-in-one path is `normalize`:
"Gölcük, Turkey".to_slug.normalize.to_s #=> "golcuk-turkey"That single call transliterates and then joins the words with hyphens, which is what most people want when they say slug. The library also normalizes all input strings to NFC before doing anything else, which the README mentions under UTF-8 support. That detail prevents a class of subtle bugs, since the same visual character can have more than one byte sequence in UTF-8 and a naive comparison or a database index can treat two spellings of the same accent as different values.
It plugs into FriendlyId 4, and it can generate Ruby method names
babosa was extracted and improved from the string code in FriendlyId, and it still has a documented integration path. The README shows an ActiveRecord model overriding the normalization method:
require "babosa"
class Person < ActiveRecord::Base
friendly_id :name, use: :slugged
def normalize_friendly_id(input)
input.to_slug.transliterate(:ukrainian).normalize.to_s
end
endHere the transliterator is chosen per call, so the same model could pick a different rule depending on the input. The second integration point is less common but neat. Babosa can generate strings for Ruby method names, and the README notes that Ruby 1.9 and later can use UTF-8 characters in method names but you may not want to:
"this is a method".to_slug.to_ruby_method! #=> this_is_a_method
"über cool stuff!".to_slug.to_ruby_method! #=> uber_cool_stuff!
# You can also disallow trailing punctuation chars
"über cool stuff!".to_slug.to_ruby_method(allow_bangs: false) #=> uber_cool_stuffThe `allow_bangs` option handles the case where the source string ends with punctuation, which would otherwise produce an invalid method name. Both features come from the same place, since the underlying operation is turning arbitrary text into a restricted identifier.
Adding a language is a class and a spec
Extending the library is the part that makes it reusable by other projects, which is the stated motivation for releasing it separately from FriendlyId. A custom transliterator for a language takes very little code, and the German one is short enough to show in full:
module Babosa
module Transliterator
class German < Latin
APPROXIMATIONS = {
"ä" => "ae",
"ö" => "oe",
"ü" => "ue",
"Ä" => "Ae",
"Ö" => "Oe",
"Ü" => "Ue"
}
end
end
endA transliterator is a class inheriting from `Latin` with an `APPROXIMATIONS` hash mapping the accented characters to their ASCII replacements. The spec that goes with it is a template too, since the README offers it as one. The design is deliberately shallow, which means a fluent speaker can add a language without understanding the rest of the library, and that is also why the README asks for contributions specifically from fluent speakers rather than from people who can guess at the orthography of a language they do not speak.
Where babosa is the wrong choice
Three limits are worth naming. The first is that Active Support may already do the job. The README says some of Babosa's functionality was added to Active Support 3.0.0, and that Babosa now differs from ActiveSupport primarily in that it supports non-Latin strings by default and has per-locale ASCII transliterations already baked in. The README then tells you to look at Active Support's `transliterate` and `parameterize` before deciding. If your inputs are already Latin, or if you are content with the generic approximation, then adding a gem is more moving parts than you need. The second is the language coverage. Fifteen locales plus generic Cyrillic and Latin diacritics is good, and it is not all of them, so a site with content in a language outside that list will fall back to behaviour the README does not fully describe. The third is maintenance. The last push was on 2026-05-08 and the single tagged release is v2.1.0 from the same date, so the project is alive, but it is a small library with a small contributor list, and the copyright notice runs 2010 to 2021.
The alternative is Active Support, and the difference is per-locale rules
The realistic alternative is to use the Active Support inflector methods that ship with Rails, and the difference in approach is where the language knowledge lives. `ActiveSupport::Inflector.transliterate` applies one generic replacement table for the Latin characters it knows about, and `parameterize` builds a parameter string from a title using that table. The result is close to babosa's default transliteration, and it is available without a gem. What babosa adds is the per-locale layer: a German transliterator that writes ue and oe, a Turkish one, a Russian one, a Greek one and the rest, selectable by a symbol at the call site, plus the byte-aware truncation and the composable chain that lets you choose the operation. If your content is German or Turkish or Russian, that locale layer is the reason to pick babosa over the built-in. If it is not, the built-in is the shorter path and you avoid a dependency.
Editorial conclusion
babosa fits a Rails or Ruby project that needs readable URLs or identifiers from non-Latin input, and that wants the transliteration rule for a specific language rather than a generic approximation. It is the wrong choice if Active Support's `parameterize` already covers your inputs, since the README itself points you at that comparison first, and the wrong choice if you need transliteration for a language outside the supported list. Before you adopt it, check whether your language is among the fifteen listed, and read the Hindi note, since the README says the author does not know enough to say whether those transliterations would make sense.
Frequently asked questions
How do I install babosa?
Install it from RubyGems with `gem install babosa`, or get the source from the Github repository. The licence is MIT, with the licence text in MIT-LICENSE in the repository.
Which languages does babosa transliterate?
The README lists Bulgarian, Danish, German, Greek, Hindi, Macedonian, Norwegian, Romanian, Russian, Serbian, Spanish, Swedish, Turkish, Ukrainian and Vietnamese, plus generic transliterators for Cyrillic and for Latin with diacritics.
How do I truncate a slug by bytes instead of characters in babosa?
Use `truncate_bytes` rather than `truncate`. The README says byte truncation is useful to ensure the generated slug fits a database column whose length is limited by bytes rather than UTF-8 characters.
What is the difference between babosa transliterate and to_ascii?
Transliterate converts characters to their ASCII equivalents, so Gölcük becomes Golcuk, while to_ascii strips the non-ASCII characters entirely, so the same string becomes Glck. The README presents them as two separate operations you can choose between.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/norman-babosa)Was this useful?