rails-i18nterface 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +17 -10
- data/app/controllers/rails_i18nterface/application_controller.rb +2 -0
- data/app/controllers/rails_i18nterface/translate_controller.rb +29 -80
- data/app/helpers/rails_i18nterface/application_helper.rb +2 -0
- data/app/helpers/rails_i18nterface/translate_helper.rb +2 -0
- data/app/views/rails_i18nterface/translate/index.html.erb +14 -23
- data/config/routes.rb +2 -0
- data/lib/rails-i18nterface.rb +3 -1
- data/lib/rails-i18nterface/cache.rb +40 -0
- data/lib/rails-i18nterface/engine.rb +2 -0
- data/lib/rails-i18nterface/keys.rb +24 -112
- data/lib/rails-i18nterface/sourcefiles.rb +14 -12
- data/lib/rails-i18nterface/storage.rb +2 -4
- data/lib/rails-i18nterface/utils.rb +51 -0
- data/lib/rails-i18nterface/version.rb +3 -1
- data/lib/rails-i18nterface/yamlfile.rb +15 -17
- data/lib/tasks/rails-i18nterface.rake +1 -0
- data/spec/controllers/translate_controller_spec.rb +18 -33
- data/spec/internal/app/controllers/application_controller.rb +2 -0
- data/spec/internal/app/models/article.rb +8 -2
- data/spec/internal/config/routes.rb +2 -0
- data/spec/internal/db/combustion_test.sqlite +0 -0
- data/spec/internal/log/test.log +241 -1608
- data/spec/lib/cache_spec.rb +51 -0
- data/spec/lib/keys_spec.rb +59 -88
- data/spec/lib/sourcefiles_spec.rb +8 -6
- data/spec/lib/storage_spec.rb +2 -0
- data/spec/lib/utils_spec.rb +34 -0
- data/spec/lib/yamlfile_spec.rb +10 -5
- data/spec/requests/search_spec.rb +2 -0
- data/spec/spec_helper.rb +3 -3
- metadata +104 -67
- checksums.yaml +0 -7
- data/app/models/rails_i18nterface/translation.rb +0 -23
- data/db/migrate/20110921112044_create_translations.rb +0 -18
- data/db/migrate/20130422115639_rename_translation_to_namespace.rb +0 -8
- data/lib/rails-i18nterface/log.rb +0 -40
- data/spec/lib/log_spec.rb +0 -47
- data/spec/models/translation_spec.rb +0 -9
    
        data/README.md
    CHANGED
    
    | @@ -40,11 +40,7 @@ In routes.rb | |
| 40 40 | 
             
            ```ruby
         | 
| 41 41 | 
             
            mount RailsI18nterface::Engine => "/translate", :as => "translate_engine"
         | 
| 42 42 | 
             
            ```
         | 
| 43 | 
            -
             | 
| 44 | 
            -
            ```
         | 
| 45 | 
            -
            rake railties:install:migrations
         | 
| 46 | 
            -
            rake db:migrate
         | 
| 47 | 
            -
            ```
         | 
| 43 | 
            +
             | 
| 48 44 | 
             
            ### Protect access
         | 
| 49 45 |  | 
| 50 46 | 
             
            You may want to protect the translation engine to admin and create a constraint
         | 
| @@ -55,6 +51,11 @@ constraints AdminConstraint.new do | |
| 55 51 | 
             
                mount RailsI18nterface::Engine => "/translate", :as => "translate_engine"
         | 
| 56 52 | 
             
              end
         | 
| 57 53 | 
             
            end
         | 
| 54 | 
            +
            # this second route will be then used if the user is not an admin
         | 
| 55 | 
            +
            get 'translate' => redirect do |p, req|
         | 
| 56 | 
            +
              req.flash['error'] = I18n.t('errors.permission_denied')
         | 
| 57 | 
            +
              "/signin"
         | 
| 58 | 
            +
            end
         | 
