Different translations per environment - ruby-on-rails

I'd like certain translations to have different values depending on the environment.
Rails.env.test? && I18n.t('foo') # => 'A value'
Rails.env.development? && I18n.t('foo') # => 'A different value'
For accomplishing this I can imagine a few approaches:
Ability to embed ERB in en.yml
Ability to create per-environment locale files, e.g. en.test.yml
Ability to directly set an entry: I18n.set('foo', 'bar') if Rails.env.test?
However I couldn't find any of these solutions ready to use.
Is there one?

I think that You need something like this:
en.production.yml:
en:
production:
foo: "Foo"
bar: "Bar"
en.development.yml:
en:
development:
foo: "foo"
bar: "bar"
en.test.yml:
en:
test:
foo: "-foo-"
bar: "-bar-"
and using is views and controllers:
I18n.t("#{Rails.env}.foo")
I18n.t("#{Rails.env}.bar")
Update:
If You just need to substitute variables to translation, use interpolation:
en.yml:
en:
foo: "Foo %{variable}"
bar: "%{var} Bar"
and using:
I18n.t('foo', :variable => 'Bar')
I18n.t('bar', :var => 'Foo')

Late to the party. I've created a gem that does that by using environment variables. i18n-env-var-lookup . You can use it in combination with an environment variable loader such as dotenv-rails
My specific use case is a bit unique though. In our org, we have an existing rails app that we wanted to "white-label" for another project by another team in the org. We wanted to share the same source code repo for both projects while only change the site name. Given that there are already a few thousands entries in the locale files and close to a hundred of them contain the site name, it would be a bad practice to update all the templates to pass the site name as a variable. Other suggestions that we found in related questions are also no good in our case. We want to keep the locale files exactly the same for both project so that we can avoid messing with the source code and manage the locale files easily with 3rd-party localization service.
Therefore we turned to implementing the gem, and it solves our exact problem.

Related

Use Rails 6 I18n translations for custom/user-specific naming schemas

What I would like to do is utilize the I18n localization structure to handle organziation-specific naming schemas, independently of the users actual local. Something like:
Default Naming Schema
show.en.yml
en:
show:
title: Component
Organization A Nameing Schema
show.org_a.yml
org_a:
show:
title: Widget
Organization B Nameing Schema
show.org_b.yml
org_b:
show:
title: Sprocket
I've tried to just set a custom local using I18n.locale = organziation.slug.to_sym || I18n.default_locale (where slug would be org_a, org_b, etc.), but that just yields a :org_a is not a valid locale error. Unfortunately, searching for possible solutions has not been all that fruitful.
Is there a way to add custom locals, or should I be approaching this problem a different way (using Rails 6)?
This works in Rails 4.2 (since that is what I have easy access to right now) to allow for custom locales but it should work for Rails 6 as well (or something similar to this):
I18n.available_locales = I18n.available_locales + [:org_a, :org_b]
I18n.locale = organziation.slug.to_sym || I18n.default_locale
Maybe append to the available locales early on in a config file, or similar.

Where can I store site-wide variables in Rails 4?

I am new to Rails and come from a ColdFusion background, where we would store global / site-wide variables in the 'application' scope. This persists the variable across any view or controller. Does Rails 4 have an equivalent functionality for this type of thing?
The site-wide variable won't typically change often so it doesn't need protecting in any way.
For example, in my situation, I want to store the website's domain name. One for testing and one for live environments. Localhost for development and xxxxxx.com for production.
Any tips or pointers would help. I have Googled this extensively and solutions seem to be far too complicated to achieve what seems to be such a trivial task. What's the best elegant solution for Rails 4?
The simplest, basic and default way is to use the Rails.application.config store.
Rails.application.config.my_config = 'foo'
You can assign a config in your environment:
# application.rb
module MyApp
class Application < Rails::Application
config.my_config = 'foo'
end
end
and read it with
Rails.application.config.my_config
# => 'foo'
This approach works well for very simple applications, but if you want something more advanced there are several gems available.
I'm currently using SimpleConfig. The main advantages are:
per-environment configuration. You can configure default configurations for the application, then override defaults with environment specific configurations
local.rb file for custom overrides
capistrano-like configuration style
it works nicely with the dotenv gem, very useful to avoid storing sensitive credentials in your repo.
This sounds like a perfect example for configuration values stored in config/environments/production.rb and config/environments/development.rb. Just store any value there:
config.my_special_value = 'val'
And access it in your application like this:
Rails.application.config.my_special_value
Always the value of your environment is active.
If you just want to have a „global“ value, store it in your application controller. All your view controllers are derived from your app controller, so you can save any value there as an instance or class variable:
class ApplicationController < ActionController::Base
MY_CONSTANT_VALUE = "foo"
end
class MyViewController < ApplicationController
def index
raise MY_CONSTANT_VALUE.inspect
end
end
You also could implement an helper:
# app/helpers/application_helper.rb
module ApplicationHelper
FOO = "bar"
end
# app/controllers/foo_controller.rb
class FooController < ApplicationController
def index
raise FOO
end
end
I can recommend good method to store variable. I use this on production
Passwords can be stored easier to .env file
like this
#Root dir create file ".env"
PASSWORD=123456
and load password
#Somewhere in app
ENV['PASSWORD'] #=> 123456
it works I hope will help you
You can use gem figaro
write your variables in config/application.yml
HELLO: world
development:
HELLO: developers
production:
HELLO: users
Then you can fetch
ENV["HELLO"]
In rails there is gem named as
gem 'dotenv-rails'
By using it we can assign the variables to system level and used in application.
By using simple steps
First create a simple filed in system level at any place with named extension .env
//in application.rb
require 'dotenv'
Dotenv.load('path-of-your-file.env')
And restart your application
Source
Please got the link for the desscription of dot env gem

