smugglys/translatomatic

View on GitHub
lib/translatomatic/cli/translate.rb

Summary

Maintainability
A
25 mins
Test Coverage
require 'ruby-progressbar'

module Translatomatic
  module CLI
    # Translation functions for the command line interface
    class Translate < Base
      default_task :file

      define_option :provider, type: :array, aliases: '-t',
                               desc: t('cli.translate.provider'),
                               enum: Translatomatic::Provider.names
      define_option :source_locale, desc: t('cli.source_locale')
      define_option :target_locales, desc: t('cli.target_locales'),
                                     type: :array
      define_option :source_files, desc: t('cli.source_files'),
                                   type: :path_array
      define_option :share, desc: t('cli.translate.share'), default: false

      desc 'string text locale...', t('cli.translate.string')
      thor_options(self, Translatomatic::CLI::CommonOptions)
      thor_options(self, Translatomatic::CLI::Translate)
      thor_options(self, Translatomatic::Provider.types)
      # Translate a string to target locales
      # @param text [String] String to translate
      # @param locales [Array<String>] List of target locales, can also be set
      #   with the --target-locales option
      # @return [void]
      def string(text, *locales)
        run do
          all_conf = conf.all
          source_locale = conf.get(:source_locale) || Locale.default.to_s
          target_locales = determine_target_locales(locales)
          providers = Provider.resolve(conf.get(:provider), all_conf)

          template = '(%<locale>s) %<text>s'
          puts format(template, locale: source_locale, text: text)
          providers.each do |provider|
            puts t('cli.translate.using_provider', name: provider.name)
            target_locales.each do |l|
              translations = provider.translate([text], source_locale, l)
              translations.each do |translation|
                puts format('  -> ' + template, locale: l, text: translation)
              end
            end
            puts
          end

          finish_log
        end
      end

      desc 'file filename locale...', t('cli.translate.file')
      thor_options(self, Translatomatic::CLI::CommonOptions)
      thor_options(self, Translatomatic::CLI::Translate)
      thor_options(self, Translatomatic::FileTranslator)
      thor_options(self, Translatomatic::Database)
      thor_options(self, Translatomatic::Provider.types)
      thor_options(self, Translatomatic::ResourceFile.types)
      # Translate files to target locales
      # @param file [String] Resource file to translate, can also be set
      #   with the --source-files option.
      # @param locales [Array<String>] List of target locales, can also be set
      #   with the --target-locales option
      # @return [void]
      def file(file = nil, *locales)
        run do
          # set up database and progress updater
          Translatomatic::Database.new(conf.all)
          stats = Translation::Stats.new

          # translate the files
          source_files = load_source_files(file)
          listener = progress_updater(source_files, locales)
          source_files.each do |source|
            stats += translate_file(source, locales, listener)
          end
          log.info stats
          finish_log
        end
      end

      private

      def translate_file(source, locales, listener)
        file_opts = conf.all(for_file: source.path)
        target_locales = determine_target_locales(locales, source)
        ft_options = file_opts.merge(listener: listener)
        ft = Translatomatic::FileTranslator.new(ft_options)
        stats = Translation::Stats.new

        target_locales.each do |target_locale|
          log.info(t('cli.translate.translating_file',
                     source: source, source_locale: source.locale,
                     target_locale: target_locale))
          ft.translate_to_file(source, target_locale)
          stats += ft.translator.stats
        end
        stats
      end

      # load the source file(s)
      def load_source_files(file)
        source_files = []
        files = parse_list(file, conf.get(:source_files))
        files.each do |path|
          raise t('file.not_found', file: path) unless File.exist?(path)
          source = resource_file(path)
          raise t('file.unsupported', file: path) unless source
          source_files << source
        end
        source_files
      end

      def resource_file(path)
        Translatomatic::ResourceFile.load(path, conf.all(for_file: path))
      end

      # use list given on command line in preference to configuration
      def determine_target_locales(locales, source = nil)
        source_path = source ? source.path : nil
        config_locales = conf.get(:target_locales, for_file: source_path)
        target_locales = parse_list(locales, config_locales)
        raise t('cli.locales_required') if target_locales.empty?
        target_locales
      end

      def total_translations(source_files, locales)
        total = 0
        source_files.each do |source|
          property_values = source.properties.values
          texts = property_values.collect { |i| build_text(i, source.locale) }
          providers = resolve_providers(source).length
          to_locales = determine_target_locales(locales, source).length
          total += TextCollection.new(texts).count * providers * to_locales
        end
        total
      end

      def resolve_providers(source)
        Provider.resolve(conf.get(:provider, for_file: source.path), conf.all)
      end

      # create a progress bar and progress updater
      def progress_updater(source_files, locales)
        return nil if conf.get(:no_wank)
        # set up progress bar
        progressbar = ProgressBar.create(
          title: t('cli.translate.translating'),
          format: '%t: |%B| %p%% ',
          autofinish: false,
          total: total_translations(source_files, locales)
        )
        log.progressbar = progressbar if log.respond_to?(:progressbar=)
        Translatomatic::ProgressUpdater.new(progressbar)
      end
    end
  end
end