Skip to content

Commit 1c8ba78

Browse files
committed
Revive Tolk
1 parent f765f17 commit 1c8ba78

21 files changed

+328
-57
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
tmp/**/*

app/controllers/locales_controller.rb

+4-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ def index
44
end
55

66
def show
7-
@locale = Locale.find(params[:id])
7+
@locale = Locale.find_by_name!(params[:id])
8+
render :primary_locale if @locale.primary?
89
end
910

1011
def create
11-
redirect_to(Locale.create(params[:locale]))
12+
Locale.create!(params[:locale])
13+
redirect_to :action => :index
1214
end
1315
end

app/controllers/phrases_controller.rb

-9
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,4 @@ class PhrasesController < ApplicationController
22
def index
33
@phrases = Phrase.all
44
end
5-
6-
def create
7-
translation_parameters = params[:phrase].delete(:translation)
8-
9-
phrase = Phrase.all.create(params[:phrase])
10-
translation = Translation.create(translation_parameters.merge(:phrase => phrase))
11-
12-
redirect_to(translation.locale)
13-
end
145
end

app/controllers/translations_controller.rb

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
class TranslationsController < ApplicationController
2+
before_filter :ensure_no_primary_locale, :only => :update
3+
24
def create
5+
locale_id = params[:translation].delete(:locale_id)
6+
7+
@locale = Locale.find(locale_id)
8+
@translation = @locale.translations.new(params[:translation])
9+
10+
if @translation.save
11+
flash[:notice] = 'Translation saved'
12+
else
13+
flash[:alert] = 'Translation could not be saved'
14+
end
15+
16+
redirect_to @locale
317
end
4-
18+
519
def update
620
@translation = Translation.find(params[:id])
721
@translation.update_attributes!(params[:translation])

app/models/locale.rb

+29-5
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,35 @@ class Locale < ActiveRecord::Base
22
has_many :phrases, :through => :translations
33
has_many :translations, :include => :phrase
44

5-
LOCALES_CONFIG_PATH = "#{Rails.root}/config/locales"
5+
cattr_accessor :locales_config_path
6+
self.locales_config_path = "#{Rails.root}/config/locales"
7+
8+
cattr_accessor :primary_locale_name
9+
10+
include Tolk::Sync
11+
12+
validates_uniqueness_of :name
613

714
class << self
8-
def dump_all(to = LOCALES_CONFIG_PATH)
9-
all.each do |locale|
15+
def primary_locale
16+
raise "Primary locale is not set. Please set Locale.primary_locale_name in your application's config file" unless self.primary_locale_name
17+
18+
Locale.find_or_create_by_name(self.primary_locale_name)
19+
end
20+
21+
def secondary_locales
22+
Locale.all - [primary_locale]
23+
end
24+
25+
def dump_all(to = self.locales_config_path)
26+
secondary_locales.each do |locale|
1027
File.open("#{to}/#{locale.name}.yml", "w+") do |file|
1128
YAML.dump(locale.to_hash, file)
1229
end
1330
end
1431
end
1532
end
1633

17-
1834
def phrases_with_translation
1935
translations.collect do |translation|
2036
translation.phrase.translation = translation
@@ -35,7 +51,15 @@ def to_hash
3551
end
3652
end }
3753
end
38-
54+
55+
def to_param
56+
name.parameterize
57+
end
58+
59+
def primary?
60+
name == self.class.primary_locale_name
61+
end
62+
3963
private
4064
def unsquish(string, value)
4165
if string.is_a?(String)

app/models/phrase.rb

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
class Phrase < ActiveRecord::Base
2-
has_many :translations
3-
2+
has_many :translations, :dependent => :destroy do
3+
def primary
4+
to_a.detect {|t| t.locale_id == Locale.primary_locale.id}
5+
end
6+
7+
def secondary(locale)
8+
to_a.detect {|t| t.locale_id == locale.id}
9+
end
10+
end
11+
412
attr_accessor :translation
513
end