rails: how can I override a locale based on subdomain?

I have internationalized and localized my application using the standard rails mechanisms.
Everything is stored in en, fr, de.yml files.
My application is multi-tenant, based on the subdomain.
I would like to allow my users to override certain translations in the application (e.g. to change "Employee" to "Associate" because it matches their own terminology).
I've tried to change the load path of my yml files on a per-request basis, but to no avail.
Any idea how I could, for each request, look up first in my user-specific yaml file, and fall back to the default yaml file if the translation was not overriden?
Assuming you store the subdomain in an instance variable from a controller filter, you could override the translation helper to do a lookup with a subdomain-specific scope first, then fallback to the specified or default scope. Something like this:
module ApplicationHelper
def t(key, original_options = {})
options = original_options.dup
site_translation_scope = ['subdomain_overrides', #subdomain.name]
scope =
case options[:scope]
when nil
site_translation_scope
when Array
options[:scope] = site_translation_scope + options[:scope]
when String
[site_translation_scope, options[:scope]].join(".")
end
translate(key, options.merge(:scope => scope, :raise => true))
rescue I18n::MissingTranslationData
translate(key, original_options)
end
end
Then you add your subdomain-specific overrides likes this:
en:
customer: Customer
subdomain_overrides:
subdomain_1:
customer: Buyer
If you want to allow tenants to use specific language but fallback to the default, I have written a micro library that will get the job done:
https://github.com/ElMassimo/i18n_multitenant
It takes care of configuring I18n to fallback to the base locale, allowing you to use tenant-specific translations if available. It's designed to work with the default backend of static .yml files, but it should also work with other I18n backends.
I've recently created I18n_global_scope gem that does exactly what you are describing, please checkout the source code https://github.com/mobilityhouse/i18n_global_scope and let me know your feedback.

How to manage Rails 2.3.x i18n locales programatically?

I would like to know if there is a way to insert, alter and remove i18n locale keys programatically (I guess I could use the DB, but I like Rails i18n and want to stay as close to it as possible).
Basically I want to know if there's a way (native, gem, plugin, whatever) to do things like:
I18n.add_locale_key("en", "application.messages.submit_message", "Submit message!")
I18n.add_locale_key("es", "application.messages.submit_message", "Enviar mensaje!")
I18n.remove_locale_key("en", "application.messages.submit_message")
I18n.remove_locale_key("es", "application.messages.submit_message")
As packaged, the Rails I18n API only support defining locale terms via the local .yaml or .rb files. Short of dynamically editing those files at runtime, your best bet is to use the DB functionality of a gem gem like FastGetText.
You could also roll your own solution, of course, but the DB method will likely work for your use case and will result in a smaller time investment.
Here's one way to do it:
>> I18n.backend.store_translations :en, :hello_world => "Hello, world."
=> {:hello_world=>"Hello, world."}
>> I18n.t :hello_world
=> "Hello, world."

How to define custom configuration variables in Rails?

I was wondering how to add custom configuration variables to a Rails application and how to access them in the controller?
Secondly, I was planning to have S3 support for uploads in my application, if I wanted to add a yaml file with the S3 access, secret key, how do I initialize it in my Rails App and how do I access the values that I have defined in that config file.
In Rails 3, Application specific custom configuration data can be placed in the application configuration object. The configuration can be assigned in the initialization files or the environment files -- say for a given application MyApp:
MyApp::Application.config.custom_config_variable = :my_config_setting
or
Rails.configuration.custom_config_variable = :my_config_setting
To read the setting, simply call the configuration variable without setting it:
Rails.configuration.custom_config_variable
=> :my_config_setting
UPDATE Rails 4
In Rails 4 there a new way for this => http://guides.rubyonrails.org/configuring.html#custom-configuration
Update 1
Very recommended: I'm going with Rails Config gem nowadays for the fine grained control it provides.
Update2
If you want a quick solution, then check Jack Pratt's answer below.
Although my original answer below still works, this answer is now outdated. I recommend looking at updates 1 and 2.
Original Answer:
For a quick solution, watching the "YAML Configuration File" screen cast by Ryan Bates should be very helpful.
In summary:
# config/initializers/load_config.rb
APP_CONFIG = YAML.load_file("#{Rails.root}/config/config.yml")[Rails.env]
# application.rb
if APP_CONFIG['perform_authentication']
# Do stuff
end
In Rails 3.0.5, the following approach worked for me:
In config/environments/development.rb, write
config.custom_config_key = :config_value
The value custom_config_key can then be referenced from other files using
Rails.application.config.custom_config_key
In Rails 4
Assuming you put your custom variables into a yaml file:
# config/acme.yml
development:
:api_user: 'joe'
:api_pass: 's4cret'
:timeout: 20
Create an initializer to load them:
# config/initializers/acme.rb
acme_config = Rails.application.config_for :acme
Rails.application.configure do
config.acme = ActiveSupport::OrderedOptions.new
config.acme.api_user = acme_config[:api_user]
config.acme.api_pass = acme_config[:api_pass]
config.acme.timeout = acme_config[:timeout]
end
Now anywhere in your app you can access these values like so:
Rails.configuration.acme.api_user
It is convenient that Rails.application.config_for :acme will load your acme.yml and use the correct environment.
This works in rails 3.1:
in config/environment.rb (or in config/environments/.. to target a specific environment) :
YourApp::Application.config.yourKey = 'foo'
This will be accessible in controller or views like this:
YourApp::Application.config.yourKey
(YourApp should be replaced by your application name.)
Note: It's Ruby code, so if you have a lot of config keys, you can do this :
in config/environment.rb :
YourApp::Application.configure do
config.something = foo
config.....
config....
.
config....
end
Since Rails 4.2, without additional gems, you can load config/hi.yml simply by using Rails.application.config_for :hi.
For example:
touch config/passwords.yml
#config/passwords.yml
development:
username: 'a'
password: 'b'
production:
username: 'aa'
password: 'bb'
touch config/initializers/constants.rb
#config/initializers/constants.rb
AUTHENTICATION = Rails.application.config_for :passwords
and now you can use AUTHENTICATION constant everywhere in your application:
#rails c production
:001> AUTHENTICATION['username'] => 'aa'
then add passwords.yml to .gitignore: echo /config/passwords.yml >> .gitignore, create an example file for your comfort cp /config/passwords.yml /config/passwords.example.yml and then just edit your example file in your production console with actual production values.
Rails 6 and 7
Many outdated answers, so adding one that is specific to Rails 6.
Application specific configuration goes in initializer files. Details are here: edge guides
Example:
config/initializers/foo.rb
module MyApp
class Application < Rails::Application
config.test_val = 'foo'
end
end
Alternatively:
Rails.application.config.test_val = 'foo'
This can now be accessed as:
Rails.configuration.test_val
Many more possibilities.
edge guides #custom-configuration
ex, you can also set up nested namespace configurations:
config.x.payment_processing.schedule = :daily
config.x.payment_processing.retries = 3
config.super_debugger = true
or use config_for to load entire custom config files:
config/payment.yml
production:
environment: production
merchant_id: production_merchant_id
public_key: production_public_key
private_key: production_private_key
development:
environment: sandbox
merchant_id: development_merchant_id
public_key: development_public_key
private_key: development_private_key
Then load it with:
config/initializers/load_payment.rb
module MyApp
class Application < Rails::Application
config.payment = config_for(:payment)
end
end
I just wanted to update this for the latest cool stuff in Rails 4.2, you can now do this inside any of your config/**/*.rb files:
config.x.whatever.you.want = 42
...and this will be available in your app as:
Rails.configuration.x.whatever.you.want
See more here: http://guides.rubyonrails.org/configuring.html#custom-configuration
Check out this neat gem doing exactly that:
https://github.com/mislav/choices
This way your sensitive data won't be exposed in open source projects
I created a simple plugin for YAML settings: Yettings
It works in a similar fashion to the code in khelll's answer, but you only need to add this YAML configuration file:
app/config/yetting.yml
The plugin dynamically creates a class that allows you to access the YML settings as class methods in your app like so:
Yetting.your_setting
Also, if you want to use multiple settings files with unique names, you can place them in a subdirectory inside app/config like this:
app/config/yettings/first.yml
app/config/yettings/second.yml
Then you can access the values like this:
FirstYetting.your_setting
SecondYetting.your_setting
It also provides you with default settings that can be overridden per environment. You can also use erb inside the yml file.
I really like the settingslogic gem. Very easy to set up and use.
https://github.com/binarylogic/settingslogic
If you use Heroku or otherwise have need to keep your application settings as environment variables, the figaro gem is very helpful.
I like to use rails-settings for global configuration values that need to be changeable via web interface.
Something we've starting doing at work is the ActiveSupport Ordered Hash
Which allows you to define your configuration cleanly inside the environment files e.g.
config.service = ActiveSupport::OrderedOptions.new
config.service.api_key = ENV['SERVICE_API_KEY']
config.service.shared_secret = ENV['SERVICE_SHARED_SECRET']
I would suggest good approach how to deal with configuration in your application at all. There are three basic rules:
change your configuration not a code;
use configurations over conditions;
write code that means something.
To have more detailed overview follow this link: Rails configuration in the proper way

Resources