fnando / i18n-js

It's a small library to provide the I18n translations on the Javascript. It comes with Rails support.
MIT License
3.77k stars 521 forks source link

missing translations deploying to Heroku #496

Closed ikbenben closed 6 years ago

ikbenben commented 6 years ago

It seems that none of our translation files are being included when we deploy our application to Heroku. We are running Rails 3.2.22 on Ruby 2.2.7

We were having issues getting it to work in our development environments but after a lot of struggles, we were able to get the translations working. The problem we were having in the dev env was that the translations for a new file was not available in I18n.translations js object even though they could be see in the generated /public/javascripts/translations.js file. The previous translations from other files in config/locales was available in the I18n.translations object.

After a lot of investigation, we discovered there was a file at /assets/i18n/filtered.js which also contained the translations but it was missing the new translations. This seems to be a generated file and we were able to force the regeneration by removing /public/javacripts/i18n.js file (also generated).

We then deployed to Heroku and hit issues again with missing translations. However this time when I look at the I18n.translations, non of our translations from config/locales folder are available, old or new. The following is the output from chrome console

translations:
    en:
    activerecord:{errors: {…}}
    date:{abbr_day_names: Array(7), abbr_month_names: Array(13), day_names: Array(7), formats: {…}, month_names: Array(13), …}
    datetime:{distance_in_words: {…}, prompts: {…}}
    errors:{format: "%{attribute} %{message}", messages: {…}}
    helpers:{button: {…}, select: {…}, submit: {…}}
    ice_cube:{array: {…}, at_hours_of_the_day: {…}, at_seconds_of_minute: {…}, date: {…}, days_of_month: {…}, …}
    number:{currency: {…}, format: {…}, human: {…}, percentage: {…}, precision: {…}}
    support:{array: {…}}
    time:{am: "am", formats: {…}, pm: "pm"}

The expected output would be:

translations:
  en:
    CardioExercise:"Cardio Exercise"
    SportExercise:"Sport Exercise"
    StrengthExercise:"Strength Exercise"
    StretchExercise:"Stretch Exercise"
    activerecord:{errors: {…}, models: {…}}
    challenges:{finished: "Challenge has finished", left: "%{duration} remaining", starts_in: "Starts in %{duration}"}
    client:{no_notes: "No trainer notes", notes: "Trainer notes"}
    date:{abbr_day_names: Array(7), abbr_month_names: Array(13), day_names: Array(7), formats: {…}, month_names: Array(13), …}
    datetime:{distance_in_words: {…}, prompts: {…}}
    default_workout_title:"Workout"
    devise:{confirmations: {…}, failure: {…}, mailer: {…}, oauth_callbacks: {…}, omniauth_callbacks: {…}, …}
    errors:{format: "%{attribute} %{message}", messages: {…}}
    gender:{f: "Female", m: "Male", prefix: {…}, u: "Unspecified"}
    graphs:{average_heart_rate: "Average heart rate", average_pace: "Average pace", calories_out: "Calories out", climb: "Climb", distance: "Distance", …}
    helpers:{button: {…}, select: {…}, submit: {…}}
    ice_cube:{array: {…}, at_hours_of_the_day: {…}, at_seconds_of_minute: {…}, date: {…}, days_of_month: {…}, …}
    indicators:{burn_fat_progress_indicator: {…}, strategy_efficiency: {…}}
    mail_binary_only:"A video or image message"
    mail_hook_devider:"Write ABOVE THIS LINE to post a reply to this message"
    measurements:{height: {…}, imperial: {…}, metric: {…}}
    messages:{activities: {…}, call_to_actions: {…}, client_invite: "You have received an invitation to connect from %{name}.↵↵%{message}", client_welcome_msg_chat: "Hi %{client_name}! Thanks for inviting me to be yo… I’ll setup a schedule for you!%{intake_url_text}", client_welcome_msg_intakeurl: " First I need you to fill out this form:↵↵%{intake_url}", …}
    meta_information:{challenges: {…}, dashboard_index: {…}, events: {…}, exercises_library: {…}, friends: {…}, …}
    number:{currency: {…}, format: {…}, human: {…}, percentage: {…}, precision: {…}}
    plans:{basic: "Monthly coaching", premium: "Daily coaching"}
    sensors:{brand: {…}, sensor_value: {…}}
    simple_form:{error_notification: {…}, no: "No", required: {…}, yes: "Yes"}
    support:{array: {…}}
    time:{am: "am", formats: {…}, pm: "pm"}
    tracking_options:{bmi: "BMI", bmr: "BMR", minutes_asleep: "Sleep"}
    user_feed:{create_manual_activity: "Just created a manual activity '%{title}'", create_vendor_activity: "Just imported '%{title}' from '%{vendor}'", height_tracked: "Just tracked their height to %{primary} (%{secondary})", move_activity: "Just moved '%{title}' from %{from} to %{to}", scheduled_message_sent: "Scheduled message was sent to the client", …}
    validates_timeliness:{error_value_formats: {…}}
    week_evaluation:{burn_fat: {…}}

