• Stars
    star
    3,702
  • Rank 11,370 (Top 0.3 %)
  • Language
    Ruby
  • License
    MIT License
  • Created over 14 years ago
  • Updated 8 months ago

Reviews

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

Repository Details

It's a small library to provide the I18n translations on the Javascript. It comes with Rails support.

i18n.js

Export i18n translations to JSON.
A perfect fit if you want to export translations to JavaScript.

Oh, you don't use Ruby? No problem! You can still use i18n-js
and the companion JavaScript package.

Tests Gem Gem MIT License

Installation

gem install i18n-js

Or add the following line to your project's Gemfile:

gem "i18n-js"

Create a default configuration file in ./config/i18n.yml

i18n init

Usage

About patterns:

  • Patterns can use * as a wildcard and can appear more than once.
    • * will include everything
    • *.messages.*
  • Patterns starting with ! are excluded.
    • !*.activerecord.* will exclude all ActiveRecord translations.
  • You can use groups:
    • {pt-BR,en}.js.* will include only pt-BR and en translations, even if more languages are available.

Note:

Patterns use glob, so check it out for the most up-to-date documentation about what's available.

The config file:

---
translations:
  - file: app/frontend/locales/en.json
    patterns:
      - "*"
      - "!*.activerecord"
      - "!*.errors"
      - "!*.number.nth"

  - file: app/frontend/locales/:locale.:digest.json
    patterns:
      - "*"

The output path can use the following placeholders:

  • :locale - the language that's being exported.
  • :digest - the MD5 hex digest of the exported file.

The example above could generate a file named app/frontend/locales/en.7bdc958e33231eafb96b81e3d108eff3.json.

The config file is processed as erb, so you can have dynamic content on it if you want. The following example shows how to use groups from a variable.

---
<% group = "{en,pt}" %>

translations:
  - file: app/frontend/translations.json
    patterns:
      - "<%= group %>.*"
      - "!<%= group %>.activerecord"
      - "!<%= group %>.errors"
      - "!<%= group %>.number.nth"

Exporting locale.yml to locale.json

Your i18n yaml file can be exported to JSON using the Ruby API or the command line utility. Examples of both approaches are provided below:

The Ruby API:

require "i18n-js"

# The following call performs the same task as the CLI `i18n export` command
I18nJS.call(config_file: "config/i18n.yml")

# You can provide the config directly using the following
config = {
  "translations"=>[
    {"file"=>"app/javascript/locales/:locale.json", "patterns"=>["*"]}
  ]
}

I18nJS.call(config: config)
#=> ["app/javascript/locales/de.json", "app/javascript/locales/en.json"]

The CLI API:

$ i18n --help
Usage: i18n COMMAND FLAGS

Commands:

- init: Initialize a project
- export: Export translations as JSON files
- version: Show package version
- plugins: List plugins that will be activated
- lint:translations: Check for missing translations
- lint:scripts: Lint files using TypeScript

Run `i18n COMMAND --help` for more information on specific commands.

By default, i18n will use config/i18n.yml and config/environment.rb as the configuration files. If you don't have these files, then you'll need to specify both --config and --require.

Plugins

Built-in plugins:

embed_fallback_translations:

Embed fallback translations inferred from the default locale. This can be useful in cases where you have multiple large translation files and don't want to load the default locale together with the target locale.

To use it, add the following to your configuration file:

---
embed_fallback_translations:
  enabled: true
export_files:

By default, i18n-js will export only JSON files out of your translations. This plugin allows exporting other file formats. To use it, add the following to your configuration file:

---
export_files:
  enabled: true
  files:
    - template: path/to/template.erb
      output: "%{dir}/%{base_name}.ts"

You can export multiple files by defining more entries.

The output name can use the following placeholders:

  • %{dir}: the directory where the translation file is.
  • %{name}: file name with extension.
  • %{base_name}: file name without extension.
  • %{digest}: MD5 hexdigest from the generated file.

The template file must be a valid eRB template. You can execute arbitrary Ruby code, so be careful. An example of how you can generate a file can be seen below:

/* eslint-disable */
<%= banner %>

import { i18n } from "config/i18n";

i18n.store(<%= JSON.pretty_generate(translations) %>);