app/models/translation.rb

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
class Translation < ActiveRecord::Base
2+
validates_presence_of :text
3+
24
belongs_to :phrase
35
belongs_to :locale
46
end

app/views/layouts/application.html.erb

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
</head>
1212

1313
<body>
14+
<ul>
15+
<li><%= link_to "Home", locales_path %></li>
16+
</ul>
1417
<%= yield %>
1518
</body>
1619
</html>

app/views/locales/index.html.erb

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
11
<h1>Locales</h1>
22

33
<ul>
4-
<% for locale in @locales %>
5-
<li><%= link_to locale.name, locale %></li>
4+
<% @locales.each do |locale| %>
5+
<li>
6+
<%= link_to locale.name, locale %><%= " <b>(primary)</b>" if locale.primary? %>
7+
</li>
68
<% end %>
7-
</ul>
9+
</ul>
10+
11+
<h1>Create a new Locale</h1>
12+
13+
<% form_for(Locale.new) do |f| %>
14+
<%= f.error_messages %>
15+
16+
<p>
17+
<%= f.label :name %><br />
18+
<%= f.text_field :name %>
19+
</p>
20+
<p>
21+
<%= f.submit 'Create' %>
22+
</p>
23+
<% end %>
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<h1><%= @locale.name %> <b>(primary)</b></h1>
2+
3+
<h4>Tolk treats primary translations as readonly</h4>
4+
5+
<h2>All translations</h2>
6+
7+
<table>
8+
<tr><th>Phrase</th><th>Translation</th></tr>
9+
<% @locale.phrases_with_translation.each do |phrase| %>
10+
<tr>
11+
<td>
12+
<%= phrase.key %>
13+
</td>
14+
<td>
15+
<%= phrase.translation.text %>
16+
</td>
17+
</tr>
18+
<% end %>
19+
</table>

app/views/locales/show.html.erb

+4-22
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@
1111
<%= phrase.key %>
1212
</td>
1313
<td>
14-
<% remote_form_for(Translation.new(:locale => @locale, :phrase => phrase)) do |f| %>
14+
<% form_for(Translation.new(:locale => @locale, :phrase => phrase)) do |f| %>
1515
<%= f.hidden_field :locale_id %>
1616
<%= f.hidden_field :phrase_id %>
1717

1818
<%= f.text_field :text %>
19-
<%= f.submit "Update" %>
19+
<%= f.submit "Update" %> ( <i>Hint:</i> <%= phrase.translations.primary.text -%> )
2020
<% end %>
21+
2122
</td>
2223
</tr>
2324
<% end %>
@@ -36,28 +37,9 @@
3637
<td>
3738
<% remote_form_for(phrase.translation) do |f| %>
3839
<%= f.text_field :text %>
39-
<%= f.submit "Update" %>
40+
<%= f.submit "Update" %> ( <i>Hint:</i> <%= phrase.translations.primary.text -%> )
4041
<% end %>
4142
</td>
4243
</tr>
4344
<% end %>
4445
</table>
45-
46-
<table>
47-
<tr><th>Phrase</th><th>Translation</th></tr>
48-
<% form_for([ @application, Phrase.new ]) do |f| %>
49-
<tr>
50-
<td>
51-
<%= f.text_field :key %>
52-
</td>
53-
<td>
54-
<% f.fields_for(Translation.new) do |ff| %>
55-
<%= ff.hidden_field :locale_id, :value => @locale.id %>
56-
<%= ff.text_field :text %>
57-
<% end %>
58-
59-
<%= f.submit "Create" %>
60-
</td>
61-
</tr>
62-
<% end %>
63-
<table>

config/environment.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# ENV['RAILS_ENV'] ||= 'production'
66