| 58 59 | 
             
            ```
         | 
| 59 60 |  | 
| 60 61 | 
             
            Then create a `config/initializers/admin_constraint.rb` containing:
         | 
| @@ -81,16 +82,22 @@ Where `[:en]` and `[:ja, :es, :fr]` could be replaced by locale list of your cho | |
| 81 82 | 
             
            ## Todo
         | 
| 82 83 |  | 
| 83 84 | 
             
            * fix the code smell reported by code climate
         | 
| 84 | 
            -
              * extract code from the controller to a lib
         | 
| 85 | 
            -
              * refactor the libs in a cleaner way
         | 
| 86 | 
            -
              * apply rubocop and follow his law
         | 
| 85 | 
            +
              * extract code from the controller to a lib (in progress)
         | 
| 86 | 
            +
              * refactor the libs in a cleaner way (in progress)
         | 
| 87 | 
            +
              * apply rubocop and follow his law (done)
         | 
| 87 88 | 
             
            * make the application thread-safe
         | 
| 88 | 
            -
            * remove those damn global variables
         | 
| 89 | 
            -
            * extend testing to refactored libs
         | 
| 89 | 
            +
            * remove those damn global variables (in progress)
         | 
| 90 | 
            +
            * extend testing to refactored libs (in progress)
         | 
| 90 91 | 
             
            * change navigation to an ajax-driven reload
         | 
| 91 92 | 
             
            * add a way to gather .one and .other and .few under same translation line
         | 
| 92 93 | 
             
            * add support for other i18n backends (gettext)
         | 
| 93 94 |  | 
| 95 | 
            +
            ## Note for upgrade 0.1.x to 0.2.x
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            The database is not used anymore, back to the good old way.
         | 
| 98 | 
            +
            So you can remove the table rails_i18nterface_translations (v0.1.7)
         | 
| 99 | 
            +
            or translations (< 0.1.7).
         | 
| 100 | 
            +
             | 
| 94 101 | 
             
            ## License
         | 
| 95 102 |  | 
| 96 103 | 
             
            ```
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module RailsI18nterface
         | 
| 2 4 | 
             
              class TranslateController < RailsI18nterface::ApplicationController
         | 
| 3 5 |  | 
| @@ -8,108 +10,68 @@ module RailsI18nterface | |
| 8 10 |  | 
| 9 11 | 
             
                def index
         | 
| 10 12 | 
             
                  @dbvalues = {}
         | 
| 11 | 
            -
                  @keys =  | 
| 12 | 
            -
                   | 
| 13 | 
            -
                  @ | 
| 13 | 
            +
                  @keys = RailsI18nterface::Keys.new(Rails.root, @from_locale, @to_locale)
         | 
| 14 | 
            +
                  @files = @keys.files
         | 
| 15 | 
            +
                  @yaml_keys = @keys.yaml_keys
         | 
| 16 | 
            +
                  @all_keys = @keys.all_keys
         | 
| 17 | 
            +
                  @deep_keys = to_deep_hash(@all_keys)
         | 
| 14 18 | 
             
                  filter_by_key_pattern
         | 
| 15 19 | 
             
                  filter_by_text_pattern
         | 
| 16 20 | 
             
                  filter_by_translated_or_changed
         | 
| 17 21 | 
             
                  sort_keys
         | 
| 18 22 | 
             
                  paginate_keys
         | 
| 19 | 
            -
                  @total_entries = @ | 
| 23 | 
            +
                  @total_entries = @all_keys.size
         | 
| 24 | 
            +
                  @page_title = 'Translate'
         | 
| 25 | 
            +
                  @show_filters = ['all', 'untranslated', 'translated']
         | 
| 20 26 | 
             
                end
         | 
| 21 27 |  | 
| 22 28 | 
             
                def destroy
         | 
| 23 | 
            -
                  puts params
         | 
| 24 | 
            -
                  term = RailsI18nterface::Translation.find_by_key(params[:del])
         | 
| 25 | 
            -
                  if term and term.destroy
         | 
| 26 | 
            -
                    flash[:success] = "Translations removed from database"
         | 
| 27 | 
            -
                  else
         | 
| 28 | 
            -
                    flash[:notice] = "Translations not found in database"
         | 
| 29 | 
            -
                  end
         | 
| 30 29 | 
             
                  params[:key] = { params[:del] => '' }
         | 
| 31 30 | 
             
                  update
         | 
| 32 31 | 
             
                end
         | 
| 33 32 |  | 
| 34 | 
            -
                def load_db_translations
         | 
| 35 | 
            -
                  @versions = {}
         | 
| 36 | 
            -
                  @dbvalues = {@to_locale => {}}
         | 
| 37 | 
            -
                  (RailsI18nterface::Translation.where(:locale => @to_locale) || []).each do |translation|
         | 
| 38 | 
            -
                    @versions[translation.key] = translation.updated_at.to_i
         | 
