• Stars
    star
    390
  • Rank 106,305 (Top 3 %)
  • Language
    Ruby
  • License
    Other
  • Created about 15 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Ruby GetText, but 12x faster + 530x less garbage + simple + clean namespace + threadsafe + extendable + multiple backends

FastGettext

GetText but 12 x faster, 530 x less garbage, clean namespace (8 vs 26), simple and threadsafe!

It supports multiple backends (.mo, .po, .yml files, Database(ActiveRecord + any other), Chain, Loggers) and can easily be extended.

Example Rails application

Comparison

Hash FastGettext GetText ActiveSupport I18n::Simple
Speed* 0.08s 0.14s 1.75s 3.75s
Objects* 11K 15K 8017K 7107K
Included backends db, yml, mo, po, logger, chain mo yml (db/key-value/po/chain in other I18n backends)
*500.000 translations with ruby 2.5.3 through `bundle exec rake benchmark`

Setup

1. Install

gem install fast_gettext

2. Add a translation repository

From mo files (traditional/default)

FastGettext.add_text_domain('my_app', path: 'locale')

Or po files (less maintenance than mo)

FastGettext.add_text_domain('my_app', path: 'locale', type: :po)
# ignore_fuzzy: true to not use fuzzy translations
# report_warning: false to hide warnings about obsolete/fuzzy translations

Or yaml files (use I18n syntax/indentation)

# A single locale can be segmented in multiple yaml files but they all should be
# named with a `qq.yml` suffix, where `qq` is the locale name.
FastGettext.add_text_domain('my_app', path: 'config/locales', type: :yaml)

Or database (scaleable, good for many locales/translators)

# db access is cached <-> only first lookup hits the db
require "fast_gettext/translation_repository/db"
FastGettext::TranslationRepository::Db.require_models # load and include default models
FastGettext.add_text_domain('my_app', type: :db, model: TranslationKey)

3. Choose text domain and locale for translation

Do this once in every Thread. (e.g. Rails -> ApplicationController)

FastGettext.text_domain = 'my_app'
FastGettext.available_locales = ['de', 'en', 'fr', 'en_US', 'en_UK'] # only allow these locales to be set (optional)
FastGettext.locale = 'de'

4. Start translating

FastGettext supports all the translation methods of ruby-gettext with added support for block defaults. (to get *gettext methods, use FastGettext::TranslationAliased)

_() or gettext(): basic translation

extend FastGettext::Translation
_('Car') == 'Auto'             # found translation for 'Car'
_('not-found') == 'not-found'  # The msgid is returned by default

n_() or ngettext(): pluralization

n_('Car', 'Cars', 1) == 'Auto'
n_('Car', 'Cars', 2) == 'Autos' # German plural of Cars

You'll often want to interpolate the results of n_() using ruby builtin % operator.

n_('Car', '%{n} Cars', 2) % { n: count } == '2 Autos'

p_() or pgettext(): translation with context

p_('File', 'Open') == _("File\004Open") == "öffnen"
p_('Context', 'not-found') == 'not-found'

s_() or sgettext(): translation with namespace

s_('File|Open') == _('File|Open') == "öffnen"
s_('Context|not-found') == 'not-found'

The difference between s_() and p_() is largely based on how the translations are stored. Your preference will be based on your workflow and translation editing tools.

pn_() or pngettext(): context-aware pluralized

pn_('Fruit', 'Apple', 'Apples', 3) == 'Äpfel'
pn_('Fruit', 'Apple', 'Apples', 1) == 'Apfel'

sn_() or sngettext(): without context pluralized

sn_('Fruit|Apple', 'Apples', 3) == 'Äpfel'
sn_('Fruit|Apple', 'Apples', 1) == 'Apfel'

N_() and Nn_(): make dynamic translations available to the parser.

In many instances, your strings will not be found by the ruby parsing. These methods allow for those strings to be discovered.

N_("active"); N_("inactive"); N_("paused") # possible value of status for parser to find.
Nn_("active", "inactive", "paused")        # alternative method
_("Your account is %{account_state}.") % { account_state: _(status) }

Managing translations

mo/po-files

Generate .po or .mo files using GetText parser (example tasks at gettext_i18n_rails)

Tell Gettext where your .mo or .po files lie, e.g. for locale/de/my_app.po and locale/de/LC_MESSAGES/my_app.mo

