lit 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. data/README.md +1 -1
  2. data/app/assets/javascripts/lit/application.js +0 -2
  3. data/app/assets/stylesheets/lit/application.css +15 -3
  4. data/app/controllers/lit/localizations_controller.rb +1 -1
  5. data/app/controllers/lit/sources_controller.rb +6 -0
  6. data/app/helpers/lit/localizations_helper.rb +6 -2
  7. data/app/models/lit/incomming_localization.rb +3 -3
  8. data/app/models/lit/localization.rb +17 -6
  9. data/app/models/lit/localization_key.rb +1 -1
  10. data/app/models/lit/source.rb +21 -5
  11. data/app/views/layouts/lit/_navigation.html.erb +23 -16
  12. data/app/views/layouts/lit/application.html.erb +10 -10
  13. data/app/views/lit/dashboard/index.html.erb +0 -1
  14. data/app/views/lit/incomming_localizations/index.html.erb +6 -6
  15. data/app/views/lit/locales/index.html.erb +1 -1
  16. data/app/views/lit/localization_keys/index.html.erb +8 -6
  17. data/app/views/lit/localization_keys/star.js.erb +1 -1
  18. data/app/views/lit/localizations/_form.html.erb +12 -9
  19. data/app/views/lit/localizations/_previous_versions_rows.html.erb +1 -1
  20. data/app/views/lit/sources/_form.html.erb +4 -4
  21. data/app/views/lit/sources/index.html.erb +4 -1
  22. data/app/views/lit/sources/show.html.erb +1 -0
  23. data/config/routes.rb +1 -0
  24. data/lib/generators/lit/install/templates/initializer.rb +7 -0
  25. data/lib/lit.rb +3 -0
  26. data/lib/lit/adapters/redis_storage.rb +12 -3
  27. data/lib/lit/cache.rb +48 -25
  28. data/lib/lit/engine.rb +0 -1
  29. data/lib/lit/i18n_backend.rb +20 -20
  30. data/lib/lit/version.rb +1 -1
  31. data/lib/tasks/lit_tasks.rake +1 -4
  32. metadata +3 -20
  33. 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~~
@@ -12,8 +12,6 @@
12
12
  //
13
13
  //= require jquery
14
14
  //= require jquery_ujs
15
- // require jquery-ui
16
- //= require bootstrap
17
15
  //= require_tree .
18
16
 