| 39 | 
            -
                    yaml_value = I18n.backend.send(:lookup, @to_locale, translation.key)
         | 
| 40 | 
            -
                    if yaml_value && translation.value != yaml_value
         | 
| 41 | 
            -
                      translation.value = yaml_value
         | 
| 42 | 
            -
                      RailsI18nterface::Translation.where(key: translation.key).first.update_attribute(:value, yaml_value)
         | 
| 43 | 
            -
                    end
         | 
| 44 | 
            -
                    @dbvalues[@to_locale][translation.key] = translation.value
         | 
| 45 | 
            -
                    @keys << translation.key
         | 
| 46 | 
            -
                  end
         | 
| 47 | 
            -
                  @keys.uniq!
         | 
| 48 | 
            -
                end
         | 
| 49 | 
            -
             | 
| 50 33 | 
             
                def export
         | 
| 51 34 | 
             
                  locale = params[:locale].to_sym
         | 
| 52 35 | 
             
                  keys = {locale => I18n.backend.send(:translations)[locale] || {}}
         | 
| 53 | 
            -
                  RailsI18nterface::Translation.where(:locale => @to_locale).each do |translation|
         | 
| 54 | 
            -
                    next if !translation.value or translation.value == ''
         | 
| 55 | 
            -
                    set_nested(keys[locale], translation.key.split('.'), translation.value)
         | 
| 56 | 
            -
                  end
         | 
| 57 36 | 
             
                  remove_blanks keys
         | 
| 58 | 
            -
                   | 
| 59 | 
            -
                  yaml = RailsI18nterface::Yamlfile.new(nil).keys_to_yaml(keys)
         | 
| 37 | 
            +
                  yaml = keys_to_yaml(keys)
         | 
| 60 38 | 
             
                  response.headers['Content-Disposition'] = "attachment; filename=#{locale}.yml"
         | 
| 61 39 | 
             
                  render :text => yaml
         | 
| 62 40 | 
             
                end
         | 
| 63 41 |  | 
| 64 42 | 
             
                def update
         | 
| 65 | 
            -
                  RailsI18nterface::Translation.update(@to_locale, params[:key])
         | 
| 66 43 | 
             
                  if I18n.backend.respond_to? :store_translations
         | 
