diff --git a/README.md b/README.md
index b5e6e281..daa6128d 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ translating app by non-technicals.
Highly inspired by Copycopter by thoughtbot.
-[![travis status](https://travis-ci.org/prograils/lit.svg)](https://travis-ci.org/prograils/lit)
+[![travis status](https://api.travis-ci.org/3eggert/lit.svg?branch=js_translations)](https://api.travis-ci.org/3eggert/lit.svg?branch=js_translations)
### Features
diff --git a/app/controllers/lit/dashboard_controller.rb b/app/controllers/lit/dashboard_controller.rb
index e4e32936..8f949187 100644
--- a/app/controllers/lit/dashboard_controller.rb
+++ b/app/controllers/lit/dashboard_controller.rb
@@ -5,5 +5,10 @@ class DashboardController < ::Lit::ApplicationController
def index
@locales = Lit::Locale.ordered.visible
end
+
+ def clear_usage_data
+ Lit::LocalizationKey.where.not(used_last_at: nil).update_all(usage_count: 0, used_last_at: nil)
+ redirect_to root_path
+ end
end
end
diff --git a/app/controllers/lit/localization_keys_controller.rb b/app/controllers/lit/localization_keys_controller.rb
index a55f9644..bf80d0ef 100644
--- a/app/controllers/lit/localization_keys_controller.rb
+++ b/app/controllers/lit/localization_keys_controller.rb
@@ -9,6 +9,16 @@ def index
get_localization_keys
end
+ def not_used
+ @scope = @scope.not_used
+ get_localization_keys
+ end
+
+ def used
+ @scope = @scope.used
+ get_localization_keys
+ end
+
def not_translated
@scope = @scope.not_completed
get_localization_keys
diff --git a/app/jobs/lit/persit_global_hits_counters_job.rb b/app/jobs/lit/persit_global_hits_counters_job.rb
new file mode 100644
index 00000000..40d50744
--- /dev/null
+++ b/app/jobs/lit/persit_global_hits_counters_job.rb
@@ -0,0 +1,11 @@
+module Lit
+ if defined?(::ActiveJob)
+ class PersitGlobalHitsCountersJob < ::ActiveJob::Base
+ queue_as :default
+
+ def perform(update_array)
+ PersitGlobalHitsCountersService.new(update_array).execute
+ end
+ end
+ end
+end
diff --git a/app/models/lit/localization_key.rb b/app/models/lit/localization_key.rb
index b3d3bf3e..41836354 100644
--- a/app/models/lit/localization_key.rb
+++ b/app/models/lit/localization_key.rb
@@ -3,6 +3,8 @@ class LocalizationKey < Lit::Base
attr_accessor :interpolated_key
## SCOPES
+ scope :used, -> { where.not(used_last_at: nil) }
+ scope :not_used, -> { where(used_last_at: nil) }
scope :completed, -> { where(is_completed: true) }
scope :not_completed, -> { where(is_completed: false) }
scope :starred, -> { where(is_starred: true) }
diff --git a/app/services/persit_global_hits_counters_service.rb b/app/services/persit_global_hits_counters_service.rb
new file mode 100644
index 00000000..73ba9a6f
--- /dev/null
+++ b/app/services/persit_global_hits_counters_service.rb
@@ -0,0 +1,12 @@
+class PersitGlobalHitsCountersService
+ def initialize(update_array)
+ @update_array = update_array
+ end
+
+ def execute
+ @update_array.each do |a|
+ Lit::LocalizationKey.find(a[0]).update_columns(usage_count: a[1], used_last_at: Time.now)
+ end
+ end
+
+end
diff --git a/app/views/lit/dashboard/index.html.erb b/app/views/lit/dashboard/index.html.erb
index f9dcd4d4..f63dd54b 100644
--- a/app/views/lit/dashboard/index.html.erb
+++ b/app/views/lit/dashboard/index.html.erb
@@ -1,4 +1,6 @@
All localization keys <%= Lit::LocalizationKey.active.count(:id) %>
+Used localization keys <%= Lit::LocalizationKey.where.not(used_last_at: nil).count(:id) %>
+<%= button_to("clear usage data", {action: "clear_usage_data"}, data: {confirm: "Are you sure you want to clear the usage data?" }) %>
<% @locales.each do |l| %>
<%= EmojiFlag.new(l.locale) %> <%= I18n.t("lit.locale_to_languages.#{l.locale}", :default=>l.locale) %>: "><%= l.translated_percentage %>%
<% end %>
diff --git a/app/views/lit/localization_keys/_localizations_list.html.erb b/app/views/lit/localization_keys/_localizations_list.html.erb
index 7e99693b..0889831d 100644
--- a/app/views/lit/localization_keys/_localizations_list.html.erb
+++ b/app/views/lit/localization_keys/_localizations_list.html.erb
@@ -3,7 +3,13 @@
<%= lk.localization_key %>
- <%= Lit.init.cache.get_global_hits_counter(lk.localization_key) %>
+ <% if lk.used_last_at.present? %>
+ <%= "#{I18n.t('lit.used', default: 'used')} #{lk.usage_count} #{I18n.t('lit.times_since', default: 'times since')} #{l(Lit::LocalizationKey.maximum(:used_last_at), :format => :short4rb)}, #{I18n.t('lit.times_since', default: 'last use')} #{l(lk.used_last_at, :format => :short4rb)}" %>
+ <% elsif Lit::LocalizationKey.maximum(:used_last_at).present? %>
+ <%= "#{I18n.t('lit.not_used', default: 'not used since')} #{l(Lit::LocalizationKey.maximum(:used_last_at), :format => :short4rb)}" %>
+ <% else %>
+ <%= "#{I18n.t('lit.not_used', default: 'not used since')}" %>
+ <% end %>
<% if Lit.store_request_info %>
<%= link_to '#', class: 'request_info_link title', title: 'Show / hide request' do %>
diff --git a/app/views/lit/localization_keys/_sidebar.html.erb b/app/views/lit/localization_keys/_sidebar.html.erb
index 7de3365e..a836f856 100644
--- a/app/views/lit/localization_keys/_sidebar.html.erb
+++ b/app/views/lit/localization_keys/_sidebar.html.erb
@@ -12,7 +12,19 @@
<% end %>
- - ">
+
- ">
+ <%= link_to lit.not_used_localization_keys_path do -%>
+ <%= draw_icon 'times-circle' %>
+ not used
+ <% end %>
+
+ - ">
+ <%= link_to lit.used_localization_keys_path do -%>
+ <%= draw_icon 'check-circle' %>
+ used
+ <% end %>
+
+ - ">
<%= link_to lit.not_translated_localization_keys_path do -%>
<%= draw_icon 'pencil' %>
not translated
diff --git a/app/views/lit/localization_keys/not_used.html.erb b/app/views/lit/localization_keys/not_used.html.erb
new file mode 100644
index 00000000..454643d1
--- /dev/null
+++ b/app/views/lit/localization_keys/not_used.html.erb
@@ -0,0 +1,11 @@
+
<%= I18n.t('lit.not_used_header', default: 'Not used localization keys') %>
+
+<%= render 'localizations_list', available_locales: I18n.backend.available_locales %>
+
+<% if defined?(Kaminari) %>
+ <%= paginate @localization_keys, :theme=>"lit" %>
+<% elsif defined?(WillPaginate) %>
+ <%= will_paginate @localization_keys %>
+<% end %>
+
+<%= render 'sidebar' %>
diff --git a/app/views/lit/localization_keys/used.html.erb b/app/views/lit/localization_keys/used.html.erb
new file mode 100644
index 00000000..b8e835b1
--- /dev/null
+++ b/app/views/lit/localization_keys/used.html.erb
@@ -0,0 +1,11 @@
+<%= I18n.t('lit.used_header', default: 'Used localization keys') %>
+
+<%= render 'localizations_list', available_locales: I18n.backend.available_locales %>
+
+<% if defined?(Kaminari) %>
+ <%= paginate @localization_keys, :theme=>"lit" %>
+<% elsif defined?(WillPaginate) %>
+ <%= will_paginate @localization_keys %>
+<% end %>
+
+<%= render 'sidebar' %>
diff --git a/config/routes.rb b/config/routes.rb
index ac6b5d7c..fead5f72 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -24,6 +24,8 @@
get :starred
get :find_localization
get :not_translated
+ get :not_used
+ get :used
get :visited_again
end
resources :localizations, only: [:edit, :update, :show] do
@@ -50,6 +52,8 @@
end
end
+ post 'dashboard/clear_usage_data', to: 'dashboard#clear_usage_data', as: "dashboard_clear_usage_data"
+
resource :cloud_translation, only: :show
root to: 'dashboard#index'
diff --git a/db/migrate/20200227082719_lit_add_usage_count_and_used_last_at_to_lit_localization_keys.rb b/db/migrate/20200227082719_lit_add_usage_count_and_used_last_at_to_lit_localization_keys.rb
new file mode 100644
index 00000000..1dc50041
--- /dev/null
+++ b/db/migrate/20200227082719_lit_add_usage_count_and_used_last_at_to_lit_localization_keys.rb
@@ -0,0 +1,8 @@
+class LitAddUsageCountAndUsedLastAtToLitLocalizationKeys < Rails::VERSION::MAJOR >= 5 ?
+ ActiveRecord::Migration[4.2] :
+ ActiveRecord::Migration
+ def change
+ add_column :lit_localization_keys, :usage_count, :integer, index: true
+ add_column :lit_localization_keys, :used_last_at, :datetime, index: true
+ end
+end
diff --git a/lib/generators/lit/install/templates/initializer.rb b/lib/generators/lit/install/templates/initializer.rb
index edf471b6..40eeee01 100644
--- a/lib/generators/lit/install/templates/initializer.rb
+++ b/lib/generators/lit/install/templates/initializer.rb
@@ -50,7 +50,10 @@
# For more information please check the README.md
Lit.store_request_info = false
-# Initialize lit
-Lit.init
+# Persist global_hits_counter every 1000 lookups, set to nil or comment out to disable
+Lit.persit_global_hits_count = 1000
+
+# Initialize lit unless it ist disabled by setting the SKIP_LIT enviroment variable. Disabling is usefull to speed up the startup, for example to execute migrations
+Lit.init unless ENV["SKIP_LIT"] == "1"
diff --git a/lib/lit.rb b/lib/lit.rb
index 06dbedf1..0bb68f7d 100644
--- a/lib/lit.rb
+++ b/lib/lit.rb
@@ -17,6 +17,7 @@ module Lit
mattr_accessor :all_translations_are_html_safe
mattr_accessor :set_last_updated_at_upon_creation
mattr_accessor :store_request_info
+ mattr_accessor :persit_global_hits_count
class << self
attr_accessor :loader
diff --git a/lib/lit/cache.rb b/lib/lit/cache.rb
index 52c92ac6..89230246 100644
--- a/lib/lit/cache.rb
+++ b/lib/lit/cache.rb
@@ -20,6 +20,7 @@ module Lit
class Cache
def initialize
@hits_counter = Lit.get_key_value_engine
+ @hits = 0
@request_info_store = Lit.get_key_value_engine
@hits_counter_working = true
@keys = nil
@@ -143,6 +144,18 @@ def get_global_hits_counter(key)
@hits_counter['global_hits_counter.' + key]
end
+ def persit_global_hits_counters
+ update_array = []
+ @hits_counter.each do |k,v|
+ if k.match?(/^global_hits_counter/)
+ localization_key = find_localization_key(k.gsub("global_hits_counter.", ""))
+ update_array << [localization_key.id, @hits_counter[k] + localization_key.usage_count.to_i]
+ #localization_key.update_columns(usage_count: @hits_counter[k] + localization_key.usage_count.to_i, used_last_at: Time.now)
+ end
+ end
+ PersitGlobalHitsCountersJob.perform_later(update_array)
+ end
+
def get_hits_counter(key)
@hits_counter['hits_counter.' + key]
end
@@ -310,6 +323,8 @@ def find_or_create_localization_key(key_without_locale)
def update_hits_count(key)
return unless @hits_counter_working
key_without_locale = split_key(key).last
+ @hits += 1
+ persit_global_hits_counters if Lit.persit_global_hits_count.present? && (@hits%Lit.persit_global_hits_count) == 0
@hits_counter.incr('hits_counter.' + key)
@hits_counter.incr('global_hits_counter.' + key_without_locale)
end
diff --git a/lib/lit/export.rb b/lib/lit/export.rb
index 25a28541..c2a6d0a9 100644
--- a/lib/lit/export.rb
+++ b/lib/lit/export.rb
@@ -3,7 +3,7 @@
module Lit
class Export
def self.call(locale_keys:, format:, include_hits_count: false)
- raise ArgumentError, "format must be yaml or csv" if %i[yaml csv].exclude?(format)
+ raise ArgumentError, "format must be yaml, json_js or csv" if %i[json_js yaml csv].exclude?(format)
Lit.loader.cache.load_all_translations
localizations_scope = Lit::Localization.active
if locale_keys.present?
@@ -19,7 +19,10 @@ def self.call(locale_keys:, format:, include_hits_count: false)
when :yaml
exported_keys = nested_string_keys_to_hash(db_localizations)
exported_keys.to_yaml
- when :csv
+ when :json_js
+ exported_keys = nested_string_keys_to_hash(db_localizations, "javascript")
+ "var js_locale= " + exported_keys.to_json
+ when :csv
relevant_locales = locale_keys.presence || I18n.available_locales.map(&:to_s)
CSV.generate do |csv|
csv << ['key', *relevant_locales, ('hits' if include_hits_count)].compact
@@ -55,7 +58,7 @@ def self.call(locale_keys:, format:, include_hits_count: false)
end
end
- private_class_method def self.nested_string_keys_to_hash(db_localizations)
+ private_class_method def self.nested_string_keys_to_hash(db_localizations, key_selector=nil)
# http://subtech.g.hatena.ne.jp/cho45/20061122
deep_proc = proc do |_k, s, o|
if s.is_a?(Hash) && o.is_a?(Hash)
@@ -66,8 +69,11 @@ def self.call(locale_keys:, format:, include_hits_count: false)
nested_keys = {}
db_localizations.sort.each do |k, v|
key_parts = k.to_s.split('.')
- converted = key_parts.reverse.reduce(v) { |a, n| { n => a } }
- nested_keys.merge!(converted, &deep_proc)
+ if (key_selector.present? && key_parts[1] == key_selector) || key_selector.nil?
+ key_parts = key_parts.drop(2) if key_selector.present?
+ converted = key_parts.reverse.reduce(v) { |a, n| { n => a } }
+ nested_keys.merge!(converted, &deep_proc)
+ end
end
nested_keys
end
|