19
17
  $(document).ready(function(){
@@ -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: 65px;
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 .icon-chevron-right {
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.refresh_key @localization.full_key
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=\"icon-#{icon} #{opts[:class]}\" title=\"#{opts[:title]}\" ></i>")
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
- before_update :update_is_changed
28
- before_update :create_version
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
- "#{self.locale.locale}.#{self.localization_key.localization_key}"
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
- self.is_changed = true unless is_changed?
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? and (not self.translated_value.nil?)
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
@@ -15,7 +15,7 @@ module Lit
15
15
  ## VALIDATIONS
16
16
  validates :localization_key,
17
17
  :presence=>true,
18
- :uniqueness=>true
18
+ :uniqueness=>{:if=>:localization_key_changed?}
19
19
 
20
20
  unless defined?(::ActionController::StrongParameters)
21
21
  ## ACCESSIBLE
@@ -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
- self.last_updated_at = lc || Time.now
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
- #begin
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 || []) << [k, v]
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
- #rescue
83
- #end
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
- <%= link_to "Lost in translation", root_path, :class=>'brand' %>
2
- <ul class="nav">
3
- <li><%= link_to "Translate!", lit.localization_keys_path %></li>
4
- <li><%= link_to "Synchronize", lit.sources_path %></li>
5
- <li class="dropdown">
6
- <a href="#" class="dropdown-toggle" data-toggle="dropdown">
7
- Settings
8
- <b class="caret"></b>
9
- </a>
10
- <ul class="dropdown-menu">
11
- </ul>
12
- <ul class="dropdown-menu">
13
- <li><%= link_to "Locales", lit.locales_path %></li>
14
- </ul>
15
- </li>
16
- </ul>
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
- <div class="navbar navbar-fixed-top navbar-inverse">
14
- <nav class="navbar-inner">
15
- <div class="container">
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="span3">
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="span9">
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="span12">
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 "ok", :class=>"icon-white" %>
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 "remove", :class=>"icon-white" %>
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>
@@ -3,7 +3,7 @@
3
3
  <table class="table table-stripped">
4
4
  <tr>
5
5
  <th>Locale</th>
6
- <th width="100">Options</th>
6
+ <th width="130">Options</th>
7
7
  </tr>
8
8
 
9
9
  <% @locales.each do |locale| %>
@@ -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-empty' %>
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-append">
57
- <%= text_field_tag :key, @search_options[:key], :class=>"input-medium search-query" %>
58
- <button type="submit" class="btn"><%= t('.search', :default=>"Search") %></button>
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-list ">
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-empty')) %>");
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
- <%= f.label :translated_value %>
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
- <br />
12
- <label>
13
- <input type="checkbox" class="wysiwyg_switch" /> use wysiwyg editor
14
- </label>
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 cancel"><%= t('lit.common.cancel', :default=>'Cancel') %></button>
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
 
@@ -1,4 +1,4 @@
1
- <span class="pull-right"><%= draw_icon 'remove', :class=>"close_versions" %></span>
1
+ <span class="pull-right"><%= draw_icon 'times', :class=>"close_versions" %></span>
2
2
  <table class="table table-condensed">
3
3
  <tr>
4
4
  <th><%= t('lit.common.previous_versions') %></th>
@@ -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>
@@ -11,6 +11,7 @@
11
11
  <br/>
12
12
  <strong>Last updated at:</strong>
13
13
  <%= @source.last_updated_at.to_s(:db) unless @source.last_updated_at.nil? %>
14
+ <%= link_to '(touch!)', touch_source_path(@source), :method => :put, :data => { :confirm => 'Are you sure?' } %>
14
15
  <br/>
15
16
 
16
17
 
@@ -32,6 +32,7 @@ Lit::Engine.routes.draw do
32
32
  resources :sources do
33
33
  member do
34
34
  get :synchronize
35
+ put :touch
35
36
  end
36
37
  resources :incomming_localizations, :only=>[:index, :destroy] do
37
38
  member do
@@ -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
@@ -9,6 +9,9 @@ module Lit
9
9
  mattr_accessor :fallback
10
10
  mattr_accessor :api_enabled
11
11
  mattr_accessor :api_key
12
+ mattr_accessor :all_translations_are_html_safe
13
+ mattr_accessor :set_last_updated_at_upon_creation
14
+
12
15
  class << self
13
16
  attr_accessor :loader
14
17
  end
@@ -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.del(_prefixed_key_for_array(k))
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
@@ -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(oninit=false)
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
- Lit::Localization.find_each do |l|
134
+ localizations_scope.find_each do |l|
130
135
  db_localizations[l.full_key] = l.get_value
131
136
  end
132
- db_localizations.sort.each do |(l_key, value)|
133
- current = keys
134
- yaml_keys = l_key.split('.')
135
-
136
- 0.upto(yaml_keys.size - 2) do |i|
137
- key = yaml_keys[i]
138
- # Overwrite en.key with en.sub.key
139
- unless current[key].class == Hash
140
- current[key] = {}
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
- current[yaml_keys.last] = value
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.to_yaml
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.default_value = value
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 = find_localization(locale, key_without_locale)
210
- if localization.persisted?
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
@@ -1,4 +1,3 @@
1
- require 'bootstrap-sass'
2
1
  module Lit
3
2
  class Engine < ::Rails::Engine
4
3
  isolate_namespace Lit
@@ -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
- newly_created = true
50
- end
51
- if content.nil? || (newly_created && options[:default].present?)
52
- @cache[key_with_locale] = options[:default]
53
- content = @cache[key_with_locale]
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
@@ -1,3 +1,3 @@
1
1
  module Lit
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
@@ -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.1
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: 2013-10-18 00:00:00.000000000 Z
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
- }