Skip to content

(PUP-7518) i18n module loading#5851

Merged
Iristyle merged 1 commit intopuppetlabs:4.10.xfrom
eputnam:modulesi18n
Jul 14, 2017
Merged

(PUP-7518) i18n module loading#5851
Iristyle merged 1 commit intopuppetlabs:4.10.xfrom
eputnam:modulesi18n

Conversation

@eputnam
Copy link
Contributor

@eputnam eputnam commented May 10, 2017

This adds to Puppet::Module to "initialize" a module for translations. Each module must be added to FastGettext.translation_repositories, so that translations in the modules code will be available to Puppet. Two methods are added here, one to check if a module has been initialized and another to initialize. To initialize, we are just wrapping GettextSetup.initialize basically.

@puppetcla
Copy link

CLA signed by all contributors.

@Iristyle
Copy link
Contributor

@eputnam the ticket here should be moved over to PUP, and commit message should be updated to correspond to the PUP ticket. We don't use MODULES tickets inside of Puppet.

Thanks!

@Iristyle Iristyle requested a review from Magisus May 10, 2017 05:48
@Iristyle
Copy link
Contributor

Pinged @Magisus for a review as she's the resident gettext ninja.

@eputnam eputnam changed the title (MODULES-4502) i18n module loading (PUP-7518) i18n module loading May 10, 2017
@eputnam
Copy link
Contributor Author

eputnam commented May 10, 2017

i may also add gettext config creation here in the future to reduce test clutter


@absolute_path_to_manifests = Puppet::FileSystem::PathPattern.absolute(manifests)

# # i18n initialization for modules
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: double hash

require 'locale'

initialize_i18n
rescue
Copy link
Contributor

Choose a reason for hiding this comment

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

It's nice to actually output the error message too

config_path = File.absolute_path('config.yaml', locales_path)
module_name = @forge_name.gsub("/","-") if @forge_name

nil if initialized_i18n? module_name
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be return nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

explicit returns in Ruby are frowned upon?

Copy link
Contributor

Choose a reason for hiding this comment

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

Only at the ends of methods. This one is in the middle, and we want to quit if this is true.


initialize_i18n
rescue
Puppet.warning "GettextSetup initialization for #{@name} failed."
Copy link
Contributor

Choose a reason for hiding this comment

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

I assume this cannot be externalised as Gettext isn't setup yet.

Copy link
Contributor

Choose a reason for hiding this comment

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

So I think since this is going to use Puppet's GettextSetup and not the module's, it can be. And it should be. We are trying to externalize all warnings and errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good catch, it should have been but i guess we aren't externalizing yet.


before do
modroot = "#{modpath}/#{modname}/"
@config_path = "#{modroot}/locales/config.yaml"
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: These variables should probably all be let definitions. None of them are used in before(:after) which is usually why @ variables are used.

end
end

def initialized_i18n? module_name
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: It's probably more readable as i18n_initialized? e.g. "Is the door closed" vs "have you closed the door?"

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 to name change

Copy link
Contributor Author

Choose a reason for hiding this comment

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

agreed.


begin
GettextSetup.initialize(locales_path) unless !File.file? config_path
Puppet.debug _("%{value0,} initialized for i18n: %{value1,}") % { value0: module_name, value1: GettextSetup.translation_repositories[module_name]}
Copy link
Contributor

Choose a reason for hiding this comment

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

We have been asked at least for now to not externalize debug messages.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also for future reference, please try to replace the value0 etc. with meaningful names. This will make it easier for the translator. Also as written, the commas will cause a mismatch of keys and this will explode.

end
end

def initialized_i18n? module_name
Copy link
Contributor

Choose a reason for hiding this comment

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

+1 to name change

@Magisus
Copy link
Contributor

Magisus commented May 10, 2017

Are modules with externalized strings able to function normally if GettextSetup is not present? See https://github.com/puppetlabs/puppet/blob/master/lib/puppet.rb#L25-L45 for how we are handling this in Puppet.

@eputnam
Copy link
Contributor Author

eputnam commented May 10, 2017

we haven't started externalizing yet fortunately. this is a great point @Magisus , thank you!

@Magisus Magisus added the blocked PRs blocked on work external to the PR itself label May 30, 2017
@Magisus
Copy link
Contributor

Magisus commented May 30, 2017

This is blocked on more extensive testing.

@Magisus
Copy link
Contributor

Magisus commented May 30, 2017

Also if this functionality is going to be needed/supported in the LTS, this needs to be retargeted at stable.

@eputnam eputnam force-pushed the modulesi18n branch 3 times, most recently from 4fd3a5a to 238c010 Compare June 16, 2017 18:42
@eputnam eputnam changed the base branch from master to stable June 16, 2017 18:42
@eputnam eputnam removed the blocked PRs blocked on work external to the PR itself label Jun 16, 2017
@Magisus
Copy link
Contributor

Magisus commented Jun 16, 2017

Closing and reopening to fix CI

@Magisus Magisus closed this Jun 16, 2017
@Magisus Magisus reopened this Jun 16, 2017
@Magisus
Copy link
Contributor

Magisus commented Jun 22, 2017

