Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #36330 - Make translated strings from plugins available in the browser and modern frontend code #9691

Merged
merged 1 commit into from
May 17, 2023

Conversation

adamruzicka
Copy link
Contributor

@adamruzicka adamruzicka commented Apr 26, 2023

For context about the problem see https://gist.github.com/adamruzicka/f578c2e519f51230d475fd72848629d1

Concerns

webhippie/po_to_json had last change in June 2018, this change is still unreleased. Sadly, the changes proposed here rely on that unreleased change. Unless webhippie/po_to_json#8 is resolved soon-ish, we may need to either depend (and maybe package?) latest master or carry the project ourselves. Version 1.1.0 is out.

webhippie/gettext_i18n_rails_js doesn't really support doing the conversion for other rails engines (and domains) than just ::Rails. The changes proposed here work around that in a rather hacky fashion. If webhippie/gettext_i18n_rails_js#57 is accepted and released soon, we could have a more sensible way of doing that, along the lines of https://github.com/theforeman/foreman/compare/develop...adamruzicka:foreman:potojson-next?expand=1

After this change is merged, all plugins will need to run the new rake task to make translations pop up.

Followup changes

  • refresh translations in all plugins
  • update plugin template

@theforeman-bot
Copy link
Member

Issues: #36330

Copy link
Member

@ekohl ekohl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been thinking about a way to register translations during plugin registration. We have this bit:

https://github.com/theforeman/foreman_plugin_template/blob/5a2f59c636e4a732b8da2d238744ab65a800fd4b/lib/foreman_plugin_template/engine.rb#L62-L66

Would it make sense to have some DSL method to register translations with a certain domain instead of having to write an initializer in every plugin?

Perhaps I'm broadening the scope here, but I've always been confused that a Rails engine registers a plugin, but in my mind it would have made more sense to make a ForemanPlugin that is an engine, or at least creates an engine.

app/views/layouts/base.html.erb Outdated Show resolved Hide resolved
@@ -32,6 +32,9 @@
<% end %>
</script>
<%= javascript_include_tag "locale/#{FastGettext.locale}/app" %>
<% for plugin in ::Foreman::Plugin.all do %>
<%= javascript_include_tag "locale/#{FastGettext.locale}/#{plugin.engine.class.to_s.underscore.split('/', 2).first}" %>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work on foreman-tasks? Perhaps because the domain is foreman_tasks, but just want to make sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

foreman-tasks is probably the sole reason why I couldn't just use plugin.name or plugin.id. The domain indeed has underscores in it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you starting to understand why I'd love to rename it? Even though it's a pain once, it'll be easier in the long run.

@adamruzicka
Copy link
Contributor Author

Would it make sense to have some DSL method to register translations with a certain domain instead of having to write an initializer in every plugin?

I took a stab at this, does it somehow resemble what you had in mind? I hope I covered everything

@ekohl
Copy link
Member

ekohl commented Apr 26, 2023

I took a stab at this, does it somehow resemble what you had in mind? I hope I covered everything

I think it does, very nice. Now I have more ideas so would it make sense to submit it as a standalone PR and then merge it?

Like enhance the rake task to utilize the domain:

desc 'Extract plugin strings - called via rake plugin:gettext[plugin_name]'
task 'plugin:gettext', :engine do |t, args|
@domain = args[:engine]
@engine = "#{@domain.camelize}::Engine".constantize
@engine_root = @engine.root
namespace :gettext do
def locale_path
"#{@engine_root}/locale"
end
def files_to_translate
@engine.root.glob(FILE_GLOB).map(&:to_s)
end
def text_domain
@domain
end
end
Foreman::Gettext::Support.add_text_domain @domain, "#{@engine_root}/locale"
Rake::Task['gettext:find'].invoke
end

Then also update the plugin template to utilize the new DSL method.

bundler.d/assets.rb Outdated Show resolved Hide resolved
app/helpers/reactjs_helper.rb Outdated Show resolved Hide resolved
Copy link
Member