We've tried all the work arounds listed at https://github.com/fnando/i18n-js#known-issues including issues looking through issues #367 and #213 but still can't get any translations.

If we browse /javascripts/translations.js in the Heroku environment, we can see all the expected translations but /assets/application.js (precompiled) is missing the expected translations

We've tried the following:

heroku rake tmp:cache:clear
heroku rake assets:precompile

and we have tried to update the assets version in application.rb:

config.assets.version = '1.5'

Any ideas how to troubleshoot this?

thanks Ben

PikachuEXE commented 6 years ago

Try I18n.t("week_evaluation") in rails console If you see something (should be a hash) And I18n.t("week_evaluation") returns nothing in JS side It's simply cache issue most of the time

I have this file to invalidate the cache for translations:

# config/locales/app_locale_cache_key/en.yml

en:
  # Since i18n-js use file content as cache key
  # To avoid changing other useful content
  # Putting this here as a cache expiring method by updating this content
  # And content within this file should never be used
  cache_key: "v2018_05_17_1437"

DELETE the tmp folder to avoid having any sprockets file cache preventing the update If you use Redis/Memcached for asset caching, clear all the keys too (for Redis should be FLUSHALL)

ikbenben commented 6 years ago

@PikachuEXE Thanks for the feedback. I'm pretty sure it is also cache (already confirmed using your suggestion) but I can't seem to invalidate it. I've tried all your steps:

I'm still not getting any love. :(

You mention to DELETE the tmp folder. I'm not sure what you mean by this. Can you clarify for me

Thanks

PikachuEXE commented 6 years ago

Where does the asset precompile occur? If it occurs on heroku I am not sure how to clear its cache (or whether it holds any asset cache) But before getting into deployment, let's debug it locally first By deleting tmp I mean [project path]/tmp It's mainly for clearing sprockets/asset pipeline cache in [project path]/tmp/cache

ikbenben commented 6 years ago

I took a shot, bashed into the Heroku env and ran rm -Rf /app/tmp/cache which deleted everything as I did not see anything removed when I ran heroku rake tmp:clear. I then tried to push an update after updating the cache_key. When it finished deploying, the /app/tmp/cache folder was not recreated

Leads me to believe this is happening elsewhere....

Based on Heroku documentation, found at https://devcenter.heroku.com/articles/rails-asset-pipeline#the-rails-3-asset-pipeline, the pipeline is precompiling during slug compilation so I'm guessing it somewhere else.

I'm going to reach out to Heroku about this and see what they say about where the precompile is happening. Based on their response, I may try to do the precompile locally before deploying

Will let you know what comes of it

ikbenben commented 6 years ago

Hi @PikachuEXE

I reached out to Heroku and got some feedback. They asked us to confirm that the translations were there when we ran the assets:precompile locally using the production env variable. We are running our dev env on docker so the command we ran was:

docker-compose run --rm -e RAILS_ENV=production web bundle exec rake assets:precompile

