translate-rails3-plus 0.0.1

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.
@@ -0,0 +1,178 @@
1
+ require 'yaml'
2
+
3
+ class Hash
4
+ def deep_merge(other)
5
+ # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
6
+ merger = proc { |key, v1, v2| (Hash === v1 && Hash === v2) ? v1.merge(v2, &merger) : v2 }
7
+ merge(other, &merger)
8
+ end
9
+
10
+ def set(keys, value)
11
+ key = keys.shift
12
+ if keys.empty?
13
+ self[key] = value
14
+ else
15
+ self[key] ||= {}
16
+ self[key].set keys, value
17
+ end
18
+ end
19
+
20
+ if ENV['SORT']
21
+ # copy of ruby's to_yaml method, prepending sort.
22
+ # before each so we get an ordered yaml file
23
+ def to_yaml( opts = {} )
24
+ YAML::quick_emit( self, opts ) do |out|
25
+ out.map( taguri, to_yaml_style ) do |map|
26
+ sort.each do |k, v| #<- Adding sort.
27
+ map.add( k, v )
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ namespace :translate do
36
+ desc "Show untranslated keys for locale LOCALE"
37
+ task :untranslated => :environment do
38
+ from_locale = I18n.default_locale
39
+ untranslated = Translate::Keys.new.untranslated_keys
40
+
41
+ messages = []
42
+ untranslated.each do |locale, keys|
43
+ keys.each do |key|
44
+ from_text = I18n.backend.send(:lookup, from_locale, key)
45
+ messages << "#{locale}.#{key} (#{from_locale}.#{key}='#{from_text}')"
46
+ end
47
+ end
48
+
49
+ if messages.present?
50
+ messages.each { |m| puts m }
51
+ else
52
+ puts "No untranslated keys"
53
+ end
54
+ end
55
+
56
+ desc "Show I18n keys that are missing in the config/locales/default_locale.yml YAML file"
57
+ task :missing => :environment do
58
+ missing = Translate::Keys.new.missing_keys.inject([]) do |keys, (key, filename)|
59
+ keys << "#{key} in \t #{filename} is missing"
60
+ end
61
+ puts missing.present? ? missing.join("\n") : "No missing translations in the default locale file"
62
+ end
63
+
64
+ desc "Remove all translation texts that are no longer present in the locale they were translated from"
65
+ task :remove_obsolete_keys => :environment do
66
+ I18n.backend.send(:init_translations)
67
+ master_locale = ENV['LOCALE'] || I18n.default_locale
68
+ Translate::Keys.translated_locales.each do |locale|
69
+ texts = {}
70
+ Translate::Keys.new.i18n_keys(locale).each do |key|
71
+ if I18n.backend.send(:lookup, master_locale, key).to_s.present?
72
+ texts[key] = I18n.backend.send(:lookup, locale, key)
73
+ end
74
+ end
75
+ I18n.backend.send(:translations)[locale] = nil # Clear out all current translations
76
+ I18n.backend.store_translations(locale, Translate::Keys.to_deep_hash(texts))
77
+ Translate::Storage.new(locale).write_to_file
78
+ end
79
+ end
80
+
81
+ desc "Merge I18n keys from log/translations.yml into config/locales/*.yml (for use with the Rails I18n TextMate bundle)"
82
+ task :merge_keys => :environment do
83
+ I18n.backend.send(:init_translations)
84
+ new_translations = YAML::load(IO.read(File.join(Rails.root, "log", "translations.yml")))
85
+ raise("Can only merge in translations in single locale") if new_translations.keys.size > 1
86
+ locale = new_translations.keys.first
87
+
88
+ overwrites = false
89
+ Translate::Keys.to_shallow_hash(new_translations[locale]).keys.each do |key|
90
+ new_text = key.split(".").inject(new_translations[locale]) { |hash, sub_key| hash[sub_key] }
91
+ existing_text = I18n.backend.send(:lookup, locale.to_sym, key)
92
+ if existing_text && new_text != existing_text
93
+ puts "ERROR: key #{key} already exists with text '#{existing_text.inspect}' and would be overwritten by new text '#{new_text}'. " +
94
+ "Set environment variable OVERWRITE=1 if you really want to do this."
95
+ overwrites = true
96
+ end
97
+ end
98
+
99
+ if !overwrites || ENV['OVERWRITE']
100
+ I18n.backend.store_translations(locale, new_translations[locale])
101
+ Translate::Storage.new(locale).write_to_file
102
+ end
103
+ end
104
+
105
+ desc "Apply Google translate to auto translate all texts in locale ENV['FROM'] to locale ENV['TO']"
106
+ task :google => :environment do
107
+ raise "Please specify FROM and TO locales as environment variables" if ENV['FROM'].blank? || ENV['TO'].blank?
108
+
109
+ # Depends on httparty gem
110
+ # http://www.robbyonrails.com/articles/2009/03/16/httparty-goes-foreign
111
+ class GoogleApi
112
+ include HTTParty
113
+ base_uri 'ajax.googleapis.com'
114
+ def self.translate(string, to, from)
115
+ tries = 0
116
+ begin
117
+ get("/ajax/services/language/translate",
118
+ :query => {:langpair => "#{from}|#{to}", :q => string, :v => 1.0},
119
+ :format => :json)
120
+ rescue
121
+ tries += 1
122
+ puts("SLEEPING - retrying in 5...")
123
+ sleep(5)
124
+ retry if tries < 10
125
+ end
126
+ end
127
+ end
128
+
129
+ I18n.backend.send(:init_translations)
130
+
131
+ start_at = Time.now
132
+ translations = {}
133
+ Translate::Keys.new.i18n_keys(ENV['FROM']).each do |key|
134
+ from_text = I18n.backend.send(:lookup, ENV['FROM'], key).to_s
135
+ to_text = I18n.backend.send(:lookup, ENV['TO'], key)
136
+ if !from_text.blank? && to_text.blank?
137
+ print "#{key}: '#{from_text[0, 40]}' => "
138
+ if !translations[from_text]
139
+ response = GoogleApi.translate(from_text, ENV['TO'], ENV['FROM'])
140
+ translations[from_text] = response["responseData"] && response["responseData"]["translatedText"]
141
+ end
142
+ if !(translation = translations[from_text]).blank?
143
+ translation.gsub!(/\(\(([a-z_.]+)\)\)/i, '{{\1}}')
144
+ # Google translate sometimes replaces {{foobar}} with (()) foobar. We skip these
145
+ if translation !~ /\(\(\)\)/
146
+ puts "'#{translation[0, 40]}'"
147
+ I18n.backend.store_translations(ENV['TO'].to_sym, Translate::Keys.to_deep_hash({key => translation}))
148
+ else
149
+ puts "SKIPPING since interpolations were messed up: '#{translation[0,40]}'"
150
+ end
151
+ else
152
+ puts "NO TRANSLATION - #{response.inspect}"
153
+ end
154
+ end
155
+ end
156
+
157
+ puts "\nTime elapsed: #{(((Time.now - start_at) / 60) * 10).to_i / 10.to_f} minutes"
158
+ Translate::Storage.new(ENV['TO'].to_sym).write_to_file
159
+ end
160
+
161
+ desc "List keys that have changed I18n texts between YAML file ENV['FROM_FILE'] and YAML file ENV['TO_FILE']. Set ENV['VERBOSE'] to see changes"
162
+ task :changed => :environment do
163
+ from_hash = Translate::Keys.to_shallow_hash(Translate::File.new(ENV['FROM_FILE']).read)
164
+ to_hash = Translate::Keys.to_shallow_hash(Translate::File.new(ENV['TO_FILE']).read)
165
+ from_hash.each do |key, from_value|
166
+ if (to_value = to_hash[key]) && to_value != from_value
167
+ key_without_locale = key[/^[^.]+\.(.+)$/, 1]
168
+ if ENV['VERBOSE']
169
+ puts "KEY: #{key_without_locale}"
170
+ puts "FROM VALUE: '#{from_value}'"
171
+ puts "TO VALUE: '#{to_value}'"
172
+ else
173
+ puts key_without_locale
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,35 @@
1
+ require 'fileutils'
2
+
3
+ class Translate::File
4
+ attr_accessor :path
5
+
6
+ def initialize(path)
7
+ self.path = path
8
+ end
9
+
10
+ def write(keys)
11
+ FileUtils.mkdir_p File.dirname(path)
12
+ File.open(path, "w") do |file|
13
+ file.puts keys_to_yaml(Translate::File.deep_stringify_keys(keys))
14
+ end
15
+ end
16
+
17
+ def read
18
+ File.exists?(path) ? YAML::load(IO.read(path)) : {}
19
+ end
20
+
21
+ # Stringifying keys for prettier YAML
22
+ def self.deep_stringify_keys(hash)
23
+ hash.inject({}) { |result, (key, value)|
24
+ value = deep_stringify_keys(value) if value.is_a? Hash
25
+ result[(key.to_s rescue key) || key] = value
26
+ result
27
+ }
28
+ end
29
+
30
+ private
31
+ def keys_to_yaml(keys)
32
+ # Using ya2yaml, if available, for UTF8 support
33
+ keys.respond_to?(:ya2yaml) ? keys.ya2yaml(:escape_as_utf8 => true) : keys.to_yaml
34
+ end
35
+ end
@@ -0,0 +1,185 @@
1
+ require 'pathname'
2
+
3
+ class Translate::Keys
4
+ # Allows keys extracted from lookups in files to be cached
5
+ def self.files
6
+ @@files ||= Translate::Keys.new.files
7
+ end
8
+
9
+ # Allows flushing of the files cache
10
+ def self.files=(files)
11
+ @@files = files
12
+ end
13
+
14
+ def files
15
+ @files ||= extract_files
16
+ end
17
+ alias_method :to_hash, :files
18
+
19
+ def keys
20
+ files.keys
21
+ end
22
+ alias_method :to_a, :keys
23
+
24
+ def i18n_keys(locale)
25
+ I18n.backend.send(:init_translations) unless I18n.backend.initialized?
26
+ Translate::Keys.to_shallow_hash(I18n.backend.send(:translations)[locale.to_sym]).keys.sort
27
+ end
28
+
29
+ def untranslated_keys
30
+ Translate::Keys.translated_locales.inject({}) do |missing, locale|
31
+ missing[locale] = i18n_keys(I18n.default_locale).map do |key|
32
+ I18n.backend.send(:lookup, locale, key).nil? ? key : nil
33
+ end.compact
34
+ missing
35
+ end
36
+ end
37
+
38
+ def missing_keys
39
+ locale = I18n.default_locale; yaml_keys = {}
40
+ yaml_keys = Translate::Storage.file_paths(locale).inject({}) do |keys, path|
41
+ keys = keys.deep_merge(Translate::File.new(path).read[locale.to_s])
42
+ end
43
+ files.reject { |key, file| self.class.contains_key?(yaml_keys, key) }
44
+ end
45
+
46
+ def self.translated_locales
47
+ I18n.available_locales.reject { |locale| [:root, I18n.default_locale.to_sym].include?(locale) }
48
+ end
49
+
50
+ # Checks if a nested hash contains the keys in dot separated I18n key.
51
+ #
52
+ # Example:
53
+ #
54
+ # hash = {
55
+ # :foo => {
56
+ # :bar => {
57
+ # :baz => 1
58
+ # }
59
+ # }
60
+ # }
61
+ #
62
+ # contains_key?("foo", key) # => true
63
+ # contains_key?("foo.bar", key) # => true
64
+ # contains_key?("foo.bar.baz", key) # => true
65
+ # contains_key?("foo.bar.baz.bla", key) # => false
66
+ #
67
+ def self.contains_key?(hash, key)
68
+ keys = key.to_s.split(".")
69
+ return false if keys.empty?
70
+ !keys.inject(HashWithIndifferentAccess.new(hash)) do |memo, key|
71
+ memo.is_a?(Hash) ? memo.try(:[], key) : nil
72
+ end.nil?
73
+ end
74
+
75
+ # Convert something like:
76
+ #
77
+ # {
78
+ # :pressrelease => {
79
+ # :label => {
80
+ # :one => "Pressmeddelande"
81
+ # }
82
+ # }
83
+ # }
84
+ #
85
+ # to:
86
+ #
87
+ # {'pressrelease.label.one' => "Pressmeddelande"}
88
+ #
89
+ def self.to_shallow_hash(hash)
90
+ hash.inject({}) do |shallow_hash, (key, value)|
91
+ if value.is_a?(Hash)
92
+ to_shallow_hash(value).each do |sub_key, sub_value|
93
+ shallow_hash[[key, sub_key].join(".")] = sub_value
94
+ end
95
+ else
96
+ shallow_hash[key.to_s] = value
97
+ end
98
+ shallow_hash
99
+ end
100
+ end
101
+
102
+ # Convert something like:
103
+ #
104
+ # {'pressrelease.label.one' => "Pressmeddelande"}
105
+ #
106
+ # to:
107
+ #
108
+ # {
109
+ # :pressrelease => {
110
+ # :label => {
111
+ # :one => "Pressmeddelande"
112
+ # }
113
+ # }
114
+ # }
115
+ def self.to_deep_hash(hash)
116
+ hash.inject({}) do |deep_hash, (key, value)|
117
+ keys = key.to_s.split('.').reverse
118
+ leaf_key = keys.shift
119
+ key_hash = keys.inject({leaf_key.to_sym => value}) { |hash, key| {key.to_sym => hash} }
120
+ deep_merge!(deep_hash, key_hash)
121
+ deep_hash
122
+ end
123
+ end
124
+
125
+ # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
126
+ def self.deep_merge!(hash1, hash2)
127
+ merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
128
+ hash1.merge!(hash2, &merger)
129
+ end
130
+
131
+ # Convert something like:
132
+ #
133
+ # {'0' => "elem 1", '1' => "elem 2"}
134
+ #
135
+ # to:
136
+ #
137
+ # ["elem 1", "elem 2"]
138
+ #
139
+ def self.arraylize(input_hash)
140
+ input_hash.inject([]) do |constructed_array, (key, value)|
141
+ constructed_array << value
142
+ constructed_array
143
+ end
144
+ end
145
+
146
+ private
147
+
148
+ def extract_files
149
+ files_to_scan.inject(HashWithIndifferentAccess.new) do |files, file|
150
+ keys = IO.read(file)
151
+ if keys.respond_to? "encode"
152
+ keys = keys.encode("UTF-8").force_encoding("UTF-8")
153
+ end
154
+ error_count = 0
155
+ begin
156
+ encoded_keys = keys.scan(i18n_lookup_pattern)
157
+ rescue => e
158
+ unless error_count > 1
159
+ if keys.respond_to? 'encode!'
160
+ keys.encode!('utf-8', 'utf-8', :invalid => :replace)
161
+ end
162
+ error_count += 1
163
+ retry
164
+ else
165
+ puts "cannot fix: #{e} on : #{file}"
166
+ end
167
+ end
168
+ encoded_keys.flatten.map(&:to_sym).each do |key|
169
+ files[key] ||= []
170
+ path = Pathname.new(File.expand_path(file)).relative_path_from(Pathname.new(Rails.root)).to_s
171
+ files[key] << path if !files[key].include?(path)
172
+ end
173
+ files
174
+ end
175
+ end
176
+
177
+ def i18n_lookup_pattern
178
+ /\b(?:I18n\.t|I18n\.translate|t)(?:\s|\():?'([a-z0-9_]+.[a-z0-9_.]+)'\)?/
179
+ end
180
+
181
+ def files_to_scan
182
+ Dir.glob(File.join(Translate::Storage.root_dir, "{app,config,lib}", "**","*.{rb,erb,rhtml}")) +
183
+ Dir.glob(File.join(Translate::Storage.root_dir, "public", "javascripts", "**","*.js"))
184
+ end
185
+ end
@@ -0,0 +1,35 @@
1
+ class Translate::Log
2
+ attr_accessor :from_locale, :to_locale, :keys
3
+
4
+ def initialize(from_locale, to_locale, keys)
5
+ self.from_locale = from_locale
6
+ self.to_locale = to_locale
7
+ self.keys = keys
8
+ end
9
+
10
+ def write_to_file
11
+ current_texts = File.exists?(file_path) ? file.read : {}
12
+ current_texts.merge!(from_texts)
13
+ file.write(current_texts)
14
+ end
15
+
16
+ def read
17
+ file.read
18
+ end
19
+
20
+ private
21
+ def file
22
+ @file ||= Translate::File.new(file_path)
23
+ end
24
+
25
+ def from_texts
26
+ Translate::File.deep_stringify_keys(Translate::Keys.to_deep_hash(keys.inject({}) do |hash, key|
27
+ hash[key] = I18n.backend.send(:lookup, from_locale, key)
28
+ hash
29
+ end))
30
+ end
31
+
32
+ def file_path
33
+ File.join(Rails.root, "config", "locales", "log", "from_#{from_locale}_to_#{to_locale}.yml")
34
+ end
35
+ end
@@ -0,0 +1,11 @@
1
+ module Translate
2
+ class Routes
3
+ def self.translation_ui(map)
4
+ map.with_options(:controller => 'translate') do |t|
5
+ t.translate_list 'translate'
6
+ t.translate 'translate/translate', :action => 'translate'
7
+ t.translate_reload 'translate/reload', :action => 'reload'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ class Translate::Storage
2
+ attr_accessor :locale
3
+
4
+ def initialize(locale)
5
+ self.locale = locale.to_sym
6
+ end
7
+
8
+ def write_to_file
9
+ Translate::File.new(file_path).write(keys)
10
+ end
11
+
12
+ def self.file_paths(locale)
13
+ Dir.glob(File.join(root_dir, "config", "locales", "**","#{locale}.yml"))
14
+ end
15
+
16
+ def self.root_dir
17
+ Rails.root
18
+ end
19
+
20
+ private
21
+ def keys
22
+ {locale => I18n.backend.send(:translations)[locale]}
23
+ end
24
+
25
+ def file_path
26
+ File.join(Translate::Storage.root_dir, "config", "locales", "#{locale}.yml")
27
+ end
28
+ end
data/lib/translate.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'ya2yaml'
2
+
3
+ module Translate
4
+ class Engine < Rails::Engine
5
+ end if defined?(Rails) && Rails::VERSION::MAJOR == 3
6
+
7
+ class << self
8
+ # For configuring Google Translate API key
9
+ attr_accessor :api_key
10
+ # For configuring Bing Application id
11
+ attr_accessor :app_id
12
+ end
13
+ end
14
+
15
+ Dir[File.join(File.dirname(__FILE__), "translate", "*.rb")].each do |file|
16
+ require file
17
+ end
@@ -0,0 +1,130 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+
4
+ describe TranslateController do
5
+ describe "index" do
6
+ before(:each) do
7
+ controller.stub!(:per_page).and_return(1)
8
+ I18n.backend.stub!(:translations).and_return(i18n_translations)
9
+ I18n.backend.instance_eval { @initialized = true }
10
+ keys = mock(:keys)
11
+ keys.stub!(:i18n_keys).and_return(['vendor.foobar'])
12
+ Translate::Keys.should_receive(:new).and_return(keys)
13
+ Translate::Keys.should_receive(:files).and_return(files)
14
+ I18n.stub!(:available_locales).and_return([:en, :sv])
15
+ I18n.stub!(:default_locale).and_return(:sv)
16
+ end
17
+
18
+ it "shows sorted paginated keys from the translate from locale and extracted keys by default" do
19
+ get_page :index
20
+ assigns(:from_locale).should == :sv
21
+ assigns(:to_locale).should == :en
22
+ assigns(:files).should == files
23
+ assigns(:keys).sort.should == ['articles.new.page_title', 'home.page_title', 'vendor.foobar']
24
+ assigns(:paginated_keys).should == ['articles.new.page_title']
25
+ end
26
+
27
+ it "can be paginated with the page param" do
28
+ get_page :index, :page => 2
29
+ assigns(:files).should == files
30
+ assigns(:paginated_keys).should == ['home.page_title']
31
+ end
32
+
33
+ it "accepts a key_pattern param with key_type=starts_with" do
34
+ get_page :index, :key_pattern => 'articles', :key_type => 'starts_with'
35
+ assigns(:files).should == files
36
+ assigns(:paginated_keys).should == ['articles.new.page_title']
37
+ assigns(:total_entries).should == 1
38
+ end
39
+
40
+ it "accepts a key_pattern param with key_type=contains" do
41
+ get_page :index, :key_pattern => 'page_', :key_type => 'contains'
42
+ assigns(:files).should == files
43
+ assigns(:total_entries).should == 2
44
+ assigns(:paginated_keys).should == ['articles.new.page_title']
45
+ end
46
+
47
+ it "accepts a filter=untranslated param" do
48
+ get_page :index, :filter => 'untranslated'
49
+ assigns(:total_entries).should == 2
50
+ assigns(:paginated_keys).should == ['articles.new.page_title']
51
+ end
52
+
53
+ it "accepts a filter=translated param" do
54
+ get_page :index, :filter => 'translated'
55
+ assigns(:total_entries).should == 1
56
+ assigns(:paginated_keys).should == ['vendor.foobar']
57
+ end
58
+
59
+ it "accepts a filter=changed param" do
60
+ log = mock(:log)
61
+ old_translations = {:home => {:page_title => "Skapar ny artikel"}}
62
+ log.should_receive(:read).and_return(Translate::File.deep_stringify_keys(old_translations))
63
+ Translate::Log.should_receive(:new).with(:sv, :en, {}).and_return(log)
64
+ get_page :index, :filter => 'changed'
65
+ assigns(:total_entries).should == 1
66
+ assigns(:keys).should == ["home.page_title"]
67
+ end
68
+
69
+ def i18n_translations
70
+ HashWithIndifferentAccess.new({
71
+ :en => {
72
+ :vendor => {
73
+ :foobar => "Foo Baar"
74
+ }
75
+ },
76
+ :sv => {
77
+ :articles => {
78
+ :new => {
79
+ :page_title => "Skapa ny artikel"
80
+ }
81
+ },
82
+ :home => {
83
+ :page_title => "Välkommen till I18n"
84
+ },
85
+ :vendor => {
86
+ :foobar => "Fobar"
87
+ }
88
+ }
89
+ })
90
+ end
91
+
92
+ def files
93
+ HashWithIndifferentAccess.new({
94
+ :'home.page_title' => ["app/views/home/index.rhtml"],
95
+ :'general.back' => ["app/views/articles/new.rhtml", "app/views/categories/new.rhtml"],
96
+ :'articles.new.page_title' => ["app/views/articles/new.rhtml"]
97
+ })
98
+ end
99
+ end
100
+
101
+ describe "translate" do
102
+ it "should store translations to I18n backend and then write them to a YAML file" do
103
+ session[:from_locale] = :sv
104
+ session[:to_locale] = :en
105
+ translations = {
106
+ :articles => {
107
+ :new => {
108
+ :title => "New Article"
109
+ }
110
+ },
111
+ :category => "Category"
112
+ }
113
+ key_param = {'articles.new.title' => "New Article", "category" => "Category"}
114
+ I18n.backend.should_receive(:store_translations).with(:en, translations)
115
+ storage = mock(:storage)
116
+ storage.should_receive(:write_to_file)
117
+ Translate::Storage.should_receive(:new).with(:en).and_return(storage)
118
+ log = mock(:log)
119
+ log.should_receive(:write_to_file)
120
+ Translate::Log.should_receive(:new).with(:sv, :en, key_param.keys).and_return(log)
121
+ post :translate, "key" => key_param
122
+ response.should be_redirect
123
+ end
124
+ end
125
+
126
+ def get_page(*args)
127
+ get(*args)
128
+ response.should be_success
129
+ end
130
+ end
data/spec/file_spec.rb ADDED
@@ -0,0 +1,54 @@
1
+ require 'fileutils'
2
+ require File.dirname(__FILE__) + '/spec_helper'
3
+
4
+ describe Translate::File do
5
+ describe "write" do
6
+ before(:each) do
7
+ @file = Translate::File.new(file_path)
8
+ end
9
+
10
+ after(:each) do
11
+ FileUtils.rm(file_path)
12
+ end
13
+
14
+ it "writes all I18n messages for a locale to YAML file" do
15
+ @file.write(translations)
16
+ @file.read.should == Translate::File.deep_stringify_keys(translations)
17
+ end
18
+
19
+ def translations
20
+ {
21
+ :en => {
22
+ :article => {
23
+ :title => "One Article"
24
+ },
25
+ :category => "Category"
26
+ }
27
+ }
28
+ end
29
+ end
30
+
31
+ describe "deep_stringify_keys" do
32
+ it "should convert all keys in a hash to strings" do
33
+ Translate::File.deep_stringify_keys({
34
+ :en => {
35
+ :article => {
36
+ :title => "One Article"
37
+ },
38
+ :category => "Category"
39
+ }
40
+ }).should == {
41
+ "en" => {
42
+ "article" => {
43
+ "title" => "One Article"
44
+ },
45
+ "category" => "Category"
46
+ }
47
+ }
48
+ end
49
+ end
50
+
51
+ def file_path
52
+ File.join(File.dirname(__FILE__), "files", "en.yml")
53
+ end
54
+ end
@@ -0,0 +1,12 @@
1
+ class Article < ActiveRecord::Base
2
+ def validate
3
+ # t('li')
4
+ errors.add_to_base([t(:'article.key1') + "#{t('article.key2')}"])
5
+ I18n.t 'article.key3'
6
+ I18n.t 'article.key3'
7
+ I18n.t :'article.key4'
8
+ I18n.translate :'article.key5'
9
+ 'bla bla t' + "blubba bla" + ' foobar'
10
+ 'bla bla t ' + "blubba bla" + ' foobar'
11
+ end
12
+ end
@@ -0,0 +1 @@
1
+ <%= t(:'category_erb.key1') %>
@@ -0,0 +1 @@
1
+ t(:'category_html.key1')