FastGettext.add_text_domain('my_app', path: 'locale')

Use the original GetText to create and manage po/mo-files. (Work on a po/mo parser & reader that is easier to use has started, contributions welcome @ get_pomo )

Database

Example migration for ActiveRecord
The default plural separator is |||| but you may overwrite it (or suggest a better one...).

This is usable with any model DataMapper/Sequel or any other(non-database) backend, the only thing you need to do is respond to the self.translation(key, locale) call. If you want to use your own models, have a look at the default models to see what you want/need to implement.

To manage translations via a Web GUI, use a Rails application and the translation_db_engine

Rails

Try the gettext_i18n_rails plugin, it simplifies the setup.
Try the translation_db_engine, to manage your translations in a db.

Setting available_locales,text_domain or locale will not work inside the environment.rb, since it runs in a different thread then e.g. controllers, so set them inside your application_controller.

# config/environment.rb after initializers
Object.send(:include, FastGettext::Translation)
FastGettext.add_text_domain('accounting', path: 'locale')
FastGettext.add_text_domain('frontend', path: 'locale')
...

# app/controllers/application_controller.rb
class ApplicationController ...
  include FastGettext::Translation
  before_filter :set_locale
  def set_locale
    FastGettext.available_locales = ['de', 'en', ...]
    FastGettext.text_domain = 'frontend'
    FastGettext.set_locale(params[:locale] || session[:locale] || request.env['HTTP_ACCEPT_LANGUAGE'])
    session[:locale] = I18n.locale = FastGettext.locale
  end

Advanced features

Abnormal pluralisation

Plurals are selected by index, think of it as ['car', 'cars'][index]
A pluralisation rule decides which form to use e.g. in english its count == 1 ? 0 : 1.
If you have any languages that do not fit this rule, you have to add a custom pluralisation rule.

Via Ruby:

FastGettext.pluralisation_rule = ->(count){ count > 5 ? 1 : (count > 2 ? 0 : 2)}

Via mo/pofile:

Plural-Forms: nplurals=2; plural=n==2?3:4;

Plural expressions for all languages.

default_text_domain

If you only use one text domain, setting FastGettext.default_text_domain = 'app' is sufficient and no more text_domain= is needed

default_locale

If the simple rule of "first available_locale or 'en'" is not sufficient for you, set FastGettext.default_locale = 'de'.

default_available_locales

Fallback when no available_locales are set

with_locale

If there is content from different locales that you wish to display, you should use the with_locale option as below:

FastGettext.with_locale 'gsw_CH' do
  FastGettext._('Car was successfully created.')
end
# => "Z auto isch erfolgriich gspeicharat worda."

Chains

You can use any number of repositories to find a translation. Simply add them to a chain and when the first cannot translate a given key, the next is asked and so forth.

repos = [
  FastGettext::TranslationRepository.build('new', path: '....'),
  FastGettext::TranslationRepository.build('old', path: '....')
]
FastGettext.add_text_domain 'combined', type: :chain, chain: repos

Merge

In some cases you can benefit from using merge repositories as an alternative to chains. They behave nearly the same. The difference is in the internal data structure. While chain repos iterate over the whole chain for each translation, merge repositories select and store the first translation at the time a subordinate repository is added. This puts the burden on the load phase and speeds up the translations.

repos = [
  FastGettext::TranslationRepository.build('new', path: '....'),
  FastGettext::TranslationRepository.build('old', path: '....')
]
domain = FastGettext.add_text_domain 'combined', type: :merge, chain: repos

Downside of this approach is that you have to reload the merge repo each time a language is changed.

FastGettext.locale = 'de'
domain.reload

Logger

When you want to know which keys could not be translated or were used, add a Logger to a Chain:

repos = [
  FastGettext::TranslationRepository.build('app', path: '....')
  FastGettext::TranslationRepository.build('logger', type: :logger, callback: ->(key_or_array_of_ids) { ... }),
}
FastGettext.add_text_domain 'combined', type: :chain, chain: repos

If the Logger is in position #1 it will see all translations, if it is in position #2 it will only see the unfound. Unfound may not always mean missing, if you choose not to translate a word because the key is a good translation, it will appear nevertheless. A lambda or anything that responds to call will do as callback. A good starting point may be examples/missing_translations_logger.rb.

