lit 0.2.1 → 0.2.2

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.
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
- }