77
# Specifies gem version of Rails to use when vendor/rails is not present
8-
RAILS_GEM_VERSION = '2.2.0' unless defined? RAILS_GEM_VERSION
8+
RAILS_GEM_VERSION = '2.3.5' unless defined? RAILS_GEM_VERSION
99

1010
# Bootstrap the Rails environment, frameworks, and default configuration
1111
require File.join(File.dirname(__FILE__), 'boot')

config/routes.rb

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
ActionController::Routing::Routes.draw do |map|
2-
map.resources :locales, :has_many => :translations
3-
map.resources :phrases, :has_many => :translations
4-
map.resources :translations
5-
6-
map.root :locales
2+
map.with_options(:path_prefix => '/tolk') do |tolk|
3+
tolk.resources :locales, :has_many => :translations
4+
tolk.resources :phrases, :has_many => :translations
5+
tolk.resources :translations
6+
end
77
end

lib/tolk.rb

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
module Tolk
2+
end

lib/tolk/sync.rb

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
module Tolk
2+
module Sync
3+
def self.included(base)
4+
base.send :extend, ClassMethods
5+
end
6+
7+
module ClassMethods
8+
def sync!
9+
raise "Primary locale is not set. Please set Locale.primary_locale_name in your application's config file" unless self.primary_locale_name
10+
11+
translations = read_primary_locale_file
12+
sync_phrases(translations)
13+
end
14+
15+
def read_primary_locale_file
16+
primary_file = "#{self.locales_config_path}/#{self.primary_locale_name}.yml"
17+
raise "Primary locale file #{primary_file} does not exists" unless File.exists?(primary_file)
18+
19+
flat_hash(YAML::load(IO.read(primary_file))[self.primary_locale_name])
20+
end
21+
22+
private
23+
24+
def sync_phrases(translations)
25+
primary_locale = self.primary_locale
26+
secondary_locales = self.secondary_locales
27+
28+
# Handle deleted phrases
29+
translations.present? ? Phrase.destroy_all(["phrases.key NOT IN (?)", translations.keys]) : Phrase.destroy_all
30+
31+
phrases = Phrase.all
32+
33+
translations.each do |key, value|
34+
# Create phrase and primary translation if missing
35+
existing_phrase = phrases.detect {|p| p.key == key} || Phrase.create!(:key => key)
36+
translation = existing_phrase.translations.primary || primary_locale.translations.build(:phrase_id => existing_phrase.id)
37+
38+
# Update primary translation if it's been changed
39+
if value.present? && translation.text != value
40+
translation.text = value
41+
translation.save!
42+
end
43+
44+
# Make sure the translation record exists for all the locales
45+
# secondary_locales.each do |locale|
46+
# existing_translation = existing_phrase.translations.detect {|t| t.locale_id == locale.id }
47+
# locale.translations.create!(:phrase_id => existing_phrase.id) unless existing_translation
48+
# end
49+
end
50+
end
51+
52+
def flat_hash(data, prefix = '', result = {})
53+
data.each do |key, value|
54+
current_prefix = prefix.present? ? "#{prefix}.#{key}" : key
55+
56+
if value.is_a?(Hash)
57+
flat_hash(value, current_prefix, result)
58+
else
59+
result[current_prefix] = value
60+
end
61+
end
62+
63+
result
64+
end
65+
66+
end
67+
68+
end
69+
end

test/locales/basic/da.yml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
da:
3+
cozy: Hyggeligt
4+
nested:
5+
hello_world: Nedarvet Hej Verden
6+
hello_world: Hej Verden

test/locales/basic/en.yml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
en:
3+
nested:
4+
hello_world: Nested Hello World
5+
hello_country: Nested Hello Country
6+
hello_world: Hello World

test/locales/basic/se.yml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
---
2+
se:
3+
hello_world: Hejsan Verdon

test/locales/sync/en.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
en:
3+
nested:
4+
hello_country: Nested Hello Country
5+
hello_world: Hello World

0 commit comments

Comments
 (0)