lit 0.0.4.3 → 0.1.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 +27 -35
- data/app/assets/javascripts/lit/localizations.js.coffee +8 -1
- data/app/assets/stylesheets/lit/application.css +4 -0
- data/app/controllers/lit/api/v1/base_controller.rb +19 -0
- data/app/controllers/lit/api/v1/locales_controller.rb +14 -0
- data/app/controllers/lit/api/v1/localization_keys_controller.rb +16 -0
- data/app/controllers/lit/api/v1/localizations_controller.rb +18 -0
- data/app/controllers/lit/application_controller.rb +1 -1
- data/app/controllers/lit/incomming_localizations_controller.rb +42 -0
- data/app/controllers/lit/localization_keys_controller.rb +2 -2
- data/app/controllers/lit/localizations_controller.rb +8 -2
- data/app/controllers/lit/sources_controller.rb +60 -0
- data/app/helpers/lit/localizations_helper.rb +1 -1
- data/app/helpers/lit/sources_helper.rb +4 -0
- data/app/models/lit/incomming_localization.rb +60 -0
- data/app/models/lit/locale.rb +3 -2
- data/app/models/lit/localization.rb +33 -3
- data/app/models/lit/localization_key.rb +2 -1
- data/app/models/lit/localization_version.rb +12 -0
- data/app/models/lit/source.rb +87 -0
- data/app/views/layouts/lit/_navigation.html.erb +3 -0
- data/app/views/lit/incomming_localizations/index.html.erb +47 -0
- data/app/views/lit/localization_keys/_localization_row.html.erb +11 -0
- data/app/views/lit/localization_keys/index.html.erb +12 -5
- data/app/views/lit/localizations/_form.html.erb +9 -1
- data/app/views/lit/localizations/_previous_versions_rows.html.erb +15 -0
- data/app/views/lit/localizations/previous_versions.js.erb +3 -0
- data/app/views/lit/localizations/update.js.erb +2 -2
- data/app/views/lit/sources/_form.html.erb +35 -0
- data/app/views/lit/sources/edit.html.erb +6 -0
- data/app/views/lit/sources/index.html.erb +36 -0
- data/app/views/lit/sources/new.html.erb +5 -0
- data/app/views/lit/sources/show.html.erb +18 -0
- data/config/routes.rb +32 -1
- data/db/migrate/20130921071304_create_lit_localization_versions.rb +11 -0
- data/db/migrate/20130923162141_create_lit_sources.rb +12 -0
- data/db/migrate/20130924151910_create_lit_incomming_localizations.rb +21 -0
- data/lib/generators/lit/install/templates/initializer.rb +34 -0
- data/lib/generators/lit/install_generator.rb +73 -0
- data/lib/lit.rb +2 -0
- data/lib/lit/adapters/hash_storage.rb +2 -2
- data/lib/lit/adapters/redis_storage.rb +25 -5
- data/lib/lit/cache.rb +30 -22
- data/lib/lit/i18n_backend.rb +9 -7
- data/lib/lit/version.rb +1 -1
- metadata +42 -2
@@ -1,28 +1,35 @@
|
|
1
1
|
module Lit
|
2
2
|
class Localization < ActiveRecord::Base
|
3
|
+
serialize :translated_value
|
4
|
+
serialize :default_value
|
3
5
|
|
4
6
|
## SCOPES
|
5
7
|
scope :changed, proc{ where(:is_changed=>true) }
|
8
|
+
# @HACK: dirty, find a way to round date to full second
|
9
|
+
scope :after, proc{|dt| where('updated_at >= ?', dt+1.second) }
|
6
10
|
|
7
11
|
## ASSOCIATIONS
|
8
12
|
belongs_to :locale
|
9
13
|
belongs_to :localization_key
|
14
|
+
has_many :localization_versions, dependent: :destroy
|
15
|
+
has_many :versions, class_name: '::Lit::LocalizationVersion'
|
10
16
|
|
11
17
|
## VALIDATIONS
|
12
18
|
validates :locale_id,
|
13
19
|
:presence=>true
|
14
20
|
|
15
|
-
|
21
|
+
unless defined?(::ActionController::StrongParameters)
|
16
22
|
## ACCESSIBLE
|
17
23
|
attr_accessible :translated_value, :locale_id
|
18
24
|
end
|
19
25
|
|
20
26
|
## BEFORE & AFTER
|
21
27
|
before_update :update_is_changed
|
28
|
+
before_update :create_version
|
22
29
|
after_update :mark_localization_key_completed
|
23
30
|
|
24
31
|
def to_s
|
25
|
-
self.
|
32
|
+
self.get_value
|
26
33
|
end
|
27
34
|
|
28
35
|
def full_key
|
@@ -30,7 +37,23 @@ module Lit
|
|
30
37
|
end
|
31
38
|
|
32
39
|
def get_value
|
33
|
-
is_changed? ? self.translated_value : self.default_value
|
40
|
+
(is_changed? && (not self.translated_value.nil?)) ? self.translated_value : self.default_value
|
41
|
+
end
|
42
|
+
|
43
|
+
def value
|
44
|
+
get_value
|
45
|
+
end
|
46
|
+
|
47
|
+
def localization_key_str
|
48
|
+
self.localization_key.localization_key
|
49
|
+
end
|
50
|
+
|
51
|
+
def locale_str
|
52
|
+
self.locale.locale
|
53
|
+
end
|
54
|
+
|
55
|
+
def last_change
|
56
|
+
self.updated_at.to_s(:db)
|
34
57
|
end
|
35
58
|
|
36
59
|
private
|
@@ -41,5 +64,12 @@ module Lit
|
|
41
64
|
def mark_localization_key_completed
|
42
65
|
self.localization_key.mark_completed!
|
43
66
|
end
|
67
|
+
|
68
|
+
def create_version
|
69
|
+
if self.translated_value.present? and (not self.translated_value.nil?)
|
70
|
+
l = self.localization_versions.new
|
71
|
+
l.translated_value = self.translated_value_was || self.default_value
|
72
|
+
end
|
73
|
+
end
|
44
74
|
end
|
45
75
|
end
|
@@ -7,6 +7,7 @@ module Lit
|
|
7
7
|
scope :not_completed, proc{ where(:is_completed=>false) }
|
8
8
|
scope :starred, proc{ where(:is_starred=>true) }
|
9
9
|
scope :ordered, proc{ order('localization_key asc') }
|
10
|
+
scope :after, proc{|dt| where('updated_at >= ?', dt) }
|
10
11
|
|
11
12
|
## ASSOCIATIONS
|
12
13
|
has_many :localizations, :dependent=>:destroy
|
@@ -16,7 +17,7 @@ module Lit
|
|
16
17
|
:presence=>true,
|
17
18
|
:uniqueness=>true
|
18
19
|
|
19
|
-
|
20
|
+
unless defined?(::ActionController::StrongParameters)
|
20
21
|
## ACCESSIBLE
|
21
22
|
attr_accessible :localization_key
|
22
23
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
module Lit
|
3
|
+
class Source < ActiveRecord::Base
|
4
|
+
LOCALES_PATH = "/api/v1/locales.json"
|
5
|
+
LOCALIZATION_KEYS_PATH = "/api/v1/localization_keys.json"
|
6
|
+
LOCALIZATIONS_PATH = "/api/v1/localizations.json"
|
7
|
+
LAST_CHANGE_PATH = "/api/v1/last_change.json"
|
8
|
+
|
9
|
+
## ASSOCIATIONS
|
10
|
+
has_many :incomming_localizations
|
11
|
+
|
12
|
+
## VALIDATIONS
|
13
|
+
validates :api_key, :identifier, :url,
|
14
|
+
:presence=>true
|
15
|
+
validates :url,
|
16
|
+
:format=>{:with=>/\Ahttps?:\/\/.*\/.*[^\/]\Z/i}
|
17
|
+
|
18
|
+
unless defined?(::ActionController::StrongParameters)
|
19
|
+
attr_accessible :api_key, :identifier, :url
|
20
|
+
end
|
21
|
+
|
22
|
+
## BEFORE & AFTER
|
23
|
+
after_validation :check_if_url_is_valid
|
24
|
+
|
25
|
+
|
26
|
+
def get_last_change
|
27
|
+
result = get_from_remote(LAST_CHANGE_PATH)
|
28
|
+
result["last_change"] unless result.nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
def synchronize
|
32
|
+
after = self.last_updated_at.nil? ? nil : self.last_updated_at.to_s(:db)
|
33
|
+
result = get_from_remote(LOCALIZATIONS_PATH, {:after=>after})
|
34
|
+
unless result.nil?
|
35
|
+
if result.is_a?(Array)
|
36
|
+
result.each do |r|
|
37
|
+
il = IncommingLocalization.new
|
38
|
+
if ::Rails::VERSION::MAJOR<4
|
39
|
+
il = IncommingLocalization.where(:incomming_id=>r["id"]).first_or_initialize
|
40
|
+
else
|
41
|
+
il = IncommingLocalization.find_or_initialize_by(:incomming_id=>r["id"])
|
42
|
+
end
|
43
|
+
il.source = self
|
44
|
+
il.locale_str = r["locale_str"]
|
45
|
+
il.locale = Locale.where(:locale=>il.locale_str).first
|
46
|
+
il.localization_key_str = r["localization_key_str"]
|
47
|
+
il.localization_key = LocalizationKey.where(:localization_key=>il.localization_key_str).first
|
48
|
+
il.save!
|
49
|
+
IncommingLocalization.where(:id=>il.id).update_all ['translated_value=?', r["value"]]
|
50
|
+
end
|
51
|
+
lc = get_last_change
|
52
|
+
lc = DateTime.parse(lc) unless lc.nil?
|
53
|
+
self.last_updated_at = lc || Time.now
|
54
|
+
self.save
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
def check_if_url_is_valid
|
61
|
+
if self.errors.empty? && (self.new_record? || self.url_changed?)
|
62
|
+
self.errors.add(:url, "is not accessible") if get_last_change.nil?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_from_remote(path, query_values={})
|
67
|
+
result = nil
|
68
|
+
#begin
|
69
|
+
uri = URI(self.url+path)
|
70
|
+
query_values.each do |k,v|
|
71
|
+
params = URI.decode_www_form(uri.query || []) << [k, v]
|
72
|
+
uri.query = URI.encode_www_form(params)
|
73
|
+
end
|
74
|
+
req = Net::HTTP::Get.new(uri.request_uri)
|
75
|
+
req.add_field("Authorization", %(Token token="#{self.api_key}"))
|
76
|
+
res = Net::HTTP.new(uri.host, uri.port).start do |http|
|
77
|
+
http.request(req)
|
78
|
+
end
|
79
|
+
if res.is_a?(Net::HTTPSuccess)
|
80
|
+
result = JSON.parse(res.body)
|
81
|
+
end
|
82
|
+
#rescue
|
83
|
+
#end
|
84
|
+
result
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -1,11 +1,14 @@
|
|
1
1
|
<%= link_to "Lost in translation", root_path, :class=>'brand' %>
|
2
2
|
<ul class="nav">
|
3
3
|
<li><%= link_to "Translate!", lit.localization_keys_path %></li>
|
4
|
+
<li><%= link_to "Synchronize", lit.sources_path %></li>
|
4
5
|
<li class="dropdown">
|
5
6
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
6
7
|
Settings
|
7
8
|
<b class="caret"></b>
|
8
9
|
</a>
|
10
|
+
<ul class="dropdown-menu">
|
11
|
+
</ul>
|
9
12
|
<ul class="dropdown-menu">
|
10
13
|
<li><%= link_to "Locales", lit.locales_path %></li>
|
11
14
|
</ul>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
<h1>Incomming localizations</h1>
|
2
|
+
<div class="row">
|
3
|
+
<span class="pull-right">
|
4
|
+
<%= link_to accept_all_source_incomming_localizations_path(@source), :class=>"btn btn-success", :data=>{:confirm=>t('lit.common.you_sure', :default=>"Are you sure?")} do %>
|
5
|
+
<%= t('lit.common.accept_all', :default=>"Accept all") %>
|
6
|
+
<% end %>
|
7
|
+
<%= link_to reject_all_source_incomming_localizations_path(@source), :class=>"btn btn-danger", :method=>:post, :data=>{:confirm=>t('lit.common.you_sure', :default=>"Are you sure?")} do %>
|
8
|
+
<%= t('lit.common.reject_all', :default=>"Reject all") %>
|
9
|
+
<% end %>
|
10
|
+
</span>
|
11
|
+
</div>
|
12
|
+
|
13
|
+
<table class="table table-bordered table-striped">
|
14
|
+
<tr>
|
15
|
+
<th>Current value</th>
|
16
|
+
<th>Imported value</th>
|
17
|
+
<th width="200px"></th>
|
18
|
+
</tr>
|
19
|
+
<% @incomming_localizations.each do |il| %>
|
20
|
+
<tr>
|
21
|
+
<td colspan="3">
|
22
|
+
<%= image_tag "lit/famfamfam_flags/#{il.locale_str[0,2]}.png" %>
|
23
|
+
<strong><%= il.full_key %></strong>
|
24
|
+
</td>
|
25
|
+
</tr>
|
26
|
+
<tr>
|
27
|
+
<td>
|
28
|
+
<% if il.localization %>
|
29
|
+
<%= render :partial=>"/lit/localization_keys/localization_row", :locals=>{:localization=>il.localization.get_value} %>
|
30
|
+
<% end %>
|
31
|
+
</td>
|
32
|
+
<Td>
|
33
|
+
<%= render :partial=>"/lit/localization_keys/localization_row", :locals=>{:localization=>il.get_value} %>
|
34
|
+
</td>
|
35
|
+
<td>
|
36
|
+
<%= link_to accept_source_incomming_localization_path(@source, il), :class=>"btn btn-success" do %>
|
37
|
+
<%= draw_icon "ok", :class=>"icon-white" %>
|
38
|
+
<%= t('lit.common.accept', :default=>"Accept") %>
|
39
|
+
<% end %>
|
40
|
+
<%= link_to source_incomming_localization_path(@source, il), :class=>"btn btn-danger", :method=>:delete, :data=>{:confirm=>t('lit.common.you_sure', :default=>"Are you sure?")} do %>
|
41
|
+
<%= draw_icon "remove", :class=>"icon-white" %>
|
42
|
+
<%= t('lit.common.reject', :default=>"Reject") %>
|
43
|
+
<% end %>
|
44
|
+
</td>
|
45
|
+
</tr>
|
46
|
+
<% end %>
|
47
|
+
</table>
|
@@ -17,20 +17,28 @@
|
|
17
17
|
<div class="detail_wrapper">
|
18
18
|
<table class="table table-bordered table-striped">
|
19
19
|
<%- I18n.backend.available_locales.each do |locale| %>
|
20
|
+
<%- localization = lk.localizations.where(:locale_id=>Lit.init.cache.find_locale(locale).id).first %>
|
20
21
|
<tr>
|
21
|
-
<%- localization = lk.localizations.where(:locale_id=>Lit.init.cache.find_locale(locale).id).first %>
|
22
22
|
<% unless localization %>
|
23
23
|
<% Lit.init.cache.refresh_key("#{locale}.#{lk.localization_key}") %>
|
24
24
|
<%- localization = lk.localizations.where(:locale_id=>Lit.init.cache.find_locale(locale).id).first %>
|
25
25
|
<% end %>
|
26
|
-
<td class="localization_row" data-id="<%= localization.id%>" data-edit="<%= edit_localization_key_localization_path(lk, localization) %>" data-editing=0 data-content="
|
27
|
-
<%= Lit.init.cache["#{locale}.#{lk.localization_key}"] %>
|
26
|
+
<td class="localization_row" data-id="<%= localization.id%>" data-edit="<%= edit_localization_key_localization_path(lk, localization) %>" data-editing=0 data-content="">
|
27
|
+
<%= render :partial=>"localization_row", :locals=>{:localization=>Lit.init.cache["#{locale}.#{lk.localization_key}"]} %>
|
28
28
|
</td>
|
29
29
|
<td class="locale_row">
|
30
30
|
<%= image_tag "lit/famfamfam_flags/#{locale[0,2]}.png" %>
|
31
31
|
<%= locale %>
|
32
|
+
<% if localization %>
|
33
|
+
<%= link_to lit.previous_versions_localization_key_localization_path(lk, localization), :class=>"show_prev_versions #{'hidden' if localization.versions.empty?}", :remote=>true do %>
|
34
|
+
<%= draw_icon 'random', :title=>t('lit.common.previous_versions', :default=>"Previous versions") %>
|
35
|
+
<% end %>
|
36
|
+
<% end %>
|
32
37
|
</td>
|
33
38
|
</tr>
|
39
|
+
<tr class="hidden localization_versions_row" data-id="<%= localization.id %>">
|
40
|
+
<td colspan="2" class="localization_versions"></td>
|
41
|
+
</tr>
|
34
42
|
<% end %>
|
35
43
|
</table>
|
36
44
|
</div>
|
@@ -39,9 +47,8 @@
|
|
39
47
|
<% end %>
|
40
48
|
|
41
49
|
</table>
|
42
|
-
<%
|
50
|
+
<% if defined?(Kaminari) %>
|
43
51
|
<%= paginate @localization_keys, :theme=>"lit" %>
|
44
|
-
<% rescue %>
|
45
52
|
<% end %>
|
46
53
|
<% content_for(:sidebar) do %>
|
47
54
|
<div class="well">
|
@@ -1,6 +1,14 @@
|
|
1
1
|
<%= form_for [@localization_key, @localization], :html=>{:remote=>true} do |f| %>
|
2
2
|
<%= f.label :translated_value %>
|
3
|
-
|
3
|
+
<% if @localization.translated_value.is_a?(Array) %>
|
4
|
+
<ul style="list-style: none;">
|
5
|
+
<% @localization.translated_value.each do |l| %>
|
6
|
+
<li><%= text_field_tag 'localization[translated_value][]', l, :class=>"input-xlarge" %></li>
|
7
|
+
<% end %>
|
8
|
+
</ul>
|
9
|
+
<% else %>
|
10
|
+
<%= f.text_area :translated_value, :size=>"40x2", :class=>"input-xxlarge" %>
|
11
|
+
<% end %>
|
4
12
|
<button class="btn" type="submit"><%= t('lit.common.update', :default=>"Update") %></button>
|
5
13
|
<button class="btn cancel"><%= t('lit.common.cancel', :default=>'Cancel') %></button>
|
6
14
|
<% end %>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<span class="pull-right"><%= draw_icon 'remove', :class=>"close_versions" %></span>
|
2
|
+
<table class="table table-condensed">
|
3
|
+
<tr>
|
4
|
+
<th><%= t('lit.common.previous_versions') %></th>
|
5
|
+
<th width="25%"><%= t('lit.common.created_at') %></th>
|
6
|
+
</tr>
|
7
|
+
<% @versions.each do |v| %>
|
8
|
+
<tr>
|
9
|
+
<td>
|
10
|
+
<%= render :partial=>"/lit/localization_keys/localization_row", :locals=>{:localization=>v.translated_value} %>
|
11
|
+
</td>
|
12
|
+
<td><%= v.created_at %></td>
|
13
|
+
</tr>
|
14
|
+
<% end %>
|
15
|
+
</table>
|
@@ -1,4 +1,4 @@
|
|
1
1
|
var $row = $('td.localization_row[data-id="<%= @localization.id %>"]');
|
2
2
|
$row.data('editing', 0);
|
3
|
-
$row.
|
4
|
-
$row.
|
3
|
+
$row.html("<%= ejs render(:partial=>"/lit/localization_keys/localization_row", :locals=>{:localization=>@localization.translated_value }) %>");
|
4
|
+
$row.siblings().find('.show_prev_versions').removeClass('hidden');
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<%= form_for(@source, :class=>"form-horizontal") do |f| %>
|
2
|
+
<% if @source.errors.any? %>
|
3
|
+
<div id="error_explanation">
|
4
|
+
<h2><%= pluralize(@source.errors.count, "error") %> prohibited this source from being saved:</h2>
|
5
|
+
|
6
|
+
<ul>
|
7
|
+
<% @source.errors.full_messages.each do |msg| %>
|
8
|
+
<li><%= msg %></li>
|
9
|
+
<% end %>
|
10
|
+
</ul>
|
11
|
+
</div>
|
12
|
+
<% end %>
|
13
|
+
<div class="control-group">
|
14
|
+
<%= f.label :identifier, :class=>"control-label" %>
|
15
|
+
<div class="controls">
|
16
|
+
<%= f.text_field :identifier %>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
<div class="control-group">
|
20
|
+
<%= f.label :url, :class=>"control-label" %>
|
21
|
+
<div class="controls">
|
22
|
+
<%= f.text_field :url, :placeholder=>"http://your_other_env.host/lit" %>
|
23
|
+
</div>
|
24
|
+
</div>
|
25
|
+
<div class="control-group">
|
26
|
+
<%= f.label :api_key, :class=>"control-label" %>
|
27
|
+
<div class="controls">
|
28
|
+
<%= f.text_field :api_key %>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
|
32
|
+
<div class="actions">
|
33
|
+
<%= f.submit t('lit.common.save'), :class=>"btn" %>
|
34
|
+
</div>
|
35
|
+
<% end %>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<h1>Synchronization sources</h1>
|
2
|
+
|
3
|
+
<table class="table">
|
4
|
+
<tr>
|
5
|
+
<th>Identifier</th>
|
6
|
+
<th>Last synchronization</th>
|
7
|
+
<th>Last change (remote)</th>
|
8
|
+
<th width="80px"></th>
|
9
|
+
</tr>
|
10
|
+
|
11
|
+
<% @sources.each do |source| %>
|
12
|
+
<tr>
|
13
|
+
<td><%= link_to source.identifier, lit.source_path(source) %></td>
|
14
|
+
<td><%= source.last_updated_at.to_s(:db) unless source.last_updated_at.nil? %></td>
|
15
|
+
<td><%= source.get_last_change %></td>
|
16
|
+
<td>
|
17
|
+
<%= link_to lit.synchronize_source_path(source), :title=>t('lit.common.synchronize', :default=>"Synchronize") do %>
|
18
|
+
<%= draw_icon 'refresh' %>
|
19
|
+
<% end %>
|
20
|
+
<%= link_to lit.source_path(source), :title=>t('lit.common.show', :default=>"Show") do %>
|
21
|
+
<%= draw_icon 'zoom-in' %>
|
22
|
+
<% end %>
|
23
|
+
<%= link_to lit.edit_source_path(source), :title=>t('lit.common.edit', :default=>"Edit") do %>
|
24
|
+
<%= draw_icon 'pencil' %>
|
25
|
+
<% end %>
|
26
|
+
<%= link_to lit.source_path(source), :method => :delete, :data => { :confirm => 'Are you sure?' }, :title=>t('lit.common.delete', :default=>"Delete") do %>
|
27
|
+
<%= draw_icon 'trash' %>
|
28
|
+
<% end %>
|
29
|
+
</td>
|
30
|
+
</tr>
|
31
|
+
<% end %>
|
32
|
+
</table>
|
33
|
+
|
34
|
+
<br />
|
35
|
+
|
36
|
+
<%= link_to 'New Source', new_source_path %>
|