Plugins

Want an xml version? Write your own TranslationRepository!

# fast_gettext/translation_repository/wtf.rb
module FastGettext
  module TranslationRepository
    class Wtf
      define initialize(name,options), [key], plural(*keys) and
      either inherit from TranslationRepository::Base or define available_locales and pluralisation_rule
    end
  end
end

Multi domain support

If you have more than one gettext domain, there are two sets of functions available:

extend FastGettext::TranslationMultidomain

d_("domainname", "string") # finds 'string' in domain domainname
dn_("domainname", "string", "strings", 1) # ditto
dp_("domainname", "context", "key")
ds_("domainname", "context|key")
dnp_("domainname", "context", "string", "strings")
dns_("domainname", "context|string", "strings")

These are helper methods so you don't need to write:

FastGettext.with_domain("domainname") { _("string") }

It is useful in Rails plugins in the views for example. The second set of functions are D functions which search for string in all domains. If there are multiple translations in different domains, it returns them in random order (depends on the Ruby hash implementation).

extend FastGettext::TranslationMultidomain

D_("string") # finds 'string' in any domain
Dn_("string", "strings", 1) # ditto
Dp_("context", "key")
Ds_("context|key")
Dnp_("context", "string", "strings")
Dns_("context|string", "strings")

Alternatively you can use merge repository to achieve the same behavior.

Block defaults

All the translation methods (including MultiDomain) support a block default, a feature not provided by ruby-gettext. When a translation is not found, if a block is provided the block is always returned. Otherwise, a key is returned. Methods doing pluralization will attempt a simple translation of alternate keys.

_('not-found'){ "alternative default" } == alternate default

This block default is useful when the default is a very long passage of text that wouldn't make a useful key. You can also instrument logging not found keys.

_('terms-and-conditions'){
  load_terms_and_conditions
  request_terms_and_conditions_translation_from_legal
}

# Override _ with logging
def _(key, &block)
  result = gettext(key){ nil } # nil returned when not found
  log_missing_translation_key(key) if result.nil?
  result || (block ? block.call : key)
end

FAQ

Authors

Mo/Po-file parsing from Masao Mutoh, see vendor/README

Michael Grosser
[email protected]
License: MIT, some vendor parts under the same license terms as Ruby (see headers)
CI

More Repositories

1

parallel

Ruby: parallel processing made simple and fast
Ruby
4,052
star
2

parallel_tests

Ruby: 2 CPUs = 2x Testing Speed for RSpec, Test::Unit and Cucumber
Ruby
3,257
star
3

pru

Pipeable Ruby - forget about grep / sed / awk / wc ... use pure, readable Ruby!
Ruby
579
star
4

smusher

Ruby/CLI: Automatic lossless reduction of all your images
Ruby
555
star
5

maxitest

Minitest + all the features you always wanted.
Ruby
441
star
6

wwtd

WWTD: Travis simulator - faster + no more waiting for build emails
Ruby
366
star
7

rspec-instafail

Show failing specs instantly
Ruby
272
star
8

gettext_i18n_rails

Rails: FastGettext, I18n integration -- simple, threadsafe and fast!
Ruby
257
star
9

test_after_commit

Make after_commit callbacks fire in tests for Rails 3+ with transactional_fixtures = true.
Ruby
240
star
10

rpx_now

Ruby: RPXNow.com user login/creation and view helpers Facebook, Twitter, Google, MSN, OpenID, MySpace, Yahoo -- All in One
Ruby
230
star
11

single_cov

Actionable code coverage.
Ruby
226
star
12

bitfields

n Booleans = 1 Integer, saves columns and migrations.
Ruby
221
star
13

i18n_data

Ruby: country/language names and 2-letter-code pairs, in 85 languages, for country/language i18n
Ruby
186
star
14

vendorer

Vendorer keeps your dependencies documented, cached and up to date
Ruby
186
star
15

ar_after_transaction

Execute irreversible actions only when transactions are not rolled back
Ruby
155
star
16

url_store

Data securely stored in urls.
Ruby
146
star
17

kennel

Datadog monitors/dashboards/slos as code, avoid chaotic management via UI
Ruby
128
star
18

ruco

Desktop-style, Intuitive, Commandline Editor in Ruby. "Better than nano, simpler than vim."
Ruby
125
star
19