@ekohl ekohl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argh, I forgot to submit my review last week.

app/helpers/reactjs_helper.rb Outdated Show resolved Hide resolved
app/helpers/reactjs_helper.rb Outdated Show resolved Hide resolved
lib/tasks/gettext.rake Outdated Show resolved Hide resolved
Copy link
Member

@ekohl ekohl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And I wonder if we can either disable the spellcheck on those words or if we can add them to the known words.

Copy link
Member

@ekohl ekohl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you can configure spellcheck/spell-checker to ignore words in .eslintrc. Other than that 👍 from my side, though I'm not an expert on JS. Perhaps @MariaAga can take a look at that part.

lib/tasks/gettext.rake Outdated Show resolved Hide resolved
ekohl
ekohl previously approved these changes May 15, 2023
Copy link
Member

@ekohl ekohl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please squash the commits so we can merge them.

app/helpers/reactjs_helper.rb Outdated Show resolved Hide resolved
Comment on lines 70 to 75
domains = ::Foreman::Plugin.all.filter_map do |plugin|
domain = plugin.gettext_domain
domain if (FastGettext.translation_repositories[domain]&.available_locales || []).include? locale
end
domains.map do |domain|
javascript_include_tag("locale/#{locale}/#{domain}")
end.join.html_safe
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Untested, but isn't it also needed to check if domain is nil? Or do you count on FastGettext.translation_repositories[nil returning nil? I was thinking about something like this:

Suggested change
domains = ::Foreman::Plugin.all.filter_map do |plugin|
domain = plugin.gettext_domain
domain if (FastGettext.translation_repositories[domain]&.available_locales || []).include? locale
end
domains.map do |domain|
javascript_include_tag("locale/#{locale}/#{domain}")
end.join.html_safe
::Foreman::Plugin.all.filter_map do |plugin|
domain = plugin.gettext_domain
if domain && (FastGettext.translation_repositories[domain]&.available_locales || []).include? locale
javascript_include_tag("locale/#{locale}/#{domain}")
end
end.join.html_safe

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or do you count on FastGettext.translation_repositories[nil returning nil

Yes, I did that. The assumption seems to hold, what you suggest is hands down more obvious and probably safe in the long run. It needed a small tweak (parentheses) though

@adamruzicka adamruzicka force-pushed the potojson branch 2 times, most recently from 828ae5b to 11595c2 Compare May 16, 2023 07:32
@adamruzicka
Copy link
Contributor Author

I went ahead and squashed this, unsquashed variant is still available here https://github.com/adamruzicka/foreman/tree/unsquashed/potojson

ekohl
ekohl previously approved these changes May 17, 2023
Copy link
Member

@ekohl ekohl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will require a bit on the packaging side, but that should be ok.

@@ -1,7 +1,8 @@
group :assets do
gem 'jquery-ui-rails', '~> 6.0'
gem 'patternfly-sass', '~> 3.59.4'
gem 'gettext_i18n_rails_js', '~> 1.3.1'
gem 'gettext_i18n_rails_js', '~> 1.4'
gem 'po_to_json', '~> 1.1.0'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any particular reason to pin to ~> 1.1.0 instead of ~> 1.1?

Copy link
Contributor Author

@adamruzicka adamruzicka May 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, not really, changed

- Add plugin:po_to_json rake task
- Load js locale files for all plugins
- Make i18n.js do multi-domain lookup
const multidomain = (strict, fallback) => (...args) => {
// eslint-disable-next-line no-unused-vars
for (const domain of Object.keys(strictJed.options.locale_data)) {
try {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Js looks fine, is the only way to do this conditional return is with try-catch?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't found any other way

Copy link
Member

@ekohl ekohl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still wondering about storing the JSON files in git, but that's a similar problem as the MO files.

@ekohl ekohl merged commit e848148 into theforeman:develop May 17, 2023
@adamruzicka adamruzicka deleted the potojson branch May 17, 2023 12:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants