Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

External I18n locale path (AWS)

I have a database based translation system for my Rails app which works great except for the fact it, obviously, sends a LOT of requests to the database. I can only use cache to a certain amount of the requests but a feasable option for me is to export the translation table into a YAML-file, which can be read by the system.

The problem I have is that my app is on Heroku and you cannot write to that file system, I have to use AWS (using Carrierwave) to store the locale-files. I can write to AWS but I cannot get my Rails app to read the locale-files from my AWS-storage.

I have tried the below setting (which is just trial and error) but it doesn't work.

Application.rb

config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
config.i18n.load_path += Dir["https://s3-eu-west-1.amazonaws.com/myapp/locales/", '*.{rb,yml}'.to_s]
config.i18n.available_locales = [:en, :se] 

Edit: My current (tedious) workflow is to create all the translations in the database (using database translations is an absolut must for me btw). Then I export the table to yaml into my AWS storage. From there I download the locale files to my local app and into the locale-folder. I upload it all back up Heroku again. All because I cannot write to the Heroku file system.

How can I setup my app so that the locale-files (e.g. https://s3-eu-west-1.amazonaws.com/myapp/locales/en.yml) are read from this external source? Is it even possible? If not, is there a workaround?

like image 477
Christoffer Avatar asked Aug 23 '16 13:08

Christoffer


2 Answers

What comes to mind is implementing a cache for your database (so you don't need to use any YML files). Firstly if a key has been accessed, the result is cached and on second lookup - the i18n will use cached value.

I18n::Backend::ActiveRecord.send(:include, I18n::Backend::Cache)
I18n.cache_store = ActiveSupport::Cache.lookup_store(:memory_store) # or whatever store you prefer

One way to proceed would be to warm up the cache using: I18n.cache_store.write({"en.some.key" => "value"}). I guess it shouldn't be too hard to populate it from database.

The problem lies when you want to invalidate the cache. You'd need to create your own backend for activerecord. Here is the store method. You'd need to create a new backend module which would clear and repopulate the cache.

def store_translations(locale, data, options = {})
  I18n.cache_store.clear
  super
  I18n.cache_store.write(#cached_values)
end

If the cache is very large you'd need to implement a smarter store_translation method, that manages the specific translation item.

This is a bit of armchair-engineering, but with some effort I think you would be able to create a robust memory store for your activerecord translations.

like image 106
Magnuss Avatar answered Nov 07 '22 05:11

Magnuss


I feel, You can not add external translations directly using 'Dir'. Because it works locally. To workaround, you can load your external file to local system and then using Dir access it in I18n in same way. Anyways, the down side, to load any changes in external file, you will always need to restart your production server. So it is same as storing file localy.

like image 42
chandrakant shinde Avatar answered Nov 07 '22 04:11

chandrakant shinde