programming_pearls

eBook: Programming Pearls Rewritten in Ruby
Ruby
108
star
20

easy_esi

Rails: Cached pages with updated partials
Ruby
106
star
21

reduce

Ruby/CLI: minify javascript + stylesheets, lossless image optimization
JavaScript
90
star
22

git-autobisect

Find the first broken commit without having to learn git bisect
Ruby
84
star
23

parallel_split_test

Split a big test file into multiple chunks and run them in parallel
Ruby
81
star
24

tic_tac_toe

Play Tic-Tac-Toe in Ruby using Curses(full-screen-commandline app)
Ruby
71
star
25

sort_alphabetical

Ruby: sort UTF8 Strings alphabetical via Enumerable extension
Ruby
69
star
26

youtube_search

Search youtube via this simple ruby api
Ruby
67
star
27

soft_deletion

Explicit soft deletion for ActiveRecord via deleted_at and default scope
Ruby
67
star
28

simple_auto_complete

Rails: Simple, customizable, unobstrusive - Autocomplete
JavaScript
64
star
29

dispel

Ruby: Remove evil curses
Ruby
63
star
30

preoomkiller

Softly kills your process with SIGTERM before it runs out of memory.
Ruby
63
star
31

single_test

Rake tasks to invoke single tests/specs with rakish syntax
Ruby
60
star
32

dotfiles

Clean and powerful dotfiles -- bash / git / ruby / irb / nano / ruco
Shell
57
star
33

bundler-organization_audit

Automatic Gemfile security audit for all your organizaition/user repos
Ruby
52
star
34

fallback

Fallback when original attribute is not present or somethings not right.
Ruby
47
star
35

record_activities

Rails: Record user activities without controller helpers, build on top of userstamps plugin
Ruby
47
star
36

ie_iframe_cookies

Rails: Normal cookies inside IFrames for IE via P3P headers
Ruby
45
star
37

cachy

Ruby: Caching library to simplify and organize caching
Ruby
44
star
38

zombie_passenger_killer

Guaranteed zombie passengers death.
Ruby
44
star
39

tracked_plugins

script/plugin now keeps track of installation, can list urls/revisions/install-dates/plugin-locally-hacked? and update.
Ruby
43
star
40

stub_server

Boot up a real server to serve testing replies
Ruby
43
star
41

rails2_asset_pipeline

Familiar asset handling for those stuck on Rails 2
Ruby
41
star
42

request_recorder

Record your rack/rails requests and store them for future inspection
Ruby
40
star
43

ar_merge

Merge 2 ActiveRecords, preserving attributes, associations and counters
Ruby
40
star
44

gem-dependent

How many gems depend on your gem ?
Ruby
39
star
45

travis_dedup

Stop all builds on the same PR when a new job starts
Ruby
38
star
46

safe_regexp

Ruby Regex Timeout / Backtracking Bomb Safety
Ruby
30
star
47

translation_db_engine

Rails/AR: engine to manage translations inside a database
Ruby
30
star
48

rubinjam

Covert ruby gem to universal cross-platform binary
Ruby
30
star
49

gettext_i18n_rails_example

Rails example application using FastGettext + gettext_i18n_rails + gettext_test_log
Ruby
29
star
50

url_to_media_tag

Convert an Youtube/Vimeo/Image... Url to image or video embed.
Ruby
27
star
51

forking_test_runner

Run every test in a fork to avoid pollution and get clean output per test
Ruby
27
star
52

restful_catch_all_route

One rule for complete restful routing, no helpers, no worries.
Ruby
26
star
53

scopify

Add named scopes and chainable scopes to any Object / Model.
Ruby
24
star
54

key_value

Abuse Sql database as Key-Value Store
Ruby
22
star
55

acts_as_feed

Rails/AR: Transform a Model into a Feed Representation (Feed Reader)
Ruby
22
star
56

sinatra-magick

Sinatra app to manipulate images given by url via mini_magick and image_magick. completly evented
Ruby
22
star
57

concern

Ruby: Seperation of concerns without meta-madness and namespace pollution.
Ruby
22
star
58

has_a_location

AR: Easy location (lat/long) handling + in_radius + find on a given map section
Ruby
22
star
59

virtual_asset_path

Improve Rails Asset Caching with MD5 and virtual folders
Ruby
21
star
60

