weeler 1.4.0 → 1.5.1
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.
- checksums.yaml +4 -4
- data/.travis.yml +13 -3
- data/CHANGELOG.md +24 -0
- data/Rakefile +4 -0
- data/app/controllers/weeler/translations_controller.rb +13 -7
- data/app/views/weeler/translations/_translation.html.haml +2 -2
- data/app/views/weeler/translations/edit.html.haml +3 -3
- data/app/views/weeler/translations/new.html.haml +2 -2
- data/app/views/weeler/translations/usage_stats.html.haml +10 -4
- data/lib/generators/weeler/templates/migrations/create_weeler_locks.rb +14 -0
- data/lib/generators/weeler/templates/migrations/create_weeler_translation_stats.rb +11 -0
- data/lib/i18n/backend/weeler.rb +15 -6
- data/lib/i18n/backend/weeler/lock.rb +78 -0
- data/lib/i18n/backend/weeler/translation_stat.rb +25 -0
- data/lib/i18n/backend/weeler/usage_logger.rb +17 -1
- data/lib/weeler/action_controller/acts/restful.rb +1 -1
- data/lib/weeler/engine.rb +1 -1
- data/lib/weeler/version.rb +2 -2
- data/spec/.gitignore +21 -0
- data/spec/dummy/config/database.yml +2 -24
- data/spec/dummy/db/migrate/20160330161101_create_weeler_locks.rb +14 -0
- data/spec/dummy/db/migrate/20160330192005_create_weeler_translation_stats.rb +11 -0
- data/spec/dummy/db/schema.rb +31 -11
- data/spec/dummy/log/development.log +780 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/weeler/action_controller/acts/restful_spec.rb +1 -1
- data/spec/weeler/i18n/backend/weeler/lock_spec.rb +89 -0
- data/spec/weeler/i18n/backend/weeler/usage_logger_spec.rb +34 -0
- data/spec/weeler/i18n/backend/weeler_spec.rb +22 -0
- data/weeler.gemspec +2 -2
- metadata +18 -8
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 21fd389096c8af80e13c46bf777233d15188fa71
|
4
|
+
data.tar.gz: 783c33428045e4d05b7e76fc10a991cafc3f9b2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39c2ceb91177c876eadeb18b9e03b86fc8367c33a48cc81f4b2e627741290816c5d8ecd8c20188c87e1f776e3e6df7f1f16e19f154007464e4200d9b25123ee1
|
7
|
+
data.tar.gz: e9602c77a0ea9738ae4eb0c8dd91c98bdfb228a594e9ead83d41b0bcbf4bb0a799f19fabeb8c2c479c0e07b0be4b148b0da8b19388d4e8bd47edfb8954f187e4
|
data/.travis.yml
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
language: ruby
|
2
|
+
before_install:
|
3
|
+
- rvm get head
|
4
|
+
services:
|
5
|
+
- postgresql
|
6
|
+
sudo: false
|
7
|
+
before_script:
|
8
|
+
- psql -c 'create database travis_ci_test;' -U postgres
|
2
9
|
rvm:
|
3
10
|
- "2.0.0"
|
4
11
|
- "2.1.0"
|
@@ -11,7 +18,10 @@ rvm:
|
|
11
18
|
- "2.2.0"
|
12
19
|
- "2.2.1"
|
13
20
|
- "2.2.2"
|
14
|
-
- "
|
15
|
-
- "
|
21
|
+
- "2.2.3"
|
22
|
+
- "2.2.4"
|
23
|
+
- "2.3.0"
|
16
24
|
# uncomment this line if your project needs to run something other than `rake`:
|
17
|
-
script:
|
25
|
+
script:
|
26
|
+
- RAILS_ENV=test bundle exec rake db:migrate --trace
|
27
|
+
- bundle exec rspec spec
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
## 1.5.1
|
2
|
+
|
3
|
+
* Fixed version number
|
4
|
+
|
5
|
+
### Contributors
|
6
|
+
|
7
|
+
* Artis Raugulis
|
8
|
+
|
9
|
+
## 1.4.0
|
10
|
+
|
11
|
+
* Added translation usage stats
|
12
|
+
* Fixed a transliteration bug
|
13
|
+
|
14
|
+
### Contributors
|
15
|
+
|
16
|
+
* Artis Raugulis
|
17
|
+
|
18
|
+
## 1.5.0
|
19
|
+
|
20
|
+
* Added Lock
|
21
|
+
* Added translation usage stats export
|
22
|
+
* Dropped jruby support
|
23
|
+
* Dropped rbx suport
|
24
|
+
|
1
25
|
## 1.4.0
|
2
26
|
|
3
27
|
* Added translation usage stats
|
data/Rakefile
CHANGED
@@ -20,7 +20,7 @@ module Weeler
|
|
20
20
|
|
21
21
|
if @translation.save
|
22
22
|
Settings.i18n_updated_at = Time.now
|
23
|
-
redirect_to
|
23
|
+
redirect_to ({ action: :edit, id: @translation }), flash: { success: "Translation saved." }
|
24
24
|
else
|
25
25
|
flash.now[:error] = "Errors in saving."
|
26
26
|
render :edit
|
@@ -33,7 +33,7 @@ module Weeler
|
|
33
33
|
if @translation.update_attributes(translation_params)
|
34
34
|
Settings.i18n_updated_at = Time.now
|
35
35
|
|
36
|
-
redirect_to
|
36
|
+
redirect_to ({ action: :edit, id: @translation }), flash: { success: "Translation updated." }
|
37
37
|
else
|
38
38
|
flash.now[:error] = "Errors in updating."
|
39
39
|
render :edit
|
@@ -46,13 +46,19 @@ module Weeler
|
|
46
46
|
|
47
47
|
Settings.i18n_updated_at = Time.now
|
48
48
|
|
49
|
-
redirect_to
|
49
|
+
redirect_to ({ action: :index }), flash: {success: "Translation succesfully removed."}
|
50
50
|
end
|
51
51
|
|
52
52
|
def usage_stats
|
53
53
|
@used_keys = []
|
54
|
-
|
55
|
-
|
54
|
+
if Settings.log_key_usage == 'dump'
|
55
|
+
I18n::Backend::Weeler::TranslationStat.all.each do |translation_stat|
|
56
|
+
@used_keys << [translation_stat.key, translation_stat.usage_count]
|
57
|
+
end
|
58
|
+
else
|
59
|
+
Weeler.i18n_cache.instance_variable_get(:@data).keys.each do |key|
|
60
|
+
@used_keys << [key, Weeler.i18n_cache.read(key)] if key.start_with?('usage_stats')
|
61
|
+
end
|
56
62
|
end
|
57
63
|
end
|
58
64
|
|
@@ -72,9 +78,9 @@ module Weeler
|
|
72
78
|
|
73
79
|
Settings.i18n_updated_at = Time.now
|
74
80
|
|
75
|
-
redirect_to
|
81
|
+
redirect_to ({ action: :index }), flash: {success: "Translations succesfully imported."}
|
76
82
|
else
|
77
|
-
redirect_to
|
83
|
+
redirect_to ({ action: :index }), flash: {success: "No file choosen"}
|
78
84
|
end
|
79
85
|
end
|
80
86
|
|
@@ -8,5 +8,5 @@
|
|
8
8
|
%td= translation.interpolations
|
9
9
|
%td.text-center= translation.created_at.strftime("%d/%m/%Y")
|
10
10
|
%td
|
11
|
-
= link_to 'Edit',
|
12
|
-
= link_to 'Remove',
|
11
|
+
= link_to 'Edit', { action: :edit, id: translation.id }, class: 'btn btn-default'
|
12
|
+
= link_to 'Remove', { action: :destroy, id: translation }, data: { confirm: 'Are you sure you want to remove?' }, method: :delete, class: 'btn btn-danger'
|
@@ -6,9 +6,9 @@
|
|
6
6
|
.edit_user.container
|
7
7
|
.row
|
8
8
|
.col-lg-12.col-md-12
|
9
|
-
= form_for @translation, {url:
|
9
|
+
= form_for @translation, {url: { action: :update, id: @translation }, html: {class: "form-horizontal", role: "form"}} do |f|
|
10
10
|
= render partial: "form", locals: {translation: @translation, f: f}
|
11
11
|
%p.text-center
|
12
12
|
%button.btn.btn-primary{type: "submit"} Save
|
13
|
-
|
14
|
-
= link_to 'Remove',
|
13
|
+
= link_to 'Cancel', { action: :index }, class: 'btn btn-link'
|
14
|
+
= link_to 'Remove', { action: :destroy, id: @translation}, :confirm => "Are you sure you want remove?", :method => :delete, :class => "btn btn-danger"
|
@@ -6,8 +6,8 @@
|
|
6
6
|
.edit_user.container
|
7
7
|
.row
|
8
8
|
.col-lg-12.col-md-12
|
9
|
-
= form_for @translation, {url:
|
9
|
+
= form_for @translation, {url: { action: :create }, html: {class: "form-horizontal", role: "form"}} do |f|
|
10
10
|
= render partial: "form", locals: {translation: @translation, f: f}
|
11
11
|
%p.text-center
|
12
12
|
%button.btn.btn-primary{type: "submit"} Save
|
13
|
-
|
13
|
+
= link_to 'Cancel', { action: :index }, class: 'btn btn-link'
|
@@ -22,7 +22,13 @@
|
|
22
22
|
%th text
|
23
23
|
%tbody
|
24
24
|
- @used_keys.each do |key, usage|
|
25
|
-
|
26
|
-
%
|
27
|
-
|
28
|
-
|
25
|
+
- begin
|
26
|
+
%tr
|
27
|
+
%td= usage
|
28
|
+
%td= key.to_s.gsub('usage_stats/en/', '')
|
29
|
+
%td= CGI::unescapeHTML(CGI::escapeHTML(t(key.to_s.gsub('usage_stats/en/', ''))))
|
30
|
+
- rescue => e
|
31
|
+
%tr
|
32
|
+
%td= "err #{usage}"
|
33
|
+
%td= key
|
34
|
+
%td= e.message
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class CreateWeelerLocks < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :weeler_locks do |t|
|
4
|
+
t.string :name, :limit => 40
|
5
|
+
t.timestamps
|
6
|
+
end
|
7
|
+
add_index :weeler_locks, :name, :unique => true
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.down
|
11
|
+
remove_index :weeler_locks, :column => :name
|
12
|
+
drop_table :weeler_locks
|
13
|
+
end
|
14
|
+
end
|
data/lib/i18n/backend/weeler.rb
CHANGED
@@ -5,6 +5,8 @@ require 'i18n/backend/weeler/html_checker'
|
|
5
5
|
require 'i18n/backend/weeler/exporter'
|
6
6
|
require 'i18n/backend/weeler/importer'
|
7
7
|
require 'i18n/backend/weeler/usage_logger'
|
8
|
+
require 'i18n/backend/weeler/translation_stat'
|
9
|
+
require 'i18n/backend/weeler/lock'
|
8
10
|
|
9
11
|
module I18n
|
10
12
|
module Backend
|
@@ -24,12 +26,14 @@ module I18n
|
|
24
26
|
|
25
27
|
PLURAL_KEYS = ["zero", "one", "other"]
|
26
28
|
|
27
|
-
autoload :HtmlChecker,
|
28
|
-
autoload :Translation,
|
29
|
-
autoload :Translation,
|
30
|
-
autoload :Exporter,
|
31
|
-
autoload :Importer,
|
32
|
-
autoload :UsageLogger,
|
29
|
+
autoload :HtmlChecker, 'i18n/backend/weeler/html_checker'
|
30
|
+
autoload :Translation, 'i18n/backend/weeler/dedupe'
|
31
|
+
autoload :Translation, 'i18n/backend/weeler/translation'
|
32
|
+
autoload :Exporter, 'i18n/backend/weeler/exporter'
|
33
|
+
autoload :Importer, 'i18n/backend/weeler/importer'
|
34
|
+
autoload :UsageLogger, 'i18n/backend/weeler/usage_logger'
|
35
|
+
autoload :TranslationStat, 'i18n/backend/weeler/translation_stat'
|
36
|
+
autoload :Lock, 'i18n/backend/weeler/lock'
|
33
37
|
|
34
38
|
module Implementation
|
35
39
|
include Base, Flatten
|
@@ -72,9 +76,14 @@ module I18n
|
|
72
76
|
|
73
77
|
# log locale/key usage for statistics
|
74
78
|
if Settings.log_key_usage == 'true'
|
79
|
+
i18n_cache.delete([:dump_usage_stats, Process.pid])
|
75
80
|
log_key_usage(locale, key)
|
76
81
|
end
|
77
82
|
|
83
|
+
if Settings.log_key_usage == 'dump'
|
84
|
+
dump_key_usage
|
85
|
+
end
|
86
|
+
|
78
87
|
return nil if i18n_cache.read([:missing, [locale, key]])
|
79
88
|
|
80
89
|
keys = expand_keys key
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Backend
|
5
|
+
# Weeler model used to store locks
|
6
|
+
#
|
7
|
+
# This model expects a table like the following to be already set up in
|
8
|
+
# your the database:
|
9
|
+
#
|
10
|
+
# def self.up
|
11
|
+
# create_table :weeler_locks do |t|
|
12
|
+
# t.string :name, :limit => 40
|
13
|
+
# t.timestamps
|
14
|
+
# end
|
15
|
+
# add_index :weeler_locks, :name, :unique => true
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# def self.down
|
19
|
+
# remove_index :weeler_locks, :column => :name
|
20
|
+
# drop_table :weeler_locks
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
class Weeler
|
24
|
+
class Lock < ActiveRecord::Base
|
25
|
+
|
26
|
+
self.table_name = 'weeler_locks'
|
27
|
+
|
28
|
+
def self.acquire(name)
|
29
|
+
already_acquired = definitely_acquired?(name)
|
30
|
+
|
31
|
+
if already_acquired
|
32
|
+
yield
|
33
|
+
else
|
34
|
+
begin
|
35
|
+
create(:name => name) unless find_by(name: name)
|
36
|
+
rescue ActiveRecord::StatementInvalid
|
37
|
+
# concurrent create is okay
|
38
|
+
end
|
39
|
+
|
40
|
+
begin
|
41
|
+
result = nil
|
42
|
+
transaction do
|
43
|
+
self.lock(true).find_by(name: name) # this is the call that will block
|
44
|
+
acquired_lock(name)
|
45
|
+
result = yield
|
46
|
+
end
|
47
|
+
|
48
|
+
result
|
49
|
+
ensure
|
50
|
+
maybe_released_lock(name)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# if true, the lock is acquired
|
56
|
+
# if false, the lock might still be acquired, because we were in another db transaction
|
57
|
+
def self.definitely_acquired?(name)
|
58
|
+
!!Thread.current[:definitely_acquired_locks] and Thread.current[:definitely_acquired_locks].has_key?(name)
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.acquired_lock(name)
|
62
|
+
logger.debug("Acquired lock '#{name}'")
|
63
|
+
Thread.current[:definitely_acquired_locks] ||= {}
|
64
|
+
Thread.current[:definitely_acquired_locks][name] = true
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.maybe_released_lock(name)
|
68
|
+
logger.debug("Released lock '#{name}' (if we are not in a bigger transaction)")
|
69
|
+
Thread.current[:definitely_acquired_locks] ||= {}
|
70
|
+
Thread.current[:definitely_acquired_locks].delete(name)
|
71
|
+
end
|
72
|
+
|
73
|
+
private_class_method :acquired_lock, :maybe_released_lock
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Backend
|
5
|
+
# Weeler model used to store translation key usage statistics
|
6
|
+
#
|
7
|
+
# This model expects a table like the following to be already set up in
|
8
|
+
# your the database:
|
9
|
+
#
|
10
|
+
# create_table :weeler_translation_stats do |t|
|
11
|
+
# t.string :key
|
12
|
+
# t.integer :usage_count, default: 0
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
class Weeler
|
16
|
+
class TranslationStat < ::ActiveRecord::Base
|
17
|
+
|
18
|
+
self.table_name = 'weeler_translation_stats'
|
19
|
+
|
20
|
+
validates :key, uniqueness: true
|
21
|
+
validates :key, :usage_count, presence: true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -11,7 +11,23 @@ module I18n
|
|
11
11
|
value = existing.present? ? (existing.to_i + 1) : 1
|
12
12
|
i18n_cache.write [:usage_stats, [locale, key]], value
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
|
+
def dump_key_usage
|
16
|
+
already_dumped = i18n_cache.read([:dump_usage_stats, Process.pid]).present?
|
17
|
+
unless already_dumped
|
18
|
+
Weeler::Lock.acquire('usage_stats_dump') do
|
19
|
+
i18n_cache.instance_variable_get(:@data).keys.each do |key|
|
20
|
+
if key.start_with?('usage_stats')
|
21
|
+
translation_stat = TranslationStat.find_or_create_by(key: key.gsub('usage_stats/en/', ''))
|
22
|
+
translation_stat.usage_count += i18n_cache.read(key).to_i
|
23
|
+
translation_stat.save!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
i18n_cache.write [:dump_usage_stats, Process.pid], Process.pid
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
15
31
|
Weeler.send(:include, UsageLogger)
|
16
32
|
end
|
17
33
|
end
|
@@ -118,7 +118,7 @@ module Weeler
|
|
118
118
|
permited_params.call(params)
|
119
119
|
elsif permited_params.blank?
|
120
120
|
warning_suggestion = params[parameterized_name.to_sym].is_a?(Hash) ? params[parameterized_name.to_sym].keys.map{ |k| k.to_sym } : "permit_params:"
|
121
|
-
warn "[UNPERMITED PARAMS] To
|
121
|
+
warn "[UNPERMITED PARAMS] To permit #{params[parameterized_name.to_sym].inspect} params, add 'permit_params: #{warning_suggestion}' option to 'acts_as_restful'"
|
122
122
|
else
|
123
123
|
params.require(parameterized_name.to_sym).permit(permited_params)
|
124
124
|
end
|
data/lib/weeler/engine.rb
CHANGED
@@ -10,7 +10,7 @@ module Weeler
|
|
10
10
|
config.weeler = Weeler
|
11
11
|
|
12
12
|
config.i18n.available_locales = [:en] unless config.i18n.available_locales.present?
|
13
|
-
|
13
|
+
config.active_record.raise_in_transactional_callbacks = true
|
14
14
|
config.assets.precompile += ["weeler/init.js", "weeler/init.css"]
|
15
15
|
|
16
16
|
# Load extend Rails classes
|
data/lib/weeler/version.rb
CHANGED
data/spec/.gitignore
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
.coveralls.yml
|
19
|
+
.DS_Store
|
20
|
+
spec/dummy/log/test.log
|
21
|
+
rspec.html
|
@@ -1,25 +1,3 @@
|
|
1
|
-
# SQLite version 3.x
|
2
|
-
# gem install sqlite3
|
3
|
-
#
|
4
|
-
# Ensure the SQLite 3 gem is defined in your Gemfile
|
5
|
-
# gem 'sqlite3'
|
6
|
-
development:
|
7
|
-
adapter: sqlite3
|
8
|
-
database: db/development.sqlite3
|
9
|
-
pool: 5
|
10
|
-
timeout: 5000
|
11
|
-
|
12
|
-
# Warning: The database defined as "test" will be erased and
|
13
|
-
# re-generated from your development database when you run "rake".
|
14
|
-
# Do not set this db to the same as development or production.
|
15
1
|
test:
|
16
|
-
adapter:
|
17
|
-
database:
|
18
|
-
pool: 5
|
19
|
-
timeout: 5000
|
20
|
-
|
21
|
-
production:
|
22
|
-
adapter: sqlite3
|
23
|
-
database: db/production.sqlite3
|
24
|
-
pool: 5
|
25
|
-
timeout: 5000
|
2
|
+
adapter: postgresql
|
3
|
+
database: travis_ci_test
|