This template is loading the instance from config/i18n and storing the translations that have been loaded. The banner(comment: "// ", include_time: true) method is built-in. The generated file will look something like this:

/* eslint-disable */
// File generated by i18n-js on 2022-12-10 15:37:00 +0000

import { i18n } from "config/i18n";

i18n.store({
  en: {
    "bunny rabbit adventure": "bunny rabbit adventure",
    "hello sunshine!": "hello sunshine!",
    "time for bed!": "time for bed!",
  },
  es: {
    "bunny rabbit adventure": "conejito conejo aventura",
    bye: "adios",
    "time for bed!": "hora de acostarse!",
  },
  pt: {
    "bunny rabbit adventure": "a aventura da coelhinha",
    bye: "tchau",
    "time for bed!": "hora de dormir!",
  },
});

Plugin API

You can transform the exported translations by adding plugins. A plugin must inherit from I18nJS::Plugin and can have 4 class methods (they're all optional and will default to a noop implementation). For real examples, see lib/i18n-js/embed_fallback_translations_plugin.rb and lib/i18n-js/export_files_plugin.rb

# frozen_string_literal: true

module I18nJS
  class SamplePlugin < I18nJS::Plugin
    # This method is responsible for transforming the translations. The
    # translations you'll receive may be already be filtered by other plugins
    # and by the default filtering itself. If you need to access the original
    # translations, use `I18nJS.translations`.
    def transform(translations:)
      # transform `translations` here…

      translations
    end

    # In case your plugin accepts configuration, this is where you must validate
    # the configuration, making sure only valid keys and type is provided.
    # If the configuration contains invalid data, then you must raise an
    # exception using something like
    # `raise I18nJS::Schema::InvalidError, error_message`.
    #
    # Notice the validation will only happen when the plugin configuration is
    # set (i.e. the configuration contains your config key).
    def validate_schema
      # validate plugin schema here…
    end

    # This method must set up the basic plugin configuration, like adding the
    # config's root key in case your plugin accepts configuration (defined via
    # the config file).
    #
    # If you don't add this key, the linter will prevent non-default keys from
    # being added to the configuration file.
    def setup
      # If you plugin has configuration, uncomment the line below
      # I18nJS::Schema.root_keys << config_key
    end

    # This method is called whenever `I18nJS.call(**kwargs)` finishes exporting
    # JSON files based on your configuration.
    #
    # You can use it to further process exported files, or generate new files
    # based on the translations that have been exported.
    def after_export(files:)
      # process exported files here…
    end
  end
end

The class I18nJS::Plugin implements some helper methods that you can use:

  • I18nJS::Plugin#config_key: the configuration key that was inferred out of your plugin's class name.
  • I18nJS::Plugin#config: the plugin configuration.
  • I18nJS::Plugin#enabled?: whether the plugin is enabled or not based on the plugin's configuration.

To distribute this plugin, you need to create a gem package that matches the pattern i18n-js/*_plugin.rb. You can test whether your plugin will be found by installing your gem, opening a iRB session and running Gem.find_files("i18n-js/*_plugin.rb"). If your plugin is not listed, then you need to double check your gem load path and see why the file is not being loaded.

Listing missing translations

To list missing and extraneous translations, you can use i18n lint:translations. This command will load your translations similarly to how i18n export does, but will output the list of keys that don't have a matching translation against the default locale. Here's an example:

$ i18n lint:translations
=> Config file: "./config/i18n.yml"
=> Require file: "./config/environment.rb"
=> Check "./config/i18n.yml" for ignored keys.
=> en: 232 translations
=> pt-BR: 5 missing, 1 extraneous, 1 ignored
   - pt-BR.actors.github.metrics (missing)
   - pt-BR.actors.github.metrics_hint (missing)
   - pt-BR.actors.github.repo_metrics (missing)
   - pt-BR.actors.github.repository (missing)
   - pt-BR.actors.github.user_metrics (missing)
   - pt-BR.github.repository (extraneous)

This command will exit with status 1 whenever there are missing translations. This way you can use it as a CI linting tool.

You can ignore keys by adding a list to the config file:

---
translations:
  - file: app/frontend/locales/en.json
    patterns:
      - "*"
      - "!*.activerecord"
      - "!*.errors"
      - "!*.number.nth"

  - file: app/frontend/locales/:locale.:digest.json
    patterns:
      - "*"

lint_translations:
  ignore:
    - en.mailer.login.subject
    - en.mailer.login.body

Note:

In order to avoid mistakenly ignoring keys, this configuration option only accepts the full translation scope, rather than accepting a pattern like pt.ignored.scope.*.

Linting your JavaScript/TypeScript files

To lint your script files and check for missing translations (which can signal that you're either using wrong scopes or forgot to add the translation), use i18n lint:scripts. This command will parse your JavaScript/TypeScript files and extract all scopes being used. This command requires a Node.js runtime. You can either specify one via --node-path, or let the plugin infer a binary from your $PATH.

The comparison will be made against the export JSON files, which means it'll consider transformations performed by plugins (e.g. the output files may be affected by embed_fallback_translations plugin).

The translations that will be extract must be called as one of the following ways:

  • i18n.t(scope, options)
  • i18n.translate(scope, options)
  • t(scope, options)

Notice that only literal strings can be used, as in i18n.t("message"). If you're using dynamic scoping through variables (e.g. const scope = "message"; i18n.t(scope)), they will be skipped.

$ i18n lint:scripts
=> Config file: "./config/i18n.yml"
=> Require file: "./config/environment.rb"
=> Node: "/Users/fnando/.asdf/shims/node"
=> Available locales: [:en, :es, :pt]
=> Patterns: ["!(node_modules)/**/*.js", "!(node_modules)/**/*.ts", "!(node_modules)/**/*.jsx", "!(node_modules)/**/*.tsx"]
=> 9 translations, 11 missing, 4 ignored
   - test/scripts/lint/file.js:1:1: en.js.missing
   - test/scripts/lint/file.js:1:1: es.js.missing
   - test/scripts/lint/file.js:1:1: pt.js.missing
   - test/scripts/lint/file.js:2:8: en.base.js.missing
   - test/scripts/lint/file.js:2:8: es.base.js.missing
   - test/scripts/lint/file.js:2:8: pt.base.js.missing
   - test/scripts/lint/file.js:4:8: en.js.missing
   - test/scripts/lint/file.js:4:8: es.js.missing
   - test/scripts/lint/file.js:4:8: pt.js.missing
   - test/scripts/lint/file.js:6:1: en.another_ignore_scope
   - test/scripts/lint/file.js:6:1: es.another_ignore_scope

This command will list all locales and their missing translations. To avoid listing a particular translation, you can set lint_scripts.ignore or lint_translations.ignore in your config file.

---
translations:
  - file: app/frontend/translations.json
    patterns:
      - "*"

lint_scripts:
  ignore:
    - ignore_scope # will ignore this scope on all languages
    - pt.another_ignore_scope # will ignore this scope only on `pt`

You can also set the patterns that will be looked up. By default, it scans all JavaScript and TypeScript files that don't live on node_modules.

---
translations:
  - file: app/frontend/translations.json
    patterns:
      - "*"

lint_scripts:
  patterns:
    - "app/assets/**/*.ts"

Automatically export translations

Using watchman

Create a script at bin/i18n-watch.

#!/usr/bin/env bash

root=`pwd`

watchman watch-del "$root"
watchman watch-project "$root"
watchman trigger-del "$root" i18n

watchman -j <<-JSON
[
  "trigger",
  "$root",
  {
    "name": "i18n",
    "expression": [
      "anyof",
      ["match", "config/locales/**/*.yml", "wholename"],
      ["match", "config/i18n.yml", "wholename"]
    ],
    "command": ["i18n", "export"]
  }
]
JSON

# If you're running this through Foreman,
# then uncomment the following lines:
# while true; do
#   sleep 1
# done

Make it executable with chmod +x bin/i18n-watch. To watch for changes, run ./bin/i18n-watch. If you're using Foreman, make sure you uncommented the lines that keep the process running (while..), and add something like the following line to your Procfile:

i18n: ./bin/i18n-watch

Using guard

Install guard and guard-compat. Then create a Guardfile with the following configuration:

guard(:"i18n-js",
      run_on_start: true,
      config_file: "./config/i18n.yml",
      require_file: "./config/environment.rb") do
  watch(%r{^(app|config)/locales/.+\.(yml|po)$})
  watch(%r{^config/i18n.yml$})
  watch("Gemfile")
end

If your files are located in a different path, remember to configure file paths accordingly.

Now you can run guard start -i.

Using listen

Create a file under config/initializers/i18n.rb with the following content:

Rails.application.config.after_initialize do
  require "i18n-js/listen"
  I18nJS.listen
end

The code above will watch for changes based on config/i18n.yml and config/locales. You can customize these options:

  • config_file - i18n-js configuration file
  • locales_dir - one or multiple directories to watch for locales changes
  • options - passed directly to listen
  • run_on_start - export files on start. Defaults to true. When disabled, files will be exported only when there are file changes.

Example:

I18nJS.listen(
  config_file: "config/i18n.yml",
  locales_dir: ["config/locales", "app/views"],
  options: {only: %r{.yml$}},
  run_on_start: false
)

Integrating with your frontend

You're done exporting files, now what? Well, go to i18n to discover how to use the NPM package that loads all the exported translation.

FAQ

I'm running v3. Is there a migration plan?

There's a document outlining some of the things you need to do to migrate from v3 to v4. It may not be as complete as we'd like it to be, so let us know if you face any issues during the migration that is not outlined in that document.

How can I export translations without having a database around?

Some people may have a build process using something like Docker that don't necessarily have a database available. In this case, you may define your own loading file by using something like i18n export --require ./config/i18n_export.rb, where i18n_export.rb may look like this:

# frozen_string_literal: true

require "bundler/setup"
require "rails"
require "active_support/railtie"
require "action_view/railtie"

I18n.load_path += Dir["./config/locales/**/*.yml"]

Note:

You may not need to load the ActiveSupport and ActionView lines, or you may need to add additional requires for other libs. With this approach you have full control on what's going to be loaded.

Maintainer

Contributors

Contributing

For more details about how to contribute, please read https://github.com/fnando/i18n-js/blob/main/CONTRIBUTING.md.

License

The gem is available as open source under the terms of the MIT License. A copy of the license can be found at https://github.com/fnando/i18n-js/blob/main/LICENSE.md.

Code of Conduct

Everyone interacting in the i18n-js project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

More Repositories

1

browser

Do some browser detection with Ruby. Includes ActionController integration.
Ruby
2,388
star
2

kitabu

A framework for creating e-books from Markdown using Ruby. Using the Prince PDF generator, you'll be able to get high quality PDFs. Also supports EPUB, Mobi, Text and HTML generation.
Ruby
659
star
3

recurrence

A simple library that handles recurring events.
Ruby
556
star
4

sparkline

Generate SVG sparklines with JavaScript without any external dependency.
JavaScript
501
star
5

paypal-recurring

PayPal Express Checkout API Client for recurring billing.
Ruby
257
star
6

cpf_cnpj

πŸ‡§πŸ‡· Validate, generate and format CPF/CNPJ numbers. Include command-line tools.
Ruby
220
star
7

password_strength

Check password strength against several rules. Includes ActiveRecord/ActiveModel support.
JavaScript
182
star
8

cpf

πŸ‡§πŸ‡· Validate, generate and format CPF numbers
TypeScript
161
star
9

pagseguro

Um plugin para o Ruby on Rails que permite utilizar o PagSeguro
Ruby
141
star
10

coupons

Coupons is a Rails engine for creating discount coupons.
Ruby
140
star
11

cpf_cnpj.js

Validate, generate and format CPF/CNPJ numbers
JavaScript
118
star
12

i18n

A small library to provide the I18n translations on the JavaScript.
TypeScript
113
star
13

uptime_checker

Check if your sites are online for $7/mo.
112
star
14

module

Define namespaces as constructor functions (or any object).
JavaScript
105
star
15

qe

A simple interface over several background job libraries like Resque, Sidekiq and DelayedJob.
Ruby
102
star
16

has_calendar

A view helper that creates a calendar using a table. You can easily add events with any content.
Ruby
101
star
17

sinatra-subdomain

Separate routes for subdomains in Sinatra apps
Ruby
96
star
18

validators

Some ActiveModel/ActiveRecord validators
Ruby
96
star
19

dotfiles

My dotfiles
Shell
88
star
20

rack-api

Create web app APIs that respond to one or more formats using an elegant DSL.
Ruby
86
star
21

notifier

Send system notifications on several platforms with a simple and unified API. Currently supports Notification Center, Libnotify, OSD, KDE (Knotify and Kdialog) and Snarl
Ruby
84
star
22

factory_bot-preload

Preload factories (factory_bot) just like fixtures. It will be easy and, probably, faster!
Ruby
83
star
23

cnpj

πŸ‡§πŸ‡· Validate, generate and format CNPJ numbers
TypeScript
81
star
24

dispatcher-js

Simple jQuery dispatcher for web apps.
JavaScript
75
star
25

gem-open

Open gems into your favorite editor by running a specific gem command
Ruby
69
star
26

test_notifier

Display system notifications (dbus, growl and snarl) after running tests. It works on Mac OS X, Linux and Windows. Powerful when used with Autotest ZenTest gem for Rails apps.
Ruby
63
star
27

test_squad

Running JavaScript tests on your Rails app, the easy way.
Ruby
56
star
28

vscode-linter

Extension for code linting, all in one package. New linters can be easily added through an extension framework.
TypeScript
56
star
29

has_friends

Add friendship support to Rails apps with this plugin
Ruby
55
star
30

breadcrumbs

Breadcrumbs is a simple Rails plugin that adds a breadcrumbs object to controllers and views.
Ruby
55
star
31

minitest-utils

Some utilities for your Minitest day-to-day usage.
Ruby
52
star
32

photomatic

Your photography is what matters.
Ruby
50
star
33

normalize_attributes

Sometimes you want to normalize data before saving it to the database like down casing e-mails, removing spaces and so on. This Rails plugin allows you to do so in a simple way.
Ruby
49
star
34

burgundy

A simple wrapper for objects (think of Burgundy as a decorator/presenter) in less than 150 lines.
Ruby
49
star
35

ar-uuid

Override migration methods to support UUID columns without having to be explicit about it.
Ruby
46
star
36

rubygems_proxy

Rack app for caching RubyGems files. Very useful in our build server that sometimes fails due to our network or rubygems.org timeout.
Ruby
43
star
37

post_commit

Post commit allows you to notify several services with a simple and elegant DSL. Five services are supported for now: Basecamp, Campfire, FriendFeed, LightHouse and Twitter.
Ruby
42
star
38

permalink

Add permalink support to Rails apps with this plugin
Ruby
40
star
39

keyring-node

Simple encryption-at-rest with key rotation support for Node.js.
JavaScript
39
star
40

superconfig

Access environment variables. Also includes presence validation, type coercion and default values.
Ruby
38
star
41

sublime-better-ruby

Sublime Text Ruby package (snippets, builder, syntax highlight)
Ruby
37
star
42

simple_presenter

A simple presenter/facade/decorator/whatever implementation.
Ruby
33
star
43

voltage

A simple observer implementation on POROs (Plain Old Ruby Object) and ActiveRecord objects.
Ruby
31
star
44

redis-settings

Store application and user settings on Redis. Comes with ActiveRecord support.
Ruby
31
star
45

tokens

Add token support to Rails apps with this plugin
Ruby
31
star
46

boppers

A simple bot framework for individuals.
Ruby
29
star
47

babel-schmooze-sprockets

Add Babel support to sprockets using Schmooze.
JavaScript
29
star
48

streamdeck

A lean framework for developing Elgato Stream Deck plugins.
TypeScript
28
star
49

sublime-text

My SublimeText settings
26
star
50

has_ratings

Add rating support to Rails apps with this plugin
Ruby
25
star
51

commentable

Add comment support to Rails apps with this plugin
Ruby
23
star
52

sinatra-basic-auth

Authentication with BasicAuth that can require different credentials for different realms.
Ruby
23
star
53

rails-routes

Enable config/routes/*.rb on your Rails application.
Ruby
23
star
54

aitch

A simple HTTP client.
Ruby
21
star
55

swiss_knife

Here's my swiss-knife Rails helpers.
Ruby
21
star
56

messages-app

Use alert messages in your README.
HTML
19
star
57

rails-env

Avoid environment detection on Rails
Ruby
19
star
58

defaults

Add default value for ActiveRecord attributes
Ruby
18
star
59

ar-check

Enable PostgreSQL's CHECK constraints on ActiveRecord migrations
Ruby
17
star
60

email_data

This project is a compilation of datasets related to emails. Includes disposable emails, disposable domains, and free email services.
Ruby
17
star
61

sublime-text-screencasts

Screencasts sobre Sublime Text
HTML
17
star
62

simple_auth

SimpleAuth is an authentication library to be used when everything else is just too complicated.
Ruby
17
star
63

attr_keyring

Simple encryption-at-rest with key rotation support for Ruby.
Ruby
17
star
64

has_bookmarks

Add bookmark support to Rails apps with this plugin
Ruby
17
star
65

paginate

Paginate collections using SIZE+1 to determine if there is a next page. Includes ActiveRecord and ActionView support.
Ruby
16
star
66

pry-meta

Meta package that requires several pry extensions.
Ruby
15
star
67

svg_optimizer

Some SVG optimization based on Node's SVGO
Ruby
15
star
68

react-starter-pack

Starter-pack for react + webpack + hot reload + mocha + enzyme + production build
JavaScript
15
star
69

check_files

Check non-reloadable files changes on Rails apps.
Ruby
15
star
70

url_signature

Create and verify signed urls. Supports expiration time.
Ruby
15
star
71

activities

Activities is a gem that enables social activities in ActiveRecord objects.
Ruby
14
star
72

using-es6-with-asset-pipeline-on-ruby-on-rails

Example for my article about ES6 + Asset Pipeline
Ruby
14
star
73

whiteboard

A small app using Canvas + Socket.IO to provide a shared whiteboard.
JavaScript
14
star
74

sublime-better-rspec

Better RSpec syntax highlighting, with matchers for v3. Also includes implementation/spec toggling command.
Python
13
star
75

ar-sequence

Add support for PostgreSQL's SEQUENCE on ActiveRecord migrations.
Ruby
13
star
76

page_meta

Easily define <meta> and <link> tags. I18n support for descriptions, keywords and titles.
Ruby
13
star
77

boppers-uptime

A bopper to check if your sites are online.
Ruby
13
star
78

has_versions

A simple plugin to version ActiveRecord objects
Ruby
13
star
79

csr

Generate CSR (Certificate Signing Request) using Ruby and OpenSSL.
Ruby
13
star
80

haikunate

Generate Heroku-like memorable random names like adorable-ox-1234.
Ruby
13
star
81

module-component

Define auto-discoverable HTML UI components using Module.js.
JavaScript
12
star
82

alfred-workflows

Alfred workflows
12
star
83

twitter_cleanup

Remove old tweets periodically using Github Actions
Ruby
12
star
84

storage

This gem provides a simple API for multiple storage backends. Supported storages: Amazon S3 and FileSystem.
Ruby
12
star
85

has_layout

Add conditional layouts with ease
Ruby
11
star
86

kalendar

A view helper that creates a calendar using a table. You can easily add events with any content.
Ruby
11
star
87

stellar-paperwallet

Make paper wallets to keep your Stellar addresses safe.
JavaScript
10
star
88

tagger

Tagging plugin for Ruby on Rails apps
Ruby
10
star
89

page_title

Set the page title on Rails apps.
Ruby
10
star
90

dogo

A simple URL shortener service backed by Redis.
Ruby
10
star
91

has_notifications

This plugin was created to act as a proxy between different notification systems (Mail, Jabber, etc) based on the user's preferences.
Ruby
10
star
92

formatter

has_markup is an ActiveRecord plugin that integrates Tidy, Markdown, Textile and sanitize helper method into a single plugin.
Ruby
10
star
93

shortcuts

Because mouse is for noobies.
Ruby
9
star
94

ar-enum

Add support for creating `ENUM` types in PostgreSQL with ActiveRecord
Ruby
9
star
95

ar-timestamptz

Make ActiveRecord's PostgreSQL adapter use timestamptz as datetime columns.
Ruby
9
star
96

parsel-js

Encrypt and decrypt data with a given key.
JavaScript
8
star
97

access_token

Access token for client-side and API authentication.
Ruby
8
star
98

ember-and-rails

Ruby
8
star
99

sinatra-oauth-twitter

Sample app used on Guru-SP meetup
Ruby
8
star
100

bolt

A nicer test runner for golang
Go
8
star