lit 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -1
- data/app/assets/javascripts/lit/application.js +0 -2
- data/app/assets/stylesheets/lit/application.css +15 -3
- data/app/controllers/lit/localizations_controller.rb +1 -1
- data/app/controllers/lit/sources_controller.rb +6 -0
- data/app/helpers/lit/localizations_helper.rb +6 -2
- data/app/models/lit/incomming_localization.rb +3 -3
- data/app/models/lit/localization.rb +17 -6
- data/app/models/lit/localization_key.rb +1 -1
- data/app/models/lit/source.rb +21 -5
- data/app/views/layouts/lit/_navigation.html.erb +23 -16
- data/app/views/layouts/lit/application.html.erb +10 -10
- data/app/views/lit/dashboard/index.html.erb +0 -1
- data/app/views/lit/incomming_localizations/index.html.erb +6 -6
- data/app/views/lit/locales/index.html.erb +1 -1
- data/app/views/lit/localization_keys/index.html.erb +8 -6
- data/app/views/lit/localization_keys/star.js.erb +1 -1
- data/app/views/lit/localizations/_form.html.erb +12 -9
- data/app/views/lit/localizations/_previous_versions_rows.html.erb +1 -1
- data/app/views/lit/sources/_form.html.erb +4 -4
- data/app/views/lit/sources/index.html.erb +4 -1
- data/app/views/lit/sources/show.html.erb +1 -0
- data/config/routes.rb +1 -0
- data/lib/generators/lit/install/templates/initializer.rb +7 -0
- data/lib/lit.rb +3 -0
- data/lib/lit/adapters/redis_storage.rb +12 -3
- data/lib/lit/cache.rb +48 -25
- data/lib/lit/engine.rb +0 -1
- data/lib/lit/i18n_backend.rb +20 -20
- data/lib/lit/version.rb +1 -1
- data/lib/tasks/lit_tasks.rake +1 -4
- metadata +3 -20
- data/app/assets/stylesheets/lit/bootstrap_and_overrides.css.scss +0 -43
data/README.md
CHANGED
@@ -47,7 +47,7 @@ You may want to take a look at generated initializer in `config/initializers/lit
|
|
47
47
|
* ~~API~~
|
48
48
|
* ~~Synchronization between environments~~
|
49
49
|
* Rewrite initializer
|
50
|
-
* Rewrite exporter (which is now code from copycopter)
|
50
|
+
* ~~Rewrite exporter (which is now code from copycopter)~~
|
51
51
|
* ~~Support for array types (ie. `date.abbr_day_names`)~~
|
52
52
|
* ~~Generator~~
|
53
53
|
* ~~Support for wysiwyg~~
|
@@ -8,7 +8,6 @@
|
|
8
8
|
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
9
|
* compiled file, but it's generally better to create a new file per style scope.
|
10
10
|
*
|
11
|
-
*= require './bootstrap_and_overrides.css'
|
12
11
|
*= require './jquery-te-1.4.0.css'
|
13
12
|
*= require_self
|
14
13
|
*/
|
@@ -16,7 +15,7 @@
|
|
16
15
|
padding: 10px 0 0 50px;
|
17
16
|
}
|
18
17
|
.detail_wrapper table tr td.locale_row{
|
19
|
-
width:
|
18
|
+
width: 75px;
|
20
19
|
}
|
21
20
|
.localization_key_row .localization_keys_options{
|
22
21
|
display: none;
|
@@ -26,7 +25,7 @@
|
|
26
25
|
display: block;
|
27
26
|
}
|
28
27
|
|
29
|
-
li.key_prefix .
|
28
|
+
li.key_prefix .fa-chevron-right {
|
30
29
|
float: right;
|
31
30
|
margin-top: 2px;
|
32
31
|
margin-right: -6px;
|
@@ -36,3 +35,16 @@ li.key_prefix .icon-chevron-right {
|
|
36
35
|
.hidden{
|
37
36
|
display: none;
|
38
37
|
}
|
38
|
+
i.fa{
|
39
|
+
color: black;
|
40
|
+
}
|
41
|
+
.nav.nav-stacked>li>a {
|
42
|
+
padding: 5px 7px;
|
43
|
+
}
|
44
|
+
.well{
|
45
|
+
background-color: white;
|
46
|
+
border-radius: 0px;
|
47
|
+
}
|
48
|
+
.well label{
|
49
|
+
font-weight: normal;
|
50
|
+
}
|
@@ -10,7 +10,7 @@ module Lit
|
|
10
10
|
|
11
11
|
def update
|
12
12
|
if @localization.update_attributes(clear_params)
|
13
|
-
Lit.init.cache.
|
13
|
+
Lit.init.cache.update_cache @localization.full_key, @localization.get_value
|
14
14
|
end
|
15
15
|
@localization.reload
|
16
16
|
respond_to :js
|
@@ -24,6 +24,12 @@ module Lit
|
|
24
24
|
redirect_to lit.source_incomming_localizations_path(@source)
|
25
25
|
end
|
26
26
|
|
27
|
+
def touch
|
28
|
+
@source = Source.find(params[:id])
|
29
|
+
@source.touch_last_updated_at!
|
30
|
+
redirect_to request.env["HTTP_REFERER"].present? ? :back : @source
|
31
|
+
end
|
32
|
+
|
27
33
|
def create
|
28
34
|
@source = Source.new(clear_params)
|
29
35
|
if @source.save
|
@@ -1,11 +1,15 @@
|
|
1
1
|
module Lit
|
2
2
|
module LocalizationsHelper
|
3
3
|
def draw_icon(icon, opts={})
|
4
|
-
raw("<i class=\"
|
4
|
+
raw("<i class=\"fa fa-#{icon} #{opts[:class]}\" title=\"#{opts[:title]}\" ></i>")
|
5
5
|
end
|
6
6
|
|
7
7
|
def ejs(val)
|
8
8
|
escape_javascript val.to_s
|
9
9
|
end
|
10
|
+
|
11
|
+
def allow_wysiwyg_editor?(key)
|
12
|
+
Lit.all_translations_are_html_safe || key.to_s =~ /(\b|_|\.)html$/
|
13
|
+
end
|
10
14
|
end
|
11
|
-
end
|
15
|
+
end
|
@@ -32,19 +32,19 @@ module Lit
|
|
32
32
|
unless self.locale.present?
|
33
33
|
self.locale = Lit::Locale.new
|
34
34
|
self.locale.locale = self.locale_str
|
35
|
-
self.locale.save
|
35
|
+
self.locale.save!
|
36
36
|
end
|
37
37
|
unless self.localization_key.present?
|
38
38
|
self.localization_key = Lit::LocalizationKey.new
|
39
39
|
self.localization_key.localization_key = self.localization_key_str
|
40
|
-
self.localization_key.save
|
40
|
+
self.localization_key.save!
|
41
41
|
end
|
42
42
|
unless self.localization.present?
|
43
43
|
self.localization = Lit::Localization.new
|
44
44
|
self.localization.locale = self.locale
|
45
45
|
self.localization.localization_key = self.localization_key
|
46
46
|
self.localization.default_value = self.translated_value
|
47
|
-
self.localization.save
|
47
|
+
self.localization.save!
|
48
48
|
end
|
49
49
|
end
|
50
50
|
self.destroy
|
@@ -24,8 +24,10 @@ module Lit
|
|
24
24
|
end
|
25
25
|
|
26
26
|
## BEFORE & AFTER
|
27
|
-
|
28
|
-
|
27
|
+
with_options :if=>:translated_value_changed? do |o|
|
28
|
+
o.before_update :update_is_changed
|
29
|
+
o.before_update :create_version
|
30
|
+
end
|
29
31
|
after_update :mark_localization_key_completed
|
30
32
|
|
31
33
|
def to_s
|
@@ -33,7 +35,7 @@ module Lit
|
|
33
35
|
end
|
34
36
|
|
35
37
|
def full_key
|
36
|
-
|
38
|
+
[self.locale.locale, self.localization_key.localization_key].join('.')
|
37
39
|
end
|
38
40
|
|
39
41
|
def get_value
|
@@ -56,17 +58,26 @@ module Lit
|
|
56
58
|
self.updated_at.to_s(:db)
|
57
59
|
end
|
58
60
|
|
61
|
+
def update_default_value(value)
|
62
|
+
return true if persisted? && default_value == value
|
63
|
+
self.default_value = value
|
64
|
+
self.save!
|
65
|
+
end
|
66
|
+
|
59
67
|
private
|
60
68
|
def update_is_changed
|
61
|
-
|
69
|
+
unless is_changed?
|
70
|
+
self.is_changed = true
|
71
|
+
@should_mark_localization_key_completed = true
|
72
|
+
end
|
62
73
|
end
|
63
74
|
|
64
75
|
def mark_localization_key_completed
|
65
|
-
self.localization_key.mark_completed!
|
76
|
+
self.localization_key.mark_completed! if @should_mark_localization_key_completed
|
66
77
|
end
|
67
78
|
|
68
79
|
def create_version
|
69
|
-
if self.translated_value.present?
|
80
|
+
if self.translated_value.present?
|
70
81
|
l = self.localization_versions.new
|
71
82
|
l.translated_value = self.translated_value_was || self.default_value
|
72
83
|
end
|
data/app/models/lit/source.rb
CHANGED
@@ -20,6 +20,7 @@ module Lit
|
|
20
20
|
end
|
21
21
|
|
22
22
|
## BEFORE & AFTER
|
23
|
+
before_create :set_last_updated_at_upon_creation
|
23
24
|
after_validation :check_if_url_is_valid
|
24
25
|
|
25
26
|
|
@@ -50,13 +51,22 @@ module Lit
|
|
50
51
|
end
|
51
52
|
lc = get_last_change
|
52
53
|
lc = DateTime.parse(lc) unless lc.nil?
|
53
|
-
|
54
|
+
touch_last_updated_at(lc)
|
54
55
|
self.save
|
55
56
|
end
|
56
57
|
end
|
57
58
|
end
|
58
59
|
|
60
|
+
def touch_last_updated_at!
|
61
|
+
touch_last_updated_at
|
62
|
+
self.save
|
63
|
+
end
|
64
|
+
|
59
65
|
private
|
66
|
+
def touch_last_updated_at(time=nil)
|
67
|
+
self.last_updated_at = time || Time.now
|
68
|
+
end
|
69
|
+
|
60
70
|
def check_if_url_is_valid
|
61
71
|
if self.errors.empty? && (self.new_record? || self.url_changed?)
|
62
72
|
self.errors.add(:url, "is not accessible") if get_last_change.nil?
|
@@ -65,10 +75,10 @@ module Lit
|
|
65
75
|
|
66
76
|
def get_from_remote(path, query_values={})
|
67
77
|
result = nil
|
68
|
-
|
78
|
+
begin
|
69
79
|
uri = URI(self.url+path)
|
70
80
|
query_values.each do |k,v|
|
71
|
-
params = URI.decode_www_form(uri.query ||
|
81
|
+
params = URI.decode_www_form(uri.query || "") << [k, v]
|
72
82
|
uri.query = URI.encode_www_form(params)
|
73
83
|
end
|
74
84
|
req = Net::HTTP::Get.new(uri.request_uri)
|
@@ -79,9 +89,15 @@ module Lit
|
|
79
89
|
if res.is_a?(Net::HTTPSuccess)
|
80
90
|
result = JSON.parse(res.body)
|
81
91
|
end
|
82
|
-
|
83
|
-
|
92
|
+
rescue
|
93
|
+
end
|
84
94
|
result
|
85
95
|
end
|
96
|
+
|
97
|
+
def set_last_updated_at_upon_creation
|
98
|
+
if self.last_updated_at.blank?
|
99
|
+
touch_last_updated_at if Lit.set_last_updated_at_upon_creation
|
100
|
+
end
|
101
|
+
end
|
86
102
|
end
|
87
103
|
end
|
@@ -1,16 +1,23 @@
|
|
1
|
-
|
2
|
-
<
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
<
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
<
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
1
|
+
<div class="navbar-header">
|
2
|
+
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
3
|
+
<span class="sr-only">Toggle navigation</span>
|
4
|
+
<span class="icon-bar"></span>
|
5
|
+
<span class="icon-bar"></span>
|
6
|
+
<span class="icon-bar"></span>
|
7
|
+
</button>
|
8
|
+
<%= link_to "Lost in translation", root_path, :class=>'navbar-brand' %>
|
9
|
+
</div>
|
10
|
+
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
11
|
+
<ul class="nav navbar-nav">
|
12
|
+
<li><%= link_to "Translate!", lit.localization_keys_path %></li>
|
13
|
+
<li><%= link_to "Synchronize", lit.sources_path %></li>
|
14
|
+
<li class="dropdown">
|
15
|
+
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
16
|
+
Settings
|
17
|
+
<b class="caret"></b>
|
18
|
+
</a>
|
19
|
+
<ul class="dropdown-menu">
|
20
|
+
<li><%= link_to "Locales", lit.locales_path %></li>
|
21
|
+
</ul>
|
22
|
+
</li>
|
23
|
+
</ul>
|
@@ -5,30 +5,30 @@
|
|
5
5
|
<meta charset="utf-8" />
|
6
6
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
8
|
+
<%= stylesheet_link_tag "//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css", :media => "all" %>
|
9
|
+
<%= stylesheet_link_tag "//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css", :media => "all" %>
|
10
|
+
<%= stylesheet_link_tag "//netdna.bootstrapcdn.com/bootswatch/3.0.3/yeti/bootstrap.min.css", :media => "all" %>
|
8
11
|
<%= stylesheet_link_tag "lit/application", :media => "all" %>
|
9
12
|
<%= javascript_include_tag "lit/application" %>
|
13
|
+
<%= javascript_include_tag "//netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js" %>
|
10
14
|
<%= csrf_meta_tags %>
|
11
15
|
</head>
|
12
16
|
<body class="<%= params[:controller] %>">
|
13
|
-
<
|
14
|
-
|
15
|
-
|
16
|
-
<%= render 'layouts/lit/navigation' %>
|
17
|
-
</div>
|
18
|
-
</nav>
|
19
|
-
</div>
|
17
|
+
<nav class="navbar navbar-default" role="navigation">
|
18
|
+
<%= render 'layouts/lit/navigation' %>
|
19
|
+
</nav>
|
20
20
|
<div id="main" class="container <%= params[:action] %>" role="main">
|
21
21
|
<div class="row">
|
22
22
|
<% if content_for?(:sidebar) %>
|
23
|
-
<div class="
|
23
|
+
<div class="col-lg-3 col-xs-12 col-sm-3 col-md-3">
|
24
24
|
<%= yield(:sidebar) %>
|
25
25
|
</div>
|
26
|
-
<div class="
|
26
|
+
<div class="col-lg-9 col-xs-12 col-sm-9 col-md-9">
|
27
27
|
<%= render 'layouts/lit/messages' %>
|
28
28
|
<%= yield %>
|
29
29
|
</div>
|
30
30
|
<% else %>
|
31
|
-
<div class="
|
31
|
+
<div class="col-lg-12 col-xs-12 col-sm-12 col-md-12">
|
32
32
|
<%= render 'layouts/lit/messages' %>
|
33
33
|
<%= yield %>
|
34
34
|
</div>
|
@@ -1,4 +1,3 @@
|
|
1
|
-
<h1>Dashboard</h1>
|
2
1
|
<strong>All localization keys</strong> <%= Lit::LocalizationKey.count(:id) %><br/>
|
3
2
|
<% @locales.each do |l| %>
|
4
3
|
<strong><%= image_tag "lit/famfamfam_flags/#{l.locale[0,2]}.png" %> <%= t("lit.locale_to_languages.#{l.locale}", :default=>l.locale) %>:</strong> <span title="<%= "#{l.get_changed_localizations_count}/#{l.get_all_localizations_count}" %>"><%= l.get_translated_percentage %>%</span><br/>
|
@@ -1,10 +1,10 @@
|
|
1
1
|
<h1>Incomming localizations</h1>
|
2
2
|
<div class="row">
|
3
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 %>
|
4
|
+
<%= link_to accept_all_source_incomming_localizations_path(@source), :class=>"btn btn-success btn-sm", :data=>{:confirm=>t('lit.common.you_sure', :default=>"Are you sure?")} do %>
|
5
5
|
<%= t('lit.common.accept_all', :default=>"Accept all") %>
|
6
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 %>
|
7
|
+
<%= link_to reject_all_source_incomming_localizations_path(@source), :class=>"btn btn-danger btn-sm", :method=>:post, :data=>{:confirm=>t('lit.common.you_sure', :default=>"Are you sure?")} do %>
|
8
8
|
<%= t('lit.common.reject_all', :default=>"Reject all") %>
|
9
9
|
<% end %>
|
10
10
|
</span>
|
@@ -33,12 +33,12 @@
|
|
33
33
|
<%= render :partial=>"/lit/localization_keys/localization_row", :locals=>{:localization=>il.get_value} %>
|
34
34
|
</td>
|
35
35
|
<td>
|
36
|
-
<%= link_to accept_source_incomming_localization_path(@source, il), :class=>"btn btn-success" do %>
|
37
|
-
<%= draw_icon "
|
36
|
+
<%= link_to accept_source_incomming_localization_path(@source, il), :class=>"btn btn-success btn-sm" do %>
|
37
|
+
<%= draw_icon "check", :class=>"icon-white" %>
|
38
38
|
<%= t('lit.common.accept', :default=>"Accept") %>
|
39
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 "
|
40
|
+
<%= link_to source_incomming_localization_path(@source, il), :class=>"btn btn-danger btn-sm", :method=>:delete, :data=>{:confirm=>t('lit.common.you_sure', :default=>"Are you sure?")} do %>
|
41
|
+
<%= draw_icon "times", :class=>"icon-white" %>
|
42
42
|
<%= t('lit.common.reject', :default=>"Reject") %>
|
43
43
|
<% end %>
|
44
44
|
</td>
|
@@ -9,10 +9,10 @@
|
|
9
9
|
<span class="badge"><%= Lit.init.cache.get_global_hits_counter(lk.localization_key) %></span>
|
10
10
|
<div class="localization_keys_options">
|
11
11
|
<%= link_to lit.star_localization_key_path(lk), :remote=>true, :class=>"star_icon" do %>
|
12
|
-
<%= draw_icon lk.is_starred? ? 'star' : 'star-
|
12
|
+
<%= draw_icon lk.is_starred? ? 'star' : 'star-o' %>
|
13
13
|
<% end %>
|
14
14
|
<%= link_to lit.localization_key_path(lk), :method=>:delete, :data=>{:confirm=>t('lit.common.you_sure', :default=>"Are you sure?")}, :remote=>true do %>
|
15
|
-
<%= draw_icon 'trash' %>
|
15
|
+
<%= draw_icon 'trash-o' %>
|
16
16
|
<% end %>
|
17
17
|
</div>
|
18
18
|
<div class="detail_wrapper">
|
@@ -53,16 +53,18 @@
|
|
53
53
|
<% if @search_options.has_key?(:key_prefix) %>
|
54
54
|
<%= hidden_field_tag :key_prefix, @search_options[:key_prefix] %>
|
55
55
|
<% end %>
|
56
|
-
<div class="input-
|
57
|
-
<%= text_field_tag :key, @search_options[:key], :class=>"
|
58
|
-
<
|
56
|
+
<div class="input-group">
|
57
|
+
<%= text_field_tag :key, @search_options[:key], :class=>"form-control search-query" %>
|
58
|
+
<div class="input-group-btn">
|
59
|
+
<button type="submit" class="btn btn-default"><%= draw_icon 'search' %></button>
|
60
|
+
</div>
|
59
61
|
</div>
|
60
62
|
<label class="checkbox">
|
61
63
|
<%= check_box_tag :include_completed, '1', @search_options[:include_completed].to_i==1 %>
|
62
64
|
<%= t('.is_completed', :default=>"Include completed") %>
|
63
65
|
</label>
|
64
66
|
<% end %>
|
65
|
-
<ul class="nav nav-
|
67
|
+
<ul class="nav nav-pills nav-stacked">
|
66
68
|
<li class="<%= "active" if params[:action]=='index' %>">
|
67
69
|
<%= link_to lit.localization_keys_path do -%>
|
68
70
|
<%= draw_icon 'list' %>
|
@@ -1 +1 @@
|
|
1
|
-
$('tr.localization_key_row[data-id="<%= @localization_key.id %>"] a.star_icon').html("<%= ejs(draw_icon(@localization_key.is_starred? ? 'star' : 'star-
|
1
|
+
$('tr.localization_key_row[data-id="<%= @localization_key.id %>"] a.star_icon').html("<%= ejs(draw_icon(@localization_key.is_starred? ? 'star' : 'star-o')) %>");
|
@@ -1,20 +1,23 @@
|
|
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
4
|
<ul style="list-style: none;">
|
5
5
|
<% @localization.translated_value.each do |l| %>
|
6
|
-
<li><%= text_field_tag 'localization[translated_value][]', l, :class=>"input-xlarge" %></li>
|
6
|
+
<li><%= text_field_tag 'localization[translated_value][]', l, :class=>"form-control input-xlarge" %></li>
|
7
7
|
<% end %>
|
8
8
|
</ul>
|
9
9
|
<% else %>
|
10
|
-
<%= f.text_area :translated_value, :size=>"40x2", :class=>"input-xxlarge" %>
|
11
|
-
|
12
|
-
|
13
|
-
<
|
14
|
-
|
10
|
+
<%= f.text_area :translated_value, :size=>"40x2", :class=>"form-control input-xxlarge" %>
|
11
|
+
<% if allow_wysiwyg_editor?(@localization_key.localization_key) %>
|
12
|
+
<br />
|
13
|
+
<label>
|
14
|
+
<input type="checkbox" class="wysiwyg_switch" /> use wysiwyg editor
|
15
|
+
</label>
|
16
|
+
<br />
|
17
|
+
<% end %>
|
15
18
|
<% end %>
|
16
19
|
|
17
|
-
<button class="btn" type="submit"><%= t('lit.common.update', :default=>"Update") %></button>
|
18
|
-
<button class="btn
|
20
|
+
<button class="btn btn-primary btn-sm" type="submit"><%= t('lit.common.update', :default=>"Update") %></button>
|
21
|
+
<button class="btn btn-default btn-sm"><%= t('lit.common.cancel', :default=>'Cancel') %></button>
|
19
22
|
<% end %>
|
20
23
|
|
@@ -13,23 +13,23 @@
|
|
13
13
|
<div class="control-group">
|
14
14
|
<%= f.label :identifier, :class=>"control-label" %>
|
15
15
|
<div class="controls">
|
16
|
-
<%= f.text_field :identifier %>
|
16
|
+
<%= f.text_field :identifier, :class=>"form-control" %>
|
17
17
|
</div>
|
18
18
|
</div>
|
19
19
|
<div class="control-group">
|
20
20
|
<%= f.label :url, :class=>"control-label" %>
|
21
21
|
<div class="controls">
|
22
|
-
<%= f.text_field :url, :placeholder=>"http://your_other_env.host/lit" %>
|
22
|
+
<%= f.text_field :url, :placeholder=>"http://your_other_env.host/lit", :class=>"form-control" %>
|
23
23
|
</div>
|
24
24
|
</div>
|
25
25
|
<div class="control-group">
|
26
26
|
<%= f.label :api_key, :class=>"control-label" %>
|
27
27
|
<div class="controls">
|
28
|
-
<%= f.text_field :api_key %>
|
28
|
+
<%= f.text_field :api_key, :class=>"form-control" %>
|
29
29
|
</div>
|
30
30
|
</div>
|
31
31
|
|
32
32
|
<div class="actions">
|
33
|
-
<%= f.submit t('lit.common.save', :default => "Save"), :class=>"btn" %>
|
33
|
+
<%= f.submit t('lit.common.save', :default => "Save"), :class=>"btn btn-primary btn-sm" %>
|
34
34
|
</div>
|
35
35
|
<% end %>
|
@@ -23,8 +23,11 @@
|
|
23
23
|
<%= link_to lit.edit_source_path(source), :title=>t('lit.common.edit', :default=>"Edit") do %>
|
24
24
|
<%= draw_icon 'pencil' %>
|
25
25
|
<% end %>
|
26
|
+
<%= link_to lit.touch_source_path(source), :title=>t('lit.common.touch', :default=>"Touch (update) last_updated_at"), :method => :put, :data => { :confirm => 'Are you sure?' } do %>
|
27
|
+
<%= draw_icon 'clock-o' %>
|
28
|
+
<% end %>
|
26
29
|
<%= 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' %>
|
30
|
+
<%= draw_icon 'trash-o' %>
|
28
31
|
<% end %>
|
29
32
|
</td>
|
30
33
|
</tr>
|
data/config/routes.rb
CHANGED
@@ -11,6 +11,9 @@ Lit.key_value_engine = "<%= @key_value_engine %>"
|
|
11
11
|
# supported at the moment)
|
12
12
|
# Lit.storage_options = { :prefix=>"my_project" }
|
13
13
|
|
14
|
+
# If true all translations are returned as html_safe strings
|
15
|
+
Lit.all_translations_are_html_safe = false
|
16
|
+
|
14
17
|
# Translations without default will be humanized (default string will be added)
|
15
18
|
# ie. scope.page_header will become "Page header"
|
16
19
|
# If `false` then will serve nil instead (but translation will be wrapped in
|
@@ -28,6 +31,10 @@ Lit.api_enabled = false
|
|
28
31
|
# API key is required to authorize third party, if API is enabled
|
29
32
|
Lit.api_key = "<%= @api_key %>"
|
30
33
|
|
34
|
+
# If true, last_updated_at column of synchronizaton source will be set to now
|
35
|
+
# upon record creation
|
36
|
+
Lit.set_last_updated_at_upon_creation = true
|
37
|
+
|
31
38
|
# Initialize lit
|
32
39
|
Lit.init
|
33
40
|
|
data/lib/lit.rb
CHANGED
@@ -13,26 +13,32 @@ module Lit
|
|
13
13
|
def [](key)
|
14
14
|
if Lit.redis.exists(_prefixed_key_for_array(key))
|
15
15
|
Lit.redis.lrange(_prefixed_key(key), 0, -1)
|
16
|
+
elsif Lit.redis.exists(_prefixed_key_for_nil(key))
|
17
|
+
nil
|
16
18
|
else
|
17
19
|
Lit.redis.get(_prefixed_key(key))
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
21
23
|
def []=(k, v)
|
24
|
+
|
25
|
+
delete(k)
|
22
26
|
if v.is_a?(Array)
|
23
|
-
delete(k)
|
24
27
|
Lit.redis.set(_prefixed_key_for_array(k), "1")
|
25
28
|
v.each do |ve|
|
26
29
|
Lit.redis.rpush(_prefixed_key(k), ve.to_s)
|
27
30
|
end
|
31
|
+
elsif v.nil?
|
32
|
+
Lit.redis.set(_prefixed_key_for_nil(k), "1")
|
33
|
+
Lit.redis.set(_prefixed_key(k), "")
|
28
34
|
else
|
29
|
-
Lit.redis.
|
30
|
-
Lit.redis.set(_prefixed_key(k), v) unless v.nil?
|
35
|
+
Lit.redis.set(_prefixed_key(k), v)
|
31
36
|
end
|
32
37
|
end
|
33
38
|
|
34
39
|
def delete(k)
|
35
40
|
Lit.redis.del(_prefixed_key_for_array(k))
|
41
|
+
Lit.redis.del(_prefixed_key_for_nil(k))
|
36
42
|
Lit.redis.del(_prefixed_key(k))
|
37
43
|
end
|
38
44
|
|
@@ -72,5 +78,8 @@ module Lit
|
|
72
78
|
def _prefixed_key_for_array(key="")
|
73
79
|
_prefix+"array_flags:"+key.to_s
|
74
80
|
end
|
81
|
+
def _prefixed_key_for_nil(key="")
|
82
|
+
_prefix+"nil_flags:"+key.to_s
|
83
|
+
end
|
75
84
|
end
|
76
85
|
end
|
data/lib/lit/cache.rb
CHANGED
@@ -40,7 +40,6 @@ module Lit
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def has_key?(key)
|
43
|
-
# @TODO: change into correct has_key? call
|
44
43
|
@localizations.has_key?(key)
|
45
44
|
end
|
46
45
|
|
@@ -60,6 +59,11 @@ module Lit
|
|
60
59
|
@localizations[key] = localization.get_value if localization
|
61
60
|
end
|
62
61
|
|
62
|
+
def update_cache(key, value)
|
63
|
+
key = key.to_s
|
64
|
+
@localizations[key] = value
|
65
|
+
end
|
66
|
+
|
63
67
|
def delete_locale(key)
|
64
68
|
key = key.to_s
|
65
69
|
locale_key, key_without_locale = split_key(key)
|
@@ -67,16 +71,12 @@ module Lit
|
|
67
71
|
delete_localization(locale, key_without_locale)
|
68
72
|
end
|
69
73
|
|
70
|
-
def load_all_translations
|
71
|
-
doinit = false
|
74
|
+
def load_all_translations
|
72
75
|
first = Localization.order('id ASC').first
|
73
76
|
last = Localization.order('id DESC').first
|
74
77
|
if not first or not last or (not @localizations.has_key?(first.full_key) or
|
75
78
|
not @localizations.has_key?(last.full_key))
|
76
|
-
doinit = true
|
77
|
-
end
|
78
79
|
|
79
|
-
if oninit==false || doinit==true
|
80
80
|
Localization.includes([:locale, :localization_key]).find_each do |l|
|
81
81
|
@localizations[l.full_key] = l.get_value
|
82
82
|
end
|
@@ -123,27 +123,36 @@ module Lit
|
|
123
123
|
|
124
124
|
# this comes directly from copycopter.
|
125
125
|
def export
|
126
|
-
keys = {}
|
127
126
|
reset
|
127
|
+
localizations_scope = Lit::Localization
|
128
|
+
unless ENV['LOCALES'].blank?
|
129
|
+
locale_keys = ENV['LOCALES'].to_s.split(',') || []
|
130
|
+
locale_ids = Lit::Locale.where(locale: locale_keys).pluck(:id)
|
131
|
+
localizations_scope = localizations_scope.where(locale_id: locale_ids) unless locale_ids.empty?
|
132
|
+
end
|
128
133
|
db_localizations = {}
|
129
|
-
|
134
|
+
localizations_scope.find_each do |l|
|
130
135
|
db_localizations[l.full_key] = l.get_value
|
131
136
|
end
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
end
|
142
|
-
current = current[key]
|
137
|
+
keys = nested_string_keys_to_hash(db_localizations)
|
138
|
+
keys.to_yaml
|
139
|
+
end
|
140
|
+
|
141
|
+
def nested_string_keys_to_hash(db_localizations)
|
142
|
+
# http://subtech.g.hatena.ne.jp/cho45/20061122
|
143
|
+
deep_proc = Proc.new { |k, s, o|
|
144
|
+
if s.kind_of?(Hash) && o.kind_of?(Hash)
|
145
|
+
next s.merge(o, &deep_proc)
|
143
146
|
end
|
144
|
-
|
147
|
+
next o
|
148
|
+
}
|
149
|
+
keys = {}
|
150
|
+
db_localizations.sort.each do |k,v|
|
151
|
+
key_parts = k.to_s.split('.')
|
152
|
+
converted = key_parts.reverse.inject(v) { |a, n| { n => a } }
|
153
|
+
keys.merge!(converted, &deep_proc)
|
145
154
|
end
|
146
|
-
keys
|
155
|
+
keys
|
147
156
|
end
|
148
157
|
|
149
158
|
def get_global_hits_counter(key)
|
@@ -196,8 +205,7 @@ module Lit
|
|
196
205
|
value = key_without_locale.split('.').last.humanize if value.nil? &&
|
197
206
|
Lit.humanize_key
|
198
207
|
end
|
199
|
-
localization.
|
200
|
-
localization.save!
|
208
|
+
localization.update_default_value(value)
|
201
209
|
end
|
202
210
|
return localization
|
203
211
|
else
|
@@ -205,9 +213,16 @@ module Lit
|
|
205
213
|
end
|
206
214
|
end
|
207
215
|
|
216
|
+
def find_localization_for_delete(locale, key_without_locale)
|
217
|
+
localization_key = find_localization_key_for_delete(key_without_locale)
|
218
|
+
return nil unless localization_key
|
219
|
+
Lit::Localization.where(:locale_id=>locale.id).
|
220
|
+
where(:localization_key_id=>localization_key.id).first
|
221
|
+
end
|
222
|
+
|
208
223
|
def delete_localization(locale, key_without_locale)
|
209
|
-
localization =
|
210
|
-
if localization
|
224
|
+
localization = find_localization_for_delete(locale, key_without_locale)
|
225
|
+
if localization
|
211
226
|
@localizations.delete("#{locale.locale}.#{key_without_locale}")
|
212
227
|
@localization_keys.delete(key_without_locale)
|
213
228
|
localization.destroy # or localization.default_value = nil; localization.save!
|
@@ -231,6 +246,8 @@ module Lit
|
|
231
246
|
end
|
232
247
|
when String then
|
233
248
|
new_value = v
|
249
|
+
when Hash then
|
250
|
+
new_value = nil
|
234
251
|
when Proc then
|
235
252
|
new_value = nil # was v.call - requires more love
|
236
253
|
else
|
@@ -248,6 +265,12 @@ module Lit
|
|
248
265
|
end
|
249
266
|
end
|
250
267
|
|
268
|
+
def find_localization_key_for_delete(key_without_locale)
|
269
|
+
@localization_keys ||= Lit.get_key_value_engine
|
270
|
+
lk = Lit::LocalizationKey.find_by_id(@localization_keys[key_without_locale]) if @localization_keys.has_key?(key_without_locale)
|
271
|
+
lk || Lit::LocalizationKey.where(:localization_key=>key_without_locale).first
|
272
|
+
end
|
273
|
+
|
251
274
|
def split_key(key)
|
252
275
|
key.split('.', 2)
|
253
276
|
end
|
data/lib/lit/engine.rb
CHANGED
data/lib/lit/i18n_backend.rb
CHANGED
@@ -12,7 +12,7 @@ module Lit
|
|
12
12
|
|
13
13
|
def translate(locale, key, options = {})
|
14
14
|
content = super(locale, key, options.merge(:fallback => true))
|
15
|
-
if content.respond_to?(:html_safe)
|
15
|
+
if Lit.all_translations_are_html_safe && content.respond_to?(:html_safe)
|
16
16
|
content.html_safe
|
17
17
|
else
|
18
18
|
content
|
@@ -43,14 +43,26 @@ module Lit
|
|
43
43
|
content = @cache[key_with_locale] || super
|
44
44
|
return content if parts.size <= 1
|
45
45
|
|
46
|
-
newly_created = false
|
47
46
|
unless @cache.has_key?(key_with_locale)
|
48
|
-
@cache.init_key_with_value(key_with_locale, content)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
47
|
+
new_content = @cache.init_key_with_value(key_with_locale, content)
|
48
|
+
content = new_content if content.nil? # Content can change when Lit.humanize is true for example
|
49
|
+
|
50
|
+
if content.nil? && options[:default].present?
|
51
|
+
if options[:default].is_a?(Array)
|
52
|
+
default = options[:default].map do |key|
|
53
|
+
if key.is_a?(Symbol)
|
54
|
+
I18n.normalize_keys(nil, key.to_s, options[:scope], options[:separator]).join('.').to_sym
|
55
|
+
else
|
56
|
+
key
|
57
|
+
end
|
58
|
+
end
|
59
|
+
else
|
60
|
+
default = options[:default]
|
61
|
+
end
|
62
|
+
|
63
|
+
@cache[key_with_locale] = default
|
64
|
+
content = @cache[key_with_locale]
|
65
|
+
end
|
54
66
|
end
|
55
67
|
## return translated content
|
56
68
|
content
|
@@ -75,17 +87,5 @@ module Lit
|
|
75
87
|
super
|
76
88
|
end
|
77
89
|
|
78
|
-
def default(locale, object, subject, options = {})
|
79
|
-
content = super(locale, object, subject, options)
|
80
|
-
if content.respond_to?(:to_str)
|
81
|
-
parts = I18n.normalize_keys(locale, object, options[:scope], options[:separator])
|
82
|
-
if parts.size > 1
|
83
|
-
key = parts.join('.')
|
84
|
-
@cache[key] = content
|
85
|
-
end
|
86
|
-
end
|
87
|
-
content
|
88
|
-
end
|
89
|
-
|
90
90
|
end
|
91
91
|
end
|
data/lib/lit/version.rb
CHANGED
data/lib/tasks/lit_tasks.rake
CHANGED
@@ -1,8 +1,5 @@
|
|
1
|
-
# desc "Explaining what the task does"
|
2
|
-
# task :lit do
|
3
|
-
# # Task goes here
|
4
|
-
# end
|
5
1
|
namespace :lit do
|
2
|
+
desc "Exports translated strings from lit to config/locales/lit.yml file."
|
6
3
|
task :export => :environment do
|
7
4
|
if yml = Lit.init.cache.export
|
8
5
|
PATH = "config/locales/lit.yml"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-04-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -59,22 +59,6 @@ dependencies:
|
|
59
59
|
- - ! '>'
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '3.1'
|
62
|
-
- !ruby/object:Gem::Dependency
|
63
|
-
name: bootstrap-sass
|
64
|
-
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
|
-
requirements:
|
67
|
-
- - ~>
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '2.1'
|
70
|
-
type: :runtime
|
71
|
-
prerelease: false
|
72
|
-
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
|
-
requirements:
|
75
|
-
- - ~>
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
version: '2.1'
|
78
62
|
- !ruby/object:Gem::Dependency
|
79
63
|
name: pg
|
80
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -388,7 +372,6 @@ files:
|
|
388
372
|
- app/assets/javascripts/lit/jquery-te-1.4.0.min.js
|
389
373
|
- app/assets/javascripts/lit/localizations.js.coffee
|
390
374
|
- app/assets/stylesheets/lit/application.css
|
391
|
-
- app/assets/stylesheets/lit/bootstrap_and_overrides.css.scss
|
392
375
|
- app/assets/stylesheets/lit/dashboard.css
|
393
376
|
- app/assets/stylesheets/lit/jquery-te-1.4.0.css.scss
|
394
377
|
- app/controllers/lit/api/v1/base_controller.rb
|
@@ -487,7 +470,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
487
470
|
version: '0'
|
488
471
|
requirements: []
|
489
472
|
rubyforge_project:
|
490
|
-
rubygems_version: 1.8.23
|
473
|
+
rubygems_version: 1.8.23.2
|
491
474
|
signing_key:
|
492
475
|
specification_version: 3
|
493
476
|
summary: Database powered i18n backend with web gui
|
@@ -1,43 +0,0 @@
|
|
1
|
-
// Set the correct sprite paths
|
2
|
-
$iconSpritePath: asset-path('glyphicons-halflings.png', image);
|
3
|
-
$iconWhiteSpritePath: asset-path('glyphicons-halflings-white.png', image);
|
4
|
-
$baseFontSize: 13px;
|
5
|
-
$baseLineHeight: 18px;
|
6
|
-
@import "bootstrap";
|
7
|
-
body { padding-top: 60px; }
|
8
|
-
@import "bootstrap-responsive";
|
9
|
-
|
10
|
-
.btn-invite {
|
11
|
-
&:active, &.active {
|
12
|
-
background-color: #99cc99; } }
|
13
|
-
|
14
|
-
.btn-save {
|
15
|
-
&:active, &.active {
|
16
|
-
background-color: #cccc66; } }
|
17
|
-
|
18
|
-
.btn-discard {
|
19
|
-
&:active, &.active {
|
20
|
-
background-color: #cc9999; } }
|
21
|
-
h1 { font-size: 30px; line-height: 36px; }
|
22
|
-
h2 { font-size: 24px; line-height: 36px; }
|
23
|
-
h3 { font-size: 18px; line-height: 27px; }
|
24
|
-
h4 { font-size: 14px; line-height: 18px; }
|
25
|
-
h5 { font-size: 12px; line-height: 18px; }
|
26
|
-
h6 { font-size: 11px; line-height: 18px; }
|
27
|
-
|
28
|
-
h1 small { font-size: 18px; }
|
29
|
-
h2 small { font-size: 18px; }
|
30
|
-
h3 small { font-size: 14px; }
|
31
|
-
h4 small { font-size: 12px; }
|
32
|
-
h1, h2, h3, h4, h5, h6 {
|
33
|
-
color: inherit;
|
34
|
-
font-family: inherit;
|
35
|
-
font-weight: bold;
|
36
|
-
margin: 0;
|
37
|
-
text-rendering: optimizelegibility;
|
38
|
-
}
|
39
|
-
h6 {
|
40
|
-
color: #999999;
|
41
|
-
font-size: 11px;
|
42
|
-
text-transform: uppercase;
|
43
|
-
}
|