| 67 | 
            -
                    I18n.backend.store_translations(@to_locale,  | 
| 44 | 
            +
                    I18n.backend.store_translations(@to_locale, to_deep_hash(params[:key]))
         | 
| 68 45 | 
             
                  end
         | 
| 69 | 
            -
                  RailsI18nterface:: | 
| 70 | 
            -
                   | 
| 71 | 
            -
                  force_init_translations | 
| 72 | 
            -
                  flash[:notice] =  | 
| 46 | 
            +
                  yaml = RailsI18nterface::Yamlfile.new(Rails.root, @to_locale)
         | 
| 47 | 
            +
                  yaml.write_to_file
         | 
| 48 | 
            +
                  force_init_translations
         | 
| 49 | 
            +
                  flash[:notice] = 'Translations stored'
         | 
| 73 50 | 
             
                  redirect_to root_path(params.slice(:filter, :sort_by, :key_type, :key_pattern, :text_type, :text_pattern))
         | 
| 74 51 | 
             
                end
         | 
| 75 52 |  | 
| 76 53 | 
             
                def reload
         | 
| 77 | 
            -
                   | 
| 54 | 
            +
                  @keys.reload
         | 
| 78 55 | 
             
                  redirect_to root_path(params.slice(:filter, :sort_by, :key_type, :key_pattern, :text_type, :text_pattern))
         | 
| 79 56 | 
             
                end
         | 
| 80 57 |  | 
| 81 58 | 
             
                private
         | 
| 82 59 |  | 
| 83 | 
            -
                def initialize_keys
         | 
| 84 | 
            -
                  @files = RailsI18nterface::Keys.files
         | 
| 85 | 
            -
                  keys = (@files.keys.map(&:to_s) + RailsI18nterface::Keys.new.i18n_keys(@from_locale)).uniq
         | 
| 86 | 
            -
                  keys.reject! do |key|
         | 
| 87 | 
            -
                    from_text = lookup(@from_locale, key)
         | 
| 88 | 
            -
                    # When translating from one language to another,
         | 
| 89 | 
            -
                    # make sure there is a text to translate from.
         | 
| 90 | 
            -
                    # Always exclude non string translation objects
         | 
| 91 | 
            -
                    # as we don't support editing them in the UI.
         | 
| 92 | 
            -
                    (@from_locale != @to_locale && !from_text.present?) ||
         | 
| 93 | 
            -
                      (from_text.present? && !from_text.is_a?(String))
         | 
| 94 | 
            -
                  end
         | 
| 95 | 
            -
                end
         | 
| 96 60 |  | 
| 97 61 | 
             
                def lookup(locale, key)
         | 
| 98 | 
            -
                   | 
| 62 | 
            +
                  I18n.backend.send(:lookup, locale, key)
         | 
| 99 63 | 
             
                end
         | 
| 100 64 | 
             
                helper_method :lookup
         | 
| 101 65 |  | 
| 102 66 | 
             
                def filter_by_translated_or_changed
         | 
| 103 67 | 
             
                  params[:filter] ||= 'all'
         | 
| 104 68 | 
             
                  return if params[:filter] == 'all'
         | 
| 105 | 
            -
                  @ | 
| 69 | 
            +
                  @all_keys.reject! do |key|
         | 
| 106 70 | 
             
                    case params[:filter]
         | 
| 107 71 | 
             
                    when 'untranslated'
         | 
| 108 72 | 
             
                      lookup(@to_locale, key).present?
         | 
| 109 73 | 
             
                    when 'translated'
         | 
| 110 74 | 
             
                      lookup(@to_locale, key).blank?
         | 
| 111 | 
            -
                    when 'changed'
         | 
| 112 | 
            -
                      old_from_text(key).blank? || lookup(@from_locale, key) == old_from_text(key)
         | 
| 113 75 | 
             
                    else
         | 
| 114 76 | 
             
                      raise "Unknown filter '#{params[:filter]}'"
         | 
| 115 77 | 
             
                    end
         | 
| @@ -118,15 +80,15 @@ module RailsI18nterface | |
| 118 80 |  | 
| 119 81 | 
             
                def filter_by_key_pattern
         | 
| 120 82 | 
             
                  return if params[:key_pattern].blank?
         | 
| 121 | 
            -
                  @ | 
| 83 | 
            +
                  @all_keys.reject! do |key|
         | 
| 122 84 | 
             
                    case params[:key_type]
         | 
| 123 | 
            -
                    when  | 
| 85 | 
            +
                    when 'starts_with'
         | 
| 124 86 | 
             
                      if params[:key_pattern] == '.'
         | 
| 125 87 | 
             
                        key.match(/\./)
         | 
| 126 88 | 
             
                      else
         | 
| 127 89 | 
             
                        !key.starts_with?(params[:key_pattern])
         | 
| 128 90 | 
             
                      end
         | 
| 129 | 
            -
                    when  | 
| 91 | 
            +
                    when 'contains'
         | 
| 130 92 | 
             
                      key.index(params[:key_pattern]).nil?
         | 
| 131 93 | 
             
                    else
         | 
| 132 94 | 
             
                      raise "Unknown key_type '#{params[:key_type]}'"
         | 
| @@ -136,7 +98,7 @@ module RailsI18nterface | |
| 136 98 |  | 
| 137 99 | 
             
                def filter_by_text_pattern
         | 
| 138 100 | 
             
                  return if params[:text_pattern].blank?
         | 
| 139 | 
            -
                  @ | 
| 101 | 
            +
                  @all_keys.reject! do |key|
         | 
| 140 102 | 
             
                    lookup_key = lookup(@from_locale, key)
         | 
| 141 103 | 
             
                    case params[:text_type]
         | 
| 142 104 | 
             
                    when 'contains'
         | 
| @@ -150,12 +112,12 @@ module RailsI18nterface | |
| 150 112 | 
             
                end
         | 
| 151 113 |  | 
| 152 114 | 
             
                def sort_keys
         | 
| 153 | 
            -
                  params[:sort_by] ||=  | 
| 115 | 
            +
                  params[:sort_by] ||= 'key'
         | 
| 154 116 | 
             
                  case params[:sort_by]
         | 
| 155 | 
            -
                  when  | 
| 156 | 
            -
                    @ | 
| 157 | 
            -
                  when  | 
| 158 | 
            -
                    @ | 
| 117 | 
            +
                  when 'key'
         | 
| 118 | 
            +
                    @all_keys.sort!
         | 
| 119 | 
            +
                  when 'text'
         | 
| 120 | 
            +
                    @all_keys.sort! do |key1, key2|
         | 
| 159 121 | 
             
                      if lookup(@from_locale, key1).present? && lookup(@from_locale, key2).present?
         | 
| 160 122 | 
             
                        lookup(@from_locale, key1).to_s.downcase <=> lookup(@from_locale, key2).to_s.downcase
         | 
| 161 123 | 
             
                      elsif lookup(@from_locale, key1).present?
         | 
| @@ -171,7 +133,7 @@ module RailsI18nterface | |
| 171 133 |  | 
| 172 134 | 
             
                def paginate_keys
         | 
| 173 135 | 
             
                  params[:page] ||= 1
         | 
| 174 | 
            -
                  @paginated_keys = @ | 
| 136 | 
            +
                  @paginated_keys = @all_keys[offset, per_page]
         | 
| 175 137 | 
             
                end
         | 
| 176 138 |  | 
| 177 139 | 
             
                def offset
         | 
| @@ -204,18 +166,5 @@ module RailsI18nterface | |
| 204 166 | 
             
                  @to_locale = session[:to_locale].to_sym
         | 
| 205 167 | 
             
                end
         | 
| 206 168 |  | 
| 207 | 
            -
                def old_from_text(key)
         | 
| 208 | 
            -
                  return @old_from_text[key] if @old_from_text && @old_from_text[key]
         | 
| 209 | 
            -
                  @old_from_text = {}
         | 
| 210 | 
            -
                  text = key.split(".").reduce(log_hash) do |hash, k|
         | 
| 211 | 
            -
                    hash ? hash[k] : nil
         | 
| 212 | 
            -
                  end
         | 
| 213 | 
            -
                  @old_from_text[key] = text
         | 
| 214 | 
            -
                end
         | 
| 215 | 
            -
                helper_method :old_from_text
         | 
| 216 | 
            -
             | 
| 217 | 
            -
                def log_hash
         | 
| 218 | 
            -
                  @log_hash ||= RailsI18nterface::Log.new(@from_locale, @to_locale, {}).read
         | 
| 219 | 
            -
                end
         | 
| 220 169 | 
             
              end
         | 
| 221 170 | 
             
            end
         | 
| @@ -1,29 +1,21 @@ | |
| 1 | 
            -
            <%
         | 
| 2 | 
            -
              @page_title = "Translate"
         | 
| 3 | 
            -
              show_filters = ["all", "untranslated", "translated"]
         | 
| 4 | 
            -
              show_filters << "changed" if @from_locale != @to_locale
         | 
| 5 | 
            -
            %>
         | 
| 6 1 | 
             
            <%= form_tag(params, :method => :get, :name => 'filter_form') do %>
         | 
| 7 2 | 
             
            <%= hidden_field_tag(:filter, params[:filter]) %>
         | 
| 8 3 | 
             
            <%= hidden_field_tag(:sort_by, params[:sort_by]) %>
         | 
| 9 4 | 
             
            <div id="top">
         | 
| 10 | 
            -
               | 
| 11 | 
            -
                < | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
                </h1>
         | 
| 26 | 
            -
              <% end %>
         | 
| 5 | 
            +
              <h1>
         | 
| 6 | 
            +
                <div class="right">
         | 
| 7 | 
            +
                 <%= select_tag(:from_locale, options_for_select(I18n.available_locales, @from_locale.to_sym)) %> <span>to</span>
         | 
| 8 | 
            +
                 <%= select_tag(:to_locale, options_for_select(I18n.available_locales, @to_locale.to_sym)) %>
         | 
| 9 | 
            +
                 <%= submit_tag "Display" %>
         | 
| 10 | 
            +
                </div>
         | 
| 11 | 
            +
                <%= link_to '.. /', '../' %>
         | 
| 12 | 
            +
                <%= link_to @page_title, root_path %></a>
         | 
| 13 | 
            +
                <div class="center">
         | 
| 14 | 
            +
                 <label>Show:</label> <%=  simple_filter(@show_filters).html_safe %>
         | 
| 15 | 
            +
                  Found <strong><%= @total_entries %></strong> messages
         | 
| 16 | 
            +
                  <%= link_to "Reload messages", translate_reload_path(params) %>
         | 
| 17 | 
            +
                </div>
         | 
| 18 | 
            +
              </h1>
         | 
| 27 19 | 
             
              <% flash.each do |key, msg| %>
         | 
| 28 20 | 
             
                <div class="flash" id="<%= key %>"><%= msg %></div>
         | 
| 29 21 | 
             
              <% end %>
         | 
| @@ -78,7 +70,6 @@ | |
| 78 70 | 
             
                  %>
         | 
| 79 71 | 
             
              	  <div class="translation">
         | 
| 80 72 | 
             
                  	<p class="edit-form">
         | 
| 81 | 
            -
              			<%= hidden_field_tag("version[#{key}]", @versions[key] || '0') %>
         | 
| 82 73 | 
             
              		  <% if n_lines > 1 %>
         | 
| 83 74 | 
             
                      <div class="right">
         | 
| 84 75 | 
             
                          <% if @files[key] %>
         | 
    
        data/config/routes.rb
    CHANGED
    
    
    
        data/lib/rails-i18nterface.rb
    CHANGED
    
    | @@ -1,9 +1,11 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require 'rails-i18nterface/engine'
         | 
| 2 4 | 
             
            require 'rails-i18nterface/utils'
         | 
| 5 | 
            +
            require 'rails-i18nterface/cache'
         | 
| 3 6 | 
             
            require 'rails-i18nterface/yamlfile'
         | 
| 4 7 | 
             
            require 'rails-i18nterface/sourcefiles'
         | 
| 5 8 | 
             
            require 'rails-i18nterface/keys'
         | 
| 6 | 
            -
            require 'rails-i18nterface/log'
         | 
| 7 9 | 
             
            require 'rails-i18nterface/storage'
         | 
| 8 10 |  | 
| 9 11 | 
             
            module RailsI18nterface
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module RailsI18nterface
         | 
| 4 | 
            +
              module Cache
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def cache_save(obj, uri, options={})
         | 
| 7 | 
            +
                  FileUtils.rm uri if File.exists? uri
         | 
| 8 | 
            +
                  File.open(uri, 'wb') do |f|
         | 
| 9 | 
            +
                    Marshal.dump(obj, f)
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def cache_load(uri, file, &process)
         | 
| 14 | 
            +
                  mtime = File.mtime(file)
         | 
| 15 | 
            +
                  if cached?(uri) && uptodate?(uri, file)
         | 
| 16 | 
            +
                    File.open(uri) do |f|
         | 
| 17 | 
            +
                      Marshal.load f
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
                  else
         | 
| 20 | 
            +
                    if block_given?
         | 
| 21 | 
            +
                      obj = yield
         | 
| 22 | 
            +
                      cache_save(obj, uri)
         | 
| 23 | 
            +
                      File.utime(mtime, mtime, uri)
         | 
| 24 | 
            +
                      obj
         | 
| 25 | 
            +
                    else
         | 
| 26 | 
            +
                      nil
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def cached?(uri)
         | 
| 32 | 
            +
                  File.file? uri
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def uptodate?(uri, file)
         | 
| 36 | 
            +
                  File.mtime(uri) == File.mtime(file)
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| @@ -1,57 +1,50 @@ | |
| 1 | 
            -
            # | 
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 2 |  | 
| 3 3 | 
             
            module RailsI18nterface
         | 
| 4 4 | 
             
              class Keys
         | 
| 5 5 |  | 
| 6 | 
            -
                 | 
| 7 | 
            -
                def self.files
         | 
| 8 | 
            -
                  @files ||= new.files
         | 
| 9 | 
            -
                end
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                def self.names
         | 
| 12 | 
            -
                  @names || new.names
         | 
| 13 | 
            -
                end
         | 
| 14 | 
            -
                # Allows flushing of the files cache
         | 
| 15 | 
            -
                def self.files=(files)
         | 
| 16 | 
            -
                  @files = files
         | 
| 17 | 
            -
                end
         | 
| 6 | 
            +
                include Utils
         | 
| 18 7 |  | 
| 19 | 
            -
                 | 
| 20 | 
            -
             | 
| 21 | 
            -
                end
         | 
| 22 | 
            -
                alias_method :to_hash, :files
         | 
| 8 | 
            +
                attr_accessor :files, :keys
         | 
| 9 | 
            +
                attr_reader :yaml_keys, :all_keys
         | 
| 23 10 |  | 
| 24 | 
            -
                def  | 
| 25 | 
            -
                  @ | 
| 11 | 
            +
                def initialize(root_dir, from, to)
         | 
| 12 | 
            +
                  @root_dir = root_dir
         | 
| 13 | 
            +
                  @files = RailsI18nterface::Sourcefiles.extract_files(root_dir)
         | 
| 14 | 
            +
                  @yaml_keys = i18n_keys(I18n.default_locale)
         | 
| 15 | 
            +
                  @from_locale = from
         | 
| 16 | 
            +
                  @to_locale = to
         | 
| 17 | 
            +
                  @all_keys = (@files.keys.map(&:to_s) + @yaml_keys).uniq
         | 
| 26 18 | 
             
                end
         | 
| 27 | 
            -
                alias_method :to_tree, :names
         | 
| 28 19 |  | 
| 29 | 
            -
                def  | 
| 30 | 
            -
                  files. | 
| 20 | 
            +
                def reload
         | 
| 21 | 
            +
                  @files = RailsI18nterface::Sourcefiles.extract_files(root_dir)
         | 
| 22 | 
            +
                  @yaml_keys = i18n_keys(I18n.default_locale)
         | 
| 23 | 
            +
                  @all_keys = (@files.keys.map(&:to_s) + @yaml_keys).uniq
         | 
| 31 24 | 
             
                end
         | 
| 32 | 
            -
                alias_method :to_a, :keys
         | 
| 33 25 |  | 
| 34 26 | 
             
                def i18n_keys(locale)
         | 
| 35 27 | 
             
                  I18n.backend.send(:init_translations) unless I18n.backend.initialized?
         | 
| 36 | 
            -
                   | 
| 28 | 
            +
                  to_shallow_hash(I18n.backend.send(:translations)[locale.to_sym]).keys.sort
         | 
| 37 29 | 
             
                end
         | 
| 38 30 |  | 
| 39 31 | 
             
                def untranslated_keys
         | 
| 40 | 
            -
                  self.class.translated_locales.reduce({}) do | | 
| 41 | 
            -
                     | 
| 42 | 
            -
                      I18n.backend.send(:lookup,  | 
| 32 | 
            +
                  self.class.translated_locales.reduce({}) do |a, e|
         | 
| 33 | 
            +
                    a[e] = i18n_keys(I18n.default_locale).map do |key|
         | 
| 34 | 
            +
                      I18n.backend.send(:lookup, e, key).nil? ? key : nil
         | 
| 43 35 | 
             
                    end.compact
         | 
| 44 | 
            -
                     | 
| 36 | 
            +
                    a
         | 
| 45 37 | 
             
                  end
         | 
| 46 38 | 
             
                end
         | 
| 47 39 |  | 
| 48 40 | 
             
                def missing_keys
         | 
| 49 41 | 
             
                  locale = I18n.default_locale
         | 
| 42 | 
            +
                  filepath = Dir.glob(File.join(@root_dir, 'config', 'locales', '**', "#{locale}.yml"))
         | 
| 50 43 | 
             
                  yaml_keys = {}
         | 
| 51 | 
            -
                  yaml_keys =  | 
| 52 | 
            -
                     | 
| 44 | 
            +
                  yaml_keys = filepath.reduce({}) do |a, e|
         | 
| 45 | 
            +
                    a = a.deep_merge(Yamlfile.new(@root_dir, locale).read[locale.to_s])
         | 
| 53 46 | 
             
                  end
         | 
| 54 | 
            -
                  files.reject { |key, file|  | 
| 47 | 
            +
                  @files.keys.reject { |key, file| contains_key?(yaml_keys, key) }
         | 
| 55 48 | 
             
                end
         | 
| 56 49 |  | 
| 57 50 | 
             
                def self.translated_locales
         | 
| @@ -60,86 +53,5 @@ module RailsI18nterface | |
| 60 53 | 
             
                  end
         | 
| 61 54 | 
             
                end
         | 
| 62 55 |  | 
| 63 | 
            -
                # Checks if a nested hash contains the keys in dot separated I18n key.
         | 
| 64 | 
            -
                #
         | 
| 65 | 
            -
                # Example:
         | 
| 66 | 
            -
                #
         | 
| 67 | 
            -
                # hash = {
         | 
| 68 | 
            -
                #   :foo => {
         | 
| 69 | 
            -
                #     :bar => {
         | 
| 70 | 
            -
                #       :baz => 1
         | 
| 71 | 
            -
                #     }
         | 
| 72 | 
            -
                #   }
         | 
| 73 | 
            -
                # }
         | 
| 74 | 
            -
                #
         | 
| 75 | 
            -
                # contains_key?("foo", key) # => true
         | 
| 76 | 
            -
                # contains_key?("foo.bar", key) # => true
         | 
| 77 | 
            -
                # contains_key?("foo.bar.baz", key) # => true
         | 
| 78 | 
            -
                # contains_key?("foo.bar.baz.bla", key) # => false
         | 
| 79 | 
            -
                #
         | 
| 80 | 
            -
                def self.contains_key?(hash, key)
         | 
| 81 | 
            -
                  keys = key.to_s.split('.')
         | 
| 82 | 
            -
                  return false if keys.empty?
         | 
| 83 | 
            -
                  !keys.reduce(HashWithIndifferentAccess.new(hash)) do |memo, k|
         | 
| 84 | 
            -
                    memo.is_a?(Hash) ? memo.try(:[], k) : nil
         | 
| 85 | 
            -
                  end.nil?
         | 
| 86 | 
            -
                end
         | 
| 87 | 
            -
             | 
| 88 | 
            -
                # Convert something like:
         | 
| 89 | 
            -
                #
         | 
| 90 | 
            -
                # {
         | 
| 91 | 
            -
                #  :pressrelease => {
         | 
| 92 | 
            -
                #    :label => {
         | 
| 93 | 
            -
                #      :one => "Pressmeddelande"
         | 
| 94 | 
            -
                #    }
         | 
| 95 | 
            -
                #   }
         | 
| 96 | 
            -
                # }
         | 
| 97 | 
            -
                #
         | 
| 98 | 
            -
                # to:
         | 
| 99 | 
            -
                #
         | 
| 100 | 
            -
                #  {'pressrelease.label.one' => "Pressmeddelande"}
         | 
| 101 | 
            -
                #
         | 
| 102 | 
            -
                def self.to_shallow_hash(hash)
         | 
| 103 | 
            -
                  hash.reduce({}) do |shallow_hash, (key, value)|
         | 
| 104 | 
            -
                    if value.is_a?(Hash)
         | 
| 105 | 
            -
                      to_shallow_hash(value).each do |sub_key, sub_value|
         | 
| 106 | 
            -
                        shallow_hash[[key, sub_key].join('.')] = sub_value
         | 
| 107 | 
            -
                      end
         | 
| 108 | 
            -
                    else
         | 
| 109 | 
            -
                      shallow_hash[key.to_s] = value
         | 
| 110 | 
            -
                    end
         | 
| 111 | 
            -
                    shallow_hash
         | 
| 112 | 
            -
                  end
         | 
| 113 | 
            -
                end
         | 
| 114 | 
            -
             | 
| 115 | 
            -
                # Convert something like:
         | 
| 116 | 
            -
                #
         | 
| 117 | 
            -
                #  {'pressrelease.label.one' => "Pressmeddelande"}
         | 
| 118 | 
            -
                #
         | 
| 119 | 
            -
                # to:
         | 
| 120 | 
            -
                #
         | 
| 121 | 
            -
                # {
         | 
| 122 | 
            -
                #  :pressrelease => {
         | 
| 123 | 
            -
                #    :label => {
         | 
| 124 | 
            -
                #      :one => "Pressmeddelande"
         | 
| 125 | 
            -
                #    }
         | 
| 126 | 
            -
                #   }
         | 
| 127 | 
            -
                # }
         | 
| 128 | 
            -
                def self.to_deep_hash(hash)
         | 
| 129 | 
            -
                  hash.reduce({}) do |deep_hash, (key, value)|
         | 
| 130 | 
            -
                    keys = key.to_s.split('.').reverse
         | 
| 131 | 
            -
                    leaf_key = keys.shift
         | 
| 132 | 
            -
                    key_hash = keys.reduce({leaf_key.to_sym => value}) { |h, k| { k.to_sym => h } }
         | 
| 133 | 
            -
                    deep_merge!(deep_hash, key_hash)
         | 
| 134 | 
            -
                    deep_hash
         | 
| 135 | 
            -
                  end
         | 
| 136 | 
            -
                end
         | 
| 137 | 
            -
             | 
| 138 | 
            -
                # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
         | 
| 139 | 
            -
                def self.deep_merge!(hash1, hash2)
         | 
| 140 | 
            -
                  merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
         | 
| 141 | 
            -
                  hash1.merge!(hash2, &merger)
         | 
| 142 | 
            -
                end
         | 
| 143 | 
            -
             | 
| 144 56 | 
             
              end
         | 
| 145 57 | 
             
            end
         |