s3_slider

jQuery: slideshow displaying images + description, ~1kb for js+css, simple and elegant
HTML
21
star
61

git-whence

Find the merge and pull request a commit came from + fuzzy search for cherry-picks
Ruby
21
star
62

readable_random

Ruby: Readable random strings for coupons or tokens
Ruby
20
star
63

s3_meta_sync

Efficiently sync folders with s3 using a metadata file with md5 sums.
Ruby
20
star
64

testrbl

Run ruby Minitest/Test::Unit/Spec/Shoulda tests by line-number / files / folder
Ruby
20
star
65

countries_and_languages

Rails: Countries and languages in I18n.locale for select_tag or output in 85 languages
Ruby
19
star
66

autoscaling

Amazon AWS/EC2 autoscaling All in one
Shell
19
star
67

helpful_fields

Simple & Helpful Field Helpers for Rails e.g. check_box_with_label or prefilled fields from params
Ruby
18
star
68

go-testcov

`go test` that fails on uncovered lines and shows them
Go
18
star
69

cleanser

Find polluting test by bisecting your tests.
Ruby
17
star
70

repo_dependency_graph

Graph the dependencies of your repositories
Ruby
16
star
71

get_pomo

Ruby/Gettext: A .mo and .po file parser/generator
Ruby
16
star
72

honeypot

Rails: Simple honeypots
Ruby
16
star
73

random_records

Rails/AR: Fast random records for ActiveRecord
Ruby
16
star
74

rpx_now_example

Example Rails app using RPXNow plugin
Ruby
16
star
75

logrecycler

Re-process logs from applications you cannot modify to convert them to json and add prometheus/stats metrics
Go
15
star
76

after_commit_exception_notification

Rails: Get notified when an after_commit block blows up
Ruby
15
star
77

textpow

Read TextMate syntax files and parse text with them
Ruby
14
star
78

codeclimate_batch

Report a batch of codeclimate results by merging and from multiple servers
Ruby
13
star
79

dockerb

Dockerfile.erb - use ruby in your dynamic Dockerfile
Ruby
12
star
80

cia

Central Internal Auditing: Audit model events like update/create/delete + attribute changes + grouped them by transaction, in normalized table layout for easy query access.
Ruby
12
star
81

cc-amend

Unify reports from all your tests runs and send them as one.
Ruby
12
star
82

gem_of_thrones

Everybody wants to be king, but only one can rule (synchronized via a distributed cache)
Ruby
12
star
83

github-grep

Grep through github search results
Ruby
11
star
84

kube-leader

Simple Kubernetes Leader Election via ConfigMap as ENTRYPOINT
Go
10
star
85

travis_cron

Run travis as cron (also supports travis PRO)
Ruby
10
star
86

air_man

Email notifications for high-frequency Airbrake errors
Ruby
10
star
87

gem_on_demand

Run your own gem server that fetches from github, uses tags as version and builds gems on demand
Ruby
9
star
88

i18n-backend-http

Rails I18n Backend for Http APIs with etag-aware distributed background polling and lru-memory+[memcache] caching.
Ruby
9
star
89

matching_bundle

Find a matching bundler version for a Gemfile and use it
Ruby
9
star
90

active_record-comments

Add comments to ActiveRecord queries to see where they came from or what user caused them
Ruby
9
star
91

translated_attributes

AR/Rails translatable attributes through virtual fields
Ruby
9
star
92

cmd2json

Covert command output and exit status to json to pipe them atomically into logs
Ruby
8
star
93

autolang

Automatic translation to a new language for Gettext/JSON using Google translate
Ruby
8
star
94

db_graph

Easy graphs from AR date fields
Ruby
8
star
95

organization_license_audit

Audit all licenses used by your github organization/user
Ruby
8
star
96

ruby-cli-daemon

Make all gem executables execute instantly
Ruby
8
star
97

ar_multi_threaded_transactional_tests

Execute multithreaded code while still using transactional fixtures by synchronizing db access to a single connection
Ruby
8
star
98

rhr

Ruby Hypertext Refinement -- the ease of PHP with the elegance of Ruby
Ruby
7
star
99

git-graph

Date porn from your git history
Ruby
7
star
100

unicorn_wrangler

Unicorn: out of band GC / restart on max memory bloat / restart after X requests
Ruby
7
star