Sorry to shuffle this again, but would you mind retargeting this at the 4.10.x branch? We're going to be deleting the stable branch in favor of that one soon.

@eputnam eputnam changed the base branch from stable to 4.10.x June 26, 2017 16:29
@Magisus Magisus requested a review from Iristyle June 27, 2017 18:20
@eputnam
Copy link
Contributor Author

eputnam commented Jul 5, 2017

Would like to get this merged before the next release. @Iristyle have you had a chance to take a look?

@joshcooper
Copy link
Contributor

Are the translations namespaced so that translations in the module(s) don't affect puppet, and vice-versa? Or do we need to rely/assume that the keys are unique across puppet and all modules?

@eputnam
Copy link
Contributor Author

eputnam commented Jul 11, 2017

they are namespaced inside the master_domain by "project_name" from config.yaml so there should not be any interference.


private

def i18n_initialized? module_name
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Please use parens in method declaration

@absolute_path_to_manifests = Puppet::FileSystem::PathPattern.absolute(manifests)

# i18n initialization for modules
if Puppet::GETTEXT_AVAILABLE
Copy link
Contributor

@Iristyle Iristyle Jul 11, 2017

Choose a reason for hiding this comment

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

GETTEXT_AVAILABLE as a top-level constant for a feature test feels a little weird. The ship has probably sailed on this decision, but wondering why this isn't in a Puppet feature?

Copy link
Contributor

@Magisus Magisus Jul 11, 2017

Choose a reason for hiding this comment

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

Loading gettext happens very early (https://github.com/puppetlabs/puppet/blob/master/lib/puppet.rb#L51) and I seem to remember there being a reason we couldn't use Puppet features because of that. If that's not the case, this CAN probably change; the constant is only used internally.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fair enough... that sounds like a plausible explanation.

config_path = File.absolute_path('config.yaml', locales_path)
module_name = @forge_name.gsub("/","-") if @forge_name

return nil if i18n_initialized? module_name
Copy link
Contributor

@Iristyle Iristyle Jul 11, 2017

Choose a reason for hiding this comment

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

nit: can just return rather than return nil given the return value of initialize_i18n is not used

Do we want to guard against a nil value for module_name?
Also, no need to allocate a locales_path or config_path if not necessary - so method could be reordered a bit:

def initialize_i18n
  module_name = @forge_name.gsub("/","-") if @forge_name
  return if module_name.nil? || i18n_initialized?(module_name)

  locales_path = File.absolute_path('locales', path)
  
  begin
    GettextSetup.initialize(locales_path)
    Puppet.debug "#{module_name} initialized for i18n: #{GettextSetup.translation_repositories[module_name]}"
  rescue
    config_path = File.absolute_path('config.yaml', locales_path)
    Puppet.debug "Could not find locales configuration file for #{module_name} at #{config_path}. Skipping i18n initialization."
  end
end

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm also not sure how the method is designed to fail here? This method rescues ... and so does its caller. Can probably streamline the error-handling a bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it's not designed to fail, it just warns that there won't be any translations. i didn't think it was worth blocking a puppet run because translations aren't running. it's not affecting system configuration or anything, just the language of the log output, which will be obvious.

also, i like your version of the function a lot. thanks for the review!

@eputnam
Copy link
Contributor Author

eputnam commented Jul 11, 2017

perhaps a little blurb above the initialize_i18n function is in order also?

Wraps GettextSetup.initialize which adds a translation_repository to the master text_domain for a module. For successful initialization, GettextSetup requires a locales/ dir and a locales/config.yaml file. If the module already has a translation_repository in the master text_domain or the module has no name, this function returns nil.

@eputnam eputnam force-pushed the modulesi18n branch 2 times, most recently from bd3565a to 6bb02e2 Compare July 12, 2017 17:33
@eputnam
Copy link
Contributor Author

eputnam commented Jul 12, 2017

doing some git shuffling now, don't merge yet.

@eputnam eputnam force-pushed the modulesi18n branch 2 times, most recently from 3586606 to 9252b22 Compare July 12, 2017 19:59
@eputnam
Copy link
Contributor Author

eputnam commented Jul 12, 2017

ok, canoodling over, ready for merge.

@Magisus
Copy link
Contributor

Magisus commented Jul 12, 2017

I would go ahead and squash those last two commits. They're not really logically separable.

This adds to Puppet::Module to "initialize" a module for translations. Each module must be added to FastGettext.translation_repositories, so that translations in the modules code will be available to Puppet. Two methods are added here, one to check if a module has been initialized and another to initialize. To initialize, we are just wrapping GettextSetup.initialize basically.
@Iristyle Iristyle merged commit d9d2edc into puppetlabs:4.10.x Jul 14, 2017
# i18n initialization for modules
if Puppet::GETTEXT_AVAILABLE
begin
initialize_i18n
Copy link
Contributor

@Iristyle Iristyle Jul 14, 2017

Choose a reason for hiding this comment

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

What I meant here @eputnam is that if initialize_i18n never raises an exception based on its code already catching inside a begin / rescue ... that means there's no need for a rescue here.

Merged for now, but this could probably be tightened up a little.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants