tolk 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,91 @@
1
+ module Tolk
2
+ class Translation < ActiveRecord::Base
3
+ set_table_name "tolk_translations"
4
+
5
+ scope :containing_text, lambda {|query| where("tolk_translations.text LIKE ?", "%#{query}%") }
6
+
7
+ serialize :text
8
+ validates_presence_of :text, :if => proc {|r| r.primary.blank? && !r.explicit_nil }
9
+
10
+ validates_uniqueness_of :phrase_id, :scope => :locale_id
11
+
12
+ belongs_to :phrase, :class_name => 'Tolk::Phrase'
13
+ belongs_to :locale, :class_name => 'Tolk::Locale'
14
+
15
+ attr_accessor :force_set_primary_update
16
+ before_save :set_primary_updated
17
+
18
+ before_save :set_previous_text
19
+
20
+ attr_accessor :primary
21
+ before_validation :fix_text_type, :unless => proc {|r| r.primary }
22
+
23
+ attr_accessor :explicit_nil
24
+ before_validation :set_explicit_nil
25
+
26
+ def up_to_date?
27
+ not out_of_date?
28
+ end
29
+
30
+ def out_of_date?
31
+ primary_updated?
32
+ end
33
+
34
+ def primary_translation
35
+ @_primary_translation ||= begin
36
+ if locale && !locale.primary?
37
+ phrase.translations.primary
38
+ end
39
+ end
40
+ end
41
+
42
+ def text=(value)
43
+ super unless value.to_s == text
44
+ end
45
+
46
+ def value
47
+ if text.is_a?(String) && /^\d+$/.match(text)
48
+ text.to_i
49
+ else
50
+ text
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def set_explicit_nil
57
+ if self.text == '~'
58
+ self.text = nil
59
+ self.explicit_nil = true
60
+ end
61
+ end
62
+
63
+ def fix_text_type
64
+ if primary_translation.present?
65
+ if self.text.is_a?(String) && !primary_translation.text.is_a?(String)
66
+ self.text = begin
67
+ YAML.load(self.text.strip)
68
+ rescue ArgumentError
69
+ nil
70
+ end
71
+
72
+ end
73
+
74
+ self.text = nil if primary_translation.text.class != self.text.class
75
+ end
76
+
77
+ true
78
+ end
79
+
80
+ def set_primary_updated
81
+ self.primary_updated = self.force_set_primary_update ? true : false
82
+ true
83
+ end
84
+
85
+ def set_previous_text
86
+ self.previous_text = self.text_was if text_changed?
87
+ true
88
+ end
89
+
90
+ end
91
+ end
@@ -0,0 +1,33 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<%= Tolk::Locale.primary_locale_name %>" lang="<%= Tolk::Locale.primary_locale_name %>">
4
+
5
+ <head>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
7
+ <title>Tolk</title>
8
+
9
+ <% if respond_to?(:sprockets_include_tag) %>
10
+ <%= sprockets_include_tag %>
11
+ <% else %>
12
+ <%= javascript_include_tag :defaults %>
13
+ <% end %>
14
+
15
+ <%= stylesheet_link_tag "/tolk/reset", "/tolk/screen" %>
16
+ <%= yield :head %>
17
+ </head>
18
+
19
+ <body>
20
+ <div id="container">
21
+ <div id="head">
22
+ <h1><span class="home"><%= link_to "Tolk", tolk_root_path %></span><%= yield :locale %></h1>
23
+ </div>
24
+ <%= yield %>
25
+ </div>
26
+
27
+ <script type="text/javascript">
28
+ $$('td textarea').each(function(element) {
29
+ element.setStyle({height: element.up('td').measure('height')+'px'});
30
+ });
31
+ </script>
32
+ </body>
33
+ </html>
@@ -0,0 +1,64 @@
1
+ <% content_for :locale do %><span class="locale"><%= @locale.language_name %></span>
2
+ <% end %>
3
+
4
+ <h3 class="switch">Completed translations <span>(<%= link_to 'See phrases missing translation', @locale %>)</span></h3>
5
+
6
+ <% if @locale.has_updated_translations? && action_name != 'updated' %>
7
+ <span class="notice">Some phrases have changed. <%= link_to "Update translations", updated_tolk_locale_path(@locale) %>.</span>
8
+ <% end %>
9
+
10
+ <div class="search">
11
+ <%= render :partial => "tolk/searches/form", :locals => { :locale => @locale } %>
12
+ </div>
13
+
14
+ <div class="translations">
15
+ <% if @phrases.any? %>
16
+ <%= form_for @locale do |locale_form| %>
17
+ <table class="translations">
18
+ <tr>
19
+ <th class="translation"><%= @locale.language_name -%></th>
20
+ <th class="key"><%= Tolk::Locale.primary_language_name -%></th>
21
+ </tr>
22
+ <% @phrases.each do |phrase| %>
23
+ <% if phrase.translations.primary %>
24
+ <tr>
25
+ <td class="translation">
26
+ <%= hidden_field_tag :"translations[][id]", phrase.translation.id %>
27
+ <%= hidden_field_tag :"translations[][locale_id]", phrase.translation.locale_id %>
28
+ <%= text_area_tag :"translations[][text]", format_i18n_text_area_value(phrase.translation.text), :class => 'locale',
29
+ :onfocus => "$(this).up('tr').addClassName('active');", :onblur => "$(this).up('tr').removeClassName('active');" %>
30
+ </td>
31
+ <td class="phrase">
32
+
33
+ <% if action_name == 'updated' %>
34
+ <div class="updated">
35
+ <span class="key">Updated</span>
36
+ <%= format_i18n_value(phrase.translations.primary.text) -%>
37
+ </div>
38
+ <div class="original">
39
+ <span class="key">Original</span>
40
+ <%= format_i18n_value(phrase.translations.primary.previous_text) -%>
41
+ </div>
42
+ <% else %>
43
+ <%= format_i18n_value(phrase.translations.primary.text) -%>
44
+ <% end %>
45
+
46
+ <span class="key"><%= phrase.key %></span>
47
+ </td>
48
+ </tr>
49
+ <% end %>
50
+ <% end %>
51
+ </table>
52
+ <div class="table_submit">
53
+ <p><%= locale_form.submit "Save changes" %></p>
54
+ </div>
55
+ <div class="paginate">
56
+ <%= will_paginate @phrases %>
57
+ </div>
58
+ <% end %>
59
+ <% else %>
60
+ <p style="text-align: left">There aren't any completed translations for this locale.</p>
61
+ <p>&nbsp;</p>
62
+ <% end %>
63
+ </div>
64
+
@@ -0,0 +1,35 @@
1
+ <% content_for :locale do %><span class="locale empty"></span>
2
+ <% end %>
3
+
4
+ <h2>Locales <span>Primary locale is <%= Tolk::Locale.primary_locale.language_name %></span></h2>
5
+ <% if @locales.any? %>
6
+ <ul class="locales clearfix">
7
+ <% @locales.each do |locale| %>
8
+ <li>
9
+ <%= link_to locale.language_name, locale %>
10
+ <% missing_count = locale.count_phrases_without_translation %>
11
+ <% if missing_count > 0 %>
12
+ <span class="missing_translations"><%= locale.count_phrases_without_translation %></span>
13
+ <% end %>
14
+ </li>
15
+ <% end %>
16
+ </ul>
17
+
18
+ <% else %>
19
+ <p>No locales yet.</p>
20
+
21
+ <% end %>
22
+ <%= form_for(Tolk::Locale.new) do |f| %>
23
+ <div class="submit">
24
+ <%= f.error_messages %>
25
+ <p>
26
+ <%= f.label "Add a new Locale" %>
27
+ <select id="select_tolk_locale_name" name="tolk_locale[name]">
28
+ <%= options_for_select tolk_locale_selection %>
29
+ </select>
30
+ <%= f.submit 'Add' %>
31
+ </p>
32
+ </div>
33
+ <% end %>
34
+
35
+
@@ -0,0 +1,11 @@
1
+ atom_feed do |feed|
2
+ feed.title "Missing Translations for #{@locale.language_name} locale"
3
+
4
+ @phrases.each do |phrase|
5
+ feed.entry(phrase, :url => tolk_locale_url(@locale)) do |entry|
6
+ entry.title(phrase.key)
7
+ entry.content(phrase.key)
8
+ entry.author {|author| author.name("Tolk") }
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,58 @@
1
+ <% content_for :locale do %>
2
+ <span class="locale"><%= @locale.language_name %></span>
3
+ <% end %>
4
+
5
+ <% content_for :head do %>
6
+ <link rel="alternate" type="application/rss+xml" title="RSS" href="<%= tolk_locale_path(@locale, :format => 'atom') -%>" />
7
+ <% end %>
8
+
9
+ <h3 class="switch">Phrases missing translation (<%= @locale.count_phrases_without_translation %>) <span>(<%= link_to 'See completed translations', all_tolk_locale_path(@locale) %>)</span></h3>
10
+
11
+ <% if @locale.has_updated_translations? && action_name != 'updated' %>
12
+ <span class="notice">Some phrases have changed. <%= link_to "Update translations", updated_tolk_locale_path(@locale) %>.</span>
13
+ <% end %>
14
+
15
+ <div class="search">
16
+ <%= render :partial => "tolk/searches/form", :locals => { :locale => @locale } %>
17
+ </div>
18
+
19
+ <div class="translations">
20
+ <% if @phrases.any? %>
21
+ <%= form_for @locale do |locale_form| %>
22
+ <table class="translations">
23
+ <tr>
24
+ <th class="translation"><%= @locale.language_name -%></th>
25
+ <th class="key"><%= Tolk::Locale.primary_language_name -%></th>
26
+ </tr>
27
+ <% @phrases.each do |phrase| %>
28
+ <tr>
29
+ <% translation = Tolk::Translation.new(:locale => @locale, :phrase => phrase) %>
30
+ <td class="translation">
31
+ <%= hidden_field_tag :"translations[][id]", translation.id, :id => "#{translation.object_id}_id" %>
32
+ <%= hidden_field_tag :"translations[][phrase_id]", phrase.id, :id => "#{translation.object_id}_phrase_id" %>
33
+ <%= hidden_field_tag :"translations[][locale_id]", translation.locale_id, :id => "#{translation.object_id}_locale_id" %>
34
+ <%= text_area_tag :"translations[][text]", format_i18n_text_area_value(translation.text), :class => "locale", :id => "#{translation.object_id}_text", :onfocus => "$(this).up('tr').addClassName('active');", :onblur => "$(this).up('tr').removeClassName('active');" %>
35
+ </td>
36
+ <td class="phrase">
37
+ <% if params[:q].present? -%>
38
+ <%= highlight(format_i18n_value(phrase.translations.primary.text), params[:q]) -%>
39
+ <% else -%>
40
+ <%= format_i18n_value(phrase.translations.primary.text) -%>
41
+ <% end -%>
42
+ <span class="key" title="<%= phrase.key %>"><%= truncate(phrase.key, :length => 100) %></span>
43
+ </td>
44
+ </tr>
45
+ <% end %>
46
+ </table>
47
+ <div class="table_submit">
48
+ <p><%= locale_form.submit "Save changes" %></p>
49
+ </div>
50
+ <% end %>
51
+ <div class="paginate">
52
+ <%= will_paginate @phrases %>
53
+ </div>
54
+ <% else %>
55
+ <p style="text-align: left">There aren't any missing or updated phrases that need translation.</p>
56
+ <p>&nbsp;</p>
57
+ <% end %>
58
+ </div>
@@ -0,0 +1,8 @@
1
+ <%= form_tag "/tolk/search", :method => :get do %>
2
+ <%= hidden_field_tag :locale, locale.name %>
3
+ Search for
4
+ <%= scope_selector_for(@locale) %>
5
+ phrase:
6
+ <%= text_field_tag :q, params[:q] %>
7
+ <%= submit_tag "Search", :name => nil %>
8
+ <% end %>
@@ -0,0 +1,55 @@
1
+ <% content_for :locale do %>
2
+ <span class="locale"><%= @locale.language_name %></span>
3
+ <% end %>
4
+
5
+ <h3 class="search">
6
+ <%= render :partial => "form", :locals => { :locale => @locale } %>
7
+ </h3>
8
+
9
+ <div class="search_exits">
10
+ <%= link_to "Phrases missing translation", @locale %>
11
+ &nbsp;
12
+ <%= link_to "Completed translations", all_tolk_locale_path(@locale) %>
13
+ </div>
14
+
15
+ <div class="translations">
16
+ <% if @phrases.any? %>
17
+ <%= form_for @locale do |locale_form| %>
18
+ <table class="translations">
19
+ <tr>
20
+ <th class="translation"><%= @locale.language_name -%></th>
21
+ <th class="key"><%= Tolk::Locale.primary_language_name -%></th>
22
+ </tr>
23
+ <% @phrases.each do |phrase| %>
24
+
25
+ <% if translation = phrase.translations.find_by_locale_id(@locale.id) || Tolk::Translation.new(:locale => @locale, :phrase => phrase) %>
26
+ <tr>
27
+ <td class="translation">
28
+ <%= hidden_field_tag :"translations[][id]", translation.id, :id => "#{translation.object_id}_id" %>
29
+ <%= hidden_field_tag :"translations[][phrase_id]", phrase.id, :id => "#{translation.object_id}_phrase_id" %>
30
+ <%= hidden_field_tag :"translations[][locale_id]", translation.locale_id, :id => "#{translation.object_id}_locale_id" %>
31
+ <%= text_area_tag :"translations[][text]", format_i18n_text_area_value(translation.text), :class => "locale", :id => "#{translation.object_id}_text", :onfocus => "$(this).up('tr').addClassName('active');", :onblur => "$(this).up('tr').removeClassName('active');" %>
32
+ </td>
33
+ <td class="phrase">
34
+ <% if params[:q].present? -%>
35
+ <%= highlight(format_i18n_value(phrase.translations.primary.text), params[:q]) -%>
36
+ <% else -%>
37
+ <%= format_i18n_value(phrase.translations.primary.text) -%>
38
+ <% end -%>
39
+ <span class="key" title="<%= phrase.key %>"><%= truncate(phrase.key, :length => 100) %></span>
40
+ </td>
41
+ </tr>
42
+ <% end %>
43
+ <% end %>
44
+ </table>
45
+ <div class="table_submit">
46
+ <p><%= locale_form.submit "Save changes" %></p>
47
+ </div>
48
+ <% end %>
49
+ <div class="paginate">
50
+ <%= will_paginate @phrases %>
51
+ </div>
52
+ <% else %>
53
+ <p style="text-align: left">No search results.</p>
54
+ <% end %>
55
+ </div>
@@ -0,0 +1,7 @@
1
+ Rails.application.routes.draw do |map|
2
+ map.namespace('tolk') do |tolk|
3
+ tolk.root :controller => 'locales'
4
+ tolk.resources :locales, :member => {:all => :get, :updated => :get}
5
+ tolk.resource :search
6
+ end
7
+ end
data/init.rb ADDED
@@ -0,0 +1,8 @@
1
+ Mime::Type.register_alias "text/yaml", :yml
2
+
3
+ $KCODE = 'UTF8'
4
+ begin
5
+ require 'ya2yaml'
6
+ rescue LoadError => e
7
+ Rails.logger.debug "[Tolk] Could not load ya2yaml"
8
+ end
@@ -0,0 +1,38 @@
1
+ class CreateTolkTables < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :tolk_locales do |t|
4
+ t.string :name
5
+ t.datetime :created_at
6
+ t.datetime :updated_at
7
+ end
8
+
9
+ add_index :tolk_locales, :name, :unique => true
10
+
11
+ create_table :tolk_phrases do |t|
12
+ t.text :key
13
+ t.datetime :created_at
14
+ t.datetime :updated_at
15
+ end
16
+
17
+ create_table :tolk_translations do |t|
18
+ t.integer :phrase_id
19
+ t.integer :locale_id
20
+ t.text :text
21
+ t.text :previous_text
22
+ t.boolean :primary_updated, :default => false
23
+ t.datetime :created_at
24
+ t.datetime :updated_at
25
+ end
26
+
27
+ add_index :tolk_translations, [:phrase_id, :locale_id], :unique => true
28
+ end
29
+
30
+ def self.down
31
+ remove_index :tolk_translations, :column => [:phrase_id, :locale_id]
32
+ remove_index :tolk_locales, :column => :name
33
+
34
+ drop_table :tolk_translations
35
+ drop_table :tolk_phrases
36
+ drop_table :tolk_locales
37
+ end
38
+ end
@@ -0,0 +1,19 @@
1
+ class TolkMigrationGenerator < Rails::Generators::Base
2
+ include Rails::Generators::Migration
3
+
4
+ source_root File.expand_path("../templates", __FILE__)
5
+
6
+ def create_migration_file
7
+ migration_template "migrate/create_tolk_tables.rb", "db/migrate/create_tolk_tables.rb"
8
+ end
9
+
10
+ # Implement the required interface for Rails::Generators::Migration.
11
+ def self.next_migration_number(dirname) #:nodoc:
12
+ next_migration_number = current_migration_number(dirname) + 1
13
+ if ActiveRecord::Base.timestamped_migrations
14
+ [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
15
+ else
16
+ "%.3d" % next_migration_number
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,43 @@
1
+ namespace :tolk do
2
+ desc "Add database tables, copy over the assets, and import existing translations"
3
+ task :setup => :environment do
4
+ Rake::Task['tolk:import_assets'].invoke
5
+ system("rails generate tolk_migration")
6
+ Rake::Task['db:migrate'].invoke
7
+ Rake::Task['tolk:sync'].invoke
8
+ Rake::Task['tolk:import'].invoke
9
+ end
10
+
11
+ desc "Sync Tolk with the default locale's yml file"
12
+ task :sync => :environment do
13
+ Tolk::Locale.sync!
14
+ end
15
+
16
+ desc "Generate yml files for all the locales defined in Tolk"
17
+ task :dump_all => :environment do
18
+ Tolk::Locale.dump_all
19
+ end
20
+
21
+ desc "Imports data all non default locale yml files to Tolk"
22
+ task :import => :environment do
23
+ Rake::Task['tolk:sync'].invoke
24
+ Tolk::Locale.import_secondary_locales
25
+ end
26
+
27
+ desc "Show all the keys potentially containing HTML values and no _html postfix"
28
+ task :html_keys => :environment do
29
+ bad_translations = Tolk::Locale.primary_locale.translations_with_html
30
+ bad_translations.each do |bt|
31
+ puts "#{bt.phrase.key} - #{bt.text}"
32
+ end
33
+ end
34
+
35
+ desc "Copies required assets from tolk to application's public/ directory"
36
+ task :import_assets do
37
+ tolk_assets = File.expand_path(File.join(File.dirname(__FILE__), '../../public/tolk'))
38
+ command = "cp -R #{tolk_assets} #{Rails.root}/public/"
39
+ puts command
40
+ system(command)
41
+ end
42
+
43
+ end