The result was the same in that none of the translations in config/locales were being included in /public/assets/application.js. I can see the I18n object and some translations (from other gems) but none of our custom translations

thoughts?

PikachuEXE commented 6 years ago

How did you fix your development environment? Can you do the same for staging/prod?

Worst case: create a sample app to reproduce it...

ikbenben commented 6 years ago

@PikachuEXE

Thanks for continuing to provide feedback

Typically, we are not precompiling the assets in our development environment. We had a lot of issues with the dev env but finally got it working (outlined in the initial post above)

I tried to include the tmp:clear task as well but still no solution. I went into the rails console on our Heroku environment to see config info for assets and precompile

Rails.configuration.assets.paths

["/app/app/assets/fonts", "/app/app/assets/images", "/app/app/assets/javascripts", "/app/app/assets/stylesheets", "/app/lib/assets/images", "/app/lib/assets/javascripts", "/app/vendor/assets/images", "/app/vendor/assets/javascripts", "/app/vendor/assets/stylesheets", "/app/vendor/bundle/ruby/2.2.0/bundler/gems/kss-rails-0c99e4bf4cce/app/assets/javascripts", "/app/vendor/bundle/ruby/2.2.0/bundler/gems/kss-rails-0c99e4bf4cce/app/assets/stylesheets", "/app/vendor/bundle/ruby/2.2.0/gems/rails-backbone-1.2.0/vendor/assets/javascripts", "/app/vendor/bundle/ruby/2.2.0/gems/modernizr-rails-2.7.1/vendor/assets/javascripts", "/app/vendor/bundle/ruby/2.2.0/gems/jquery-ui-rails-5.0.5/app/assets/images", "/app/vendor/bundle/ruby/2.2.0/gems/jquery-ui-rails-5.0.5/app/assets/javascripts", "/app/vendor/bundle/ruby/2.2.0/gems/jquery-ui-rails-5.0.5/app/assets/stylesheets", "/app/vendor/bundle/ruby/2.2.0/gems/jquery-rails-3.1.4/vendor/assets/javascripts", "/app/vendor/bundle/ruby/2.2.0/gems/i18n-js-3.0.5/app/assets/javascripts", #<Pathname:/app/app/assets/fonts>, #<Pathname:/app/app/assets/images/marketing>]

Rails.configuration.assets.precompile

[#<Proc:0x00000001604568@/app/vendor/bundle/ruby/2.2.0/gems/railties-3.2.22/lib/rails/application/configuration.rb:48>, /(?:\/|\\|\A)application\.(css|js)$/, "application.*", "backbone_libraries.*", "backbone/boot.js", "messages.js", "standalone.*", "marketing.*", "reviews.*", "raphael.js", "raphael_popup.js", "styleguide*", "kss.js", "jquery-1.7.1.min.js", "modernizr.js", "highcharts.js", "features/icons/*.png", "features/images/*.png", "pricing/*.png", "mobile/sign_up.css", "sign_up.css", "fonts.css", "light.css", "modernizr.js"]

I don't see any path included to the /public/javascripts/translations.js file that is generated. I'm not sure if it should

ikbenben commented 6 years ago

@PikachuEXE

I think I was able to track down what is going on. The gem currently defaults to output the translations.js and i18n.js files to public/javascripts however the asset pipeline never uses the folder

I created a i18n-js.yml config file with the following settings so that the files are generated in the app/assets/javascripts folder:

translations:
  - file: "app/assets/javascripts/i18n/translations.js"

export_i18n_js: "app/assets/javascripts"
PikachuEXE commented 6 years ago

I guess you are using export/middleware plus asset pipeline?

In my project main JS I just add //= require i18n/translations as mentioned in https://github.com/fnando/i18n-js#rails-app-with-asset-pipeline

ikbenben commented 6 years ago

ah. maybe I missed something in the docs. We also have the require statement (also included the //= require i18n before it but we also have added config.middleware.use I18n::JS::Middleware in our application.js. I missed the statement For Rails app without Asset Pipeline in the header.

Will try to remove the middleware as well to see how it behaves